qsimlab.shor
qsimlab.shor
¶
Shor's algorithm at gate level: factoring runs, oracle circuits, resource counts, cost laws.
Provisional (phase 2, see python/API.md §1 and §8).
Every run simulates the semiclassical order-finding circuit exactly (one recycled
control qubit, Griffiths–Niu phase corrections) with a gate-level oracle built
from X/CNOT/Toffoli gates, on the bit-sliced branch engine of
research/shor/shor.md (or the dense/sparse engines for the permutation and
Beauregard oracles):
>>> import qsimlab.shor as shor
>>> r = shor.factor(1_005_973, seed=1) # 20-bit N, 88 qubits
>>> r.factors, r.base, r.order
((997, 1009), 980062, 41832)
>>> r.qubits, r.toffoli_gates
(88, 70720)
>>> bool((r.runs[0].support_trace <= r.runs[0].predicted_support).all())
True
The cost of a run is set by the multiplicative order r of the base, not by
N (the support law, research/theory/theory-shor.md T1): before round i the
state holds at most B_i = min(2^i, r / gcd(r, 2^(t-i))) branches.
factor predicts the peak memory from it before running and refuses
runs over budget with ResourceLimitError. The order used
for that prediction is computed classically (Pollard–Brent factoring); the
simulated algorithm never sees it. This is exact simulation, not a factoring
speed-up: for a generic semiprime and a random base, r ≈ N/c and the work
grows like N · n³.
Oracles (oracle=, see ORACLES):
"windowed-opt"(default): Gidney's windowed table-lookup multiplier with the superoptimised blocks ofresearch/shor/superopt.md;4n + 4 + wqubits;"windowed-mbu-lookup"/"windowed-mbu": measurement-based uncomputation (research/shor/mbu-shor.md): fewer Toffolis, X-basis measurements with classical fix-ups;"windowed","ripple": the round-4 windowed oracle and the Cuccaro ripple-carry oracle (3n + 4qubits);"beauregard": Draper/Beauregard QFT arithmetic,2n + 3qubits, dense state (≈ 10-bit N);"permutation": a classical lookup table as the oracle,n + 1qubits (measurement statistics only, not a compilable circuit);"ge"/"eh": Gidney–Ekerå exponent windowing (research/shor/ge-shor.md) for Shor's order finding, or the Ekerå–Håstad short-discrete-log schedule (1.5nexponent bits, lattice post-processing; balanced semiprimes).
ShorRun
dataclass
¶
ShorRun(
base: int,
measured: Union[int, Tuple[int, ...]],
order: Optional[int],
factors: Optional[Tuple[int, int]],
qubits: int,
total_gates: int,
toffoli_gates: int,
measurements: int,
peak_support: int,
peak_amplitude_bytes: int,
gate_branch_ops: int,
true_order: int,
predicted_peak_support: int,
predicted_bytes: int,
engine: str,
wall_time: float,
support_trace: Optional[ndarray] = None,
p1_trace: Optional[ndarray] = None,
)
One order-finding (or Ekerå–Håstad) run.
base: the basea;measured: the measured integer (biti= roundi), a tuple(k, j)for"eh"(one integer per exponent register);order/factors: what the classical post-processing recovered (Noneif it failed — that is the classical part of Shor failing, e.g. an odd order ora^(r/2) ≡ −1);qubits,total_gates(every gate of the run, control gates included),toffoli_gates,measurements(mid-circuit X-basis measurements of the MBU oracles);peak_support: largest number of stored branches;peak_amplitude_bytes: amplitude memory of dense/sparse engines, peak branch count of the GE engine;gate_branch_ops: gates × branches evaluated (the work of the sliced engine);true_order: the multiplicative order computed classically (for the memory guard);predicted_peak_support/predicted_bytes: the guard's prediction;support_trace: branches stored before every round (sliced engine,trace=True),p1_trace:P(control = 1)of every round.
predicted_support
property
¶
B_i for the rounds in support_trace (None without a trace).
FactorResult
dataclass
¶
FactorResult(
engine: str,
components: List[Tuple[int, int, str]],
seed: int,
precision: str,
wall_time: float,
explanation: Optional[Explanation] = None,
N: int = 0,
oracle: str = "",
factors: Optional[Tuple[int, int]] = None,
base: Optional[int] = None,
order: Optional[int] = None,
measured: Union[int, Tuple[int, ...], None] = None,
qubits: int = 0,
total_gates: int = 0,
toffoli_gates: int = 0,
peak_support: int = 0,
budget: int = 0,
runs: List[ShorRun] = list(),
)
Bases: Result
Result of factor (a qsimlab.sim.Result).
factors is (p, q) with p ≤ q or None; base, order,
measured and the resource fields describe the last (successful) run;
runs lists every attempt (ShorRun). components has one
(qubits, gates, engine) entry per run.
ResourceCounts
dataclass
¶
ResourceCounts(
N: int,
base: int,
oracle: str,
qubits: int,
rounds: int,
gate_level: bool,
oracle_gates: int,
toffoli: int,
cnot: int,
x: int,
measurements: int,
fixups: int,
slice_steps: Optional[int] = None,
per_round_gates: Optional[ndarray] = None,
per_round_toffoli: Optional[ndarray] = None,
)
Whole-run counts of the oracle blocks of one order-finding (or EH) run.
oracle_gates counts every operation of the rounds controlled-U
blocks (X, CNOT, Toffoli, X-basis measurements and their Z/CZ fix-ups);
toffoli, cnot, x, measurements, fixups break it down.
The semiclassical control adds at most 2 H, 1 phase and 1 recycling X per
round (control_gates_max). For the MBU and GE oracles the counts depend
on the (fixed, seeded) outcome stream of the engine. slice_steps: GE only.
gate_level is False for the permutation oracle (no gates).
OracleCircuit
dataclass
¶
OracleCircuit(
circuit: Circuit,
N: int,
a: int,
oracle: str,
control: int,
work: List[int],
num_qubits: int,
gates: int,
toffolis: int,
)
A controlled-U_a block: |c⟩|x⟩|0…0⟩ → |c⟩|a^c·x mod N⟩|0…0⟩ for x < N.
control is qubit 0, work[k] holds bit k of x, every other qubit
is an ancilla that starts and ends in |0⟩.
SupportPrediction
dataclass
¶
SupportPrediction(
order: int,
nu: int,
rounds: int,
peak: int,
sum: int,
engine: str,
predicted_bytes: int,
bounds: ndarray,
)
The support law for (N, a): order r, nu = ν₂(r), rounds t = 2n,
bounds (B_i), peak (max_i B_i), sum (Σ B_i; the sliced
engine's work is ≈ 2 Ḡ Σ B_i gate·branch steps for Ḡ gates per round),
and the engine and peak bytes factor would predict.
NoisySuccess
dataclass
¶
NoisySuccess(
engine: str,
components: List[Tuple[int, int, str]],
seed: int,
precision: str,
wall_time: float,
explanation: Optional[Explanation] = None,
N: int = 0,
base: int = 0,
p: float = 0.0,
noise: str = "",
trajectories: int = 0,
locations: int = 0,
order: int = 0,
success: float = 0.0,
ci: Tuple[float, float] = (0.0, 1.0),
order_rate: float = 0.0,
peak_rate: float = 0.0,
capped: int = 0,
mean_faults: float = 0.0,
faults: Optional[ndarray] = None,
factor_ok: Optional[ndarray] = None,
order_ok: Optional[ndarray] = None,
peak_ok: Optional[ndarray] = None,
measured: Optional[List[Optional[int]]] = None,
)
Bases: Result
Result of noisy_success (a qsimlab.sim.Result).
success: fraction of trajectories whose post-processing returned a factor, withciits Wilson 95 % interval;order_rate: the true order was recovered;peak_rate: the measuredyis a "good" outcome,|y/2^t − s/r| < 1/(2r²)(the metric ofresearch/shor/shor-noise.md);locations: fault locationsLof the circuit,mean_faults;capped: trajectories abandoned because their support exceededcap(counted as failures);- per-trajectory arrays
faults,factor_ok,order_ok,peak_ok.
support_bounds
¶
The support law (research/theory/theory-shor.md T1): B_i = min(2^i, r / gcd(r, 2^(t-i)))
for i = 0 … t-1 — an upper bound on the number of branches before round i,
attained except with probability ≤ 4/r_odd per round.
factor
¶
factor(
N: int,
*,
oracle: str = "windowed-opt",
window: Optional[int] = None,
exponent_window: Optional[int] = None,
base: Optional[int] = None,
precision: str = "f64",
seed: Optional[int] = None,
tries: int = 10,
budget: Union[Budget, int, str, None] = None,
engine: str = "auto",
trace: bool = True,
threads: Optional[int] = None,
) -> FactorResult
Factor N by simulating Shor's algorithm at gate level.
Up to tries runs; each draws a random base a (or uses base),
simulates the whole semiclassical order-finding circuit and post-processes
the measured integer (continued fractions, small multiples), stopping at
the first run that yields a factor. With the same seed the bases and
measured integers are those of qsim run shor --seed <seed> (the CLI of
the Rust crate).
window: lookup windowwof the windowed oracles (default 4) or the multiplicand windoww_mof"ge"/"eh"(default 3);exponent_window:w_eof"ge"/"eh"(default 2).precision: amplitudes in"f64"or"f32"(≈ 35 % less memory; distributions within 1e-7 of f64,research/shor/shor.md).budget: refuse (ResourceLimitError, withneeded/limit) any run whose predicted peak memory exceeds it. Default:min(32 GiB, half the physical memory).engine:"auto"(sliced branches for the gate-level X/CNOT/CCX oracles, the cheaper of fused dense/sparse for"permutation", dense for"beauregard"), or"sliced","dense","sparse".
N must be odd, composite, not a prime power, and below 2^62.
resource_counts
¶
resource_counts(
N: int,
oracle: str = "windowed-opt",
*,
window: Optional[int] = None,
exponent_window: Optional[int] = None,
base: Optional[int] = None,
per_round: bool = False,
threads: Optional[int] = None,
) -> ResourceCounts
Qubits and whole-run gate counts of the circuit, without simulating.
base defaults to the smallest base coprime to N (counts depend on
it only weakly, through the constants of the lookup tables).
oracle_circuit
¶
oracle_circuit(
N: int,
a: int,
oracle: str = "windowed-opt",
*,
window: Optional[int] = None,
) -> OracleCircuit
The controlled-multiplication-by-a block of oracle as a Circuit.
Supported: "windowed-opt", "windowed", "ripple" (X/CNOT/CCX only)
and "beauregard" (QFT arithmetic). The MBU oracles need multi-bit
classical feed-forward that a Circuit cannot express
(UnsupportedOperationError); count them with resource_counts.
shor_circuit
¶
shor_circuit(
N: int,
a: int,
oracle: str = "ripple",
*,
window: Optional[int] = None,
) -> Circuit
The whole semiclassical order-finding circuit as a Circuit.
Qubit 0 is the recycled control, 1 … n the work register (prepared in
|1⟩). Round i: recycle (X conditioned on measurement i−1),
H, controlled U^(2^(t−1−i)), one conditioned phase per earlier bit,
H, measure. Measurement i is bit i of the measured integer, so
simulate(c, samples(k)) samples the same distribution as factor.
exact_distribution
¶
exact_distribution(
N: int,
a: int,
oracle: str = "permutation",
*,
window: Optional[int] = None,
prune: float = 0.0,
threads: Optional[int] = None,
) -> ndarray
Exact probabilities of the 2n-bit measured integer (float64[2**(2n)]),
by walking the whole measurement tree of the semiclassical circuit (n ≤ 8 bits;
10 for "permutation", 6 for "beauregard").
predict_support
¶
predict_support(
N: int,
a: int,
oracle: str = "windowed-opt",
*,
window: Optional[int] = None,
exponent_window: Optional[int] = None,
precision: str = "f64",
) -> SupportPrediction
multiplicative_order
¶
carmichael
¶
noisy_success
¶
noisy_success(
N: int,
a: int,
p: float,
*,
noise: str = "depolarizing",
trajectories: int = 200,
oracle: str = "windowed",
window: Optional[int] = None,
faults: Optional[int] = None,
seed: Optional[int] = None,
reset_ancillas: bool = False,
cap: int = 1 << 26,
threads: Optional[int] = None,
) -> NoisySuccess
Success probability of the gate-level circuit under circuit-level Pauli noise.
Exact Monte-Carlo trajectories (research/shor/shor-noise.md): a Pauli fault
at rate p after every oracle gate on each of its qubits, and on the
control (preparation, after each H and the phase correction, readout
flip). noise: "depolarizing", "bitflip" or "phaseflip".
faults=k instead conditions every trajectory on exactly k faults at
uniformly random locations (stratified estimates). reset_ancillas: an
ideal reset of every ancilla after each round. Oracles: "windowed",
"windowed-opt", "ripple" (≤ 129 qubits). Trajectory i uses a
stream derived from (seed, i): results do not depend on threads.