Skip to content

Conventions

These conventions fix the sign of time evolution, phase units, qubit and bit order, units, normalization and error metrics in every NWQLib method. Rows named after a method give a convention specific to that method. Paper notation often differs. The docstring of the implementing function states each departure, and each algorithm guide's source map links its steps to paper equations. The Code column names the module whose docstring states the convention.

Frequent lookups: count keys and Pauli labels, occupation strings, sign of time evolution, Eigenphase in turns, units are labels, norms of each error and block encodings and QSP phases.

Time evolution, phases and Hadamard tests

Convention Statement Code
Evolution sign A Hermitian generator H evolves as exp(-i t H). This covers Pauli-evolution blocks and product formulas, QSP evolution of a block encoding of A (exp(-i t A) at effective time alpha * t), the controlled powers U = exp(-i tau H) of QPE, each LCHS branch exp(-i t (k L + H)) with A = L + i H, and each QHD step. subroutines/hamiltonian_evolution/pauli_evolution.py, subroutines/qsp/evolution.py, algorithms/qpe/method.py, algorithms/lchs/time_independent_terms.py, algorithms/qhd/compiler.py
QHD schedule QHD.schedule is a record whose kind names the formula of the weights in H(t) = a(t) K + b(t) V, with K the kinetic operator and V the objective. "quadratic" has a = 1/(1 + gamma t²) and b = 1 + gamma t², "cubic" has a = 2/(s + t³) and b = 2t³, and "shifted_cubic" has a = (2/(s + t))³ and b = 2t³. The record holds only its own parameter, which belongs to the model and stays fixed when num_steps changes, and its kind enters the Method identity. Step k covers [k dt, (k+1) dt]. The "midpoint" coefficient rule takes a and b at the step midpoint, and "integrated" takes the step averages of their interval integrals. algorithms/qhd/schedules.py step_weights
Linear dynamics LinearDynamics is du/dt = -A u + source, so the homogeneous solution is expm(-A (time - initial_time)) initial_state. problems/records.py LinearDynamics
ADAPT generators Pool members are anti-Hermitian generators A_j. Basis states apply exp(theta A_j) to the reference, and the screening gradient is <[H, A_j]>. At a fixed angle, replacing A_j by -A_j changes the basis. subroutines/fermionic_pool.py, algorithms/gcim/adapt_acquisition.py
Eigenphase Eigenphase is phi in turns, in [0, 1), with U v = exp(2 pi i phi) v. For a Hamiltonian, U = exp(-i tau H) and phi = -tau E / (2 pi) modulo 1, so the phase order need not follow the energy order. result.eigenvalue is the estimator's energy itself, and phase is computed from it. Converting phase back fixes E only modulo 2 pi / tau. For a unitary, estimator_value is a principal angle in radians. problems/records.py Eigenphase, algorithms/qpe/records.py energy_phase_turns
Estimator target An Eigenproblem asks for the smallest eigenvalue in its full space or explicit sector, while a QPE estimator returns one eigencomponent of the prepared state. QCELS, RFE and RWPE are verified against the cluster of largest prepared weight. SPE locates the lowest component on its coordinate. For a Hamiltonian that is the lowest energy. For a unitary it is the lowest principal eigenphase, which for U = exp(-i tau H) is the highest energy when tau times the spectral radius keeps every prepared phase inside (-pi/2, pi/2), the interval that the scan covers. Supplying H, or U† = exp(i tau H), targets the lowest energy. SPE verification compares the lowest cluster of the dense spectrum and checks its prepared weight against overlap_lower_bound, unless QPEVerification.minimum_overlap is set. problems/records.py Eigenproblem, algorithms/qpe/method.py SPE, algorithms/qpe/numerical.py spe, algorithms/qpe/verification.py
Hadamard test The ancilla starts in |+>, controls the operation and is measured in Z after a final Hadamard. With ancilla phase s before the final Hadamard, the mean P(0) - P(1) is Re(exp(i s) z), so s = 0 gives Re z and s = -pi/2 (S†) gives +Im z. QPE measures z_p = <psi|U^p|psi>, and its exact static route reads the same two quadratures as the ancilla X and Y expectations at each power position of one controlled trajectory, with no phase or final Hadamard. ADAPT's sampled queries measure z = <phi_i|P|phi_j> for the Pauli words P of the Eigenproblem operator A, so the stored pencil entries are H_ij = <phi_i|A|phi_j> and S_ij = <phi_i|phi_j>. Sampled FixedGCIM obtains the same entries from grouped joint-state counts, one system group at a time, and exact FixedGCIM and ADAPT from each pair's saved state. algorithms/qpe/method.py _quantum_program, algorithms/gcim/adapt_acquisition.py, algorithms/gcim/pencil.py
Parity readout Outcome 0 of a measured Pauli parity is the eigenvalue +1, so a mean is (n0 - n1)/n. evidence/binary.py, algorithms/expectation.py
Controlled phases Under control, a global phase becomes a relative phase, so no identity term is dropped. QPE applies the identity coefficient c_I of a Pauli Hamiltonian on the control through phase increments P(-c_I (p_k - p_(k-1)) tau) between adjacent static power positions, and as P(-p tau c_I) at an RWPE time. Each LCHS product-formula branch applies exp(-i t c_I(k)), where c_I(k) is the identity coefficient of k L + H. Dense powers and branches keep c_I inside their matrices, and their controlled matrices are synthesized exactly because Qiskit's controlled UnitaryGate can err (Dependency issues). blocks/selection.py, algorithms/qpe/method.py _split_pauli_terms, algorithms/lchs/time_independent_terms.py _combined_trotter_terms, subroutines/_dense_synthesis.py

