Skip to content

Structural layer

pauli

Pauli strings and Pauli sums: exact Pauli algebra without operator construction.

Coefficients are complex numbers; the Pauli algebra is entered after the parameters have been bound. Two Pauli strings commute if and only if they differ in an even number of tensor positions, the product of two strings is a string times a phase, and the commutator of two Pauli sums is a Pauli sum. No Hilbert space is constructed.

The single-qubit conventions are shared with qsimod.realise.hilbert:

  • the local basis index is the occupation number, |0> is empty and |1> is occupied;
  • Z = 2n - 1 = diag(-1, +1), X = [[0,1],[1,0]], Y = [[0,i],[-i,0]];
  • hence n = (Z + 1)/2, sigma^+ = |1><0| = (X + iY)/2, sigma^- = (X - iY)/2 and XY = iZ; the axes are right-handed.

IDENTITY_STRING module-attribute

IDENTITY_STRING = PauliString()

The identity Pauli string.

PauliAxis

Bases: Enum

One of the three Pauli axes.

PauliString dataclass

A tensor product of Pauli operators that acts as the identity on every unlisted qubit.

Attributes:

Name Type Description
axes tuple[tuple[int, PauliAxis], ...]

the (qubit, axis) pairs on which the string acts non-trivially, ascending by qubit. The empty tuple is the identity.

mapping property
mapping: dict[int, PauliAxis]

The string as a {qubit: axis} mapping.

support property
support: frozenset[int]

The qubits on which the string acts non-trivially.

weight property
weight: int

The locality of the string, that is, the number of qubits on which it acts.

is_identity property
is_identity: bool

Whether the string is the identity.

sort_key property
sort_key: tuple[int, tuple[tuple[int, str], ...]]

A total order on strings, by weight, then by qubit and axis letter.

of classmethod
of(axes: Mapping[int, PauliAxis]) -> PauliString

Construct a string from a {qubit: axis} mapping.

single classmethod
single(qubit: int, axis: PauliAxis) -> PauliString

The string that acts with axis on a single qubit.

commutes_with
commutes_with(other: PauliString) -> bool

Whether the two strings commute.

Two strings anticommute on every position where both act with different axes; they commute if and only if the number of such positions is even.

times
times(other: PauliString) -> tuple[PauliString, complex]

The product self * other, as a string and a phase.

PauliSum dataclass

A real or complex linear combination of Pauli strings.

Attributes:

Name Type Description
terms Mapping[PauliString, complex]

the coefficient of each string. Strings with a coefficient below COEFFICIENT_TOLERANCE are dropped on construction.

name str

a display name, used in reports.

is_zero property
is_zero: bool

Whether the sum is empty.

strings property
strings: tuple[PauliString, ...]

The strings present, in PauliString.sort_key order.

support property
support: frozenset[int]

The union of the supports of all strings.

max_weight property
max_weight: int

The largest locality of any string.

one_norm property
one_norm: float

The one-norm sum |coefficient|, an upper bound on the spectral norm.

Every Pauli string has spectral norm one, so ||sum c_P P|| <= sum |c_P|.

from_terms classmethod
from_terms(
    terms: Iterable[tuple[PauliString, complex]],
    name: str = "",
) -> PauliSum

Construct a sum; repeated strings are merged and cancelled strings are dropped.

zero classmethod
zero(name: str = '') -> PauliSum

The empty sum.

scaled
scaled(factor: complex) -> PauliSum

The sum with every coefficient multiplied by factor.

times
times(other: PauliSum) -> PauliSum

The operator product self * other.

adjoint
adjoint() -> PauliSum

The Hermitian adjoint.

Pauli strings are self-adjoint, so the coefficients are conjugated.

renamed
renamed(name: str) -> PauliSum

A copy carrying a different display name.

is_hermitian
is_hermitian(tolerance: float = 1e-12) -> bool

Whether every coefficient is real to within tolerance.

internally_commuting
internally_commuting() -> bool

Whether every pair of strings in the sum commutes.

commutes_with
commutes_with(other: PauliSum) -> bool

Whether [self, other] = 0 exactly, decided by computing the commutator.

identity_coefficient
identity_coefficient() -> complex

The coefficient of the identity string, that is, the additive constant.

weight_histogram
weight_histogram() -> dict[int, int]

The number of strings of each locality.

commutator

commutator(left: PauliSum, right: PauliSum) -> PauliSum

The commutator [left, right] = left*right - right*left, exactly.

nested_commutator

nested_commutator(operands: list[PauliSum]) -> PauliSum

