mimiqcircuits.backends.measure_analysis

Final-block analysis. Reverse-scan a Circuit, absorb its trailing “projection block” (Measures, Resets, post-measure X gates) into a small projection_circuit of classical-bit instructions, and return the remaining quantum_circuit plus that projection.

The two-circuit decomposition is the post-evolution analog of the old MeasureInfo enum:

quantum_circuit, projection_circuit = extract_projection(c) # evolve through quantum_circuit once # for each shot: # sample = quantum_state.sample() # cstate = evaluate_projection(projection_circuit, sample)

projection_circuit only contains:

  • Measure(q, b)cstate[b] = sample[q]

  • Not(b)cstate[b] = !cstate[b]

  • SetBit0(b) / SetBit1(b) — bit is classically known

Mirrors the Julia AbstractQCSs.extract_projection. The two ports must stay behavioural-parity — if one is fixed, fix the other.

Functions

any_mixed_unitary(circuit)

Return True if circuit contains a mixed-unitary krauschannel whose ismixedunitary() is true.

evaluate_projection(projection, sample)

Run the projection circuit on a single raw quantum-state sample, returning the resulting classical bitstring.

extract_projection(circuit)

Reverse-scan circuit, absorbing every trailing operation that does not affect the qubit observables of the post-evolution state into a projection_circuit of classical-bit instructions.

needs_loss_sampling(circuit)

Return True if circuit contains a LossErr or QubitLoss operation that must be sampled (Method-1 pre-evolve sampling) before the simulator runs.

needs_trajectories(circuit)

Return True if circuit still contains any non-unitary op that requires per-shot evolution.

remap_projection_qubits(projection, ...)

Rewrite every Measure(q, b) instruction in projection so that q qubit_order[q].

mimiqcircuits.backends.measure_analysis.extract_projection(circuit)[source]

Reverse-scan circuit, absorbing every trailing operation that does not affect the qubit observables of the post-evolution state into a projection_circuit of classical-bit instructions. The remaining operations are returned as quantum_circuit — the part the simulator must evolve.

Absorbed operations:

  • Trailing Measure(q, b) / MeasureReset(q, b)Measure(q, b).

  • Trailing GateID — dropped as a no-op. GateX / GateY / GateZ are NOT absorbed: Y and Z carry phases that would corrupt amplitude lookups, and X absorbed alone would require XOR-ing the qubit-flip pattern into every user-supplied bitstrings entry for amplitudes to stay consistent. Keeping all Paulis in quantum_circuit means the projection only contains phase-free transformations and amplitude lookups need no compensation.

  • Reset(q) whose qubit has captured pending bits → those bits become classical constants (SetBit0 / SetBit1 based on absorbed X parity). A Reset whose qubit has no captured bits is harmless and dropped.

Anything that cannot be absorbed (other gates, Kraus channels, IfStatement, Amplitude, ExpectationValue, …) blocks its qubits and survives into quantum_circuit.

If the source has no classical register, the projection is synthesised over an identity bit↔qubit mapping (bit i mirrors qubit i, length = circuit.num_qubits()).

mimiqcircuits.backends.measure_analysis.evaluate_projection(projection, sample)[source]

Run the projection circuit on a single raw quantum-state sample, returning the resulting classical bitstring.

mimiqcircuits.backends.measure_analysis.needs_trajectories(circuit)[source]

Return True if circuit still contains any non-unitary op that requires per-shot evolution. Operations that don’t touch qubits (Amplitude on a z-register, Tick, …) or that declare themselves unitary (Gates, AbstractAnnotation, ExpectationValue, …) are ignored.

Mirrors the Julia AbstractQCSs.needs_trajectories: num_qubits(op) != 0 && !isunitary(op).

mimiqcircuits.backends.measure_analysis.needs_loss_sampling(circuit)[source]

Return True if circuit contains a LossErr or QubitLoss operation that must be sampled (Method-1 pre-evolve sampling) before the simulator runs.

mimiqcircuits.backends.measure_analysis.any_mixed_unitary(circuit)[source]

Return True if circuit contains a mixed-unitary krauschannel whose ismixedunitary() is true. Used as the default predicate for the per-trajectory recompile decision in LocalBackend.recompile_per_trajectory().

Mirrors the Julia AbstractQCSs.any_mixed_unitary.

mimiqcircuits.backends.measure_analysis.remap_projection_qubits(projection, qubit_order, do_remap)[source]

Rewrite every Measure(q, b) instruction in projection so that q qubit_order[q]. Used by the driver when the pass pipeline reordered the qubits and the projection was synthesised in the reordered frame.

Returns a new Circuit; the input is not mutated.