Qubit, bit and mode order

"Little-endian" refers to index significance, k = sum_q b_q 2**q. Strings are described by the position of qubit 0 rather than by an endianness adjective, because the index order and the written order of a label run in opposite directions.

Object Order Code
Coordinate index Qubit 0 is the least significant bit and the rightmost tensor factor. operators/inputs.py ORDER
Pauli labels, count keys, printed kets Qubit 0, or classical bit 0, is the rightmost character. operators/inputs.py, execution.py CountBin
Probability keys The first requested qubit is the rightmost character. An adapter's dense float64 array or (indices, values) pair takes the first requested qubit as the least significant index bit. backends/connection.py, _prepared_execution.py _probability_output
Samples arrays Increasing int64 original-coordinate indices with their int64 counts. Bit 0 of an index is coordinate qubit 0. _quantum_readout.py reduce_sample_arrays
Compact labels x0z2 is X on qubit 0 and Z on qubit 2. subroutines/hamiltonian_evolution/pauli_labels.py
Occupation strings Qubit 0 is the leftmost character. "10" occupies qubit 0, has index 1 and prints as the ket |01>. A count key read as an occupation string must be reversed first. A Samples index is the coordinate index itself. problems/inputs.py ingest_occupation
Product-state rows Row j belongs to qubit j. problems/inputs.py ingest_product
Fermionic modes Mode j is qubit j, and an occupied mode is |1>. The Jordan–Wigner image is a_j = (prod_{k<j} Z_k)(X_j + i Y_j)/2, and the rightmost operator of an ordered ladder string acts first. operators/_fermion.py, subroutines/fermionic_pool.py
Spin orbitals Spin orbital (p, sigma) is mode 2p + sigma, with sigma 0 for alpha. The chemistry builder, the named ADAPT pools and the sector checks use this interleaved order, and a Hamiltonian in blocked order does not match them. subroutines/fermionic_pool.py, algorithms/gcim/chemistry.py, operators/df.py, algorithms/gcim/sector.py
Ancilla, index and control registers They occupy the low-order qubits, before the system register. Papers write the ancilla register first, as in (<0^a| ⊗ I) U (|0^a> ⊗ I) and sum_j |j><j| ⊗ U_j. In NumPy order the first is the block U[::2**a, ::2**a] of stride 2^a that block_encoding_top_left returns, and the second is sum_j kron(U_j, |j><j|). subroutines/block_encoding/core.py, subroutines/lcu/core.py, blocks/selection.py
Padding A non-power-of-two input of dimension d occupies coordinates 0 to d-1, and the dummy coordinates follow. The dummy diagonal is alpha in QLS, zero in LCHS, the mean diagonal trace(A)/d in padded Lanczos, GCIM, ADAPT and QPE Hamiltonians, and one for a QPE unitary. Outputs and Samples exclude the dummy coordinates. algorithms/qls/host_planning.py, algorithms/lchs/time_independent_terms.py, algorithms/_eigen_inputs.py, algorithms/qpe/method.py, amplitudes.py, _quantum_readout.py reduce_sample_arrays
QHD registers QHD.encoding selects the register, "one_hot" by default or "binary", which requires boundary="periodic" and K a power of two. For d variables with K grid points each, one-hot encoding uses d * K qubits. Binary encoding uses d * log2(K) qubits and requires K = 2**b with b>=1 on a periodic grid. Both have K ** d valid grid states. The full one-hot Hilbert space also contains invalid states, whereas binary encoding uses every basis state for a grid point. Changing boundary conditions or grid size changes the finite problem. A local quantum simulation checks its encoded qubit count against max_simulation_qubits before allocating the readout state space. With K grid points per variable, grid point i of variable j is qubit j*K + i in the one-hot encoding. In the binary encoding, with K = 2**b, bit l of the grid index of variable j is qubit j*b + l, so the statevector index is sum_j n_j K**j. Classical restricted arrays order grid-index tuples lexicographically, with variable 0 most significant, so a full-register statevector, where variable 0 holds the low-order qubits, and a restricted array give variable 0 opposite significance. The binary conversion reverses the variable axes and keeps the bits within each variable. algorithms/qhd/grid.py, algorithms/qhd/binary.py, algorithms/qhd/decoding.py, algorithms/qhd/theory.py, algorithms/qhd/split_step.py, algorithms/qhd/records.py

