oxicuda_quantum/algorithm/
deutsch_jozsa.rs1use crate::error::{QuantumError, QuantumResult};
25use crate::gates::hadamard::gate_h;
26use crate::statevec::apply_1q::apply_1q_inplace;
27use crate::statevec::state::StateVector;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum FunctionKind {
32 Constant,
34 Balanced,
36}
37
38#[derive(Debug, Clone)]
40pub struct DeutschJozsaResult {
41 pub kind: FunctionKind,
43 pub all_zero_probability: f32,
45}
46
47pub fn deutsch_jozsa<F>(oracle: F, n_qubits: usize) -> QuantumResult<DeutschJozsaResult>
57where
58 F: Fn(usize) -> bool,
59{
60 if n_qubits == 0 || n_qubits > 30 {
61 return Err(QuantumError::InvalidQubitCount { n: n_qubits });
62 }
63
64 let mut sv = StateVector::new_zero_state(n_qubits)?;
66 for q in 0..n_qubits {
67 apply_1q_inplace(&mut sv, q, &gate_h())?;
68 }
69
70 for (x, a) in sv.amps.iter_mut().enumerate() {
72 if oracle(x) {
73 *a = -*a;
74 }
75 }
76
77 for q in 0..n_qubits {
79 apply_1q_inplace(&mut sv, q, &gate_h())?;
80 }
81
82 let all_zero_probability = sv.amps[0].norm_sqr();
84 let kind = if all_zero_probability > 0.5 {
85 FunctionKind::Constant
86 } else {
87 FunctionKind::Balanced
88 };
89
90 Ok(DeutschJozsaResult {
91 kind,
92 all_zero_probability,
93 })
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn constant_zero_is_constant() {
102 let res = deutsch_jozsa(|_| false, 3)
104 .expect("n=3 is within [1, 30] and constant-zero oracle is well-defined");
105 assert_eq!(res.kind, FunctionKind::Constant);
106 assert!(
107 (res.all_zero_probability - 1.0).abs() < 1e-5,
108 "p={}",
109 res.all_zero_probability
110 );
111 }
112
113 #[test]
114 fn constant_one_is_constant() {
115 let res = deutsch_jozsa(|_| true, 4)
117 .expect("n=4 is within [1, 30] and constant-one oracle is well-defined");
118 assert_eq!(res.kind, FunctionKind::Constant);
119 assert!(
120 (res.all_zero_probability - 1.0).abs() < 1e-5,
121 "p={}",
122 res.all_zero_probability
123 );
124 }
125
126 #[test]
127 fn parity_function_is_balanced() {
128 let res = deutsch_jozsa(|x| (x.count_ones() & 1) == 1, 3)
130 .expect("n=3 is within [1, 30] and parity is a well-defined boolean function");
131 assert_eq!(res.kind, FunctionKind::Balanced);
132 assert!(
133 res.all_zero_probability < 1e-5,
134 "p={}",
135 res.all_zero_probability
136 );
137 }
138
139 #[test]
140 fn single_bit_balanced() {
141 let res = deutsch_jozsa(|x| (x & 1) == 1, 3)
143 .expect("n=3 is within [1, 30] and the LSB oracle is well-defined");
144 assert_eq!(res.kind, FunctionKind::Balanced);
145 assert!(
146 res.all_zero_probability < 1e-5,
147 "p={}",
148 res.all_zero_probability
149 );
150 }
151
152 #[test]
153 fn balanced_half_outputs_one() {
154 let res = deutsch_jozsa(|x| x >= 4, 3)
156 .expect("n=3 is within [1, 30] and the threshold oracle is well-defined");
157 assert_eq!(res.kind, FunctionKind::Balanced);
158 }
159
160 #[test]
161 fn single_qubit_constant() {
162 let res = deutsch_jozsa(|_| false, 1)
164 .expect("n=1 is within [1, 30] and the constant-zero oracle is well-defined");
165 assert_eq!(res.kind, FunctionKind::Constant);
166 assert!((res.all_zero_probability - 1.0).abs() < 1e-5);
167 }
168
169 #[test]
170 fn single_qubit_balanced() {
171 let res = deutsch_jozsa(|x| x == 1, 1)
173 .expect("n=1 is within [1, 30] and the identity oracle is well-defined");
174 assert_eq!(res.kind, FunctionKind::Balanced);
175 assert!(res.all_zero_probability < 1e-5);
176 }
177
178 #[test]
179 fn n_qubits_zero_errors() {
180 assert!(deutsch_jozsa(|_| false, 0).is_err());
181 }
182
183 #[test]
184 fn probability_in_range_and_finite() {
185 let res = deutsch_jozsa(|x| (x & 2) != 0, 4)
186 .expect("n=4 is within [1, 30] and the bit-1 mask oracle is well-defined");
187 assert!(res.all_zero_probability.is_finite());
188 assert!(
189 (0.0..=1.0 + 1e-5).contains(&res.all_zero_probability),
190 "p={}",
191 res.all_zero_probability
192 );
193 }
194
195 #[test]
196 fn deterministic() {
197 let a = deutsch_jozsa(|x| (x & 1) == 1, 4)
198 .expect("n=4 is within [1, 30] and the LSB oracle is well-defined");
199 let b = deutsch_jozsa(|x| (x & 1) == 1, 4)
200 .expect("n=4 is within [1, 30] and the LSB oracle is well-defined");
201 assert_eq!(a.kind, b.kind);
202 assert!((a.all_zero_probability - b.all_zero_probability).abs() < 1e-7);
203 }
204}