API Reference¶
An index of the public surface. For what the knobs mean see
Concepts, for execute()'s keywords see
Circuit Execution, and for runnable code see
Examples.
Gate and operator matrix inputs
Anything taking a one- or two-qubit gate or operator (apply_gate_1q,
apply_gate_2q, expectation_1q, expectation_2q, apply_kraus_*)
accepts a numpy array of dtype complex128: (2, 2) for a 1Q gate,
(4, 4) for a 2Q gate, (n_ops, dim, dim) for a stack of Kraus operators.
On a qudit site of dimension d, the shapes are (d, d) and
(d₁·d₂, d₁·d₂).
A flat list of floats in column-major [re, im, re, im, ...] order is also
accepted, with length 8 for a 1Q gate and 32 for a 2Q gate. It is
deprecated; use numpy arrays.
Bitstring / qubit ordering
TensorWeaver is little-endian by qubit index: bitstring position i is
qubit i. This is the opposite of Qiskit's convention, so bitstrings from
mps.sample_bitstring(), mps.sample(), results.cstates, and
results.histogram() appear reversed compared to Qiskit output. The same
applies to the bitstring argument of mps.amplitude().
High-level¶
execute¶
Every keyword, with its default and when to change it, is documented in Circuit Execution.
tensorweaver.execute(circuit, nsamples=..., *, num_qubits=..., bonddim=..., entdim=..., max_bond_dim=..., sv_cutoff=..., algorithm=..., post_compress=..., strict_bonddim=..., seed=..., bitstrings=..., reorderqubits=..., fuse=..., fuse_threshold=..., canonicaldecompose=..., simplify=..., buffer=..., traversal=..., linalg=..., usegpu=..., usemkl=...)
¶
TwSimulator¶
A reusable simulator. Configuration is fixed at construction; nsamples,
seed, and num_qubits are per call.
Bases: LocalBackend
MPS quantum circuit simulator, backed by the TensorWeaver core.
Subclasses :class:mimiqcircuits.backends.LocalBackend, so the usual
sim.execute(circuit, nsamples=..., seed=...) call works and returns a
:class:mimiqcircuits.QCSResults. :meth:capabilities lists what it can
serve.
Every knob below is set on the constructor and fixed for the life of the instance; build a new simulator to change one. Accepting them per call as well would mean distinguishing "not passed" from "passed the default" on every keyword.
Execution mode. The circuit decides, not a keyword. Trailing
measurements are split off into a classical projection and do not count.
If everything left is unitary, the state is evolved once and nsamples
bitstrings are drawn from it (sampling mode, one entry in
results.fidelities). If any surviving operation on qubits is
non-unitary (a mid-circuit Measure or Reset, a noise channel,
qubit loss), the circuit is re-evolved from scratch nsamples times
(trajectory mode, one fidelity and one cstate per trajectory).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bonddim
|
int
|
Maximum MPS bond dimension, the memory and accuracy knob.
Default |
256
|
entdim
|
int
|
Maximum bond dimension of the MPO that gates are fused into
between state updates. Default |
16
|
sv_cutoff
|
float | None
|
Singular-value floor applied when an MPO is compressed into
the state. |
None
|
mpo_cutoff
|
float | None
|
Singular-value floor applied while gates are fused into the
MPO. |
None
|
algorithm
|
Algorithm
|
How each fused MPO is applied to the state. The names read
as the method plus what it applies:
|
'vmpoa'
|
strict_bonddim
|
bool | None
|
Whether every intermediate bond must stay within
|
None
|
post_compress
|
bool
|
Run the global recond and compression sweep after every
MPO application. Default |
True
|
seed
|
int | None
|
Master RNG seed for every run this instance drives. |
None
|
buffer
|
int
|
Depth of the gate-fusion pipeline. |
0
|
traversal
|
Traversal
|
Order in which gates are walked while they are fused into
MPOs. |
'sequential'
|
linalg
|
Linalg | None
|
Linear-algebra library: |
None
|
usegpu
|
bool
|
Run the state on an NVIDIA GPU. Whether it is faster depends on the bond dimension. The device
wins where the state is large and loses where it is small, because
each site's truncated SVD carries a fixed launch cost that the host
does not pay. Measured on an A30 against one Xeon core, on a
24-qubit brick-layer circuit: 0.8× at |
False
|
max_num_threads
|
int | None
|
The most threads a run of this simulator uses, for
the linear algebra and for sampling alike. |
None
|
usemkl
|
bool | None
|
Deprecated, use |
None
|
Reordering under traversal applies only to the fusable gates between
state-reading or measuring instructions. Measurement, reset, channel,
observable (Amplitude / BondDim / SchmidtRank /
ExpectationValue), barrier and IfStatement stay put and act as
synchronisation points. Within a gate run, two gates are ordered relative
to each other only when they share a qubit.
Which engines a wheel carries depends on the platform, because the compute
core binds the CBLAS and LAPACKE interfaces directly and no one provider
supplies both everywhere: Linux x86-64 ships OpenBLAS, MKL and faer, macOS
arm64 OpenBLAS and faer (MKL is x86-only), Windows x86-64 MKL and faer.
faer is pure Rust and binds neither interface. This is why
linalg defaults to None rather than to an engine name.
Each engine is a separate native module, so linalg and usegpu are
per instance and simulators on different engines can run side by side in one
process. Their objects do not interoperate: an :class:~tensorweaver.MPS,
:class:~tensorweaver.MPO, Rng or :class:~tensorweaver.TwState built
by one engine cannot be passed to a simulator or method using the other,
which raises TypeError. To carry a state across engines, round-trip it
through MPS.serialize() and MPS.deserialize(), which copies it.
Caveats
num_qubits=on :meth:executeis a TensorWeaver-specific kwarg (also accepted by :class:quantanium.QuantaniumQCS); :class:mimiqengines.MPSSimulatordoes not expose it. Code that drives the three simulators with a portablesim.execute(c, nsamples=100, seed=42)shape is unaffected.- Amplitudes requested in trajectory mode reflect the last shot's state,
not an ensemble average, whenever the circuit contains a mid-circuit
measure, reset or
IfStatement. - RNG resolution priority: a call-site
seed=beats the instanceseed, which beats fresh entropy from :mod:secrets. The free functiontensorweaver.execute(...)defaults toseed=42; this method resolves to a concrete int before forwarding, so the two surfaces never collide. - :meth:
bindsubstitutes parameters and re-runs the full compile pipeline; there is no native parametric fast path. - :meth:
evolvereturns(state, TruncationLowerBound)and never promotes toExactFidelityeven whenfid == 1.0, because each MPO application is an SVD truncation event whose fidelity is at best a lower bound.
Examples:
>>> import mimiqcircuits as mc
>>> from tensorweaver import TwSimulator
>>> sim = TwSimulator(bonddim=64)
>>> c = mc.Circuit()
>>> c.push(mc.GateH(), 0)
...
>>> c.push(mc.GateCX(), 0, 1)
...
>>> c.push(mc.Measure(), [0, 1], [0, 1])
...
>>> results = sim.execute(c, nsamples=100, seed=42)
usemkl
property
¶
Deprecated: whether this simulator runs on MKL. Use linalg.
capabilities()
¶
Capability tokens this simulator can serve.
A copy, so a caller cannot mutate the class-level set.
limits()
¶
Resource limits: the configured bonddim as max_bond_dim.
topology()
¶
Connectivity assumed by the MPS evolution: all-to-all.
Long-range gates cost more bond dimension than neighbouring ones, but no routing or SWAP insertion is required of the caller.
build_state(nq, nb=0, nz=0, **_)
¶
Allocate a fresh |0…0⟩ state on nq qubits.
The MPS is capped at this simulator's bonddim and built on this
simulator's engine, so it can only be used with this simulator.
nb and nz size the classical-bit and complex registers.
zerostate(nq, nb=0, nz=0)
¶
Back-compat alias for :meth:build_state.
evolvezerostate(circuit, *, seed=None)
¶
Evolve a fresh zero state through circuit and return it.
Returns (state, fidelity), the fidelity being a plain float
lower bound on the evolved state. This is a single evolution, so a
circuit with mid-circuit measurement or noise gives one trajectory,
not an ensemble; use :meth:execute for that.
Seed resolution: call-site seed=, then the instance seed, then
fresh cryptographic entropy from :mod:secrets.
compile(circuit)
¶
Lower circuit for the MPS evolution loop.
Populates :attr:CompileMetadata.active_qubits. Decomposition to
TensorWeaverBasis and fusion into MPOs happen later, in
:meth:evolve. Qubit reordering is not done here: it is a pass, which
:meth:execute runs before compiling when asked to (see
:meth:reorder_pass).
default_passes()
¶
No passes run by default, so a circuit runs as written.
reorder_pass(method=None, *, seed=None)
¶
The pass execute(reorderqubits=...) adds.
A :class:~tensorweaver.TwReorderQubitsPass scored against this
simulator's bonddim. method=None, which is what
reorderqubits=True asks for, runs the whole search portfolio; a
method name pins one search. To set the pass's alpha or margin,
build it yourself and pass it through passes=.
simplify_pass()
¶
The pass execute(simplify=True) adds.
A :class:~mimiqcircuits.SimplifyPass running
:data:~mimiqcircuits.DEFAULT_SIMPLIFY_PASSES without
resynthesize_2q. That pass rewrites every two-qubit block, which
reorders the gates and makes the MPS evolution slower even when it
saves a CX. To run it anyway, pass a SimplifyPass through
passes=.
expectation(state, op, *qubits)
¶
Compute ⟨ψ|op|ψ⟩ on state without mutating it.
Exact, with no sampling involved. Supports 1- and 2-qubit operators
and a :class:PauliString of any length. qubits are the 0-based
indices op acts on, in the operator's own leg order, and there
must be exactly as many as the operator has qubits.
Raises:
| Type | Description |
|---|---|
ValueError
|
if the qubit count does not match the operator, or if a dense operator acts on three or more qubits. |
evolve(state, compiled, *, rng=None, callback=None, stopped=None)
¶
Evolve state under compiled, in place.
Returns (state, TruncationLowerBound). The product of the per-step
fidelities is always wrapped as :class:TruncationLowerBound, never
collapsed to :class:ExactFidelity even at fid == 1.0, because
that scalar bounds the fidelity from below rather than claiming the
exact state was reproduced.
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
apply_segment(state, insts, *, rng=None)
¶
Fuse a run of loss-free instructions into MPOs and apply it.
Returns the truncation fidelity of the run. Every qubit in the run is present, so fusing it cannot bury an operation a fired loss should have dropped. The run is padded to the register width, so one that misses the high qubits still builds full-width MPOs.
apply_instruction(state, inst, *, rng=None)
¶
Apply a single instruction the driver issues around a loss boundary.
These are a reload Reset, a Check or MeasureCheck
SetBit, or a partial-loss rewrite. A multi-qubit gate has to be
fused into an MPO, so it is routed through :meth:apply_segment;
everything else applies directly to the MPS.
sample_kraus(state, channel, targets, *, rng=None)
¶
Sample one branch of a Kraus channel against the live state and apply it.
Returns (fidelity, fired_operator). The operator returned is the
original one, not a reconstruction, so a LossyOperator branch
reaches the driver with its tag intact.
execute(circuit, *, nsamples=1000, seed=None, rng=None, num_qubits=None, passes=None, fuse=None, fuse_threshold=None, canonicaldecompose=None, reorderqubits=None, remove_swaps=None, simplify=None, reorderqubits_seed=None, callback=None, param_grid=None, strict_pass_order=True, stopped=None, progress=False)
¶
Execute circuit and return :class:QCSResults.
The TensorWeaver configuration (bonddim, entdim, sv_cutoff,
mpo_cutoff, algorithm, strict_bonddim, post_compress,
buffer, traversal, linalg, usegpu) comes from the constructor, not
from this call. Circuit preparation, qubit reordering included, comes
from this call. Amplitudes and expectation values are requested by
putting :class:Amplitude and :class:ExpectationValue operations in
the circuit; they write into results.zstates.
Whether the run is a single evolution plus nsamples draws, or
nsamples independent trajectories, follows from the circuit; see
the class docstring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
circuit
|
Circuit | SweepExperiment | list
|
One circuit, a list of circuits to run in turn, or a
:class: |
required |
nsamples
|
int
|
Bitstrings to draw in sampling mode, or trajectories to
run in trajectory mode. Default |
1000
|
seed
|
int | None
|
Master RNG seed for this run. Overrides the instance
|
None
|
rng
|
Random | None
|
A :class: |
None
|
num_qubits
|
int | None
|
Width of the simulated register. |
None
|
passes
|
PassPipeline | None
|
Extra circuit-preparation passes, appended after the ones the flags below select, as given. |
None
|
fuse
|
bool | None
|
Fuse runs of gates into |
None
|
fuse_threshold
|
int | None
|
Minimum qubit count for |
None
|
canonicaldecompose
|
bool | None
|
Decompose to the canonical basis before
evolution. Default |
None
|
reorderqubits
|
bool | str | None
|
Relabel the qubits before evolution to bring
interacting ones closer together, which lowers bond-dimension
growth. |
None
|
remove_swaps
|
bool | None
|
Server-side only: raises when set locally. |
None
|
simplify
|
bool | None
|
Simplify the circuit before evolution with
:class: |
None
|
reorderqubits_seed
|
int | None
|
Seed for the layout search alone. |
None
|
callback
|
object | None
|
Called as |
None
|
param_grid
|
list[dict] | None
|
List of parameter dicts. Each is substituted into the
circuit and executed with its own derived seed, and the return
value becomes a list of results, one per grid point. A
|
None
|
strict_pass_order
|
bool
|
Enforce the pass pipeline's declared ordering
constraints. Default |
True
|
stopped
|
object | None
|
Cooperative cancellation handle checked during evolution. |
None
|
progress
|
bool
|
Show a progress display. Default |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
QCSResults | list[QCSResults]
|
class: |
QCSResults | list[QCSResults]
|
or a |
|
QCSResults | list[QCSResults]
|
|
|
QCSResults | list[QCSResults]
|
trajectory mode. |
Raises:
| Type | Description |
|---|---|
TypeError
|
if both |
ValueError
|
if |
NotImplementedError
|
if |
TwDirectSimulator¶
A simulator that applies a circuit one operation at a time and builds no MPO. Distant qubits are swapped next to each other and stay where they were moved; every read-out answers in your qubit numbering.
Bases: TwSimulator
MPS simulator that applies a circuit one operation at a time.
Where :class:~tensorweaver.TwSimulator fuses gates into matrix product
operators and applies each one in a sweep, this simulator builds no MPO.
Each gate updates the state directly:
- a one-qubit gate acts on the site of its qubit;
- a two-qubit gate acts on two neighbouring sites, contracted together and
split back with one truncated SVD. Qubits that are not neighbours are
first brought together with swaps of adjacent sites. Which of the two
moves is
routing's choice: by default the one that leaves the next gates closer, where its swaps cannot truncate, and otherwise the gate's second qubit, next to its first (for a CX, the target to the control); - a gate on three to
max_gate_qubitsqubits gathers them into one block of sites and acts there in one step. A larger gate is decomposed.
Qubits move and stay moved. Routing swaps are not undone. The state
keeps track of where each qubit sits, so a second gate on the same pair
needs no routing, and every read-out (sampling, measurement, amplitudes,
expectation values) answers in your qubit numbering. :meth:evolvezerostate
sorts the chain back at the end and returns the plain MPS, with qubit i
on site i. :meth:execute skips that sort, since nothing it reads
needs it.
Fidelity. Every swap is a truncated SVD at sv_cutoff and
bonddim, like a gate, and what it discards is in the reported
fidelity.
Not supported. BondDim, SchmidtRank and VonNeumannEntropy
read a bond of the chain, and the chain is in whatever order routing left
it, so circuits containing them are refused, as are noise channels on
three or more qubits. There is no GPU path.
Which to use. This simulator pays one SVD per two-qubit gate, plus the
routing swaps. :class:~tensorweaver.TwSimulator pays one sweep per fused
block of gates. Circuits of local gates, or with few gates per qubit
between read-outs, favour this one; deep, dense circuits at large
bonddim favour MPO fusion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bonddim
|
int
|
Maximum MPS bond dimension. Default |
256
|
sv_cutoff
|
float | None
|
Singular values below this are discarded by every gate and
swap. |
None
|
max_gate_qubits
|
int
|
The most qubits a gate may act on before it is
decomposed. Default |
DEFAULT_MAX_GATE_QUBITS
|
routing
|
Routing
|
Which qubit a two-qubit gate moves. |
'lookahead'
|
seed
|
int | None
|
Default master seed for :meth: |
None
|
linalg
|
Linalg | None
|
Linear-algebra library, |
None
|
max_num_threads
|
int | None
|
The most threads a run uses, as for
:class: |
None
|
usemkl
|
bool | None
|
Deprecated, use |
None
|
Example::
import mimiqcircuits as mc
from tensorweaver import TwDirectSimulator
c = mc.Circuit()
c.push(mc.GateH(), 0)
# Qubits 0 and 9 are far apart on the chain: qubit 9 is swapped down
# next to qubit 0, and stays there for the next gate.
c.push(mc.GateCX(), 0, 9)
c.push(mc.GateCZ(), 9, 0)
c.push(mc.Measure(), range(10), range(10))
sim = TwDirectSimulator(bonddim=64)
results = sim.execute(c, nsamples=1000, seed=1)
print(results.histogram())
capabilities()
¶
Capability tokens served: those of TwSimulator without bond_dim and schmidt_rank.
limits()
¶
Resource limits: the configured bonddim as max_bond_dim.
can_handle(circuit)
¶
Refuse what this simulator does not run, before any work is done.
On top of the checks every backend makes, refuses BondDim,
SchmidtRank, VonNeumannEntropy and noise channels on three or
more qubits.
compile(circuit)
¶
Lower circuit as :meth:TwSimulator.compile does, after
refusing what this simulator does not run.
Raises:
| Type | Description |
|---|---|
ValueError
|
for |
build_state(nq, nb=0, nz=0, **_)
¶
Allocate a fresh |0…0⟩ routed state on nq qubits.
evolvezerostate(circuit, *, seed=None)
¶
Evolve a fresh zero state through circuit and return it.
Returns (state, fidelity). The chain is sorted back at the end, so
state.mps is a plain MPS with qubit i on site i, and the
fidelity includes the sorting swaps.
Raises:
| Type | Description |
|---|---|
ValueError
|
if the circuit has an operation this simulator refuses. |
apply_instruction(state, inst, *, rng=None)
¶
Apply one instruction the runtime-loss driver issues, directly.
sample_kraus(state, channel, targets, *, rng=None)
¶
Sample one branch of a Kraus channel against the live state and apply it.
TwState¶
Bases: State
Composite simulation state: MPS, classical bits, and z-vars.
Subclasses :class:mimiqcircuits.backends.State. Build one with
:meth:TwSimulator.build_state or :meth:TwSimulator.evolvezerostate;
constructing it directly is for advanced use, and requires passing the
core the MPS came from.
Instructions mutate all three registers in place as a circuit is evolved:
gates and channels act on mps, measurements write into c, and the
observable operations write into z.
Attributes:
| Name | Type | Description |
|---|---|---|
mps |
PyMps
|
the tensor-network quantum register. |
c |
list[int]
|
classical-bit register. |
z |
list[complex]
|
complex z-variable register. |
classical_bits
property
¶
Live view of the classical-bit register.
complex_values
property
¶
Live view of the complex z-register.
get_loss_state()
¶
Per-qubit present/lost register.
Mutated only by the shared runtime-loss driver
(:meth:LocalBackend.evolve_with_loss), and left at all-present on
circuits without qubit loss.
amplitude(bitstring)
¶
⟨bitstring|ψ⟩. Qubit 0 is the LSB (little-endian).
bitstring is read in the same qubit frame as the underlying MPS.
Reorder passes rewrite the embedded bs of every Amplitude op
when they fire (see :func:Circuit.reorder_qubits), so a caller
issuing Amplitude(bs) from a circuit does not need to permute the
bitstring; a caller reaching into this method with a hand-built
bitstring on a reordered state does.
sample(nsamples, rng=None, *, seed=None)
¶
Sample nsamples measurement outcomes as :class:BitString\ s.
Sampling does not collapse the state, so the same state can be sampled
repeatedly. Either rng (a :class:random.Random) or seed (an
int) may be passed, but not both: the native Rng takes a single
integer, which is drawn from rng when one is given and from
:mod:secrets when neither is.
Raises:
| Type | Description |
|---|---|
TypeError
|
if both |
ValueError
|
if |
reset()
¶
Always raises: resetting a state in place is not supported.
Rebuilding the MPS needs the bond-dimension cap, which is simulator
configuration and not carried on the state. Call
sim.build_state(nq, nb, nz) for a fresh state instead.
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
always. |
TensorWeaverBasis¶
Bases: DecompositionBasis
Decomposition basis targeting TensorWeaver's native gate set.
Terminal operations, executed directly by TensorWeaver:
- 1Q parametric: GateRX, GateRY, GateRZ, GateU
- 1Q identity: GateID, skipped during execution
- 2Q optimized: GateCX, GateCZ, GateISWAP
- 2Q generic: any 2-qubit unitary gate, fused into an MPO from its
matrix
- Multi-controlled: Control(n, 1Q-gate), any number of controls
- Measurement/reset: Measure, Reset, MeasureReset
- Conditional: IfStatement, terminal when its inner operation is
- Z-variable ops: Amplitude, BondDim, SchmidtRank,
VonNeumannEntropy, ExpectationValue, all of which observe the
state without changing it
- Classical: AbstractClassical logic (Not, And, Or,
Xor, SetBit0/SetBit1) and the z-register
arithmetic Add, Multiply, Pow
- Noise channels: any krauschannel subclass, Kraus or mixed
unitary
- Scheduling: Barrier, a gate-fusion boundary with no effect on
the state
- Annotations: AbstractAnnotation, which carries no simulation
semantics
Anything else is decomposed through the canonical rewrite rule, which
delegates to each gate's _decompose(). A gate that neither is terminal
nor decomposes raises :class:DecompositionError.
Example
from mimiqcircuits import Circuit, GateCCX, GateH from mimiqcircuits.decomposition import decompose from tensorweaver.basis import TensorWeaverBasis c = Circuit() c.push(GateH(), 0) 1-qubit circuit with 1 instruction: └── H @ q[0]
c.push(GateCCX(), 0, 1, 2) 3-qubit circuit with 2 instructions: ├── H @ q[0] └── C₂X @ q[0:1], q[2] decomposed = decompose(c, TensorWeaverBasis()) CCX stays as Control(2, GateX), dispatched to apply_controlled_gate¶
isterminal(op)
¶
Whether op can be executed natively, without decomposing it.
decompose(op, qubits, bits, zvars)
¶
Decompose a non-terminal operation through the canonical rewrite.
Raises:
| Type | Description |
|---|---|
DecompositionError
|
if the canonical rewrite has no rule for |
TwDirectBasis¶
Bases: TensorWeaverBasis
Decomposition basis for :class:TwDirectSimulator.
Any unitary gate on at most max_gate_qubits qubits is executed as it
is, from its matrix, including controlled gates and custom gates. A larger
gate is decomposed through the canonical rewrite until its pieces fit.
Everything else is as in :class:~tensorweaver.basis.TensorWeaverBasis,
except that BondDim, SchmidtRank and VonNeumannEntropy are not
terminal: :class:TwDirectSimulator does not run them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_gate_qubits
|
int
|
The most qubits a gate may act on before it is
decomposed. Default :data: |
DEFAULT_MAX_GATE_QUBITS
|
isterminal(op)
¶
Whether op is executed as it is, without decomposing it.
TwReorderQubitsPass¶
The qubit-reordering pass that execute(reorderqubits=...) runs. Build it
yourself and pass it through passes= to set its options; see
Qubit ordering.
Bases: AbstractPass
Reorder qubits to reduce MPS bond-dimension growth.
An MPS lays the qubits out on a line, so a gate between two distant
qubits pushes entanglement through every site between them. This pass
relabels the qubits with a permutation π chosen by the native
choose_layout (whose result does not depend on the engine).
Searches minimise the weighted-distance cost
Cα(π) = Σ |π(i) − π(j)|^α · w(i, j), which is smooth and cheap to
update. What picks between their results is a different cost, one that
knows the bond dimension the run will use: per bond, how many truncations
happen there times how many bits each one has to discard against it. The
circuit's own layout is always a candidate, so a search that finds nothing
better leaves it alone. The rewritten circuit is equivalent to the
original; the pipeline maps the results back to the user's qubit frame.
Parameters¶
method:
None (default) runs the whole portfolio and keeps whichever
result scores best. A single spelling ("greedy", "sa" /
"simulated_annealing", "multilevel", or True for
"greedy") pins one search, which is still scored the same way.
alpha:
Exponent in the distance the search minimises. None (default)
sweeps it, since every result is scored afterwards and a pointless
exponent simply loses. Only 1.0 has a meaning: there the sum is
identically the number of bond truncations the layout causes.
seed:
Seed for the stochastic searches. None (default) draws one from
the pass-context RNG.
bonddim:
The bond dimension the run will use, which is what makes the cost
meaningful. None (default) reads it off the backend in the pass
context, falling back to 256 when the context has none.
margin:
How much better than the circuit's own layout a candidate must score
before it is applied. A layout that truncates nothing is applied
whatever the margin.
See also¶
:class:AbstractQCSs.ReorderQubitsPass, the Julia analogue used by
MPSSim.MPSSimulator, which wraps SOptimizer's search.
spec()
¶
Report the pass identity "reorder_qubits" and its parameters.
seed is part of the spec only when one was given explicitly; a
seed drawn from the pass context is not, since it belongs to the
run rather than to the pass configuration.
preserves(feature)
¶
Return True for every feature.
Relabelling qubits leaves the circuit's properties intact, and the
pipeline's composed_perm step maps the output cstate back to
the user's qubit frame.
apply(ctx, circuit)
¶
Search for a layout and return the relabelled circuit.
Returns (circuit, PassResult). The result carries the chosen
permutation, or None when nothing beat the circuit's own layout,
in which case circuit comes back unchanged. Either way the native
report lands in :attr:last_report and is logged at INFO;
PassResult has nowhere to carry it.
MockTensorWeaver¶
MockTensorWeaver and MockTwSimulator are the same class, and MockState is
the state it returns. See Without a licence.
Bases: TwSimulator
TensorWeaver's LocalBackend interface, with no simulation behind it.
Same constructor as :class:~tensorweaver.TwSimulator, same execute,
same :meth:capabilities, same :meth:limits, same :meth:topology, same
refusals. Results are real :class:~mimiqcircuits.QCSResults objects built
by the shared LocalBackend driver and carrying all-zero samples,
zero amplitudes and expectation values, and fidelity 1.0.
What it is for: exercising the MIMIQ data models end to end (circuit in,
passes, compilation, the sampling and trajectory routing, QCSResults,
BitString, the protobuf round-trip) on a machine with no licence. It
is not an approximation of TensorWeaver; it computes nothing.
Every constructor argument is accepted and validated the same way, so a configuration TensorWeaver refuses is refused here too::
>>> from tensorweaver import MockTensorWeaver
>>> MockTensorWeaver(usegpu=True, algorithm="vmpoa")
Traceback (most recent call last):
...
ValueError: usegpu=True requires algorithm in ('dmpo', 'cmpo'), ...
and one it accepts is accepted::
>>> import mimiqcircuits as mc
>>> sim = MockTensorWeaver(bonddim=64)
>>> c = mc.Circuit()
>>> c.push(mc.GateH(), 0)
...
>>> c.push(mc.Measure(), 0, 0)
...
>>> res = sim.execute(c, nsamples=10)
>>> len(res.cstates)
10
build_state(nq, nb=0, nz=0, **_)
¶
Allocate a :class:MockState of the requested register sizes.
The quantum register is a real |0…0⟩ MPS capped at bonddim;
nb and nz size the classical and complex registers. usegpu
is honoured as far as accepting it: nothing is uploaded, since nothing
runs.
evolve(state, compiled, *, rng=None, callback=None, stopped=None)
¶
Return (state, TruncationLowerBound(1.0)) without touching state.
The TypeError on a non-:class:CompiledCircuit is kept: it is part
of the contract a caller may be testing, and it costs one check.
callback is invoked once so a progress display sees a run that
finished rather than one that never started.
expectation(state, op, *qubits)
¶
Always 0j, for any operator on any qubits.
sample_kraus(state, channel, targets, *, rng=None)
¶
Fire the channel's first branch, without applying it.
The driver reads the returned operator to decide what a loss event did,
so it has to be one of the channel's own operators rather than a
placeholder: a LossyOperator branch must still arrive tagged.
tensorweaver.MockState
¶
Bases: TwState
A :class:~tensorweaver.TwState that is never evolved.
The MPS underneath is genuine: |0…0⟩ at the simulator's bond
dimension, with real site tensors, bond dimensions and canonical form. So
anything reading the state back gets the real data model. It simply never
has a gate applied to it.
:meth:sample is the one read-out that has to be reimplemented: the
native sampler is part of the compute kernels and is absent from the
public build.
sample(nsamples, rng=None, *, seed=None)
¶
nsamples all-zero :class:~mimiqcircuits.BitString\ s.
Keeps the real sampler's argument checks, nsamples and the
rng/seed exclusivity, so a bad call is refused here exactly as
it would be there. rng and seed are otherwise unused: the
result does not depend on them.
amplitude(bitstring)
¶
Always 0j.
The untouched state would answer 1 for |0…0⟩ and 0 elsewhere, which
reads as a result and is not one. A flat zero cannot be mistaken for a
simulation.
Core Classes¶
MPS, MPO, RoutedMPS and Rng are native classes. The tables below index their
methods; each method's own docstring is available with help().
MPS¶
A quantum state as a chain of tensors with bounded bond dimension.
Constructors
| Method | Description |
|---|---|
MPS.zero_state(num_qubits, max_bond_dim) |
The \|00...0⟩ state |
MPS.product_state(states, max_bond_dim) |
From a list of 0/1 values |
MPS.random_maxent_state(num_qubits, max_bond_dim, rng) |
Random maximally entangled state |
MPS.zero_state_qudits(physical_dims, max_bond_dim) |
Qudit \|0…0⟩ on sites of the given per-site dimensions (each ≥ 2) |
MPS.product_state_qudits(digits, physical_dims, max_bond_dim) |
Qudit product state from per-site levels (digits[i] < physical_dims[i]) |
MPS.deserialize(data) |
From protobuf bytes |
Sites carry any physical dimension d ≥ 2, reported per site by
mps.physical_dims. A 2×2 or 4×4 qubit gate applied to a d > 2 site acts on
the {\|0⟩, \|1⟩} subspace. See example 13.
Gate application (returns fidelity; always 1.0 for single-qubit gates)
| Method | Description |
|---|---|
mps.apply_rx(theta, qubit) |
RX rotation |
mps.apply_ry(theta, qubit) |
RY rotation |
mps.apply_rz(lmbda, qubit) |
RZ rotation |
mps.apply_u(theta, phi, lmbda, gamma, qubit) |
General U gate |
mps.apply_gate_1q(gate, qubit) |
Arbitrary 1-qubit gate |
mps.apply_gate_2q(gate, q1, q2, *, center="right") |
Arbitrary 2-qubit gate. Skips the post-application compression sweep; pair with mps.compress(). center selects which site holds the orthogonality center afterwards |
mps.apply_two_qubit_gate(...) |
Deprecated alias for apply_gate_2q; emits a DeprecationWarning |
MPO application (returns fidelity, below 1.0 when truncation discards weight)
| Method | Description |
|---|---|
mps.apply_mpo(mpo, sv_cutoff=None, algorithm=None, post_compress=True, *, strict_bonddim=None) |
Apply an operator. algorithm is "dmpo" (the default at this level), "cmpo", "vmpoa", or "vmpob". strict_bonddim says whether intermediate bonds may exceed the state's max_bond_dim; None is strict for all but "cmpo". Strict keeps memory at max_bond_dim and can cost accuracy, which the returned fidelity shows; "cmpo" with True raises BondDimensionError. See Strict and relaxed bond dimension |
mps.apply_mpo_dmpo(mpo, sv_cutoff=None, *, strict_bonddim=None) |
Wrapper for algorithm="dmpo" |
mps.apply_mpo_cmpo(mpo, sv_cutoff=None, *, strict_bonddim=None) |
Wrapper for algorithm="cmpo" |
mps.apply_mpo_vmpoa(mpo, sv_cutoff=None, *, strict_bonddim=None) |
Wrapper for algorithm="vmpoa" |
mps.apply_mpo_vmpob(mpo, sv_cutoff=None, *, strict_bonddim=None) |
Wrapper for algorithm="vmpob" |
mps.compress(sv_cutoff=None) |
Global compression sweep, restoring canonical form. None or non-positive uses the library default 1e-7 |
The default algorithm differs by level
apply_mpo defaults to "dmpo", the low-level primitive's own default.
TwSimulator and execute() default to "vmpoa", which is more accurate
at a given bond dimension. Driving the MPS yourself does not inherit the
simulator's choice.
Deferred compression
Skipping the per-call compression sweep and running one pass at a quiet point is faster for a batch of two-qubit gates:
import numpy as np
import tensorweaver as tw
mps = tw.MPS.zero_state(64, max_bond_dim=256)
mpo = tw.MPO.identity(64, max_bond_dim=16)
mpo.apply_cx(0, 1)
mpo.apply_cz(2, 3)
mps.apply_mpo(mpo, post_compress=False)
gate = np.eye(4, dtype=np.complex128) # any 4x4 unitary
mps.apply_gate_2q(gate, 4, 5)
# One sweep at quiescence: before measuring, reading an observable,
# or at the end of the circuit.
mps.compress()
Deferring the sweep leaves the state out of canonical form, so a later
truncation compares singular values that are no longer the physical Schmidt
weights. Batch only gates you know keep the bond dimension well below the cap,
and prefer "cmpo" or "vmpoa" if unsure. See
canonical form.
Noise channels (return (fidelity, index), where index is the 0-based
sampled Kraus operator or unitary)
| Method | Description |
|---|---|
mps.apply_kraus_1q(kraus_ops, site, rng, *, validate=True) |
General 1-qubit Kraus channel |
mps.apply_kraus_2q(kraus_ops, site1, site2, rng, *, validate=True) |
General 2-qubit Kraus channel |
mps.apply_mixed_unitary_1q(unitaries, probs, site, rng, *, validate=True) |
1-qubit mixed-unitary channel |
mps.apply_mixed_unitary_2q(unitaries, probs, site1, site2, rng, *, validate=True) |
2-qubit mixed-unitary channel |
With validate=True (the default), Kraus channels check completeness
(‖Σᵢ Kᵢ† Kᵢ − I‖_F ≤ 1e-8) and mixed-unitary channels check that the
probabilities sum to 1 within 1e-8. Failures raise KrausCompletenessError.
An incomplete operator set produces a non-physical state silently, which is why
the check is on by default; validate=False is for post-selection and
projective channels, where incompleteness is intended.
Measurement and sampling
| Method | Returns |
|---|---|
mps.measure_qubit(rng, qubit) |
int, the measured bit; collapses the state |
mps.sample_bitstring(rng) |
list[int], one bitstring |
mps.sample(rng, num_samples) |
list[list[int]] |
mps.sample_packed(rng, num_samples) |
bytes of length num_samples * num_qubits, one byte per site per shot, qubit 0 first |
mps.amplitude(bitstring) |
complex, ⟨bitstring\|ψ⟩ |
mps.reset_qubit(rng, qubit) |
int, the pre-reset outcome; leaves the qubit in |0⟩ |
Observables
| Method | Returns |
|---|---|
mps.expectation_1q(op, site) |
complex, ⟨ψ\|O\|ψ⟩ for a 1-qubit operator |
mps.expectation_2q(op, site1, site2) |
complex, for a 2-qubit operator |
mps.expectation_prod(ops, sites) |
complex, for a product of single-site operators |
mps.schmidt_values(bond) |
ndarray[float64], singular values at the bond, decreasing |
mps.schmidt_rank(bond, cutoff=1e-15) |
int, singular values above cutoff; minimum 1 |
mps.von_neumann_entropy(bond) |
float, S = -Σ pᵢ ln pᵢ in nats |
mps.all_entropies() |
list[float], the entropy of every interior bond |
Properties
| Property | Type |
|---|---|
mps.num_qubits |
int |
mps.physical_dims |
list[int], per-site dimension |
mps.max_bond_dim |
int, the configured cap |
mps.max_used_bond_dim |
int, the largest bond actually in use |
mps.orth_center |
int, current orthogonality center |
mps.bond_dim(i) |
int, bond dimension at cut i |
mps.all_bond_dims() |
list[int] |
mps.norm_squared() |
float |
mps.normalize() |
float, the norm before normalising |
Tensor access and copying
| Method | Description |
|---|---|
mps.tensor(site) |
ndarray[complex128] of shape (left_bond, phys, right_bond), Fortran order |
mps.set_tensor(site, arr) |
Overwrite a site tensor. Can invalidate canonical form; follow with recanonicalize() |
mps.tensor_element(site, left, phys, right) |
complex, one entry |
mps.shift_orth_center(target) |
Move the orthogonality center |
mps.recanonicalize(target=0) |
Restore canonical form with the center at target |
mps.clone_mps() |
Deep copy; copy.copy and copy.deepcopy also work |
mps.overlap(other) |
complex, ⟨ψ\|φ⟩ |
mps.fidelity(other) |
float, \|⟨ψ\|φ⟩\|² |
mps.serialize() |
bytes (protobuf) |
Device residency
Present on every engine, so a caller asks rather than testing for the
attribute. Only to_device() needs the CUDA engine; the other two answer on a
CPU engine, where a state is already where they want it. See
GPU engine.
| Method | Description |
|---|---|
mps.to_device() |
Move the state into device memory. Raises GpuError on an engine with no device path, or when no GPU is reachable |
mps.to_host() |
Move it back. A no-op on a host-resident state |
mps.is_on_device |
bool, whether the state currently lives on the device |
TwSimulator(usegpu=True) does both moves for you, so these are for drivers
built by hand.
MPO¶
An operator as a chain of tensors, applied to a state with
mps.apply_mpo(mpo).
Constructors
| Method | Description |
|---|---|
MPO.identity(num_qubits, max_bond_dim) |
Identity operator |
MPO.identity_with_dims(physical_dims, max_bond_dim) |
Identity on sites of the given per-site dimensions (each ≥ 2) |
MPO.deserialize(data) |
From protobuf bytes |
Gate application (returns True, or False when the gate would push the
bond dimension past max_bond_dim)
Every method takes a keyword-only side selecting the physical leg the gate
multiplies into: "output" (the default) gives M' = G·M, "input" gives
M' = M·G. The two-qubit methods also take sv_cutoff.
| Method | Description |
|---|---|
mpo.apply_gate_1q(gate, site, *, side="output") |
Arbitrary 1-qubit gate |
mpo.apply_gate_2q(gate, q1, q2, *, side="output", sv_cutoff=None) |
Arbitrary 2-qubit gate |
mpo.apply_cx(control, target, *, side="output", sv_cutoff=None) |
CNOT |
mpo.apply_cz(q1, q2, *, side="output", sv_cutoff=None) |
CZ |
mpo.apply_iswap(q1, q2, *, side="output", sv_cutoff=None) |
iSWAP |
mpo.apply_rx(theta, site, *, side="output") |
RX rotation |
mpo.apply_ry(theta, site, *, side="output") |
RY rotation |
mpo.apply_rz(lmbda, site, *, side="output") |
RZ rotation |
mpo.apply_u(theta, phi, lmbda, gamma, site, *, side="output") |
General U gate |
mpo.apply_controlled_gate(unitary, controls, target, *, side="output", sv_cutoff=None) |
Multi-controlled gate, any number of controls |
Normalisation
| Method | Description |
|---|---|
mpo.ensure_operator_norm() |
Convert to operator norm (identity = δ). No-op if already there |
mpo.ensure_trace_norm() |
Convert to trace norm (Tr(A†A) = 1 per site). No-op if already there |
Properties and other methods
| Member | Description |
|---|---|
mpo.num_qubits |
int |
mpo.physical_dims |
list[int], per-site dimension |
mpo.max_bond_dim |
int, the configured cap |
mpo.max_used_bond_dim |
int, the largest bond actually in use |
mpo.bond_dim(i) |
int, bond dimension at cut i |
mpo.all_bond_dims() |
list[int] |
mpo.norm |
str, 'Operator' or 'Trace' |
mpo.tensor(site) |
ndarray[complex128] of shape (left_bond, d_in, d_out, right_bond), Fortran order |
mpo.set_tensor(site, arr) |
Overwrite a site tensor |
mpo.tensor_element(site, left, s_in, s_out, right) |
complex, one entry |
mpo.shift_orth_center(target) |
Move the orthogonality center |
mpo.clone_mpo() |
Deep copy |
mpo.dagger() |
MPO, the adjoint (the inverse for unitary operators) |
mpo.serialize() |
bytes (protobuf) |
RoutedMPS¶
The state behind TwDirectSimulator: an MPS whose qubits move along the chain
as gates are routed, with the map from each qubit to its site. Every method
takes 0-based logical qubits and every read-out answers in that numbering. No
method builds an MPO.
import numpy as np
from tensorweaver import RoutedMPS
state = RoutedMPS.zero_state(6, 32)
h = np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2)
cx = np.eye(4, dtype=complex)[[0, 1, 3, 2]]
state.apply_gate(h, [0])
state.apply_gate(cx, [0, 5]) # qubit 5 is swapped next to qubit 0, and stays
print(state.layout) # [0, 2, 3, 4, 5, 1]: qubit 5 sits on site 1
mps, fidelity = state.to_mps() # sort back: qubit i on site i
Constructors
| Method | Description |
|---|---|
RoutedMPS.zero_state(num_qubits, max_bond_dim) |
\|0…0⟩, qubit i on site i |
RoutedMPS.from_mps(mps) |
A copy of an MPS, qubit i on site i |
Operations (each returns the truncation fidelity, routing swaps included)
| Method | Description |
|---|---|
state.apply_gate(gate, qubits, sv_cutoff=None) |
D×D gate on any number of qubits, qubits[0] the most significant leg |
state.apply_kraus(kraus_ops, qubits, rng, *, validate=True, sv_cutoff=None) |
One sampled Kraus branch on one or two qubits; returns (fidelity, index) |
state.apply_mixed_unitary(unitaries, probs, qubits, rng, *, validate=True, sv_cutoff=None) |
One sampled unitary on one or two qubits; returns (fidelity, index) |
state.measure_qubit(rng, qubit) |
Measure and collapse; returns the level |
state.reset_qubit(rng, qubit) |
Measure, then reset to \|0⟩; returns the measured level |
Read-outs, in logical order
| Method | Description |
|---|---|
state.amplitude(bitstring) |
complex, ⟨bitstring\|ψ⟩ |
state.sample_packed(rng, num_samples) |
bytes, one level per qubit per shot |
state.expectation_1q(op, qubit) |
complex |
state.expectation_2q(op, q1, q2) |
complex, q1 the most significant leg |
state.expectation_prod(ops, qubits) |
complex, product of one-qubit operators |
Layout and properties
| Member | Description |
|---|---|
state.layout |
list[int], entry q is the site holding qubit q |
state.is_ordered |
bool, whether qubit i is on site i |
state.restore_order(sv_cutoff=None) |
Sort back with the fewest adjacent swaps; returns their fidelity |
state.to_mps(sv_cutoff=None) |
Sort back, then return (MPS, fidelity) |
state.num_qubits, state.physical_dims |
Size and per-qubit dimension, in logical order |
state.max_bond_dim, state.max_used_bond_dim |
The cap and the largest bond in use |
state.all_bond_dims() |
list[int], bond dimensions in site order, outer bonds included |
Rng¶
A seeded generator for reproducible measurement and sampling. The same seed always produces the same sequence.
import tensorweaver as tw
mps = tw.MPS.zero_state(4, max_bond_dim=16)
rng = tw.Rng(seed=42)
bits = mps.sample_bitstring(rng)
An Rng belongs to the engine that created it and must be used with states
from that same engine.
Utility Functions¶
| Function | Description |
|---|---|
tensorweaver.optimize_ordering(pairs, num_qubits, method="greedy", alpha=1.0, seed=42, fixed_cuts=None) |
Qubit layout for a weighted interaction graph, from one search. pairs is a list of (i, j, weight); fixed_cuts lists bonds no qubit may cross. Returns (permutation, cost). reorderqubits= does not call it: it runs choose_layout |
tensorweaver.extract_pairs(circuit) |
The weighted interaction graph of a circuit, as (i, j, weight) triples |
tensorweaver.reorder_qubits(circuit, perm) |
Rewrite a circuit into the layout perm |
tensorweaver.choose_layout(pairs, num_qubits, max_bond_dim, fixed_cuts=None, margin=2.0, seed=42, methods=None, alphas=None) |
Run the portfolio of layout searches and pick a layout, or keep the caller's, scoring against max_bond_dim. pairs is a list of (i, j, events, bits). Returns (perm, report) |
tensorweaver.layout_score(perm, pairs, num_qubits, max_bond_dim) |
Score one layout: a dict with cost, events, max_bits, budget_bits and bonds_over_budget |
tensorweaver.operator_entanglement(gate, d1=2, d2=2) |
Entangling weight of a two-qudit gate, in bits |
tensorweaver.examples_dir() |
Path to the bundled example scripts |
tensorweaver.docs_dir() |
Path to the bundled documentation site |
tensorweaver.library_info() |
Build information string |
tensorweaver.rs_version() |
Version of the native core |
tensorweaver.compile_info() |
Build configuration, formatted for reading |
tensorweaver.compile_info_json() |
The same, as a JSON string |
tensorweaver.has_kernels() |
bool, False only on the unlicensed public wheel, which has no compute kernels. See Without a licence |
tensorweaver.__version__ |
Version of the installed mimiq-tensorweaver package |
tensorweaver.thread_info() |
dict: what each thread pool resolved to, and which variable decided it |
tensorweaver.thread_info_json() |
The same, as the raw JSON string |
tensorweaver._engine.available_engines() |
Engine names this build ships, from "openblas", "mkl", "faer" and "cuda". A name here means the module is present, not that it loads |
tensorweaver._engine.get_core(linalg=None, usegpu=False) |
The engine module for an engine choice. get_core(usegpu=True) raises ImportError, naming the fix, when this build has no CUDA engine or no GPU is reachable. Each engine module also has gpu_available(), which is False on every CPU engine |
Instruction Dispatch¶
Applying one mimiqcircuits instruction at a time, for drivers built by hand.
| Function | Description |
|---|---|
tensorweaver.apply_instruction_mps(mps, rng, inst, cstate, zstate) |
Apply an instruction to an MPS. Returns the fidelity |
tensorweaver.apply_instruction_mpo(mpo, inst, *, mpo_cutoff=None) |
Accumulate an instruction into an MPO. Returns True, or False when the gate would push the MPO past its max_bond_dim |
Plotting¶
tensorweaver.visualization needs the visualization extra
(pip install 'mimiq-tensorweaver[visualization]'); import tensorweaver
alone never loads matplotlib. For a guided tour, see
Visualization.
tensorweaver.visualization.plotbonds(state, mimiqstyle=True)
¶
Plot the bond dimension and the entanglement entropy along the chain.
The top panel shows the bond dimension χ of every interior bond on a
log-2 scale, with max_bond_dim as a dashed line. A bond that has
reached that line is drawn red: it holds as many Schmidt values as the
simulator allows, so any further weight on that cut was discarded. A
state can also fit its cap exactly, a GHZ state at χ = 2 for one, so red
marks where truncation can happen; the fidelity of the run and
:func:plotschmidt tell how much it cost. Bonds below the line can still
be truncated by sv_cutoff. The bottom panel shows the von
Neumann entropy of each cut, in nats, which tells how much entanglement
the bond carries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
TwState | MPS
|
a :class: |
required |
mimiqstyle
|
bool
|
draw with the MIMIQ matplotlib style (default |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
The |
Figure
|
class: |
Example::
import mimiqcircuits as mc
import tensorweaver as tw
from tensorweaver.visualization import plotbonds
# A 12-qubit brickwork of RY rotations and CX bricks.
c = mc.Circuit()
for layer in range(6):
for q in range(12):
c.push(mc.GateRY(0.5 + 0.1 * q), q)
for q in range(layer % 2, 11, 2):
c.push(mc.GateCX(), q, q + 1)
# χ = 4 is too small for this depth: the middle bonds reach the cap.
state, _ = tw.TwSimulator(bonddim=4, strict_bonddim=False).evolvezerostate(c)
fig = plotbonds(state)
fig.savefig("bonds.png")
tensorweaver.visualization.plotschmidt(state, bond, mimiqstyle=True)
¶
Plot the Schmidt spectrum of one bond on a log scale.
Each bar is a Schmidt weight λᵢ², the probability carried by one
Schmidt vector of the cut. A spectrum that is still high where it ends
means the bond dimension is cutting off weight that matters; a spectrum
that falls off fast means the state is well represented at this bond.
Reading the spectrum moves the orthogonality center to bond, which
changes no amplitude.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
TwState | MPS
|
a :class: |
required |
bond
|
int
|
the bond, |
required |
mimiqstyle
|
bool
|
draw with the MIMIQ matplotlib style (default |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
The |
Figure
|
class: |
Raises:
| Type | Description |
|---|---|
QubitIndexError
|
if |
Example::
# The bond plotbonds showed at the cap, in the example above.
fig = plotschmidt(state, 6)
tensorweaver.visualization.BondWindow
¶
A window that follows the bond structure of a :class:TwState as it evolves.
The window shows what :func:plotbonds shows. It is drawn when created
and changes only when :meth:update is called: the state is read as it
is then, and the picture moves there gradually. Bond dimensions grow on
the log-2 axis, bars fade to red as they reach the cap, and the entropies
follow. Between two updates the state can be evolved by any number of
instructions.
The window needs an interactive matplotlib backend such as QtAgg or
TkAgg, which in turn needs PyQt / PySide or Tk installed. In Jupyter,
run %matplotlib qt first. With a non-interactive backend nothing
opens and :meth:update redraws the figure in one step. In a script,
the window only repaints during :meth:update; end with
matplotlib.pyplot.show() to keep it open and responsive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
TwState | MPS
|
the :class: |
required |
mimiqstyle
|
bool
|
draw with the MIMIQ matplotlib style (default |
True
|
duration
|
float
|
default length of an :meth: |
1.0
|
Example::
import matplotlib.pyplot as plt
import mimiqcircuits as mc
import tensorweaver as tw
from tensorweaver.visualization import BondWindow
sim = tw.TwSimulator(bonddim=16, strict_bonddim=False)
state = sim.build_state(20) # |0...0>: every bond at χ = 1
window = BondWindow(state)
layer = mc.Circuit()
for q in range(20):
layer.push(mc.GateRY(0.7), q)
for q in range(19):
layer.push(mc.GateCX(), q, q + 1)
step = sim.compile(layer)
for _ in range(6):
sim.evolve(state, step) # as many gates as you like...
window.update() # ...then one animation to the new state
plt.show() # keep the window open at the end
update(duration=None)
¶
Move the picture to the watched state as it is now.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration
|
float | None
|
length of the animation in seconds; defaults to the
window's |
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
if the window has been closed. |
Exceptions¶
All inherit from TensorWeaverError.
| Exception | Raised when |
|---|---|
TensorWeaverError |
Base class for everything below |
QubitIndexError |
A qubit or site index is out of range. Also a ValueError |
BondDimensionError |
A bond dimension constraint cannot be met |
KrausCompletenessError |
A validated channel's operators do not sum to identity, or its probabilities do not sum to 1 |
GateShapeError |
A gate or operator array has the wrong shape or dtype |
SerializationError |
Protobuf encoding or decoding failed |
GpuError |
A GPU operation failed, or the device was asked for and is not there |
LicenseError |
No valid license was found |
Qiskit¶
See the Qiskit page for usage.
| Object | Description |
|---|---|
tensorweaver.qiskit.TensorWeaverBackend(*, name="tensorweaver", num_qubits=64, **tw_options) |
A Qiskit BackendV2 backed by TwSimulator |
tensorweaver.qiskit.TensorWeaverEstimator(*, simulator=None, method="auto", trajectories=None, shots=None, emulate_shot_noise=False, default_precision=0.0, reorderqubits=None, seed=None, **tw_options) |
An EstimatorV2 reading expectation values from the MPS. trajectories= / shots= set the budget for a circuit that ends in an ensemble |