// Kiwi 1.4.9 port: Copyright (c) 2013-2025, Nucleic Development Team.
// MoonBit adaptation: Copyright (c) 2026, MoonCassowary contributors.
// Distributed under BSD-3-Clause; see LICENSE and THIRD_PARTY_NOTICES.md.
///|
/// An immutable affine expression, sum(coefficient * variable) + constant.
/// Input arrays are copied and duplicate terms combined. Validation of finite
/// coefficients is performed when the expression enters a solver.
pub struct Expression {
priv terms : Map[Variable, Double]
constant : Double
}
///|
pub fn Expression::new(
terms : Array[(Variable, Double)],
constant? : Double = 0.0,
) -> Expression {
let collected : Map[Variable, Double] = Map([])
for (variable, coefficient) in terms {
collected[variable] = collected.get(variable).unwrap_or(0.0) + coefficient
}
{ terms: collected, constant, }
}
///|
/// Reject overflow instead of allowing NaN to masquerade as a valid residual.
pub fn Expression::value(
self : Expression,
solver : Solver,
) -> Double raise SolverError {
let mut value = self.constant
if !is_finite(value) {
raise InvalidNumber
}
for variable, coefficient in self.terms {
if !is_finite(coefficient) {
raise InvalidNumber
}
value += coefficient * solver.value(variable)
if !is_finite(value) {
raise NumericalFailure("expression evaluation overflow")
}
}
value
}