1use crate::error::QuantRS2Error;
15use scirs2_core::ndarray::{Array1, Array2};
16use scirs2_core::random::prelude::*;
17use scirs2_core::Complex64;
18use std::f64::consts::PI;
19
20pub trait AmplitudeOracle {
25 fn state_preparation(&self) -> Array1<Complex64>;
27
28 fn grover_oracle(&self, state: &mut Array1<Complex64>);
30
31 fn num_qubits(&self) -> usize;
33
34 fn is_good_state(&self, basis_index: usize) -> bool;
36}
37
38#[derive(Debug, Clone)]
45pub struct GroverOperator {
46 num_qubits: usize,
47}
48
49impl GroverOperator {
50 pub const fn new(num_qubits: usize) -> Self {
52 Self { num_qubits }
53 }
54
55 pub fn apply(
57 &self,
58 state: &mut Array1<Complex64>,
59 oracle: &dyn AmplitudeOracle,
60 ) -> Result<(), QuantRS2Error> {
61 let dim = 1 << self.num_qubits;
62 if state.len() != dim {
63 return Err(QuantRS2Error::InvalidInput(format!(
64 "State dimension {} doesn't match 2^{}",
65 state.len(),
66 self.num_qubits
67 )));
68 }
69
70 oracle.grover_oracle(state);
72
73 self.apply_diffusion(state);
75
76 Ok(())
77 }
78
79 fn apply_diffusion(&self, state: &mut Array1<Complex64>) {
81 let avg: Complex64 = state.iter().sum::<Complex64>() / (state.len() as f64);
83
84 for amplitude in state.iter_mut() {
86 *amplitude = Complex64::new(2.0, 0.0) * avg - *amplitude;
87 }
88 }
89}
90
91#[derive(Debug)]
93pub struct CanonicalQAE {
94 pub num_eval_qubits: usize,
96 grover_operator: GroverOperator,
98}
99
100impl CanonicalQAE {
101 pub fn new(num_eval_qubits: usize, num_state_qubits: usize) -> Self {
107 Self {
108 num_eval_qubits,
109 grover_operator: GroverOperator::new(num_state_qubits),
110 }
111 }
112
113 pub fn estimate(
117 &self,
118 oracle: &dyn AmplitudeOracle,
119 ) -> Result<(f64, (f64, f64)), QuantRS2Error> {
120 let mut state = oracle.state_preparation();
122
123 let phase = self.quantum_phase_estimation(&mut state, oracle)?;
125
126 let theta = phase * PI;
128 let amplitude = (theta / 2.0).sin().powi(2);
129
130 let precision = PI / (1 << self.num_eval_qubits) as f64;
132 let lower_bound = ((theta - precision) / 2.0).sin().powi(2).max(0.0);
133 let upper_bound = ((theta + precision) / 2.0).sin().powi(2).min(1.0);
134
135 Ok((amplitude, (lower_bound, upper_bound)))
136 }
137
138 fn quantum_phase_estimation(
140 &self,
141 state: &mut Array1<Complex64>,
142 oracle: &dyn AmplitudeOracle,
143 ) -> Result<f64, QuantRS2Error> {
144 let num_measurements = 1 << self.num_eval_qubits;
148 let mut phase_estimates = Vec::new();
149
150 for k in 0..num_measurements {
151 let mut temp_state = state.clone();
152
153 for _ in 0..k {
155 self.grover_operator.apply(&mut temp_state, oracle)?;
156 }
157
158 let measurement = self.measure_phase(&temp_state);
160 phase_estimates.push(measurement);
161 }
162
163 let avg_phase = phase_estimates.iter().sum::<f64>() / phase_estimates.len() as f64;
165
166 Ok(avg_phase)
167 }
168
169 fn measure_phase(&self, state: &Array1<Complex64>) -> f64 {
171 let mut max_amplitude = 0.0;
173 let mut max_phase = 0.0;
174
175 for amp in state.iter() {
176 let magnitude = amp.norm();
177 if magnitude > max_amplitude {
178 max_amplitude = magnitude;
179 max_phase = amp.arg();
180 }
181 }
182
183 max_phase / (2.0 * PI)
184 }
185}
186
187#[derive(Debug)]
194pub struct MaximumLikelihoodAE {
195 pub schedule: Vec<usize>,
197 grover_operator: GroverOperator,
199}
200
201impl MaximumLikelihoodAE {
202 pub fn new(schedule: Vec<usize>, num_qubits: usize) -> Self {
204 Self {
205 schedule,
206 grover_operator: GroverOperator::new(num_qubits),
207 }
208 }
209
210 pub fn with_exponential_schedule(max_power: usize, num_qubits: usize) -> Self {
212 let schedule: Vec<usize> = (0..=max_power).map(|k| 1 << k).collect();
213 Self::new(schedule, num_qubits)
214 }
215
216 pub fn estimate(
218 &self,
219 oracle: &dyn AmplitudeOracle,
220 shots_per_iteration: usize,
221 ) -> Result<(f64, f64), QuantRS2Error> {
222 let mut observations = Vec::new();
223
224 for &num_grover in &self.schedule {
226 let good_state_count =
227 self.run_measurements(oracle, num_grover, shots_per_iteration)?;
228 let success_probability = good_state_count as f64 / shots_per_iteration as f64;
229 observations.push((num_grover, success_probability));
230 }
231
232 let (estimated_amplitude, fisher_info) = self.maximum_likelihood(&observations)?;
234
235 let std_dev = 1.0 / fisher_info.sqrt();
237
238 Ok((estimated_amplitude, std_dev))
239 }
240
241 fn run_measurements(
243 &self,
244 oracle: &dyn AmplitudeOracle,
245 num_grover: usize,
246 shots: usize,
247 ) -> Result<usize, QuantRS2Error> {
248 let mut good_count = 0;
249
250 for _ in 0..shots {
251 let mut state = oracle.state_preparation();
252
253 for _ in 0..num_grover {
255 self.grover_operator.apply(&mut state, oracle)?;
256 }
257
258 let measurement = self.measure_computational_basis(&state);
260 if oracle.is_good_state(measurement) {
261 good_count += 1;
262 }
263 }
264
265 Ok(good_count)
266 }
267
268 fn measure_computational_basis(&self, state: &Array1<Complex64>) -> usize {
270 let mut rng = thread_rng();
271 let random: f64 = rng.gen();
272
273 let mut cumulative_prob = 0.0;
274 for (idx, amp) in state.iter().enumerate() {
275 cumulative_prob += amp.norm_sqr();
276 if random <= cumulative_prob {
277 return idx;
278 }
279 }
280
281 state.len() - 1
282 }
283
284 fn maximum_likelihood(
286 &self,
287 observations: &[(usize, f64)],
288 ) -> Result<(f64, f64), QuantRS2Error> {
289 let mut best_amplitude = 0.0;
291 let mut best_likelihood = f64::NEG_INFINITY;
292
293 const GRID_POINTS: usize = 1000;
294 for i in 0..=GRID_POINTS {
295 let a = i as f64 / GRID_POINTS as f64;
296 let likelihood = self.compute_log_likelihood(a, observations);
297
298 if likelihood > best_likelihood {
299 best_likelihood = likelihood;
300 best_amplitude = a;
301 }
302 }
303
304 let fisher_info = self.compute_fisher_information(best_amplitude, observations);
306
307 Ok((best_amplitude, fisher_info))
308 }
309
310 fn compute_log_likelihood(&self, amplitude: f64, observations: &[(usize, f64)]) -> f64 {
312 let theta = (amplitude.sqrt()).asin() * 2.0;
313 let mut log_likelihood = 0.0;
314
315 for &(m, p_obs) in observations {
316 let p_theory = ((2.0 * m as f64 + 1.0) * theta / 2.0).sin().powi(2);
318
319 log_likelihood += p_obs * p_theory.ln() + (1.0 - p_obs) * (1.0 - p_theory).ln();
321 }
322
323 log_likelihood
324 }
325
326 fn compute_fisher_information(&self, amplitude: f64, observations: &[(usize, f64)]) -> f64 {
328 let theta = (amplitude.sqrt()).asin() * 2.0;
329 let mut fisher_info = 0.0;
330
331 for &(m, _) in observations {
332 let phase = (2.0 * m as f64 + 1.0) * theta / 2.0;
334 let derivative = (2.0 * m as f64 + 1.0) * phase.sin() * phase.cos();
335
336 let p = phase.sin().powi(2);
337 fisher_info += derivative.powi(2) / (p * (1.0 - p)).max(1e-10);
338 }
339
340 fisher_info
341 }
342}
343
344#[derive(Debug)]
351pub struct IterativeQAE {
352 pub target_accuracy: f64,
354 pub confidence_level: f64,
356 grover_operator: GroverOperator,
358}
359
360impl IterativeQAE {
361 pub fn new(target_accuracy: f64, confidence_level: f64, num_qubits: usize) -> Self {
363 Self {
364 target_accuracy,
365 confidence_level,
366 grover_operator: GroverOperator::new(num_qubits),
367 }
368 }
369
370 pub fn estimate(&mut self, oracle: &dyn AmplitudeOracle) -> Result<IQAEResult, QuantRS2Error> {
372 let mut lower_bound = 0.0;
373 let mut upper_bound = 1.0;
374 let mut num_oracle_calls = 0;
375 let mut iteration = 0;
376
377 while (upper_bound - lower_bound) > self.target_accuracy {
378 let k = self.choose_grover_iterations(lower_bound, upper_bound);
380
381 let success_count = self.run_adaptive_measurements(oracle, k, 100)?;
383 let success_rate = success_count as f64 / 100.0;
384 num_oracle_calls += 100 * (k + 1);
385
386 (lower_bound, upper_bound) =
388 self.update_interval(lower_bound, upper_bound, k, success_rate);
389
390 iteration += 1;
391 }
392
393 let estimated_amplitude = (lower_bound + upper_bound) / 2.0;
394
395 Ok(IQAEResult {
396 amplitude: estimated_amplitude,
397 lower_bound,
398 upper_bound,
399 num_iterations: iteration,
400 num_oracle_calls,
401 })
402 }
403
404 fn choose_grover_iterations(&self, lower: f64, upper: f64) -> usize {
406 let theta_lower = (lower.sqrt()).asin() * 2.0;
407 let theta_upper = (upper.sqrt()).asin() * 2.0;
408 let theta_mid = (theta_lower + theta_upper) / 2.0;
409
410 let k = ((PI / 2.0) / theta_mid - 0.5).max(0.0) as usize;
412
413 k
414 }
415
416 fn run_adaptive_measurements(
418 &self,
419 oracle: &dyn AmplitudeOracle,
420 num_grover: usize,
421 shots: usize,
422 ) -> Result<usize, QuantRS2Error> {
423 let mut success_count = 0;
424
425 for _ in 0..shots {
426 let mut state = oracle.state_preparation();
427
428 for _ in 0..num_grover {
429 self.grover_operator.apply(&mut state, oracle)?;
430 }
431
432 let measurement = self.measure_good_state(&state, oracle);
433 if measurement {
434 success_count += 1;
435 }
436 }
437
438 Ok(success_count)
439 }
440
441 fn measure_good_state(&self, state: &Array1<Complex64>, oracle: &dyn AmplitudeOracle) -> bool {
443 let mut rng = thread_rng();
444 let random: f64 = rng.gen();
445
446 let mut cumulative_prob = 0.0;
447 for (idx, amp) in state.iter().enumerate() {
448 cumulative_prob += amp.norm_sqr();
449 if random <= cumulative_prob {
450 return oracle.is_good_state(idx);
451 }
452 }
453
454 false
455 }
456
457 fn update_interval(
459 &self,
460 lower: f64,
461 upper: f64,
462 k: usize,
463 observed_success_rate: f64,
464 ) -> (f64, f64) {
465 const GRID_SIZE: usize = 100;
469 let mut likelihoods = vec![0.0; GRID_SIZE];
470 let mut max_likelihood = f64::NEG_INFINITY;
471
472 for i in 0..GRID_SIZE {
473 let a = lower + (upper - lower) * i as f64 / (GRID_SIZE - 1) as f64;
474 let theta = (a.sqrt()).asin() * 2.0;
475 let p_theory = ((2 * k + 1) as f64 * theta / 2.0).sin().powi(2);
476
477 let likelihood = -((observed_success_rate - p_theory).powi(2));
479 likelihoods[i] = likelihood;
480 max_likelihood = max_likelihood.max(likelihood);
481 }
482
483 let threshold = max_likelihood - 2.0; let mut new_lower = lower;
486 let mut new_upper = upper;
487
488 for (i, &likelihood) in likelihoods.iter().enumerate() {
489 if likelihood >= threshold {
490 let a = lower + (upper - lower) * i as f64 / (GRID_SIZE - 1) as f64;
491 if a < new_lower || new_lower == lower {
492 new_lower = a;
493 }
494 new_upper = a;
495 }
496 }
497
498 (new_lower, new_upper)
499 }
500}
501
502#[derive(Debug, Clone)]
504pub struct IQAEResult {
505 pub amplitude: f64,
507 pub lower_bound: f64,
509 pub upper_bound: f64,
511 pub num_iterations: usize,
513 pub num_oracle_calls: usize,
515}
516
517impl IQAEResult {
518 pub fn interval_width(&self) -> f64 {
520 self.upper_bound - self.lower_bound
521 }
522
523 pub fn relative_error(&self) -> f64 {
525 self.interval_width() / self.amplitude.max(1e-10)
526 }
527}
528
529pub struct OptionPricingOracle {
534 num_qubits: usize,
535 strike_price: f64,
536 risk_free_rate: f64,
537 volatility: f64,
538 time_to_maturity: f64,
539}
540
541impl OptionPricingOracle {
542 pub const fn new(
544 num_qubits: usize,
545 strike_price: f64,
546 risk_free_rate: f64,
547 volatility: f64,
548 time_to_maturity: f64,
549 ) -> Self {
550 Self {
551 num_qubits,
552 strike_price,
553 risk_free_rate,
554 volatility,
555 time_to_maturity,
556 }
557 }
558
559 fn payoff(&self, price_index: usize) -> f64 {
561 let s_t = self.index_to_price(price_index);
563 (s_t - self.strike_price).max(0.0)
564 }
565
566 fn index_to_price(&self, index: usize) -> f64 {
568 let num_levels = 1 << self.num_qubits;
569 let normalized = index as f64 / num_levels as f64;
570
571 let z = (normalized * 6.0) - 3.0; let s_0 = self.strike_price; s_0 * ((self.risk_free_rate - 0.5 * self.volatility.powi(2)) * self.time_to_maturity
575 + self.volatility * self.time_to_maturity.sqrt() * z)
576 .exp()
577 }
578}
579
580impl AmplitudeOracle for OptionPricingOracle {
581 fn state_preparation(&self) -> Array1<Complex64> {
582 let dim = 1 << self.num_qubits;
583 let mut state = Array1::<Complex64>::zeros(dim);
584
585 let amplitude = Complex64::new(1.0 / (dim as f64).sqrt(), 0.0);
587 state.fill(amplitude);
588
589 state
590 }
591
592 fn grover_oracle(&self, state: &mut Array1<Complex64>) {
593 for (idx, amplitude) in state.iter_mut().enumerate() {
594 if self.is_good_state(idx) {
595 *amplitude = -*amplitude; }
597 }
598 }
599
600 fn num_qubits(&self) -> usize {
601 self.num_qubits
602 }
603
604 fn is_good_state(&self, basis_index: usize) -> bool {
605 self.payoff(basis_index) > 0.0
606 }
607}
608
609#[cfg(test)]
610mod tests {
611 use super::*;
612
613 #[test]
614 fn test_grover_operator() {
615 let grover = GroverOperator::new(2);
616
617 struct TestOracle;
619 impl AmplitudeOracle for TestOracle {
620 fn state_preparation(&self) -> Array1<Complex64> {
621 Array1::from_vec(vec![
622 Complex64::new(0.5, 0.0),
623 Complex64::new(0.5, 0.0),
624 Complex64::new(0.5, 0.0),
625 Complex64::new(0.5, 0.0),
626 ])
627 }
628
629 fn grover_oracle(&self, state: &mut Array1<Complex64>) {
630 state[3] = -state[3]; }
632
633 fn num_qubits(&self) -> usize {
634 2
635 }
636 fn is_good_state(&self, basis_index: usize) -> bool {
637 basis_index == 3
638 }
639 }
640
641 let oracle = TestOracle;
642 let mut state = oracle.state_preparation();
643
644 grover.apply(&mut state, &oracle).unwrap();
645
646 assert!(state[3].norm() > 0.5);
648 }
649
650 #[test]
651 fn test_mlae_exponential_schedule() {
652 let mlae = MaximumLikelihoodAE::with_exponential_schedule(3, 2);
653
654 assert_eq!(mlae.schedule, vec![1, 2, 4, 8]);
655 }
656
657 #[test]
658 fn test_iqae_interval_update() {
659 let iqae = IterativeQAE::new(0.01, 0.95, 2);
660
661 let (lower, upper) = iqae.update_interval(0.0, 1.0, 1, 0.5);
662
663 assert!(upper - lower < 1.0);
665 assert!(lower >= 0.0 && upper <= 1.0);
666 }
667
668 #[test]
669 fn test_option_pricing_oracle() {
670 let oracle = OptionPricingOracle::new(3, 100.0, 0.05, 0.2, 1.0);
671
672 assert_eq!(oracle.num_qubits(), 3);
673
674 let state = oracle.state_preparation();
675 assert_eq!(state.len(), 8);
676
677 let norm: f64 = state.iter().map(|c| c.norm_sqr()).sum();
679 assert!((norm - 1.0).abs() < 1e-6);
680 }
681}