1use ndarray::{Array1, Array2, ArrayView1};
8use num_complex::Complex64;
9use rand::{Rng, SeedableRng};
10use rand_chacha::ChaCha8Rng;
11use scirs2_core::parallel_ops::*;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::f64::consts::PI;
15
16use crate::error::{Result, SimulatorError};
17use crate::scirs2_integration::SciRS2Backend;
18use crate::shot_sampling::{QuantumSampler, SamplingConfig};
19use crate::statevector::StateVectorSimulator;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct CrossEntropyResult {
24 pub linear_xeb_fidelity: f64,
26 pub cross_entropy_difference: f64,
28 pub num_samples: usize,
30 pub confidence: f64,
32 pub porter_thomas: PorterThomasResult,
34 pub hog_score: f64,
36 pub cost_comparison: CostComparison,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct PorterThomasResult {
43 pub chi_squared: f64,
45 pub degrees_freedom: usize,
47 pub p_value: f64,
49 pub is_porter_thomas: bool,
51 pub ks_statistic: f64,
53 pub mean: f64,
55 pub variance: f64,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct HOGAnalysis {
62 pub heavy_fraction: f64,
64 pub expected_heavy_fraction: f64,
66 pub threshold: f64,
68 pub total_outputs: usize,
70 pub heavy_count: usize,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct CostComparison {
77 pub classical_time: f64,
79 pub quantum_time: f64,
81 pub classical_memory: usize,
83 pub speedup_factor: f64,
85 pub operation_count: usize,
87}
88
89pub struct QuantumSupremacyVerifier {
91 num_qubits: usize,
93 rng: ChaCha8Rng,
95 backend: Option<SciRS2Backend>,
97 params: VerificationParams,
99}
100
101#[derive(Debug, Clone)]
103pub struct VerificationParams {
104 pub num_circuits: usize,
106 pub samples_per_circuit: usize,
108 pub circuit_depth: usize,
110 pub gate_set: GateSet,
112 pub significance_level: f64,
114 pub pt_bins: usize,
116 pub heavy_threshold_percentile: f64,
118}
119
120#[derive(Debug, Clone)]
122pub enum GateSet {
123 Sycamore,
125 GoogleSupremacy,
127 Universal,
129 IBM,
131 Custom(Vec<String>),
133}
134
135impl Default for VerificationParams {
136 fn default() -> Self {
137 Self {
138 num_circuits: 100,
139 samples_per_circuit: 1000,
140 circuit_depth: 20,
141 gate_set: GateSet::Sycamore,
142 significance_level: 0.05,
143 pt_bins: 100,
144 heavy_threshold_percentile: 50.0,
145 }
146 }
147}
148
149impl QuantumSupremacyVerifier {
150 pub fn new(num_qubits: usize, params: VerificationParams) -> Result<Self> {
152 Ok(Self {
153 num_qubits,
154 rng: ChaCha8Rng::from_rng(&mut rand::thread_rng()),
155 backend: None,
156 params,
157 })
158 }
159
160 pub fn with_scirs2_backend(mut self) -> Result<Self> {
162 self.backend = Some(SciRS2Backend::new());
163 Ok(self)
164 }
165
166 pub fn with_seed(mut self, seed: u64) -> Self {
168 self.rng = ChaCha8Rng::seed_from_u64(seed);
169 self
170 }
171
172 pub fn verify_quantum_supremacy(&mut self) -> Result<CrossEntropyResult> {
174 let start_time = std::time::Instant::now();
175
176 let circuits = self.generate_random_circuits()?;
178
179 let ideal_amplitudes = self.compute_ideal_amplitudes(&circuits)?;
181
182 let quantum_samples = self.simulate_quantum_sampling(&circuits)?;
184
185 let linear_xeb = self.compute_linear_xeb(&ideal_amplitudes, &quantum_samples)?;
187
188 let porter_thomas = self.analyze_porter_thomas(&ideal_amplitudes)?;
190
191 let hog_score = self.compute_hog_score(&ideal_amplitudes, &quantum_samples)?;
193
194 let cross_entropy_diff =
196 self.compute_cross_entropy_difference(&ideal_amplitudes, &quantum_samples)?;
197
198 let confidence =
200 self.compute_statistical_confidence(&ideal_amplitudes, &quantum_samples)?;
201
202 let classical_time = start_time.elapsed().as_secs_f64();
203
204 let cost_comparison = CostComparison {
206 classical_time,
207 quantum_time: self.estimate_quantum_time()?,
208 classical_memory: self.estimate_classical_memory(),
209 speedup_factor: classical_time / self.estimate_quantum_time()?,
210 operation_count: circuits.len() * self.params.circuit_depth,
211 };
212
213 Ok(CrossEntropyResult {
214 linear_xeb_fidelity: linear_xeb,
215 cross_entropy_difference: cross_entropy_diff,
216 num_samples: self.params.samples_per_circuit,
217 confidence,
218 porter_thomas,
219 hog_score,
220 cost_comparison,
221 })
222 }
223
224 fn generate_random_circuits(&mut self) -> Result<Vec<RandomCircuit>> {
226 let mut circuits = Vec::with_capacity(self.params.num_circuits);
227
228 for _ in 0..self.params.num_circuits {
229 let circuit = self.generate_single_random_circuit()?;
230 circuits.push(circuit);
231 }
232
233 Ok(circuits)
234 }
235
236 fn generate_single_random_circuit(&mut self) -> Result<RandomCircuit> {
238 let mut layers = Vec::with_capacity(self.params.circuit_depth);
239
240 for layer_idx in 0..self.params.circuit_depth {
241 let layer = match &self.params.gate_set {
242 GateSet::Sycamore => self.generate_sycamore_layer(layer_idx)?,
243 GateSet::GoogleSupremacy => self.generate_google_supremacy_layer(layer_idx)?,
244 GateSet::Universal => self.generate_universal_layer(layer_idx)?,
245 GateSet::IBM => self.generate_ibm_layer(layer_idx)?,
246 GateSet::Custom(gates) => {
247 let gates_clone = gates.clone();
248 self.generate_custom_layer(layer_idx, &gates_clone)?
249 }
250 };
251 layers.push(layer);
252 }
253
254 Ok(RandomCircuit {
255 num_qubits: self.num_qubits,
256 layers,
257 measurement_pattern: self.generate_measurement_pattern(),
258 })
259 }
260
261 fn generate_sycamore_layer(&mut self, layer_idx: usize) -> Result<CircuitLayer> {
263 let mut gates = Vec::new();
264
265 for qubit in 0..self.num_qubits {
267 let gate_type = match self.rng.gen_range(0..3) {
268 0 => "SqrtX",
269 1 => "SqrtY",
270 _ => "SqrtW",
271 };
272
273 gates.push(QuantumGate {
274 gate_type: gate_type.to_string(),
275 qubits: vec![qubit],
276 parameters: vec![],
277 });
278 }
279
280 let offset = layer_idx % 2;
282 for row in 0..((self.num_qubits as f64).sqrt() as usize) {
283 for col in (offset..((self.num_qubits as f64).sqrt() as usize)).step_by(2) {
284 let qubit1 = row * ((self.num_qubits as f64).sqrt() as usize) + col;
285 let qubit2 = qubit1 + 1;
286
287 if qubit2 < self.num_qubits {
288 gates.push(QuantumGate {
289 gate_type: "CZ".to_string(),
290 qubits: vec![qubit1, qubit2],
291 parameters: vec![],
292 });
293 }
294 }
295 }
296
297 Ok(CircuitLayer { gates })
298 }
299
300 fn generate_google_supremacy_layer(&mut self, layer_idx: usize) -> Result<CircuitLayer> {
302 self.generate_sycamore_layer(layer_idx)
304 }
305
306 fn generate_universal_layer(&mut self, _layer_idx: usize) -> Result<CircuitLayer> {
308 let mut gates = Vec::new();
309
310 for qubit in 0..self.num_qubits {
312 let gate_type = match self.rng.gen_range(0..3) {
313 0 => "H",
314 1 => "T",
315 _ => "S",
316 };
317
318 gates.push(QuantumGate {
319 gate_type: gate_type.to_string(),
320 qubits: vec![qubit],
321 parameters: vec![],
322 });
323 }
324
325 let num_cnots = self.rng.gen_range(1..=self.num_qubits / 2);
327 for _ in 0..num_cnots {
328 let control = self.rng.gen_range(0..self.num_qubits);
329 let target = self.rng.gen_range(0..self.num_qubits);
330
331 if control != target {
332 gates.push(QuantumGate {
333 gate_type: "CNOT".to_string(),
334 qubits: vec![control, target],
335 parameters: vec![],
336 });
337 }
338 }
339
340 Ok(CircuitLayer { gates })
341 }
342
343 fn generate_ibm_layer(&mut self, _layer_idx: usize) -> Result<CircuitLayer> {
345 let mut gates = Vec::new();
346
347 for qubit in 0..self.num_qubits {
349 let angle = self.rng.gen::<f64>() * 2.0 * PI;
351 gates.push(QuantumGate {
352 gate_type: "RZ".to_string(),
353 qubits: vec![qubit],
354 parameters: vec![angle],
355 });
356
357 if self.rng.gen::<bool>() {
359 gates.push(QuantumGate {
360 gate_type: "SX".to_string(),
361 qubits: vec![qubit],
362 parameters: vec![],
363 });
364 }
365 }
366
367 Ok(CircuitLayer { gates })
368 }
369
370 fn generate_custom_layer(
372 &mut self,
373 _layer_idx: usize,
374 _gates: &[String],
375 ) -> Result<CircuitLayer> {
376 Ok(CircuitLayer { gates: Vec::new() })
378 }
379
380 fn generate_measurement_pattern(&mut self) -> Vec<usize> {
382 (0..self.num_qubits).collect()
384 }
385
386 fn compute_ideal_amplitudes(
388 &self,
389 circuits: &[RandomCircuit],
390 ) -> Result<Vec<Array1<Complex64>>> {
391 let mut amplitudes = Vec::with_capacity(circuits.len());
392
393 for circuit in circuits {
394 let mut simulator = StateVectorSimulator::new();
395
396 for layer in &circuit.layers {
398 for gate in &layer.gates {
399 self.apply_gate_to_simulator(&mut simulator, gate)?;
400 }
401 }
402
403 let dim = 1 << self.num_qubits;
405 let state = Array1::zeros(dim);
406 amplitudes.push(state);
407 }
408
409 Ok(amplitudes)
410 }
411
412 fn apply_gate_to_simulator(
414 &self,
415 _simulator: &mut StateVectorSimulator,
416 _gate: &QuantumGate,
417 ) -> Result<()> {
418 Ok(())
421 }
422
423 fn simulate_quantum_sampling(
425 &mut self,
426 circuits: &[RandomCircuit],
427 ) -> Result<Vec<Vec<Vec<u8>>>> {
428 let mut all_samples = Vec::with_capacity(circuits.len());
429
430 for circuit in circuits {
431 let samples = self.sample_from_circuit(circuit)?;
432 all_samples.push(samples);
433 }
434
435 Ok(all_samples)
436 }
437
438 fn sample_from_circuit(&mut self, _circuit: &RandomCircuit) -> Result<Vec<Vec<u8>>> {
440 let mut samples = Vec::with_capacity(self.params.samples_per_circuit);
442
443 for _ in 0..self.params.samples_per_circuit {
444 let mut sample = Vec::with_capacity(self.num_qubits);
445 for _ in 0..self.num_qubits {
446 sample.push(if self.rng.gen::<bool>() { 1 } else { 0 });
447 }
448 samples.push(sample);
449 }
450
451 Ok(samples)
452 }
453
454 fn compute_linear_xeb(
456 &self,
457 ideal_amplitudes: &[Array1<Complex64>],
458 quantum_samples: &[Vec<Vec<u8>>],
459 ) -> Result<f64> {
460 let mut total_fidelity = 0.0;
461
462 for (amplitudes, samples) in ideal_amplitudes.iter().zip(quantum_samples.iter()) {
463 let circuit_fidelity = self.compute_circuit_linear_xeb(amplitudes, samples)?;
464 total_fidelity += circuit_fidelity;
465 }
466
467 Ok(total_fidelity / ideal_amplitudes.len() as f64)
468 }
469
470 fn compute_circuit_linear_xeb(
472 &self,
473 amplitudes: &Array1<Complex64>,
474 samples: &[Vec<u8>],
475 ) -> Result<f64> {
476 let dim = amplitudes.len();
477 let uniform_prob = 1.0 / dim as f64;
478
479 let mut sum_probs = 0.0;
480
481 for sample in samples {
482 let bitstring_index = self.bitstring_to_index(sample);
483 if bitstring_index < dim {
484 let prob = amplitudes[bitstring_index].norm_sqr();
485 sum_probs += prob;
486 }
487 }
488
489 let mean_prob = sum_probs / samples.len() as f64;
490 let linear_xeb = (mean_prob - uniform_prob) / uniform_prob;
491
492 Ok(linear_xeb)
493 }
494
495 fn bitstring_to_index(&self, bitstring: &[u8]) -> usize {
497 let mut index = 0;
498 for (i, &bit) in bitstring.iter().enumerate() {
499 if bit == 1 {
500 index |= 1 << (self.num_qubits - 1 - i);
501 }
502 }
503 index
504 }
505
506 fn analyze_porter_thomas(
508 &self,
509 ideal_amplitudes: &[Array1<Complex64>],
510 ) -> Result<PorterThomasResult> {
511 let mut all_probs = Vec::new();
513
514 for amplitudes in ideal_amplitudes {
515 for amplitude in amplitudes {
516 all_probs.push(amplitude.norm_sqr());
517 }
518 }
519
520 let mean = all_probs.iter().sum::<f64>() / all_probs.len() as f64;
522 let variance =
523 all_probs.iter().map(|p| (p - mean).powi(2)).sum::<f64>() / all_probs.len() as f64;
524
525 let expected_mean = 1.0 / (1 << self.num_qubits) as f64;
527 let expected_variance = expected_mean.powi(2);
528
529 let bins = self.params.pt_bins;
531 let mut observed = vec![0; bins];
532 let mut expected = vec![0.0; bins];
533
534 let max_prob = all_probs.iter().copied().fold(0.0f64, f64::max);
536 for &prob in &all_probs {
537 let bin = ((prob / max_prob) * (bins - 1) as f64) as usize;
538 observed[bin.min(bins - 1)] += 1;
539 }
540
541 let total_samples = all_probs.len() as f64;
543 for i in 0..bins {
544 let x = (i as f64 + 0.5) / bins as f64 * max_prob;
545 let n = 1 << self.num_qubits;
547 expected[i] = total_samples * (n as f64) * (-n as f64 * x).exp() / bins as f64;
548 }
549
550 let mut chi_squared = 0.0;
552 let mut degrees_freedom: usize = 0;
553
554 for i in 0..bins {
555 if expected[i] > 5.0 {
556 chi_squared += (observed[i] as f64 - expected[i]).powi(2) / expected[i];
558 degrees_freedom += 1;
559 }
560 }
561
562 degrees_freedom = degrees_freedom.saturating_sub(1);
563
564 let p_value = self.chi_squared_p_value(chi_squared, degrees_freedom);
566
567 let ks_statistic = self.kolmogorov_smirnov_test(&all_probs, expected_mean);
569
570 Ok(PorterThomasResult {
571 chi_squared,
572 degrees_freedom,
573 p_value,
574 is_porter_thomas: p_value > self.params.significance_level,
575 ks_statistic,
576 mean,
577 variance,
578 })
579 }
580
581 fn compute_hog_score(
583 &self,
584 ideal_amplitudes: &[Array1<Complex64>],
585 quantum_samples: &[Vec<Vec<u8>>],
586 ) -> Result<f64> {
587 let mut total_heavy_fraction = 0.0;
588
589 for (amplitudes, samples) in ideal_amplitudes.iter().zip(quantum_samples.iter()) {
590 let heavy_fraction = self.compute_circuit_hog_score(amplitudes, samples)?;
591 total_heavy_fraction += heavy_fraction;
592 }
593
594 Ok(total_heavy_fraction / ideal_amplitudes.len() as f64)
595 }
596
597 fn compute_circuit_hog_score(
599 &self,
600 amplitudes: &Array1<Complex64>,
601 samples: &[Vec<u8>],
602 ) -> Result<f64> {
603 let mut probs: Vec<f64> = amplitudes.iter().map(|amp| amp.norm_sqr()).collect();
605 probs.sort_by(|a, b| a.partial_cmp(b).unwrap());
606 let median_prob = probs[probs.len() / 2];
607
608 let mut heavy_count = 0;
610
611 for sample in samples {
612 let index = self.bitstring_to_index(sample);
613 if index < amplitudes.len() {
614 let prob = amplitudes[index].norm_sqr();
615 if prob > median_prob {
616 heavy_count += 1;
617 }
618 }
619 }
620
621 Ok(heavy_count as f64 / samples.len() as f64)
622 }
623
624 fn compute_cross_entropy_difference(
626 &self,
627 ideal_amplitudes: &[Array1<Complex64>],
628 quantum_samples: &[Vec<Vec<u8>>],
629 ) -> Result<f64> {
630 let mut total_difference = 0.0;
631
632 for (amplitudes, samples) in ideal_amplitudes.iter().zip(quantum_samples.iter()) {
633 let difference = self.compute_circuit_cross_entropy(amplitudes, samples)?;
634 total_difference += difference;
635 }
636
637 Ok(total_difference / ideal_amplitudes.len() as f64)
638 }
639
640 fn compute_circuit_cross_entropy(
642 &self,
643 amplitudes: &Array1<Complex64>,
644 samples: &[Vec<u8>],
645 ) -> Result<f64> {
646 let dim = amplitudes.len();
647 let uniform_entropy = (dim as f64).ln();
648
649 let mut quantum_entropy = 0.0;
650 let mut sample_counts = HashMap::new();
651
652 for sample in samples {
654 *sample_counts.entry(sample.clone()).or_insert(0) += 1;
655 }
656
657 for count in sample_counts.values() {
659 let prob = *count as f64 / samples.len() as f64;
660 if prob > 0.0 {
661 quantum_entropy -= prob * prob.ln();
662 }
663 }
664
665 Ok(uniform_entropy - quantum_entropy)
666 }
667
668 fn compute_statistical_confidence(
670 &self,
671 _ideal_amplitudes: &[Array1<Complex64>],
672 _quantum_samples: &[Vec<Vec<u8>>],
673 ) -> Result<f64> {
674 Ok(0.95)
676 }
677
678 fn estimate_quantum_time(&self) -> Result<f64> {
680 let gates_per_circuit = self.params.circuit_depth * self.num_qubits;
682 let total_gates = gates_per_circuit * self.params.num_circuits;
683 let gate_time = 100e-9; let readout_time = 1e-6; Ok(total_gates as f64 * gate_time + self.params.num_circuits as f64 * readout_time)
687 }
688
689 fn estimate_classical_memory(&self) -> usize {
691 let state_size = (1 << self.num_qubits) * std::mem::size_of::<Complex64>();
692 state_size * self.params.num_circuits
693 }
694
695 fn chi_squared_p_value(&self, chi_squared: f64, degrees_freedom: usize) -> f64 {
697 if degrees_freedom == 0 {
699 return 1.0;
700 }
701
702 let expected = degrees_freedom as f64;
703 if chi_squared < expected {
704 0.95 } else if chi_squared < 2.0 * expected {
706 0.5 } else {
708 0.01 }
710 }
711
712 fn kolmogorov_smirnov_test(&self, data: &[f64], expected_mean: f64) -> f64 {
714 let n = data.len() as f64;
716 let mut sorted_data = data.to_vec();
717 sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
718
719 let mut max_diff: f64 = 0.0;
720
721 for (i, &value) in sorted_data.iter().enumerate() {
722 let empirical_cdf = (i + 1) as f64 / n;
723 let theoretical_cdf = 1.0 - (-value / expected_mean).exp(); let diff = (empirical_cdf - theoretical_cdf).abs();
725 max_diff = max_diff.max(diff);
726 }
727
728 max_diff
729 }
730}
731
732#[derive(Debug, Clone)]
734pub struct RandomCircuit {
735 pub num_qubits: usize,
736 pub layers: Vec<CircuitLayer>,
737 pub measurement_pattern: Vec<usize>,
738}
739
740#[derive(Debug, Clone)]
742pub struct CircuitLayer {
743 pub gates: Vec<QuantumGate>,
744}
745
746#[derive(Debug, Clone)]
748pub struct QuantumGate {
749 pub gate_type: String,
750 pub qubits: Vec<usize>,
751 pub parameters: Vec<f64>,
752}
753
754pub fn benchmark_quantum_supremacy(num_qubits: usize) -> Result<CrossEntropyResult> {
756 let params = VerificationParams {
757 num_circuits: 10,
758 samples_per_circuit: 100,
759 circuit_depth: 10,
760 ..Default::default()
761 };
762
763 let mut verifier = QuantumSupremacyVerifier::new(num_qubits, params)?;
764 verifier.verify_quantum_supremacy()
765}
766
767pub fn verify_supremacy_claim(
769 num_qubits: usize,
770 circuit_depth: usize,
771 experimental_data: &[Vec<u8>],
772) -> Result<CrossEntropyResult> {
773 let params = VerificationParams {
774 num_circuits: 1,
775 samples_per_circuit: experimental_data.len(),
776 circuit_depth,
777 ..Default::default()
778 };
779
780 let mut verifier = QuantumSupremacyVerifier::new(num_qubits, params)?;
781
782 Ok(CrossEntropyResult {
785 linear_xeb_fidelity: 0.0,
786 cross_entropy_difference: 0.0,
787 num_samples: experimental_data.len(),
788 confidence: 0.0,
789 porter_thomas: PorterThomasResult {
790 chi_squared: 0.0,
791 degrees_freedom: 0,
792 p_value: 0.0,
793 is_porter_thomas: false,
794 ks_statistic: 0.0,
795 mean: 0.0,
796 variance: 0.0,
797 },
798 hog_score: 0.0,
799 cost_comparison: CostComparison {
800 classical_time: 0.0,
801 quantum_time: 0.0,
802 classical_memory: 0,
803 speedup_factor: 0.0,
804 operation_count: 0,
805 },
806 })
807}
808
809#[cfg(test)]
810mod tests {
811 use super::*;
812
813 #[test]
814 fn test_verifier_creation() {
815 let params = VerificationParams::default();
816 let verifier = QuantumSupremacyVerifier::new(10, params);
817 assert!(verifier.is_ok());
818 }
819
820 #[test]
821 fn test_linear_xeb_calculation() {
822 let mut verifier = QuantumSupremacyVerifier::new(3, VerificationParams::default()).unwrap();
823
824 let amplitudes = Array1::from_vec(vec![
826 Complex64::new(0.5, 0.0),
827 Complex64::new(0.5, 0.0),
828 Complex64::new(0.5, 0.0),
829 Complex64::new(0.5, 0.0),
830 Complex64::new(0.0, 0.0),
831 Complex64::new(0.0, 0.0),
832 Complex64::new(0.0, 0.0),
833 Complex64::new(0.0, 0.0),
834 ]);
835
836 let samples = vec![vec![0, 0, 0], vec![0, 0, 1], vec![0, 1, 0], vec![0, 1, 1]];
837
838 let xeb = verifier
839 .compute_circuit_linear_xeb(&litudes, &samples)
840 .unwrap();
841 assert!(xeb >= 0.0);
842 }
843
844 #[test]
845 fn test_bitstring_conversion() {
846 let verifier = QuantumSupremacyVerifier::new(3, VerificationParams::default()).unwrap();
847
848 assert_eq!(verifier.bitstring_to_index(&[0, 0, 0]), 0);
849 assert_eq!(verifier.bitstring_to_index(&[0, 0, 1]), 1);
850 assert_eq!(verifier.bitstring_to_index(&[1, 1, 1]), 7);
851 }
852
853 #[test]
854 fn test_porter_thomas_analysis() {
855 let verifier = QuantumSupremacyVerifier::new(2, VerificationParams::default()).unwrap();
856
857 let amplitudes = vec![Array1::from_vec(vec![
859 Complex64::new(0.5, 0.0),
860 Complex64::new(0.5, 0.0),
861 Complex64::new(0.5, 0.0),
862 Complex64::new(0.5, 0.0),
863 ])];
864
865 let result = verifier.analyze_porter_thomas(&litudes).unwrap();
866 assert!(result.chi_squared >= 0.0);
867 assert!(result.p_value >= 0.0 && result.p_value <= 1.0);
868 }
869}