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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
common.geometry
|
|
3
|
+
===============
|
|
4
|
+
|
|
5
|
+
Shared geometry generation for bond scans, angle scans, etc.
|
|
6
|
+
Used identically by VQE and QPE.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
import numpy as np
|
|
11
|
+
from typing import Tuple, List
|
|
12
|
+
|
|
13
|
+
def generate_geometry(name: str, param: float):
|
|
14
|
+
"""
|
|
15
|
+
Geometry wrapper.
|
|
16
|
+
Supported conventions (matching VQE):
|
|
17
|
+
"H2_BOND"
|
|
18
|
+
"H3+_BOND"
|
|
19
|
+
"LiH_BOND"
|
|
20
|
+
"H2O_ANGLE"
|
|
21
|
+
"""
|
|
22
|
+
if name == "H2_BOND":
|
|
23
|
+
return ["H", "H"], np.array([
|
|
24
|
+
[0.0, 0.0, 0.0],
|
|
25
|
+
[0.0, 0.0, param]
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
if name == "H3+_BOND":
|
|
29
|
+
# Example equilateral-ish geometry
|
|
30
|
+
return ["H", "H", "H"], np.array([
|
|
31
|
+
[0.0, 0.0, 0.0],
|
|
32
|
+
[param, 0.0, 0.0],
|
|
33
|
+
[0.5 * param, 0.866 * param, 0.0],
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
if name == "LiH_BOND":
|
|
37
|
+
return ["Li", "H"], np.array([
|
|
38
|
+
[0.0, 0.0, 0.0],
|
|
39
|
+
[0.0, 0.0, param]
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
if name == "H2O_ANGLE":
|
|
43
|
+
# Angle given in degrees
|
|
44
|
+
theta = np.deg2rad(param)
|
|
45
|
+
bond = 0.958
|
|
46
|
+
return ["O", "H", "H"], np.array([
|
|
47
|
+
[0.0, 0.0, 0.0],
|
|
48
|
+
[bond, 0.0, 0.0],
|
|
49
|
+
[bond * np.cos(theta), bond * np.sin(theta), 0.0],
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
raise KeyError(f"Unknown geometry type: {name}")
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
common.hamiltonian
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
Shared Hamiltonian construction used by VQE, QPE, and future solvers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pennylane as qml
|
|
11
|
+
from pennylane import qchem
|
|
12
|
+
from typing import Tuple
|
|
13
|
+
|
|
14
|
+
from vqe_qpe_common.molecules import get_molecule_config
|
|
15
|
+
|
|
16
|
+
def hartree_fock_state(symbols, charge, n_qubits):
|
|
17
|
+
"""Compute electron count and return HF basis state bitstring."""
|
|
18
|
+
Z = {
|
|
19
|
+
"H": 1,
|
|
20
|
+
"He": 2,
|
|
21
|
+
"Li": 3,
|
|
22
|
+
"Be": 4,
|
|
23
|
+
"O": 8,
|
|
24
|
+
}
|
|
25
|
+
electrons = sum(Z[s] for s in symbols) - charge
|
|
26
|
+
return qchem.hf_state(int(electrons), n_qubits)
|
|
27
|
+
|
|
28
|
+
def build_hamiltonian(symbols, coordinates, charge, basis) -> Tuple[qml.Hamiltonian, int, np.ndarray]:
|
|
29
|
+
"""
|
|
30
|
+
Build Hamiltonian + deduce HF state.
|
|
31
|
+
Returns: (Hamiltonian, n_qubits, hf_state)
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
H, n_qubits = qchem.molecular_hamiltonian(
|
|
35
|
+
symbols=symbols,
|
|
36
|
+
coordinates=coordinates,
|
|
37
|
+
charge=charge,
|
|
38
|
+
basis=basis,
|
|
39
|
+
)
|
|
40
|
+
except Exception as e_primary:
|
|
41
|
+
print("⚠️ Default PennyLane-qchem backend failed — retrying with OpenFermion...")
|
|
42
|
+
try:
|
|
43
|
+
H, n_qubits = qchem.molecular_hamiltonian(
|
|
44
|
+
symbols=symbols,
|
|
45
|
+
coordinates=coordinates,
|
|
46
|
+
charge=charge,
|
|
47
|
+
basis=basis,
|
|
48
|
+
method="openfermion",
|
|
49
|
+
)
|
|
50
|
+
except Exception as e_fallback:
|
|
51
|
+
raise RuntimeError(
|
|
52
|
+
f"Failed to construct Hamiltonian.\n"
|
|
53
|
+
f"Primary error: {e_primary}\n"
|
|
54
|
+
f"Fallback error: {e_fallback}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
hf_state = hartree_fock_state(symbols, charge, n_qubits)
|
|
58
|
+
return H, n_qubits, hf_state
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
common.molecules
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
Canonical molecule registry shared by VQE and QPE.
|
|
6
|
+
|
|
7
|
+
Every molecule entry contains:
|
|
8
|
+
• symbols (list[str])
|
|
9
|
+
• coordinates (np.ndarray)
|
|
10
|
+
• charge (int)
|
|
11
|
+
• basis (str)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
MOLECULES = {
|
|
18
|
+
"H2": {
|
|
19
|
+
"symbols": ["H", "H"],
|
|
20
|
+
"coordinates": np.array([
|
|
21
|
+
[0.0, 0.0, 0.0],
|
|
22
|
+
[0.0, 0.0, 0.7414],
|
|
23
|
+
]),
|
|
24
|
+
"charge": 0,
|
|
25
|
+
"basis": "STO-3G",
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"H3+": {
|
|
29
|
+
"symbols": ["H", "H", "H"],
|
|
30
|
+
"coordinates": np.array([
|
|
31
|
+
[0.0, 0.0, 0.0],
|
|
32
|
+
[0.0, 0.0, 0.872],
|
|
33
|
+
[0.755, 0.0, 0.436],
|
|
34
|
+
]),
|
|
35
|
+
"charge": +1,
|
|
36
|
+
"basis": "STO-3G",
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
"LiH": {
|
|
40
|
+
"symbols": ["Li", "H"],
|
|
41
|
+
"coordinates": np.array([
|
|
42
|
+
[0.0, 0.0, 0.0],
|
|
43
|
+
[0.0, 0.0, 1.6],
|
|
44
|
+
]),
|
|
45
|
+
"charge": 0,
|
|
46
|
+
"basis": "STO-3G",
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
"H2O": {
|
|
50
|
+
"symbols": ["O", "H", "H"],
|
|
51
|
+
"coordinates": np.array([
|
|
52
|
+
[0.000000, 0.000000, 0.000000],
|
|
53
|
+
[0.758602, 0.000000, 0.504284],
|
|
54
|
+
[-0.758602, 0.000000, 0.504284],
|
|
55
|
+
]),
|
|
56
|
+
"charge": 0,
|
|
57
|
+
"basis": "STO-3G",
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
# ------------------------------------------------------
|
|
61
|
+
# NEW MOLECULES (BeH2, H4-chain, HeH+)
|
|
62
|
+
# ------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
"HeH+": {
|
|
65
|
+
"symbols": ["He", "H"],
|
|
66
|
+
# Typical HeH+ bond length ~1.46 Å (varies in literature)
|
|
67
|
+
"coordinates": np.array([
|
|
68
|
+
[0.0, 0.0, 0.0],
|
|
69
|
+
[0.0, 0.0, 1.46],
|
|
70
|
+
]),
|
|
71
|
+
"charge": +1,
|
|
72
|
+
"basis": "STO-3G",
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
"BeH2": {
|
|
76
|
+
"symbols": ["Be", "H", "H"],
|
|
77
|
+
# Linear geometry: H–Be–H with ~1.33 Å Be–H bond length
|
|
78
|
+
"coordinates": np.array([
|
|
79
|
+
[0.0, 0.0, 0.0],
|
|
80
|
+
[0.0, 0.0, 1.33],
|
|
81
|
+
[0.0, 0.0, -1.33],
|
|
82
|
+
]),
|
|
83
|
+
"charge": 0,
|
|
84
|
+
"basis": "STO-3G",
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
"H4": {
|
|
88
|
+
"symbols": ["H", "H", "H", "H"],
|
|
89
|
+
# Linear H4 chain, equally spaced at 1.0 Å
|
|
90
|
+
"coordinates": np.array([
|
|
91
|
+
[0.0, 0.0, 0.0],
|
|
92
|
+
[1.0, 0.0, 0.0],
|
|
93
|
+
[2.0, 0.0, 0.0],
|
|
94
|
+
[3.0, 0.0, 0.0],
|
|
95
|
+
]),
|
|
96
|
+
"charge": 0,
|
|
97
|
+
"basis": "STO-3G",
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_molecule_config(name: str):
|
|
103
|
+
"""Return the molecule configuration dict."""
|
|
104
|
+
try:
|
|
105
|
+
return MOLECULES[name]
|
|
106
|
+
except KeyError:
|
|
107
|
+
raise KeyError(f"Unknown molecule '{name}'. Available = {list(MOLECULES.keys())}")
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""
|
|
2
|
+
common.plotting
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
Centralised plotting utilities for the entire VQE/QPE package.
|
|
6
|
+
|
|
7
|
+
Provides:
|
|
8
|
+
- Unified filename builder for all PNG plots
|
|
9
|
+
- Automatic path sanitisation (molecule names, operators, symbols)
|
|
10
|
+
- Consistent plotting export (DPI, bbox, tight layout)
|
|
11
|
+
- Single point of control for changing any plotting behaviour
|
|
12
|
+
|
|
13
|
+
This ensures:
|
|
14
|
+
• Zero filename collisions
|
|
15
|
+
• Fully consistent naming between VQE, QPE, and notebooks
|
|
16
|
+
• Clean, readable filenames for publication-quality figures
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
import os
|
|
21
|
+
from typing import Dict, Optional
|
|
22
|
+
import matplotlib.pyplot as plt
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------
|
|
26
|
+
# Base Directories
|
|
27
|
+
# ---------------------------------------------------------------------
|
|
28
|
+
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
29
|
+
IMG_DIR = os.path.join(BASE_DIR, "images")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def ensure_plot_dirs():
|
|
33
|
+
"""Ensure required directories exist."""
|
|
34
|
+
os.makedirs(IMG_DIR, exist_ok=True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ---------------------------------------------------------------------
|
|
38
|
+
# Name Sanitisation
|
|
39
|
+
# ---------------------------------------------------------------------
|
|
40
|
+
def format_molecule_name(mol: str) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Convert a molecule name into a filesystem-safe token.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
"H3+" → "H3plus"
|
|
46
|
+
"H2 O" → "H2_O"
|
|
47
|
+
"LiH" → "LiH"
|
|
48
|
+
"""
|
|
49
|
+
mol = mol.replace("+", "plus")
|
|
50
|
+
mol = mol.replace(" ", "_")
|
|
51
|
+
return mol
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_token(val: Optional[str | float | int]) -> Optional[str]:
|
|
55
|
+
"""
|
|
56
|
+
Convert metadata values into clean filename components.
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
0.05 → "0p05"
|
|
60
|
+
0.0 → "0p0"
|
|
61
|
+
"Adam" → "Adam"
|
|
62
|
+
None → None
|
|
63
|
+
"""
|
|
64
|
+
if val is None:
|
|
65
|
+
return None
|
|
66
|
+
if isinstance(val, (int, float)):
|
|
67
|
+
s = f"{val:.5f}".rstrip("0").rstrip(".")
|
|
68
|
+
return s.replace(".", "p")
|
|
69
|
+
return str(val).replace(" ", "_")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------
|
|
73
|
+
# Filename Builder
|
|
74
|
+
# ---------------------------------------------------------------------
|
|
75
|
+
def build_filename(
|
|
76
|
+
molecule: Optional[str] = None,
|
|
77
|
+
*,
|
|
78
|
+
topic: str,
|
|
79
|
+
extras: Optional[Dict[str, Optional[float | int | str]]] = None,
|
|
80
|
+
) -> str:
|
|
81
|
+
"""
|
|
82
|
+
Build a descriptive, collision-safe PNG filename.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
molecule : str, optional
|
|
87
|
+
Molecule identifier (e.g., "H2", "H3+").
|
|
88
|
+
topic : str
|
|
89
|
+
The major theme of the plot, e.g.
|
|
90
|
+
"vqe_convergence", "qpe_distribution",
|
|
91
|
+
"noise_sweep", "optimizer_comparison"
|
|
92
|
+
extras : dict, optional
|
|
93
|
+
Arbitrary metadata to encode in filename, e.g.
|
|
94
|
+
{"optimizer": "Adam", "ansatz": "UCCSD", "anc": 4}
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
str
|
|
99
|
+
Filename ending in `.png`.
|
|
100
|
+
|
|
101
|
+
Example
|
|
102
|
+
-------
|
|
103
|
+
build_filename(
|
|
104
|
+
molecule="H2",
|
|
105
|
+
topic="qpe_distribution",
|
|
106
|
+
extras={"anc": 4, "pdep": 0.02}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
→ "H2_qpe_distribution_anc4_pdep0p02.png"
|
|
110
|
+
"""
|
|
111
|
+
parts = []
|
|
112
|
+
|
|
113
|
+
if molecule:
|
|
114
|
+
parts.append(format_molecule_name(molecule))
|
|
115
|
+
|
|
116
|
+
# Topic (safe)
|
|
117
|
+
topic = topic.lower().replace(" ", "_")
|
|
118
|
+
parts.append(topic)
|
|
119
|
+
|
|
120
|
+
# Append metadata tokens
|
|
121
|
+
if extras:
|
|
122
|
+
for key, val in extras.items():
|
|
123
|
+
fv = format_token(val)
|
|
124
|
+
if fv is not None:
|
|
125
|
+
parts.append(f"{key}{fv}")
|
|
126
|
+
|
|
127
|
+
return "_".join(parts) + ".png"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# ---------------------------------------------------------------------
|
|
131
|
+
# Unified Save
|
|
132
|
+
# ---------------------------------------------------------------------
|
|
133
|
+
def save_plot(filename: str, show: bool = True) -> str:
|
|
134
|
+
"""
|
|
135
|
+
Save the current matplotlib figure to the global IMG_DIR and optionally
|
|
136
|
+
display it inline (for notebooks).
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
filename : str
|
|
141
|
+
A clean filename produced by build_filename().
|
|
142
|
+
show : bool, default=True
|
|
143
|
+
If True, display the plot (for Jupyter/VSCode notebooks).
|
|
144
|
+
If False, only save.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
str
|
|
149
|
+
Absolute path to the saved PNG.
|
|
150
|
+
"""
|
|
151
|
+
ensure_plot_dirs()
|
|
152
|
+
|
|
153
|
+
# Ensure .png suffix
|
|
154
|
+
if not filename.lower().endswith(".png"):
|
|
155
|
+
filename = filename + ".png"
|
|
156
|
+
|
|
157
|
+
path = os.path.join(IMG_DIR, filename)
|
|
158
|
+
|
|
159
|
+
plt.savefig(path, dpi=300, bbox_inches="tight")
|
|
160
|
+
|
|
161
|
+
if show:
|
|
162
|
+
plt.show()
|
|
163
|
+
else:
|
|
164
|
+
plt.close()
|
|
165
|
+
|
|
166
|
+
print(f"📁 Saved plot → {path}")
|
|
167
|
+
return path
|