diff --git a/Cargo.toml b/Cargo.toml index f121d17..4ba3f01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,15 @@ repository = "https://github.com/schell/casuarius" readme = "README.md" license = "MIT / Apache-2.0" keywords = ["constraint", "simplex", "user", "interface", "layout"] +rust-version = "1.63" + +[features] +default = ["std"] +std = ["rustc-hash/std"] +# FIXME: should be enabled only if std feature is disabled but cargo can not do that yet +hashbrown = ["dep:hashbrown"] [dependencies] -ordered-float = "^1.0" -rustc-hash = "^1.1" +ordered-float = "1.0" +rustc-hash = { version = "1.1", default-features = false } +hashbrown = { version = "0.14", default-features = false, optional = true } diff --git a/src/derive_syntax.rs b/src/derive_syntax.rs index ba8c61d..0f42941 100644 --- a/src/derive_syntax.rs +++ b/src/derive_syntax.rs @@ -9,49 +9,49 @@ macro_rules! derive_syntax_for { } } - impl std::ops::Add for $x { + impl core::ops::Add for $x { type Output = casuarius::Expression<$x>; fn add(self, v: f64) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(self, 1.0)], v) } } - impl std::ops::Add for $x { + impl core::ops::Add for $x { type Output = casuarius::Expression<$x>; fn add(self, v: f32) -> casuarius::Expression<$x> { self.add(v as f64) } } - impl std::ops::Add for $x { + impl core::ops::Add for $x { type Output = casuarius::Expression<$x>; fn add(self, v: u32) -> casuarius::Expression<$x> { self.add(v as f64) } } - impl std::ops::Add<$x> for f64 { + impl core::ops::Add<$x> for f64 { type Output = casuarius::Expression<$x>; fn add(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(v, 1.0)], self) } } - impl std::ops::Add<$x> for f32 { + impl core::ops::Add<$x> for f32 { type Output = casuarius::Expression<$x>; fn add(self, v: $x) -> casuarius::Expression<$x> { (self as f64).add(v) } } - impl std::ops::Add<$x> for u32 { + impl core::ops::Add<$x> for u32 { type Output = casuarius::Expression<$x>; fn add(self, v: $x) -> casuarius::Expression<$x> { (self as f64).add(v) } } - impl std::ops::Add<$x> for $x { + impl core::ops::Add<$x> for $x { type Output = casuarius::Expression<$x>; fn add(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new( @@ -64,21 +64,21 @@ macro_rules! derive_syntax_for { } } - impl std::ops::Add> for $x { + impl core::ops::Add> for $x { type Output = casuarius::Expression<$x>; fn add(self, t: casuarius::Term<$x>) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(self, 1.0), t], 0.0) } } - impl std::ops::Add<$x> for casuarius::Term<$x> { + impl core::ops::Add<$x> for casuarius::Term<$x> { type Output = casuarius::Expression<$x>; fn add(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![self, casuarius::Term::new(v, 1.0)], 0.0) } } - impl std::ops::Add> for $x { + impl core::ops::Add> for $x { type Output = casuarius::Expression<$x>; fn add(self, mut e: casuarius::Expression<$x>) -> casuarius::Expression<$x> { e.terms.push(casuarius::Term::new(self, 1.0)); @@ -86,7 +86,7 @@ macro_rules! derive_syntax_for { } } - impl std::ops::Add<$x> for casuarius::Expression<$x> { + impl core::ops::Add<$x> for casuarius::Expression<$x> { type Output = casuarius::Expression<$x>; fn add(mut self, v: $x) -> casuarius::Expression<$x> { self += v; @@ -94,62 +94,62 @@ macro_rules! derive_syntax_for { } } - impl std::ops::AddAssign<$x> for casuarius::Expression<$x> { + impl core::ops::AddAssign<$x> for casuarius::Expression<$x> { fn add_assign(&mut self, v: $x) { self.terms.push(casuarius::Term::new(v, 1.0)); } } - impl std::ops::Neg for $x { + impl core::ops::Neg for $x { type Output = casuarius::Term<$x>; fn neg(self) -> casuarius::Term<$x> { casuarius::Term::new(self, -1.0) } } - impl std::ops::Sub for $x { + impl core::ops::Sub for $x { type Output = casuarius::Expression<$x>; fn sub(self, v: f64) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(self, 1.0)], -v) } } - impl std::ops::Sub for $x { + impl core::ops::Sub for $x { type Output = casuarius::Expression<$x>; fn sub(self, v: f32) -> casuarius::Expression<$x> { self.sub(v as f64) } } - impl std::ops::Sub for $x { + impl core::ops::Sub for $x { type Output = casuarius::Expression<$x>; fn sub(self, v: u32) -> casuarius::Expression<$x> { self.sub(v as f64) } } - impl std::ops::Sub<$x> for f64 { + impl core::ops::Sub<$x> for f64 { type Output = casuarius::Expression<$x>; fn sub(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(v, -1.0)], self) } } - impl std::ops::Sub<$x> for f32 { + impl core::ops::Sub<$x> for f32 { type Output = casuarius::Expression<$x>; fn sub(self, v: $x) -> casuarius::Expression<$x> { (self as f64).sub(v) } } - impl std::ops::Sub<$x> for u32 { + impl core::ops::Sub<$x> for u32 { type Output = casuarius::Expression<$x>; fn sub(self, v: $x) -> casuarius::Expression<$x> { (self as f64).sub(v) } } - impl std::ops::Sub<$x> for $x { + impl core::ops::Sub<$x> for $x { type Output = casuarius::Expression<$x>; fn sub(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new( @@ -162,21 +162,21 @@ macro_rules! derive_syntax_for { } } - impl std::ops::Sub> for $x { + impl core::ops::Sub> for $x { type Output = casuarius::Expression<$x>; fn sub(self, t: casuarius::Term<$x>) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![casuarius::Term::new(self, 1.0), -t], 0.0) } } - impl std::ops::Sub<$x> for casuarius::Term<$x> { + impl core::ops::Sub<$x> for casuarius::Term<$x> { type Output = casuarius::Expression<$x>; fn sub(self, v: $x) -> casuarius::Expression<$x> { casuarius::Expression::new(vec![self, casuarius::Term::new(v, -1.0)], 0.0) } } - impl std::ops::Sub> for $x { + impl core::ops::Sub> for $x { type Output = casuarius::Expression<$x>; fn sub(self, mut e: casuarius::Expression<$x>) -> casuarius::Expression<$x> { e.negate(); @@ -185,7 +185,7 @@ macro_rules! derive_syntax_for { } } - impl std::ops::Sub<$x> for casuarius::Expression<$x> { + impl core::ops::Sub<$x> for casuarius::Expression<$x> { type Output = casuarius::Expression<$x>; fn sub(mut self, v: $x) -> casuarius::Expression<$x> { self -= v; @@ -193,48 +193,48 @@ macro_rules! derive_syntax_for { } } - impl std::ops::SubAssign<$x> for casuarius::Expression<$x> { + impl core::ops::SubAssign<$x> for casuarius::Expression<$x> { fn sub_assign(&mut self, v: $x) { self.terms.push(casuarius::Term::new(v, -1.0)); } } - impl std::ops::Mul for $x { + impl core::ops::Mul for $x { type Output = casuarius::Term<$x>; fn mul(self, v: f64) -> casuarius::Term<$x> { casuarius::Term::new(self, v) } } - impl std::ops::Mul for $x { + impl core::ops::Mul for $x { type Output = casuarius::Term<$x>; fn mul(self, v: f32) -> casuarius::Term<$x> { self.mul(v as f64) } } - impl std::ops::Mul<$x> for f64 { + impl core::ops::Mul<$x> for f64 { type Output = casuarius::Term<$x>; fn mul(self, v: $x) -> casuarius::Term<$x> { casuarius::Term::new(v, self) } } - impl std::ops::Mul<$x> for f32 { + impl core::ops::Mul<$x> for f32 { type Output = casuarius::Term<$x>; fn mul(self, v: $x) -> casuarius::Term<$x> { (self as f64).mul(v) } } - impl std::ops::Div for $x { + impl core::ops::Div for $x { type Output = casuarius::Term<$x>; fn div(self, v: f64) -> casuarius::Term<$x> { casuarius::Term::new(self, 1.0 / v) } } - impl std::ops::Div for $x { + impl core::ops::Div for $x { type Output = casuarius::Term<$x>; fn div(self, v: f32) -> casuarius::Term<$x> { self.div(v as f64) @@ -272,7 +272,7 @@ macro_rules! derive_syntax_for { #[cfg(test)] mod tests { - use crate::{self as casuarius, Solver, Constrainable}; + use crate::{self as casuarius, Constrainable, Solver}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum VariableX { diff --git a/src/hash_map.rs b/src/hash_map.rs new file mode 100644 index 0000000..29a7c04 --- /dev/null +++ b/src/hash_map.rs @@ -0,0 +1,27 @@ +pub use self::imp::*; + +#[cfg(feature = "std")] +mod imp { + pub use rustc_hash::{FxHashMap, FxHashSet}; + pub use std::collections::hash_map::Entry; +} + +#[cfg(not(feature = "std"))] +mod imp { + use rustc_hash::FxHasher; + + pub use hashbrown::hash_map::Entry; + + pub type FxHashMap = hashbrown::HashMap; + pub type FxHashSet = hashbrown::HashSet; + + #[derive(Copy, Clone, Default)] + pub struct FxBuildHasher; + + impl core::hash::BuildHasher for FxBuildHasher { + type Hasher = FxHasher; + fn build_hasher(&self) -> FxHasher { + rustc_hash::FxHasher::default() + } + } +} diff --git a/src/lib.rs b/src/lib.rs index c5a4d4b..4da1d12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,15 +161,29 @@ //! One thing that this example exposes is that this crate is a rather low level library. It does not have //! any inherent knowledge of user interfaces, directions or boxes. Thus for use in a user interface this //! crate should ideally be wrapped by a higher level API, which is outside the scope of this crate. -use std::collections::hash_map::Entry; -use crate as casuarius; +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; + +use core::fmt; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + use ordered_float::OrderedFloat; +use crate::{ + self as casuarius, + hash_map::{Entry, FxHashMap}, +}; + +mod hash_map; mod operators; mod solver_impl; pub use operators::Constrainable; -use rustc_hash::FxHashMap; pub use strength::{MEDIUM, REQUIRED, STRONG, WEAK}; #[macro_use] @@ -198,7 +212,7 @@ impl Term { /// Construct a new Term from a variable and a coefficient. pub fn new(variable: T, coefficient: f64) -> Term { Term { - variable: variable, + variable, coefficient: coefficient.into(), } } @@ -231,7 +245,7 @@ impl Expression { /// General constructor. Each `Term` in `terms` is part of the sum forming the expression, as well as `constant`. pub fn new(terms: Vec>, constant: f64) -> Expression { Expression { - terms: terms, + terms, constant: constant.into(), } } @@ -250,7 +264,7 @@ impl Constrainable for Expression { where X: Into> + Clone, { - let lhs = PartialConstraint(self.into(), WeightedRelation::EQ(strength::REQUIRED)); + let lhs = PartialConstraint(self, WeightedRelation::EQ(strength::REQUIRED)); let rhs: Expression = x.into(); let (op, s) = lhs.1.into(); Constraint::new(lhs.0 - rhs, op, s) @@ -260,7 +274,7 @@ impl Constrainable for Expression { where X: Into> + Clone, { - let lhs = PartialConstraint(self.into(), WeightedRelation::GE(strength::REQUIRED)); + let lhs = PartialConstraint(self, WeightedRelation::GE(strength::REQUIRED)); let rhs: Expression = x.into(); let (op, s) = lhs.1.into(); Constraint::new(lhs.0 - rhs, op, s) @@ -270,7 +284,7 @@ impl Constrainable for Expression { where X: Into> + Clone, { - let lhs = PartialConstraint(self.into(), WeightedRelation::LE(strength::REQUIRED)); + let lhs = PartialConstraint(self, WeightedRelation::LE(strength::REQUIRED)); let rhs: Expression = x.into(); let (op, s) = lhs.1.into(); Constraint::new(lhs.0 - rhs, op, s) @@ -323,9 +337,9 @@ pub mod strength { /// Create a constraint as a linear combination of STRONG, MEDIUM and WEAK strengths, corresponding to `a` /// `b` and `c` respectively. The result is further multiplied by `w`. pub fn create(a: f64, b: f64, c: f64, w: f64) -> f64 { - (a * w).max(0.0).min(1000.0) * 1_000_000.0 - + (b * w).max(0.0).min(1000.0) * 1000.0 - + (c * w).max(0.0).min(1000.0) + (a * w).clamp(0.0, 1000.0) * 1_000_000.0 + + (b * w).clamp(0.0, 1000.0) * 1000.0 + + (c * w).clamp(0.0, 1000.0) } pub const REQUIRED: f64 = 1_001_001_000.0; pub const STRONG: f64 = 1_000_000.0; @@ -334,7 +348,7 @@ pub mod strength { /// Clips a strength value to the legal range pub fn clip(s: f64) -> f64 { - s.min(REQUIRED).max(0.0) + s.clamp(0.0, REQUIRED) } } @@ -349,8 +363,8 @@ pub enum RelationalOperator { GreaterOrEqual, } -impl std::fmt::Display for RelationalOperator { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Display for RelationalOperator { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { RelationalOperator::LessOrEqual => write!(fmt, "<=")?, RelationalOperator::Equal => write!(fmt, "==")?, @@ -376,7 +390,7 @@ impl Constraint { pub fn new(e: Expression, op: RelationalOperator, strength: f64) -> Constraint { Constraint { expression: e, - op: op, + op, strength: strength.into(), } } @@ -458,15 +472,15 @@ impl Symbol { return *s; } } - if tag.marker.type_() == SymbolType::Slack || tag.marker.type_() == SymbolType::Error { - if row.coefficient_for(tag.marker) < 0.0 { - return tag.marker; - } + if (tag.marker.type_() == SymbolType::Slack || tag.marker.type_() == SymbolType::Error) + && row.coefficient_for(tag.marker) < 0.0 + { + return tag.marker; } - if tag.other.type_() == SymbolType::Slack || tag.other.type_() == SymbolType::Error { - if row.coefficient_for(tag.other) < 0.0 { - return tag.other; - } + if (tag.other.type_() == SymbolType::Slack || tag.other.type_() == SymbolType::Error) + && row.coefficient_for(tag.other) < 0.0 + { + return tag.other; } Symbol::invalid() } @@ -544,7 +558,7 @@ impl Row { fn reverse_sign(&mut self) { *self.constant.as_mut() *= -1.0; - for (_, v) in &mut self.cells { + for v in &mut self.cells.values_mut() { *v.as_mut() *= -1.0; } } @@ -556,7 +570,7 @@ impl Row { Entry::Vacant(_) => unreachable!(), }; *self.constant.as_mut() *= coeff; - for (_, v) in &mut self.cells { + for v in &mut self.cells.values_mut() { *v.as_mut() *= coeff; } } @@ -615,7 +629,7 @@ impl Row { fn get_entering_symbol(&self) -> Symbol { for (symbol, value) in &self.cells { if symbol.type_() != SymbolType::Dummy && *value.as_ref() < 0.0 { - return symbol.clone(); + return *symbol; } } Symbol::invalid() @@ -686,10 +700,7 @@ pub use solver_impl::Solver; mod tests { use super::*; use crate as casuarius; - use std::{ - collections::HashMap, - sync::atomic::{AtomicUsize, Ordering}, - }; + use core::sync::atomic::{AtomicUsize, Ordering}; static NEXT_K: AtomicUsize = AtomicUsize::new(0); @@ -697,37 +708,42 @@ mod tests { pub struct Var(usize); derive_syntax_for!(Var); - impl Var { - pub fn new() -> Var { - Var(NEXT_K.fetch_add(1, Ordering::Relaxed)) + impl Default for Var { + fn default() -> Self { + Self(NEXT_K.fetch_add(1, Ordering::Relaxed)) } } #[test] fn example() { - let mut names = HashMap::new(); - fn print_changes(names: &HashMap, changes: &[(Var, f64)]) { + let mut names = FxHashMap::default(); + + #[cfg(feature = "std")] + fn print_changes(names: &FxHashMap, changes: &[(Var, f64)]) { println!("Changes:"); - for &(ref var, ref val) in changes { + for (var, val) in changes { println!("{}: {}", names[var], val); } } - let window_width = Var::new(); + #[cfg(not(feature = "std"))] + fn print_changes(_: &FxHashMap, _: &[(Var, f64)]) {} + + let window_width = Var::default(); names.insert(window_width, "window_width"); struct Element { left: Var, right: Var, } let box1 = Element { - left: Var::new(), - right: Var::new(), + left: Var::default(), + right: Var::default(), }; names.insert(box1.left, "box1.left"); names.insert(box1.right, "box1.right"); let box2 = Element { - left: Var::new(), - right: Var::new(), + left: Var::default(), + right: Var::default(), }; names.insert(box2.left, "box2.left"); names.insert(box2.right, "box2.right"); @@ -794,8 +810,8 @@ mod tests { impl Point { fn new() -> Point { Point { - x: Var::new(), - y: Var::new(), + x: Var::default(), + y: Var::default(), } } } @@ -981,25 +997,30 @@ mod tests { solver.add_edit_variable(window_width, STRONG).unwrap(); solver.suggest_value(window_width, 300.0).unwrap(); - let mut print_changes = || { - println!("Changes:"); - solver - .fetch_changes() - .iter() - .for_each(|(var, val)| println!("{}: {}", var.0, val)); - }; - print_changes(); - let ww = solver.get_value(window_width); let b1l = solver.get_value(box1.left); let b1r = solver.get_value(box1.right); let b2l = solver.get_value(box2.left); let b2r = solver.get_value(box2.right); - println!("window_width: {}", ww); - println!("box1.left {}", b1l); - println!("box1.right {}", b1r); - println!("box2.left {}", b2l); - println!("box2.right {}", b2r); + + #[cfg(feature = "std")] + { + let mut print_changes = || { + println!("Changes:"); + solver + .fetch_changes() + .iter() + .for_each(|(var, val)| println!("{}: {}", var.0, val)); + }; + print_changes(); + + println!("window_width: {}", ww); + println!("box1.left {}", b1l); + println!("box1.right {}", b1r); + println!("box2.left {}", b2l); + println!("box2.right {}", b2r); + } + assert!(ww >= 0.0, "window_width >= 0.0"); assert_eq!(0.0, b1l, "box1.left ({}) == 0", b1l); assert_eq!(ww, b2r, "box2.right ({}) != ww ({})", b2r, ww); diff --git a/src/operators.rs b/src/operators.rs index a3bc4f7..c7add04 100644 --- a/src/operators.rs +++ b/src/operators.rs @@ -1,38 +1,48 @@ -use crate::{ - Term, - Expression, - Constraint -}; +use crate::{Constraint, Expression, Term}; /// A trait for creating constraints using custom variable types. pub trait Constrainable where Var: Sized, - Self: Sized + Self: Sized, { - fn equal_to(self, x: X) -> Constraint where X: Into> + Clone; - - fn is(self, x: X) -> Constraint where X: Into> + Clone { + fn equal_to(self, x: X) -> Constraint + where + X: Into> + Clone; + + fn is(self, x: X) -> Constraint + where + X: Into> + Clone, + { self.equal_to(x) } - fn greater_than_or_equal_to(self, x: X) -> Constraint where X: Into> + Clone; + fn greater_than_or_equal_to(self, x: X) -> Constraint + where + X: Into> + Clone; - fn is_ge(self, x: X) -> Constraint where X: Into> + Clone { + fn is_ge(self, x: X) -> Constraint + where + X: Into> + Clone, + { self.greater_than_or_equal_to(x) } - fn less_than_or_equal_to(self, x: X) -> Constraint where X: Into> + Clone; + fn less_than_or_equal_to(self, x: X) -> Constraint + where + X: Into> + Clone; - fn is_le(self, x: X) -> Constraint where X: Into> + Clone { + fn is_le(self, x: X) -> Constraint + where + X: Into> + Clone, + { self.less_than_or_equal_to(x) } } - // Term -impl std::ops::Mul for Term { +impl core::ops::Mul for Term { type Output = Term; fn mul(mut self, v: f64) -> Term { self *= v; @@ -40,26 +50,26 @@ impl std::ops::Mul for Term { } } -impl std::ops::MulAssign for Term { +impl core::ops::MulAssign for Term { fn mul_assign(&mut self, v: f64) { *(self.coefficient.as_mut()) *= v; } } -impl std::ops::Mul for Term { +impl core::ops::Mul for Term { type Output = Term; fn mul(self, v: f32) -> Term { self.mul(v as f64) } } -impl std::ops::MulAssign for Term { +impl core::ops::MulAssign for Term { fn mul_assign(&mut self, v: f32) { self.mul_assign(v as f64) } } -impl std::ops::Mul> for f64 { +impl core::ops::Mul> for f64 { type Output = Term; fn mul(self, mut t: Term) -> Term { *(t.coefficient.as_mut()) *= self; @@ -67,14 +77,14 @@ impl std::ops::Mul> for f64 { } } -impl std::ops::Mul> for f32 { +impl core::ops::Mul> for f32 { type Output = Term; fn mul(self, t: Term) -> Term { (self as f64).mul(t) } } -impl std::ops::Div for Term { +impl core::ops::Div for Term { type Output = Term; fn div(mut self, v: f64) -> Term { self /= v; @@ -82,61 +92,61 @@ impl std::ops::Div for Term { } } -impl std::ops::DivAssign for Term { +impl core::ops::DivAssign for Term { fn div_assign(&mut self, v: f64) { *(self.coefficient.as_mut()) /= v; } } -impl std::ops::Div for Term { +impl core::ops::Div for Term { type Output = Term; fn div(self, v: f32) -> Term { self.div(v as f64) } } -impl std::ops::DivAssign for Term { +impl core::ops::DivAssign for Term { fn div_assign(&mut self, v: f32) { self.div_assign(v as f64) } } -impl std::ops::Add for Term { +impl core::ops::Add for Term { type Output = Expression; fn add(self, v: f64) -> Expression { Expression::new(vec![self], v) } } -impl std::ops::Add for Term { +impl core::ops::Add for Term { type Output = Expression; fn add(self, v: f32) -> Expression { self.add(v as f64) } } -impl std::ops::Add> for f64 { +impl core::ops::Add> for f64 { type Output = Expression; fn add(self, t: Term) -> Expression { Expression::new(vec![t], self) } } -impl std::ops::Add> for f32 { +impl core::ops::Add> for f32 { type Output = Expression; fn add(self, t: Term) -> Expression { (self as f64).add(t) } } -impl std::ops::Add> for Term { +impl core::ops::Add> for Term { type Output = Expression; fn add(self, t: Term) -> Expression { Expression::new(vec![self, t], 0.0) } } -impl std::ops::Add> for Term { +impl core::ops::Add> for Term { type Output = Expression; fn add(self, mut e: Expression) -> Expression { e.terms.push(self); @@ -144,7 +154,7 @@ impl std::ops::Add> for Term { } } -impl std::ops::Add> for Expression { +impl core::ops::Add> for Expression { type Output = Expression; fn add(mut self, t: Term) -> Expression { self += t; @@ -152,13 +162,13 @@ impl std::ops::Add> for Expression { } } -impl std::ops::AddAssign> for Expression { +impl core::ops::AddAssign> for Expression { fn add_assign(&mut self, t: Term) { self.terms.push(t); } } -impl std::ops::Neg for Term { +impl core::ops::Neg for Term { type Output = Term; fn neg(mut self) -> Term { *(self.coefficient.as_mut()) = -(self.coefficient.into_inner()); @@ -166,42 +176,42 @@ impl std::ops::Neg for Term { } } -impl std::ops::Sub for Term { +impl core::ops::Sub for Term { type Output = Expression; fn sub(self, v: f64) -> Expression { Expression::new(vec![self], -v) } } -impl std::ops::Sub for Term { +impl core::ops::Sub for Term { type Output = Expression; fn sub(self, v: f32) -> Expression { self.sub(v as f64) } } -impl std::ops::Sub> for f64 { +impl core::ops::Sub> for f64 { type Output = Expression; fn sub(self, t: Term) -> Expression { Expression::new(vec![-t], self) } } -impl std::ops::Sub> for f32 { +impl core::ops::Sub> for f32 { type Output = Expression; fn sub(self, t: Term) -> Expression { (self as f64).sub(t) } } -impl std::ops::Sub> for Term { +impl core::ops::Sub> for Term { type Output = Expression; fn sub(self, t: Term) -> Expression { Expression::new(vec![self, -t], 0.0) } } -impl std::ops::Sub> for Term { +impl core::ops::Sub> for Term { type Output = Expression; fn sub(self, mut e: Expression) -> Expression { e.negate(); @@ -210,7 +220,7 @@ impl std::ops::Sub> for Term { } } -impl std::ops::Sub> for Expression { +impl core::ops::Sub> for Expression { type Output = Expression; fn sub(mut self, t: Term) -> Expression { self -= t; @@ -218,7 +228,7 @@ impl std::ops::Sub> for Expression { } } -impl std::ops::SubAssign> for Expression { +impl core::ops::SubAssign> for Expression { fn sub_assign(&mut self, t: Term) { self.terms.push(-t); } @@ -226,15 +236,15 @@ impl std::ops::SubAssign> for Expression { // Expression -impl std::ops::Mul for Expression { +impl core::ops::Mul for Expression { type Output = Expression; fn mul(mut self, v: f64) -> Expression { - self *= v.clone(); + self *= v; self } } -impl std::ops::MulAssign for Expression { +impl core::ops::MulAssign for Expression { fn mul_assign(&mut self, v: f64) { *(self.constant.as_mut()) *= v; for t in &mut self.terms { @@ -243,7 +253,7 @@ impl std::ops::MulAssign for Expression { } } -impl std::ops::Mul> for f64 { +impl core::ops::Mul> for f64 { type Output = Expression; fn mul(self, mut e: Expression) -> Expression { *(e.constant.as_mut()) *= self; @@ -254,7 +264,7 @@ impl std::ops::Mul> for f64 { } } -impl std::ops::Div for Expression { +impl core::ops::Div for Expression { type Output = Expression; fn div(mut self, v: f64) -> Expression { self /= v; @@ -262,7 +272,7 @@ impl std::ops::Div for Expression { } } -impl std::ops::DivAssign for Expression { +impl core::ops::DivAssign for Expression { fn div_assign(&mut self, v: f64) { *(self.constant.as_mut()) /= v; for t in &mut self.terms { @@ -271,7 +281,7 @@ impl std::ops::DivAssign for Expression { } } -impl std::ops::Add for Expression { +impl core::ops::Add for Expression { type Output = Expression; fn add(mut self, v: f64) -> Expression { self += v; @@ -279,13 +289,13 @@ impl std::ops::Add for Expression { } } -impl std::ops::AddAssign for Expression { +impl core::ops::AddAssign for Expression { fn add_assign(&mut self, v: f64) { *(self.constant.as_mut()) += v; } } -impl std::ops::Add> for f64 { +impl core::ops::Add> for f64 { type Output = Expression; fn add(self, mut e: Expression) -> Expression { *(e.constant.as_mut()) += self; @@ -293,7 +303,7 @@ impl std::ops::Add> for f64 { } } -impl std::ops::Add> for Expression { +impl core::ops::Add> for Expression { type Output = Expression; fn add(mut self, e: Expression) -> Expression { self += e; @@ -301,14 +311,14 @@ impl std::ops::Add> for Expression { } } -impl std::ops::AddAssign> for Expression { +impl core::ops::AddAssign> for Expression { fn add_assign(&mut self, mut e: Expression) { self.terms.append(&mut e.terms); *(self.constant.as_mut()) += e.constant.into_inner(); } } -impl std::ops::Neg for Expression { +impl core::ops::Neg for Expression { type Output = Expression; fn neg(mut self) -> Expression { self.negate(); @@ -316,7 +326,7 @@ impl std::ops::Neg for Expression { } } -impl std::ops::Sub for Expression { +impl core::ops::Sub for Expression { type Output = Expression; fn sub(mut self, v: f64) -> Expression { self -= v; @@ -324,13 +334,14 @@ impl std::ops::Sub for Expression { } } -impl std::ops::SubAssign for Expression { +impl core::ops::SubAssign for Expression { fn sub_assign(&mut self, v: f64) { *(self.constant.as_mut()) -= v; } } -impl std::ops::Sub> for f64 { +#[allow(clippy::suspicious_arithmetic_impl)] +impl core::ops::Sub> for f64 { type Output = Expression; fn sub(self, mut e: Expression) -> Expression { e.negate(); @@ -339,7 +350,7 @@ impl std::ops::Sub> for f64 { } } -impl std::ops::Sub> for Expression { +impl core::ops::Sub> for Expression { type Output = Expression; fn sub(mut self, e: Expression) -> Expression { self -= e; @@ -347,7 +358,8 @@ impl std::ops::Sub> for Expression { } } -impl std::ops::SubAssign> for Expression { +impl core::ops::SubAssign> for Expression { + #[allow(clippy::suspicious_op_assign_impl)] fn sub_assign(&mut self, mut e: Expression) { e.negate(); self.terms.append(&mut e.terms); @@ -356,84 +368,84 @@ impl std::ops::SubAssign> for Expression { } macro_rules! derive_expr_ops_for { - ( $x:ty ) => { - impl std::ops::Mul<$x> for Expression { - type Output = Expression; - fn mul(self, v: $x) -> Expression { - self.mul(v as f64) - } - } + ( $x:ty ) => { + impl core::ops::Mul<$x> for Expression { + type Output = Expression; + fn mul(self, v: $x) -> Expression { + self.mul(v as f64) + } + } - impl std::ops::MulAssign<$x> for Expression { - fn mul_assign(&mut self, v: $x) { - let v2 = v as f64; - *(self.constant.as_mut()) *= v2; - for t in &mut self.terms { - *t = t.clone() * v2; + impl core::ops::MulAssign<$x> for Expression { + fn mul_assign(&mut self, v: $x) { + let v2 = v as f64; + *(self.constant.as_mut()) *= v2; + for t in &mut self.terms { + *t = t.clone() * v2; + } + } } - } - } - impl std::ops::Mul> for $x { - type Output = Expression; - fn mul(self, e: Expression) -> Expression { - (self as f64).mul(e) - } - } + impl core::ops::Mul> for $x { + type Output = Expression; + fn mul(self, e: Expression) -> Expression { + (self as f64).mul(e) + } + } - impl std::ops::Div<$x> for Expression { - type Output = Expression; - fn div(self, v: $x) -> Expression { - self.div(v as f64) - } - } + impl core::ops::Div<$x> for Expression { + type Output = Expression; + fn div(self, v: $x) -> Expression { + self.div(v as f64) + } + } - impl std::ops::DivAssign<$x> for Expression { - fn div_assign(&mut self, v: $x) { - self.div_assign(v as f64) - } - } + impl core::ops::DivAssign<$x> for Expression { + fn div_assign(&mut self, v: $x) { + self.div_assign(v as f64) + } + } - impl std::ops::Add<$x> for Expression { - type Output = Expression; - fn add(self, v: $x) -> Expression { - self.add(v as f64) - } - } + impl core::ops::Add<$x> for Expression { + type Output = Expression; + fn add(self, v: $x) -> Expression { + self.add(v as f64) + } + } - impl std::ops::AddAssign<$x> for Expression { - fn add_assign(&mut self, v: $x) { - self.add_assign(v as f64) - } - } + impl core::ops::AddAssign<$x> for Expression { + fn add_assign(&mut self, v: $x) { + self.add_assign(v as f64) + } + } - impl std::ops::Add> for $x { - type Output = Expression; - fn add(self, e: Expression) -> Expression { - (self as f64).add(e) - } - } + impl core::ops::Add> for $x { + type Output = Expression; + fn add(self, e: Expression) -> Expression { + (self as f64).add(e) + } + } - impl std::ops::Sub<$x> for Expression { - type Output = Expression; - fn sub(self, v: $x) -> Expression { - self.sub(v as f64) - } - } + impl core::ops::Sub<$x> for Expression { + type Output = Expression; + fn sub(self, v: $x) -> Expression { + self.sub(v as f64) + } + } - impl std::ops::Sub> for $x { - type Output = Expression; - fn sub(self, e: Expression) -> Expression { - (self as f64).sub(e) - } - } + impl core::ops::Sub> for $x { + type Output = Expression; + fn sub(self, e: Expression) -> Expression { + (self as f64).sub(e) + } + } - impl std::ops::SubAssign<$x> for Expression { - fn sub_assign(&mut self, v: $x) { - self.sub_assign(v as f64) - } - } - }; + impl core::ops::SubAssign<$x> for Expression { + fn sub_assign(&mut self, v: $x) { + self.sub_assign(v as f64) + } + } + }; } derive_expr_ops_for!(f32); diff --git a/src/solver_impl.rs b/src/solver_impl.rs index 2061a47..881ec41 100644 --- a/src/solver_impl.rs +++ b/src/solver_impl.rs @@ -1,17 +1,14 @@ use crate::{ + hash_map::{Entry, FxHashMap, FxHashSet}, near_zero, strength, AddConstraintError, AddEditVariableError, Constraint, Expression, InternalSolverError, RelationalOperator, RemoveConstraintError, RemoveEditVariableError, Row, SuggestValueError, Symbol, SymbolType, Tag, Term, }; -use std::{ - any::Any, - collections::hash_map::Entry, - fmt::Debug, - hash::Hash, -}; +use core::{any::Any, fmt::Debug, hash::Hash}; -use rustc_hash::{FxHashMap, FxHashSet}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; #[derive(Clone, Debug)] struct EditInfo { @@ -165,7 +162,7 @@ impl Solver { // If the marker is basic, simply drop the row. Otherwise, // pivot the marker into the basis and then drop the row. - if let None = self.rows.remove(&tag.marker) { + if self.rows.remove(&tag.marker).is_none() { let (leaving, mut row) = self.get_marker_leaving_row(tag.marker).ok_or( RemoveConstraintError::InternalSolverError("Failed to find leaving row."), )?; @@ -254,7 +251,7 @@ impl Solver { self.edits.insert( v.clone(), EditInfo { - tag: self.cns[&cn].clone(), + tag: self.cns[&cn], constraint: cn, constant: 0.0, }, @@ -346,7 +343,7 @@ impl Solver { } self.dual_optimise() .map_err(|e| SuggestValueError::InternalSolverError(e.0))?; - return Ok(()); + Ok(()) } fn var_changed(&mut self, v: T) { @@ -370,7 +367,7 @@ impl Solver { } self.public_changes.clear(); for v in &self.changed { - if let Some(var_data) = self.var_data.get_mut(&v) { + if let Some(var_data) = self.var_data.get_mut(v) { let new_value = self .rows .get(&var_data.1) @@ -417,7 +414,7 @@ impl Solver { let s = Symbol(*id_tick, SymbolType::External); var_for_symbol.insert(s, v); *id_tick += 1; - (std::f64::NAN, s, 0) + (f64::NAN, s, 0) }); value.2 += 1; value.1 @@ -550,7 +547,7 @@ impl Solver { } // Remove the artificial row from the tableau - for (_, row) in &mut self.rows { + for row in self.rows.values_mut() { row.remove(art); } self.objective @@ -617,9 +614,7 @@ impl Solver { /// an iteration of the dual simplex method to make the solution both /// optimal and feasible. fn dual_optimise(&mut self) -> Result<(), InternalSolverError> { - while !self.infeasible_rows.is_empty() { - let leaving = self.infeasible_rows.pop().unwrap(); - + while let Some(leaving) = self.infeasible_rows.pop() { let row = if let Entry::Occupied(entry) = self.rows.entry(leaving) { if *entry.get().constant.as_ref() < 0.0 { Some(entry.remove()) @@ -657,7 +652,7 @@ impl Solver { /// Could return an External symbol fn get_dual_entering_symbol(&self, row: &Row) -> Symbol { let mut entering = Symbol::invalid(); - let mut ratio = std::f64::INFINITY; + let mut ratio = f64::INFINITY; let objective = self .objective .as_ref() @@ -684,7 +679,7 @@ impl Solver { /// the objective function is unbounded. /// Never returns a row for an External symbol fn get_leaving_row(&mut self, entering: Symbol) -> Option<(Symbol, Row)> { - let mut ratio = std::f64::INFINITY; + let mut ratio = f64::INFINITY; let mut found = None; for (symbol, row) in &self.rows { if symbol.type_() != SymbolType::External { @@ -719,7 +714,7 @@ impl Solver { /// will be returned. This indicates an internal solver error since /// the marker *should* exist somewhere in the tableau. fn get_marker_leaving_row(&mut self, marker: Symbol) -> Option<(Symbol, Row)> { - let mut r1 = std::f64::INFINITY; + let mut r1 = f64::INFINITY; let mut r2 = r1; let mut first = None; let mut second = None;