vqe-pennylane 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qpe/__init__.py +77 -0
- qpe/__main__.py +233 -0
- qpe/core.py +317 -0
- qpe/hamiltonian.py +100 -0
- qpe/io_utils.py +132 -0
- qpe/noise.py +47 -0
- qpe/visualize.py +212 -0
- vqe/__init__.py +118 -0
- vqe/__main__.py +318 -0
- vqe/ansatz.py +420 -0
- vqe/core.py +907 -0
- vqe/engine.py +390 -0
- vqe/hamiltonian.py +260 -0
- vqe/io_utils.py +265 -0
- vqe/optimizer.py +58 -0
- vqe/ssvqe.py +271 -0
- vqe/visualize.py +308 -0
- vqe_pennylane-0.2.2.dist-info/METADATA +239 -0
- vqe_pennylane-0.2.2.dist-info/RECORD +28 -0
- vqe_pennylane-0.2.2.dist-info/WHEEL +5 -0
- vqe_pennylane-0.2.2.dist-info/entry_points.txt +3 -0
- vqe_pennylane-0.2.2.dist-info/licenses/LICENSE +21 -0
- vqe_pennylane-0.2.2.dist-info/top_level.txt +3 -0
- vqe_qpe_common/__init__.py +67 -0
- vqe_qpe_common/geometry.py +52 -0
- vqe_qpe_common/hamiltonian.py +58 -0
- vqe_qpe_common/molecules.py +107 -0
- vqe_qpe_common/plotting.py +167 -0
qpe/hamiltonian.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
common.hamiltonian.py
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
Shared molecular configuration + Hamiltonian construction for QPE.
|
|
6
|
+
|
|
7
|
+
This module mirrors the VQE architecture and ensures that QPE uses
|
|
8
|
+
the *exact same Hamiltonian pipeline* as VQE, guaranteeing consistent
|
|
9
|
+
chemistry, reproducibility, and shared geometry generation.
|
|
10
|
+
|
|
11
|
+
Provides:
|
|
12
|
+
• get_molecule_config(name)
|
|
13
|
+
• generate_geometry(name, param)
|
|
14
|
+
• build_hamiltonian(symbols, coordinates, charge, basis)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pennylane as qml
|
|
20
|
+
from pennylane import qchem
|
|
21
|
+
from typing import Dict, Any, Tuple
|
|
22
|
+
|
|
23
|
+
# ---------------------------------------------------------------------
|
|
24
|
+
# Import from VQE: SINGLE SOURCE OF TRUTH
|
|
25
|
+
# ---------------------------------------------------------------------
|
|
26
|
+
from vqe.hamiltonian import (
|
|
27
|
+
MOLECULES as VQE_MOLECULES,
|
|
28
|
+
generate_geometry as vqe_generate_geometry,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Expose VQE molecule registry to QPE
|
|
32
|
+
MOLECULES: Dict[str, Dict[str, Any]] = VQE_MOLECULES
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_molecule_config(name: str) -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Retrieve molecular configuration from the unified registry.
|
|
38
|
+
"""
|
|
39
|
+
if name not in MOLECULES:
|
|
40
|
+
raise KeyError(
|
|
41
|
+
f"Unknown molecule '{name}'. Available: {list(MOLECULES.keys())}"
|
|
42
|
+
)
|
|
43
|
+
return MOLECULES[name]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------
|
|
47
|
+
# Geometry variation (bond scans, angles)
|
|
48
|
+
# ---------------------------------------------------------------------
|
|
49
|
+
def generate_geometry(name: str, param: float):
|
|
50
|
+
"""
|
|
51
|
+
Geometry generation wrapper for QPE.
|
|
52
|
+
|
|
53
|
+
Calls the VQE geometry generator directly.
|
|
54
|
+
"""
|
|
55
|
+
return vqe_generate_geometry(name, param)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------
|
|
59
|
+
# Hamiltonian Builder
|
|
60
|
+
# ---------------------------------------------------------------------
|
|
61
|
+
def build_hamiltonian(
|
|
62
|
+
symbols: list[str],
|
|
63
|
+
coordinates: np.ndarray,
|
|
64
|
+
charge: int,
|
|
65
|
+
basis: str,
|
|
66
|
+
) -> Tuple[qml.Hamiltonian, int]:
|
|
67
|
+
"""
|
|
68
|
+
Build the molecular Hamiltonian using PennyLane-qchem,
|
|
69
|
+
with OpenFermion fallback.
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
H, n_qubits = qchem.molecular_hamiltonian(
|
|
73
|
+
symbols=symbols,
|
|
74
|
+
coordinates=coordinates,
|
|
75
|
+
charge=charge,
|
|
76
|
+
basis=basis,
|
|
77
|
+
)
|
|
78
|
+
return H, n_qubits
|
|
79
|
+
|
|
80
|
+
except Exception as e_primary:
|
|
81
|
+
print("⚠️ PennyLane-qchem failed — retrying with OpenFermion backend...")
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
H, n_qubits = qchem.molecular_hamiltonian(
|
|
85
|
+
symbols=symbols,
|
|
86
|
+
coordinates=coordinates,
|
|
87
|
+
charge=charge,
|
|
88
|
+
basis=basis,
|
|
89
|
+
method="openfermion",
|
|
90
|
+
)
|
|
91
|
+
return H, n_qubits
|
|
92
|
+
|
|
93
|
+
except Exception as e_fallback:
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
"Failed to construct Hamiltonian.\n"
|
|
96
|
+
f"Primary error:\n {e_primary}\n"
|
|
97
|
+
f"OpenFermion fallback error:\n {e_fallback}\n"
|
|
98
|
+
"Try installing OpenFermion:\n"
|
|
99
|
+
" pip install openfermion openfermionpyscf\n"
|
|
100
|
+
)
|
qpe/io_utils.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
qpe/io_utils.py
|
|
3
|
+
================
|
|
4
|
+
Unified result persistence, caching, and filename utilities for QPE.
|
|
5
|
+
|
|
6
|
+
This version is fully aligned with the VQE I/O stack:
|
|
7
|
+
|
|
8
|
+
results/
|
|
9
|
+
├── vqe/
|
|
10
|
+
└── qpe/
|
|
11
|
+
|
|
12
|
+
All QPE JSON output files live in: results/qpe/
|
|
13
|
+
|
|
14
|
+
All PNG figures must be saved through common.plotting.save_plot(),
|
|
15
|
+
which stores everything under: plots/
|
|
16
|
+
|
|
17
|
+
This file intentionally contains:
|
|
18
|
+
• No plotting
|
|
19
|
+
• No PennyLane logic
|
|
20
|
+
• Only JSON I/O + persistent directory management
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
import os
|
|
25
|
+
import json
|
|
26
|
+
import hashlib
|
|
27
|
+
from typing import Any, Dict
|
|
28
|
+
|
|
29
|
+
from vqe_qpe_common.plotting import save_plot, build_filename
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------
|
|
33
|
+
# Base Directories (mirrors VQE)
|
|
34
|
+
# ---------------------------------------------------------------------
|
|
35
|
+
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
36
|
+
RESULTS_DIR = os.path.join(BASE_DIR, "results", "qpe")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def ensure_dirs() -> None:
|
|
40
|
+
"""Ensure that the QPE results directory exists."""
|
|
41
|
+
os.makedirs(RESULTS_DIR, exist_ok=True)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------
|
|
45
|
+
# Hashing: repeatable, human-stable, JSON-safe
|
|
46
|
+
# ---------------------------------------------------------------------
|
|
47
|
+
def signature_hash(
|
|
48
|
+
*,
|
|
49
|
+
molecule: str,
|
|
50
|
+
n_ancilla: int,
|
|
51
|
+
t: float,
|
|
52
|
+
shots: int | None,
|
|
53
|
+
noise: Dict[str, float] | None,
|
|
54
|
+
) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Generate a reproducible hash key for a QPE configuration.
|
|
57
|
+
|
|
58
|
+
All important run parameters are included.
|
|
59
|
+
"""
|
|
60
|
+
key = json.dumps(
|
|
61
|
+
{
|
|
62
|
+
"molecule": molecule,
|
|
63
|
+
"ancilla_qubits": n_ancilla,
|
|
64
|
+
"time_param": round(float(t), 10),
|
|
65
|
+
"shots": shots,
|
|
66
|
+
"noise_params": noise or {},
|
|
67
|
+
},
|
|
68
|
+
sort_keys=True,
|
|
69
|
+
separators=(",", ":"),
|
|
70
|
+
)
|
|
71
|
+
return hashlib.sha256(key.encode("utf-8")).hexdigest()[:12]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cache_path(molecule: str, key: str) -> str:
|
|
75
|
+
"""Create the canonical JSON file path for a cached QPE result."""
|
|
76
|
+
ensure_dirs()
|
|
77
|
+
safe_mol = molecule.replace("+", "plus").replace(" ", "_")
|
|
78
|
+
return os.path.join(RESULTS_DIR, f"{safe_mol}_QPE_{key}.json")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------
|
|
82
|
+
# JSON Save / Load
|
|
83
|
+
# ---------------------------------------------------------------------
|
|
84
|
+
def save_qpe_result(result: Dict[str, Any]) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Save a QPE result to JSON using the canonical naming convention.
|
|
87
|
+
|
|
88
|
+
Fields that MUST be present in result:
|
|
89
|
+
molecule, n_ancilla, t, shots, noise
|
|
90
|
+
"""
|
|
91
|
+
ensure_dirs()
|
|
92
|
+
|
|
93
|
+
key = signature_hash(
|
|
94
|
+
molecule=result["molecule"],
|
|
95
|
+
n_ancilla=result["n_ancilla"],
|
|
96
|
+
t=result["t"],
|
|
97
|
+
shots=result.get("shots", None),
|
|
98
|
+
noise=result.get("noise", {}),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
path = cache_path(result["molecule"], key)
|
|
102
|
+
|
|
103
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
104
|
+
json.dump(result, f, indent=2)
|
|
105
|
+
|
|
106
|
+
print(f"💾 Saved QPE result → {path}")
|
|
107
|
+
return path
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def load_qpe_result(molecule: str, key: str) -> Dict[str, Any] | None:
|
|
111
|
+
"""
|
|
112
|
+
Load a cached QPE JSON result if it exists, otherwise return None.
|
|
113
|
+
"""
|
|
114
|
+
path = cache_path(molecule, key)
|
|
115
|
+
if os.path.exists(path):
|
|
116
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
117
|
+
return json.load(f)
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------------------------------------------------
|
|
122
|
+
# Unified PNG Save Wrapper
|
|
123
|
+
# ---------------------------------------------------------------------
|
|
124
|
+
def save_qpe_plot(filename: str) -> str:
|
|
125
|
+
"""
|
|
126
|
+
Save a QPE plot using the unified project-wide plotting logic.
|
|
127
|
+
|
|
128
|
+
This stores all images under the root-level plots/ directory.
|
|
129
|
+
|
|
130
|
+
filename should be produced by build_filename().
|
|
131
|
+
"""
|
|
132
|
+
return save_plot(filename)
|
qpe/noise.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
qpe/noise.py
|
|
3
|
+
============
|
|
4
|
+
Noise utility functions for Quantum Phase Estimation (QPE) circuits.
|
|
5
|
+
|
|
6
|
+
Currently supports:
|
|
7
|
+
• Depolarizing channel
|
|
8
|
+
• Amplitude damping channel
|
|
9
|
+
|
|
10
|
+
Both can be applied together to all wires in a circuit segment.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
import pennylane as qml
|
|
15
|
+
from typing import Iterable
|
|
16
|
+
|
|
17
|
+
def apply_noise_all(
|
|
18
|
+
wires: Iterable[int],
|
|
19
|
+
p_dep: float = 0.0,
|
|
20
|
+
p_amp: float = 0.0,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Apply depolarizing and/or amplitude damping noise to the given wires.
|
|
23
|
+
|
|
24
|
+
This function is intended to be called *inside* a QNode, typically
|
|
25
|
+
after a unitary operation or ansatz to simulate mixed noise channels.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
wires : Iterable[int]
|
|
30
|
+
Wires (qubit indices) on which to apply noise.
|
|
31
|
+
p_dep : float, optional
|
|
32
|
+
Depolarizing probability per wire (default = 0.0).
|
|
33
|
+
p_amp : float, optional
|
|
34
|
+
Amplitude damping probability per wire (default = 0.0).
|
|
35
|
+
|
|
36
|
+
Example
|
|
37
|
+
-------
|
|
38
|
+
>>> apply_noise_all([0, 1, 2], p_dep=0.02, p_amp=0.01)
|
|
39
|
+
"""
|
|
40
|
+
if p_dep <= 0.0 and p_amp <= 0.0:
|
|
41
|
+
return # Skip if no noise configured
|
|
42
|
+
|
|
43
|
+
for w in wires:
|
|
44
|
+
if p_dep > 0.0:
|
|
45
|
+
qml.DepolarizingChannel(p_dep, wires=w)
|
|
46
|
+
if p_amp > 0.0:
|
|
47
|
+
qml.AmplitudeDamping(p_amp, wires=w)
|
qpe/visualize.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
qpe.visualize
|
|
3
|
+
==============
|
|
4
|
+
High-quality plotting utilities for Quantum Phase Estimation (QPE),
|
|
5
|
+
fully unified with the project's global plotting system in
|
|
6
|
+
`common.plotting`.
|
|
7
|
+
|
|
8
|
+
Provides:
|
|
9
|
+
• plot_qpe_distribution – histogram of ancilla measurement outcomes
|
|
10
|
+
• plot_qpe_sweep – generic sweep plotting (noise, ancillas, t, etc.)
|
|
11
|
+
|
|
12
|
+
All plots are saved via:
|
|
13
|
+
common.plotting.build_filename
|
|
14
|
+
common.plotting.save_plot
|
|
15
|
+
|
|
16
|
+
This guarantees:
|
|
17
|
+
• uniform PNG naming across VQE + QPE
|
|
18
|
+
• safe molecule names
|
|
19
|
+
• plots stored in /plots/
|
|
20
|
+
• consistent DPI / formatting for publication-quality figures
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from typing import Dict, Any, Sequence, Optional
|
|
26
|
+
|
|
27
|
+
import matplotlib.pyplot as plt
|
|
28
|
+
|
|
29
|
+
from vqe_qpe_common.plotting import (
|
|
30
|
+
build_filename,
|
|
31
|
+
save_plot,
|
|
32
|
+
format_molecule_name,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------
|
|
37
|
+
# QPE Probability Distribution Plot
|
|
38
|
+
# ---------------------------------------------------------------------
|
|
39
|
+
def plot_qpe_distribution(
|
|
40
|
+
result: Dict[str, Any],
|
|
41
|
+
*,
|
|
42
|
+
show: bool = True,
|
|
43
|
+
save: bool = True,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Plot the ancilla probability distribution from a QPE run.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
result : dict
|
|
51
|
+
QPE result dictionary produced by run_qpe().
|
|
52
|
+
show : bool
|
|
53
|
+
Display figure window.
|
|
54
|
+
save : bool
|
|
55
|
+
Save figure via common plotting system.
|
|
56
|
+
"""
|
|
57
|
+
probs = result.get("probs", {})
|
|
58
|
+
if not probs:
|
|
59
|
+
print("⚠️ No probability data found in QPE result — skipping plot.")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
molecule = format_molecule_name(result.get("molecule", "QPE"))
|
|
63
|
+
n_anc = int(result.get("n_ancilla", 0))
|
|
64
|
+
|
|
65
|
+
noise = result.get("noise", {})
|
|
66
|
+
p_dep = float(noise.get("p_dep", 0.0))
|
|
67
|
+
p_amp = float(noise.get("p_amp", 0.0))
|
|
68
|
+
|
|
69
|
+
# Sort by probability descending
|
|
70
|
+
items = sorted(probs.items(), key=lambda kv: -kv[1])
|
|
71
|
+
xs = [f"|{b}⟩" for b, _ in items]
|
|
72
|
+
ys = [float(p) for _, p in items]
|
|
73
|
+
|
|
74
|
+
# Figure
|
|
75
|
+
plt.figure(figsize=(8, 4))
|
|
76
|
+
plt.bar(xs, ys, alpha=0.85, edgecolor="black")
|
|
77
|
+
|
|
78
|
+
plt.xlabel("Ancilla State", fontsize=11)
|
|
79
|
+
plt.ylabel("Probability", fontsize=11)
|
|
80
|
+
|
|
81
|
+
noise_suffix = ""
|
|
82
|
+
if p_dep > 0 or p_amp > 0:
|
|
83
|
+
noise_suffix = f" • noise(p_dep={p_dep}, p_amp={p_amp})"
|
|
84
|
+
|
|
85
|
+
plt.title(
|
|
86
|
+
f"{molecule} QPE Distribution ({n_anc} ancilla){noise_suffix}",
|
|
87
|
+
fontsize=12
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
plt.xticks(rotation=45, ha="right")
|
|
91
|
+
plt.grid(axis="y", linestyle="--", alpha=0.4)
|
|
92
|
+
plt.tight_layout()
|
|
93
|
+
|
|
94
|
+
if save:
|
|
95
|
+
fname = build_filename(
|
|
96
|
+
molecule=molecule,
|
|
97
|
+
topic="qpe_distribution",
|
|
98
|
+
extras={
|
|
99
|
+
"anc": n_anc,
|
|
100
|
+
"pdep": p_dep,
|
|
101
|
+
"pamp": p_amp,
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
save_plot(fname)
|
|
105
|
+
|
|
106
|
+
if show:
|
|
107
|
+
plt.show()
|
|
108
|
+
else:
|
|
109
|
+
plt.close()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# ---------------------------------------------------------------------
|
|
113
|
+
# Generic QPE Sweep Plot
|
|
114
|
+
# ---------------------------------------------------------------------
|
|
115
|
+
def plot_qpe_sweep(
|
|
116
|
+
x_values: Sequence[float],
|
|
117
|
+
y_means: Sequence[float],
|
|
118
|
+
y_stds: Optional[Sequence[float]] = None,
|
|
119
|
+
*,
|
|
120
|
+
molecule: str = "?",
|
|
121
|
+
sweep_label: str = "Sweep parameter",
|
|
122
|
+
ylabel: str = "Energy (Ha)",
|
|
123
|
+
title: str = "QPE Sweep",
|
|
124
|
+
ref_value: Optional[float] = None,
|
|
125
|
+
ref_label: str = "Reference",
|
|
126
|
+
ancilla: Optional[int] = None,
|
|
127
|
+
noise_params: Optional[Dict[str, float]] = None,
|
|
128
|
+
show: bool = True,
|
|
129
|
+
save: bool = True,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""
|
|
132
|
+
A general-purpose plotting routine for QPE sweeps:
|
|
133
|
+
• sweep over noise strengths
|
|
134
|
+
• sweep over t parameter
|
|
135
|
+
• sweep over number of ancilla qubits
|
|
136
|
+
• sweep over geometry/bond length (rare for QPE, but possible)
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
x_values : list
|
|
141
|
+
Parameter values for sweep
|
|
142
|
+
y_means : list
|
|
143
|
+
Mean energies or phases
|
|
144
|
+
y_stds : list, optional
|
|
145
|
+
Standard deviations
|
|
146
|
+
molecule : str
|
|
147
|
+
Molecule label
|
|
148
|
+
sweep_label : str
|
|
149
|
+
X-axis label
|
|
150
|
+
ylabel : str
|
|
151
|
+
Y-axis label (energy or phase)
|
|
152
|
+
title : str
|
|
153
|
+
Plot title
|
|
154
|
+
ref_value : float, optional
|
|
155
|
+
Add horizontal reference line
|
|
156
|
+
ancilla : int, optional
|
|
157
|
+
Ancilla count for filename metadata
|
|
158
|
+
noise_params : dict, optional
|
|
159
|
+
Noise info for filename metadata
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
molecule = format_molecule_name(molecule)
|
|
163
|
+
p_dep = float((noise_params or {}).get("p_dep", 0.0))
|
|
164
|
+
p_amp = float((noise_params or {}).get("p_amp", 0.0))
|
|
165
|
+
|
|
166
|
+
plt.figure(figsize=(6.5, 4.5))
|
|
167
|
+
|
|
168
|
+
if y_stds is not None:
|
|
169
|
+
plt.errorbar(
|
|
170
|
+
x_values,
|
|
171
|
+
y_means,
|
|
172
|
+
yerr=y_stds,
|
|
173
|
+
fmt="o-",
|
|
174
|
+
capsize=4,
|
|
175
|
+
label="QPE mean ± std",
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
plt.plot(x_values, y_means, "o-", label="QPE mean")
|
|
179
|
+
|
|
180
|
+
if ref_value is not None:
|
|
181
|
+
plt.axhline(
|
|
182
|
+
ref_value,
|
|
183
|
+
linestyle="--",
|
|
184
|
+
color="gray",
|
|
185
|
+
label=ref_label,
|
|
186
|
+
alpha=0.8,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
plt.xlabel(sweep_label)
|
|
190
|
+
plt.ylabel(ylabel)
|
|
191
|
+
plt.title(f"{molecule} – {title}")
|
|
192
|
+
plt.grid(True, linestyle="--", alpha=0.5)
|
|
193
|
+
plt.legend()
|
|
194
|
+
plt.tight_layout()
|
|
195
|
+
|
|
196
|
+
if save:
|
|
197
|
+
fname = build_filename(
|
|
198
|
+
molecule=molecule,
|
|
199
|
+
topic="qpe_sweep",
|
|
200
|
+
extras={
|
|
201
|
+
"anc": ancilla,
|
|
202
|
+
"pdep": p_dep,
|
|
203
|
+
"pamp": p_amp,
|
|
204
|
+
"tag": title.replace(" ", "_").lower(),
|
|
205
|
+
},
|
|
206
|
+
)
|
|
207
|
+
save_plot(fname)
|
|
208
|
+
|
|
209
|
+
if show:
|
|
210
|
+
plt.show()
|
|
211
|
+
else:
|
|
212
|
+
plt.close()
|
vqe/__init__.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
vqe
|
|
3
|
+
---
|
|
4
|
+
A modular Variational Quantum Eigensolver (VQE) and SSVQE toolkit built on PennyLane.
|
|
5
|
+
|
|
6
|
+
Public API:
|
|
7
|
+
- run_vqe
|
|
8
|
+
- run_ssvqe
|
|
9
|
+
- run_vqe_noise_sweep
|
|
10
|
+
- run_vqe_optimizer_comparison
|
|
11
|
+
- run_vqe_ansatz_comparison
|
|
12
|
+
- run_vqe_multi_seed_noise
|
|
13
|
+
- run_vqe_geometry_scan
|
|
14
|
+
- run_vqe_mapping_comparison
|
|
15
|
+
|
|
16
|
+
- get_ansatz, init_params, ANSATZES
|
|
17
|
+
- get_optimizer
|
|
18
|
+
- build_hamiltonian, generate_geometry
|
|
19
|
+
- make_run_config_dict, run_signature, save_run_record, ensure_dirs
|
|
20
|
+
|
|
21
|
+
- Plotting helpers (visualize.*)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__version__ = "0.2.0"
|
|
25
|
+
|
|
26
|
+
# ------------------------------------------------------------------
|
|
27
|
+
# Core VQE APIs
|
|
28
|
+
# ------------------------------------------------------------------
|
|
29
|
+
from .core import (
|
|
30
|
+
run_vqe,
|
|
31
|
+
run_vqe_noise_sweep,
|
|
32
|
+
run_vqe_optimizer_comparison,
|
|
33
|
+
run_vqe_ansatz_comparison,
|
|
34
|
+
run_vqe_multi_seed_noise,
|
|
35
|
+
run_vqe_geometry_scan,
|
|
36
|
+
run_vqe_mapping_comparison,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# ------------------------------------------------------------------
|
|
40
|
+
# Ansatz registry & utilities
|
|
41
|
+
# ------------------------------------------------------------------
|
|
42
|
+
from .ansatz import get_ansatz, init_params, ANSATZES
|
|
43
|
+
|
|
44
|
+
# ------------------------------------------------------------------
|
|
45
|
+
# Optimizers
|
|
46
|
+
# ------------------------------------------------------------------
|
|
47
|
+
from .optimizer import get_optimizer
|
|
48
|
+
|
|
49
|
+
# ------------------------------------------------------------------
|
|
50
|
+
# Hamiltonian & geometry
|
|
51
|
+
# ------------------------------------------------------------------
|
|
52
|
+
from .hamiltonian import build_hamiltonian, generate_geometry
|
|
53
|
+
|
|
54
|
+
# ------------------------------------------------------------------
|
|
55
|
+
# I/O utilities (config, hashing, results)
|
|
56
|
+
# ------------------------------------------------------------------
|
|
57
|
+
from .io_utils import (
|
|
58
|
+
make_run_config_dict,
|
|
59
|
+
run_signature,
|
|
60
|
+
save_run_record,
|
|
61
|
+
ensure_dirs,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# ------------------------------------------------------------------
|
|
65
|
+
# Visualization utilities
|
|
66
|
+
# ------------------------------------------------------------------
|
|
67
|
+
from .visualize import (
|
|
68
|
+
plot_convergence,
|
|
69
|
+
plot_ssvqe_convergence_multi,
|
|
70
|
+
plot_optimizer_comparison,
|
|
71
|
+
plot_ansatz_comparison,
|
|
72
|
+
plot_noise_statistics,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# ------------------------------------------------------------------
|
|
76
|
+
# SSVQE
|
|
77
|
+
# ------------------------------------------------------------------
|
|
78
|
+
from .ssvqe import run_ssvqe
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = [
|
|
82
|
+
# Core VQE API
|
|
83
|
+
"run_vqe",
|
|
84
|
+
"run_vqe_noise_sweep",
|
|
85
|
+
"run_vqe_optimizer_comparison",
|
|
86
|
+
"run_vqe_ansatz_comparison",
|
|
87
|
+
"run_vqe_multi_seed_noise",
|
|
88
|
+
"run_vqe_geometry_scan",
|
|
89
|
+
"run_vqe_mapping_comparison",
|
|
90
|
+
|
|
91
|
+
# Ansatz tools
|
|
92
|
+
"get_ansatz",
|
|
93
|
+
"init_params",
|
|
94
|
+
"ANSATZES",
|
|
95
|
+
|
|
96
|
+
# Optimizers
|
|
97
|
+
"get_optimizer",
|
|
98
|
+
|
|
99
|
+
# Hamiltonian
|
|
100
|
+
"build_hamiltonian",
|
|
101
|
+
"generate_geometry",
|
|
102
|
+
|
|
103
|
+
# I/O
|
|
104
|
+
"make_run_config_dict",
|
|
105
|
+
"run_signature",
|
|
106
|
+
"save_run_record",
|
|
107
|
+
"ensure_dirs",
|
|
108
|
+
|
|
109
|
+
# SSVQE
|
|
110
|
+
"run_ssvqe",
|
|
111
|
+
|
|
112
|
+
# Visualization
|
|
113
|
+
"plot_convergence",
|
|
114
|
+
"plot_optimizer_comparison",
|
|
115
|
+
"plot_ansatz_comparison",
|
|
116
|
+
"plot_noise_statistics",
|
|
117
|
+
"plot_ssvqe_convergence_multi",
|
|
118
|
+
]
|