1mod instantiater;
2pub mod numerical;
3mod qfactor;
4mod result;
5mod target;
6
7pub use instantiater::DataMap;
8pub use instantiater::Instantiater;
9pub use result::InstantiationResult;
10pub use target::InstantiationTarget;
11
12#[cfg(feature = "python")]
13pub use instantiater::python::PyInstantiater;
14
15#[cfg(feature = "python")]
19pub(crate) mod python {
20 use pyo3::prelude::{Bound, PyAnyMethods, PyModule, PyModuleMethods, PyResult};
21
22 pub struct PyInstantiationRegistrar {
24 pub func: fn(parent_module: &Bound<'_, PyModule>) -> PyResult<()>,
26 }
27
28 inventory::collect!(PyInstantiationRegistrar);
29
30 fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
32 let submodule = PyModule::new(parent_module.py(), "instantiation")?;
33
34 for registrar in inventory::iter::<PyInstantiationRegistrar> {
35 (registrar.func)(&submodule)?;
36 }
37
38 parent_module.add_submodule(&submodule)?;
39 parent_module
40 .py()
41 .import("sys")?
42 .getattr("modules")?
43 .set_item("openqudit.instantiation", submodule)?;
44
45 Ok(())
46 }
47
48 inventory::submit!(qudit_core::PyRegistrar { func: register });
49}
50#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::numerical::MinimizingInstantiater;
56 use crate::numerical::functions::HSProblem;
57 use crate::numerical::initializers::Uniform;
59 use crate::numerical::minimizers::LM;
61 use crate::numerical::runners::MultiStartRunner;
62 use faer::mat;
63 use qudit_circuit::ArgumentList;
64 use qudit_circuit::QuditCircuit;
65 use qudit_core::UnitaryMatrix;
66 use qudit_core::c64;
68 use qudit_expr::BraSystemExpression;
69 use qudit_expr::UnitaryExpression;
72 use qudit_expr::library::Controlled;
73 use qudit_expr::library::PGate;
74 use qudit_expr::library::U3Gate;
75 use qudit_expr::library::XGate;
76 use std::sync::Arc;
78
79 #[allow(dead_code)]
80 pub fn build_qsearch_thin_step_circuit(n: usize) -> QuditCircuit {
81 let block_expr = U3Gate()
82 .otimes(U3Gate())
83 .dot(Controlled(XGate(2), [2].into(), None));
84 let mut circ = QuditCircuit::pure(vec![2; n]);
85 for i in 0..n {
86 circ.append(U3Gate(), [i], None);
87 }
88 for _ in 0..2 {
89 for i in 0..(n - 1) {
90 circ.append(block_expr.clone(), [i, i + 1], None);
91 }
92 }
93 circ
94 }
95
96 #[allow(dead_code)]
97 pub fn build_qutrit_thin_step_circuit(n: usize) -> QuditCircuit {
98 let csum = UnitaryExpression::new(
99 "CSUM() {
100 [
101 [ 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
102 [ 0, 1, 0, 0, 0, 0, 0, 0, 0 ],
103 [ 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
104 [ 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
105 [ 0, 0, 0, 1, 0, 0, 0, 0, 0 ],
106 [ 0, 0, 0, 0, 1, 0, 0, 0, 0 ],
107 [ 0, 0, 0, 0, 0, 0, 0, 1, 0 ],
108 [ 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
109 [ 0, 0, 0, 0, 0, 0, 1, 0, 0 ],
110 ]
111 }",
112 );
113
114 let block_expr = PGate(3).otimes(PGate(3)).dot(csum);
115 let mut circ = QuditCircuit::pure(vec![3; n]);
116 for i in 0..n {
117 circ.append(PGate(3), [i], None);
118 }
119 for _ in 0..2 {
120 for i in 0..(n - 1) {
121 circ.append(block_expr.clone(), [i, i + 1], None);
122 }
123 }
124 circ
125 }
126
127 #[allow(dead_code)]
128 pub fn build_dynamic_circuit() -> QuditCircuit {
129 let mut circ: QuditCircuit = QuditCircuit::new([2, 2, 2, 2], [2, 2]);
130
131 circ.zero_initialize([1, 2]);
132
133 for i in 0..4 {
134 circ.append(qudit_expr::library::U3Gate(), [i], None);
135 }
136
137 let block_expr = U3Gate()
138 .otimes(U3Gate())
139 .dot(Controlled(XGate(2), [2].into(), None));
140 circ.append(block_expr.clone(), [1, 2], None);
141 circ.append(
142 block_expr.clone(),
143 [0, 1],
144 ArgumentList::new(vec![None::<f64>.try_into().unwrap(); 6]),
145 );
146 circ.append(block_expr.clone(), [2, 3], None);
147
148 let one_qubit_basis_measurement = BraSystemExpression::new(
149 "OneQMeasure() {
150 [
151 [[ 1, 0, ]],
152 [[ 0, 1, ]],
153 ]
154 }",
155 );
156
157 circ.append(one_qubit_basis_measurement.clone(), ([1], [0]), None);
158 circ.append(one_qubit_basis_measurement, ([2], [1]), None);
159
160 let u3_u3 = U3Gate().otimes(U3Gate());
161 circ.append(
162 UnitaryExpression::classically_multiplex(&[&u3_u3, &u3_u3, &u3_u3, &u3_u3], &[2, 2]),
163 ([0, 3], [0, 1]),
164 None,
165 );
166
167 circ
189 }
190
191 #[test]
192 fn test_lm_minimization_simple() {
193 let circ = build_dynamic_circuit();
195 let target_utry = UnitaryMatrix::new(
208 [2, 2],
209 mat![
210 [
211 c64::new(1.0, 0.0),
212 c64::new(0.0, 0.0),
213 c64::new(0.0, 0.0),
214 c64::new(0.0, 0.0)
215 ],
216 [
217 c64::new(0.0, 0.0),
218 c64::new(1.0, 0.0),
219 c64::new(0.0, 0.0),
220 c64::new(0.0, 0.0)
221 ],
222 [
223 c64::new(0.0, 0.0),
224 c64::new(0.0, 0.0),
225 c64::new(0.0, 0.0),
226 c64::new(1.0, 0.0)
227 ],
228 [
229 c64::new(0.0, 0.0),
230 c64::new(0.0, 0.0),
231 c64::new(1.0, 0.0),
232 c64::new(0.0, 0.0)
233 ],
234 ],
235 );
236 let target = InstantiationTarget::UnitaryMatrix(target_utry);
237
238 let minimizer = LM::default();
240 let initializer = Uniform::default();
242 let runner = MultiStartRunner {
244 minimizer,
245 guess_generator: initializer,
246 num_starts: 16,
247 };
248 let instantiater = MinimizingInstantiater::<_, HSProblem<f64>>::new(runner);
249 let data = std::collections::HashMap::new();
250
251 let circ = Arc::new(circ);
253 let target = Arc::new(target);
254 let data = Arc::new(data);
255 let _result = instantiater.instantiate(circ.clone(), target.clone(), data.clone());
256 let mut success_times = vec![];
257 let mut failure_times = vec![];
258 let n = 1000;
259 for _ in 0..n {
260 let now = std::time::Instant::now();
261 let result = instantiater.instantiate(circ.clone(), target.clone(), data.clone());
262 let elapsed = now.elapsed();
263 if let Some(f) = result.fun {
264 if f < 1e-4 {
267 success_times.push(elapsed);
268 } else {
269 failure_times.push(elapsed);
270 }
271 }
272 }
273 println!("Number of successes: {:?}", success_times.len());
274 println!("Number of failures: {:?}", failure_times.len());
275 if !success_times.is_empty() {
276 let average_success_time = success_times.iter().cloned().sum::<std::time::Duration>()
277 / (success_times.len() as u32);
278 println!("Average success time: {:?}", average_success_time);
279 }
280 if !failure_times.is_empty() {
281 let average_failure_time = failure_times.iter().cloned().sum::<std::time::Duration>()
282 / (failure_times.len() as u32);
283 println!("Average failure time: {:?}", average_failure_time);
284 }
285 let average_time = success_times
286 .iter()
287 .chain(failure_times.iter())
288 .cloned()
289 .sum::<std::time::Duration>()
290 / n;
291 println!("Average overall time: {:?}", average_time);
292 }
293}