Skip to content
/ odesign Public

maunke/odesign

Repository files navigation

odesign

odesign is an optimal design of experiments library written in pure rust. There are at least these following use cases:

  • Fast calculation of optimal designs of arbitrary linear models with custom design bounds and optimalities.
  • Research in area of optimal designs; e.g. I am working on a new optimal design feature selection algorithm, a mixture of SFFS, D-, C- and Measurements-Costs-Optimality, allowing to perform model feature selection and measurements alternating.

Get started

Please have a look at the book on odesign.rs for a high level introduction and theoretical background and at the docs on docs.rs/odesign for the implementation details.

Roadmap

  • Optimalities:
    • D-Optimality
    • C-Optimality
    • Custom Optimality
    • A-Optimality
    • Costs Optimality
  • Design Bounds:
    • Cubic Bounds
    • Custom Bounds
  • Documentation:
    • documentation of the optimal design solver backed by "adaptive grid semidefinite programming for finding optimal designs" (doi: 10.1007/s11222-017-9741-y)
  • Research:
    • New optimal design feature selection algorithm, a mixture of SFFS, D-, C- and Measurements-Costs-Optimality, allowing to perform model feature selection and measurements alternating

Basic Example

Run the example:

cargo run --release --example basic

In short, this is a basic example of an optimal design of the simple polynomial 1 + x within design bounds [-1, +1] and 101 equally distributed grid points as an init design.

use nalgebra::{SVector, Vector1};
use num_dual::DualNum;
use odesign::{
    DOptimality, Feature, FeatureFunction, FeatureSet, LinearModel, OptimalDesign, Result,
};
use std::sync::Arc;

#[derive(Feature)]
#[dimension = 1]
struct Monomial {
    i: i32,
}

impl FeatureFunction<1> for Monomial {
    fn f<D: DualNum<f64>>(&self, x: &SVector<D, 1>) -> D {
        x[0].powi(self.i)
    }
}

// f(x): 1 + x
fn main() -> Result<()> {
    let mut fs = FeatureSet::new();
    let c: Arc<_> = Monomial { i: 0 }.into();
    fs.push(c);
    let c: Arc<_> = Monomial { i: 1 }.into();
    fs.push(c);

    let lm = LinearModel::new(fs.features);

    let optimality: Arc<_> = DOptimality::new(lm.into()).into();
    let lower = Vector1::new(-1.0);
    let upper = Vector1::new(1.0);
    let q = Vector1::new(101);

    let mut od = OptimalDesign::new()
        .with_optimality(optimality)
        .with_bound_args(lower, upper)?
        .with_init_design_grid_args(lower, upper, q)?;
    od.solve();

    println!("{od}");

    Ok(())
}
// Output
// ---------- Design ----------
// Weight  Support Vector
// 0.5000  [ -1.0000 ]
// 0.5000  [ +1.0000 ]
// -------- Statistics --------
// Optimality measure: 1.000000
// No. support vectors: 2
// Iterations: 1
// ----------------------------

Advanced Example

Run the example:

cargo run --release --example polynomial-3dim

As a more complex example please take a look at this 3 dimensional polynomial example with monoms lower than a degree of 3 within a design space of [-1, -1, -1] x [+1, +1, +1] and an initial design grid of 11 x 11 x 11 points.

use nalgebra::{SVector, Vector3};
use num_dual::DualNum;
use odesign::{
    DOptimality, Feature, FeatureFunction, FeatureSet, LinearModel, OptimalDesign, Result,
};
use std::sync::Arc;

#[derive(Feature)]
#[dimension = 3]
struct Monomial {
    i: i32,
    j: i32,
    k: i32,
}

impl FeatureFunction<3> for Monomial {
    fn f<D: DualNum<f64>>(&self, x: &SVector<D, 3>) -> D {
        x[0].powi(self.i) * x[1].powi(self.j) * x[2].powi(self.k)
    }
}