The nested commutator [operands[-1], [..., [operands[1], operands[0]]]].

The brackets are evaluated from the innermost outwards.

Raises:

Type Description
ValueError

if fewer than two operands are given.

pauli_sum_from_operator

pauli_sum_from_operator(
    hamiltonian: OperatorSum,
    environment: Mapping[str, float],
    structure: StructureType | None = None,
    name: str = "",
) -> PauliSum

Expand a bound symbolic Hamiltonian into a Pauli sum.

Parameters:

Name Type Description Default
hamiltonian OperatorSum

the symbolic sum; its coefficients are evaluated at environment.

required
environment Mapping[str, float]

parameter values.

required
structure StructureType | None

if given, every site in the support of the Hamiltonian is checked to be two-level.

None
name str

a display name for the result.

''

Returns:

Type Description
PauliSum

The Pauli sum.

Raises:

Type Description
ValueError

if the model has a site whose algebra is not two-level, or an operator with no Pauli expansion.

trotter

Suzuki-Trotter product formulas, their a-priori error bounds and their resource summary.

The package implements the digital simulator model of the article, the product formula U_approx. It is generic over any Hamiltonian given as a layer decomposition of a Pauli sum: the a-priori error bound is computed from the commutators of the layers, and the resource summary counts gates and circuit depth in layers. Both are derived from the term structure by Pauli algebra.

layers

Layer decompositions of a Hamiltonian and the commutation structure between layers.

A layer is a group of Pauli terms that mutually commute; each layer therefore exponentiates exactly into a product of one rotation per term. A decomposition is either declared (declared_layers) or derived by first-fit greedy grouping (derive_layers). Whether two layers commute is decided by computing their commutator.

Layer dataclass

One group of mutually commuting Pauli terms.

Attributes:

Name Type Description
name str

a label, used in reports and in resource summaries.

operator PauliSum

the terms of the layer, as a Pauli sum.

support property
support: frozenset[int]

The qubits on which the layer acts.

term_count property
term_count: int

The number of Pauli strings in the layer.

one_norm property
one_norm: float

The one-norm sum |coefficient|, an upper bound on the spectral norm of the layer.

is_internally_commuting
is_internally_commuting() -> bool

Whether every pair of strings in the layer commutes.

is_diagonal
is_diagonal() -> bool

Whether every string is a product of Z operators only.

LayerDecomposition dataclass

An ordered partition of a Hamiltonian into layers of mutually commuting terms.

Attributes:

Name Type Description
layers tuple[Layer, ...]

the layers, in the order in which a product formula visits them.

provenance str

"declared" or "derived".

names property
names: tuple[str, ...]

The layer names, in order.

support property
support: frozenset[int]

The union of the supports of all layers.

qubit_count property
qubit_count: int

The register size implied by the support, max qubit index + 1.

one_norm property
one_norm: float

The sum sum_gamma ||H_gamma||_1 of layer one-norms, an upper bound on ||H||.

total
total() -> PauliSum

The Hamiltonian that the decomposition partitions, the sum of all layers.

layer_commutator
layer_commutator(first: int, second: int) -> PauliSum

The commutator [H_first, H_second] as an exact Pauli sum.

commuting_pairs
commuting_pairs() -> frozenset[tuple[int, int]]

The index pairs (i, j), i < j, whose layers commute exactly.

non_commuting_pairs
non_commuting_pairs() -> tuple[tuple[int, int], ...]

The index pairs (i, j), i < j, whose layers do not commute, sorted.

commutation_report
commutation_report() -> str

A textual table stating which pairs of layers commute.

layer_named
layer_named(name: str) -> Layer

The layer with the given name.

Raises:

Type Description
KeyError

if no layer has that name.

declared_layers

declared_layers(
    groups: Sequence[tuple[str, PauliSum]],
) -> LayerDecomposition

Construct a decomposition from an explicitly declared, ordered partition.

Raises:

Type Description
ValueError

if any group is not internally commuting.

derive_layers

derive_layers(
    hamiltonian: PauliSum, name_prefix: str = "layer"
) -> LayerDecomposition

Partition a Pauli sum into layers of mutually commuting terms by a greedy algorithm.

The strings are visited in PauliString.sort_key order and placed by first fit: each string joins the first existing layer with all of whose strings it commutes, or opens a new layer.

Parameters:

Name Type Description Default
hamiltonian PauliSum

the Pauli sum to partition.

required
name_prefix str

the stem for the generated layer names.

'layer'

Returns:

Type Description
LayerDecomposition

