Skip to content

Commit

Permalink
refactor: Breaking out the model.rs file into smaller files
Browse files Browse the repository at this point in the history
  • Loading branch information
dandxy89 committed Nov 13, 2023
1 parent 72dc2e5 commit 9470c48
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 207 deletions.
4 changes: 2 additions & 2 deletions src/lp_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use pest::iterators::Pair;

use crate::{
common::RuleExt,
model::{Constraint, LPDefinition, Objective, SOSClass, Sense, VariableType},
model::{constraint::Constraint, lp_problem::LPProblem, objective::Objective, sense::Sense, sos::SOSClass, variable::VariableType},
Rule,
};

Expand Down Expand Up @@ -84,7 +84,7 @@ fn get_bound(pair: Pair<'_, Rule>) -> Option<(&str, VariableType)> {
#[allow(clippy::wildcard_enum_match_arm)]
/// # Errors
/// Returns an error if the `compose` fails
pub fn compose(pair: Pair<'_, Rule>, mut parsed: LPDefinition) -> anyhow::Result<LPDefinition> {
pub fn compose(pair: Pair<'_, Rule>, mut parsed: LPProblem) -> anyhow::Result<LPProblem> {
match pair.as_rule() {
// Problem Name
Rule::PROBLEM_NAME => return Ok(parsed.with_problem_name(pair.as_str())),
Expand Down
200 changes: 0 additions & 200 deletions src/model.rs

This file was deleted.

34 changes: 34 additions & 0 deletions src/model/coefficient.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use pest::iterators::Pairs;

use crate::{
common::{AsFloat, RuleExt},
Rule,
};

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Coefficient {
pub var_name: String,
pub coefficient: f64,
}

impl TryFrom<Pairs<'_, Rule>> for Coefficient {
type Error = anyhow::Error;

#[allow(clippy::unreachable, clippy::wildcard_enum_match_arm)]
fn try_from(values: Pairs<'_, Rule>) -> anyhow::Result<Self> {
let (mut value, mut var_name) = (1.0, String::new());
for item in values {
match item.as_rule() {
r if r.is_numeric() => {
value *= item.as_float()?;
}
Rule::VARIABLE => {
var_name = item.as_str().to_string();
}
_ => unreachable!("Unexpected rule encountered"),
}
}
Ok(Self { var_name, coefficient: value })
}
}
24 changes: 24 additions & 0 deletions src/model/constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use super::{coefficient::Coefficient, sos::SOSClass};

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Constraint {
Standard { name: String, coefficients: Vec<Coefficient>, sense: String, rhs: f64 },
SOS { name: String, kind: SOSClass, coefficients: Vec<Coefficient> },
}

impl Constraint {
#[must_use]
pub fn name(&self) -> String {
match self {
Self::Standard { name, .. } | Self::SOS { name, .. } => name.to_string(),
}
}

#[must_use]
pub fn coefficients(&self) -> &[Coefficient] {
match self {
Self::Standard { coefficients, .. } | Self::SOS { coefficients, .. } => coefficients,
}
}
}
64 changes: 64 additions & 0 deletions src/model/lp_problem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::collections::{hash_map::Entry, HashMap};

use crate::model::{constraint::Constraint, objective::Objective, sense::Sense, variable::VariableType};

#[derive(Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LPProblem {
pub problem_name: String,
pub problem_sense: Sense,
pub variables: HashMap<String, VariableType>,
pub objectives: Vec<Objective>,
pub constraints: HashMap<String, Constraint>,
}

impl LPProblem {
#[must_use]
pub fn with_problem_name(self, problem_name: &str) -> Self {
Self { problem_name: problem_name.to_string(), ..self }
}

#[must_use]
pub fn with_sense(self, problem_sense: Sense) -> Self {
Self { problem_sense, ..self }
}

pub fn add_variable(&mut self, name: &str) {
if !name.is_empty() {
self.variables.entry(name.to_string()).or_default();
}
}

pub fn set_var_bounds(&mut self, name: &str, kind: VariableType) {
if !name.is_empty() {
match self.variables.entry(name.to_string()) {
Entry::Occupied(k) if matches!(kind, VariableType::SemiContinuous) => {
k.into_mut().set_semi_continuous();
}
Entry::Occupied(k) => *k.into_mut() = kind,
Entry::Vacant(k) => {
k.insert(kind);
}
}
}
}

pub fn add_objective(&mut self, objectives: Vec<Objective>) {
for ob in &objectives {
ob.coefficients.iter().for_each(|c| {
self.add_variable(&c.var_name);
});
}
self.objectives = objectives;
}

pub fn add_constraints(&mut self, constraints: Vec<Constraint>) {
for con in constraints {
let name = if con.name().is_empty() { format!("UnnamedConstraint:{}", self.constraints.len()) } else { con.name() };
con.coefficients().iter().for_each(|c| {
self.add_variable(&c.var_name);
});
self.constraints.entry(name).or_insert(con);
}
}
}
7 changes: 7 additions & 0 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod coefficient;
pub mod constraint;
pub mod lp_problem;
pub mod objective;
pub mod sense;
pub mod sos;
pub mod variable;
8 changes: 8 additions & 0 deletions src/model/objective.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::model::coefficient::Coefficient;

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Objective {
pub name: String,
pub coefficients: Vec<Coefficient>,
}
7 changes: 7 additions & 0 deletions src/model/sense.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[derive(Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Sense {
#[default]
Minimize,
Maximize,
}
20 changes: 20 additions & 0 deletions src/model/sos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::str::FromStr;

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SOSClass {
S1,
S2,
}

impl FromStr for SOSClass {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"s1" | "s1::" => Ok(Self::S1),
"s2" | "s2::" => Ok(Self::S2),
_ => Err(anyhow::anyhow!("Invalid SOS class: {}", s)),
}
}
}
Loading

0 comments on commit 9470c48

Please sign in to comment.