// f(x, y, z):  1 + x + y + z
//              + x * y + x * z + y * y
//              + x ^ 2 + y ^ 2 + z ^ 2
fn main() -> Result<()> {
    let mut fs = FeatureSet::new();
    for i in 0..3 {
        for j in 0..3 {
            for k in 0..3 {
                if i + j + k < 3 {
                    let c: Arc<_> = Monomial { i, j, k }.into();
                    fs.push(c);
                }
            }
        }
    }

    let lm = LinearModel::new(fs.features);

    let q = Vector3::new(11, 11, 11);
    let lower = Vector3::new(-1., -1., -1.);
    let upper = Vector3::new(1., 1., 1.);
    let optimality = Arc::new(DOptimality::new(lm.into()));
    let mut od = OptimalDesign::new()
        .with_optimality(optimality)
        .with_bound_args(lower, upper)?
        .with_init_design_grid_args(lower, upper, q)?;
    od.solve();

    println!("{od}");

    Ok(())
}
// Output
// -------------- Design ---------------
// Weight	Support Vector
// 0.0689	[ -1.0000, -1.0000, -1.0000 ]
// 0.0251	[ -1.0000, -1.0000, +0.0000 ]
// 0.0689	[ -1.0000, -1.0000, +1.0000 ]
// 0.0251	[ -1.0000, +0.0000, -1.0000 ]
// 0.0205	[ -1.0000, +0.0000, +0.0000 ]
// 0.0251	[ -1.0000, +0.0000, +1.0000 ]
// 0.0689	[ -1.0000, +1.0000, -1.0000 ]
// 0.0251	[ -1.0000, +1.0000, +0.0000 ]
// 0.0689	[ -1.0000, +1.0000, +1.0000 ]
// 0.0251	[ +0.0000, -1.0000, -1.0000 ]
// 0.0205	[ +0.0000, -1.0000, +0.0000 ]
// 0.0251	[ +0.0000, -1.0000, +1.0000 ]
// 0.0205	[ +0.0000, +0.0000, -1.0000 ]
// 0.0245	[ +0.0000, +0.0000, +0.0000 ]
// 0.0205	[ +0.0000, +0.0000, +1.0000 ]
// 0.0251	[ +0.0000, +1.0000, -1.0000 ]
// 0.0205	[ +0.0000, +1.0000, +0.0000 ]
// 0.0251	[ +0.0000, +1.0000, +1.0000 ]
// 0.0689	[ +1.0000, -1.0000, -1.0000 ]
// 0.0251	[ +1.0000, -1.0000, +0.0000 ]
// 0.0689	[ +1.0000, -1.0000, +1.0000 ]
// 0.0251	[ +1.0000, +0.0000, -1.0000 ]
// 0.0205	[ +1.0000, +0.0000, +0.0000 ]
// 0.0251	[ +1.0000, +0.0000, +1.0000 ]
// 0.0689	[ +1.0000, +1.0000, -1.0000 ]
// 0.0251	[ +1.0000, +1.0000, +0.0000 ]
// 0.0689	[ +1.0000, +1.0000, +1.0000 ]
// ------------ Statistics -------------
// Optimality measure: 0.474478
// No. support vectors: 27
// Iterations: 2
// -------------------------------------

Community

Mailing lists

Tickets

The tracker on todo.sr.ht/~maunke/odesign is for confirmed bugs and confirmed feature requests only.

Before creating a ticket, search for existing (possibly already fixed) issues, on the docs or in the mailing list archives: odesign-discuss, odesign-devel.

If you cannot find anything describing your issue or if you have a question, ask on one of the the mailing lists first. You will be asked to file a ticket if appropriate.

About

An optimal design of experiments library written in pure Rust. Read-only mirror of https://git.sr.ht/~maunke/odesign. This repository does not accept pull requests. Please send contributions to https://lists.sr.ht/~maunke/odesign-devel.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Contributors