Units and frames

Convention Statement Code
Units are labels Problem.unit labels the primary result and LinearDynamics.time_unit labels time. No conversion is performed. Error frames match units only when symbol and dimension agree exactly, so "Ha" and "Hartree" differ, and a plain string (dimension custom) differs from a Unit with dimension energy. An output record's unit labels only a quantity that neither the Problem nor the output kind labels. A unit with another symbol than the Problem-defined or fixed one, such as Eigenvalue(unit="eV") for a Problem in "Hartree" or any unit other than "turn" on Eigenphase, raises ValueError at planning. problems/records.py OutputRecord.frame, core/records.py Unit
Time A * time and tau * E are dimensionless, so QPE's tau carries the inverse energy unit. problems/records.py, algorithms/qpe/method.py
Chemistry build_gcim_chemistry_problem(...).eigenproblem() is in "Hartree" and includes the constant energy offset. algorithms/gcim/chemistry.py
Lanczos H = center I + alpha K with the spectrum of K in [-1, 1], where center is the identity coefficient of a Pauli input or the Gershgorin center of a matrix. Moments, the Gram matrix, its cutoff, gram_sampling_bound, empirical_gram_noise_frobenius_rms and projected_backward_error are dimensionless quantities of K. An identity offset of a Pauli input leaves them unchanged. For a matrix input the Gershgorin frame widens its enclosure by a roundoff allowance proportional to |center|, so an offset c changes alpha, and these quantities, by a relative amount of order eps |c| / alpha. hamiltonian, eigenvalue and eigenvalues are in the physical unit. algorithms/lanczos/method.py, algorithms/_eigen_inputs.py gershgorin_frame, algorithms/lanczos/numerical.py, algorithms/lanczos/records.py
GCIM and ADAPT identity offset The projected solve uses H0 = H - c S, where H is the projected matrix and c the identity component of the Eigenproblem operator A (its Pauli identity coefficient, or trace(A)/d for a dense or sparse matrix), and adds c to the Ritz values. Quantum queries never measure the identity term, and classical queries remove c from the Pauli table or the stored diagonal before they project. projected_backward_error is computed on the physical pencil (H, S) with H = H0 + c S, so an identity offset changes it, unlike the Lanczos value. algorithms/gcim/fixed_basis.py, algorithms/gcim/adapt_acquisition.py _pair_scalars, _projected_eigensolver.py
QHD The Hamiltonian uses the kinetic operator -Delta/2 on the box coordinates (hbar = 1, unit mass) and the objective's numerical values. A unit label does not rescale the dynamics, and rescaling the objective or the box changes the dynamics at fixed total_time. algorithms/qhd/kinetic.py, algorithms/qhd/compiler.py
QHD constraints ConstrainedOptimization stores residuals, h_i(x) = 0 for an equality and g_j(x) <= 0 for an inequality, so Eq(p, q) and Le(p, q) become p - q and Ge(p, q) becomes q - p. The augmented-Lagrangian layer evaluates the original residuals at the projected point x and uses the normalized tentative multipliers lambda+ = lambda_bar + rho H(x) and mu+ = max(0, mu_bar + rho G(x)). With F=f/s_f, H=h/s_h and G=g/s_g, where the original functions are differentiable, the vector grad F + J_H^T lambda+ + J_G^T mu+ is the gradient of the PHR effective objective L_k at x, including when the inner problem uses slack coordinates. Its stationarity diagnostic works in the unit coordinates u of the box [a, b], with x = a + D u and D = diag(b - a). problems/records.py ConstrainedOptimization, algorithms/qhd/constrained.py
QHD augmented-Lagrangian scales Every tolerance, the penalty measure and the complementarity test act on the normalized f/s_f, h_i/s_{h_i} and g_j/s_{g_j}, with the scales objective_scale, equality_scales and inequality_scales, whose default 1 assumes a dimensionless problem. The multipliers and MultiplierBounds belong to this scaled problem, and ConstrainedQHDResult.multipliers converts them to original units with lambda_i = (s_f/s_{h_i}) lambda~_i and mu_j = (s_f/s_{g_j}) mu~_j. The record keeps the original-unit residuals next to the normalized ones. algorithms/qhd/constrained_records.py AugmentedLagrangian, algorithms/qhd/constrained.py
QHD refinement coordinates With BoxRefinement.scaling="physical" a level solves the original objective on the level box in original coordinates. With "search_model", the default, a level solves on the unit box u in [0, 1]^d, with variables named u_<name> and x = a + D u for the lower corner a and side lengths D = diag(L_j) of the level box, the objective kappa (F(a + D u) - c)/E, where kappa is BoxRefinement.gain, the explicit potential_gain or 8 without one, and E (energy_scale) and c (energy_shift) are in the units of F. Its kinetic -1/2 sum_j d²/du_j² is the same at every level and is not the original kinetic. Every reported point and box face comes from the level grid's coordinates. A search-model level records its unit coordinate as unit_point and reports point, the image a + D u rounded once to binary64. algorithms/qhd/refinement.py, algorithms/qhd/refinement_records.py RefinementLevel
Error frames OutputRecord.frame fixes the quantity, metric, unit, scope and conditioning in which evidence about an output is stated. ErrorFrame adds the domain, and two frames are compatible only when all six fields agree. problems/records.py, evidence/error_model.py ErrorFrame

