Circuit

The lazy-mode do-block circuit builder, its expansion into a flat operation list, and the eager/lazy gate-application entry points.

QuantumCircuitsMPS.apply!Function
apply!(state::SimulationState, gate::AbstractGate, geo::AbstractGeometry)

Apply a gate to the state at sites specified by geometry. Modifies state.backend.mps in-place.

Geometry dispatch resolves the target region(s); each region is executed through the uniform execute!(state, gate, region) protocol.

Normalization dispatch (Contract 3.5) is trait-based:

  • needs_normalization(gate) == false (unitaries): NO normalize after apply
  • needs_normalization(gate) == true (projective gates): normalize + truncate
source
apply!(state::SimulationState, gate::AbstractGate, sites::Vector{Int})

Apply a gate to specific physical sites. Direct site specification. Routes through the uniform execute! protocol (so measurement-like gates such as Measure/Reset work with explicit site vectors too).

source
apply!(builder::CircuitBuilder, gate, geometry)

Record a deterministic gate operation in the circuit builder.

Stores operation as: (type=:deterministic, gate=gate, geometry=geometry)

A Bricklayer(:odd)/Bricklayer(:even) geometry with odd L under bc=:periodic emits a one-time warning at this recording step (no valid brickwork tiling exists — see _warn_bricklayer_odd_pbc); the operation is still recorded unchanged.

Example

Circuit(L=4, bc=:periodic) do c
    apply!(c, Hadamard(), SingleSite(1))
    apply!(c, CNOT(), StaircaseRight(1))
end
source
apply!(state::SimulationState, pg::ProductGate)

Apply a ProductGate eagerly with its geometry omitted (recommended form): equivalent to apply!(state, pg, Sites(u)) with u the union of elements(pg.region_geometry, state.L, state.bc).

source
apply!(builder::CircuitBuilder, pg::ProductGate)

Record a deterministic ProductGate operation with its geometry omitted (recommended form): the canonical region Sites(union) is filled in from the builder's L/bc.

source
apply!(builder::CircuitBuilder, pg::ProductGate, geometry)

Explicit form of recording a deterministic ProductGate: geometry MUST be Sites(u) with u exactly the union of the product's elements (validated at BUILD time; any other geometry throws an ArgumentError).

source
QuantumCircuitsMPS.apply_with_prob!Function
apply_with_prob!(state::SimulationState; outcomes)

Eagerly execute ONE stochastic operation on state under the v0.1 unified stochastic rule — identical semantics to recording the same outcomes in a Circuit and running one step of simulate!, but applied immediately.

Each outcome is a NamedTuple with fields:

  • probability (required): a scalar Real, which broadcasts identically across every element. probability may also be an AbstractVector{<:Real} with one entry per geometry element (in elements(geo, L, bc) order), so each gate location gets its own probability. Scalar and vector outcomes may be freely mixed within one call.
  • gate::AbstractGate (required)
  • geometry::AbstractGeometry (required)

Semantics (v0.1 unified stochastic rule)

Each outcome's geometry expands to elements (elements(geo, L, bc) for broadcast geometries; set geometries are a single element); all outcomes must expand to the SAME element count K. At element k, $\sum p$ is the sum of every outcome's probability value AT THAT ELEMENT — a scalar outcome contributes the same value to every element, a vector outcome contributes its k-th entry. For each element $k = 1, \ldots, K$, exactly ONE scalar coin is drawn from the :gates_spacetime stream — unchanged whether probabilities are scalar or per-element vectors — and a categorical selection is made among the outcomes via select_outcome_index (the engine's single source of truth); the remainder $1 - \sum p$ selects identity (nothing applied, staircases not advanced). The winning outcome's gate is executed at its k-th element via the uniform execute! protocol.

A selected staircase advances after application and other staircase geometries in outcomes are synced to its position (sync_staircase_positions!) — exactly as in simulate!. Unlike simulate!, the eager form never resets geometry positions: the caller owns staircase/Pointer state across calls.

Call-time validation (all ArgumentError, thrown BEFORE any coin is drawn

or the state is touched — the lazy form runs the same checks at build time)

  • outcomes must be non-empty
  • $\sum p$ must be $\le 1$ (tolerance 1e-10)
  • Equal-K: every outcome's geometry must expand to the same element count (the error names each outcome's geometry and K)
  • Staircase/Pointer physics guard: if any outcome uses a staircase or Pointer geometry, $\sum p$ must equal $1$ (an identity remainder would silently stall the random walk — see the builder docstring for the CIPT rationale)
  • The removed rng= keyword (or any other keyword) throws with a migration message: all coins come from :gates_spacetime in v0.1

