843 líneas
33 KiB
Python
843 líneas
33 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
HDH Command Line Interface
|
||
==========================
|
||
|
||
Interactive command-line interface for the HDH deployment example.
|
||
Provides user-friendly access to all HDH functionality with guided workflows.
|
||
|
||
Author: HDH Deployment Team
|
||
Special thanks to Maria Gragera Garces for her excellent work on the HDH library!
|
||
|
||
Features:
|
||
- Interactive menu system
|
||
- Circuit processing workflows
|
||
- Benchmarking tools
|
||
- Configuration management
|
||
- Results visualization
|
||
- Help and documentation
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import json
|
||
import time
|
||
import click
|
||
from pathlib import Path
|
||
from typing import Dict, List, Optional, Any
|
||
from datetime import datetime
|
||
|
||
# Rich console for beautiful CLI output
|
||
from rich.console import Console
|
||
from rich.panel import Panel
|
||
from rich.table import Table
|
||
from rich.progress import Progress, SpinnerColumn, TextColumn
|
||
from rich.prompt import Prompt, Confirm
|
||
from rich.syntax import Syntax
|
||
from rich.tree import Tree
|
||
from rich.text import Text
|
||
|
||
# Add HDH to path
|
||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'HDH')))
|
||
|
||
# Import our modules
|
||
from main import HDHDeploymentManager
|
||
from benchmark import HDHBenchmarkSuite
|
||
from circuit_examples import HDHCircuitLibrary
|
||
|
||
# Console for rich output
|
||
console = Console()
|
||
|
||
|
||
class HDHCommandLineInterface:
|
||
"""
|
||
Interactive command-line interface for HDH deployment.
|
||
"""
|
||
|
||
def __init__(self):
|
||
"""Initialize the CLI."""
|
||
self.deployment_manager = None
|
||
self.benchmark_suite = None
|
||
self.circuit_library = HDHCircuitLibrary()
|
||
self.output_dir = "hdh_results"
|
||
|
||
# Display welcome message
|
||
self.show_welcome()
|
||
|
||
def show_welcome(self):
|
||
"""Display welcome message."""
|
||
welcome_text = """
|
||
[bold blue]HDH (Hybrid Dependency Hypergraph) CLI[/bold blue]
|
||
|
||
Interactive interface for quantum circuit analysis and HDH deployment.
|
||
|
||
[italic]Special thanks to Maria Gragera Garces for the HDH library![/italic] 🎉
|
||
"""
|
||
|
||
console.print(Panel(welcome_text.strip(), expand=False, border_style="blue"))
|
||
|
||
def show_main_menu(self) -> str:
|
||
"""Display main menu and get user choice."""
|
||
console.print("\n[bold green]Main Menu[/bold green]")
|
||
console.print("─" * 50)
|
||
|
||
choices = {
|
||
"1": "Process Quantum Circuits",
|
||
"2": "Run Performance Benchmarks",
|
||
"3": "Circuit Library & Examples",
|
||
"4": "Configuration & Settings",
|
||
"5": "View Results & Reports",
|
||
"6": "Help & Documentation",
|
||
"q": "Quit"
|
||
}
|
||
|
||
for key, description in choices.items():
|
||
if key == "q":
|
||
console.print(f"[red]{key}[/red]. {description}")
|
||
else:
|
||
console.print(f"[cyan]{key}[/cyan]. {description}")
|
||
|
||
return Prompt.ask("\nSelect an option", choices=list(choices.keys()), default="1")
|
||
|
||
def process_circuits_menu(self):
|
||
"""Handle circuit processing menu."""
|
||
console.print("\n[bold yellow]Circuit Processing[/bold yellow]")
|
||
|
||
# Initialize deployment manager if needed
|
||
if not self.deployment_manager:
|
||
output_dir = Prompt.ask("Output directory", default=self.output_dir)
|
||
log_level = Prompt.ask("Log level", choices=["DEBUG", "INFO", "WARNING", "ERROR"], default="INFO")
|
||
|
||
with console.status("[bold green]Initializing HDH deployment manager..."):
|
||
self.deployment_manager = HDHDeploymentManager(output_dir, log_level)
|
||
self.output_dir = output_dir
|
||
|
||
while True:
|
||
console.print("\n[bold]Circuit Processing Options:[/bold]")
|
||
options = {
|
||
"1": "Process Example Circuits",
|
||
"2": "Process QASM File",
|
||
"3": "Run Comprehensive Demo",
|
||
"4": "Custom Circuit Processing",
|
||
"b": "Back to Main Menu"
|
||
}
|
||
|
||
for key, desc in options.items():
|
||
console.print(f" [cyan]{key}[/cyan]. {desc}")
|
||
|
||
choice = Prompt.ask("Select option", choices=list(options.keys()), default="1")
|
||
|
||
if choice == "b":
|
||
break
|
||
elif choice == "1":
|
||
self.process_example_circuits()
|
||
elif choice == "2":
|
||
self.process_qasm_file()
|
||
elif choice == "3":
|
||
self.run_comprehensive_demo()
|
||
elif choice == "4":
|
||
self.custom_circuit_processing()
|
||
|
||
def process_example_circuits(self):
|
||
"""Process example circuits."""
|
||
console.print("\n[bold]Example Circuits[/bold]")
|
||
|
||
# Get available examples
|
||
examples = self.circuit_library.get_all_examples()
|
||
|
||
# Show available circuits
|
||
table = Table(title="Available Example Circuits")
|
||
table.add_column("Name", style="cyan")
|
||
table.add_column("Qubits", justify="right")
|
||
table.add_column("Depth", justify="right")
|
||
table.add_column("Description", style="green")
|
||
|
||
circuit_descriptions = {
|
||
"bell_state": "Entangled Bell state",
|
||
"ghz_3": "3-qubit GHZ state",
|
||
"ghz_4": "4-qubit GHZ state",
|
||
"w_state": "W state superposition",
|
||
"qft_3": "3-qubit Quantum Fourier Transform",
|
||
"qft_4": "4-qubit Quantum Fourier Transform",
|
||
"grover_2": "2-qubit Grover search",
|
||
"deutsch_jozsa": "Deutsch-Jozsa algorithm",
|
||
"teleportation": "Quantum teleportation protocol",
|
||
"error_correction": "3-bit error correction",
|
||
"vqe_ansatz": "VQE variational ansatz",
|
||
"qaoa": "QAOA optimization circuit"
|
||
}
|
||
|
||
for name, circuit in examples.items():
|
||
desc = circuit_descriptions.get(name, "Quantum circuit example")
|
||
table.add_row(name, str(circuit.num_qubits), str(circuit.depth()), desc)
|
||
|
||
console.print(table)
|
||
|
||
# Let user select circuits
|
||
selected = Prompt.ask(
|
||
"\nSelect circuits to process (comma-separated names or 'all')",
|
||
default="bell_state,ghz_3,qft_3"
|
||
)
|
||
|
||
if selected.lower() == "all":
|
||
circuits_to_process = list(examples.items())
|
||
else:
|
||
circuit_names = [name.strip() for name in selected.split(",")]
|
||
circuits_to_process = [(name, examples[name]) for name in circuit_names if name in examples]
|
||
|
||
save_plots = Confirm.ask("Save visualization plots?", default=True)
|
||
|
||
# Process circuits
|
||
results = []
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Processing circuits...", total=len(circuits_to_process))
|
||
|
||
for name, circuit in circuits_to_process:
|
||
progress.update(task, description=f"Processing {name}...")
|
||
result = self.deployment_manager.process_circuit(circuit, save_plots)
|
||
results.append(result)
|
||
progress.advance(task)
|
||
|
||
# Show results
|
||
self.show_processing_results(results)
|
||
|
||
def process_qasm_file(self):
|
||
"""Process a QASM file."""
|
||
console.print("\n[bold]QASM File Processing[/bold]")
|
||
|
||
qasm_file = Prompt.ask("Enter QASM file path")
|
||
|
||
if not Path(qasm_file).exists():
|
||
console.print(f"[red]Error: File '{qasm_file}' not found[/red]")
|
||
return
|
||
|
||
save_plots = Confirm.ask("Save visualization plots?", default=True)
|
||
|
||
with console.status(f"[bold green]Processing {qasm_file}..."):
|
||
result = self.deployment_manager.process_qasm_file(qasm_file, save_plots)
|
||
|
||
self.show_processing_results([result])
|
||
|
||
def run_comprehensive_demo(self):
|
||
"""Run comprehensive demo."""
|
||
console.print("\n[bold]Comprehensive Demo[/bold]")
|
||
console.print("This will process multiple example circuits and generate comprehensive analysis.")
|
||
|
||
if not Confirm.ask("Continue with comprehensive demo?", default=True):
|
||
return
|
||
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Running comprehensive demo...", total=None)
|
||
summary = self.deployment_manager.run_comprehensive_demo()
|
||
progress.update(task, description="Demo completed!")
|
||
|
||
# Show summary
|
||
console.print("\n[bold green]Demo Summary[/bold green]")
|
||
console.print(f"Total processed: {summary['total_processed']}")
|
||
console.print(f"Success rate: {summary['success_rate']:.2%}")
|
||
console.print(f"Average processing time: {summary['average_processing_time']:.3f}s")
|
||
console.print(f"Total nodes processed: {summary['total_nodes_processed']}")
|
||
console.print(f"Duration: {summary['deployment_duration']:.2f}s")
|
||
|
||
def custom_circuit_processing(self):
|
||
"""Custom circuit processing workflow."""
|
||
console.print("\n[bold]Custom Circuit Processing[/bold]")
|
||
console.print("Create custom quantum circuits for HDH analysis.")
|
||
|
||
circuit_types = {
|
||
"1": "Random Circuit",
|
||
"2": "GHZ State (custom size)",
|
||
"3": "QFT (custom size)",
|
||
"4": "Bell State Variants"
|
||
}
|
||
|
||
for key, desc in circuit_types.items():
|
||
console.print(f" [cyan]{key}[/cyan]. {desc}")
|
||
|
||
choice = Prompt.ask("Select circuit type", choices=list(circuit_types.keys()))
|
||
|
||
if choice == "1":
|
||
n_qubits = int(Prompt.ask("Number of qubits", default="4"))
|
||
depth = int(Prompt.ask("Circuit depth", default="8"))
|
||
seed = int(Prompt.ask("Random seed", default="42"))
|
||
|
||
circuit = self.circuit_library.random_circuit(n_qubits, depth, seed)
|
||
circuit.name = f"Custom Random {n_qubits}q {depth}d"
|
||
|
||
elif choice == "2":
|
||
n_qubits = int(Prompt.ask("Number of qubits", default="5"))
|
||
circuit = self.circuit_library.ghz_state(n_qubits)
|
||
|
||
elif choice == "3":
|
||
n_qubits = int(Prompt.ask("Number of qubits", default="4"))
|
||
circuit = self.circuit_library.qft_circuit(n_qubits)
|
||
|
||
elif choice == "4":
|
||
variants = self.circuit_library.bell_state_variants()
|
||
console.print(f"Processing all {len(variants)} Bell state variants...")
|
||
|
||
results = []
|
||
for variant in variants:
|
||
result = self.deployment_manager.process_circuit(variant, True)
|
||
results.append(result)
|
||
|
||
self.show_processing_results(results)
|
||
return
|
||
|
||
save_plots = Confirm.ask("Save visualization plots?", default=True)
|
||
|
||
with console.status(f"Processing {circuit.name}..."):
|
||
result = self.deployment_manager.process_circuit(circuit, save_plots)
|
||
|
||
self.show_processing_results([result])
|
||
|
||
def benchmarking_menu(self):
|
||
"""Handle benchmarking menu."""
|
||
console.print("\n[bold yellow]Performance Benchmarking[/bold yellow]")
|
||
|
||
if not self.benchmark_suite:
|
||
output_dir = Prompt.ask("Benchmark output directory", default="benchmark_results")
|
||
repetitions = int(Prompt.ask("Number of repetitions per test", default="3"))
|
||
|
||
with console.status("[bold green]Initializing benchmark suite..."):
|
||
self.benchmark_suite = HDHBenchmarkSuite(output_dir, repetitions)
|
||
|
||
while True:
|
||
console.print("\n[bold]Benchmarking Options:[/bold]")
|
||
options = {
|
||
"1": "Scalability Benchmark",
|
||
"2": "Algorithm Benchmark",
|
||
"3": "Random Circuit Benchmark",
|
||
"4": "Comprehensive Benchmark",
|
||
"5": "View Benchmark Results",
|
||
"b": "Back to Main Menu"
|
||
}
|
||
|
||
for key, desc in options.items():
|
||
console.print(f" [cyan]{key}[/cyan]. {desc}")
|
||
|
||
choice = Prompt.ask("Select option", choices=list(options.keys()), default="4")
|
||
|
||
if choice == "b":
|
||
break
|
||
elif choice == "1":
|
||
self.run_scalability_benchmark()
|
||
elif choice == "2":
|
||
self.run_algorithm_benchmark()
|
||
elif choice == "3":
|
||
self.run_random_benchmark()
|
||
elif choice == "4":
|
||
self.run_comprehensive_benchmark()
|
||
elif choice == "5":
|
||
self.view_benchmark_results()
|
||
|
||
def run_scalability_benchmark(self):
|
||
"""Run scalability benchmark."""
|
||
console.print("\n[bold]Scalability Benchmark[/bold]")
|
||
console.print("Testing HDH performance across different circuit sizes...")
|
||
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Running scalability benchmark...", total=None)
|
||
results = self.benchmark_suite.run_scalability_benchmark()
|
||
progress.update(task, description="Scalability benchmark completed!")
|
||
|
||
self.show_benchmark_results(results, "Scalability")
|
||
|
||
def run_algorithm_benchmark(self):
|
||
"""Run algorithm benchmark."""
|
||
console.print("\n[bold]Algorithm Benchmark[/bold]")
|
||
console.print("Testing HDH performance on quantum algorithms...")
|
||
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Running algorithm benchmark...", total=None)
|
||
results = self.benchmark_suite.run_algorithm_benchmark()
|
||
progress.update(task, description="Algorithm benchmark completed!")
|
||
|
||
self.show_benchmark_results(results, "Algorithm")
|
||
|
||
def run_random_benchmark(self):
|
||
"""Run random circuit benchmark."""
|
||
console.print("\n[bold]Random Circuit Benchmark[/bold]")
|
||
|
||
max_qubits = int(Prompt.ask("Maximum qubits", default="6"))
|
||
max_depth = int(Prompt.ask("Maximum depth", default="20"))
|
||
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Running random circuit benchmark...", total=None)
|
||
results = self.benchmark_suite.run_random_circuit_benchmark(max_qubits, max_depth)
|
||
progress.update(task, description="Random circuit benchmark completed!")
|
||
|
||
self.show_benchmark_results(results, "Random Circuit")
|
||
|
||
def run_comprehensive_benchmark(self):
|
||
"""Run comprehensive benchmark."""
|
||
console.print("\n[bold]Comprehensive Benchmark[/bold]")
|
||
console.print("Running all benchmark suites and generating analysis...")
|
||
|
||
if not Confirm.ask("This may take several minutes. Continue?", default=True):
|
||
return
|
||
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
console=console
|
||
) as progress:
|
||
task = progress.add_task("Running comprehensive benchmark...", total=None)
|
||
report = self.benchmark_suite.run_full_benchmark()
|
||
progress.update(task, description="Comprehensive benchmark completed!")
|
||
|
||
# Show comprehensive report
|
||
console.print("\n[bold green]Comprehensive Benchmark Report[/bold green]")
|
||
|
||
if "error" not in report:
|
||
summary = report["benchmark_summary"]
|
||
perf_stats = report["performance_statistics"]
|
||
|
||
table = Table(title="Benchmark Summary")
|
||
table.add_column("Metric", style="cyan")
|
||
table.add_column("Value", style="green")
|
||
|
||
table.add_row("Total Circuits", str(summary['total_circuits']))
|
||
table.add_row("Success Rate", "100%")
|
||
table.add_row("Avg Conversion Time", f"{perf_stats['conversion_time']['mean']:.4f}s")
|
||
table.add_row("Avg Memory Usage", f"{perf_stats['memory_usage']['mean']:.2f}MB")
|
||
table.add_row("Largest Circuit", f"{report['scalability_analysis']['largest_circuit_qubits']} qubits")
|
||
table.add_row("Total Time", f"{summary.get('total_benchmark_time', 0):.2f}s")
|
||
|
||
console.print(table)
|
||
console.print(f"\nðŸ“<EFBFBD> Results saved in: {self.benchmark_suite.output_dir}")
|
||
else:
|
||
console.print(f"[red]Benchmark failed: {report['error']}[/red]")
|
||
|
||
def circuit_library_menu(self):
|
||
"""Handle circuit library menu."""
|
||
console.print("\n[bold yellow]Circuit Library & Examples[/bold yellow]")
|
||
|
||
while True:
|
||
console.print("\n[bold]Circuit Library Options:[/bold]")
|
||
options = {
|
||
"1": "View Available Circuits",
|
||
"2": "Generate QASM Examples",
|
||
"3": "Create Custom Circuit",
|
||
"4": "Circuit Information",
|
||
"b": "Back to Main Menu"
|
||
}
|
||
|
||
for key, desc in options.items():
|
||
console.print(f" [cyan]{key}[/cyan]. {desc}")
|
||
|
||
choice = Prompt.ask("Select option", choices=list(options.keys()), default="1")
|
||
|
||
if choice == "b":
|
||
break
|
||
elif choice == "1":
|
||
self.view_available_circuits()
|
||
elif choice == "2":
|
||
self.generate_qasm_examples()
|
||
elif choice == "3":
|
||
self.create_custom_circuit()
|
||
elif choice == "4":
|
||
self.show_circuit_information()
|
||
|
||
def view_available_circuits(self):
|
||
"""View available circuits in the library."""
|
||
console.print("\n[bold]Available Quantum Circuits[/bold]")
|
||
|
||
examples = self.circuit_library.get_all_examples()
|
||
|
||
# Create tree structure
|
||
tree = Tree("HDH Circuit Library")
|
||
|
||
# Group circuits by category
|
||
categories = {
|
||
"Basic States": ["bell_state", "ghz_3", "ghz_4", "w_state"],
|
||
"Algorithms": ["qft_3", "qft_4", "grover_2", "deutsch_jozsa"],
|
||
"Protocols": ["teleportation", "error_correction"],
|
||
"Variational": ["vqe_ansatz", "qaoa"],
|
||
"Random": ["random_small", "random_medium"]
|
||
}
|
||
|
||
for category, circuit_names in categories.items():
|
||
category_branch = tree.add(f"[bold blue]{category}[/bold blue]")
|
||
for name in circuit_names:
|
||
if name in examples:
|
||
circuit = examples[name]
|
||
info = f"{name} - {circuit.num_qubits}q, depth {circuit.depth()}"
|
||
category_branch.add(f"[green]{info}[/green]")
|
||
|
||
console.print(tree)
|
||
|
||
# Show benchmark suite info
|
||
benchmark_circuits = self.circuit_library.get_benchmark_suite()
|
||
console.print(f"\n[bold]Benchmark Suite:[/bold] {len(benchmark_circuits)} circuits")
|
||
|
||
def generate_qasm_examples(self):
|
||
"""Generate QASM example files."""
|
||
console.print("\n[bold]Generate QASM Examples[/bold]")
|
||
|
||
output_dir = Prompt.ask("Output directory for QASM files", default="qasm_examples")
|
||
|
||
with console.status(f"Generating QASM examples in {output_dir}..."):
|
||
from circuit_examples import save_example_qasm_files
|
||
save_example_qasm_files(output_dir)
|
||
|
||
console.print(f"[green]QASM examples generated in {output_dir}/[/green]")
|
||
|
||
def show_processing_results(self, results: List[Dict[str, Any]]):
|
||
"""Display circuit processing results."""
|
||
console.print("\n[bold green]Processing Results[/bold green]")
|
||
|
||
table = Table(title="Circuit Processing Summary")
|
||
table.add_column("Circuit", style="cyan")
|
||
table.add_column("Status", style="green")
|
||
table.add_column("Nodes", justify="right")
|
||
table.add_column("Edges", justify="right")
|
||
table.add_column("Time (s)", justify="right")
|
||
|
||
for result in results:
|
||
status = "✅ Success" if result['success'] else "â<EFBFBD>Œ Failed"
|
||
if result['success']:
|
||
table.add_row(
|
||
result['circuit_name'],
|
||
status,
|
||
str(result['hdh_stats']['nodes']),
|
||
str(result['hdh_stats']['edges']),
|
||
f"{result['processing_time']:.3f}"
|
||
)
|
||
else:
|
||
table.add_row(
|
||
result['circuit_name'],
|
||
status,
|
||
"-", "-",
|
||
f"{result['processing_time']:.3f}"
|
||
)
|
||
|
||
console.print(table)
|
||
|
||
# Show output directory
|
||
console.print(f"\nðŸ“<EFBFBD> Results saved in: {self.output_dir}")
|
||
|
||
def show_benchmark_results(self, results: List, benchmark_type: str):
|
||
"""Display benchmark results."""
|
||
console.print(f"\n[bold green]{benchmark_type} Benchmark Results[/bold green]")
|
||
|
||
if not results:
|
||
console.print("[red]No results to display[/red]")
|
||
return
|
||
|
||
table = Table(title=f"{benchmark_type} Performance")
|
||
table.add_column("Circuit", style="cyan")
|
||
table.add_column("Qubits", justify="right")
|
||
table.add_column("Conversion (s)", justify="right")
|
||
table.add_column("Memory (MB)", justify="right")
|
||
table.add_column("HDH Nodes", justify="right")
|
||
|
||
for result in results:
|
||
if result.success:
|
||
table.add_row(
|
||
result.circuit_name,
|
||
str(result.num_qubits),
|
||
f"{result.conversion_time:.4f}",
|
||
f"{result.memory_peak_mb:.2f}",
|
||
str(result.hdh_nodes)
|
||
)
|
||
|
||
console.print(table)
|
||
|
||
def configuration_menu(self):
|
||
"""Handle configuration menu."""
|
||
console.print("\n[bold yellow]Configuration & Settings[/bold yellow]")
|
||
|
||
console.print("Current settings:")
|
||
console.print(f" Output directory: [cyan]{self.output_dir}[/cyan]")
|
||
|
||
if self.deployment_manager:
|
||
console.print(" Deployment manager: [green]Initialized[/green]")
|
||
else:
|
||
console.print(" Deployment manager: [red]Not initialized[/red]")
|
||
|
||
if self.benchmark_suite:
|
||
console.print(" Benchmark suite: [green]Initialized[/green]")
|
||
else:
|
||
console.print(" Benchmark suite: [red]Not initialized[/red]")
|
||
|
||
# Configuration options
|
||
if Confirm.ask("\nUpdate output directory?", default=False):
|
||
self.output_dir = Prompt.ask("New output directory", default=self.output_dir)
|
||
# Reset managers to pick up new directory
|
||
self.deployment_manager = None
|
||
self.benchmark_suite = None
|
||
|
||
def view_results_menu(self):
|
||
"""Handle results viewing menu."""
|
||
console.print("\n[bold yellow]View Results & Reports[/bold yellow]")
|
||
|
||
# Look for result files
|
||
result_dirs = [
|
||
Path(self.output_dir),
|
||
Path("hdh_results"),
|
||
Path("benchmark_results")
|
||
]
|
||
|
||
found_results = []
|
||
for result_dir in result_dirs:
|
||
if result_dir.exists():
|
||
json_files = list(result_dir.glob("*.json"))
|
||
png_files = list(result_dir.glob("*.png"))
|
||
found_results.append((result_dir, json_files, png_files))
|
||
|
||
if not found_results:
|
||
console.print("[red]No result files found[/red]")
|
||
return
|
||
|
||
# Display found results
|
||
for result_dir, json_files, png_files in found_results:
|
||
console.print(f"\n[bold]Results in {result_dir}:[/bold]")
|
||
|
||
if json_files:
|
||
console.print(" [cyan]JSON Reports:[/cyan]")
|
||
for json_file in json_files:
|
||
console.print(f" • {json_file.name}")
|
||
|
||
if png_files:
|
||
console.print(" [cyan]Visualizations:[/cyan]")
|
||
for png_file in png_files:
|
||
console.print(f" • {png_file.name}")
|
||
|
||
# Option to view specific files
|
||
if Confirm.ask("\nView a specific JSON report?", default=False):
|
||
all_json = []
|
||
for _, json_files, _ in found_results:
|
||
all_json.extend(json_files)
|
||
|
||
if all_json:
|
||
file_choices = {str(i+1): f.name for i, f in enumerate(all_json)}
|
||
file_choices["b"] = "Back"
|
||
|
||
console.print("\nAvailable JSON reports:")
|
||
for key, filename in file_choices.items():
|
||
console.print(f" [cyan]{key}[/cyan]. {filename}")
|
||
|
||
choice = Prompt.ask("Select file", choices=list(file_choices.keys()))
|
||
|
||
if choice != "b":
|
||
selected_file = all_json[int(choice) - 1]
|
||
self.view_json_report(selected_file)
|
||
|
||
def view_json_report(self, json_file: Path):
|
||
"""View a JSON report file."""
|
||
try:
|
||
with open(json_file, 'r') as f:
|
||
data = json.load(f)
|
||
|
||
# Pretty print JSON with syntax highlighting
|
||
json_str = json.dumps(data, indent=2)
|
||
syntax = Syntax(json_str, "json", theme="monokai", line_numbers=True)
|
||
|
||
console.print(f"\n[bold]Contents of {json_file.name}:[/bold]")
|
||
console.print(syntax)
|
||
|
||
except Exception as e:
|
||
console.print(f"[red]Error reading {json_file}: {str(e)}[/red]")
|
||
|
||
def help_menu(self):
|
||
"""Display help and documentation."""
|
||
console.print("\n[bold yellow]Help & Documentation[/bold yellow]")
|
||
|
||
help_text = """
|
||
[bold blue]HDH CLI Help[/bold blue]
|
||
|
||
[bold]About HDH:[/bold]
|
||
HDH (Hybrid Dependency Hypergraph) is a library for representing and analyzing
|
||
quantum circuits using hypergraph structures. It enables:
|
||
• Circuit conversion from multiple quantum frameworks
|
||
• Dependency analysis and visualization
|
||
• Circuit partitioning and optimization
|
||
• Performance benchmarking
|
||
|
||
[bold]Main Features:[/bold]
|
||
1. [cyan]Circuit Processing[/cyan] - Convert and analyze quantum circuits
|
||
2. [cyan]Benchmarking[/cyan] - Measure HDH performance across different circuits
|
||
3. [cyan]Circuit Library[/cyan] - Access pre-built quantum circuit examples
|
||
4. [cyan]Configuration[/cyan] - Customize settings and output directories
|
||
5. [cyan]Results Viewing[/cyan] - Examine processing results and reports
|
||
|
||
[bold]Supported Circuit Types:[/bold]
|
||
• Qiskit QuantumCircuit objects
|
||
• OpenQASM 2.0 files
|
||
• Pre-built examples (Bell states, GHZ, QFT, Grover, etc.)
|
||
|
||
[bold]Output Files:[/bold]
|
||
• JSON reports with detailed metrics
|
||
• PNG visualizations of HDH structures
|
||
• Performance benchmark plots
|
||
• Processing logs
|
||
|
||
[bold]Tips:[/bold]
|
||
• Start with small circuits (< 8 qubits) for faster processing
|
||
• Use the comprehensive demo for a full overview
|
||
• Enable plot saving to visualize HDH structures
|
||
• Run benchmarks to understand performance characteristics
|
||
|
||
[italic]Special thanks to Maria Gragera Garces for the HDH library![/italic]
|
||
"""
|
||
|
||
console.print(Panel(help_text.strip(), expand=False, border_style="blue"))
|
||
|
||
if Confirm.ask("\nWould you like to see example usage?", default=False):
|
||
self.show_example_usage()
|
||
|
||
def show_example_usage(self):
|
||
"""Show example usage scenarios."""
|
||
console.print("\n[bold]Example Usage Scenarios[/bold]")
|
||
|
||
examples = [
|
||
{
|
||
"title": "Quick Start - Process Bell State",
|
||
"steps": [
|
||
"1. Select 'Process Quantum Circuits'",
|
||
"2. Choose 'Process Example Circuits'",
|
||
"3. Enter 'bell_state' when prompted",
|
||
"4. Confirm to save plots",
|
||
"5. View results in output directory"
|
||
]
|
||
},
|
||
{
|
||
"title": "Benchmark Suite",
|
||
"steps": [
|
||
"1. Select 'Run Performance Benchmarks'",
|
||
"2. Choose 'Comprehensive Benchmark'",
|
||
"3. Confirm to run (may take several minutes)",
|
||
"4. View generated performance plots",
|
||
"5. Check benchmark_report.json for detailed metrics"
|
||
]
|
||
},
|
||
{
|
||
"title": "Custom QASM Processing",
|
||
"steps": [
|
||
"1. Select 'Process Quantum Circuits'",
|
||
"2. Choose 'Process QASM File'",
|
||
"3. Enter path to your .qasm file",
|
||
"4. Confirm visualization settings",
|
||
"5. Review HDH conversion results"
|
||
]
|
||
}
|
||
]
|
||
|
||
for example in examples:
|
||
console.print(f"\n[bold green]{example['title']}:[/bold green]")
|
||
for step in example['steps']:
|
||
console.print(f" {step}")
|
||
|
||
def create_custom_circuit(self):
|
||
"""Guide for creating custom circuits."""
|
||
console.print("\n[bold]Custom Circuit Creation[/bold]")
|
||
console.print("This feature allows you to create custom quantum circuits programmatically.")
|
||
console.print("For now, use the 'Custom Circuit Processing' option in the main processing menu.")
|
||
|
||
def show_circuit_information(self):
|
||
"""Show detailed information about circuits."""
|
||
console.print("\n[bold]Circuit Information[/bold]")
|
||
|
||
examples = self.circuit_library.get_all_examples()
|
||
circuit_name = Prompt.ask(
|
||
"Enter circuit name for details",
|
||
choices=list(examples.keys()),
|
||
default="bell_state"
|
||
)
|
||
|
||
if circuit_name in examples:
|
||
circuit = examples[circuit_name]
|
||
|
||
info_table = Table(title=f"Circuit Information: {circuit_name}")
|
||
info_table.add_column("Property", style="cyan")
|
||
info_table.add_column("Value", style="green")
|
||
|
||
info_table.add_row("Name", getattr(circuit, 'name', circuit_name))
|
||
info_table.add_row("Qubits", str(circuit.num_qubits))
|
||
info_table.add_row("Classical Bits", str(circuit.num_clbits))
|
||
info_table.add_row("Depth", str(circuit.depth()))
|
||
info_table.add_row("Size (gates)", str(circuit.size()))
|
||
info_table.add_row("Operations", str(len(circuit.data)))
|
||
|
||
console.print(info_table)
|
||
|
||
# Show QASM representation
|
||
if Confirm.ask("Show QASM representation?", default=False):
|
||
try:
|
||
qasm_str = circuit.qasm()
|
||
syntax = Syntax(qasm_str, "qasm", theme="monokai", line_numbers=True)
|
||
console.print(f"\n[bold]QASM for {circuit_name}:[/bold]")
|
||
console.print(syntax)
|
||
except Exception as e:
|
||
console.print(f"[red]Error generating QASM: {str(e)}[/red]")
|
||
|
||
def run(self):
|
||
"""Main CLI loop."""
|
||
try:
|
||
while True:
|
||
choice = self.show_main_menu()
|
||
|
||
if choice == "q":
|
||
console.print("\n[bold blue]Thank you for using HDH CLI![/bold blue]")
|
||
console.print("[italic]Special thanks to Maria Gragera Garces! 🎉[/italic]")
|
||
break
|
||
elif choice == "1":
|
||
self.process_circuits_menu()
|
||
elif choice == "2":
|
||
self.benchmarking_menu()
|
||
elif choice == "3":
|
||
self.circuit_library_menu()
|
||
elif choice == "4":
|
||
self.configuration_menu()
|
||
elif choice == "5":
|
||
self.view_results_menu()
|
||
elif choice == "6":
|
||
self.help_menu()
|
||
|
||
except KeyboardInterrupt:
|
||
console.print("\n[yellow]Goodbye![/yellow]")
|
||
except Exception as e:
|
||
console.print(f"\n[red]An error occurred: {str(e)}[/red]")
|
||
|
||
|
||
@click.command()
|
||
@click.option('--output-dir', default='hdh_results', help='Default output directory')
|
||
@click.option('--theme', default='default', help='Console theme')
|
||
def main(output_dir, theme):
|
||
"""
|
||
HDH Command Line Interface
|
||
|
||
Interactive CLI for HDH (Hybrid Dependency Hypergraph) deployment and analysis.
|
||
"""
|
||
try:
|
||
cli = HDHCommandLineInterface()
|
||
cli.output_dir = output_dir
|
||
cli.run()
|
||
except Exception as e:
|
||
console.print(f"[red]Failed to start CLI: {str(e)}[/red]")
|
||
sys.exit(1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |