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 classical-bit operations:
Measure(q, b)—cstate[b] = sample[q]SetBit0(b)/SetBit1(b)— bit is classically knownNot(b)—cstate[b] = !cstate[b]And/Or/Xor—bits[0]is the target, the rest are read
Evaluate it one shot at a time with evaluate_projection, or a whole block at a time with CompiledProjection, which is the same semantics compiled once instead of interpreted per shot.
Functions
|
Return True if circuit contains a mixed-unitary |
|
Run the projection circuit for one shot. |
|
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. |
|
Return True if circuit contains loss operations (Loss, Reload, Check, MeasureCheck) that must be resolved into primitives before the simulator runs. |
|
Return True if circuit still contains any non-unitary op that requires per-shot evolution. |
|
Rewrite every Measure(q, b) instruction in projection so that |
- 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 classical logic:
Not,And,Or,Xor,SetBit0,SetBit1. These read other classical bits, so what comes out is a straight-line program over the register rather than a per-bit map, emitted in source order. A logic op is absorbed only when no operation left inquantum_circuittouches any of its bits, otherwise moving it past that operation would change what it reads.Trailing
GateID— dropped as a no-op.GateX/GateY/GateZare NOT absorbed:YandZcarry phases that would corrupt amplitude lookups, andXabsorbed alone would require XOR-ing the qubit-flip pattern into every user-suppliedbitstringsentry for amplitudes to stay consistent. Keeping all Paulis inquantum_circuitmeans 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/SetBit1based on absorbed X parity). AResetwhose 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 intoquantum_circuit.If the source has no classical register, the projection is synthesised over an identity bit↔qubit mapping (bit
imirrors qubiti, length =circuit.num_qubits()).A write to a classical bit that a later absorbed operation overwrites without reading is dropped from the projection, so reusing a classical bit does not cost a per-shot write that nothing observes.
- mimiqcircuits.backends.measure_analysis.evaluate_projection(projection, sample)[source]¶
Run the projection circuit for one shot.
- Parameters:
projection (Circuit) – the projection circuit returned by
extract_projection().sample (BitString) – one computational-basis outcome, one bit per qubit of the evolved state. Not a quantum state: it is a single shot already drawn from it.
- Returns:
the classical register after the projection, of length
projection.num_bits().- Return type:
BitString
- Raises:
ValueError – if projection holds an instruction outside the classical language listed below.
The classical language is
Measure,SetBit0,SetBit1,Not,And,OrandXor. The logic ops take their target as the first bit and read the rest, and the whole right-hand side is evaluated before the target is written, so a target that is also one of its own operands reads its old value.A
Measure(q, b)whose qubit falls outside sample leaves bitbuntouched, which is how a projection that references a qubit the state never spanned reads back as zero.This is the single-shot reference implementation of the projection semantics.
CompiledProjectionis the fast path, and is tested against this.
- 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.
- mimiqcircuits.backends.measure_analysis.needs_loss_sampling(circuit)[source]¶
Return True if circuit contains loss operations (Loss, Reload, Check, MeasureCheck) that must be resolved into primitives before the simulator runs.
- mimiqcircuits.backends.measure_analysis.any_mixed_unitary(circuit)[source]¶
Return True if circuit contains a mixed-unitary
krauschannelwhose ismixedunitary() is true. Used as the default predicate for the per-trajectory recompile decision inLocalBackend.recompile_per_trajectory().
- 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.