1
//! Normalisation of optimisation objectives before rewriting.
2

            
3
use crate::ast::{Atom, Expression, Metadata, Model, Moo, Reference};
4
use crate::bug;
5

            
6
/// Introduces an auxiliary find variable for a non-atomic optimisation objective and links it
7
/// with an aux declaration constraint.
8
///
9
/// Objectives that are already atoms (for example `minimising z`) are left unchanged.
10
1351539
pub fn introduce_objective_auxiliary(mut model: Model) -> Model {
11
1351539
    let Some(objective) = model.objective.as_ref() else {
12
1330292
        return model;
13
    };
14

            
15
21247
    if matches!(&objective.expression, Expression::Atomic(_, _)) {
16
2455
        return model;
17
18792
    }
18

            
19
18792
    let expr = objective.expression.clone();
20

            
21
18792
    let Some(domain) = expr.domain_of() else {
22
        bug!(
23
            "objective expression has no domain and could not be introduced as an auxiliary variable: {expr}"
24
        );
25
    };
26

            
27
18792
    let mut symbols = model.symbols().clone();
28
18792
    let decl = symbols.gen_find_auxiliary(&domain);
29
18792
    let aux_reference = Expression::Atomic(Metadata::new(), Atom::new_ref(decl.clone()));
30
    let aux_constraint =
31
18792
        Expression::AuxDeclaration(Metadata::new(), Reference::new(decl), Moo::new(expr));
32

            
33
18792
    model.symbols_mut().extend(symbols);
34
18792
    model.add_constraint(aux_constraint);
35
18792
    model
36
18792
        .objective
37
18792
        .as_mut()
38
18792
        .expect("objective should still be present")
39
18792
        .expression = aux_reference;
40

            
41
18792
    model
42
1351539
}