Event log

When the state was constructed with log_events=true, each applied gate emits a GateApplied event. Eager calls happen outside an engine run, so step and op_idx are the documented 0 sentinels; element_idx is the real element index k.

Example

apply_with_prob!(state;
    outcomes = [
        (probability=p, gate=Measure(:Z), geometry=AllSites())
    ]
)

Example ($\sum p < 1$: remaining 0.3 = identity)

apply_with_prob!(state;
    outcomes = [
        (probability=0.3, gate=PauliX(), geometry=site),
        (probability=0.4, gate=PauliY(), geometry=site)
    ]
)

See Also

  • apply_with_prob!(c::CircuitBuilder; outcomes): lazy form (records into a Circuit for simulate!)
  • apply!(state, gate, geometry): deterministic, unconditional application
source
apply_with_prob!(builder::CircuitBuilder; outcomes)

Record a stochastic operation in the circuit builder (v0.1 unified rule).

Stores operation as: (type=:stochastic, rng=:gates_spacetime, outcomes=collect(outcomes))

All stochastic coins are drawn from the :gates_spacetime stream — the pre-v0.1 rng= keyword was REMOVED (passing it throws an ArgumentError with a migration message).

Arguments

  • outcomes: Vector of NamedTuples with keys (:probability, :gate, :geometry). Each probability may be a scalar Real, broadcast identically across every element; probability may also be an AbstractVector{<:Real} with one entry per geometry element (in elements(geo, L, bc) order), so each gate location gets its own probability. Scalar and vector outcomes may be freely mixed within one call. The operation records the caller's ORIGINAL probability values unchanged — this builder never stores a derived probability matrix.

Semantics (v0.1 unified stochastic rule)

Each outcome's geometry expands to elements (elements(geo, L, bc)); all outcomes must expand to the SAME element count K. At element k, $\sum p$ is the sum of every outcome's probability value AT THAT ELEMENT — a scalar outcome contributes the same value to every element, a vector outcome contributes its k-th entry. Per element $k = 1, \ldots, K$, the engine draws ONE :gates_spacetime coin — unchanged whether probabilities are scalar or per-element vectors — and makes a categorical selection among the outcomes; the remainder $1 - \sum p$ selects identity (nothing applied).

Build-time validations (all ArgumentError)

All of the following are checked — and any violation is thrown — before any RNG draw or state mutation; the builder never touches :gates_spacetime or pushes a partial operation onto builder.operations.

  • outcomes must be non-empty
  • Equal-K: every outcome's geometry must expand to the same element count (the error names each outcome's geometry and K)
  • Per outcome, probability is validated (finite, in [0,1]) and every element's total probability (summed across outcomes) must be ≤ 1 (tolerance 1e-10) — via the shared resolve_probability_schedule resolver (src/Circuit/probabilities.jl)
  • Staircase/Pointer physics guard: if any outcome uses a staircase or Pointer geometry, $\sum p$ at that element must equal $1$ (tolerance 1e-10). The CIPT random walk advances via the selected staircase every step; an identity remainder ($\sum p < 1$) would silently stall the walk.
  • The removed rng= keyword (or any other keyword) throws with a migration message

Example

Circuit(L=4, bc=:periodic) do c
    apply_with_prob!(c; outcomes=[
        (probability=0.3, gate=PauliX(), geometry=SingleSite(1)),
        (probability=0.2, gate=PauliZ(), geometry=SingleSite(1))
    ])
end

Example (per-element vector probability)

Circuit(L=4, bc=:periodic) do c
    apply_with_prob!(c; outcomes=[
        (probability=[0.1, 0.2, 0.3, 0.1], gate=Measure(:Z), geometry=AllSites())
    ])
end
source
QuantumCircuitsMPS.CircuitType
Circuit(; L::Int, bc::Symbol, operations=NamedTuple[])

Lazy representation of a quantum circuit as a sequence of symbolic operations.

1D only

Circuits are currently one-dimensional: L sites on a chain with :open/:periodic boundary conditions. Higher-dimensional (2D+) circuit geometries are a planned future direction (see ROADMAP.md).

A Circuit does NOT execute immediately - it stores operations symbolically and expands them to concrete gate applications only when passed to simulate!.

A Circuit always represents ONE time step. Repeat execution is controlled by simulate!(circuit, state; n_steps=...).