Normalization

Convention Statement Code
States A vector input keeps its physical norm and phase. For a nonzero vector, the input check forms the direction v/||v|| once. A zero vector is accepted with zero norm and no direction. PhysicalScale stores a norm as a binary mantissa and exponent. problems/inputs.py
Outputs Solution and a physical StateVector carry the physical scale and phase. A unit StateVector has norm one. modulo_global_phase leaves the returned amplitudes unchanged. It changes the comparison metric to phase_aligned_l2 and the declared phase of the output array, and the QLS shortcut solvers accept a StateVector only in this form. NormSquared is u†u, QuadraticForm is u†Ou and NormalizedExpectation is u†Ou/u†u. problems/records.py
Block encodings The all-zero ancilla block is A/alpha, and error_bound bounds ||A - alpha * block||_2 in the units of A. For an LCU of unitaries, alpha = sum_j |c_j|, PREP prepares sum_j sqrt(|c_j|/alpha) |j> and SELECT applies the coefficient phases. A combination of block encodings with subnormalizations alpha_j has alpha = sum_j |c_j| alpha_j. subroutines/block_encoding/core.py, subroutines/lcu/core.py, subroutines/qsp/evolution.py, Block encodings and QSP
QLS recovery For the default qsvt_inverse solver, x = ||b|| (polynomial_kappa s / alpha) (P/s)(A/alpha) b/||b||, where P is the stored fit polynomial.coefficients and s its rescale. The circuit implements P/s. The shortcut solvers return a unit direction without a physical norm. algorithms/qls/method.py _realize
LCHS recovery Without a source the physical solution is alpha times the QSP amplitude factor times ||u0|| times the success-projected amplitudes. With a constant source the branch coefficients already contain the input norms. A PSD shift multiplies each coefficient by exp(shift * t) for its elapsed time t, and when that factor exceeds binary64 a power of two moves from the coefficients into the recovery. coefficient_l1_norm is therefore dimensionless for the kernel table of a classical or source-free Plan, and in the solution's unit for the branch layout of a quantum constant-source Plan. algorithms/lchs/quantum.py plan_quantum, algorithms/lchs/source_selection.py, algorithms/lchs/primary_records.py
Recovery scale of an observation ObservationChunk.physical_scale is the norm of the output vector in LCHS and in QLS with the qsvt_inverse solver, which analysis multiplies into the unit solution direction, and the norm of the supplied input state in Expectation, Lanczos and QPE. QHD, FixedGCIM and ADAPT host chunks record None with a reason, because their scalars need no recovery. A QLS shortcut chunk records None because the shortcut recovers no physical norm, and quantum circuit chunks other than amplitude readout carry None. execution.py ObservationChunk, blocks/kernels.py KernelOutput
Masses and samples A mass or success probability is an unconditional probability over all returned outcomes. Samples bins are conditional on the method's success event and exclude dummy coordinates. QHD expected_objective is conditional on an outcome that encodes a grid point, which every binary outcome does. amplitudes.py, _quantum_readout.py, algorithms/qhd/records.py
Reused symbols alpha is a block-encoding subnormalization or LCU one-norm, except in Lanczos, where it is the half-width of the spectral enclosure, and in binary inference, where alpha = delta/F is the failure probability of one of F settings. s is the QLS rescale, the squared state norm in Expectation, the PSD shift and the Duhamel source time in LCHS, and the ancilla phase in QPE. kappa_be = max(1, alpha/sigma_min) when kappa="auto" and the singular endpoints are known, and the supplied kappa otherwise, polynomial_kappa = max(kappa_be, 1.01), except that the analytic periodic encoding with kappa="auto" uses alpha / min(sigma_min, encoded gap) rounded outward, and condition_number = sigma_max/sigma_min. algorithms/qls/host_planning.py, algorithms/expectation.py, evidence/binary.py, algorithms/lchs/solution_error_budget.py, algorithms/lanczos/records.py, algorithms/qpe/method.py

