qudit_inst/numerical/
instantiation.rs

1use std::sync::Arc;
2
3use qudit_circuit::QuditCircuit;
4use qudit_core::ComplexScalar;
5use qudit_core::RealScalar;
6
7use super::Problem;
8use super::Runner;
9use crate::DataMap;
10use crate::Instantiater;
11use crate::InstantiationResult;
12use crate::InstantiationTarget;
13
14pub trait InstantiationProblem<R: RealScalar>: Problem {
15    fn from_instantiation(
16        circuit: Arc<QuditCircuit>,
17        target: Arc<InstantiationTarget<R::C>>,
18        data: Arc<DataMap>,
19    ) -> Self;
20}
21
22#[derive(Clone)]
23pub struct MinimizingInstantiater<R, P> {
24    runner: R,
25    _phantom: std::marker::PhantomData<P>,
26}
27
28impl<R, P> MinimizingInstantiater<R, P> {
29    pub fn new(runner: R) -> Self {
30        Self {
31            runner,
32            _phantom: std::marker::PhantomData::<P>,
33        }
34    }
35}
36
37impl<C, R, P> Instantiater<C> for MinimizingInstantiater<R, P>
38where
39    C: ComplexScalar,
40    P: InstantiationProblem<C::R>,
41    R: Runner<C::R, P>,
42{
43    fn instantiate(
44        &self,
45        circuit: Arc<QuditCircuit>,
46        target: Arc<InstantiationTarget<C>>,
47        data: Arc<DataMap>,
48    ) -> InstantiationResult<C> {
49        let problem = P::from_instantiation(circuit, target, data);
50        self.runner.run(problem).to_instantiation()
51    }
52}
53
54#[cfg(feature = "python")]
55mod python {
56    #![allow(non_snake_case)]
57    use crate::{
58        instantiater::python::{BoxedInstantiater, InstantiaterWrapper},
59        numerical::{
60            functions::HSProblem, initializers::Uniform, minimizers::LM, runners::MultiStartRunner,
61        },
62        python::PyInstantiationRegistrar,
63    };
64
65    use super::*;
66    use pyo3::prelude::*;
67
68    impl InstantiaterWrapper
69        for MinimizingInstantiater<MultiStartRunner<LM<f64>, Uniform<f64>>, HSProblem<f64>>
70    {
71    }
72
73    #[pyfunction]
74    fn DefaultInstantiater() -> BoxedInstantiater {
75        SequentialMultiStartInstantiater(8)
76    }
77
78    #[pyfunction]
79    #[pyo3(signature = (num_starts = 8))]
80    fn SequentialMultiStartInstantiater(num_starts: usize) -> BoxedInstantiater {
81        let minimizer = LM::default();
82        let initializer = Uniform::default();
83        let runner = MultiStartRunner {
84            minimizer,
85            guess_generator: initializer,
86            num_starts,
87        };
88        let instantiater = MinimizingInstantiater::<_, HSProblem<f64>>::new(runner);
89        BoxedInstantiater {
90            inner: Box::new(instantiater),
91        }
92    }
93
94    /// Registers the Instantiaters with the Python module.
95    fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
96        parent_module.add_function(wrap_pyfunction!(DefaultInstantiater, parent_module)?)?;
97        parent_module.add_function(wrap_pyfunction!(
98            SequentialMultiStartInstantiater,
99            parent_module
100        )?)?;
101        Ok(())
102    }
103    inventory::submit!(PyInstantiationRegistrar { func: register });
104}