Skip to content

Commit

Permalink
Use a builder pattern for Settings and support updating settings on a…
Browse files Browse the repository at this point in the history
…n existing Workspace.
  • Loading branch information
ebarnard committed Dec 1, 2017
1 parent b98e07f commit fa4fcd3
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 3 deletions.
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use osqp_sys as ffi;
use std::ptr::null_mut;
use std::slice;

pub use ffi::OSQPSettings as Settings;

mod csc;
pub use csc::CscMatrix;

mod settings;
pub use settings::{LinsysSolver, Settings};

#[allow(non_camel_case_types)]
type float = f64;

Expand Down Expand Up @@ -77,7 +78,9 @@ impl Workspace {
u: u.as_ptr() as *mut float,
};

let inner = ffi::osqp_setup(&data, settings as *const Settings as *mut Settings);
let settings = &settings.inner as *const ffi::OSQPSettings as *mut ffi::OSQPSettings;

let inner = ffi::osqp_setup(&data, settings);
assert!(inner as usize != 0, "osqp setup failure");

Workspace {
Expand Down
163 changes: 163 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use std::mem;

use {Workspace, float, osqp_sys as ffi};

pub enum LinsysSolver {
SuiteSparse,
MklPardiso,
// Prevent exhaustive enum matching
#[doc(hidden)]
__Nonexhaustive,
}

fn u32_to_osqp_int(val: u32) -> ffi::osqp_int {
val as ffi::osqp_int
}

macro_rules! rust_type {
(float) => (float);
(u32) => (u32);
(option_u32) => (Option<u32>);
(bool) => (bool);
(linsys_solver) => (LinsysSolver);
}

macro_rules! convert_rust_type {
(float, $value:expr) => ($value);
(u32, $value:expr) => (u32_to_osqp_int($value));
(option_u32, $value:expr) => (u32_to_osqp_int($value.unwrap_or(0)));
(bool, $value:expr) => ($value as ffi::osqp_int);
(linsys_solver, $value:expr) => (
match $value {
LinsysSolver::SuiteSparse => ffi::SUITESPARSE_LDL_SOLVER,
LinsysSolver::MklPardiso => ffi::MKL_PARDISO_SOLVER,
LinsysSolver::__Nonexhaustive => unreachable!(),
}
);
}

macro_rules! settings {
($workspace:path, $(#[$doc:meta] $name:ident: $typ:ident $([$update_name:ident, $update_ffi:ident])*,)*) => (
pub struct Settings {
pub(crate) inner: ffi::OSQPSettings,
}

impl Settings {
$(
#[$doc]
pub fn $name(mut self, value: rust_type!($typ)) -> Settings {
self.inner.$name = convert_rust_type!($typ, value);
Settings {
inner: self.inner
}
}
)*
}

impl Default for Settings {
fn default() -> Settings {
unsafe {
let mut settings: ffi::OSQPSettings = mem::zeroed();
ffi::set_default_settings(&mut settings);
Settings {
inner: settings
}
}
}
}

impl $workspace {
$($(
#[$doc]
pub fn $update_name(&mut self, value: rust_type!($typ)) {
unsafe {
ffi::$update_ffi(self.inner, convert_rust_type!($typ, value));
}
}
)*)*
}
);
}

settings! {
Workspace,

#[doc = "Set the ADMM step rho."]
rho: float [update_rho, osqp_update_rho],

#[doc = "Set the ADMM step sigma."]
sigma: float,

#[doc = "
Set the number of heuristic data scaling iterations.
If `None` scaling is disabled.
"]
scaling: option_u32,

#[doc = "Enable choosing rho adaptively."]
adaptive_rho: bool,

#[doc = "
Set the number of iterations between rho adaptations.
If `None` it is automatic.
"]
adaptive_rho_interval: option_u32,

#[doc = "
Set the tolerance for adapting rho.
The new rho has to be `x` times larger or `1/x` times smaller than the current rho to trigger a new factorization.
"]
adaptive_rho_tolerance: float,

#[doc = "Set the interval for adapting rho as a fraction of the setup time."]
adaptive_rho_fraction: float,

#[doc = "Set the maximum number of ADMM iterations."]
max_iter: u32 [update_max_iter, osqp_update_max_iter],

#[doc = "Set the absolute convergence tolerance."]
eps_abs: float [update_eps_abs, osqp_update_eps_abs],

#[doc = "Set the relative convergence tolerance."]
eps_rel: float [update_eps_rel, osqp_update_eps_rel],

#[doc = "Set the primal infeasibility tolerance."]
eps_prim_inf: float [update_eps_prim_inf, osqp_update_eps_prim_inf],

#[doc = "Set the dual infeasibility tolerance."]
eps_dual_inf: float [update_eps_dual_inf, osqp_update_eps_dual_inf],

#[doc = "Set the linear solver relaxation parameter."]
alpha: float [update_alpha, osqp_update_alpha],

#[doc = "Set the linear system solver to use."]
linsys_solver: linsys_solver,

#[doc = "Set the polishing regularization parameter."]
delta: float [update_delta, osqp_update_delta],

#[doc = "Enable polishing the ADMM solution."]
polish: bool [update_polish, osqp_update_polish],

#[doc = "Set the number of iterative refinement steps to use when polishing."]
polish_refine_iter: u32 [update_polish_refine_iter, osqp_update_polish_refine_iter],

#[doc = "Enable writing progress to stdout."]
verbose: bool [update_verbose, osqp_update_verbose],

#[doc = "Use scaled termination criteria."]
scaled_termination: bool [update_scaled_termination, osqp_update_scaled_termination],

#[doc = "
Set the number of ADMM iterations between termination checks.
If `None` termination checking is disabled.
"]
check_termination: option_u32 [update_check_termination, osqp_update_check_termination],

#[doc = "Enable warm starting the primal and dual variables from the previous solution."]
warm_start: bool [update_warm_start, osqp_update_warm_start],
}

0 comments on commit fa4fcd3

Please sign in to comment.