1use rayon::prelude::*;
60
61pub use ghz::*;
62pub use symbolic::*;
63pub use w_state::*;
64
65pub const BLOCK_SIZE: usize = 128;
69pub const BLOCK_SHIFT: usize = 7;
70
71#[derive(Clone, Copy, Debug)]
73pub struct VecBlock {
74 pub re: [f64; BLOCK_SIZE],
76 pub im: [f64; BLOCK_SIZE],
78}
79
80impl VecBlock {
81 #[inline]
83 pub fn new() -> Self {
84 Self {
85 re: [0.0; BLOCK_SIZE],
86 im: [0.0; BLOCK_SIZE],
87 }
88 }
89
90 #[inline]
92 pub fn set(&mut self, addr: usize, amp: Complex64) {
93 self.re[addr] = amp.re;
94 self.im[addr] = amp.im;
95 }
96
97 #[inline]
99 pub fn get(&self, addr: usize) -> Complex64 {
100 Complex64 {
101 re: self.re[addr],
102 im: self.im[addr],
103 }
104 }
105
106 pub fn is_zero(&self) -> bool {
108 self.re.iter().all(|&x| x == 0.0) && self.im.iter().all(|&x| x == 0.0)
109 }
110}
111
112impl Default for VecBlock {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118#[derive(Clone, Copy, Debug, Default)]
120pub struct Complex64 {
121 pub re: f64,
122 pub im: f64,
123}
124
125impl Complex64 {
126 #[inline]
127 pub fn new(re: f64, im: f64) -> Self {
128 Self { re, im }
129 }
130
131 #[inline]
132 pub fn zero() -> Self {
133 Self { re: 0.0, im: 0.0 }
134 }
135
136 #[inline]
137 pub fn norm_squared(&self) -> f64 {
138 self.re * self.re + self.im * self.im
139 }
140
141 #[inline]
142 pub fn norm(&self) -> f64 {
143 self.norm_squared().sqrt()
144 }
145}
146
147fn terminal_local_addr_for_usize(n_qubits: usize) -> usize {
148 assert!(n_qubits > 0, "GHZ state requires at least one qubit");
149
150 if n_qubits < BLOCK_SHIFT {
151 (1usize << n_qubits) - 1
152 } else {
153 BLOCK_SIZE - 1
154 }
155}
156
157fn terminal_local_addr_for_biguint(n_qubits: &num_bigint::BigUint) -> usize {
158 assert!(n_qubits.bits() > 0, "GHZ state requires at least one qubit");
159
160 let digits = n_qubits.to_u64_digits();
161 if digits.len() == 1 && digits[0] < BLOCK_SHIFT as u64 {
162 (1usize << digits[0] as usize) - 1
163 } else {
164 BLOCK_SIZE - 1
165 }
166}
167
168mod ghz {
169 use super::*;
175 use num_traits::identities::One;
176
177 #[derive(Clone)]
206 pub struct MinimalGhzState {
207 pub n_qubits: usize,
209 pub block_zero: VecBlock,
211 pub block_last: VecBlock,
213 pub creation_time_us: u64,
215 }
216
217 impl MinimalGhzState {
218 pub fn new(n_qubits: usize) -> Self {
233 assert!(n_qubits > 0, "GHZ state requires at least one qubit");
234
235 let start = std::time::Instant::now();
236
237 let inv_sqrt2 = std::f64::consts::FRAC_1_SQRT_2;
238 let terminal_addr = terminal_local_addr_for_usize(n_qubits);
239
240 let mut block_zero = VecBlock::new();
241 block_zero.set(0, Complex64::new(inv_sqrt2, 0.0));
242
243 let mut block_last = VecBlock::new();
244 block_last.set(terminal_addr, Complex64::new(inv_sqrt2, 0.0));
245
246 let creation_time_us = start.elapsed().as_micros() as u64;
247
248 Self {
249 n_qubits,
250 block_zero,
251 block_last,
252 creation_time_us,
253 }
254 }
255
256 pub fn verify(&self) -> MinimalGhzVerification {
270 let expected_amp = std::f64::consts::FRAC_1_SQRT_2;
271 let terminal_addr = terminal_local_addr_for_usize(self.n_qubits);
272
273 let amp0_complex = self.block_zero.get(0);
274 let amp_last_complex = self.block_last.get(terminal_addr);
275 let amp0 = amp0_complex.norm();
276 let amp_last = amp_last_complex.norm();
277
278 let overlap = Complex64::new(
279 expected_amp * (amp0_complex.re + amp_last_complex.re),
280 expected_amp * (amp0_complex.im + amp_last_complex.im),
281 );
282 let fidelity = overlap.norm_squared();
283
284 let mut max_spurious = 0.0f64;
285
286 for addr in 1..BLOCK_SIZE {
287 let mag = self.block_zero.get(addr).norm();
288 if mag > max_spurious {
289 max_spurious = mag;
290 }
291 }
292
293 for addr in 0..BLOCK_SIZE {
294 if addr == terminal_addr {
295 continue;
296 }
297
298 let mag = self.block_last.get(addr).norm();
299 if mag > max_spurious {
300 max_spurious = mag;
301 }
302 }
303
304 MinimalGhzVerification {
305 n_qubits: self.n_qubits,
306 amp_zero_state: amp0,
307 amp_one_state: amp_last,
308 expected_amplitude: expected_amp,
309 fidelity,
310 max_spurious,
311 }
312 }
313
314 pub fn memory_bytes(&self) -> usize {
316 std::mem::size_of::<Self>()
317 }
318
319 pub fn n_qubits(&self) -> usize {
321 self.n_qubits
322 }
323
324 pub fn creation_time_us(&self) -> u64 {
326 self.creation_time_us
327 }
328 }
329
330 impl std::fmt::Display for MinimalGhzState {
331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 let label = if self.n_qubits >= 1_000_000_000_000 {
333 format!("{:.1}T", self.n_qubits as f64 / 1e12)
334 } else if self.n_qubits >= 1_000_000_000 {
335 format!("{:.1}B", self.n_qubits as f64 / 1e9)
336 } else if self.n_qubits >= 1_000_000 {
337 format!("{:.1}M", self.n_qubits as f64 / 1e6)
338 } else if self.n_qubits >= 1_000 {
339 format!("{:.1}K", self.n_qubits as f64 / 1e3)
340 } else {
341 format!("{}", self.n_qubits)
342 };
343 write!(f, "|GHZ_{}>", label)
344 }
345 }
346
347 #[derive(Debug, Clone)]
349 pub struct MinimalGhzVerification {
350 pub n_qubits: usize,
351 pub amp_zero_state: f64,
352 pub amp_one_state: f64,
353 pub expected_amplitude: f64,
354 pub fidelity: f64,
355 pub max_spurious: f64,
356 }
357
358 impl std::fmt::Display for MinimalGhzVerification {
359 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360 writeln!(
361 f,
362 "Minimal GHZ Verification ({} qubits) [O(1) — NO BIGINT]",
363 self.n_qubits
364 )?;
365 writeln!(
366 f,
367 " |00...0> amplitude: {:.6} (expected {:.6})",
368 self.amp_zero_state, self.expected_amplitude
369 )?;
370 writeln!(
371 f,
372 " |11...1> amplitude: {:.6} (expected {:.6})",
373 self.amp_one_state, self.expected_amplitude
374 )?;
375 writeln!(f, " Fidelity: {:.6}", self.fidelity)?;
376 writeln!(f, " Max spurious: {:.6}", self.max_spurious)?;
377 Ok(())
378 }
379 }
380
381 pub fn create_minimal_ghz(n_qubits: usize) -> MinimalGhzState {
393 MinimalGhzState::new(n_qubits)
394 }
395
396 #[derive(Clone)]
418 pub struct UnlimitedGhzState {
419 pub n_qubits: num_bigint::BigUint,
421 pub block_zero: VecBlock,
423 pub block_last: VecBlock,
425 pub creation_time_us: u64,
427 }
428
429 impl UnlimitedGhzState {
430 pub fn new(n_qubits: num_bigint::BigUint) -> Self {
445 assert!(n_qubits.bits() > 0, "GHZ state requires at least one qubit");
446
447 let start = std::time::Instant::now();
448
449 let inv_sqrt2 = std::f64::consts::FRAC_1_SQRT_2;
450 let terminal_addr = terminal_local_addr_for_biguint(&n_qubits);
451
452 let mut block_zero = VecBlock::new();
453 block_zero.set(0, Complex64::new(inv_sqrt2, 0.0));
454
455 let mut block_last = VecBlock::new();
456 block_last.set(terminal_addr, Complex64::new(inv_sqrt2, 0.0));
457
458 let creation_time_us = start.elapsed().as_micros() as u64;
459
460 Self {
461 n_qubits,
462 block_zero,
463 block_last,
464 creation_time_us,
465 }
466 }
467
468 pub fn from_power_of_10(exponent: u32) -> Self {
480 let n_qubits = num_bigint::BigUint::from(10u32).pow(exponent);
481 Self::new(n_qubits)
482 }
483
484 pub fn from_power_of_2(exponent: u32) -> Self {
496 let n_qubits = num_bigint::BigUint::one() << exponent;
497 Self::new(n_qubits)
498 }
499
500 pub fn verify(&self) -> UnlimitedGhzVerification {
502 let expected_amp = std::f64::consts::FRAC_1_SQRT_2;
503 let terminal_addr = terminal_local_addr_for_biguint(&self.n_qubits);
504
505 let amp0_complex = self.block_zero.get(0);
506 let amp_last_complex = self.block_last.get(terminal_addr);
507 let amp0 = amp0_complex.norm();
508 let amp_last = amp_last_complex.norm();
509
510 let overlap = Complex64::new(
511 expected_amp * (amp0_complex.re + amp_last_complex.re),
512 expected_amp * (amp0_complex.im + amp_last_complex.im),
513 );
514 let fidelity = overlap.norm_squared();
515
516 let mut max_spurious = 0.0f64;
517
518 for addr in 1..BLOCK_SIZE {
519 let mag = self.block_zero.get(addr).norm();
520 if mag > max_spurious {
521 max_spurious = mag;
522 }
523 }
524
525 for addr in 0..BLOCK_SIZE {
526 if addr == terminal_addr {
527 continue;
528 }
529
530 let mag = self.block_last.get(addr).norm();
531 if mag > max_spurious {
532 max_spurious = mag;
533 }
534 }
535
536 UnlimitedGhzVerification {
537 n_qubits: self.n_qubits.clone(),
538 amp_zero_state: amp0,
539 amp_one_state: amp_last,
540 expected_amplitude: expected_amp,
541 fidelity,
542 max_spurious,
543 }
544 }
545
546 pub fn memory_bytes(&self) -> usize {
548 std::mem::size_of::<VecBlock>() * 2 + self.n_qubits.to_bytes_le().len()
549 }
550
551 pub fn n_qubits(&self) -> &num_bigint::BigUint {
553 &self.n_qubits
554 }
555
556 pub fn log10_qubits(&self) -> f64 {
558 let bits = self.n_qubits.bits();
559 bits as f64 * 0.30103 }
561
562 pub fn state_space_description(&self) -> String {
564 format!("2^{} amplitudes", self.n_qubits)
565 }
566 }
567
568 impl std::fmt::Display for UnlimitedGhzState {
569 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
570 let bits = self.n_qubits.bits();
571 if bits > 1000 {
572 write!(f, "|GHZ_(~10^{:.0})>", bits as f64 * 0.30103)
573 } else if bits > 100 {
574 write!(f, "|GHZ_(2^{})>", bits)
575 } else {
576 write!(f, "|GHZ_{}>", self.n_qubits)
577 }
578 }
579 }
580
581 #[derive(Debug, Clone)]
583 pub struct UnlimitedGhzVerification {
584 pub n_qubits: num_bigint::BigUint,
585 pub amp_zero_state: f64,
586 pub amp_one_state: f64,
587 pub expected_amplitude: f64,
588 pub fidelity: f64,
589 pub max_spurious: f64,
590 }
591
592 impl std::fmt::Display for UnlimitedGhzVerification {
593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
594 let bits = self.n_qubits.bits();
595 let log10 = bits as f64 * 0.30103;
596
597 writeln!(f, "BigUint GHZ Verification [endpoint representation]")?;
598 if bits > 1000 {
599 writeln!(
600 f,
601 " Qubits: ~10^{:.0} (~2^{} bits to represent)",
602 log10, bits
603 )?;
604 } else {
605 writeln!(f, " Qubits: {} ({} bits)", self.n_qubits, bits)?;
606 }
607 writeln!(
608 f,
609 " |00...0> amplitude: {:.6} (expected {:.6})",
610 self.amp_zero_state, self.expected_amplitude
611 )?;
612 writeln!(
613 f,
614 " |11...1> amplitude: {:.6} (expected {:.6})",
615 self.amp_one_state, self.expected_amplitude
616 )?;
617 writeln!(f, " Fidelity: {:.6}", self.fidelity)?;
618 writeln!(f, " Max spurious: {:.6}", self.max_spurious)?;
619 writeln!(f, " State space: 2^(10^{:.0}) amplitudes", log10)?;
620 Ok(())
621 }
622 }
623
624 pub fn create_unlimited_ghz(n_qubits: num_bigint::BigUint) -> UnlimitedGhzState {
637 UnlimitedGhzState::new(n_qubits)
638 }
639
640 pub fn create_ghz_power_of_10(exponent: u32) -> UnlimitedGhzState {
651 UnlimitedGhzState::from_power_of_10(exponent)
652 }
653}
654
655mod w_state {
656 use super::*;
662
663 const W_AMPLITUDE_TOLERANCE: f64 = 1e-12;
664
665 #[derive(Debug, Clone)]
667 pub struct WStateVerificationVec {
668 pub n_qubits: usize,
669 pub expected_amplitudes: usize,
670 pub correct_amplitudes: usize,
671 pub expected_amplitude: f64,
672 pub total_probability: f64,
673 pub fidelity: f64,
674 pub max_amplitude_error: f64,
675 pub max_spurious_amplitude: f64,
676 pub active_blocks: usize,
677 pub memory_bytes: usize,
678 }
679
680 #[derive(Clone)]
706 pub struct SparseQuantumGridVec {
707 n_qubits: usize,
708 n_blocks: usize,
709 blocks: Vec<VecBlock>,
710 }
711
712 impl SparseQuantumGridVec {
713 pub fn new(n_qubits: usize) -> Self {
731 assert!(n_qubits >= 7, "Minimum 7 qubits required");
732 let n_blocks = (n_qubits + BLOCK_SIZE - 1) / BLOCK_SIZE;
733
734 Self {
735 n_qubits,
736 n_blocks,
737 blocks: vec![VecBlock::new(); n_blocks],
738 }
739 }
740
741 pub fn new_lazy(n_qubits: usize) -> Self {
745 assert!(n_qubits >= 7, "Minimum 7 qubits required");
746 let n_blocks = (n_qubits + BLOCK_SIZE - 1) / BLOCK_SIZE;
747
748 Self {
749 n_qubits,
750 n_blocks,
751 blocks: Vec::with_capacity(n_blocks),
752 }
753 }
754
755 #[inline]
757 pub fn n_qubits(&self) -> usize {
758 self.n_qubits
759 }
760
761 #[inline]
763 pub fn n_blocks(&self) -> usize {
764 self.n_blocks
765 }
766
767 #[inline]
769 pub fn allocated_blocks(&self) -> usize {
770 self.blocks.len()
771 }
772
773 pub fn memory_bytes(&self) -> usize {
775 self.blocks.len() * std::mem::size_of::<VecBlock>()
776 }
777
778 fn max_spurious_tail_amplitude(&self) -> f64 {
779 let mut max_spurious = 0.0f64;
780 let total_slots = self.blocks.len() * BLOCK_SIZE;
781
782 for slot in self.n_qubits..total_slots {
783 let block_idx = slot / BLOCK_SIZE;
784 let local_addr = slot % BLOCK_SIZE;
785 let mag = self.blocks[block_idx].get(local_addr).norm();
786 if mag > max_spurious {
787 max_spurious = mag;
788 }
789 }
790
791 max_spurious
792 }
793
794 pub fn clear(&mut self) {
796 for block in &mut self.blocks {
797 block.re.fill(0.0);
798 block.im.fill(0.0);
799 }
800 }
801
802 fn ensure_blocks(&mut self, count: usize) {
804 while self.blocks.len() < count {
805 self.blocks.push(VecBlock::new());
806 }
807 }
808
809 pub fn create_w_state(&mut self) -> u64 {
823 let start = std::time::Instant::now();
824
825 self.ensure_blocks(self.n_blocks);
826 self.clear();
827
828 let amplitude = 1.0 / (self.n_qubits as f64).sqrt();
829 let amp = Complex64::new(amplitude, 0.0);
830
831 for qubit in 0..self.n_qubits {
832 let block_idx = qubit / BLOCK_SIZE;
833 let local_addr = qubit % BLOCK_SIZE;
834 self.blocks[block_idx].set(local_addr, amp);
835 }
836
837 start.elapsed().as_micros() as u64
838 }
839
840 pub fn create_w_state_parallel(&mut self) -> u64 {
842 let start = std::time::Instant::now();
843
844 self.ensure_blocks(self.n_blocks);
845
846 let amplitude = 1.0 / (self.n_qubits as f64).sqrt();
847 let n_qubits = self.n_qubits;
848
849 self.blocks
850 .par_iter_mut()
851 .enumerate()
852 .for_each(|(block_idx, block)| {
853 block.re.fill(0.0);
854 block.im.fill(0.0);
855
856 let start_qubit = block_idx * BLOCK_SIZE;
857 let end_qubit = (start_qubit + BLOCK_SIZE).min(n_qubits);
858
859 for qubit in start_qubit..end_qubit {
860 let local_addr = qubit % BLOCK_SIZE;
861 block.re[local_addr] = amplitude;
862 }
863 });
864
865 start.elapsed().as_micros() as u64
866 }
867
868 pub fn verify_w_fidelity(&self) -> WStateVerificationVec {
882 let expected_amp = 1.0 / (self.n_qubits as f64).sqrt();
883
884 let mut total_prob = 0.0;
885 let mut overlap_re = 0.0;
886 let mut overlap_im = 0.0;
887 let mut correct_amplitudes = 0usize;
888 let mut max_error = 0.0f64;
889
890 for qubit in 0..self.n_qubits {
891 let block_idx = qubit / BLOCK_SIZE;
892 let local_addr = qubit % BLOCK_SIZE;
893
894 if block_idx < self.blocks.len() {
895 let amp = self.blocks[block_idx].get(local_addr);
896 let prob = amp.norm_squared();
897 total_prob += prob;
898 overlap_re += expected_amp * amp.re;
899 overlap_im += expected_amp * amp.im;
900
901 let error = ((amp.re - expected_amp).powi(2) + amp.im.powi(2)).sqrt();
902 if error <= W_AMPLITUDE_TOLERANCE {
903 correct_amplitudes += 1;
904 }
905 if error > max_error {
906 max_error = error;
907 }
908 }
909 }
910
911 WStateVerificationVec {
912 n_qubits: self.n_qubits,
913 expected_amplitudes: self.n_qubits,
914 correct_amplitudes,
915 expected_amplitude: expected_amp,
916 total_probability: total_prob,
917 fidelity: overlap_re.powi(2) + overlap_im.powi(2),
918 max_amplitude_error: max_error,
919 max_spurious_amplitude: self.max_spurious_tail_amplitude(),
920 active_blocks: self.blocks.len(),
921 memory_bytes: self.memory_bytes(),
922 }
923 }
924
925 pub fn verify_w_fidelity_parallel(&self) -> WStateVerificationVec {
927 let expected_amp = 1.0 / (self.n_qubits as f64).sqrt();
928 let n_qubits = self.n_qubits;
929
930 let (total_prob, correct_amplitudes, max_error, overlap_re, overlap_im) = self
931 .blocks
932 .par_iter()
933 .enumerate()
934 .map(|(block_idx, block): (usize, &VecBlock)| {
935 let start_qubit = block_idx * BLOCK_SIZE;
936 let end_qubit = (start_qubit + BLOCK_SIZE).min(n_qubits);
937
938 let mut block_prob = 0.0;
939 let mut block_correct = 0usize;
940 let mut block_max_error = 0.0f64;
941 let mut block_overlap_re = 0.0;
942 let mut block_overlap_im = 0.0;
943
944 for qubit in start_qubit..end_qubit {
945 let local_addr = qubit % BLOCK_SIZE;
946 let amp = block.get(local_addr);
947 let prob = amp.norm_squared();
948 block_prob += prob;
949 block_overlap_re += expected_amp * amp.re;
950 block_overlap_im += expected_amp * amp.im;
951
952 let error = ((amp.re - expected_amp).powi(2) + amp.im.powi(2)).sqrt();
953 if error <= W_AMPLITUDE_TOLERANCE {
954 block_correct += 1;
955 }
956 if error > block_max_error {
957 block_max_error = error;
958 }
959 }
960
961 (
962 block_prob,
963 block_correct,
964 block_max_error,
965 block_overlap_re,
966 block_overlap_im,
967 )
968 })
969 .reduce(
970 || (0.0, 0usize, 0.0f64, 0.0, 0.0),
971 |(p1, c1, e1, r1, i1), (p2, c2, e2, r2, i2)| {
972 (p1 + p2, c1 + c2, e1.max(e2), r1 + r2, i1 + i2)
973 },
974 );
975
976 WStateVerificationVec {
977 n_qubits: self.n_qubits,
978 expected_amplitudes: self.n_qubits,
979 correct_amplitudes,
980 expected_amplitude: expected_amp,
981 total_probability: total_prob,
982 fidelity: overlap_re.powi(2) + overlap_im.powi(2),
983 max_amplitude_error: max_error,
984 max_spurious_amplitude: self.max_spurious_tail_amplitude(),
985 active_blocks: self.blocks.len(),
986 memory_bytes: self.memory_bytes(),
987 }
988 }
989
990 #[inline]
992 pub fn get_amplitude(&self, qubit: usize) -> Complex64 {
993 let block_idx = qubit / BLOCK_SIZE;
994 let local_addr = qubit % BLOCK_SIZE;
995
996 if block_idx < self.blocks.len() {
997 self.blocks[block_idx].get(local_addr)
998 } else {
999 Complex64::zero()
1000 }
1001 }
1002
1003 #[inline]
1005 pub fn set_amplitude(&mut self, qubit: usize, amp: Complex64) {
1006 let block_idx = qubit / BLOCK_SIZE;
1007 let local_addr = qubit % BLOCK_SIZE;
1008
1009 self.ensure_blocks(block_idx + 1);
1010 self.blocks[block_idx].set(local_addr, amp);
1011 }
1012 }
1013}
1014
1015mod symbolic {
1016 use super::*;
1025
1026 #[derive(Clone, Debug)]
1033 pub enum SymbolicNumber {
1034 Literal(u64),
1036 Big(num_bigint::BigUint),
1038 Pow {
1040 base: u64,
1041 exponent: Box<SymbolicNumber>,
1042 },
1043 Tetration {
1045 base: u64,
1046 height: Box<SymbolicNumber>,
1047 },
1048 KnuthArrow {
1050 a: u64,
1051 arrows: u64,
1052 b: Box<SymbolicNumber>,
1053 },
1054 Graham,
1056 Tree(u64),
1058 Rayo,
1060 Infinity,
1062 Named { name: String, description: String },
1064 Div {
1066 numerator: Box<SymbolicNumber>,
1067 denominator: Box<SymbolicNumber>,
1068 },
1069 Sub {
1071 minuend: Box<SymbolicNumber>,
1072 subtrahend: Box<SymbolicNumber>,
1073 },
1074 }
1075
1076 impl SymbolicNumber {
1077 pub fn to_notation(&self) -> String {
1079 match self {
1080 Self::Literal(n) => format!("{}", n),
1081 Self::Big(n) => {
1082 let bits = n.bits();
1083 if bits > 1000 {
1084 format!("~10^{:.0}", bits as f64 * 0.30103)
1085 } else {
1086 format!("{}", n)
1087 }
1088 }
1089 Self::Pow { base, exponent } => {
1090 format!("{}^({})", base, exponent.to_notation())
1091 }
1092 Self::Tetration { base, height } => {
1093 format!("{}^^{}", base, height.to_notation())
1094 }
1095 Self::KnuthArrow { a, arrows, b } => {
1096 let arrow_str: String = std::iter::repeat('↑').take(*arrows as usize).collect();
1097 format!("{}{}{}", a, arrow_str, b.to_notation())
1098 }
1099 Self::Graham => "G (Graham's number)".to_string(),
1100 Self::Tree(n) => format!("TREE({})", n),
1101 Self::Rayo => "Rayo's number".to_string(),
1102 Self::Infinity => "infty".to_string(),
1103 Self::Named { name, .. } => name.clone(),
1104 Self::Div {
1105 numerator,
1106 denominator,
1107 } => {
1108 format!(
1109 "({}/{})",
1110 numerator.to_notation(),
1111 denominator.to_notation()
1112 )
1113 }
1114 Self::Sub {
1115 minuend,
1116 subtrahend,
1117 } => {
1118 format!("({}-{})", minuend.to_notation(), subtrahend.to_notation())
1119 }
1120 }
1121 }
1122
1123 pub fn size_class(&self) -> &'static str {
1125 match self {
1126 Self::Literal(n) if *n < 1_000_000 => "small",
1127 Self::Literal(_) => "large",
1128 Self::Big(n) if n.bits() < 1000 => "astronomical",
1129 Self::Big(_) => "cosmological",
1130 Self::Pow { .. } => "cosmological",
1131 Self::Tetration { .. } => "tetration",
1132 Self::KnuthArrow { arrows, .. } if *arrows <= 2 => "tetration",
1133 Self::KnuthArrow { arrows, .. } if *arrows <= 4 => "pentation+",
1134 Self::KnuthArrow { .. } => "arrow-notation",
1135 Self::Graham => "Graham-class",
1136 Self::Tree(_) => "TREE-class",
1137 Self::Rayo => "uncomputable",
1138 Self::Infinity => "infinite",
1139 Self::Named { .. } => "named",
1140 Self::Div { numerator, .. } => numerator.size_class(),
1141 Self::Sub { minuend, .. } => minuend.size_class(),
1142 }
1143 }
1144
1145 pub fn is_zero(&self) -> bool {
1147 match self {
1148 Self::Literal(0) => true,
1149 Self::Big(n) => n == &num_bigint::BigUint::from(0u32),
1150 _ => false,
1151 }
1152 }
1153
1154 pub fn structurally_equal(&self, other: &Self) -> bool {
1156 match (self, other) {
1157 (Self::Literal(a), Self::Literal(b)) => a == b,
1158 (Self::Big(a), Self::Big(b)) => a == b,
1159 (Self::Graham, Self::Graham) => true,
1160 (Self::Tree(a), Self::Tree(b)) => a == b,
1161 (Self::Infinity, Self::Infinity) => true,
1162 (Self::Rayo, Self::Rayo) => true,
1163 _ => false,
1164 }
1165 }
1166
1167 pub fn estimate_log10(&self) -> Option<f64> {
1169 match self {
1170 Self::Literal(n) => Some((*n as f64).log10()),
1171 Self::Big(n) => Some(n.bits() as f64 * 0.30103),
1172 Self::Pow { base, exponent } => {
1173 let exp_log = exponent.estimate_log10()?;
1174 Some(10f64.powf(exp_log) * (*base as f64).log10())
1175 }
1176 Self::Div {
1177 numerator,
1178 denominator,
1179 } => {
1180 let num_log = numerator.estimate_log10()?;
1181 let denom_log = denominator.estimate_log10()?;
1182 Some(num_log - denom_log)
1183 }
1184 Self::Sub {
1185 minuend,
1186 subtrahend,
1187 } => {
1188 let minuend_log = minuend.estimate_log10()?;
1189 let subtrahend_log = subtrahend.estimate_log10()?;
1190 if minuend_log > subtrahend_log + 1.0 {
1191 Some(minuend_log)
1192 } else {
1193 None
1194 }
1195 }
1196 _ => None,
1197 }
1198 }
1199
1200 pub fn is_materializable(&self) -> bool {
1202 match self {
1203 Self::Literal(_) => true,
1204 Self::Big(_) => true,
1205 Self::Pow { exponent, .. } => match exponent.as_ref() {
1206 SymbolicNumber::Literal(e) => *e < 100_000_000,
1207 _ => false,
1208 },
1209 Self::Div {
1210 numerator,
1211 denominator,
1212 } => numerator.is_materializable() && denominator.is_materializable(),
1213 Self::Sub {
1214 minuend,
1215 subtrahend,
1216 } => minuend.is_materializable() && subtrahend.is_materializable(),
1217 _ => false,
1218 }
1219 }
1220 }
1221
1222 impl std::fmt::Display for SymbolicNumber {
1223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1224 write!(f, "{}", self.to_notation())
1225 }
1226 }
1227
1228 fn terminal_local_addr_for_symbolic_number(n_qubits: &SymbolicNumber) -> usize {
1229 assert!(!n_qubits.is_zero(), "GHZ state requires at least one qubit");
1230
1231 match n_qubits {
1232 SymbolicNumber::Literal(n) if *n < BLOCK_SHIFT as u64 => (1usize << *n as usize) - 1,
1233 SymbolicNumber::Big(n) => terminal_local_addr_for_biguint(n),
1234 _ => BLOCK_SIZE - 1,
1235 }
1236 }
1237
1238 #[derive(Clone)]
1266 pub struct SymbolicGhzState {
1267 pub n_qubits: SymbolicNumber,
1269 pub block_zero: VecBlock,
1271 pub block_last: VecBlock,
1273 pub creation_time_ns: u64,
1275 }
1276
1277 impl SymbolicGhzState {
1278 pub fn new(n_qubits: SymbolicNumber) -> Self {
1293 assert!(!n_qubits.is_zero(), "GHZ state requires at least one qubit");
1294
1295 let start = std::time::Instant::now();
1296
1297 let inv_sqrt2 = std::f64::consts::FRAC_1_SQRT_2;
1298 let terminal_addr = terminal_local_addr_for_symbolic_number(&n_qubits);
1299
1300 let mut block_zero = VecBlock::new();
1301 block_zero.set(0, Complex64::new(inv_sqrt2, 0.0));
1302
1303 let mut block_last = VecBlock::new();
1304 block_last.set(terminal_addr, Complex64::new(inv_sqrt2, 0.0));
1305
1306 let creation_time_ns = start.elapsed().as_nanos() as u64;
1307
1308 Self {
1309 n_qubits,
1310 block_zero,
1311 block_last,
1312 creation_time_ns,
1313 }
1314 }
1315
1316 pub fn graham() -> Self {
1327 Self::new(SymbolicNumber::Graham)
1328 }
1329
1330 pub fn tree(n: u64) -> Self {
1332 Self::new(SymbolicNumber::Tree(n))
1333 }
1334
1335 pub fn infinite() -> Self {
1337 Self::new(SymbolicNumber::Infinity)
1338 }
1339
1340 pub fn knuth_arrow(a: u64, arrows: u64, b: u64) -> Self {
1342 Self::new(SymbolicNumber::KnuthArrow {
1343 a,
1344 arrows,
1345 b: Box::new(SymbolicNumber::Literal(b)),
1346 })
1347 }
1348
1349 pub fn tetration(base: u64, height: u64) -> Self {
1351 Self::new(SymbolicNumber::Tetration {
1352 base,
1353 height: Box::new(SymbolicNumber::Literal(height)),
1354 })
1355 }
1356
1357 pub fn verify(&self) -> SymbolicGhzVerification {
1371 let expected_amp = std::f64::consts::FRAC_1_SQRT_2;
1372 let terminal_addr = terminal_local_addr_for_symbolic_number(&self.n_qubits);
1373
1374 let amp0_complex = self.block_zero.get(0);
1375 let amp_last_complex = self.block_last.get(terminal_addr);
1376 let amp0 = amp0_complex.norm();
1377 let amp_last = amp_last_complex.norm();
1378
1379 let overlap = Complex64::new(
1380 expected_amp * (amp0_complex.re + amp_last_complex.re),
1381 expected_amp * (amp0_complex.im + amp_last_complex.im),
1382 );
1383 let fidelity = overlap.norm_squared();
1384
1385 let mut max_spurious = 0.0f64;
1386
1387 for addr in 1..BLOCK_SIZE {
1388 let mag = self.block_zero.get(addr).norm();
1389 if mag > max_spurious {
1390 max_spurious = mag;
1391 }
1392 }
1393
1394 for addr in 0..BLOCK_SIZE {
1395 if addr == terminal_addr {
1396 continue;
1397 }
1398
1399 let mag = self.block_last.get(addr).norm();
1400 if mag > max_spurious {
1401 max_spurious = mag;
1402 }
1403 }
1404
1405 SymbolicGhzVerification {
1406 n_qubits: self.n_qubits.clone(),
1407 amp_zero_state: amp0,
1408 amp_one_state: amp_last,
1409 expected_amplitude: expected_amp,
1410 fidelity,
1411 max_spurious,
1412 size_class: self.n_qubits.size_class().to_string(),
1413 }
1414 }
1415
1416 pub fn memory_bytes(&self) -> usize {
1418 std::mem::size_of::<Self>()
1419 }
1420 }
1421
1422 impl std::fmt::Display for SymbolicGhzState {
1423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1424 write!(f, "|GHZ_({})>", self.n_qubits)
1425 }
1426 }
1427
1428 #[derive(Debug, Clone)]
1430 pub struct SymbolicGhzVerification {
1431 pub n_qubits: SymbolicNumber,
1432 pub amp_zero_state: f64,
1433 pub amp_one_state: f64,
1434 pub expected_amplitude: f64,
1435 pub fidelity: f64,
1436 pub max_spurious: f64,
1437 pub size_class: String,
1438 }
1439
1440 impl std::fmt::Display for SymbolicGhzVerification {
1441 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1442 writeln!(f, "Symbolic GHZ Verification [{}]", self.size_class)?;
1443 writeln!(f, " Qubits: {}", self.n_qubits)?;
1444 writeln!(
1445 f,
1446 " |00...0> amplitude: {:.6} (expected {:.6})",
1447 self.amp_zero_state, self.expected_amplitude
1448 )?;
1449 writeln!(
1450 f,
1451 " |11...1> amplitude: {:.6} (expected {:.6})",
1452 self.amp_one_state, self.expected_amplitude
1453 )?;
1454 writeln!(f, " Fidelity: {:.6}", self.fidelity)?;
1455 writeln!(f, " Max spurious: {:.6}", self.max_spurious)?;
1456
1457 match &self.n_qubits {
1458 SymbolicNumber::Graham => {
1459 writeln!(f, " ")?;
1460 writeln!(f, " Graham's number is so large that:")?;
1461 writeln!(f, " - It cannot be written in standard notation")?;
1462 writeln!(f, " - Even the NUMBER OF DIGITS cannot be written")?;
1463 writeln!(f, " - It requires Knuth's up-arrow notation")?;
1464 writeln!(f, " - g_64 where g_1 = 3↑↑↑↑3, g_n = 3↑^(g_{{n-1}})3")?;
1465 }
1466 SymbolicNumber::Tree(n) => {
1467 writeln!(f, " ")?;
1468 writeln!(f, " TREE({}) grows faster than Graham's number!", n)?;
1469 writeln!(f, " - TREE(1) = 1")?;
1470 writeln!(f, " - TREE(2) = 3")?;
1471 writeln!(f, " - TREE(3) > g_64 (Graham's number)")?;
1472 }
1473 SymbolicNumber::Infinity => {
1474 writeln!(f, " ")?;
1475 writeln!(f, " Formal infinity label (aleph_0).")?;
1476 writeln!(
1477 f,
1478 " This is a symbolic endpoint object, not an analytic infinite-Hilbert-space model."
1479 )?;
1480 }
1481 _ => {}
1482 }
1483
1484 Ok(())
1485 }
1486 }
1487
1488 pub fn create_graham_ghz() -> SymbolicGhzState {
1490 SymbolicGhzState::graham()
1491 }
1492
1493 pub fn create_tree_ghz(n: u64) -> SymbolicGhzState {
1495 SymbolicGhzState::tree(n)
1496 }
1497
1498 pub fn create_infinite_ghz() -> SymbolicGhzState {
1500 SymbolicGhzState::infinite()
1501 }
1502
1503 pub fn create_symbolic_ghz(n_qubits: SymbolicNumber) -> SymbolicGhzState {
1505 SymbolicGhzState::new(n_qubits)
1506 }
1507
1508 #[derive(Clone, Debug)]
1516 pub enum SymbolicAmplitude {
1517 Real(f64),
1519 ReciprocalSqrt(SymbolicNumber),
1521 ReciprocalSqrtBinomial(SymbolicBinomial),
1523 SqrtFraction {
1525 numerator: SymbolicNumber,
1526 denominator: SymbolicNumber,
1527 },
1528 Product(Vec<SymbolicAmplitude>),
1530 Zero,
1532 }
1533
1534 impl SymbolicAmplitude {
1535 pub fn reciprocal_sqrt(n: SymbolicNumber) -> Self {
1537 Self::ReciprocalSqrt(n)
1538 }
1539
1540 pub fn sqrt_fraction(numerator: SymbolicNumber, denominator: SymbolicNumber) -> Self {
1542 Self::SqrtFraction {
1543 numerator,
1544 denominator,
1545 }
1546 }
1547
1548 pub fn magnitude_squared_symbolic(&self) -> Option<SymbolicFraction> {
1550 match self {
1551 Self::Real(r) => Some(SymbolicFraction {
1552 numerator: SymbolicNumber::Big(num_bigint::BigUint::from(
1553 (r * r * 1e15) as u64,
1554 )),
1555 denominator: SymbolicNumber::Big(num_bigint::BigUint::from(
1556 1_000_000_000_000_000u64,
1557 )),
1558 }),
1559 Self::ReciprocalSqrt(n) => Some(SymbolicFraction::one_over(n.clone())),
1560 Self::ReciprocalSqrtBinomial(binom) => Some(SymbolicFraction {
1561 numerator: SymbolicNumber::Literal(1),
1562 denominator: SymbolicNumber::Named {
1563 name: binom.to_notation(),
1564 description: format!("Binomial coefficient {}", binom.to_notation()),
1565 },
1566 }),
1567 Self::SqrtFraction {
1568 numerator,
1569 denominator,
1570 } => Some(SymbolicFraction {
1571 numerator: numerator.clone(),
1572 denominator: denominator.clone(),
1573 }),
1574 Self::Zero => Some(SymbolicFraction {
1575 numerator: SymbolicNumber::Literal(0),
1576 denominator: SymbolicNumber::Literal(1),
1577 }),
1578 Self::Product(factors) => {
1579 if factors.len() == 1 {
1580 factors[0].magnitude_squared_symbolic()
1581 } else {
1582 None
1583 }
1584 }
1585 }
1586 }
1587
1588 pub fn try_evaluate(&self) -> Option<f64> {
1600 match self {
1601 Self::Real(r) => Some(*r),
1602 Self::ReciprocalSqrt(n) => match n {
1603 SymbolicNumber::Literal(lit) => Some(1.0 / (*lit as f64).sqrt()),
1604 SymbolicNumber::Big(big) => {
1605 if big.bits() < 53 {
1606 let val: u64 = big.try_into().ok()?;
1607 Some(1.0 / (val as f64).sqrt())
1608 } else {
1609 None
1610 }
1611 }
1612 _ => None,
1613 },
1614 Self::ReciprocalSqrtBinomial(binom) => {
1615 let binom_val = binom.try_evaluate()?;
1616 if binom_val == 0 {
1617 return None;
1618 }
1619 Some(1.0 / (binom_val as f64).sqrt())
1620 }
1621 Self::SqrtFraction {
1622 numerator,
1623 denominator,
1624 } => {
1625 let num = match numerator {
1626 SymbolicNumber::Literal(n) => *n as f64,
1627 _ => return None,
1628 };
1629 let denom = match denominator {
1630 SymbolicNumber::Literal(d) => *d as f64,
1631 _ => return None,
1632 };
1633 Some((num / denom).sqrt())
1634 }
1635 Self::Zero => Some(0.0),
1636 Self::Product(factors) => {
1637 let mut result = 1.0;
1638 for factor in factors {
1639 result *= factor.try_evaluate()?;
1640 }
1641 Some(result)
1642 }
1643 }
1644 }
1645
1646 pub fn to_notation(&self) -> String {
1648 match self {
1649 Self::Real(r) => format!("{:.6}", r),
1650 Self::ReciprocalSqrt(n) => format!("1/sqrt({})", n.to_notation()),
1651 Self::ReciprocalSqrtBinomial(binom) => format!("1/sqrt{}", binom.to_notation()),
1652 Self::SqrtFraction {
1653 numerator,
1654 denominator,
1655 } => format!(
1656 "sqrt({}/{})",
1657 numerator.to_notation(),
1658 denominator.to_notation()
1659 ),
1660 Self::Zero => "0".to_string(),
1661 Self::Product(factors) => {
1662 let parts: Vec<String> = factors.iter().map(|f| f.to_notation()).collect();
1663 parts.join(" x ")
1664 }
1665 }
1666 }
1667 }
1668
1669 impl std::fmt::Display for SymbolicAmplitude {
1670 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1671 write!(f, "{}", self.to_notation())
1672 }
1673 }
1674
1675 #[derive(Clone, Debug)]
1681 pub struct SymbolicFraction {
1682 pub numerator: SymbolicNumber,
1683 pub denominator: SymbolicNumber,
1684 }
1685
1686 impl SymbolicFraction {
1687 pub fn one_over(n: SymbolicNumber) -> Self {
1689 Self {
1690 numerator: SymbolicNumber::Literal(1),
1691 denominator: n,
1692 }
1693 }
1694
1695 pub fn new(numerator: SymbolicNumber, denominator: SymbolicNumber) -> Self {
1697 Self {
1698 numerator,
1699 denominator,
1700 }
1701 }
1702
1703 pub fn to_notation(&self) -> String {
1705 match (&self.numerator, &self.denominator) {
1706 (SymbolicNumber::Literal(1), d) => format!("1/{}", d.to_notation()),
1707 (n, d) => format!("{}/{}", n.to_notation(), d.to_notation()),
1708 }
1709 }
1710
1711 pub fn try_evaluate(&self) -> Option<f64> {
1713 let num = match &self.numerator {
1714 SymbolicNumber::Literal(n) => *n as f64,
1715 SymbolicNumber::Big(big) if big.bits() < 53 => {
1716 let val: u64 = big.try_into().ok()?;
1717 val as f64
1718 }
1719 _ => return None,
1720 };
1721 let denom = match &self.denominator {
1722 SymbolicNumber::Literal(d) => *d as f64,
1723 SymbolicNumber::Big(big) if big.bits() < 53 => {
1724 let val: u64 = big.try_into().ok()?;
1725 val as f64
1726 }
1727 _ => return None,
1728 };
1729 Some(num / denom)
1730 }
1731
1732 pub fn is_one(&self) -> bool {
1753 match (&self.numerator, &self.denominator) {
1754 (SymbolicNumber::Literal(a), SymbolicNumber::Literal(b)) => a == b,
1755 (SymbolicNumber::Big(a), SymbolicNumber::Big(b)) => a == b,
1756 (SymbolicNumber::Graham, SymbolicNumber::Graham) => true,
1757 (SymbolicNumber::Tree(a), SymbolicNumber::Tree(b)) => a == b,
1758 (SymbolicNumber::Infinity, SymbolicNumber::Infinity) => true,
1759 (SymbolicNumber::Rayo, SymbolicNumber::Rayo) => true,
1760 _ => false,
1761 }
1762 }
1763 }
1764
1765 impl std::fmt::Display for SymbolicFraction {
1766 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1767 write!(f, "{}", self.to_notation())
1768 }
1769 }
1770
1771 #[derive(Clone, Debug)]
1777 pub enum SymbolicEntropy {
1778 Log2(SymbolicNumber),
1780 Bits(f64),
1782 Infinite,
1784 }
1785
1786 impl SymbolicEntropy {
1787 pub fn log2(n: SymbolicNumber) -> Self {
1789 match n {
1790 SymbolicNumber::Infinity => Self::Infinite,
1791 SymbolicNumber::Literal(lit) => Self::Bits((lit as f64).log2()),
1792 _ => Self::Log2(n),
1793 }
1794 }
1795
1796 pub fn to_notation(&self) -> String {
1798 match self {
1799 Self::Log2(n) => format!("log_2({})", n.to_notation()),
1800 Self::Bits(b) => format!("{:.3} bits", b),
1801 Self::Infinite => "infty bits".to_string(),
1802 }
1803 }
1804
1805 pub fn try_evaluate(&self) -> Option<f64> {
1807 match self {
1808 Self::Bits(b) => Some(*b),
1809 Self::Log2(n) => match n {
1810 SymbolicNumber::Literal(lit) => Some((*lit as f64).log2()),
1811 SymbolicNumber::Big(big) => Some(big.bits() as f64),
1812 _ => None,
1813 },
1814 Self::Infinite => None,
1815 }
1816 }
1817 }
1818
1819 impl std::fmt::Display for SymbolicEntropy {
1820 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1821 write!(f, "{}", self.to_notation())
1822 }
1823 }
1824
1825 #[derive(Clone, Debug)]
1852 pub struct SymbolicBinomial {
1853 pub n: SymbolicNumber,
1855 pub k: SymbolicNumber,
1857 }
1858
1859 impl SymbolicBinomial {
1860 pub fn new(n: SymbolicNumber, k: SymbolicNumber) -> Self {
1862 Self { n, k }
1863 }
1864
1865 pub fn try_evaluate(&self) -> Option<u128> {
1877 let n_val = match &self.n {
1878 SymbolicNumber::Literal(n) => *n as u128,
1879 SymbolicNumber::Big(n) => {
1880 if n.bits() <= 64 {
1881 n.to_u64_digits().first().map(|&d| d as u128)?
1882 } else {
1883 return None;
1884 }
1885 }
1886 _ => return None,
1887 };
1888
1889 let k_val = match &self.k {
1890 SymbolicNumber::Literal(k) => *k as u128,
1891 SymbolicNumber::Big(k) => {
1892 if k.bits() <= 64 {
1893 k.to_u64_digits().first().map(|&d| d as u128)?
1894 } else {
1895 return None;
1896 }
1897 }
1898 _ => return None,
1899 };
1900
1901 if k_val > n_val {
1902 return Some(0);
1903 }
1904
1905 let k_val = k_val.min(n_val - k_val);
1906
1907 if k_val == 0 {
1908 return Some(1);
1909 }
1910
1911 let mut result: u128 = 1;
1912 for i in 0..k_val {
1913 result = result.checked_mul(n_val - i)?;
1914 result /= i + 1;
1915 }
1916 Some(result)
1917 }
1918
1919 pub fn simplify(&self) -> SimplifiedBinomial {
1923 if let SymbolicNumber::Literal(0) = &self.k {
1924 return SimplifiedBinomial::One;
1925 }
1926 if let SymbolicNumber::Big(k) = &self.k {
1927 if k == &num_bigint::BigUint::from(0u32) {
1928 return SimplifiedBinomial::One;
1929 }
1930 }
1931
1932 if self.n.structurally_equal(&self.k) {
1933 return SimplifiedBinomial::One;
1934 }
1935
1936 if matches!(&self.n, SymbolicNumber::Infinity) {
1937 if !matches!(&self.k, SymbolicNumber::Infinity) {
1938 return SimplifiedBinomial::Infinite;
1939 }
1940 }
1941
1942 if let SymbolicNumber::Literal(1) = &self.k {
1943 return SimplifiedBinomial::N(self.n.clone());
1944 }
1945 if let SymbolicNumber::Big(k) = &self.k {
1946 if k == &num_bigint::BigUint::from(1u32) {
1947 return SimplifiedBinomial::N(self.n.clone());
1948 }
1949 }
1950
1951 if let SymbolicNumber::Literal(2) = &self.k {
1952 return SimplifiedBinomial::NChoose2(self.n.clone());
1953 }
1954 if let SymbolicNumber::Big(k) = &self.k {
1955 if k == &num_bigint::BigUint::from(2u32) {
1956 return SimplifiedBinomial::NChoose2(self.n.clone());
1957 }
1958 }
1959
1960 if let (SymbolicNumber::Literal(n), SymbolicNumber::Literal(k)) = (&self.n, &self.k) {
1961 if k > n {
1962 return SimplifiedBinomial::Zero;
1963 }
1964 if *k == *n - 1 {
1965 return SimplifiedBinomial::N(self.n.clone());
1966 }
1967 }
1968
1969 SimplifiedBinomial::General(self.clone())
1970 }
1971
1972 pub fn to_notation(&self) -> String {
1974 format!("C({}, {})", self.n.to_notation(), self.k.to_notation())
1975 }
1976
1977 pub fn is_one(&self) -> bool {
1979 matches!(self.simplify(), SimplifiedBinomial::One)
1980 }
1981
1982 pub fn is_n(&self) -> bool {
1984 matches!(self.simplify(), SimplifiedBinomial::N(_))
1985 }
1986
1987 pub fn is_infinite(&self) -> bool {
1989 matches!(self.simplify(), SimplifiedBinomial::Infinite)
1990 }
1991
1992 pub fn is_zero(&self) -> bool {
1994 matches!(self.simplify(), SimplifiedBinomial::Zero)
1995 }
1996 }
1997
1998 impl std::fmt::Display for SymbolicBinomial {
1999 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2000 write!(f, "{}", self.to_notation())
2001 }
2002 }
2003
2004 #[derive(Clone, Debug)]
2006 pub enum SimplifiedBinomial {
2007 One,
2009 N(SymbolicNumber),
2011 NChoose2(SymbolicNumber),
2013 General(SymbolicBinomial),
2015 Infinite,
2017 Zero,
2019 }
2020
2021 impl SimplifiedBinomial {
2022 pub fn to_notation(&self) -> String {
2024 match self {
2025 Self::One => "1".to_string(),
2026 Self::N(n) => n.to_notation(),
2027 Self::NChoose2(n) => format!("{}({}-1)/2", n.to_notation(), n.to_notation()),
2028 Self::General(binom) => binom.to_notation(),
2029 Self::Infinite => "infty".to_string(),
2030 Self::Zero => "0".to_string(),
2031 }
2032 }
2033
2034 pub fn try_evaluate(&self) -> Option<u128> {
2036 match self {
2037 Self::One => Some(1),
2038 Self::N(n) => match n {
2039 SymbolicNumber::Literal(v) => Some(*v as u128),
2040 SymbolicNumber::Big(b) if b.bits() <= 128 => {
2041 let digits = b.to_u64_digits();
2042 if digits.len() == 1 {
2043 Some(digits[0] as u128)
2044 } else if digits.len() == 2 {
2045 Some(digits[0] as u128 | ((digits[1] as u128) << 64))
2046 } else {
2047 None
2048 }
2049 }
2050 _ => None,
2051 },
2052 Self::NChoose2(n) => {
2053 if let SymbolicNumber::Literal(v) = n {
2054 Some((*v as u128) * (*v as u128 - 1) / 2)
2055 } else {
2056 None
2057 }
2058 }
2059 Self::General(binom) => binom.try_evaluate(),
2060 Self::Infinite => None,
2061 Self::Zero => Some(0),
2062 }
2063 }
2064 }
2065
2066 impl std::fmt::Display for SimplifiedBinomial {
2067 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2068 write!(f, "{}", self.to_notation())
2069 }
2070 }
2071
2072 #[derive(Clone)]
2098 pub struct SymbolicWState {
2099 pub n_qubits: SymbolicNumber,
2101 pub amplitude: SymbolicAmplitude,
2103 pub creation_time_ns: u64,
2105 }
2106
2107 impl SymbolicWState {
2108 pub fn new(n_qubits: SymbolicNumber) -> Self {
2112 assert!(!n_qubits.is_zero(), "W-state requires at least one qubit");
2113
2114 let start = std::time::Instant::now();
2115 let amplitude = SymbolicAmplitude::ReciprocalSqrt(n_qubits.clone());
2116 Self {
2117 n_qubits,
2118 amplitude,
2119 creation_time_ns: start.elapsed().as_nanos() as u64,
2120 }
2121 }
2122
2123 pub fn graham() -> Self {
2125 Self::new(SymbolicNumber::Graham)
2126 }
2127
2128 pub fn tree(n: u64) -> Self {
2130 Self::new(SymbolicNumber::Tree(n))
2131 }
2132
2133 pub fn infinite() -> Self {
2135 Self::new(SymbolicNumber::Infinity)
2136 }
2137
2138 pub fn knuth_arrow(a: u64, arrows: u64, b: u64) -> Self {
2140 Self::new(SymbolicNumber::KnuthArrow {
2141 a,
2142 arrows,
2143 b: Box::new(SymbolicNumber::Literal(b)),
2144 })
2145 }
2146
2147 pub fn tetration(base: u64, height: u64) -> Self {
2149 Self::new(SymbolicNumber::Tetration {
2150 base,
2151 height: Box::new(SymbolicNumber::Literal(height)),
2152 })
2153 }
2154
2155 pub fn verify(&self) -> SymbolicWVerification {
2173 let amplitude = self.amplitude.clone();
2174 let prob_per_state = SymbolicFraction::one_over(self.n_qubits.clone());
2175 let total_probability =
2176 SymbolicFraction::new(self.n_qubits.clone(), self.n_qubits.clone());
2177 let per_qubit_probability = SymbolicFraction::one_over(self.n_qubits.clone());
2178 let entanglement_entropy = SymbolicEntropy::log2(self.n_qubits.clone());
2179
2180 SymbolicWVerification {
2181 n_qubits: self.n_qubits.clone(),
2182 amplitude,
2183 num_nonzero_amplitudes: self.n_qubits.clone(),
2184 probability_per_state: prob_per_state,
2185 total_probability,
2186 per_qubit_probability,
2187 entanglement_entropy,
2188 size_class: self.n_qubits.size_class().to_string(),
2189 is_valid: true,
2190 }
2191 }
2192
2193 pub fn entanglement_entropy(&self) -> SymbolicEntropy {
2195 SymbolicEntropy::log2(self.n_qubits.clone())
2196 }
2197
2198 pub fn measurement_probability(&self) -> SymbolicFraction {
2200 SymbolicFraction::one_over(self.n_qubits.clone())
2201 }
2202
2203 pub fn memory_bytes(&self) -> usize {
2205 std::mem::size_of::<Self>()
2206 }
2207
2208 pub fn n_qubits(&self) -> &SymbolicNumber {
2210 &self.n_qubits
2211 }
2212
2213 pub fn creation_time_ns(&self) -> u64 {
2215 self.creation_time_ns
2216 }
2217 }
2218
2219 impl std::fmt::Display for SymbolicWState {
2220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2221 write!(f, "|W_({})>", self.n_qubits)
2222 }
2223 }
2224
2225 #[derive(Debug, Clone)]
2229 pub struct SymbolicWVerification {
2230 pub n_qubits: SymbolicNumber,
2232 pub amplitude: SymbolicAmplitude,
2234 pub num_nonzero_amplitudes: SymbolicNumber,
2236 pub probability_per_state: SymbolicFraction,
2238 pub total_probability: SymbolicFraction,
2240 pub per_qubit_probability: SymbolicFraction,
2242 pub entanglement_entropy: SymbolicEntropy,
2244 pub size_class: String,
2246 pub is_valid: bool,
2248 }
2249
2250 impl std::fmt::Display for SymbolicWVerification {
2251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2252 writeln!(f, "SYMBOLIC W-STATE VERIFICATION [{}]", self.size_class)?;
2253 writeln!(f, " Qubits (n): {}", self.n_qubits)?;
2254 writeln!(f, " Amplitude per state: {}", self.amplitude)?;
2255 writeln!(
2256 f,
2257 " Non-zero amplitudes: {}",
2258 self.num_nonzero_amplitudes
2259 )?;
2260 writeln!(
2261 f,
2262 " Probability per state: {} = {}",
2263 self.probability_per_state,
2264 self.probability_per_state.to_notation()
2265 )?;
2266 writeln!(f, " ALGEBRAIC PROOF OF NORMALIZATION:")?;
2267 writeln!(f, " Total prob = n x |amplitude|^2")?;
2268 writeln!(
2269 f,
2270 " = {} x |{}|^2",
2271 self.n_qubits, self.amplitude
2272 )?;
2273 writeln!(
2274 f,
2275 " = {} x ({})",
2276 self.n_qubits, self.probability_per_state
2277 )?;
2278 writeln!(f, " = {}", self.total_probability)?;
2279 writeln!(
2280 f,
2281 " = 1 {} ({})",
2282 if self.total_probability.is_one() {
2283 "v"
2284 } else {
2285 "x"
2286 },
2287 if self.total_probability.is_one() {
2288 "algebraically verified"
2289 } else {
2290 "FAILED"
2291 }
2292 )?;
2293 writeln!(
2294 f,
2295 " Entanglement entropy: {}",
2296 self.entanglement_entropy
2297 )?;
2298 writeln!(
2299 f,
2300 " Per-qubit probability: {}",
2301 self.per_qubit_probability
2302 )?;
2303 writeln!(
2304 f,
2305 " Valid: {}",
2306 if self.is_valid { "YES" } else { "NO" }
2307 )?;
2308 writeln!(
2309 f,
2310 " Memory: formula object; no iteration over {} amplitudes",
2311 self.n_qubits
2312 )?;
2313
2314 match &self.n_qubits {
2315 SymbolicNumber::Graham => {
2316 writeln!(f, " Graham label: amplitudes are not enumerated.")?;
2317 writeln!(
2318 f,
2319 " - The stored normalization formula simplifies to 1 algebraically."
2320 )?;
2321 }
2322 SymbolicNumber::Tree(n) => {
2323 writeln!(f, " TREE({}) label: amplitudes are not enumerated.", n)?;
2324 writeln!(f, " - Verification checks the symbolic formula.")?;
2325 }
2326 SymbolicNumber::Infinity => {
2327 writeln!(f, " Formal infinity label (aleph_0):")?;
2328 writeln!(f, " - This is a symbolic formula object.")?;
2329 writeln!(
2330 f,
2331 " - It is not a numerical construction of an infinite W-state limit."
2332 )?;
2333 }
2334 _ => {}
2335 }
2336
2337 Ok(())
2338 }
2339 }
2340
2341 #[derive(Clone)]
2369 pub struct SymbolicDickeState {
2370 pub n_qubits: SymbolicNumber,
2372 pub k_excitations: SymbolicNumber,
2374 pub num_amplitudes: SymbolicBinomial,
2376 pub amplitude: SymbolicAmplitude,
2378 pub creation_time_ns: u64,
2380 }
2381
2382 impl SymbolicDickeState {
2383 pub fn new(n: SymbolicNumber, k: SymbolicNumber) -> Self {
2385 let start = std::time::Instant::now();
2386 let num_amplitudes = SymbolicBinomial::new(n.clone(), k.clone());
2387 let amplitude = SymbolicAmplitude::ReciprocalSqrtBinomial(num_amplitudes.clone());
2388 Self {
2389 n_qubits: n,
2390 k_excitations: k,
2391 num_amplitudes,
2392 amplitude,
2393 creation_time_ns: start.elapsed().as_nanos() as u64,
2394 }
2395 }
2396
2397 pub fn graham(k: u64) -> Self {
2399 Self::new(SymbolicNumber::Graham, SymbolicNumber::Literal(k))
2400 }
2401
2402 pub fn infinite(k: u64) -> Self {
2404 Self::new(SymbolicNumber::Infinity, SymbolicNumber::Literal(k))
2405 }
2406
2407 pub fn tree(t: u64, k: u64) -> Self {
2409 Self::new(SymbolicNumber::Tree(t), SymbolicNumber::Literal(k))
2410 }
2411
2412 pub fn as_w_state(n: SymbolicNumber) -> Self {
2414 Self::new(n, SymbolicNumber::Literal(1))
2415 }
2416
2417 pub fn ground_state(n: SymbolicNumber) -> Self {
2419 Self::new(n, SymbolicNumber::Literal(0))
2420 }
2421
2422 pub fn all_excited(n: SymbolicNumber) -> Self {
2424 Self::new(n.clone(), n)
2425 }
2426
2427 pub fn half_excitations(n: SymbolicNumber) -> Self {
2429 let k = SymbolicNumber::Div {
2430 numerator: Box::new(n.clone()),
2431 denominator: Box::new(SymbolicNumber::Literal(2)),
2432 };
2433 Self::new(n, k)
2434 }
2435
2436 pub fn verify(&self) -> SymbolicDickeVerification {
2450 let simplified = self.num_amplitudes.simplify();
2451
2452 let is_w_state = matches!(&self.k_excitations, SymbolicNumber::Literal(1))
2453 || matches!(&self.k_excitations, SymbolicNumber::Big(k) if k == &num_bigint::BigUint::from(1u32));
2454
2455 let is_product_state = matches!(&self.k_excitations, SymbolicNumber::Literal(0))
2456 || matches!(&self.k_excitations, SymbolicNumber::Big(k) if k == &num_bigint::BigUint::from(0u32))
2457 || self.n_qubits.structurally_equal(&self.k_excitations);
2458
2459 SymbolicDickeVerification {
2460 n_qubits: self.n_qubits.clone(),
2461 k_excitations: self.k_excitations.clone(),
2462 num_amplitudes: self.num_amplitudes.clone(),
2463 simplified_count: simplified,
2464 amplitude: self.amplitude.clone(),
2465 total_probability: "C(n,k) x 1/C(n,k) = 1".to_string(),
2466 is_w_state,
2467 is_product_state,
2468 size_class: format!(
2469 "{} qubits, {} excitations",
2470 self.n_qubits.size_class(),
2471 self.k_excitations.size_class()
2472 ),
2473 is_valid: true,
2474 }
2475 }
2476
2477 pub fn apply_lowering(&self) -> Option<(SymbolicAmplitude, SymbolicDickeState)> {
2481 if matches!(&self.k_excitations, SymbolicNumber::Literal(0)) {
2482 return None;
2483 }
2484 if let SymbolicNumber::Big(k) = &self.k_excitations {
2485 if k == &num_bigint::BigUint::from(0u32) {
2486 return None;
2487 }
2488 }
2489
2490 let new_k = SymbolicNumber::Sub {
2491 minuend: Box::new(self.k_excitations.clone()),
2492 subtrahend: Box::new(SymbolicNumber::Literal(1)),
2493 };
2494
2495 let coefficient = SymbolicAmplitude::SqrtFraction {
2496 numerator: self.k_excitations.clone(),
2497 denominator: SymbolicNumber::Literal(1),
2498 };
2499
2500 let new_state = SymbolicDickeState::new(self.n_qubits.clone(), new_k);
2501 Some((coefficient, new_state))
2502 }
2503
2504 pub fn is_w_state(&self) -> bool {
2519 matches!(&self.k_excitations, SymbolicNumber::Literal(1))
2520 || matches!(&self.k_excitations, SymbolicNumber::Big(k) if k == &num_bigint::BigUint::from(1u32))
2521 }
2522
2523 pub fn is_product_state(&self) -> bool {
2535 if matches!(&self.k_excitations, SymbolicNumber::Literal(0)) {
2536 return true;
2537 }
2538 if let SymbolicNumber::Big(k) = &self.k_excitations {
2539 if k == &num_bigint::BigUint::from(0u32) {
2540 return true;
2541 }
2542 }
2543 self.n_qubits.structurally_equal(&self.k_excitations)
2544 }
2545
2546 pub fn memory_bytes(&self) -> usize {
2548 std::mem::size_of::<Self>()
2549 }
2550
2551 pub fn n_qubits(&self) -> &SymbolicNumber {
2553 &self.n_qubits
2554 }
2555
2556 pub fn k_excitations(&self) -> &SymbolicNumber {
2558 &self.k_excitations
2559 }
2560
2561 pub fn creation_time_ns(&self) -> u64 {
2563 self.creation_time_ns
2564 }
2565 }
2566
2567 impl std::fmt::Display for SymbolicDickeState {
2568 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2569 write!(
2570 f,
2571 "|D_{}^{}>",
2572 self.n_qubits.to_notation(),
2573 self.k_excitations.to_notation()
2574 )
2575 }
2576 }
2577
2578 #[derive(Debug, Clone)]
2582 pub struct SymbolicDickeVerification {
2583 pub n_qubits: SymbolicNumber,
2585 pub k_excitations: SymbolicNumber,
2587 pub num_amplitudes: SymbolicBinomial,
2589 pub simplified_count: SimplifiedBinomial,
2591 pub amplitude: SymbolicAmplitude,
2593 pub total_probability: String,
2595 pub is_w_state: bool,
2597 pub is_product_state: bool,
2599 pub size_class: String,
2601 pub is_valid: bool,
2603 }
2604
2605 impl std::fmt::Display for SymbolicDickeVerification {
2606 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2607 writeln!(
2608 f,
2609 "SYMBOLIC DICKE STATE VERIFICATION |D_{}^{}>",
2610 self.n_qubits.to_notation(),
2611 self.k_excitations.to_notation()
2612 )?;
2613 writeln!(f, " Qubits (n): {}", self.n_qubits)?;
2614 writeln!(f, " Excitations (k): {}", self.k_excitations)?;
2615 writeln!(f, " C(n,k) = {}", self.num_amplitudes)?;
2616 writeln!(f, " Simplified: {}", self.simplified_count)?;
2617 writeln!(f, " Amplitude: {}", self.amplitude)?;
2618 writeln!(f, " Total probability: {}", self.total_probability)?;
2619 if self.is_product_state {
2620 writeln!(f, " [PRODUCT STATE] — separable, no entanglement")?;
2621 }
2622 if self.is_w_state {
2623 writeln!(f, " [W-STATE] — k=1, equivalent to |W_n>")?;
2624 }
2625 if !self.is_product_state && !self.is_w_state {
2626 writeln!(f, " [ENTANGLED] — general Dicke state")?;
2627 }
2628 writeln!(f, " Memory: O(1) — no iteration over C(n,k) amplitudes!")?;
2629 writeln!(f, " Valid: {}", if self.is_valid { "YES" } else { "NO" })?;
2630 Ok(())
2631 }
2632 }
2633
2634 pub fn create_graham_w() -> SymbolicWState {
2648 SymbolicWState::graham()
2649 }
2650
2651 pub fn create_tree_w(n: u64) -> SymbolicWState {
2662 SymbolicWState::tree(n)
2663 }
2664
2665 pub fn create_infinite_w() -> SymbolicWState {
2667 SymbolicWState::infinite()
2668 }
2669
2670 pub fn create_symbolic_w(n_qubits: SymbolicNumber) -> SymbolicWState {
2672 SymbolicWState::new(n_qubits)
2673 }
2674
2675 pub fn create_symbolic_dicke(n: SymbolicNumber, k: SymbolicNumber) -> SymbolicDickeState {
2677 SymbolicDickeState::new(n, k)
2678 }
2679
2680 pub fn create_graham_dicke(k: u64) -> SymbolicDickeState {
2692 SymbolicDickeState::graham(k)
2693 }
2694
2695 pub fn create_tree_dicke(t: u64, k: u64) -> SymbolicDickeState {
2697 SymbolicDickeState::tree(t, k)
2698 }
2699
2700 pub fn create_infinite_dicke(k: u64) -> SymbolicDickeState {
2702 SymbolicDickeState::infinite(k)
2703 }
2704}