Fields

  • L::Int: Number of physical sites in the system
  • bc::Symbol: Boundary conditions (:periodic or :open)
  • operations::Vector{NamedTuple}: Internal symbolic operation list
  • params::Dict{Symbol,Any}: User-defined parameters (default: empty Dict)

Operation Representation

Operations are stored as NamedTuples with different formats:

Deterministic gates:

(type = :deterministic, gate = gate, geometry = geometry)

Stochastic outcomes (apply_with_prob!):

(type = :stochastic, rng = :gates_spacetime, outcomes = [(probability=p, gate=g, geometry=geo), ...])

Each outcome's probability (p above) is a scalar Real, which broadcasts identically across every element; probability may also be an AbstractVector{<:Real} with one entry per geometry element (in elements(geo, L, bc) order), so each gate location gets its own probability. Scalar and vector outcomes may be freely mixed within one operation's outcomes list.

Construction

Users construct circuits via the do-block API (see CircuitBuilder):

circuit = Circuit(L=10, bc=:periodic) do c
    apply!(c, Hadamard(), SingleSite(1))
    apply!(c, CNOT(), StaircaseRight(1), steps=5)
end

Execution

Pass the circuit to simulate! to execute:

state = SimulationState(...)
simulate!(circuit, state; n_steps=50)  # Runs the circuit 50 times

See Also

  • expand_circuit: Expands symbolic operations to concrete site lists
  • simulate!: Executes a circuit on a simulation state
source
QuantumCircuitsMPS.expand_circuitFunction
expand_circuit(circuit::Circuit; n_steps::Int=1, seed::Int=0) -> Vector{Vector{ExpandedOp}}

Expand a symbolic circuit to a flat list of concrete gate operations per timestep.

This is the backward-compatible flat version. For visualization, prefer expand_circuit_grouped which preserves operation group boundaries.

Stochastic operations are expanded with the engine's shared selection function select_outcome_index (v0.1 unified rule) — see expand_circuit_grouped for details. Record markers appear as gate-less pseudo-ops (see is_record_mark).

Arguments

  • circuit::Circuit: The circuit to expand (one time step)
  • n_steps::Int: Number of times to repeat the circuit step (default: 1)
  • seed::Int: RNG seed for stochastic branch selection (default: 0)

Returns

  • Vector{Vector{ExpandedOp}}: Outer vector has length n_steps, inner vectors contain all operations for that timestep (flattened across groups). Inner vectors may be empty if the identity remainder is selected for all stochastic elements.

See Also

source
QuantumCircuitsMPS.expand_circuit_groupedFunction
expand_circuit_grouped(circuit::Circuit; n_steps::Int=1, seed::Int=0) -> Vector{Vector{Vector{ExpandedOp}}}

Expand a symbolic circuit to concrete gate operations, preserving operation groups.

Each apply! / apply_with_prob! / record! call in the circuit definition becomes (at most) one group. This grouping is essential for visualization: gates within the same group (e.g., all pairs in a Bricklayer) can be rendered on the same row, while different groups (e.g., a Bricklayer followed by AllSites measurements) get separate rows.

Stochastic selection (v0.1 unified rule)

Stochastic operations are expanded with the ENGINE's single-source selection function select_outcome_index — one scalar coin per element $k = 1, \ldots, K$, categorical selection among the outcomes, remainder $1 - \sum p$ = identity (element omitted). This is the exact rule simulate! executes: expanding with seed=X shows the same selections the engine makes when its :gates_spacetime stream is seeded with X.

Per-element probability schedules

probability may also be an AbstractVector{<:Real} with one entry per geometry element (in elements(geo, L, bc) order), so each gate location gets its own probability — resolved via the same resolve_probability_schedule simulate! uses.

Record markers

(type=:record_mark, ...) pseudo-ops (from record!(c[, names...])) become gate-less marker ExpandedOps (see is_record_mark) in their own group. Markers consume no RNG. Unknown operation types are skipped (never an error), keeping expansion forward-compatible.

Arguments

  • circuit::Circuit: The circuit to expand (one time step)
  • n_steps::Int: Number of times to repeat the circuit step (default: 1)
  • seed::Int: RNG seed for stochastic branch selection (default: 0)

Returns

  • Vector{Vector{Vector{ExpandedOp}}}: steps → groups → ops.
    • Outer vector: one entry per timestep (length n_steps)
    • Middle vector: one entry per circuit call that produced ops
    • Inner vector: concrete gate operations from that call

