mimiqcircuits.backends.compiled_projection

Compiled form of a projection circuit.

extract_projection() returns the projection as a Circuit, and evaluate_projection() interprets it one instruction at a time, for one shot at a time. That is the reference semantics, and it costs one interpreted loop per shot.

CompiledProjection compiles the same circuit once, into a straight-line program over classical bits, and runs it over a whole block of shots. Two tiers:

  • Tier.IDENTITY. Bit b reads qubit b for every bit and the sample is exactly as wide as the register, so the samples are already the answer and are returned unchanged. This is the common case: measure(range, range), measure_all(), and any circuit with no classical register, since extract_projection synthesises the identity mapping for those.

  • Tier.PROGRAM. Everything else. The block becomes one (shots, num_bits) array and each operation is a single vector operation over its columns, so a permuted read-out, a reset-folded constant and a Xor tail all cost the same handful of them.

The tier depends on the width of the samples as well as on the circuit, because a Measure reading past the end of a sample contributes a zero rather than a qubit. It is therefore chosen the first time a block of a given width is evaluated, and cached.

Semantics are those of evaluate_projection, which stays the reference implementation the compiled form is tested against.

Classes

CompiledProjection(num_bits[, steps, _plans])

A projection circuit compiled for block evaluation.

Tier()

Names of the two evaluation strategies, in increasing generality.

class mimiqcircuits.backends.compiled_projection.CompiledProjection(num_bits, steps=<factory>, _plans=<factory>)[source]

Bases: object

A projection circuit compiled for block evaluation.

Build one with from_circuit() and evaluate a whole block of shots with evaluate_batch(). An instance is reusable across blocks and holds no per-shot state.

num_bits

Width of the classical bitstring the projection produces, equal to projection.num_bits().

Type:

int

steps

The straight-line program, before specialisation to a sample width. Internal representation, subject to change.

Type:

list[tuple]

num_bits: int
steps: List[tuple]
classmethod from_circuit(projection)[source]

Compile projection for block evaluation.

Parameters:

projection (Circuit) – the projection circuit returned by extract_projection(), in the frame its samples will arrive in. Qubit remapping must already have been applied, otherwise the tier keys off the wrong frame and a permuted read-out is mistaken for an identity one.

Returns:

the compiled form, of width projection.num_bits().

Return type:

CompiledProjection

Raises:

ValueError – if projection holds an operation outside the classical language, that is anything other than Measure, SetBit0, SetBit1, Not, And, Or, Xor and ParityCheck.

evaluate_batch(samples)[source]

Evaluate the projection for every shot in samples.

Parameters:

samples (Sequence[BitString]) – one computational-basis outcome per shot, all of the same width. Not quantum states: each is a single shot already drawn from one.

Returns:

one classical bitstring per shot, of length num_bits, in the order the samples came in.

Return type:

list[BitString]

On the identity tier the input bitstrings are returned as they are, without copying, so a caller that keeps using the samples afterwards must copy them itself.

evaluate(sample)[source]

Evaluate the projection for a single shot.

Provided for parity with evaluate_projection(). evaluate_batch() is the fast path and the one drivers should call.

__init__(num_bits, steps=<factory>, _plans=<factory>)
class mimiqcircuits.backends.compiled_projection.Tier[source]

Bases: object

Names of the two evaluation strategies, in increasing generality.

IDENTITY = 'identity'
PROGRAM = 'program'