use crate::error::{QuantumError, QuantumResult};
use crate::fourier::qft::qft_inverse_inplace;
use crate::gates::hadamard::gate_h;
use crate::statevec::apply_1q::apply_1q_inplace;
use crate::statevec::state::StateVector;
#[must_use]
pub fn mod_exp(base: u64, exp: u64, modulus: u64) -> u64 {
if modulus <= 1 {
return 0;
}
let mut result: u128 = 1;
let mut b = (base % modulus) as u128;
let m = modulus as u128;
let mut e = exp;
while e > 0 {
if e & 1 == 1 {
result = (result * b) % m;
}
b = (b * b) % m;
e >>= 1;
}
result as u64
}
#[must_use]
pub fn gcd(mut a: u64, mut b: u64) -> u64 {
if a == 0 {
return b;
}
if b == 0 {
return a;
}
let shift = (a | b).trailing_zeros();
a >>= a.trailing_zeros();
loop {
b >>= b.trailing_zeros();
if a > b {
std::mem::swap(&mut a, &mut b);
}
b -= a;
if b == 0 {
break;
}
}
a << shift
}
#[must_use]
pub fn continued_fraction_convergents(value: f64, max_denominator: u64) -> Vec<(u64, u64)> {
let mut convergents = Vec::new();
let mut x = value;
let mut p_minus2: i128 = 0; let mut p_minus1: i128 = 1; let mut q_minus2: i128 = 1; let mut q_minus1: i128 = 0; for _ in 0..64 {
let a = x.floor();
if !a.is_finite() {
break;
}
let a_i = a as i128;
let p_next = a_i * p_minus1 + p_minus2;
let q_next = a_i * q_minus1 + q_minus2;
if q_next <= 0 || q_next as u64 > max_denominator {
break;
}
convergents.push((p_next.max(0) as u64, q_next as u64));
p_minus2 = p_minus1;
p_minus1 = p_next;
q_minus2 = q_minus1;
q_minus1 = q_next;
let frac = x - a;
if frac.abs() < 1e-12 {
break;
}
x = 1.0 / frac;
}
convergents
}
#[derive(Debug, Clone)]
pub struct OrderFindingResult {
pub order: u64,
pub phase: f64,
pub measured: usize,
pub counting_qubits: usize,
}
#[must_use]
pub fn classical_order(a: u64, n: u64) -> u64 {
if n <= 1 || gcd(a, n) != 1 {
return 0;
}
let mut cur = a % n;
let mut r = 1u64;
while cur != 1 {
cur = (cur as u128 * (a % n) as u128 % n as u128) as u64;
r += 1;
if r > n {
return 0;
}
}
r
}
pub fn order_finding(
base: u64,
modulus: u64,
counting_qubits: usize,
) -> QuantumResult<OrderFindingResult> {
if modulus < 2 {
return Err(QuantumError::InvalidParameter {
name: format!("modulus {modulus} must be ≥ 2"),
});
}
if counting_qubits == 0 {
return Err(QuantumError::InvalidQubitCount { n: 0 });
}
let a = base % modulus;
if gcd(a, modulus) != 1 {
return Err(QuantumError::InvalidParameter {
name: format!("base {base} not coprime to modulus {modulus}"),
});
}
let work_qubits = {
let mut bits = 0usize;
let mut cap = 1u64;
while cap < modulus {
cap <<= 1;
bits += 1;
}
bits.max(1)
};
let total = counting_qubits + work_qubits;
if total > 30 {
return Err(QuantumError::InvalidParameter {
name: format!("total qubits {total} exceeds 30"),
});
}
let mut sv = StateVector::new_zero_state(total)?;
let work_one = 1usize << counting_qubits;
sv.amps[0] = num_complex::Complex::new(0.0, 0.0);
sv.amps[work_one] = num_complex::Complex::new(1.0, 0.0);
for q in 0..counting_qubits {
apply_1q_inplace(&mut sv, q, &gate_h())?;
}
let count_mask = (1usize << counting_qubits) - 1;
for j in 0..counting_qubits {
let power = mod_exp(a, 1u64 << j, modulus);
if power == 1 {
continue; }
let ctrl_bit = 1usize << j;
let dim = 1usize << total;
let mut new_amps = vec![num_complex::Complex::<f32>::new(0.0, 0.0); dim];
for (idx, amp) in sv.amps.iter().enumerate() {
if amp.norm_sqr() == 0.0 {
continue;
}
if idx & ctrl_bit == 0 {
new_amps[idx] += *amp;
continue;
}
let work_val = (idx >> counting_qubits) as u64;
let count_part = idx & count_mask;
let new_work = if work_val < modulus {
(work_val as u128 * power as u128 % modulus as u128) as usize
} else {
work_val as usize };
let target = count_part | (new_work << counting_qubits);
new_amps[target] += *amp;
}
sv.amps = new_amps;
}
let counting_indices: Vec<usize> = (0..counting_qubits).collect();
qft_inverse_inplace(&mut sv, &counting_indices)?;
let dim_count = 1usize << counting_qubits;
let mut marg = vec![0.0f32; dim_count];
for (idx, amp) in sv.amps.iter().enumerate() {
marg[idx & count_mask] += amp.norm_sqr();
}
let mut measured = 0usize;
let mut best = f32::NEG_INFINITY;
for (i, &p) in marg.iter().enumerate() {
if p > best {
best = p;
measured = i;
}
}
let phase = measured as f64 / dim_count as f64;
let threshold = 0.5f32 / dim_count as f32; let mut peaks: Vec<(usize, f32)> = marg
.iter()
.enumerate()
.filter(|&(_, &p)| p > threshold)
.map(|(i, &p)| (i, p))
.collect();
peaks.sort_by(|a, b| {
b.1.partial_cmp(&a.1)
.unwrap_or(std::cmp::Ordering::Equal)
.then(a.0.cmp(&b.0))
});
let mut order = 0u64;
'scan: for &(idx, _) in &peaks {
if idx == 0 {
continue; }
let phi = idx as f64 / dim_count as f64;
for (_, q) in continued_fraction_convergents(phi, modulus) {
if q == 0 {
continue;
}
if mod_exp(a, q, modulus) == 1 {
order = q;
break 'scan;
}
}
}
Ok(OrderFindingResult {
order,
phase,
measured,
counting_qubits,
})
}
#[derive(Debug, Clone)]
pub struct ShorResult {
pub factor: Option<u64>,
pub base: u64,
pub order: u64,
}
#[must_use]
pub fn factor_from_order(base: u64, n: u64, r: u64) -> Option<u64> {
if r == 0 || !r.is_multiple_of(2) || n < 2 {
return None;
}
let half = mod_exp(base, r / 2, n);
if half == 1 || half == n - 1 {
return None;
}
[gcd(half + 1, n), gcd(half.wrapping_sub(1), n)]
.into_iter()
.find(|&candidate| candidate > 1 && candidate < n)
}
pub fn shor_factor(n: u64, bases: &[u64], counting_qubits: usize) -> QuantumResult<ShorResult> {
if n < 2 {
return Err(QuantumError::InvalidParameter {
name: format!("N {n} must be ≥ 2"),
});
}
if bases.is_empty() {
return Err(QuantumError::EmptyInput);
}
if n.is_multiple_of(2) {
return Ok(ShorResult {
factor: Some(2),
base: 2,
order: 0,
});
}
let mut last_base = bases[0];
for &a in bases {
let a = a % n;
if a < 2 {
continue;
}
last_base = a;
let g = gcd(a, n);
if g > 1 {
return Ok(ShorResult {
factor: Some(g),
base: a,
order: 0,
});
}
let of = order_finding(a, n, counting_qubits)?;
if of.order == 0 {
continue;
}
if let Some(factor) = factor_from_order(a, n, of.order) {
return Ok(ShorResult {
factor: Some(factor),
base: a,
order: of.order,
});
}
}
Ok(ShorResult {
factor: None,
base: last_base,
order: 0,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mod_exp_basic() {
assert_eq!(mod_exp(2, 10, 1000), 24); assert_eq!(mod_exp(7, 0, 13), 1);
assert_eq!(mod_exp(3, 3, 7), 6); }
#[test]
fn mod_exp_large_no_overflow() {
let m = (1u64 << 61) - 1;
let v = mod_exp(2, 62, m);
assert!(v < m);
assert_eq!(v, 2);
}
#[test]
fn gcd_basic() {
assert_eq!(gcd(54, 24), 6);
assert_eq!(gcd(17, 13), 1);
assert_eq!(gcd(0, 5), 5);
assert_eq!(gcd(8, 0), 8);
}
#[test]
fn continued_fraction_recovers_denominator() {
let cs = continued_fraction_convergents(0.25, 100);
assert!(cs.iter().any(|&(_, q)| q == 4), "convergents={cs:?}");
}
#[test]
fn continued_fraction_for_third() {
let cs = continued_fraction_convergents(1.0 / 3.0, 100);
assert!(cs.iter().any(|&(p, q)| p == 1 && q == 3), "cs={cs:?}");
}
#[test]
fn classical_order_matches_definition() {
assert_eq!(classical_order(2, 15), 4);
assert_eq!(classical_order(7, 15), 4);
assert_eq!(classical_order(6, 15), 0);
}
#[test]
fn order_finding_period_of_2_mod_15() {
let res = order_finding(2, 15, 8)
.expect("a=2 coprime to N=15, 8 counting qubits within valid range");
assert_eq!(
res.order, 4,
"phase={}, measured={}",
res.phase, res.measured
);
}
#[test]
fn order_finding_period_of_4_mod_15() {
let res = order_finding(4, 15, 8)
.expect("a=4 coprime to N=15, 8 counting qubits within valid range");
assert_eq!(res.order, 2);
}
#[test]
fn order_finding_period_of_2_mod_21() {
let res = order_finding(2, 21, 9)
.expect("a=2 coprime to N=21, 9 counting qubits within valid range");
assert!(res.order == 6 || (res.order > 0 && mod_exp(2, res.order, 21) == 1));
}
#[test]
fn order_finding_rejects_non_coprime() {
assert!(order_finding(3, 15, 6).is_err()); }
#[test]
fn order_finding_rejects_bad_modulus() {
assert!(order_finding(2, 1, 6).is_err());
assert!(order_finding(2, 15, 0).is_err());
}
#[test]
fn factor_from_order_factors_15() {
let f = factor_from_order(7, 15, 4)
.expect("order 4 of base 7 mod 15 is even and yields a non-trivial factor");
assert!(f == 3 || f == 5, "f={f}");
}
#[test]
fn factor_from_order_rejects_odd_order() {
assert_eq!(factor_from_order(2, 7, 3), None);
}
#[test]
fn shor_factor_even_shortcut() {
let res = shor_factor(8, &[3, 5, 7], 6)
.expect("N=8 is even so shor_factor short-circuits to factor 2");
assert_eq!(res.factor, Some(2));
}
#[test]
fn shor_factor_fifteen() {
let res = shor_factor(15, &[2, 7, 11, 13], 8)
.expect("N=15 with coprime bases and 8 counting qubits should succeed");
let f = res.factor.expect("should find a factor");
assert!(f == 3 || f == 5, "factor={f}");
assert_eq!(15 % f, 0);
}
#[test]
fn shor_factor_lucky_gcd() {
let res = shor_factor(15, &[5], 6)
.expect("base=5 shares factor 5 with N=15 so shor_factor succeeds immediately");
assert_eq!(res.factor, Some(5));
}
#[test]
fn shor_factor_empty_bases_errors() {
assert!(shor_factor(15, &[], 6).is_err());
}
#[test]
fn shor_factor_invalid_n_errors() {
assert!(shor_factor(1, &[2], 6).is_err());
}
}