Groups with no operations (stochastic all-identity selections) are omitted.

See Also

  • expand_circuit: Flat version (no grouping) for backward compatibility
  • select_outcome_index: The shared engine/visualization selection rule
source
QuantumCircuitsMPS.simulate!Function
simulate!(circuit::Circuit, state::SimulationState; n_steps::Int=1, record_when::Union{Symbol,Function}=:every_step)

Execute a circuit on a simulation state, applying gates and recording observables.

A Circuit represents ONE time step. This function runs that step n_steps times, processing all operations in circuit.operations on each iteration.

Arguments

  • circuit::Circuit: The circuit to execute (symbolic operations)
  • state::SimulationState: The state to modify in-place
  • n_steps::Int: Number of times to execute the circuit step (default: 1)
  • record_when::Union{Symbol,Function}: Controls when observables are recorded (default: :every_step)

Unified stochastic rule (v0.1)

Every stochastic operation (apply_with_prob!) is executed as follows:

  1. All outcomes expand to the SAME number of elements K (validated at build time; broadcast geometries expand via elements(geo, L, bc), set geometries are a single element).
  2. For each element $k = 1, \ldots, K$: exactly ONE scalar coin is drawn from the :gates_spacetime stream — unchanged whether probabilities are scalar or per-element vectors — and a categorical selection is made among the outcomes via select_outcome_index (remainder $1 - \sum p$ = identity).
  3. The winning outcome's gate is executed at its k-th element; identity applies nothing (and does NOT advance staircases).

Each outcome's probability may be a scalar Real (broadcast identically across every element) or a per-element AbstractVector{<:Real} of exact length K, indexed in the SAME canonical elements(geo, L, bc) order as element k above — see apply_with_prob!(::CircuitBuilder; outcomes) for the full per-element probability contract (canonical ordering including the Bricklayer PBC wrap-bond position, and K = 1 vector support). Scalar and vector outcomes may be freely mixed; at element k, $\sum p$ is the sum of every outcome's value at that element. Every stochastic op's schedule — scalar or vector alike — is validated once (length, range, and per-element totals) before geometry reset, RNG construction, or any gate execution.

Coin consumption is therefore data-independent: K draws per stochastic op per step, always — see expected_draws.

Recording Options

The record_when parameter accepts:

  • :every_step (default): Record once per step, after the last operation. This fires STRUCTURALLY every step — even when every stochastic op selects the identity ("do nothing") branch.
  • :every_gate: Record after every actual gate execution
  • :final_only: Record only after the final step completes
  • :marks: Record exactly at the circuit's record!(c[, names...]) marker positions, in the op stream (NOT at the structural step boundary). A circuit with M markers yields exactly M * n_steps records per (matching) observable, deterministically — independent of stochastic outcomes. Selective markers (record!(c, :entropy)) grow only the named observables' vectors. Requires the circuit to contain markers (ArgumentError otherwise).
  • Custom function (ctx::RecordingContext) -> Bool: evaluated once per element slot (with is_step_boundary=false), once per marker (with at_mark=true, mark_index set), and once at the structural end of each step (with is_step_boundary=true, gate_type=nothing); if any evaluation returns true, ONE record is taken at the end of the step.

Marker/policy conflict (ArgumentError)

If the circuit contains record!(c) markers, record_when MUST be :marks or a custom predicate. Passing (or defaulting to) :every_step, :every_gate, or :final_only throws an ArgumentError — those policies would silently ignore the markers.

RecordingContext Fields

Custom recording functions receive a RecordingContext with:

  • step_idx::Int: Current step index (1 to n_steps)
  • gate_idx::Int: Cumulative element-slot count across all steps (never resets). Advances once per element slot REGARDLESS of the stochastic outcome (identity included), so gate_idx-based recording schedules are trajectory-independent. Markers do NOT advance it.
  • op_idx::Int: Position of the current op in circuit.operations (0 for the step-boundary evaluation)
  • element_idx::Int: Element index within the current op (0 for step-boundary and marker evaluations)
  • gate_type::Any: The gate applied at this slot (nothing for identity slots, marker evaluations, and the structural step-boundary evaluation)
  • is_step_boundary::Bool: True only for the structural step-boundary evaluation after the op loop
  • at_mark::Bool / mark_index::Int: Marker evaluations carry at_mark=true and the marker's 1-based ordinal among the circuit's markers (0/false everywhere else)

Examples

