use std::collections::Bound;
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::iter::{FromIterator, repeat_n};
use std::ops::{Div, Mul, Neg, Not, RangeBounds};
use fnv::FnvHashMap as HashMap;
use crate::affine_expression_trait::IntoAffineExpression;
use crate::expression::{Expression, LinearExpression};
use crate::solvers::{ObjectiveDirection, Solver};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Variable {
index: usize,
}
impl IntoAffineExpression for Variable {
type Iter = std::iter::Once<(Self, f64)>;
#[inline]
fn linear_coefficients(self) -> Self::Iter {
std::iter::once((self, 1.))
}
}
impl IntoAffineExpression for Option<Variable> {
#[allow(clippy::type_complexity)]
type Iter = std::iter::Map<std::option::IntoIter<Variable>, fn(Variable) -> (Variable, f64)>;
#[inline]
fn linear_coefficients(self) -> Self::Iter {
self.into_iter().map(|v| (v, 1.))
}
}
impl IntoAffineExpression for &Variable {
type Iter = std::iter::Once<(Variable, f64)>;
#[inline]
fn linear_coefficients(self) -> Self::Iter {
(*self).linear_coefficients()
}
}
impl Variable {
fn at(index: usize) -> Self {
Self { index }
}
}
impl Variable {
pub(super) fn index(&self) -> usize {
self.index
}
}
pub trait FormatWithVars {
fn format_with<FUN>(&self, f: &mut Formatter<'_>, variable_format: FUN) -> std::fmt::Result
where
FUN: FnMut(&mut Formatter<'_>, Variable) -> std::fmt::Result;
fn format_debug(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.format_with(f, |f, var| write!(f, "v{}", var.index()))
}
}
impl FormatWithVars for Variable {
fn format_with<FUN>(&self, f: &mut Formatter<'_>, mut variable_format: FUN) -> std::fmt::Result
where
FUN: FnMut(&mut Formatter<'_>, Variable) -> std::fmt::Result,
{
variable_format(f, *self)
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct VariableDefinition {
pub(crate) min: f64,
pub(crate) max: f64,
pub(crate) initial: Option<f64>,
pub(crate) name: String,
pub(crate) is_integer: bool,
}
impl VariableDefinition {
pub fn new() -> Self {
VariableDefinition {
min: f64::NEG_INFINITY,
max: f64::INFINITY,
initial: None,
name: String::new(),
is_integer: false,
}
}
pub fn integer(mut self) -> Self {
self.is_integer = true;
self
}
pub fn is_integer(&self) -> bool {
self.is_integer
}
pub fn binary(mut self) -> Self {
self.is_integer = true;
self.min = 0.;
self.max = 1.;
self
}
pub fn initial<N: Into<f64>>(mut self, value: N) -> Self {
self.initial = Some(value.into());
self
}
pub fn get_initial(&self) -> Option<f64> {
self.initial
}
pub fn has_initial(&self) -> bool {
self.initial.is_some()
}
pub fn name<S: Into<String>>(mut self, name: S) -> Self {
self.name = name.into();
self
}
pub fn get_name(&self) -> &str {
&self.name
}
pub fn bounds<N: Into<f64> + Copy, B: RangeBounds<N>>(self, bounds: B) -> Self {
self.min(match bounds.start_bound() {
Bound::Included(&x) => x.into(),
Bound::Excluded(&x) => x.into(),
Bound::Unbounded => f64::NEG_INFINITY,
})
.max(match bounds.end_bound() {
Bound::Included(&x) => x.into(),
Bound::Excluded(&x) => x.into(),
Bound::Unbounded => f64::INFINITY,
})
}
pub fn min<N: Into<f64>>(mut self, min: N) -> Self {
self.min = min.into();
self
}
pub fn get_min(&self) -> f64 {
self.min
}
pub fn max<N: Into<f64>>(mut self, max: N) -> Self {
self.max = max.into();
self
}
pub fn get_max(&self) -> f64 {
self.max
}
pub fn clamp<N1: Into<f64>, N2: Into<f64>>(self, min: N1, max: N2) -> Self {
self.min(min).max(max)
}
}
impl Default for VariableDefinition {
fn default() -> Self {
VariableDefinition::new()
}
}
pub fn variable() -> VariableDefinition {
VariableDefinition::default()
}
#[derive(Default, Clone)]
pub struct ProblemVariables {
variables: Vec<VariableDefinition>,
initial_count: usize,
}
impl ProblemVariables {
pub fn new() -> Self {
ProblemVariables {
variables: vec![],
initial_count: 0,
}
}
pub fn add_variable(&mut self) -> Variable {
self.add(variable())
}
pub fn add(&mut self, var_def: VariableDefinition) -> Variable {
let index = self.variables.len();
if var_def.initial.is_some() {
self.initial_count += 1;
}
self.variables.push(var_def);
Variable::at(index)
}
pub fn add_all<T, B: FromIterator<Variable>>(&mut self, var_defs: T) -> B
where
T: IntoIterator<Item = VariableDefinition>,
{
let index = self.variables.len();
self.variables.extend(var_defs);
self.initial_count += self.variables[index..]
.iter()
.filter(|v| v.initial.is_some())
.count();
(index..self.variables.len()).map(Variable::at).collect()
}
pub fn add_vector(&mut self, var_def: VariableDefinition, len: usize) -> Vec<Variable> {
self.add_all(repeat_n(var_def, len))
}
pub fn optimise<E: IntoAffineExpression>(
self,
direction: ObjectiveDirection,
objective: E,
) -> UnsolvedProblem {
let objective = Expression::from_other_affine(objective);
assert!(
objective.linear.coefficients.len() <= self.variables.len(),
"There should not be more variables in the objective function than in the problem. \
You probably used variables from a different problem in this one."
);
UnsolvedProblem {
objective,
direction,
variables: self,
}
}
pub fn maximise<E: IntoAffineExpression>(self, objective: E) -> UnsolvedProblem {
self.optimise(ObjectiveDirection::Maximisation, objective)
}
pub fn minimise<E: IntoAffineExpression>(self, objective: E) -> UnsolvedProblem {
self.optimise(ObjectiveDirection::Minimisation, objective)
}
pub fn iter_variables_with_def(&self) -> impl Iterator<Item = (Variable, &VariableDefinition)> {
self.variables
.iter()
.enumerate()
.map(|(i, def)| (Variable::at(i), def))
}
pub fn len(&self) -> usize {
self.variables.len()
}
pub fn is_empty(&self) -> bool {
self.variables.is_empty()
}
pub fn initial_solution_len(&self) -> usize {
self.initial_count
}
pub fn display<'a, V: FormatWithVars>(&'a self, value: &'a V) -> impl Display + 'a {
DisplayExpr {
problem: self,
value,
}
}
}
struct DisplayExpr<'a, 'b, V> {
problem: &'a ProblemVariables,
value: &'b V,
}
impl<V: FormatWithVars> Display for DisplayExpr<'_, '_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.value.format_with(f, |f, var| {
let mut name = &self.problem.variables[var.index].name;
let alternative_name: String;
if name.is_empty() {
alternative_name = format!("v{}", var.index);
name = &alternative_name;
}
write!(f, "{}", name)
})
}
}
impl IntoIterator for ProblemVariables {
type Item = VariableDefinition;
type IntoIter = std::vec::IntoIter<VariableDefinition>;
fn into_iter(self) -> Self::IntoIter {
self.variables.into_iter()
}
}
pub struct UnsolvedProblem {
pub(crate) objective: Expression,
pub(crate) direction: ObjectiveDirection,
pub(crate) variables: ProblemVariables,
}
impl UnsolvedProblem {
pub fn using<S: Solver>(self, mut solver: S) -> S::Model {
solver.create_model(self)
}
}
impl<N: Into<f64>> Mul<N> for Variable {
type Output = Expression;
fn mul(self, rhs: N) -> Self::Output {
let mut coefficients = HashMap::with_capacity_and_hasher(1, Default::default());
coefficients.insert(self, rhs.into());
Expression {
linear: LinearExpression { coefficients },
constant: 0.0,
}
}
}
impl Mul<Variable> for f64 {
type Output = Expression;
fn mul(self, rhs: Variable) -> Self::Output {
let mut coefficients = HashMap::with_capacity_and_hasher(1, Default::default());
coefficients.insert(rhs, self);
Expression {
linear: LinearExpression { coefficients },
constant: 0.0,
}
}
}
impl Mul<Variable> for i32 {
type Output = Expression;
fn mul(self, rhs: Variable) -> Self::Output {
rhs.mul(f64::from(self))
}
}
impl Div<f64> for Variable {
type Output = Expression;
fn div(self, rhs: f64) -> Self::Output {
self * (1. / rhs)
}
}
impl Div<i32> for Variable {
type Output = Expression;
fn div(self, rhs: i32) -> Self::Output {
self * (1. / f64::from(rhs))
}
}
impl Neg for Variable {
type Output = Expression;
fn neg(self) -> Self::Output {
-Expression::from(self)
}
}
impl Not for Variable {
type Output = Expression;
fn not(self) -> Self::Output {
1. - self
}
}