GCiM and ADAPT¶
Use Eigenproblem(A=...) with FixedGCIM(basis=...) or ADAPT(initial_state=..., pool=...) to estimate the smallest eigenvalue of A by solving the projected problem H f = E S f in a basis of trial states. FixedGCIM uses a basis that you supply, and ADAPT grows one from a generator pool. Both results report projected Ritz values, which do not certify the full-space ground energy.
from nwqlib import Eigenproblem, solve
from nwqlib.algorithms import ADAPT, FixedGCIM
from nwqlib.algorithms.gcim import build_gcim_chemistry_problem
Every object on this page imports from nwqlib.algorithms.gcim. The methods, their results, ProjectedPencil, FixedGCIMBasis and AdaptVerificationOptions also import from nwqlib.algorithms.
FixedGCIM solves the discretized Hill-Wheeler problem of Zheng et al., Phys. Rev. Research 5, 023200 (2023), arXiv:2212.09205v1, Eq. (13). ADAPT follows Zheng et al., npj Quantum Information 10, 127 (2024), arXiv:2312.07691v3. The GCiM guide explains the matrix elements, their error bounds and the adaptive screening rule, and its source and code map gives the paper location of each step.
Solve in a fixed basis¶
FixedGCIM ¶
Bases: Method
Generator-coordinate (GCiM) method for the smallest eigenvalue in a fixed trial basis.
Build it with keyword arguments and pass it as method=, for example
solve(Eigenproblem(A=matrix), method=FixedGCIM(basis=(phi_1, phi_2))).
basis is the only required argument. The result is a
FixedGCIMResult
whose eigenvalue is the lowest Ritz value of the projected problem
H f = E S f, with H_ij = <phi_i|A|phi_j> and S_ij = <phi_i|phi_j>
for the normalized trial states phi_i. This is the discretized
Hill-Wheeler problem of Zheng et al., Phys. Rev. Research 5, 023200
(2023), arXiv:2212.09205v1, Eq. (13), with matrix elements
Eqs. (14)-(15). The trial states are the supplied states, normalized,
instead of the paper's states exp(Gamma(Z_p))|Phi> at discretized
generator coordinates Z_p (Eq. (10), discretized in Eq. (17)). A
projected Ritz value does not certify the full-space ground energy.
The call chooses how H and S are obtained, for M basis pairs of which D are diagonal:
- Default, exact quantum: one phase-faithful joint state per
off-diagonal pair and one system state per diagonal pair, each reduced
when it is measured to the offset-free
H0_ijandS_ij, so(M - D) + Dmeasurements. shots=n: the same joint state per off-diagonal pair, with its ancilla measured in X and Y together with each qubit-wise commuting group of system terms, and each diagonal pair's system state per group, so2(M - D) max(1, G) + DGsettings for G groups, n shots each. Each count table supplies its group's weighted Hamiltonian mean and, for the first group, the overlap and its covariance with that mean.execution="classical":V^dagger (A - cI) VandV^dagger Vcomputed directly, withc = trace(A)/d.
Every path solves without the identity term and adds c to the Ritz
values afterwards. Sampled Ritz values are raw estimates, and the
enclosure diagnostic in result.pencil does not certify their physical
accuracy. overlap_cutoff can be changed after the run with
result.analyze(overlap_cutoff=...), which reuses the same matrix
elements. The GCiM guide describes the matrix
elements, their error bounds and the solve.
Attributes:
-
basis(tuple[StateData, ...]) –Required. Trial states phi_i, a nonempty tuple of states in a form that
StateDataaccepts. Each is normalized. -
overlap_cutoff(Real) –Default
1e-12, positive. Overlap eigenvectors with eigenvalues above it are kept for the solve. -
max_basis_size(PositiveInt) –Default
64. Largest accepted number of trial states, checked before pairs are formed. -
max_experiments(PositiveInt) –Default
100_000. Largest number of measurement settings: exact pair reductions, or sampled group settings. -
max_bytes(PositiveInt) –Default 10 GB (decimal,
10_000_000_000bytes). Limit on the known bytes of conversion, the pair table, the grouped count analysis and the projected solve, and on each exact pair reduction's workspace, checked when that pair is prepared. -
max_analysis_work(PositiveInt) –Default
1_000_000_000. Limit on the work of the projected matrices and eigensolve, of the comparisons that form qubit-wise commuting groups, and of each pass of the grouped count analysis. Sampled planning checks the worst-case pass for one measurement per setting before it builds circuits, and analysis checks the stored counts again before decoding them. The default is ten times the other work defaults because that planning bound is conservative (Engineering constants, row "Sampled FixedGCIM analysis admission"). -
max_classical_products(PositiveInt) –Default
100_000_000. Limit on classical operator-vector products and on the summed classical work of the exact pair reductions. -
input_conversion(Literal['auto', 'dense_pauli']) –Default
"auto", which keeps the accepted input access."dense_pauli"permits explicit dense-to-Pauli conversion. -
max_conversion_work(PositiveInt) –Default
100_000_000. Limit on the work of an explicitly chosen operator conversion. -
max_admission_steps(PositiveInt) –Default
1_000_000. Limit on the planning work of checking each circuit description that the method builds. It caps both the number of stored fields of a description and the work units of one structural check of it. Summing a description's resource counts may use up to 24 times this value. The default equals that ofQLSand is ten times the shared default of100_000. Raising it permits a larger check and changes no quantum operation (planning work limit).
Examples:
H = ZZ + 0.5*(XI + IX) on two qubits has lowest eigenvalue
-sqrt(2) = -1.4142135623..., which this three-state basis
recovers on Aer with exact readout:
>>> from qiskit.quantum_info import SparsePauliOp
>>> from nwqlib import Eigenproblem, solve
>>> from nwqlib.algorithms import FixedGCIM
>>> H = SparsePauliOp.from_list([("ZZ", 1), ("XI", 0.5), ("IX", 0.5)])
>>> basis = ([1, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 0])
>>> result = solve(Eigenproblem(A=H), method=FixedGCIM(basis=basis), seed=7)
>>> print(round(result.eigenvalue, 10))
-1.4142135624
FixedGCIMResult ¶
Bases: Result
Smallest projected eigenvalue from a FixedGCIM run, with its projected matrices.
solve returns it for a FixedGCIM method,
and load_result reopens a saved one. The answer is eigenvalue, the
lowest kept Ritz value of the projected pencil, in the unit of the
Eigenproblem. It is None when data are missing or the solve was
refused. It is a projected estimate, not a certified full-space ground
energy. pencil holds the projected matrices H and S and the solve
diagnostics. print(result) shows the value and its scope, and
result.analyze(overlap_cutoff=...) solves the same matrix elements at
another cutoff without new measurement. Whenever a Result is attached to
its Plan and data, as after loading or reanalysis, NWQLib rejects a value
that differs from its own pencil, a pencil built under another
measurement policy, and any estimate formed from incomplete data. The
fields below are read-only. The fields of
Result are present too.
Attributes:
-
eigenvalue(Real | None) –Lowest kept Ritz value in the problem's energy unit, or None when data are missing or the solve was refused. It is not a certified full-space ground energy.
-
missing(tuple[Text, ...]) –Names of planned measurements with no returned data. A nonempty tuple means no pencil was solved.
-
pairs(tuple[PairEstimate, ...]) –Exact pair measurements: pooled
H0_ijandS_ijwith their reductions and entry error bounds. Empty for sampled and classical Plans. -
estimates(tuple[ScalarEstimate, ...]) –For a sampled Plan, the pooled weighted group means (
ScalarEstimate) with their contributing count data, weights and the estimated variance of each contribution's mean. -
group_moments(tuple[GroupMoment, ...]) –For a sampled Plan, the moments of every count measurement, in measurement order.
-
sampled_pair_variances(tuple[SampledPairVariance, ...]) –For a complete sampled pencil, the pooled sample-mean variances and overlap–H0 covariance of each pair.
-
pencil(ProjectedPencil | None) –The
ProjectedPencilwith the projected matrices and solve diagnostics, or None for partial data or a scalar identity target. -
analysis_cutoff(Real) –Overlap-eigenvalue cutoff used by this analysis.
-
target_identification(Text) –Fixed statement of what the value does not establish.
projected_diagnostics ¶
projected_diagnostics()
Return the stored Gram matrix and solve diagnostics for projected checks.
It reads the stored pencil and runs no new solve.
result.verify(checks=ProjectedVerificationOptions(...)) uses it.
Returns:
-
diagnostics(ProjectedDiagnostics) –Its
overlap,spectrum,normalizationandbackward_errorare the pencil'soverlap,overlap_eigenvalues,overlap_normalization_errorandprojected_backward_error, the last on the physical pencil (H, S). All four are None when there is no pencil.
ProjectedPencil ¶
Bases: Record
Projected matrices H and S of one trial basis and the diagnostics of their solve.
FixedGCIMResult.pencil and ADAPTResult.pencil hold it. The matrices
are the measured values, completed by complex conjugation, without
averaging, diagonal jitter or positive-semidefinite repair. The solve
keeps the overlap eigenvectors whose eigenvalues exceed overlap_cutoff
and diagonalizes H in that subspace (canonical orthogonalization,
Epperly, Lin and Nakatsukasa, arXiv:2110.07492v2, Algorithm 1.1, and
Zheng et al., arXiv:2312.07691v3, Appendix F, Eqs. (F1)-(F3)). No
full-space state residual is computed. The fields below are read-only.
Attributes:
-
hamiltonian(tuple[tuple[Complex128, ...], ...]) –Projected Hamiltonian
H = H0 + c_I Sof shape (m, m) in the problem's energy unit, from the acquiredH0without the identity termc_I Iand the acquiredS, completed from its upper triangle by conjugation. The solve usedH0and addedc_Ito its Ritz values. -
overlap(tuple[tuple[Complex128, ...], ...]) –Acquired Gram matrix
Sof shape (m, m), completed the same way. -
overlap_eigenvalues(tuple[Real, ...]) –Full ascending spectrum of
S, before the cutoff. -
eigenvalues(tuple[Real, ...]) –Ascending Ritz values of the kept subspace.
-
coordinate_vectors(tuple[tuple[Complex128, ...], ...]) –Rows index the m basis states and columns the Ritz pairs. Each column is an S-normalized coefficient vector.
-
kept_rank(Count) –Number of overlap directions above
overlap_cutoff. -
overlap_cutoff(Real) –Absolute overlap-eigenvalue threshold used by this solve.
-
overlap_filter(Literal['deterministic_gram', 'sampled_positive_subspace']) –"deterministic_gram"refuses a negative overlap mode beyond roundoff."sampled_positive_subspace"keeps only positive modes above the cutoff of a sampled, possibly indefinite S. -
overlap_condition_number(Real | None) –Largest over smallest kept overlap eigenvalue.
-
projected_residual(Nonnegative | None) –norm2(Hc - ESc)for the lowest Ritz pair. -
projected_backward_error(Nonnegative | None) –Dimensionless residual scaled by
(normF(H) + abs(E) normF(S)) norm2(c), on the physical pencil (H, S) in the Problem's energy unit, withH = H0 + c_I Swhen the solve removed an identity coefficient c_I. Rescaling the energy unit leaves it unchanged, but adding an identity term to the operator changesnormF(H)andabs(E)and therefore the value. Lanczos states its value on the normalized pencil instead. -
overlap_normalization_error(Nonnegative | None) –abs(c^dagger S c - 1)for the lowest Ritz pair. -
failure_reason(Text | None) –Solver refusal code, or None when the solve completed.
-
sampled_enclosure(tuple[Real, Real] | None) –For sampled quantum data, the outward-rounded interval
[c - sum_k |c_k|, c + sum_k |c_k|]that contains the spectrum of the processed operatorc I + sum_k c_k P_k, or None. -
sampled_enclosure_violation(Nonnegative | None) –Distance of the lowest Ritz value outside that enclosure, zero inside it, or None when unavailable.
-
sampled_enclosure_passed(StrictBool | None) –Whether the violation lies within
sampled_enclosure_rtoltimes the largest enclosure endpoint magnitude. -
sampled_enclosure_rtol(Nonnegative | None) –Relative window used by that comparison.
-
sampled_failure(Text | None) –Solver refusal or
"ritz_outside_operator_enclosure". -
processing(Literal['raw Hermitian completion; canonical positive-subspace projection']) –Fixed description of the processing applied to the raw pencil.
coefficients ¶
coefficients
Coefficient vector of the lowest Ritz pair, the first column of coordinate_vectors.
It is an empty tuple when no Ritz value exists. In the coordinates of
all columns, the kept pencil is (diag(eigenvalues), I) up to the
reported solve and normalization errors. Reading it performs no new
projection or eigensolve.
ScalarEstimate ¶
Bases: Record
Pooled mean of one weighted group of Pauli terms in a sampled FixedGCIM run.
FixedGCIMResult.estimates holds one per group setting. Each count
measurement of the setting measures Y = sum_k c_k Z_k from shared
shots. value is the shot-weighted mean of the measurements' means and
need not lie in [-1, 1]. chunk_mean_variances contains
(mean(Y**2) - mean(Y)**2)/(N - 1) for N > 1 shots and None for N = 1.
The group moments in FixedGCIMResult.group_moments keep the raw
moments and flag a negative raw variance. Independent measurements pool
their variances with squared shot weights. The overlap and physical-H
covariance are recorded in the group and pair statistics. These are
sample-mean variance estimates, not a joint bound on the pencil or a
confidence interval for the projected eigenvalue. The fields below are
read-only.
Attributes:
-
experiment(Text) –Name of the group setting.
-
value(Real) –Shot-weighted mean of the measurements' means of Y.
-
contribution_ids(tuple[ContentID, ...]) –Content hashes of the contributing count data.
-
weights(tuple[Real, ...]) –Fraction of the returned shots in each contribution.
-
chunk_mean_variances(tuple[Real | None, ...]) –The sample-mean variance of Y of each contribution, or None for a one-shot contribution.
-
sampled_shots(Count) –Total returned shots.
PairEstimate ¶
Bases: Record
The acquired H0_ij and S_ij of one exact pair and the reductions they were pooled from.
Each contribution is one block_matrix_elements reduction of the pair's
phase-faithful joint state (or diagonal system state), with population
one. Its two raw complex scalars are the offset-free Hamiltonian entry and
the overlap entry in the requested (left, right) orientation. A
diagonal pair's overlap is its raw squared norm, kept as evidence while
assembly uses unit diagonal overlap. The individual Pauli-term
transitions are not recorded and cannot be recovered from the weighted
payload, so a different Hamiltonian truncation needs new measurements.
Attributes:
-
experiment(Text) –The pair's experiment name.
-
pair(tuple[Count, Count]) –(left, right)withleft <= right. -
hamiltonian(Complex128) –Pooled offset-free
H0_ij. -
overlap(Complex128) –Pooled
S_ij. -
contribution_ids(tuple[ContentID, ...]) –Contributing reduction chunks.
-
weights(tuple[Real, ...]) –Population fraction of each contribution.
-
hamiltonian_bound(Nonnegative | None) –Outward error allowance for the acquired H0 entry under the state-error model of the producing preparation records, combined with the classical action, contraction and pooling bounds. None when a producing preparation record has an unresolved exclusion or no applicable state budget. When a supplied matrix is synthesized under control, this allowance also assumes the exact-to-rounding convention of exact dense synthesis. It does not add an independently certified synthesis residual.
-
overlap_bound(Nonnegative | None) –The corresponding allowance for the acquired overlap, with state, contraction and pooling terms. The solved diagonal is algebraic one and contributes zero to the Gram allowance. When a supplied matrix is synthesized under control, this allowance also assumes the exact-to-rounding convention of exact dense synthesis. It does not add an independently certified synthesis residual.
GroupMoment ¶
Bases: Record
Moments of one independently measured counts histogram.
Y is the coefficient-weighted group parity, including the ancilla sign on an off-diagonal pair. The optional X is that ancilla sign and is recorded only by group zero. Variances and covariance concern sample means. A one-shot measurement has unavailable variance. A negative raw variance is published with variance_negative=True and is never clipped. label_means preserves each term's first moment from the same histogram.
With N returned shots of one fixed setting and the unbiased sample
covariance divided again by N, the sample-mean variances are
V_Y = (mean(Y**2) - mean(Y)**2)/(N - 1),
V_X = (1 - mean(X)**2)/(N - 1) and
C_XY = (mean(XY) - mean(X) mean(Y))/(N - 1) for N > 1.
Attributes:
-
experiment(Text) –The setting's experiment name.
-
contribution_id(ContentID) –The count chunk these moments come from.
-
pair(tuple[Count, Count]) –(i, j)withi <= j. -
quadrature(Literal['real', 'imag']) –real(ancilla X) orimag(ancilla Y). -
group(Count) –Index into
FixedGCIMReconstruction.groups. -
shots(Count) –The chunk's returned population N.
-
label_means(tuple[Real, ...]) –The mean of each member's
Z_kin group order. -
mean(Real) –mean(Y). -
second(Real) –mean(Y**2). -
mean_variance(Real | None) –V_Y, or None for N = 1. -
overlap_mean(Real | None) –mean(X)for the overlap-supplying group of an off-diagonal pair, otherwise None. -
overlap_cross(Real | None) –mean(XY)of that group, otherwise None. -
overlap_variance(Real | None) –V_Xof that group, otherwise None. -
mean_covariance(Real | None) –C_XYof that group, otherwise None. -
variance_negative(StrictBool) –Whether
V_YorV_Xis negative.
SampledPairVariance ¶
Bases: Record
Independent real/imaginary sample-mean variances, including shared-shot covariance.
Entries are (real, imaginary). A diagonal overlap is algebraic one, with zero variance. None means a required measurement has one shot. Negative estimates stay raw and set variance_negative. These estimates are not simultaneous confidence bounds or a Ritz-value certificate.
Under independent measurements of different settings, each quadrature
has V_H0 = sum_g V_(Y_g) and
V_H = sum_g V_(Y_g) + c_I**2 V_X + 2 c_I C_(X,Y_0). The diagonal
uses V_S = 0 and covariance zero because its solved overlap is
algebraic. When c_I = 0, an unavailable overlap variance does not make
the physical-H variance unavailable. Independent real and imaginary
settings give E|error|**2 = V_real + V_imag.
Attributes:
-
pair(tuple[Count, Count]) –(i, j)withi <= j. -
h0(tuple[Real | None, Real | None]) –Variance of the offset-free Hamiltonian entry per quadrature.
-
overlap(tuple[Real | None, Real | None]) –Variance of the overlap entry per quadrature.
-
covariance(tuple[Real | None, Real | None]) –Overlap–H0 sample-mean covariance per quadrature.
-
physical_h(tuple[Real | None, Real | None]) –Variance of
H0 + c_I Sper quadrature. -
variance_negative(StrictBool) –Whether any h0, overlap or physical_h entry is negative.
FixedGCIMBasis ¶
Bases: Record
Record that names a FixedGCIM trial basis as an Eigenproblem subspace.
Build it with keyword arguments from the preparation records of the
trial states, for example
FixedGCIMBasis(preparations=tuple(state_input(v).preparation for v in basis))
with state_input from nwqlib.problems. preparations is the only
required argument. It holds the ordered content hashes and physical
scales of the states, not their data. Pass its reference as
Eigenproblem(subspace=...) to request exactly this trial basis.
FixedGCIM then rejects a basis that differs from it.
Attributes:
-
preparations(tuple[StatePreparationSpec, ...]) –Required, nonempty. One preparation record per trial state, in basis order.
-
convention(Literal['normalized prepared columns']) –Default
"normalized prepared columns", the only accepted value. Each state enters as its normalized preparation column.
Examples:
>>> from nwqlib import Eigenproblem, solve
>>> from nwqlib.algorithms import FixedGCIM, FixedGCIMBasis
>>> from nwqlib.problems import state_input
>>> basis = ([1, 1], [1, 1j])
>>> preparations = tuple(state_input(v).preparation for v in basis)
>>> record = FixedGCIMBasis(preparations=preparations)
>>> problem = Eigenproblem(A=[[1, 0], [0, -1]], subspace=record.reference)
>>> result = solve(problem, method=FixedGCIM(basis=basis), seed=7)
>>> print(round(result.eigenvalue, 10))
-1.0
Grow the basis adaptively¶
ADAPT ¶
Bases: Method
Adaptive GCiM (ADAPT-GCIM) method for the smallest eigenvalue of an Eigenproblem.
It grows its trial basis from a pool of generators. Build it with
keyword arguments and pass it as method=, for example
solve(Eigenproblem(A=H), method=ADAPT(initial_state=psi, pool=generators)).
initial_state and pool are required. The result is an
ADAPTResult whose
eigenvalue is the lowest projected Ritz value in the trial basis the run
built.
The method follows ADAPT-GCIM of Zheng et al., npj Quantum Inf. 10, 127
(2024), arXiv:2312.07691v3. Each round screens the current product state
with the ADAPT gradient <[H, A_i]> of every unselected generator (main
text, "Integration of GCIM with ADAPT approach", p. 4, and Grimsley et
al. (2019), arXiv:1812.11173v2, Sec. II.B, steps 5-7). The selected
generator enters at the fixed angle theta, and the basis grows by two
states per selection (METHODS, p. 9). A selected generator is not
screened again, following the paper's QuGCM adapt_gcim.py
implementation (commit c5efcb0, lines 303-398), whereas Grimsley et al.
step 7 permits reuse in its ADAPT-VQE ansatz. Optimization every
optimize_every_m selections is the intermittent, truncated optimization
of Appendix H, and its extra energy evaluations run through the same Run.
Because later queries act on generators selected from earlier outcomes,
prepare(plan, settings="all") is refused.
The default flat-counter stop follows METHODS, p. 9: stop after
T = min(T_auto, T_usr) consecutive energy changes below
energy_change_tolerance, with T_auto equal to t_auto_fraction
(20%) of the unselected generators and T_usr = t_user. Counting starts
at the first change from the reference energy, and the integer counter
reaches a fractional T at its ceiling. QuGCM's code instead uses a max
rule with 10% and a warmup. With max_iterations=8 and t_user=10, the
flat counter can fire only for pools of at most 42 generators. After k
selections a pool of P generators has P - k unselected members and a
flat count of at most k, so the stop needs k >= 0.2*(P - k). The
iteration cap is checked first and ends the run at the eighth selection,
so k <= 7 and P <= 42. Larger pools reach the iteration cap first
unless another stop applies. Every stop, including the gradient-norm
floor, is an operational rule, not proof of ground-state accuracy.
result.analyze(overlap_cutoff=...) solves the saved basis again at
another cutoff. The GCiM guide describes the
screening rule, the pools and the stopping rules.
Attributes:
-
initial_state(StateData) –Required. Reference state in the operator's original basis, in a form that
StateDataaccepts. -
pool(Any) –Required. A nonempty tuple of anti-Hermitian generators,
FermionicGeneratorrecords or operators thatoperator_inputaccepts, or the name of a built-in fermionic pool:"spin_adapted_sd","uccsd_sd","qeb_sd"or"ceo_ovp". Pools other than"spin_adapted_sd"need an occupation-number reference state. -
n_spatial_orbitals(PositiveInt | None) –Default
None. Number of spatial orbitals, required by a named pool, with twice as many qubits.Nonefor an explicit pool. -
theta(Real) –Default
pi/4, nonzero. Angle in radians of each selected generator's exponential. -
gradient_norm_floor(Real) –Default
1e-8, nonnegative. The run stops when the norm of the pool gradients falls below it. -
energy_change_tolerance(Real) –Default
1e-6, positive. Absolute change between consecutive energies below which the flat counter counts a round. -
t_auto_fraction(Real) –Default
0.2, in (0, 1]. Fraction of the unselected pool size that setsT_auto. -
t_user(PositiveInt) –Default
10. CapT_usron consecutive flat rounds in the rulemin(T_auto, T_usr). A fractional round count is rounded up. -
max_iterations(PositiveInt) –Default
8. Largest number of selection rounds. The basis holds at most2*min(max_iterations, pool size)states, somax_basis_size=64allows at most 32 selections for a pool of more than 32 members. The default is a cost cap. With exact evaluation and the spin-adapted pool, the H4 chain of the eigenvalue example reaches FCI at the eighth selection, and 10-qubit LiH is then 0.46 mHa above its FCI energy. The flat counter would stop them only at selections 18 and 19 (Engineering constants). -
overlap_cutoff(Real) –Default
1e-12, positive. Overlap eigenvalue cutoff that defines the kept Gram subspace. -
symmetrize_matrices(bool) –Default
True. Request Hermitian averaging in the projected solve. The raw measured values are still checked. -
stop_criterion(Literal['flat_counter', 'residual_norm']) –Default
"flat_counter", which counts repeated small changes."residual_norm"uses the full-state residual||(H - E) psi||of the normalized Ritz state psi of the current basis, which only classical execution can evaluate. It differs from the pencil'sprojected_residual||H c - E S c||in basis coordinates. -
residual_norm_tolerance(Real) –Default
1.6e-3, positive. Threshold on that full-state residual for the residual stop, in the Hamiltonian's energy unit. -
optimize_every_m(PositiveInt | None) –Default
None, no optimization. Run coefficient optimization every m selected generators. -
optimize_rounds_n(PositiveInt | None) –Default
None. Largest number of BFGS iterations per optimization, required together with the other two optimization settings. -
optimize_max_evaluations(PositiveInt | None) –Default
None. Largest number of energy queries for enabled optimization, counted as distinct measured parameter points. A classical point is one energy-and-gradient evaluation, whose work record includes its forward, derivative and reverse Taylor work. -
max_basis_size(PositiveInt) –Default
64. Limit on the size of the growing trial basis, checked before matrix construction. -
max_pool_size(PositiveInt) –Default
1024. Limit on the number of generators, checked before a pool is expanded. -
max_bytes(PositiveInt) –Default 10 GB (decimal,
10_000_000_000bytes). Limit on the known bytes of the pool, matrices, states and readout workspace. -
max_products(PositiveInt) –Default
1_000_000_000. Limit on the counted work of conversion, matrices and operator products. It also limits, separately, the exact synthesis of the dense unitaries in a supplied reference circuit and Qiskit's control of them. Before a classical query starts, its reference, generator, Hamiltonian and scalar work are summed and checked, and each later query is checked afresh. Packed Pauli tables are checked once per Plan. The recorded allowance covers a whole query, while the counters record the actions performed after cache reuse. -
input_conversion(Literal['auto', 'dense_pauli']) –Default
"auto", which keeps the accepted input access."dense_pauli"permits explicit dense-to-Pauli conversion. -
max_conversion_work(PositiveInt) –Default
100_000_000. Separate limit on the work of the chosen input conversion. -
pauli_coefficient_cutoff(Real) –Default
1e-14, nonnegative. Operator coefficients at or below it in magnitude are removed, and the removed mass is recorded. -
input_symmetry_tolerance(Real) –Default
1e-12, nonnegative. Relative Frobenius window for the anti-Hermitian projection of each pool generator. The Hamiltonian gets no window and must be exactly Hermitian.
Raises:
-
ValueError–If
thetais zero, if only some of the three optimization settings are given, or if an explicit pool is empty or has more thanmax_pool_sizemembers.
Examples:
H = Z has lowest eigenvalue -1. From |+>, ADAPT with the
one-generator pool {iY} returns it after one selection:
>>> from nwqlib import Eigenproblem, solve
>>> from nwqlib.algorithms import ADAPT
>>> from nwqlib.operators import ingest_pauli
>>> pool = (ingest_pauli((("Y", 1j),), num_qubits=1),)
>>> method = ADAPT(initial_state=[1, 1], pool=pool)
>>> result = solve(Eigenproblem(A=[[1, 0], [0, -1]]), method=method, seed=7)
>>> print(result.selected, result.stop_reason, round(result.eigenvalue, 10))
(0,) pool_exhausted -1.0
ADAPTResult ¶
Bases: Result
Smallest projected eigenvalue from an ADAPT run, with its history and stop reason.
solve returns it for an ADAPT method, and
load_result reopens a saved one. The answer is eigenvalue, the lowest
projected Ritz value of the processed Hamiltonian in the basis given by
value_selected and value_theta, in the unit of the Eigenproblem. It
establishes neither the ground state nor coverage of the adaptive search.
stop_reason says why the run ended, history holds one round per
projected analysis, and pencil holds the projected matrices. selected
and theta describe the latest generators and angles, while
value_selected and value_theta describe the basis behind eigenvalue
and pencil. They differ when a generator was selected or optimized
after the last projection, and reanalysis always uses the value basis.
print(result) shows the value, its scope and the stop reason. The
fields below are read-only. The fields of
Result are present too.
Attributes:
-
eigenvalue(Real | None) –Lowest projected Ritz value of the processed Hamiltonian, or None. It establishes neither the ground state nor coverage of the adaptive search.
-
selected(tuple[Count, ...]) –Pool indices chosen so far, in selection order.
-
theta(tuple[Real, ...]) –Current angles of those generators, in radians.
-
value_selected(tuple[Count, ...]) –Pool indices of the basis behind
eigenvalue. -
value_theta(tuple[Real, ...]) –Angles of the basis behind
eigenvalue. -
history(tuple[AdaptRound, ...]) –One
AdaptRoundper completed projected analysis. -
pencil(ProjectedPencil | None) –The
ProjectedPencilof the value basis, or None. -
stop_reason(Text) –Why the run stopped. Scientific stops are
gradient_norm_floor,flat_counter,residual_norm_threshold,pool_exhausted,max_iterations,optimization_evaluation_budget_exhausted,no_usable_overlap_subspaceandinvalid_sampled_evidence. Execution states arerunning,cancelled,partial_observation,pending_preparation,pending_acquisition,uncertain_preparation,uncertain_native_intent,backend_failedandnot_started. -
pending(tuple[Text, ...]) –Labels of queries or statuses that blocked further progress.
-
optimizer_attempts(Count) –Number of optimizer invocations started.
-
optimizer_rounds(Count) –Completed BFGS iterations over all invocations.
-
optimizer_restarts(tuple[dict, ...]) –Records of BFGS restarts from a saved incumbent after the run was resumed.
-
energy_queries(Count) –Energy queries counted against
optimize_max_evaluations. -
analysis_attempts(Count) –Projected analyses started by the run.
-
analysis_cutoff(Real) –Overlap-eigenvalue cutoff of this analysis.
-
target_identification(Text) –Fixed statement of what the value does not establish.
projected_diagnostics ¶
projected_diagnostics()
Return the stored Gram matrix and solve diagnostics for projected checks.
It reads the stored pencil and runs no new solve.
result.verify(checks=ProjectedVerificationOptions(...)) uses it.
Returns:
-
diagnostics(ProjectedDiagnostics) –Its
overlap,spectrum,normalizationandbackward_errorare the pencil'soverlap,overlap_eigenvalues,overlap_normalization_errorandprojected_backward_error, the last on the physical pencil (H, S). All four are None when there is no pencil.
AdaptRound ¶
Bases: Record
One projected analysis of an ADAPT run and the selection that followed it.
ADAPTResult.history holds one per completed projected analysis. A round
keeps the values that drove its decision, so a later reanalysis of the
Result at another cutoff does not change it. The fields below are
read-only.
Attributes:
-
iteration(Count) –Number of selected generators in the basis of this round.
-
selected(tuple[Count, ...]) –Pool indices of those generators in selection order.
-
theta(tuple[Real, ...]) –Their angles at this analysis, in radians.
-
energy(Real | None) –Lowest projected Ritz value of this round, or None.
-
gradient_norm(Real | None) –Euclidean norm of the screened product-state gradients, or None when no screening followed.
-
gradients(tuple[tuple[Count, Real], ...]) –(pool_index, <[H, A_i]>)pairs for the unselected generators. -
winner(Count | None) –Pool index selected next, or None when no screening followed or the gradient-norm floor stopped the run.
-
residual_norm(Real | None) –Full-space residual
||(H - E) psi||of the normalized Ritz state. It is recorded only under"residual_norm"stopping and is None otherwise. -
flat_count(Count) –Consecutive small energy changes counted after this round.
-
contribution_ids(tuple[str, ...]) –Observation data first collected after the previous round's screening and up to this round's screening, including any optimizer energy queries in between.
-
basis_realization(Text | None) –Content hash of the query that supplied the diagonal of the full selected product, which the completed matrix stage must contain: the shared full-chain query of an exact quantum run, whose screening values the later screen reuses, or the diagonal pair query otherwise.
-
analysis_attempt(Count) –Analysis attempt of the run that produced this round.
-
optimizer_attempts(Count) –Cumulative optimizer invocations at this round.
-
optimizer_rounds(Count) –Cumulative completed BFGS iterations at this round.
-
energy_queries(Count) –Cumulative energy queries counted against
optimize_max_evaluations. -
sampled_failure(Text | None) –Sampled-pencil failure or enclosure excursion code, or None.
-
sampled_enclosure_violation(Real | None) –Distance of the sampled Ritz value outside the Pauli L1 enclosure of the processed operator, or None.
AdaptVerificationOptions ¶
Bases: Record
Options for checking the Ritz state of an ADAPT result.
Build it with keyword arguments, for example
AdaptVerificationOptions(name="adapt", comparisons=("residual", "sector")),
and pass it to result.verify(checks=...). name and comparisons are
required. "residual" and "sector" rebuild the Ritz state of the
processed Hamiltonian, and "supplied_reference_energy" compares two
recorded numbers. No reference eigensolve runs. A zero residual can
belong to an excited eigenstate, sector expectations do not prove sector
membership, and the signed spin contamination keeps its sign. The
GCiM guide gives the work limits of these
checks.
Attributes:
-
name(Text) –Required. Prefix for the check names of these options.
-
comparisons(tuple[Literal['residual', 'sector', 'supplied_reference_energy'], ...]) –Required. Distinct nonempty tuple of
"residual","sector"and"supplied_reference_energy". -
residual_tolerance(Real) –Default
1.6e-3, positive. Residual threshold in the problem's energy unit for the non-sampledresidual_threshold_metclassification. -
reference_spin(Real) –Default
0.0. Spin quantum number s, a nonnegative integer or half-integer, whoses(s+1)defines the spin contamination. -
reference_energy(FramedFact | None) –Default
None. Supplied reference energy, with the quantity and unit it refers to and its source, required by"supplied_reference_energy". It must be a concrete real scalar without point restrictions. -
reference_tolerance(Real | None) –Default
None. Positive absolute comparison threshold for that energy, required by"supplied_reference_energy". -
max_bytes(PositiveInt) –Default 10 GB (decimal,
10_000_000_000bytes). Limit on the known bytes of the verification workspace. -
max_products(PositiveInt) –Default
1_000_000_000. Limit on the counted state and operator work of the verification, including the exact synthesis of the dense unitaries in a supplied reference circuit.
Raises:
-
ValueError–If
comparisonsis empty or repeats a check, ifreference_spinis not an integer or half-integer, or if"supplied_reference_energy"lacksreference_energyorreference_tolerance, or has them without that comparison. Also ifreference_energyis not a concrete real scalar with a source and no point restrictions.
Build a molecular problem¶
build_gcim_chemistry_problem ¶
build_gcim_chemistry_problem(geometry: Any, *, basis: str = 'sto-3g', charge: int = 0, spin: int = 0, unit: str = 'Angstrom', name: str | None = None, coefficient_cutoff: float = 1e-12, active_space: tuple[int, int] | None = None, reference_methods: tuple[str, ...] = ()) -> GCIMChemistryProblemData
Build a closed-shell molecular Hamiltonian for GCiM and ADAPT from a geometry.
PySCF performs RHF and the molecular-orbital integral transforms, NWQLib
assembles the spin-orbital fermionic operator, and OpenFermion performs
only the Jordan-Wigner transform. It needs the chemistry extra,
pip install "nwqlib[chemistry]". MP2, CCSD or active-space CASCI
references run only when reference_methods requests them. Integrals
are in the RHF molecular-orbital basis, with each orbital's first AO coefficient above
1e-8 of its largest magnitude made positive.
The Hamiltonian is
E_c + sum h_pq a_p^dagger a_q + 1/2 sum h_pqrs a_p^dagger a_q^dagger a_r a_s
over interleaved spin orbitals, mapped by Jordan-Wigner with spin orbital
j on qubit j.
Parameters:
-
geometry(Any) –PySCF atom specification, for example
"H 0 0 0; H 0 0 0.74". -
basis(str, default:'sto-3g') –PySCF basis name.
-
charge(int, default:0) –Total molecular charge.
-
spin(int, default:0) –2S. Only 0, closed-shell RHF, is supported. -
unit(str, default:'Angstrom') –Unit of the coordinates,
"Angstrom"or"Bohr". -
name(str | None, default:None) –Optional label stored in
metadata. -
coefficient_cutoff(float, default:1e-12) –Absolute cutoff in Hartree. Fermionic terms and final Pauli coefficients at or below it are dropped, and an imaginary part at or below it is set to zero.
-
active_space(tuple[int, int] | None, default:None) –Optional
(n_active_electrons, n_active_orbitals). For a molecule of N electrons the lowest(N - n_active_electrons)/2RHF orbitals are frozen as doubly occupied core, and PySCF CASCI supplies the effective one- and two-body integrals and the core energy. -
reference_methods(tuple[str, ...], default:()) –Any of
"mp2","ccsd"and"casci"to run as application context."casci"needsactive_space.
Returns:
-
data(GCIMChemistryProblemData) –The Hamiltonian, reference state and integrals of the selected full or active space.
Raises:
-
ValueError–For an open-shell or odd-electron molecule, an invalid active space, an unsupported reference method,
"casci"withoutactive_space, a negative cutoff or an unconverged RHF. -
ImportError–If PySCF or OpenFermion is not installed.
Examples:
H2 in the STO-3G basis at 0.74 Angstrom maps to four qubits. ADAPT
with the default spin-adapted pool returns -1.137284 Hartree, the
lowest eigenvalue of data.hamiltonian by exact diagonalization,
below the RHF energy of -1.116759 Hartree:
>>> from nwqlib import solve
>>> from nwqlib.algorithms.gcim import build_gcim_chemistry_problem
>>> data = build_gcim_chemistry_problem("H 0 0 0; H 0 0 0.74")
>>> print(data.num_qubits, data.reference_occupations)
4 (1, 1, 0, 0)
>>> print(round(data.rhf_energy, 6))
-1.116759
>>> result = solve(data.eigenproblem(), method=data.adapt_method(), seed=7)
>>> print(round(result.eigenvalue, 6))
-1.137284
GCIMChemistryProblemData ¶
GCIMChemistryProblemData(*, hamiltonian: SparsePauliOp, reference_preparation: QuantumCircuit, reference_occupations: tuple[int, ...], n_spatial_orbitals: int, num_qubits: int, num_electrons: int, nuclear_repulsion_energy: float, constant_energy: float, rhf_energy: float, one_body_integrals: ndarray, two_body_integrals: ndarray, reference_panel: Mapping[str, Any] = dict(), metadata: Mapping[str, Any] = dict())
Molecular Hamiltonian, reference state and integrals from build_gcim_chemistry_problem.
build_gcim_chemistry_problem returns it. eigenproblem() gives the
Eigenproblem, and adapt_method(...) an ADAPT method with the
matching reference state. Energies and integral coefficients are in
Hartree. The builder uses the converged closed-shell RHF molecular orbitals
and interleaved alpha/beta spin modes. Each orbital's sign is fixed so
that its first significant AO coefficient is positive. This removes the
dependence on the eigensolver's sign choice, which could flip the
generators that contain the orbital and change a fixed-angle ADAPT-GCIM
trajectory. It fixes signs only. Degenerate orbitals can still be
returned in another rotation of their subspace, and binary64 rounding
can still decide between generators whose gradients tie in exact
arithmetic (GCiM guide).
In tensor shapes below, n is n_spatial_orbitals. Requested reference
calculations give application context and do not certify the solver.
The fields below are read-only.
Attributes:
-
hamiltonian(SparsePauliOp) –Jordan-Wigner SparsePauliOp for the selected full or active space, including its constant offset and the requested coefficient cutoff.
-
reference_preparation(QuantumCircuit) –Computational-basis circuit preparing the recorded closed-shell occupations from zero. Inspecting it runs no chemistry solve.
-
reference_occupations(tuple[int, ...]) –Zero/one occupation per qubit in interleaved spatial-orbital alpha/beta order, which
adapt_methoduses as the reference state. -
n_spatial_orbitals(int) –Number of selected spatial orbitals, reduced to the active orbital count when an active space was requested.
-
num_qubits(int) –Twice n_spatial_orbitals for the Jordan-Wigner spin-orbital register.
-
num_electrons(int) –Electrons in the selected Hamiltonian space, which is the active electron count when frozen-core reduction is used.
-
nuclear_repulsion_energy(float) –Original molecule's nuclear repulsion contribution.
-
constant_energy(float) –Scalar offset before Jordan-Wigner mapping: nuclear repulsion for the full space, or the returned frozen-core energy for an active space. This is not necessarily the entire final Pauli-identity coefficient.
-
rhf_energy(float) –Converged full-molecule RHF total energy, including nuclear repulsion.
-
one_body_integrals(ndarray) –Spatial-orbital tensor of shape (n,n) in the RHF orbital basis, or the active-space effective one-body tensor with frozen-core contributions.
-
two_body_integrals(ndarray) –Spatial-orbital tensor of shape (n,n,n,n), obtained by transposing the chemist-ordered integrals with axes (0,2,3,1). After spin expansion, entries multiply a_p^dagger a_q^dagger a_r a_s with factor 1/2.
-
reference_panel(Mapping[str, Any]) –RHF and explicitly requested MP2/CCSD/CASCI values/statuses. Unrequested or failed reference energies stay None with their status/reason.
-
metadata(Mapping[str, Any]) –Geometry and basis, charge, ordering, cutoff, active space and dependency versions of this construction.
to_dictomits the large integral tensors.
eigenproblem ¶
eigenproblem()
Return the Eigenproblem of hamiltonian, in Hartree with its constant offset.
adapt_method ¶
adapt_method(**settings)
Return an ADAPT method with this molecule's reference state and the spin-adapted pool.
Parameters:
-
**settings(object, default:{}) –Further
ADAPTarguments. They override the defaults set here:initial_state(the occupation state ofreference_occupations),pool="spin_adapted_sd"andn_spatial_orbitals.
Returns:
-
method(ADAPT) –The configured method.
to_dict ¶
to_dict() -> dict[str, Any]
Return a JSON-like summary of the fields, without the integral tensors.
The summary holds the orbital, qubit and electron counts, the
nuclear-repulsion, constant and RHF energies, the reference panel,
the reference occupations, the Pauli term count of hamiltonian and
metadata.
closed_shell_reference_occupations ¶
closed_shell_reference_occupations(*, n_spatial_orbitals: int, num_electrons: int) -> tuple[int, ...]
Return the closed-shell RHF occupation bitstring in interleaved spin-orbital order.
Spin orbitals 2k and 2k + 1 are the alpha and beta orbitals of
spatial orbital k, and the lowest num_electrons/2 spatial orbitals are
doubly occupied.
Parameters:
-
n_spatial_orbitals(int) –Positive number of spatial orbitals.
-
num_electrons(int) –Nonnegative even number of electrons, at most
2*n_spatial_orbitals.
Returns:
-
occupations(tuple[int, ...]) –2*n_spatial_orbitalszeros and ones.
Raises:
-
ValueError–For an odd electron count or more electrons than the orbitals can hold.
Examples:
>>> from nwqlib.algorithms.gcim import closed_shell_reference_occupations
>>> closed_shell_reference_occupations(n_spatial_orbitals=3, num_electrons=2)
(1, 1, 0, 0, 0, 0)
qubit_operator_to_sparse_pauli ¶
qubit_operator_to_sparse_pauli(qubit_operator: Any, *, num_qubits: int, coefficient_cutoff: float = 1e-12) -> SparsePauliOp
Convert an OpenFermion QubitOperator to a Qiskit SparsePauliOp.
In a Qiskit label qubit 0 is the rightmost character, so OpenFermion
qubit j becomes label position num_qubits - 1 - j. Terms with
magnitude at or below coefficient_cutoff are dropped, an imaginary part
at or below it is set to zero, and equal labels are then combined by
SparsePauliOp.simplify with the same absolute tolerance.
Parameters:
-
qubit_operator(Any) –The OpenFermion
QubitOperator. -
num_qubits(int) –Positive number of qubits.
-
coefficient_cutoff(float, default:1e-12) –Nonnegative absolute cutoff on coefficients.
Returns:
-
operator(SparsePauliOp) –The converted operator, or the zero operator on
num_qubitsqubits when no term remains.
Raises:
-
ValueError–If
num_qubitsis not positive,coefficient_cutoffis negative, or a term acts on a qubit outsidenum_qubits.
Compare with chemistry references and spin sectors¶
chemistry_reference_diagnostic ¶
chemistry_reference_diagnostic(metadata: Mapping[str, Any], *, energy: float | None) -> dict[str, Any] | None
Return the stored chemistry reference energies and correlation fractions for an energy.
It reads metadata["chemistry_reference_panel"], which
build_gcim_chemistry_problem stores, and adds the full-space CCSD
correlation fraction (E - E_HF)/(E_CCSD - E_HF) and the active-space
CASCI fraction (E - E_HF)/(E_CASCI - E_HF) when the needed energies
are present. A zero denominator is recorded as the note
"undefined: E_CCSD == E_HF" or "undefined: E_CASCI == E_HF". It runs
no calculation. The values give application context, not a bound on the
error of E or an identification of the ground state. The
GCiM guide
prints the report section of such a diagnostic.
Parameters:
-
metadata(Mapping[str, Any]) –The
metadataof aGCIMChemistryProblemData. -
energy(float | None) –The energy E to compare, for example
result.eigenvalue, or None.
Returns:
-
diagnostic(dict | None) –The reference panel and the fractions, or None when
metadataholds no reference panel.
chemistry_reference_report_section ¶
chemistry_reference_report_section(diagnostic: Mapping[str, Any]) -> ReportSection
Format a chemistry reference diagnostic as a "Chemistry References" report section.
The section lists E_HF, E_MP2 and E_CCSD, plus E_CASCI for an active
space, and the correlation fractions that the diagnostic holds. A
missing energy shows its recorded status and reason, or unavailable.
result.report() does not include this section, so print or store it
beside the report.
Parameters:
-
diagnostic(Mapping[str, Any]) –A diagnostic from
chemistry_reference_diagnostic.
Returns:
-
section(ReportSection) –The formatted lines in
section.linesand the diagnostic insection.data.
correlation_fraction ¶
correlation_fraction(energy: float, e_hf: float, e_ccsd: float) -> float
Return the correlation fraction (E - E_HF) / (E_CCSD - E_HF) of an energy.
The fraction gives application context, not a bound on the error of E.
chemistry_reference_diagnostic uses it with the stored reference
energies.
Parameters:
-
energy(float) –The energy E to compare.
-
e_hf(float) –The Hartree-Fock energy, in the unit of E.
-
e_ccsd(float) –The CCSD energy, or another reference energy such as CASCI, in the unit of E.
Returns:
-
fraction(float) –(E - E_HF) / (E_CCSD - E_HF).
Raises:
-
ValueError–If
E_CCSD - E_HFis zero.
sector_expectations ¶
sector_expectations(state: ndarray, *, num_qubits: int | None = None, reference_spin: float = 0.0) -> dict[str, Any]
Return the exact particle number, spin projection and total spin of a state.
The returned dict holds <N>, <S_z> and <S^2> of the normalized
state and the spin contamination <S^2> - s(s+1) for
s = reference_spin, which keeps its sign. Qubit j is spin orbital j in
the interleaved order of the fermionic pools: even qubits are alpha
(S_z = +1/2) and odd qubits beta. <N> and <S_z> are diagonal in the
occupation basis and come from bit probabilities. <S^2> uses a
matrix-free action of S^2. These expectations describe the state. A
value equal to a sector's eigenvalue does not prove membership in that
sector, and the result is marked "validation_gate": False.
For the computed probability vector p, m_j = sum_(x: x_j = 1) p_x
gives <N> = sum_j m_j and <S_z> = (1/2) sum_j (-1)**j m_j by
exchanging two finite sums. At most q marginal scalars are stored, and
fsum then forms the two weighted sums. Multiplication by one half is
exact when it does not underflow. With P = sum p_x, M = N/2,
gamma(r) = r*u/(1 - r*u) and unit roundoff u, each marginal error is
at most gamma(M - 1)*m_j for normal arithmetic. The difference from
the occupation-diagonal dot products on the same p is
T_N <= q*P*[gamma(N) + gamma(M - 1) + u*(1 + gamma(M - 1))] for <N>
and T_{S_z} <= T_N/2 (Higham, Accuracy and Stability of Numerical
Algorithms, 2nd ed., Lemma 3.1 and Chapter 3,
doi:10.1137/1.9780898718027). Absolute underflow terms are added if
reached.
Parameters:
-
state(ndarray) –State vector of length
2**q, nonzero. It is normalized before use. -
num_qubits(int | None, default:None) –Number of qubits q, or None to infer it from the length.
-
reference_spin(float, default:0.0) –Spin quantum number s of the reference sector.
Returns:
-
expectations(dict) –The keys
particle_number,spin_z,spin_squared,reference_spinandspin_contamination, withlabel,evaluationandvalidation_gatedescribing them.
Raises:
-
ValueError–If the state length is not a power of two, does not match
num_qubits, or the state is zero.
Examples:
The two-qubit state |11> doubly occupies spatial orbital 0:
>>> from nwqlib.algorithms.gcim import sector_expectations
>>> v = sector_expectations([0, 0, 0, 1])
>>> print(v["particle_number"], v["spin_z"], v["spin_squared"])
2.0 0.0 0.0
solve calls plan and the other hooks of a Method. Extending NWQLib describes them.