use ;
use ;
/// Common interface for all optimizers.
///
/// All optimizers implement a common interface defined by the [`Optimizer`]
/// trait. The essential method is [`next`](Optimizer::next) which takes
/// variables *x* and computes the next step. Thus it represents one iteration
/// in the process. Repeated call to this method should move *x* towards the
/// minimum in successful cases.
///
/// If you implement an optimizer, please consider make it a contribution to
/// this library.
///
/// ## Implementing an optimizer
///
/// Here is an implementation of a random optimizer (if such a thing can be
/// called an optimizer) which randomly generates values in a hope that
/// eventually goes to the minimum with enough luck.
///
/// ```rust
/// use gomez::nalgebra as na;
/// use gomez::core::*;
/// use na::{storage::StorageMut, IsContiguous, Vector};
/// use rand::Rng;
/// use rand_distr::{uniform::SampleUniform, Distribution, Uniform};
///
/// struct Random<R> {
/// rng: R,
/// }
///
/// impl<R> Random<R> {
/// fn new(rng: R) -> Self {
/// Self { rng }
/// }
/// }
///
/// impl<F: Function, R: Rng> Optimizer<F> for Random<R>
/// where
/// F::Scalar: SampleUniform,
/// {
/// const NAME: &'static str = "Random";
/// type Error = ProblemError;
///
/// fn next<Sx>(
/// &mut self,
/// f: &F,
/// dom: &Domain<F::Scalar>,
/// x: &mut Vector<F::Scalar, F::Dim, Sx>,
/// ) -> Result<F::Scalar, Self::Error>
/// where
/// Sx: StorageMut<F::Scalar, F::Dim> + IsContiguous,
/// {
/// // Randomly sample within the bounds.
/// x.iter_mut().zip(dom.vars().iter()).for_each(|(xi, vi)| {
/// *xi = Uniform::new_inclusive(vi.lower(), vi.upper()).sample(&mut self.rng)
/// });
///
/// // We must compute the value.
/// let value = f.apply(x)?;
/// Ok(value)
/// }
/// }
/// ```