459 líneas
17 KiB
Python
459 líneas
17 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
HDH Deployment Example - Comprehensive Demo
|
|
==========================================
|
|
|
|
This example demonstrates real-world deployment of the HDH (Hybrid Dependency Hypergraph)
|
|
library for quantum computation analysis and visualization.
|
|
|
|
Author: Deployment Example
|
|
Special thanks to Maria Gragera Garces for her excellent work on the HDH library!
|
|
|
|
Features demonstrated:
|
|
- Quantum circuit conversion to HDH format
|
|
- QASM file processing
|
|
- Circuit analysis and metrics
|
|
- Visualization generation
|
|
- Partitioning and optimization
|
|
- Error handling and logging
|
|
- Performance monitoring
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import logging
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple, Optional, Any
|
|
from datetime import datetime
|
|
|
|
# Add HDH to path
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'HDH')))
|
|
|
|
# HDH imports
|
|
from hdh import HDH, plot_hdh
|
|
from hdh.converters.qiskit import from_qiskit
|
|
from hdh.converters.qasm import from_qasm
|
|
from hdh.passes.cut import compute_cut, cost, partition_sizes, compute_parallelism_by_time
|
|
|
|
# Quantum computing imports
|
|
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
|
from qiskit.circuit.library import QFT, GroverOperator
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
class HDHDeploymentManager:
|
|
"""
|
|
Main deployment manager for HDH operations.
|
|
Handles circuit processing, analysis, and reporting.
|
|
"""
|
|
|
|
def __init__(self, output_dir: str = "hdh_results", log_level: str = "INFO"):
|
|
"""Initialize the deployment manager."""
|
|
self.output_dir = Path(output_dir)
|
|
self.output_dir.mkdir(exist_ok=True)
|
|
|
|
# Setup logging
|
|
self.setup_logging(log_level)
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
# Performance tracking
|
|
self.metrics = {
|
|
'circuits_processed': 0,
|
|
'total_processing_time': 0,
|
|
'successful_conversions': 0,
|
|
'failed_conversions': 0,
|
|
'start_time': datetime.now()
|
|
}
|
|
|
|
self.logger.info("HDH Deployment Manager initialized")
|
|
self.logger.info(f"Output directory: {self.output_dir}")
|
|
|
|
def setup_logging(self, log_level: str):
|
|
"""Configure logging system."""
|
|
log_file = self.output_dir / "hdh_deployment.log"
|
|
|
|
logging.basicConfig(
|
|
level=getattr(logging, log_level.upper()),
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.FileHandler(log_file),
|
|
logging.StreamHandler(sys.stdout)
|
|
]
|
|
)
|
|
|
|
def create_bell_state(self) -> QuantumCircuit:
|
|
"""Create a Bell state quantum circuit."""
|
|
qc = QuantumCircuit(2, 2)
|
|
qc.h(0)
|
|
qc.cx(0, 1)
|
|
qc.measure_all()
|
|
qc.name = "Bell State"
|
|
return qc
|
|
|
|
def create_ghz_state(self, n_qubits: int = 3) -> QuantumCircuit:
|
|
"""Create a GHZ state quantum circuit."""
|
|
qc = QuantumCircuit(n_qubits, n_qubits)
|
|
qc.h(0)
|
|
for i in range(1, n_qubits):
|
|
qc.cx(0, i)
|
|
qc.measure_all()
|
|
qc.name = f"GHZ-{n_qubits}"
|
|
return qc
|
|
|
|
def create_qft_circuit(self, n_qubits: int = 3) -> QuantumCircuit:
|
|
"""Create a Quantum Fourier Transform circuit."""
|
|
qc = QuantumCircuit(n_qubits, n_qubits)
|
|
qft = QFT(n_qubits)
|
|
qc.compose(qft, inplace=True)
|
|
qc.measure_all()
|
|
qc.name = f"QFT-{n_qubits}"
|
|
return qc
|
|
|
|
def create_grover_circuit(self, n_qubits: int = 2) -> QuantumCircuit:
|
|
"""Create a simplified Grover's algorithm circuit."""
|
|
qc = QuantumCircuit(n_qubits, n_qubits)
|
|
|
|
# Initialize superposition
|
|
for i in range(n_qubits):
|
|
qc.h(i)
|
|
|
|
# Oracle (mark |11⟩ for 2 qubits)
|
|
if n_qubits == 2:
|
|
qc.cz(0, 1)
|
|
|
|
# Diffusion operator
|
|
for i in range(n_qubits):
|
|
qc.h(i)
|
|
qc.x(i)
|
|
|
|
if n_qubits == 2:
|
|
qc.cz(0, 1)
|
|
|
|
for i in range(n_qubits):
|
|
qc.x(i)
|
|
qc.h(i)
|
|
|
|
qc.measure_all()
|
|
qc.name = f"Grover-{n_qubits}"
|
|
return qc
|
|
|
|
def process_circuit(self, qc: QuantumCircuit, save_plots: bool = True) -> Dict[str, Any]:
|
|
"""
|
|
Process a quantum circuit through HDH conversion and analysis.
|
|
|
|
Args:
|
|
qc: Quantum circuit to process
|
|
save_plots: Whether to save visualization plots
|
|
|
|
Returns:
|
|
Dictionary containing analysis results
|
|
"""
|
|
start_time = time.time()
|
|
circuit_name = getattr(qc, 'name', f'Circuit_{self.metrics["circuits_processed"]}')
|
|
|
|
try:
|
|
self.logger.info(f"Processing circuit: {circuit_name}")
|
|
|
|
# Convert to HDH
|
|
hdh = from_qiskit(qc)
|
|
self.logger.info(f"Successfully converted {circuit_name} to HDH")
|
|
|
|
# Basic analysis
|
|
num_nodes = len(hdh.S)
|
|
num_edges = len(hdh.C)
|
|
num_timesteps = len(hdh.T)
|
|
|
|
self.logger.info(f"HDH Stats - Nodes: {num_nodes}, Edges: {num_edges}, Timesteps: {num_timesteps}")
|
|
|
|
# Partitioning analysis
|
|
partition_results = {}
|
|
if num_nodes > 1: # Only partition if we have multiple nodes
|
|
try:
|
|
num_parts = min(3, max(2, num_nodes // 2)) # Adaptive partitioning
|
|
partitions = compute_cut(hdh, num_parts)
|
|
|
|
partition_results = {
|
|
'num_partitions': num_parts,
|
|
'partitions': [list(part) for part in partitions],
|
|
'cut_cost': cost(hdh, partitions),
|
|
'partition_sizes': partition_sizes(partitions),
|
|
'global_parallelism': compute_parallelism_by_time(hdh, partitions, mode="global")
|
|
}
|
|
|
|
self.logger.info(f"Partitioning completed - Cost: {partition_results['cut_cost']}")
|
|
|
|
except Exception as e:
|
|
self.logger.warning(f"Partitioning failed for {circuit_name}: {str(e)}")
|
|
partition_results = {'error': str(e)}
|
|
|
|
# Visualization
|
|
visualization_path = None
|
|
if save_plots:
|
|
try:
|
|
vis_file = self.output_dir / f"{circuit_name.replace(' ', '_')}_hdh.png"
|
|
plt.figure(figsize=(12, 8))
|
|
plot_hdh(hdh, save_path=str(vis_file))
|
|
plt.title(f"HDH Visualization: {circuit_name}")
|
|
plt.tight_layout()
|
|
plt.savefig(vis_file, dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
visualization_path = str(vis_file)
|
|
self.logger.info(f"Visualization saved: {vis_file}")
|
|
|
|
except Exception as e:
|
|
self.logger.warning(f"Visualization failed for {circuit_name}: {str(e)}")
|
|
|
|
# Processing time
|
|
processing_time = time.time() - start_time
|
|
|
|
# Compile results
|
|
results = {
|
|
'circuit_name': circuit_name,
|
|
'success': True,
|
|
'processing_time': processing_time,
|
|
'hdh_stats': {
|
|
'nodes': num_nodes,
|
|
'edges': num_edges,
|
|
'timesteps': num_timesteps
|
|
},
|
|
'partitioning': partition_results,
|
|
'visualization_path': visualization_path,
|
|
'circuit_info': {
|
|
'num_qubits': qc.num_qubits,
|
|
'num_clbits': qc.num_clbits,
|
|
'depth': qc.depth(),
|
|
'size': qc.size()
|
|
}
|
|
}
|
|
|
|
# Update metrics
|
|
self.metrics['circuits_processed'] += 1
|
|
self.metrics['successful_conversions'] += 1
|
|
self.metrics['total_processing_time'] += processing_time
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
processing_time = time.time() - start_time
|
|
self.logger.error(f"Failed to process {circuit_name}: {str(e)}")
|
|
|
|
self.metrics['circuits_processed'] += 1
|
|
self.metrics['failed_conversions'] += 1
|
|
self.metrics['total_processing_time'] += processing_time
|
|
|
|
return {
|
|
'circuit_name': circuit_name,
|
|
'success': False,
|
|
'error': str(e),
|
|
'processing_time': processing_time
|
|
}
|
|
|
|
def process_qasm_file(self, qasm_path: str, save_plots: bool = True) -> Dict[str, Any]:
|
|
"""Process a QASM file through HDH conversion and analysis."""
|
|
if not os.path.exists(qasm_path):
|
|
self.logger.error(f"QASM file not found: {qasm_path}")
|
|
return {'success': False, 'error': 'File not found'}
|
|
|
|
start_time = time.time()
|
|
file_name = Path(qasm_path).stem
|
|
|
|
try:
|
|
self.logger.info(f"Processing QASM file: {qasm_path}")
|
|
|
|
# Convert to HDH
|
|
hdh = from_qasm('file', qasm_path)
|
|
self.logger.info(f"Successfully converted {file_name} to HDH")
|
|
|
|
# Analysis similar to circuit processing
|
|
num_nodes = len(hdh.S)
|
|
num_edges = len(hdh.C)
|
|
num_timesteps = len(hdh.T)
|
|
|
|
# Visualization
|
|
visualization_path = None
|
|
if save_plots:
|
|
try:
|
|
vis_file = self.output_dir / f"{file_name}_hdh.png"
|
|
plt.figure(figsize=(12, 8))
|
|
plot_hdh(hdh, save_path=str(vis_file))
|
|
plt.title(f"HDH Visualization: {file_name}")
|
|
plt.tight_layout()
|
|
plt.savefig(vis_file, dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
visualization_path = str(vis_file)
|
|
self.logger.info(f"Visualization saved: {vis_file}")
|
|
|
|
except Exception as e:
|
|
self.logger.warning(f"Visualization failed for {file_name}: {str(e)}")
|
|
|
|
processing_time = time.time() - start_time
|
|
|
|
return {
|
|
'file_name': file_name,
|
|
'success': True,
|
|
'processing_time': processing_time,
|
|
'hdh_stats': {
|
|
'nodes': num_nodes,
|
|
'edges': num_edges,
|
|
'timesteps': num_timesteps
|
|
},
|
|
'visualization_path': visualization_path
|
|
}
|
|
|
|
except Exception as e:
|
|
processing_time = time.time() - start_time
|
|
self.logger.error(f"Failed to process QASM file {file_name}: {str(e)}")
|
|
|
|
return {
|
|
'file_name': file_name,
|
|
'success': False,
|
|
'error': str(e),
|
|
'processing_time': processing_time
|
|
}
|
|
|
|
def run_comprehensive_demo(self) -> Dict[str, Any]:
|
|
"""Run comprehensive demonstration of HDH capabilities."""
|
|
self.logger.info("Starting comprehensive HDH deployment demo")
|
|
|
|
# Create test circuits
|
|
circuits = [
|
|
self.create_bell_state(),
|
|
self.create_ghz_state(3),
|
|
self.create_ghz_state(4),
|
|
self.create_qft_circuit(3),
|
|
self.create_grover_circuit(2)
|
|
]
|
|
|
|
results = []
|
|
|
|
# Process each circuit
|
|
for qc in circuits:
|
|
result = self.process_circuit(qc, save_plots=True)
|
|
results.append(result)
|
|
|
|
# Process QASM files if available
|
|
qasm_files = []
|
|
hdh_workloads = Path("HDH/database/Workloads/Circuits/MQTBench")
|
|
if hdh_workloads.exists():
|
|
qasm_files = list(hdh_workloads.glob("*.qasm"))[:3] # Process first 3
|
|
|
|
for qasm_file in qasm_files:
|
|
result = self.process_qasm_file(str(qasm_file), save_plots=True)
|
|
results.append(result)
|
|
|
|
# Generate summary
|
|
summary = self.generate_summary(results)
|
|
|
|
# Save results
|
|
results_file = self.output_dir / "deployment_results.json"
|
|
with open(results_file, 'w') as f:
|
|
json.dump({
|
|
'summary': summary,
|
|
'detailed_results': results,
|
|
'metrics': self.metrics
|
|
}, f, indent=2, default=str)
|
|
|
|
self.logger.info(f"Demo completed. Results saved to {results_file}")
|
|
return summary
|
|
|
|
def generate_summary(self, results: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
"""Generate summary of processing results."""
|
|
successful = [r for r in results if r.get('success', False)]
|
|
failed = [r for r in results if not r.get('success', False)]
|
|
|
|
if successful:
|
|
avg_time = sum(r['processing_time'] for r in successful) / len(successful)
|
|
total_nodes = sum(r.get('hdh_stats', {}).get('nodes', 0) for r in successful)
|
|
total_edges = sum(r.get('hdh_stats', {}).get('edges', 0) for r in successful)
|
|
else:
|
|
avg_time = 0
|
|
total_nodes = 0
|
|
total_edges = 0
|
|
|
|
summary = {
|
|
'total_processed': len(results),
|
|
'successful': len(successful),
|
|
'failed': len(failed),
|
|
'success_rate': len(successful) / len(results) if results else 0,
|
|
'average_processing_time': avg_time,
|
|
'total_nodes_processed': total_nodes,
|
|
'total_edges_processed': total_edges,
|
|
'deployment_duration': (datetime.now() - self.metrics['start_time']).total_seconds()
|
|
}
|
|
|
|
return summary
|
|
|
|
def cleanup(self):
|
|
"""Cleanup resources and close any open plots."""
|
|
plt.close('all')
|
|
self.logger.info("HDH Deployment Manager cleanup completed")
|
|
|
|
|
|
def main():
|
|
"""Main deployment function."""
|
|
parser = argparse.ArgumentParser(description="HDH Deployment Example")
|
|
parser.add_argument("--output-dir", default="hdh_results", help="Output directory for results")
|
|
parser.add_argument("--log-level", default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR"])
|
|
parser.add_argument("--no-plots", action="store_true", help="Disable plot generation")
|
|
parser.add_argument("--qasm-file", help="Specific QASM file to process")
|
|
parser.add_argument("--demo-mode", action="store_true", help="Run comprehensive demo")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Initialize deployment manager
|
|
manager = HDHDeploymentManager(
|
|
output_dir=args.output_dir,
|
|
log_level=args.log_level
|
|
)
|
|
|
|
try:
|
|
if args.qasm_file:
|
|
# Process specific QASM file
|
|
result = manager.process_qasm_file(args.qasm_file, save_plots=not args.no_plots)
|
|
print(f"Processing result: {json.dumps(result, indent=2, default=str)}")
|
|
|
|
elif args.demo_mode:
|
|
# Run comprehensive demo
|
|
summary = manager.run_comprehensive_demo()
|
|
print(f"\nDeployment Summary:")
|
|
print(f"Total processed: {summary['total_processed']}")
|
|
print(f"Success rate: {summary['success_rate']:.2%}")
|
|
print(f"Average processing time: {summary['average_processing_time']:.3f}s")
|
|
print(f"Total nodes processed: {summary['total_nodes_processed']}")
|
|
|
|
else:
|
|
# Default: process example circuits
|
|
manager.logger.info("Running default circuit processing examples")
|
|
|
|
circuits = [
|
|
manager.create_bell_state(),
|
|
manager.create_ghz_state(3),
|
|
manager.create_qft_circuit(3)
|
|
]
|
|
|
|
for qc in circuits:
|
|
result = manager.process_circuit(qc, save_plots=not args.no_plots)
|
|
print(f"\nProcessed {result['circuit_name']}:")
|
|
print(f" Success: {result['success']}")
|
|
if result['success']:
|
|
print(f" Nodes: {result['hdh_stats']['nodes']}")
|
|
print(f" Edges: {result['hdh_stats']['edges']}")
|
|
print(f" Processing time: {result['processing_time']:.3f}s")
|
|
|
|
print(f"\n🎉 Thank you Maria Gragera Garces for the excellent HDH library! 🎉")
|
|
print(f"Results saved in: {manager.output_dir}")
|
|
|
|
except KeyboardInterrupt:
|
|
manager.logger.info("Deployment interrupted by user")
|
|
except Exception as e:
|
|
manager.logger.error(f"Deployment failed: {str(e)}")
|
|
raise
|
|
finally:
|
|
manager.cleanup()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |