#![allow(dead_code)]
use ticit::TableauSimulator;
pub const SEED: u64 = 0x5EED_0000_0000_0001;
pub struct Rng(u64);
impl Rng {
pub fn new(seed: u64) -> Self {
Rng(seed)
}
pub fn next_u64(&mut self) -> u64 {
self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.0;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
pub fn below(&mut self, bound: usize) -> usize {
(self.next_u64() % bound as u64) as usize
}
pub fn below_except(&mut self, bound: usize, avoid: usize) -> usize {
debug_assert!(bound >= 2, "no distinct partner exists on one qubit");
let q = self.below(bound - 1);
if q >= avoid { q + 1 } else { q }
}
}
pub fn clifford_stream(sim: &mut TableauSimulator, rng: &mut Rng, n: usize, count: usize) {
for _ in 0..count {
let q = rng.below(n);
match rng.below(6) {
0 => sim.h(q),
1 => sim.s(q),
2 => sim.sqrt_x(q),
3 => {
let target = rng.below_except(n, q);
sim.cx(q, target)
.expect("operands are distinct by construction");
}
4 => {
let target = rng.below_except(n, q);
sim.cz(q, target)
.expect("operands are distinct by construction");
}
_ => {
let target = rng.below_except(n, q);
sim.swap(q, target);
}
}
}
}
pub fn magic_state(n: usize, magic_qubits: u32, seed: u64) -> TableauSimulator {
let mut sim = TableauSimulator::with_seed(n, seed);
for q in 0..magic_qubits as usize {
sim.h(q);
sim.t(q)
.expect("h;t on distinct fresh qubits stays under the rank cap");
}
debug_assert_eq!(sim.rank(), 1usize << magic_qubits);
sim
}
pub fn magic_qubits_for(rank: usize) -> u32 {
debug_assert!(rank.is_power_of_two(), "rank ladder is built by doubling");
rank.trailing_zeros()
}
pub struct MixedShape {
pub n: usize,
pub rounds: usize,
pub cliffords_per_round: usize,
pub magic_per_round: usize,
pub measurements_per_round: usize,
}
impl MixedShape {
pub fn bench(n: usize) -> Self {
MixedShape {
n,
rounds: 50,
cliffords_per_round: 200,
magic_per_round: 10,
measurements_per_round: 20,
}
}
}
pub struct MixedStats {
pub final_rank: usize,
pub peak_rank: usize,
pub mean_readout_rank: f64,
pub minus_outcomes: u64,
}
pub fn mixed_verify(shape: &MixedShape, seed: u64) -> MixedStats {
let mut sim = TableauSimulator::with_seed(shape.n, seed);
let mut rng = Rng::new(seed ^ 0x5DEE_CE66_D1D3_7B00);
let mut peak_rank = sim.rank();
let mut minus_outcomes = 0u64;
let mut readout_rank_total = 0u64;
let mut readout_count = 0u64;
let mut magic_cursor = 0usize;
for _ in 0..shape.rounds {
clifford_stream(&mut sim, &mut rng, shape.n, shape.cliffords_per_round);
let magic: Vec<usize> = (0..shape.magic_per_round)
.map(|i| (magic_cursor + i) % shape.n)
.collect();
magic_cursor = (magic_cursor + shape.magic_per_round) % shape.n;
for &q in &magic {
sim.h(q);
sim.t(q).expect("injection stays under the rank cap");
}
peak_rank = peak_rank.max(sim.rank());
for _ in 0..shape.measurements_per_round {
readout_rank_total += sim.rank() as u64;
readout_count += 1;
let q = rng.below(shape.n);
let outcome = sim
.measure(q)
.expect("projection never grows the compressed rank");
minus_outcomes += u64::from(outcome.outcome);
}
for &q in &magic {
sim.reset_z(q)
.expect("reset is a measurement plus a frame X");
}
}
MixedStats {
final_rank: sim.rank(),
peak_rank,
mean_readout_rank: readout_rank_total as f64 / readout_count.max(1) as f64,
minus_outcomes,
}
}