Skip to main content

rooc/pipe/
pipe_definitions.rs

1use crate::parser::model_transformer::Model;
2use crate::parser::model_transformer::TransformError;
3use crate::parser::pre_model::PreModel;
4#[allow(unused_imports)]
5use crate::prelude::*;
6use crate::primitives::Constant;
7use crate::runtime_builtin::RoocFunction;
8use crate::solvers::IntOrBoolValue;
9use crate::solvers::{
10    CanonicalTransformError, OptimalTableau, OptimalTableauWithSteps, SimplexError, Tableau,
11};
12use crate::solvers::{LpSolution, SolverError};
13use crate::transformers::LinearModel;
14use crate::transformers::LinearizationError;
15use crate::transformers::StandardLinearModel;
16use crate::utils::CompilationError;
17use crate::{MILPValue, RoocParser, match_pipe_data_to};
18use indexmap::IndexMap;
19use std::fmt::Display;
20
21/// The data that can be passed between pipes
22#[derive(Debug, Clone)]
23pub enum PipeableData {
24    String(String),
25    Parser(RoocParser),
26    PreModel(PreModel),
27    Model(Model),
28    LinearModel(LinearModel),
29    StandardLinearModel(StandardLinearModel),
30    Tableau(Tableau),
31    OptimalTableau(OptimalTableau),
32    OptimalTableauWithSteps(OptimalTableauWithSteps),
33    BinarySolution(LpSolution<bool>),
34    IntegerBinarySolution(LpSolution<IntOrBoolValue>),
35    RealSolution(LpSolution<f64>),
36    MILPSolution(LpSolution<MILPValue>),
37}
38
39#[allow(clippy::result_large_err)]
40#[allow(clippy::wrong_self_convention)]
41impl PipeableData {
42    /// Gets the type of the data
43    pub fn get_type(&self) -> PipeDataType {
44        match self {
45            PipeableData::String(_) => PipeDataType::String,
46            PipeableData::Parser(_) => PipeDataType::Parser,
47            PipeableData::Model(_) => PipeDataType::Model,
48            PipeableData::LinearModel(_) => PipeDataType::LinearModel,
49            PipeableData::StandardLinearModel(_) => PipeDataType::StandardLinearModel,
50            PipeableData::Tableau(_) => PipeDataType::Tableau,
51            PipeableData::PreModel(_) => PipeDataType::PreModel,
52            PipeableData::OptimalTableau(_) => PipeDataType::OptimalTableau,
53            PipeableData::OptimalTableauWithSteps(_) => PipeDataType::OptimalTableauWithSteps,
54            PipeableData::BinarySolution(_) => PipeDataType::BinarySolution,
55            PipeableData::IntegerBinarySolution(_) => PipeDataType::IntegerBinarySolution,
56            PipeableData::RealSolution(_) => PipeDataType::RealSolution,
57            PipeableData::MILPSolution(_) => PipeDataType::MILPSolution,
58        }
59    }
60    //TODO make this macros
61    pub fn to_string_data(self) -> Result<String, PipeError> {
62        match_pipe_data_to!(self, String, String)
63    }
64    pub fn to_parser(self) -> Result<RoocParser, PipeError> {
65        match_pipe_data_to!(self, Parser, Parser)
66    }
67    pub fn to_pre_model(self) -> Result<PreModel, PipeError> {
68        match_pipe_data_to!(self, PreModel, PreModel)
69    }
70    pub fn to_model(self) -> Result<Model, PipeError> {
71        match_pipe_data_to!(self, Model, Model)
72    }
73    pub fn to_linear_model(self) -> Result<LinearModel, PipeError> {
74        match_pipe_data_to!(self, LinearModel, LinearModel)
75    }
76    pub fn to_standard_linear_model(self) -> Result<StandardLinearModel, PipeError> {
77        match_pipe_data_to!(self, StandardLinearModel, StandardLinearModel)
78    }
79    pub fn to_tableau(self) -> Result<Tableau, PipeError> {
80        match_pipe_data_to!(self, Tableau, Tableau)
81    }
82    pub fn to_optimal_tableau(self) -> Result<OptimalTableau, PipeError> {
83        match_pipe_data_to!(self, OptimalTableau, OptimalTableau)
84    }
85    pub fn to_optimal_tableau_with_steps(self) -> Result<OptimalTableauWithSteps, PipeError> {
86        match_pipe_data_to!(self, OptimalTableauWithSteps, OptimalTableauWithSteps)
87    }
88    pub fn to_binary_solution(self) -> Result<LpSolution<bool>, PipeError> {
89        match_pipe_data_to!(self, BinarySolution, BinarySolution)
90    }
91    pub fn to_real_solution(self) -> Result<LpSolution<f64>, PipeError> {
92        match_pipe_data_to!(self, RealSolution, RealSolution)
93    }
94    pub fn to_milp_solution(self) -> Result<LpSolution<MILPValue>, PipeError> {
95        match_pipe_data_to!(self, MILPSolution, MILPSolution)
96    }
97
98    pub fn to_integer_binary_solution(self) -> Result<LpSolution<IntOrBoolValue>, PipeError> {
99        match_pipe_data_to!(self, IntegerBinarySolution, IntegerBinarySolution)
100    }
101    pub fn as_string_data(&self) -> Result<&String, PipeError> {
102        match_pipe_data_to!(self, String, String)
103    }
104    pub fn as_binary_solution(&self) -> Result<&LpSolution<bool>, PipeError> {
105        match_pipe_data_to!(self, BinarySolution, BinarySolution)
106    }
107    pub fn as_integer_binary_solution(&self) -> Result<&LpSolution<IntOrBoolValue>, PipeError> {
108        match_pipe_data_to!(self, IntegerBinarySolution, IntegerBinarySolution)
109    }
110    pub fn as_real_solution(&self) -> Result<&LpSolution<f64>, PipeError> {
111        match_pipe_data_to!(self, RealSolution, RealSolution)
112    }
113
114    pub fn as_parser(&self) -> Result<&RoocParser, PipeError> {
115        match_pipe_data_to!(self, Parser, Parser)
116    }
117    pub fn as_pre_model(&self) -> Result<&PreModel, PipeError> {
118        match_pipe_data_to!(self, PreModel, PreModel)
119    }
120    pub fn as_model(&self) -> Result<&Model, PipeError> {
121        match_pipe_data_to!(self, Model, Model)
122    }
123    pub fn as_linear_model(&self) -> Result<&LinearModel, PipeError> {
124        match_pipe_data_to!(self, LinearModel, LinearModel)
125    }
126    pub fn as_standard_linear_model(&self) -> Result<&StandardLinearModel, PipeError> {
127        match_pipe_data_to!(self, StandardLinearModel, StandardLinearModel)
128    }
129    pub fn as_tableau(&self) -> Result<&Tableau, PipeError> {
130        match_pipe_data_to!(self, Tableau, Tableau)
131    }
132    pub fn as_optimal_tableau(&self) -> Result<&OptimalTableau, PipeError> {
133        match_pipe_data_to!(self, OptimalTableau, OptimalTableau)
134    }
135}
136
137impl Display for PipeableData {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        match self {
140            PipeableData::String(s) => write!(f, "{}", s),
141            PipeableData::Parser(p) => write!(f, "{}", p.source),
142            PipeableData::PreModel(p) => write!(f, "{}", p),
143            PipeableData::Model(m) => write!(f, "{}", m),
144            PipeableData::LinearModel(m) => write!(f, "{}", m),
145            PipeableData::StandardLinearModel(m) => write!(f, "{}", m),
146            PipeableData::Tableau(t) => write!(f, "{}", t),
147            PipeableData::OptimalTableau(t) => write!(f, "{}", t),
148            PipeableData::OptimalTableauWithSteps(t) => write!(f, "{}", t),
149            PipeableData::BinarySolution(s) => write!(f, "{}", s),
150            PipeableData::IntegerBinarySolution(s) => write!(f, "{}", s),
151            PipeableData::RealSolution(s) => write!(f, "{}", s),
152            PipeableData::MILPSolution(s) => write!(f, "{}", s),
153        }
154    }
155}
156
157#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
158#[derive(Debug)]
159/// The type of data that can be passed between pipes
160pub enum PipeDataType {
161    String,
162    Parser,
163    PreModel,
164    Model,
165    LinearModel,
166    StandardLinearModel,
167    Tableau,
168    OptimalTableau,
169    OptimalTableauWithSteps,
170    BinarySolution,
171    IntegerBinarySolution,
172    RealSolution,
173    MILPSolution,
174}
175impl Display for PipeDataType {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        let s = match self {
178            PipeDataType::String => "String".to_string(),
179            PipeDataType::Parser => "Parser".to_string(),
180            PipeDataType::PreModel => "PreModel".to_string(),
181            PipeDataType::Model => "Model".to_string(),
182            PipeDataType::LinearModel => "LinearModel".to_string(),
183            PipeDataType::StandardLinearModel => "StandardLinearModel".to_string(),
184            PipeDataType::Tableau => "Tableau".to_string(),
185            PipeDataType::OptimalTableau => "OptimalTableau".to_string(),
186            PipeDataType::OptimalTableauWithSteps => "OptimalTableauWithSteps".to_string(),
187            PipeDataType::BinarySolution => "BinarySolution".to_string(),
188            PipeDataType::IntegerBinarySolution => "IntegerBinarySolution".to_string(),
189            PipeDataType::RealSolution => "RealSolution".to_string(),
190            PipeDataType::MILPSolution => "MILPSolution".to_string(),
191        };
192
193        f.write_str(&s)
194    }
195}
196
197#[derive(Debug)]
198pub enum PipeError {
199    EmptyPipeData,
200    InvalidData {
201        expected: PipeDataType,
202        got: PipeDataType,
203    },
204    CompilationError {
205        error: CompilationError,
206        source: String,
207    },
208    TransformError {
209        error: TransformError,
210        source: String,
211    },
212    LinearizationError(LinearizationError),
213    StandardizationError(SolverError),
214    CanonicalizationError(CanonicalTransformError),
215    StepByStepSimplexError(SimplexError, Tableau),
216    SolverError(SolverError),
217    Other(String),
218}
219impl Display for PipeError {
220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221        match self {
222            PipeError::EmptyPipeData => write!(f, "Pipe data is empty"),
223            PipeError::InvalidData { expected, got } => {
224                write!(
225                    f,
226                    "Expected data of type \"{}\" but got \"{}\"",
227                    expected, got
228                )
229            }
230            PipeError::Other(s) => write!(f, "{}", s),
231            PipeError::CompilationError { error, source } => {
232                write!(f, "{}", error.to_string_from_source(source))
233            }
234            PipeError::TransformError { error, source } => match error.trace_from_source(source) {
235                Ok(trace) => write!(f, "{}", trace),
236                Err(_) => write!(f, "{}", error.traced_error()),
237            },
238            PipeError::LinearizationError(e) => write!(f, "{}", e),
239            PipeError::StandardizationError(e) => write!(f, "{}", e),
240            PipeError::CanonicalizationError(e) => write!(f, "{}", e),
241            PipeError::StepByStepSimplexError(e, _) => write!(f, "{}", e),
242            PipeError::SolverError(e) => write!(f, "{}", e),
243        }
244    }
245}
246
247/// The context in which a pipe is executed
248///
249/// It contains the functions and constants that can be used in the pipe
250pub struct PipeContext<'a> {
251    functions: &'a IndexMap<String, Box<dyn RoocFunction>>,
252    constants: Vec<Constant>,
253}
254impl PipeContext<'_> {
255    pub fn new(
256        constants: Vec<Constant>,
257        fns: &IndexMap<String, Box<dyn RoocFunction>>,
258    ) -> PipeContext<'_> {
259        PipeContext {
260            constants,
261            functions: fns,
262        }
263    }
264    pub fn constants(&self) -> &Vec<Constant> {
265        &self.constants
266    }
267    pub fn functions(&self) -> &IndexMap<String, Box<dyn RoocFunction>> {
268        self.functions
269    }
270}
271
272pub trait Pipeable {
273    /// The function that is called when the pipe is executed
274    #[allow(clippy::result_large_err)]
275    fn pipe(
276        &self,
277        data: &mut PipeableData,
278        pipe_context: &PipeContext,
279    ) -> Result<PipeableData, PipeError>;
280}