Block encodings and QSP

A unitary U on a + n qubits is an (alpha, a, epsilon) block encoding of A when the all-zero ancilla block approximates A / alpha, equivalently ||A - alpha (<0^a| (x) I) U (|0^a> (x) I)|| <= epsilon. Every BlockEncoding records alpha, ancilla and system widths, its operator-error bound, and the resolved implementation as canonical fields. Polynomial transformations act on A / alpha, so simulating exp(-i A t) uses effective time alpha * t. Products multiply subnormalizations, while an LCU combination has subnormalization sum_j |c_j| alpha_j.

Tensor formulas in these docs and in docstrings write the ancilla, label or control register first, as the papers do, for example (<0^a| (x) I) U (|0^a> (x) I) above and SELECT = sum_j |j><j| (x) sign(c_j) P_j. The circuits place that register on the low-order qubits, starting at qubit 0. A dense matrix of such a circuit in Qiskit's Kronecker order, whose qubit 0 is the least significant index, therefore reads (I (x) <0^a|) U (I (x) |0^a>) and sum_j sign(c_j) P_j (x) |j><j|. The written order is notation, and the stored register order decides the qubit positions. Saved relation strings keep the paper order.

The project uses the Wx QSP convention, W(x) = [[x, i sqrt(1-x^2)], [i sqrt(1-x^2), x]], with phases applied as exp(i phi Z). Since Qiskit uses RZ(theta) = exp(-i theta Z / 2), a direct exp(i phi Z) is RZ(-2 phi). The projector-phase circuit of build_qsvt_circuit applies reflection-convention phases phi' instead, which wx_phases_to_reflection computes from the Wx phases as phi'_0 = phi_0 - pi/4, phi'_d = phi_d - pi/4 and phi'_j = phi_j - pi/2 for 0 < j < d (Martyn et al., arXiv:2105.02859v5, Eq. (14) and App. A.2, Eq. (A5)). Each phase step flips the signal qubit onto the projector subspace Pi, applies RZ(+2 phi'_j) = exp(-i phi'_j Z) and flips back, which realizes exp(i phi'_j (2 Pi - 1)). The circuit's global phase d pi / 2 multiplies the reflection-form product by i^d, which makes the encoded block the Wx polynomial, and this global phase stays correct under control. Phase ordering and convention are part of the contract and may not be silently reversed, conjugated, or renormalized. The all-zero phase vector of length d + 1 realizes T_d(x) and remains the convention known-answer test.

Composition combines only errors with compatible mathematical metrics, domains and premises. A sum of multiplicities times unitary operator-norm bounds needs the applicable telescoping relation and is not a general total-error rule. State-preparation agreement on the all-zero input does not establish full-unitary equivalence under control, adjoint or workspace reuse. Solver residual criteria, physical operator error and model/cost uncertainty remain distinct. Small dense matrix extraction is a test oracle, not the runtime definition of a structured encoding.

Code: subroutines/block_encoding/core.py, subroutines/lcu/core.py, subroutines/qsp/phases.py wx_phases_to_reflection, subroutines/qsp/evolution.py.

Error quantities

Convention Statement Code
Absolute or relative An output's error metric is absolute (OutputRecord.metric defaults to absolute_error). A relative criterion or a relative_l2 metric divides the error by the magnitude or norm of the reference. Without explicit tolerances, the QLS inverse-error and mass checks report a discrepancy divided by its allowance (relative_error_over_method_allowance, heuristic_mass_window_discrepancy_ratio), while shortcut_direction reports its raw discrepancy. problems/records.py OutputRecord.metric, Accuracy, evidence/error_model.py accuracy_threshold, family verification.py modules
Norms and metrics Vector discrepancies use the Euclidean norm in the original coordinates, phase_aligned_l2 for a modulo_global_phase StateVector. Operator bounds for block encodings, product formulas, QSP evolution and the LCHS kernel and quadrature use the spectral norm. The Lanczos Gram noise uses the Frobenius norm. Eigenphase discrepancies use the circular distance in turns, Samples the total variation distance and OptimizationCandidate the objective gap. problems/records.py output metrics, subroutines/block_encoding/core.py, subroutines/trotterization/error_budget.py, algorithms/lanczos/numerical.py
Bounds and intervals A component bound is a one-sided upper bound on a nonnegative error. Hoeffding intervals (doi:10.1080/01621459.1963.10500830) are two-sided, and a family failure probability is divided among the predeclared settings or moments by a union bound. The RWPE 95 percent interval comes from its Gaussian model and carries no frequentist coverage guarantee. evidence/error_model.py ErrorTerm, ErrorModel.assess, evidence/binary.py, algorithms/lanczos/numerical.py, algorithms/qpe/numerical.py
Sampling with exact readout With exact readout, as with shots=None, the sampling error source is zero only for a Method whose estimate averages or emulates no random draw, and Sampling error by method gives the rule for each method. evidence/error_model.py exact_readout_sampling, ErrorModel.assess, algorithms/qpe/method.py _analysis
LCHS frames approximation_tolerance sets operator-norm allowances for a unit input to the shifted propagator, and the reconstruction fields kernel_approximation_bound and quadrature_bound are the bounds chosen at planning in that frame. The facts kernel_approximation and k_quadrature in Plan.facts, which a classical Result also carries in Result.facts, are physical L2 bounds. Each sums, over the physical applications, the input norm times the Duhamel weight times exp(shift * t) times the operator bound. algorithms/lchs/primary_records.py, algorithms/lchs/solution_error_budget.py
Combination Result.assess adds component bounds by the triangle inequality and their failure probabilities by a union bound. It combines only facts stated in a frame compatible with the output's frame. evidence/error_model.py
Verification verdicts result.verify(checks=options) returns (receipt, facts) for every options type. Except for LCHSRefinement, facts answer the options' verification_checks, and Certificate.with_verification with the same options compares each fact with its check's threshold. It gives PASS or FAIL, or INCONCLUSIVE when the check has no threshold, the value is unavailable or a premise is open, as for an LCHSVerification without threshold. core/analysis.py Result.verify, evidence/verification.py witness_check_facts, evidence/error_model.py Certificate.with_verification