oxicuda_quantum/algorithm/
shor.rs1use crate::error::{QuantumError, QuantumResult};
24use crate::fourier::qft::qft_inverse_inplace;
25use crate::gates::hadamard::gate_h;
26use crate::statevec::apply_1q::apply_1q_inplace;
27use crate::statevec::state::StateVector;
28
29#[must_use]
35pub fn mod_exp(base: u64, exp: u64, modulus: u64) -> u64 {
36 if modulus <= 1 {
37 return 0;
38 }
39 let mut result: u128 = 1;
40 let mut b = (base % modulus) as u128;
41 let m = modulus as u128;
42 let mut e = exp;
43 while e > 0 {
44 if e & 1 == 1 {
45 result = (result * b) % m;
46 }
47 b = (b * b) % m;
48 e >>= 1;
49 }
50 result as u64
51}
52
53#[must_use]
55pub fn gcd(mut a: u64, mut b: u64) -> u64 {
56 if a == 0 {
57 return b;
58 }
59 if b == 0 {
60 return a;
61 }
62 let shift = (a | b).trailing_zeros();
63 a >>= a.trailing_zeros();
64 loop {
65 b >>= b.trailing_zeros();
66 if a > b {
67 std::mem::swap(&mut a, &mut b);
68 }
69 b -= a;
70 if b == 0 {
71 break;
72 }
73 }
74 a << shift
75}
76
77#[must_use]
85pub fn continued_fraction_convergents(value: f64, max_denominator: u64) -> Vec<(u64, u64)> {
86 let mut convergents = Vec::new();
87 let mut x = value;
88 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 {
95 let a = x.floor();
96 if !a.is_finite() {
97 break;
98 }
99 let a_i = a as i128;
100 let p_next = a_i * p_minus1 + p_minus2;
101 let q_next = a_i * q_minus1 + q_minus2;
102 if q_next <= 0 || q_next as u64 > max_denominator {
103 break;
104 }
105 convergents.push((p_next.max(0) as u64, q_next as u64));
106 p_minus2 = p_minus1;
107 p_minus1 = p_next;
108 q_minus2 = q_minus1;
109 q_minus1 = q_next;
110 let frac = x - a;
111 if frac.abs() < 1e-12 {
112 break;
113 }
114 x = 1.0 / frac;
115 }
116 convergents
117}
118
119#[derive(Debug, Clone)]
121pub struct OrderFindingResult {
122 pub order: u64,
124 pub phase: f64,
126 pub measured: usize,
128 pub counting_qubits: usize,
130}
131
132#[must_use]
137pub fn classical_order(a: u64, n: u64) -> u64 {
138 if n <= 1 || gcd(a, n) != 1 {
139 return 0;
140 }
141 let mut cur = a % n;
142 let mut r = 1u64;
143 while cur != 1 {
144 cur = (cur as u128 * (a % n) as u128 % n as u128) as u64;
145 r += 1;
146 if r > n {
147 return 0;
148 }
149 }
150 r
151}
152
153pub fn order_finding(
168 base: u64,
169 modulus: u64,
170 counting_qubits: usize,
171) -> QuantumResult<OrderFindingResult> {
172 if modulus < 2 {
173 return Err(QuantumError::InvalidParameter {
174 name: format!("modulus {modulus} must be ≥ 2"),
175 });
176 }
177 if counting_qubits == 0 {
178 return Err(QuantumError::InvalidQubitCount { n: 0 });
179 }
180 let a = base % modulus;
181 if gcd(a, modulus) != 1 {
182 return Err(QuantumError::InvalidParameter {
183 name: format!("base {base} not coprime to modulus {modulus}"),
184 });
185 }
186 let work_qubits = {
188 let mut bits = 0usize;
189 let mut cap = 1u64;
190 while cap < modulus {
191 cap <<= 1;
192 bits += 1;
193 }
194 bits.max(1)
195 };
196 let total = counting_qubits + work_qubits;
197 if total > 30 {
198 return Err(QuantumError::InvalidParameter {
199 name: format!("total qubits {total} exceeds 30"),
200 });
201 }
202
203 let mut sv = StateVector::new_zero_state(total)?;
204 let work_one = 1usize << counting_qubits;
206 sv.amps[0] = num_complex::Complex::new(0.0, 0.0);
207 sv.amps[work_one] = num_complex::Complex::new(1.0, 0.0);
208
209 for q in 0..counting_qubits {
211 apply_1q_inplace(&mut sv, q, &gate_h())?;
212 }
213
214 let count_mask = (1usize << counting_qubits) - 1;
217 for j in 0..counting_qubits {
218 let power = mod_exp(a, 1u64 << j, modulus);
219 if power == 1 {
220 continue; }
222 let ctrl_bit = 1usize << j;
223 let dim = 1usize << total;
224 let mut new_amps = vec![num_complex::Complex::<f32>::new(0.0, 0.0); dim];
225 for (idx, amp) in sv.amps.iter().enumerate() {
226 if amp.norm_sqr() == 0.0 {
227 continue;
228 }
229 if idx & ctrl_bit == 0 {
230 new_amps[idx] += *amp;
231 continue;
232 }
233 let work_val = (idx >> counting_qubits) as u64;
234 let count_part = idx & count_mask;
235 let new_work = if work_val < modulus {
236 (work_val as u128 * power as u128 % modulus as u128) as usize
237 } else {
238 work_val as usize };
240 let target = count_part | (new_work << counting_qubits);
241 new_amps[target] += *amp;
242 }
243 sv.amps = new_amps;
244 }
245
246 let counting_indices: Vec<usize> = (0..counting_qubits).collect();
248 qft_inverse_inplace(&mut sv, &counting_indices)?;
249
250 let dim_count = 1usize << counting_qubits;
252 let mut marg = vec![0.0f32; dim_count];
253 for (idx, amp) in sv.amps.iter().enumerate() {
254 marg[idx & count_mask] += amp.norm_sqr();
255 }
256
257 let mut measured = 0usize;
259 let mut best = f32::NEG_INFINITY;
260 for (i, &p) in marg.iter().enumerate() {
261 if p > best {
262 best = p;
263 measured = i;
264 }
265 }
266 let phase = measured as f64 / dim_count as f64;
267
268 let threshold = 0.5f32 / dim_count as f32; let mut peaks: Vec<(usize, f32)> = marg
276 .iter()
277 .enumerate()
278 .filter(|&(_, &p)| p > threshold)
279 .map(|(i, &p)| (i, p))
280 .collect();
281 peaks.sort_by(|a, b| {
282 b.1.partial_cmp(&a.1)
283 .unwrap_or(std::cmp::Ordering::Equal)
284 .then(a.0.cmp(&b.0))
285 });
286
287 let mut order = 0u64;
288 'scan: for &(idx, _) in &peaks {
289 if idx == 0 {
290 continue; }
292 let phi = idx as f64 / dim_count as f64;
293 for (_, q) in continued_fraction_convergents(phi, modulus) {
294 if q == 0 {
295 continue;
296 }
297 if mod_exp(a, q, modulus) == 1 {
298 order = q;
299 break 'scan;
300 }
301 }
302 }
303
304 Ok(OrderFindingResult {
305 order,
306 phase,
307 measured,
308 counting_qubits,
309 })
310}
311
312#[derive(Debug, Clone)]
314pub struct ShorResult {
315 pub factor: Option<u64>,
317 pub base: u64,
319 pub order: u64,
321}
322
323#[must_use]
329pub fn factor_from_order(base: u64, n: u64, r: u64) -> Option<u64> {
330 if r == 0 || !r.is_multiple_of(2) || n < 2 {
331 return None;
332 }
333 let half = mod_exp(base, r / 2, n);
334 if half == 1 || half == n - 1 {
335 return None;
336 }
337 [gcd(half + 1, n), gcd(half.wrapping_sub(1), n)]
338 .into_iter()
339 .find(|&candidate| candidate > 1 && candidate < n)
340}
341
342pub fn shor_factor(n: u64, bases: &[u64], counting_qubits: usize) -> QuantumResult<ShorResult> {
352 if n < 2 {
353 return Err(QuantumError::InvalidParameter {
354 name: format!("N {n} must be ≥ 2"),
355 });
356 }
357 if bases.is_empty() {
358 return Err(QuantumError::EmptyInput);
359 }
360 if n.is_multiple_of(2) {
361 return Ok(ShorResult {
362 factor: Some(2),
363 base: 2,
364 order: 0,
365 });
366 }
367 let mut last_base = bases[0];
368 for &a in bases {
369 let a = a % n;
370 if a < 2 {
371 continue;
372 }
373 last_base = a;
374 let g = gcd(a, n);
375 if g > 1 {
376 return Ok(ShorResult {
378 factor: Some(g),
379 base: a,
380 order: 0,
381 });
382 }
383 let of = order_finding(a, n, counting_qubits)?;
384 if of.order == 0 {
385 continue;
386 }
387 if let Some(factor) = factor_from_order(a, n, of.order) {
388 return Ok(ShorResult {
389 factor: Some(factor),
390 base: a,
391 order: of.order,
392 });
393 }
394 }
395 Ok(ShorResult {
396 factor: None,
397 base: last_base,
398 order: 0,
399 })
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405
406 #[test]
407 fn mod_exp_basic() {
408 assert_eq!(mod_exp(2, 10, 1000), 24); assert_eq!(mod_exp(7, 0, 13), 1);
410 assert_eq!(mod_exp(3, 3, 7), 6); }
412
413 #[test]
414 fn mod_exp_large_no_overflow() {
415 let m = (1u64 << 61) - 1;
417 let v = mod_exp(2, 62, m);
418 assert!(v < m);
419 assert_eq!(v, 2);
421 }
422
423 #[test]
424 fn gcd_basic() {
425 assert_eq!(gcd(54, 24), 6);
426 assert_eq!(gcd(17, 13), 1);
427 assert_eq!(gcd(0, 5), 5);
428 assert_eq!(gcd(8, 0), 8);
429 }
430
431 #[test]
432 fn continued_fraction_recovers_denominator() {
433 let cs = continued_fraction_convergents(0.25, 100);
435 assert!(cs.iter().any(|&(_, q)| q == 4), "convergents={cs:?}");
436 }
437
438 #[test]
439 fn continued_fraction_for_third() {
440 let cs = continued_fraction_convergents(1.0 / 3.0, 100);
441 assert!(cs.iter().any(|&(p, q)| p == 1 && q == 3), "cs={cs:?}");
442 }
443
444 #[test]
445 fn classical_order_matches_definition() {
446 assert_eq!(classical_order(2, 15), 4);
448 assert_eq!(classical_order(7, 15), 4);
450 assert_eq!(classical_order(6, 15), 0);
452 }
453
454 #[test]
455 fn order_finding_period_of_2_mod_15() {
456 let res = order_finding(2, 15, 8)
458 .expect("a=2 coprime to N=15, 8 counting qubits within valid range");
459 assert_eq!(
460 res.order, 4,
461 "phase={}, measured={}",
462 res.phase, res.measured
463 );
464 }
465
466 #[test]
467 fn order_finding_period_of_4_mod_15() {
468 let res = order_finding(4, 15, 8)
470 .expect("a=4 coprime to N=15, 8 counting qubits within valid range");
471 assert_eq!(res.order, 2);
472 }
473
474 #[test]
475 fn order_finding_period_of_2_mod_21() {
476 let res = order_finding(2, 21, 9)
478 .expect("a=2 coprime to N=21, 9 counting qubits within valid range");
479 assert!(res.order == 6 || (res.order > 0 && mod_exp(2, res.order, 21) == 1));
482 }
483
484 #[test]
485 fn order_finding_rejects_non_coprime() {
486 assert!(order_finding(3, 15, 6).is_err()); }
488
489 #[test]
490 fn order_finding_rejects_bad_modulus() {
491 assert!(order_finding(2, 1, 6).is_err());
492 assert!(order_finding(2, 15, 0).is_err());
493 }
494
495 #[test]
496 fn factor_from_order_factors_15() {
497 let f = factor_from_order(7, 15, 4)
499 .expect("order 4 of base 7 mod 15 is even and yields a non-trivial factor");
500 assert!(f == 3 || f == 5, "f={f}");
501 }
502
503 #[test]
504 fn factor_from_order_rejects_odd_order() {
505 assert_eq!(factor_from_order(2, 7, 3), None);
506 }
507
508 #[test]
509 fn shor_factor_even_shortcut() {
510 let res = shor_factor(8, &[3, 5, 7], 6)
511 .expect("N=8 is even so shor_factor short-circuits to factor 2");
512 assert_eq!(res.factor, Some(2));
513 }
514
515 #[test]
516 fn shor_factor_fifteen() {
517 let res = shor_factor(15, &[2, 7, 11, 13], 8)
519 .expect("N=15 with coprime bases and 8 counting qubits should succeed");
520 let f = res.factor.expect("should find a factor");
521 assert!(f == 3 || f == 5, "factor={f}");
522 assert_eq!(15 % f, 0);
523 }
524
525 #[test]
526 fn shor_factor_lucky_gcd() {
527 let res = shor_factor(15, &[5], 6)
529 .expect("base=5 shares factor 5 with N=15 so shor_factor succeeds immediately");
530 assert_eq!(res.factor, Some(5));
531 }
532
533 #[test]
534 fn shor_factor_empty_bases_errors() {
535 assert!(shor_factor(15, &[], 6).is_err());
536 }
537
538 #[test]
539 fn shor_factor_invalid_n_errors() {
540 assert!(shor_factor(1, &[2], 6).is_err());
541 }
542}