The decomposition, with provenance "derived".

Raises:

Type Description
ValueError

if hamiltonian is empty.

formulas

Suzuki-Trotter product formulas as stage schedules independent of the Hamiltonian.

A stage schedule is an ordered list of (layer index, coefficient) pairs whose coefficients sum to one on every layer; qsimod.trotter.schedule applies a schedule to a layer decomposition. The first-order Lie-Trotter formula, the second-order Strang formula and the Suzuki recursion for any even order 2k >= 4 are provided, with

S_2k(tau) = S_2k-2(p tau)**2 . S_2k-2((1 - 4p) tau) . S_2k-2(p tau)**2, p = 1 / (4 - 4**(1/(2k-1))).

Adjacent stages on the same layer are merged by the identity exp(-i a H) exp(-i b H) = exp(-i (a+b) H) at every level of the recursion; stages are not merged across step boundaries.

Stage dataclass

One exponential in a product formula.

Attributes:

Name Type Description
layer int

the index of the layer that the stage exponentiates.

coefficient float

the multiple of the step size tau in the exponent.

ProductFormulaSchedule dataclass

An ordered list of stages: one step of a product formula, independent of the Hamiltonian.

Attributes:

Name Type Description
order int

the order p of the formula; the error per step is O(tau**(p+1)).

layer_count int

the number of layers the schedule addresses.

stages tuple[Stage, ...]

the stages, from left to right as written; stages[0] is the leftmost factor of the product.

merged bool

whether adjacent same-layer stages were merged.

stage_count property
stage_count: int

The number of exponentials in one step.

one_norm_of_coefficients property
one_norm_of_coefficients: float

sum_s |c_s|, as used by the Taylor-remainder error bound.

is_symmetric property
is_symmetric: bool

Whether the stage list is invariant under reversal.

lie_trotter

lie_trotter(layer_count: int) -> ProductFormulaSchedule

The first-order Lie-Trotter formula, one full-step exponential per layer in layer order.

Raises:

Type Description
ValueError

if there are no layers.

strang

strang(layer_count: int) -> ProductFormulaSchedule

The second-order symmetric formula of Strang.

For three layers this is the conventional S_2, exp(-i H_0 tau/2) exp(-i H_1 tau/2) exp(-i H_2 tau) exp(-i H_1 tau/2) exp(-i H_0 tau/2).

Raises:

Type Description
ValueError

if there are no layers.

suzuki_parameter

suzuki_parameter(order: int) -> float

The Suzuki recursion parameter p = 1 / (4 - 4**(1/(2k-1))) for order = 2k.

Raises:

Type Description
ValueError

if order is not an even integer of at least four.

suzuki

suzuki(
    order: int, layer_count: int
) -> ProductFormulaSchedule

The product formula of the given order over layer_count layers.

Parameters:

Name Type Description Default
order int

1 for Lie-Trotter, 2 for Strang, or any even 2k >= 4 for the Suzuki recursion.

required
layer_count int

the number of layers.

required

Returns:

Type Description
ProductFormulaSchedule

The stage schedule.

Raises:

Type Description
ValueError

for an unsupported order.

supported_orders

supported_orders(maximum: int = 8) -> tuple[int, ...]

The orders suzuki accepts, up to maximum.

bounds

A-priori error bounds of product formulas in the spectral norm.

