""" NVIDIA CUDA-Q VQE Demo ===================== This Gradio application demonstrates the Variational Quantum Eigensolver (VQE) algorithm using NVIDIA's CUDA Quantum library. The demo allows users to: 1. Select from available molecules 2. Adjust bond length parameters 3. Run VQE simulations with real-time visualization 4. View energy convergence and molecular structure in 3D Running the Demo --------------- 1. Ensure you have all dependencies installed: ```bash pip install -r requirements.txt ``` 2. Launch the application: ```bash python app.py ``` 3. Open your browser to the local URL displayed in the terminal (typically http://localhost:7860) Using the Interface ----------------- - Select a molecule from the dropdown - Adjust bond length using the slider (0.5 to 2.5 Å) - Click "Run VQE Simulation" or watch real-time updates as you adjust parameters - View results in three panels: * Simulation Results: Shows final energy and optimization status * VQE Convergence: Plots energy vs. iteration * Molecule Visualization: 3D representation of the molecule GPU Acceleration -------------- The app automatically detects if NVIDIA GPUs are available: - With GPU: Uses CUDA-Q's nvidia backend for acceleration - Without GPU: Falls back to CPU-based quantum simulation References --------- - Installation: See Cuda-Q_install.md - VQE Implementation: See VQE_Example.md - Project Structure: See quantum-demo-blueprint.md """ import spaces from gradio_client import Client from gradio.routes import Request as gr_Request import subprocess import sys import json import os import logging from logging.handlers import RotatingFileHandler import gradio as gr import numpy as np from quantum_utils import run_vqe_simulation from visualization import plot_convergence, create_molecule_viewer, format_molecule_params import plotly.graph_objects as go # Configure logging os.makedirs('logs', exist_ok=True) # Create formatters file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_formatter = logging.Formatter('%(levelname)s - %(message)s') # Set up file handler with rotation file_handler = RotatingFileHandler( 'logs/vqe_simulation.log', maxBytes=1024 * 1024, # 1MB per file backupCount=3 # Keep 3 backup files ) file_handler.setFormatter(file_formatter) file_handler.setLevel(logging.DEBUG) # Set up console handler with less verbose output console_handler = logging.StreamHandler() console_handler.setFormatter(console_formatter) console_handler.setLevel(logging.INFO) # Only show INFO and above in console # Configure root logger logger = logging.getLogger() logger.setLevel(logging.DEBUG) # Remove any existing handlers for handler in logger.handlers[:]: logger.removeHandler(handler) # Add our handlers logger.addHandler(file_handler) logger.addHandler(console_handler) # Disable other loggers that might be too verbose logging.getLogger('httpcore.http11').setLevel(logging.WARNING) logging.getLogger('httpx').setLevel(logging.WARNING) logging.getLogger('gradio').setLevel(logging.WARNING) # Log startup message logger.info("VQE Demo Application Starting") def install_dependencies(): print("""Install required packages from requirements.txt.""") try: subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]) print("Dependencies installed successfully") except subprocess.CalledProcessError as e: print(f"Error installing dependencies: {e}") sys.exit(1) # Test if cudaq is already installed try: import cudaq print("CUDA-Q already installed, skipping dependency installation") except ImportError: print("CUDA-Q not found, installing dependencies...") # Run installation before any other imports install_dependencies() # Load molecule definitions def load_molecules(): """Load molecule definitions from JSON file.""" try: with open('molecules.json', 'r') as f: all_molecules = json.load(f) # Filter to only include enabled molecules enabled_molecules = {k: v for k, v in all_molecules.items() if v.get('enabled', 0) == 1} if not enabled_molecules: print("Warning: No enabled molecules found in molecules.json", file=sys.stderr) return enabled_molecules except Exception as e: print(f"Error loading molecules.json: {e}", file=sys.stderr) return {} # Now import the rest of the modules print("about to import numpy and quantum_utils", file=sys.stderr, flush=True) import numpy as np from quantum_utils import run_vqe_simulation from visualization import plot_convergence, create_molecule_viewer, format_molecule_params # Add immediate logging print("Imported all modules successfully", file=sys.stderr, flush=True) def update_simulation(molecule_choice: str, scale_factor: float) -> tuple: """ Run VQE simulation and update visualizations. Args: molecule_choice: Selected molecule from available options scale_factor: Factor to scale the molecule geometry by (1.0 = original size) Returns: Tuple of (energy text, convergence plot, molecule HTML) """ print("UPDATE_SIMULATION CALLED", file=sys.stderr, flush=True) try: # Get molecule data molecules = load_molecules() if molecule_choice not in molecules: raise ValueError(f"Unknown molecule: {molecule_choice}") molecule_data = molecules[molecule_choice] print(f"Starting simulation with molecule: {molecule_choice}, scale: {scale_factor}", file=sys.stderr, flush=True) # Run VQE simulation results = run_vqe_simulation( molecule_data=molecule_data, scale_factor=scale_factor ) print(f"VQE simulation completed with results: {results}", file=sys.stderr, flush=True) # Create plots print("Creating convergence plot...", file=sys.stderr) convergence_plot = plot_convergence(results) print("Convergence plot created", file=sys.stderr) print("Creating molecule visualization...", file=sys.stderr) molecule_html = create_molecule_viewer(molecule_choice, scale_factor) print("Molecule visualization created", file=sys.stderr) # Format energy output energy_text = f""" Final Energy: {results['final_energy']:.6f} Hartree Optimization Status: {'Success' if results['success'] else 'Failed'} Message: {results['message']} Number of Iterations: {len(results['history'])} Scale Factor: {scale_factor:.2f} """ print("Returning results...", file=sys.stderr) return energy_text, convergence_plot, molecule_html except Exception as e: import traceback error_msg = f"Error in simulation:\n{str(e)}\n\nTraceback:\n{traceback.format_exc()}" print(error_msg, file=sys.stderr) # This will show in the server logs return error_msg, None, None def create_interface(): """Create the Gradio interface for the VQE demo.""" def set_client_for_session(request: gr.Request): """Initialize client with user's IP token to handle rate limiting.""" logger.info(f"Setting client for session with request: {request}") try: # Try to initialize client with HF token from environment variable client = Client("A19grey/Cuda-Quantum-Molecular-Playground", hf_token=os.getenv("HF_TOKEN")) logger.info(f"Client initialized with A19grey HF token") return client except Exception as e: logger.error(f"Error setting client with HF token: {e}") try: # Fallback to using x-ip-token from request headers x_ip_token = request.headers['x-ip-token'] logger.info(f"Client initialized with x-ip-token from request headers") return Client("A19grey/Cuda-Quantum-Molecular-Playground", headers={"x-ip-token": x_ip_token}) except Exception as e: logger.error(f"Error setting client with x-ip-token: {e}") return None # Load available molecules molecules = load_molecules() if not molecules: raise ValueError("No molecules found in molecules.json") with gr.Blocks(title="CUDA-Q VQE Demo") as demo: gr.Markdown(""" # 🔬 NVIDIA CUDA-Q VQE Demo This demo harnesses the power of **NVIDIA's GPU-accelerated CUDA Quantum** library to simulate quantum systems on classical hardware. The process works in two steps: 1. 📊 Generate the [Hamiltonian](https://quantumfrontiers.com/2017/01/31/hamiltonian-an-american-musical-without-americana-or-music/) - *the mathematical description of the system's energy* 2. ⚛️ Use the **Variational Quantum Eigensolver (VQE)** algorithm to calculate the ground state energy ## How to Use > 🔍 Select a molecule below, adjust its parameters, and watch as the simulation computes the lowest > possible energy state using quantum-inspired algorithms accelerated by NVIDIA GPUs. ## Important Note ⚠️ Even for small molecules, the quantum circuits can become quite complex. In this demo, we show only the first terms. > 💡 **Pro Tip:** In real-world applications, even with GPU acceleration, scientists use more advanced methods > that focus on simulating only outer shell electrons for practical quantum chemistry calculations. --- *Inspired by the [NVIDIA CUDA-Q VQE Example](https://nvidia.github.io/cuda-quantum/latest/applications/python/vqe_advanced.html)* """) client = gr.State() state = gr.State({}) # Top section: 3 columns with gr.Row(): with gr.Column(scale=1): molecule_choice = gr.Dropdown( choices=list(molecules.keys()), value=None, label="Select Molecule", interactive=True, allow_custom_value=False ) default_molecule = molecules[list(molecules.keys())[0]] scale_factor = gr.Slider( minimum=default_molecule['scale_range']['min'], maximum=default_molecule['scale_range']['max'], value=default_molecule['default_scale'], step=default_molecule['scale_range']['step'], label="Scale Factor (1.0 = original size)", interactive=True ) with gr.Column(scale=1): params_display = gr.HTML( label="Molecule Parameters", value="
Ready to run VQE optimization.
{results.get('circuit_latex', 'Circuit visualization not available').replace('`', '`')}
{results['message']}