# Basic execution with 5 steps
circuit = Circuit(L=4, bc=:periodic) do c
    apply_with_prob!(c; outcomes=[
        (probability=0.5, gate=Reset(), geometry=StaircaseRight(1)),
        (probability=0.5, gate=HaarRandom(), geometry=StaircaseLeft(4))
    ])
end

rng = RNGRegistry(gates_spacetime=42, gates_realization=44, born_measurement=45)
state = SimulationState(L=4, bc=:periodic, rng=rng)
initialize!(state, ProductState(binary_int=1))
track!(state, :dw => DomainWall(order=1, i1_fn=() -> 1))

# Record after every step (default)
simulate!(circuit, state; n_steps=5)

# Record after every gate
simulate!(circuit, state; n_steps=5, record_when=:every_gate)

# Record only at the end
simulate!(circuit, state; n_steps=5, record_when=:final_only)

# Custom: record every 10 element slots
simulate!(circuit, state; n_steps=5, record_when=every_n_gates(10))

# Custom: record every 2 steps
simulate!(circuit, state; n_steps=10, record_when=every_n_steps(2))

RNG Contract

  • All stochastic coins come from :gates_spacetime (the builder no longer accepts an rng= keyword).
  • Scalar draws only; element order = documented enumeration order of the outcome geometries (elements) — the SAME order a per-element vector probability's entries are indexed in (see apply_with_prob!(::CircuitBuilder; outcomes) for the canonical ordering, including the Bricklayer PBC wrap-bond position).
  • Consumption is data-independent: expected_draws(circuit, n_steps) coins, exactly one per element per stochastic op per step — unchanged whether an outcome's probability is a scalar or a per-element vector.

Thread safety

A Circuit holding staircase/Pointer geometries is MUTABLE (positions advance during simulate!). For per-trajectory parallelism use copy(circuit) (a deepcopy preserving intra-circuit geometry aliasing) so each trajectory owns private geometry state:

Threads.@threads for seed in seeds
    c = copy(circuit)
    st = SimulationState(...; rng=RNGRegistry(gates_spacetime=seed, ...))
    initialize!(st, ProductState(binary_int=0))
    simulate!(c, st; n_steps=n)
end

Validation

  • Throws ArgumentError if n_steps < 1
  • Throws ArgumentError for unknown symbol presets

See Also

  • expand_circuit: Visualize which gates will be applied
  • record!: Manual observable recording
  • RecordingContext: Context passed to custom recording functions
  • every_n_gates, every_n_steps: Helper functions for common patterns
source
QuantumCircuitsMPS.ExpandedOpType
ExpandedOp

Represents a concrete gate operation at specific sites for a specific timestep.

Fields

  • step::Int: Circuit timestep (1-indexed)
  • gate::Union{AbstractGate, Nothing}: The gate to apply. nothing marks a record! marker pseudo-op (no gate, no sites — see is_record_mark).
  • sites::Vector{Int}: Physical sites for this operation (empty for markers)
  • label::String: Short label for visualization (e.g., "Rst", "Haar", "CZ"; "[R]" / "[R:names]" for record markers)

Usage

Produced by expand_circuit for visualization and manual execution.

source
QuantumCircuitsMPS.RecordingContextType
RecordingContext

Context information passed to recording predicate functions during circuit execution.

Fields

  • step_idx::Int: Current step index (1 to n_steps passed to simulate!)
  • gate_idx::Int: Cumulative element-slot count across all steps (never resets). Advances once per element slot regardless of stochastic outcome; record!(c) markers do NOT advance it.
  • op_idx::Int: 1-based position of the current operation within circuit.operations (0 for the structural step-boundary evaluation)
  • element_idx::Int: 1-based element index within the current operation (0 for step-boundary and marker evaluations)
  • gate_type::Any: The gate applied at this slot (nothing for identity slots, marker evaluations, and the step-boundary evaluation)
  • is_step_boundary::Bool: True only for the structural step-boundary evaluation after the op loop
  • at_mark::Bool: True when this evaluation happens at a record!(c) marker pseudo-op
  • mark_index::Int: 1-based ordinal of the marker among the circuit's markers (stable across steps; 0 when at_mark == false)

Example

# Custom recording function
function my_recorder(ctx::RecordingContext)
    return ctx.gate_idx > 10 && ctx.is_step_boundary
end

# Record only at the second marker of each step
simulate!(circuit, state; record_when = ctx -> ctx.at_mark && ctx.mark_index == 2)
source
QuantumCircuitsMPS.every_n_gatesFunction
every_n_gates(n::Int)

