Skip to content

Commit

Permalink
docs: Add examples for Solver/System traits
Browse files Browse the repository at this point in the history
These were previously in the module docs for corresponding modules, but
they were made private during a later restructuring.
  • Loading branch information
pnevyk committed Jan 6, 2022
1 parent 9f2cc5b commit 24028d7
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 114 deletions.
128 changes: 63 additions & 65 deletions src/core/solver.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,72 @@
//! Abstractions for solvers.
//!
//! All solvers implement a common interface defined by the [`Solver`] trait.
//! The essential method is [`next`](Solver::next) which takes variables *x* and
//! computes the next step. Thus it represents one iteration in the process.
//! Repeated call to this method should converge *x* to the solution in
//! successful cases.
//!
//! If you implement a solver, please consider make it a contribution to this
//! library.
//!
//! # Implementing a solver
//!
//! Here is an implementation of a random solver (if such a thing can be called
//! a solver) which randomly generates values in a hope that a solution can be
//! found with enough luck.
//!
//! ```rust
//! use gomez::nalgebra as na;
//! use gomez::core::{Domain, Solver, System, SystemError};
//! use na::{storage::StorageMut, 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: System, R: Rng> Solver<F> for Random<R>
//! where
//! F::Scalar: SampleUniform,
//! {
//! const NAME: &'static str = "Random";
//! type Error = SystemError;
//!
//! fn next<Sx, Sfx>(
//! &mut self,
//! f: &F,
//! dom: &Domain<F::Scalar>,
//! x: &mut Vector<F::Scalar, F::Dim, Sx>,
//! fx: &mut Vector<F::Scalar, F::Dim, Sfx>,
//! ) -> Result<(), Self::Error>
//! where
//! Sx: StorageMut<F::Scalar, F::Dim>,
//! Sfx: StorageMut<F::Scalar, F::Dim>,
//! {
//! // 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 residuals.
//! f.apply_mut(x, fx)?;
//!
//! Ok(())
//! }
//! }
//! ```

use nalgebra::{storage::StorageMut, Vector};

use super::domain::Domain;
use super::system::System;

/// Common interface for all solvers.
///
/// All solvers implement a common interface defined by the [`Solver`] trait.
/// The essential method is [`next`](Solver::next) which takes variables *x* and
/// computes the next step. Thus it represents one iteration in the process.
/// Repeated call to this method should converge *x* to the solution in
/// successful cases.
///
/// If you implement a solver, please consider make it a contribution to this
/// library.
///
/// ## Implementing a solver
///
/// Here is an implementation of a random solver (if such a thing can be called
/// a solver) which randomly generates values in a hope that a solution can be
/// found with enough luck.
///
/// ```rust
/// use gomez::nalgebra as na;
/// use gomez::core::{Domain, Solver, System, SystemError};
/// use na::{storage::StorageMut, 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: System, R: Rng> Solver<F> for Random<R>
/// where
/// F::Scalar: SampleUniform,
/// {
/// const NAME: &'static str = "Random";
/// type Error = SystemError;
///
/// fn next<Sx, Sfx>(
/// &mut self,
/// f: &F,
/// dom: &Domain<F::Scalar>,
/// x: &mut Vector<F::Scalar, F::Dim, Sx>,
/// fx: &mut Vector<F::Scalar, F::Dim, Sfx>,
/// ) -> Result<(), Self::Error>
/// where
/// Sx: StorageMut<F::Scalar, F::Dim>,
/// Sfx: StorageMut<F::Scalar, F::Dim>,
/// {
/// // 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 residuals.
/// f.apply_mut(x, fx)?;
///
/// Ok(())
/// }
/// }
/// ```
pub trait Solver<F: System> {
/// Name of the solver.
const NAME: &'static str;
Expand Down
96 changes: 47 additions & 49 deletions src/core/system.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,3 @@
//! Abstractions and types for defining equation systems.
//!
//! # Defining a system
//!
//! A system is any type that implements [`System`] trait. There are two
//! required associated types (scalar type and dimension type) and two required
//! methods: [`apply_mut`](System::apply_mut) and [`dim`](System::dim).
//!
//! ```rust
//! use gomez::nalgebra as na;
//! use gomez::prelude::*;
//! use na::{Dim, DimName};
//!
//! // A problem is represented by a type.
//! struct Rosenbrock {
//! a: f64,
//! b: f64,
//! }
//!
//! impl System for Rosenbrock {
//! // The numeric type. Usually f64 or f32.
//! type Scalar = f64;
//! // The dimension of the problem. Can be either statically known or dynamic.
//! type Dim = na::U2;
//!
//! // Apply trial values of variables to the system.
//! fn apply_mut<Sx, Sfx>(
//! &self,
//! x: &na::Vector<Self::Scalar, Self::Dim, Sx>,
//! fx: &mut na::Vector<Self::Scalar, Self::Dim, Sfx>,
//! ) -> Result<(), SystemError>
//! where
//! Sx: na::storage::Storage<Self::Scalar, Self::Dim>,
//! Sfx: na::storage::StorageMut<Self::Scalar, Self::Dim>,
//! {
//! // Compute the residuals of all equations.
//! fx[0] = (self.a - x[0]).powi(2);
//! fx[1] = self.b * (x[1] - x[0].powi(2)).powi(2);
//!
//! Ok(())
//! }
//!
//! // Return the actual dimension of the system.
//! fn dim(&self) -> Self::Dim {
//! na::U2::name()
//! }
//! }
//! ```

use nalgebra::{
allocator::Allocator,
storage::{Storage, StorageMut},
Expand All @@ -73,6 +24,53 @@ pub enum SystemError {
}

/// The trait for defining equations systems.
///
/// ## Defining a system
///
/// A system is any type that implements [`System`] trait. There are two
/// required associated types (scalar type and dimension type) and two required
/// methods: [`apply_mut`](System::apply_mut) and [`dim`](System::dim).
///
/// ```rust
/// use gomez::nalgebra as na;
/// use gomez::prelude::*;
/// use na::{Dim, DimName};
///
/// // A problem is represented by a type.
/// struct Rosenbrock {
/// a: f64,
/// b: f64,
/// }
///
/// impl System for Rosenbrock {
/// // The numeric type. Usually f64 or f32.
/// type Scalar = f64;
/// // The dimension of the problem. Can be either statically known or dynamic.
/// type Dim = na::U2;
///
/// // Apply trial values of variables to the system.
/// fn apply_mut<Sx, Sfx>(
/// &self,
/// x: &na::Vector<Self::Scalar, Self::Dim, Sx>,
/// fx: &mut na::Vector<Self::Scalar, Self::Dim, Sfx>,
/// ) -> Result<(), SystemError>
/// where
/// Sx: na::storage::Storage<Self::Scalar, Self::Dim>,
/// Sfx: na::storage::StorageMut<Self::Scalar, Self::Dim>,
/// {
/// // Compute the residuals of all equations.
/// fx[0] = (self.a - x[0]).powi(2);
/// fx[1] = self.b * (x[1] - x[0].powi(2)).powi(2);
///
/// Ok(())
/// }
///
/// // Return the actual dimension of the system.
/// fn dim(&self) -> Self::Dim {
/// na::U2::name()
/// }
/// }
/// ```
pub trait System {
/// Type of the scalar, usually f32 or f64.
type Scalar: RealField;
Expand Down

0 comments on commit 24028d7

Please sign in to comment.