1
use std::cell::RefCell;
2
use std::fmt::Debug;
3
use std::sync::{Arc, RwLock};
4

            
5
use derivative::Derivative;
6
use serde::{Deserialize, Serialize};
7
use serde_with::serde_as;
8

            
9
use crate::ast::{DecisionVariable, Domain, Expression, Name, SymbolTable};
10
use crate::context::Context;
11
use crate::metadata::Metadata;
12

            
13
/// Represents a computational model containing variables, constraints, and a shared context.
14
///
15
/// The `Model` struct holds a set of variables and constraints for manipulating and evaluating symbolic expressions.
16
///
17
/// # Fields
18
/// - `variables`:
19
///   - Type: `SymbolTable`
20
///   - A table that links each variable's name to its corresponding `DecisionVariable`.
21
///   - For example, the name `x` might be linked to a `DecisionVariable` that says `x` can only take values between 1 and 10.
22
///
23
/// - `constraints`:
24
///   - Type: `Expression`
25
///   - Represents the logical constraints applied to the model's variables.
26
///   - Can be a single constraint or a combination of various expressions, such as logical operations (e.g., `AND`, `OR`),
27
///     arithmetic operations (e.g., `SafeDiv`, `UnsafeDiv`), or specialized constraints like `SumEq`.
28
///
29
/// - `context`:
30
///   - Type: `Arc<RwLock<Context<'static>>>`
31
///   - A shared object that stores global settings and state for the model.
32
///   - Can be safely read or changed by multiple parts of the program at the same time, making it good for multi-threaded use.
33
///
34
/// - `next_var`:
35
///   - Type: `RefCell<i32>`
36
///   - A counter used to create new, unique variable names.
37
///   - Allows updating the counter inside the model without making the whole model mutable.
38
///
39
/// # Usage
40
/// This struct is typically used to:
41
/// - Define a set of variables and constraints for rule-based evaluation.
42
/// - Have transformations, optimizations, and simplifications applied to it using a set of rules.
43
#[serde_as]
44
1050
#[derive(Derivative, Clone, Debug, Serialize, Deserialize)]
45
#[derivative(PartialEq, Eq)]
46
pub struct Model {
47
    #[serde_as(as = "Vec<(_, _)>")]
48
    pub variables: SymbolTable,
49
    pub constraints: Expression,
50
    #[serde(skip)]
51
    #[derivative(PartialEq = "ignore")]
52
    pub context: Arc<RwLock<Context<'static>>>,
53
    next_var: RefCell<i32>,
54
}
55

            
56
impl Model {
57
2286975
    pub fn new(
58
2286975
        variables: SymbolTable,
59
2286975
        constraints: Expression,
60
2286975
        context: Arc<RwLock<Context<'static>>>,
61
2286975
    ) -> Model {
62
2286975
        Model {
63
2286975
            variables,
64
2286975
            constraints,
65
2286975
            context,
66
2286975
            next_var: RefCell::new(0),
67
2286975
        }
68
2286975
    }
69

            
70
2286675
    pub fn new_empty(context: Arc<RwLock<Context<'static>>>) -> Model {
71
2286675
        Model::new(
72
2286675
            Default::default(),
73
2286675
            Expression::And(Metadata::new(), Vec::new()),
74
2286675
            context,
75
2286675
        )
76
2286675
    }
77
    // Function to update a DecisionVariable based on its Name
78
15
    pub fn update_domain(&mut self, name: &Name, new_domain: Domain) {
79
15
        if let Some(decision_var) = self.variables.get_mut(name) {
80
15
            decision_var.domain = new_domain;
81
15
        }
82
15
    }
83

            
84
255
    pub fn get_domain(&self, name: &Name) -> Option<&Domain> {
85
255
        self.variables.get(name).map(|v| &v.domain)
86
255
    }
87

            
88
    // Function to add a new DecisionVariable to the Model
89
1260
    pub fn add_variable(&mut self, name: Name, decision_var: DecisionVariable) {
90
1260
        self.variables.insert(name, decision_var);
91
1260
    }
92

            
93
1275
    pub fn get_constraints_vec(&self) -> Vec<Expression> {
94
1275
        match &self.constraints {
95
1005
            Expression::And(_, constraints) => constraints.clone(),
96
270
            _ => vec![self.constraints.clone()],
97
        }
98
1275
    }
99

            
100
585
    pub fn set_constraints(&mut self, constraints: Vec<Expression>) {
101
585
        if constraints.is_empty() {
102
            self.constraints = Expression::And(Metadata::new(), Vec::new());
103
585
        } else if constraints.len() == 1 {
104
465
            self.constraints = constraints[0].clone();
105
465
        } else {
106
120
            self.constraints = Expression::And(Metadata::new(), constraints);
107
120
        }
108
585
    }
109

            
110
    pub fn set_context(&mut self, context: Arc<RwLock<Context<'static>>>) {
111
        self.context = context;
112
    }
113

            
114
    pub fn add_constraint(&mut self, expression: Expression) {
115
        // ToDo (gs248) - there is no checking whatsoever
116
        // We need to properly validate the expression but this is just for testing
117
        let mut constraints = self.get_constraints_vec();
118
        constraints.push(expression);
119
        self.set_constraints(constraints);
120
    }
121

            
122
585
    pub fn add_constraints(&mut self, expressions: Vec<Expression>) {
123
585
        let mut constraints = self.get_constraints_vec();
124
585
        constraints.extend(expressions);
125
585
        self.set_constraints(constraints);
126
585
    }
127

            
128
    /// Returns an arbitrary variable name that is not in the model.
129
255
    pub fn gensym(&self) -> Name {
130
255
        let num = *self.next_var.borrow();
131
255
        *(self.next_var.borrow_mut()) += 1;
132
255
        Name::MachineName(num) // incremented when inserted
133
255
    }
134
}