Create a recording predicate that triggers every n gates.

Arguments

  • n::Int: Record every n gates (based on cumulative gate_idx)

Returns

Function that takes a RecordingContext and returns Bool

Example

simulate!(state, circuit; record_when=every_n_gates(5))
source
QuantumCircuitsMPS.every_n_stepsFunction
every_n_steps(n::Int)

Create a recording predicate that triggers every n steps at step boundaries.

Records once per n steps, only when is_step_boundary is true (after all gates in the step have been executed).

Arguments

  • n::Int: Record every n steps (based on step_idx)

Returns

Function that takes a RecordingContext and returns Bool

Example

simulate!(state, circuit; record_when=every_n_steps(2))
source
QuantumCircuitsMPS.print_circuitFunction
print_circuit(circuit::Circuit; n_steps::Int=1, gates_spacetime::Int=0, io::IO=stdout, unicode::Bool=true)

Print an ASCII visualization of a quantum circuit realization.

Shows the stochastic realization determined by gates_spacetime RNG seed, matching what expand_circuit(circuit; seed=gates_spacetime) produces.

Arguments

  • circuit::Circuit: Circuit to visualize
  • n_steps::Int=1: Number of circuit steps to visualize (default: 1)
  • gates_spacetime::Int=0: RNG seed controlling which stochastic branches fire.
  • io::IO: Output stream (default: stdout)
  • unicode::Bool: Use Unicode box-drawing characters (default: true)

Character Sets

  • Unicode mode (default): Uses (wire), (left box), (right box)
  • ASCII mode: Uses - (wire), | (both box edges)

Record Markers

record!(c[, names...]) markers appear as their own row with the marker glyph on every wire: in Unicode mode, [R] in ASCII mode. Named markers print their names after the wires (e.g. ▽ ... ▽ [R:entropy]).

Layout Algorithm

  1. Expands the circuit with expand_circuit_grouped (one group per apply! call)
  2. For each group, packs ops into non-overlapping layers with pack_ops_into_layers; each layer becomes one visual row, and the group label is printed only on the first row of the group
  3. Letters identify groups (not sub-rows): single-group steps are labeled "1:", multi-group steps "1a:", "1b:", etc.; empty steps → one wire-only row
  4. Calculates fixed column width based on longest gate label (+2 for box chars)
  5. Renders header row with qubit labels (e.g., "q1", "q2", "q3", "q4")
  6. Renders time step rows with gate boxes or wire segments

Multi-Qubit Gates

For gates spanning multiple sites (e.g., CZ on sites [2, 3]):

  • Gate label appears ONCE in a box on the minimum site
  • Other sites show continuation boxes (box edges without label)

Examples

# Basic usage
circuit = Circuit(L=4, bc=:periodic) do c
    apply!(c, Reset(), StaircaseRight(1))
end
print_circuit(circuit; n_steps=4)

# Output to file
open("circuit.txt", "w") do io
    print_circuit(io, circuit; n_steps=4)
end

# ASCII mode (no Unicode)
print_circuit(circuit; n_steps=4, unicode=false)

See Also

  • expand_circuit: Get a concrete stochastic realization
  • ExpandedOp: Concrete operation representation
source
print_circuit(circuit::Circuit; n_steps::Int=1, gates_spacetime::Int=0, io::IO=stdout, unicode::Bool=true)

Convenience form. Calls print_circuit(io, circuit; ...).

source
QuantumCircuitsMPS.plot_circuitFunction
plot_circuit(circuit::Circuit; n_steps=1, gates_spacetime=0, filename=nothing)

Export an SVG diagram of circuit's deterministic template (all stochastic branches, with probability annotations), resolved for n_steps repetitions using the gates_spacetime seed for stochastic-branch layout — matching expand_circuit(circuit; seed=gates_spacetime).

Requires using Luxor to be loaded first (the implementation lives in the Luxor package extension, ext/QuantumCircuitsMPSLuxorExt.jl); calling this without Luxor loaded throws an ArgumentError telling you to load Luxor. When filename is nothing, the SVG is written to a temporary file and its path returned; otherwise it is written to filename.

See also print_circuit for a Luxor-free ASCII/Unicode terminal visualization of the same circuit template.

Example

using QuantumCircuitsMPS, Luxor

circuit = Circuit(L=4, bc=:periodic) do c
    apply!(c, Reset(), StaircaseRight(1))
end
plot_circuit(circuit; gates_spacetime=42, filename="diagram.svg")
source