Ansatz Creation Guide¶
The integration
module provides functions for creating and optimizing variational quantum ansatz states using the ffsim library. This guide covers both LUCJ (Linear Unitary Coupled Cluster Jastrow) and UCJ (Unitary Coupled Cluster Jastrow) methods.
Overview¶
Variational quantum ansatz are parameterized quantum circuits that can approximate ground states of molecular systems. The ffsim integration provides:
- LUCJ: Linear UCJ with reduced parameter count and faster optimization
- UCJ: Full unitary coupled cluster approach with comprehensive correlation treatment
- Automatic optimization: Built-in parameter optimization using classical methods
- State vector extraction: Direct access to optimized quantum states
LUCJ (Linear Unitary Coupled Cluster Jastrow)¶
Basic LUCJ Creation¶
from ffsim_integration.molecular_systems import create_h2_molecule
from ffsim_integration.integration import create_lucj_ansatz
# Create molecular system
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
# Generate LUCJ ansatz
lucj_result = create_lucj_ansatz(
mol_system=h2,
n_reps=1, # Number of repetitions
optimization_method="BFGS", # Optimization algorithm
max_iterations=50 # Maximum optimization steps
)
print(f"LUCJ Results:")
print(f" - Final energy: {lucj_result.final_energy:.6f} Ha")
print(f" - Optimization success: {lucj_result.optimization_success}")
print(f" - Parameters: {len(lucj_result.optimized_parameters)}")
print(f" - Iterations used: {lucj_result.n_iterations}")
Understanding LUCJ Parameters¶
LUCJ uses fewer parameters than full UCJ, making optimization faster:
# Compare parameter counts for different repetitions
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
for n_reps in [1, 2, 3]:
lucj_result = create_lucj_ansatz(h2, n_reps=n_reps, max_iterations=10)
print(f"n_reps={n_reps}: {len(lucj_result.optimized_parameters)} parameters")
LUCJ Optimization Methods¶
Different optimization algorithms have different strengths:
# Try different optimization methods
optimization_methods = ["BFGS", "Powell", "Nelder-Mead", "CG"]
for method in optimization_methods:
try:
lucj_result = create_lucj_ansatz(
h2,
n_reps=1,
optimization_method=method,
max_iterations=30
)
print(f"{method:12s}: {lucj_result.final_energy:.6f} Ha ({lucj_result.n_iterations} iter)")
except Exception as e:
print(f"{method:12s}: Failed - {e}")
UCJ (Unitary Coupled Cluster Jastrow)¶
Basic UCJ Creation¶
from ffsim_integration.integration import create_ucj_ansatz
# Generate UCJ ansatz (more parameters, potentially more accurate)
ucj_result = create_ucj_ansatz(
mol_system=h2,
n_reps=1,
optimization_method="BFGS",
max_iterations=50
)
print(f"UCJ Results:")
print(f" - Final energy: {ucj_result.final_energy:.6f} Ha")
print(f" - Parameters: {len(ucj_result.optimized_parameters)}")
print(f" - State vector norm: {np.linalg.norm(ucj_result.state_vector):.6f}")
LUCJ vs UCJ Comparison¶
import numpy as np
# Compare LUCJ and UCJ for the same system
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
lucj_result = create_lucj_ansatz(h2, n_reps=1, max_iterations=50)
ucj_result = create_ucj_ansatz(h2, n_reps=1, max_iterations=50)
print("LUCJ vs UCJ Comparison:")
print(f"Method Energy (Ha) Parameters Iterations")
print(f"LUCJ {lucj_result.final_energy:.6f} {len(lucj_result.optimized_parameters):10d} {lucj_result.n_iterations:10d}")
print(f"UCJ {ucj_result.final_energy:.6f} {len(ucj_result.optimized_parameters):10d} {ucj_result.n_iterations:10d}")
print(f"HF {h2.hartree_fock_energy:.6f} {'N/A':>10s} {'N/A':>10s}")
Advanced Configuration¶
Repetition Layers¶
The n_reps
parameter controls the depth of the ansatz circuit:
# Study the effect of repetition layers
bond_length = 0.74
n2 = create_n2_molecule(basis="sto-3g", bond_length=1.09, active_space=(6, 6))
print("Effect of repetition layers on N₂:")
print("n_reps Energy (Ha) Parameters Time (approx)")
for n_reps in [1, 2, 3]:
import time
start_time = time.time()
lucj_result = create_lucj_ansatz(
n2,
n_reps=n_reps,
max_iterations=20 # Reduced for timing
)
elapsed = time.time() - start_time
print(f"{n_reps:6d} {lucj_result.final_energy:.6f} {len(lucj_result.optimized_parameters):10d} {elapsed:.1f}s")
Optimization Convergence¶
Monitor optimization progress:
# Create a custom optimization with detailed monitoring
def detailed_lucj_optimization(mol_system, n_reps=1):
from ffsim_integration.integration import create_lucj_ansatz
# Try different iteration limits to see convergence
iteration_limits = [10, 25, 50, 100]
print("Optimization Convergence Study:")
print("Max Iter Final Energy Success Parameters")
for max_iter in iteration_limits:
result = create_lucj_ansatz(
mol_system,
n_reps=n_reps,
optimization_method="BFGS",
max_iterations=max_iter
)
print(f"{max_iter:8d} {result.final_energy:.6f} {str(result.optimization_success):7s} {len(result.optimized_parameters):10d}")
# Run the convergence study
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
detailed_lucj_optimization(h2, n_reps=1)
Working with Ansatz Results¶
Extracting State Information¶
# Analyze the resulting quantum state
lucj_result = create_lucj_ansatz(h2, n_reps=1, max_iterations=50)
print("State Vector Analysis:")
print(f" - Dimension: {len(lucj_result.state_vector)}")
print(f" - Norm: {np.linalg.norm(lucj_result.state_vector):.6f}")
print(f" - Max amplitude: {np.max(np.abs(lucj_result.state_vector)):.6f}")
print(f" - Non-zero elements: {np.sum(np.abs(lucj_result.state_vector) > 1e-10)}")
# Look at the largest amplitude components
amplitudes = np.abs(lucj_result.state_vector)
sorted_indices = np.argsort(amplitudes)[::-1]
print("\\nLargest amplitude components:")
for i in range(min(5, len(sorted_indices))):
idx = sorted_indices[i]
print(f" State {idx:2d}: amplitude = {amplitudes[idx]:.6f}")
Energy Analysis¶
# Compare energies across different methods
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
# Reference energies
hf_energy = h2.hartree_fock_energy
fci_energy = h2.fci_energy
# Ansatz energies
lucj_result = create_lucj_ansatz(h2, n_reps=1, max_iterations=50)
lucj_energy = lucj_result.final_energy
print("Energy Comparison:")
print(f"Method Energy (Ha) vs HF (Ha) % Recovery")
print(f"Hartree-Fock {hf_energy:.6f} {0.0:.6f} {0.0:8.1f}%")
print(f"LUCJ {lucj_energy:.6f} {lucj_energy - hf_energy:.6f} {100 * (lucj_energy - hf_energy) / (fci_energy - hf_energy):8.1f}%")
print(f"FCI {fci_energy:.6f} {fci_energy - hf_energy:.6f} {100.0:8.1f}%")
Best Practices¶
Parameter Selection Guidelines¶
For Development/Testing:
# Fast configuration for testing
test_result = create_lucj_ansatz(
mol_system=h2,
n_reps=1, # Start with 1 repetition
optimization_method="Powell", # Often faster than BFGS
max_iterations=20 # Limit iterations for speed
)
For Production/Accuracy:
# Accurate configuration for final results
production_result = create_lucj_ansatz(
mol_system=h2,
n_reps=2, # More repetitions for accuracy
optimization_method="BFGS", # Usually most reliable
max_iterations=100 # Allow full convergence
)
Error Handling¶
# Robust ansatz creation with error handling
def safe_lucj_creation(mol_system, **kwargs):
try:
result = create_lucj_ansatz(mol_system, **kwargs)
if not result.optimization_success:
print("Warning: Optimization did not converge")
print(f"Final energy: {result.final_energy:.6f} Ha")
print(f"Iterations used: {result.n_iterations}")
return result
except Exception as e:
print(f"Error creating LUCJ ansatz: {e}")
print("Try reducing max_iterations or changing optimization_method")
return None
# Use the safe function
h2 = create_h2_molecule(basis="sto-3g", bond_length=0.74)
result = safe_lucj_creation(h2, n_reps=1, max_iterations=50)
Performance Tips¶
- Start Small: Begin with
n_reps=1
and small iteration limits - Choose Method Wisely: BFGS is usually best, but Powell can be faster
- Monitor Convergence: Check
optimization_success
flag - Scale Gradually: Increase complexity only when needed
- Use Validation: Always compare with Hartree-Fock and FCI when available
Next Steps¶
- State Conversion: Convert ansatz states for use with QSCI
- Getting Started: See complete workflow examples
- Molecular Systems: Create different molecular systems to test
- API Reference: Detailed function documentation