error_bound returns the minimum of the applicable bounds:

  • for order 1, the commutator bound || exp(-iHt) - S_1(t/n)**n || <= (t**2 / 2n) sum_{g<g'} ||[H_g, H_g']||;
  • for order 2, the commutator bound of Childs et al. with tau = t/n and the tail R_g = sum_{g'>g} H_g', per step (tau**3/12) sum_g ||[R_g, [R_g, H_g]]|| + (tau**3/24) sum_g ||[H_g, [R_g, H_g]]||;
  • for every order, the stage-based Taylor-remainder bound t**(p+1) / (p+1)! / n**p * (||H|| + sum_s |c_s| ||H_g(s)||)**(p+1).

Norms are supplied by a NormEstimator; the default AdaptiveNormEstimator is exact up to DEFAULT_SPECTRAL_QUBIT_LIMIT qubits and uses the Pauli one-norm beyond.

NormEstimator

Bases: ABC

An estimator that provides an upper bound on the spectral norm of a Pauli sum.

norm abstractmethod
norm(operator: PauliSum) -> float

An upper bound on ||operator|| in the spectral norm.

is_exact abstractmethod
is_exact() -> bool

Whether the estimate is the spectral norm itself rather than a bound.

OneNormEstimator dataclass

Bases: NormEstimator

The bound sum |c_P| obtained from the triangle inequality on the Pauli coefficients.

norm
norm(operator: PauliSum) -> float

The one-norm sum |c_P| of the coefficients.

is_exact
is_exact() -> bool

Always False; the one-norm is a bound, not the spectral norm itself.

SpectralNormEstimator dataclass

Bases: NormEstimator

The exact spectral norm, obtained by constructing the dense operator and diagonalising it.

Attributes:

Name Type Description
qubits int

the register size in which the operator is constructed; it must cover the support of the operator.

norm
norm(operator: PauliSum) -> float

||operator|| in the spectral norm.

is_exact
is_exact() -> bool

Always True.

AdaptiveNormEstimator dataclass

Bases: NormEstimator

An estimator that is exact on small registers and uses the one-norm bound on larger ones.

Attributes:

Name Type Description
qubits int

the register size.

limit int

the largest register size for which the exact spectral norm is computed.

norm
norm(operator: PauliSum) -> float

The estimate of the delegate, the exact or the one-norm estimator.

is_exact
is_exact() -> bool

Whether the exact estimator is the delegate.

ErrorBound dataclass

An a-priori bound on || exp(-iHt) - S_p(t/n)**n || in the spectral norm.

Attributes:

Name Type Description
value float

the bound.

order int

the order of the formula.

time float

the simulated time t.

steps int

the step count n.

method str

the family of bounds that produced value.

candidates Mapping[str, float]

every candidate bound computed, by method name.

components Mapping[str, float]

the quantities from which the chosen bound is assembled, for instance individual commutator norms.

norm_estimator str

the name of the norm estimator.

exact_norms bool

whether the underlying norms were exact spectral norms.

commutator_bound

commutator_bound(
    decomposition: LayerDecomposition,
    order: int,
    time: float,
    steps: int,
    estimator: NormEstimator,
) -> ErrorBound | None

The commutator bound, implemented for orders 1 and 2.

Returns:

Type Description
ErrorBound | None

The bound, or None for an order above 2.

Raises:

Type Description
ValueError

if steps is not positive.

taylor_remainder_bound

taylor_remainder_bound(
    decomposition: LayerDecomposition,
    schedule: ProductFormulaSchedule,
    time: float,
    steps: int,
    estimator: NormEstimator,
) -> ErrorBound

The stage-based Taylor-remainder bound stated in the module docstring.

Raises:

Type Description
ValueError

if steps is not positive.

error_bound

error_bound(
    decomposition: LayerDecomposition,
    schedule: ProductFormulaSchedule,
    time: float,
    steps: int,
    estimator: NormEstimator | None = None,
) -> ErrorBound

The tightest available a-priori error bound at the given settings.

Parameters:

Name Type Description Default
decomposition LayerDecomposition

the layer decomposition to which the formula is applied.

required
schedule ProductFormulaSchedule

the stage schedule.

required
time float

the simulated time.

required
steps int

the number of Trotter steps.

required
estimator NormEstimator | None

the norm estimator; defaults to AdaptiveNormEstimator on the register of the decomposition.

None

Returns:

Type Description
ErrorBound

The minimum of the applicable bounds; every candidate is recorded.

schedule

The product-formula artifact, the digital simulator model U_approx of the article.

The artifact is an ordered sequence of k-local unitaries on a qubit register, parametrised by the simulated time t, the step count n and the order of the product formula. ProductFormulaModel stores the layer decomposition and the stage schedule; the (Pauli string, angle) factors of one step are derived on demand and the step is repeated n times. Factors are listed from left to right as written, so that the rightmost factor acts first on a state.

Depth convention: a depth layer is a maximal run of consecutive factors with pairwise disjoint support; the depth is computed for one step and multiplied by n, without packing across step boundaries. Resources are counted as k-local unitaries and depth layers only; no gate-set decomposition, CNOT count or routing is performed.

UnitaryFactor dataclass

One k-local unitary exp(-i angle * string) of a product formula.

Attributes:

Name Type Description
string PauliString

the Hermitian Pauli string that is exponentiated.

angle float

the real rotation angle.

layer str

the name of the Hamiltonian layer from which the factor originates.

support property
support: frozenset[int]

The qubits on which the factor acts.

locality property
locality: int

The number k of qubits on which the factor acts.

ResourceSummary dataclass

The resource summary of a product formula, independent of any particular hardware.

Attributes:

Name Type Description
qubits int

the register size.

steps int

the Trotter step count n.

order int

the order of the product formula.

time float

the simulated time t.

factors_per_step int

the number of k-local unitary factors in one step.

factor_count int

the total number of factors, factors_per_step * steps.

factors_by_locality Mapping[int, int]

the number of factors acting on each number of qubits, totalled over all steps.

depth_per_step int

the depth of one step in layers of factors with disjoint support.

depth_in_layers int

the total depth depth_per_step * steps, without packing across step boundaries.

hamiltonian_layers int

the number of layers of mutually commuting terms in the Hamiltonian.

stages_per_step int

the number of exponentials in one step of the formula.

global_phase_per_step float

the angle contributed by identity Pauli strings.

error_bound float

the a-priori error bound at the given settings.

error_bound_method str

the family of bounds that produced error_bound.

exact_norms bool

whether the norms entering the bound were exact spectral norms.

as_row
as_row() -> dict[str, float | int | str]

A flat mapping, suitable for instance as a pandas row.

ProductFormulaModel dataclass

Bases: Artifact

An ordered product of k-local unitaries on a qubit register, the digital simulator model.

Attributes:

Name Type Description
layers LayerDecomposition

the partition of the Hamiltonian into layers of mutually commuting terms.

formula ProductFormulaSchedule

the stage schedule of the product formula.

time float

the simulated time t.

steps int

the Trotter step count n.

kind property
kind: ArtifactKind

Always PRODUCT_FORMULA.

order property
order: int

The order of the product formula.

qubit_count property
qubit_count: int

The register size, from the structural type.

step_size property
step_size: float

The step size tau = t / n.

step_factors
step_factors() -> tuple[UnitaryFactor, ...]

The k-local unitary factors of one step, from left to right as written.

result[0] is the leftmost factor of the product. Identity strings are excluded; their contribution is reported by global_phase_per_step.

global_phase_per_step
global_phase_per_step() -> float

The angle contributed by identity Pauli strings in one step.

support_structure
support_structure() -> tuple[frozenset[int], ...]

The support of each factor of one step, in order.

resources
resources(
    estimator: NormEstimator | None = None,
) -> ResourceSummary

The complete resource summary; no operator is constructed.

error_bound
error_bound(
    estimator: NormEstimator | None = None,
) -> ErrorBound

The a-priori error bound at the (t, n, order) of this artifact.

with_steps
with_steps(steps: int) -> ProductFormulaModel

A copy with a different step count.

with_schedule
with_schedule(
    schedule: ProductFormulaSchedule,
) -> ProductFormulaModel

A copy with a different product formula, that is, a different order.

step_matrix
step_matrix() -> Array

The unitary of one step, as a dense array.

Each factor is cos(angle) I - i sin(angle) P, since a Pauli string squares to the identity.

matrix
matrix() -> Array

The full propagator S_p(t/n)**n, by binary exponentiation of the step unitary.

apply_to_state
apply_to_state(state: Array) -> Array

Apply the product formula to a state vector.

Each factor is applied as cos(angle)|psi> - i sin(angle) P|psi> at cost O(k * dimension); the n steps are executed under jax.lax.fori_loop. The rightmost factor acts first, as in the written product.

factors_for

factors_for(
    decomposition: LayerDecomposition,
    schedule: ProductFormulaSchedule,
    step_size: float,
) -> tuple[UnitaryFactor, ...]

The k-local unitary factors of one step of schedule at step size step_size.

result[0] is the leftmost factor of the product. Identity Pauli strings are excluded; their contribution is reported by global_phase_for.

global_phase_for

global_phase_for(
    decomposition: LayerDecomposition,
    schedule: ProductFormulaSchedule,
    step_size: float,
) -> float

The angle contributed by identity Pauli strings in one step.

layer_depth_of

layer_depth_of(factors: Sequence[UnitaryFactor]) -> int

The depth of an ordered factor sequence, counted in layers of factors with disjoint support.

The assignment is greedy and respects the order: a factor joins the current layer if its support is disjoint from every support in that layer; otherwise a new layer is started.

as_product_formula

as_product_formula(
    artifact: Artifact, subject: str = "this operation"
) -> ProductFormulaModel

Narrow an artifact to a product formula, verifying its kind.

Parameters:

Name Type Description Default
artifact Artifact

the artifact to narrow.

required
subject str

the name of the operation reported in the diagnostic.

'this operation'

Returns:

Type Description
ProductFormulaModel

The artifact, typed as a product formula.

Raises:

Type Description
ArtifactKindError

if the artifact is not a product formula.