Absolute value
AbsFunction represents the absolute value of a linear polynomial:
The implementation in ospf-kotlin-core is the authoritative contract for this page.
Contract
- Input: one
LinearPolynomial<V>namedpolynomial. - Output: a non-negative
URealVarexposed throughresultPolynomial. evaluatereturnsnullwhen the input polynomial cannot be evaluated from the supplied symbol values; otherwise it returns|p|.Vmust implement bothRealNumber<V>andNumberField<V>, and the sameIntoValue<V>converter must be used for constants and evaluation.
Mathematical definition
For an evaluated input value
The solver model decomposes the value into non-negative parts:
and uses a binary selector
Domain and boundaries
The mathematical function accepts any finite real value. The solver encoding needs a usable Big-M bound. If bigM is omitted, the implementation derives side-specific bounds from the polynomial's finite range (the positive part from its upper bound, the negative part from its negated lower bound); when that is not possible it falls back to the library default (currently bigM for a tightly bounded model. The result variable is non-negative, while the input polynomial itself may be negative.
Current API
Kotlin
Source: Abs.kt (constructor, variables, evaluation, and constraints)
The primary constructor/factory is:
AbsFunction(
polynomial: LinearPolynomial<V>,
converter: IntoValue<V>,
bigM: V? = null,
name: String,
displayName: String? = null
)The public helper/result variables are resultVar, posVar, negVar, and signVar; helperVariables registers all four. resultPolynomial is the one-term polynomial for resultVar.
Rust
Source: abs.rs
The Rust implementation takes a flattened Linear<V> and exposes AbsFunction::new(id, name, input), AbsFunction::named(name, input), and AbsFunction::auto(input). The result and sign helper variables are available through result_variable() and side_variable(). Big-M is inferred from registered variable bounds when possible and otherwise uses the core fallback; there is no explicit big_m constructor argument.
AbsFunction::new(id: u64, name: &str, input: Linear<V>) -> Self
AbsFunction::named(name: impl AsRef<str>, input: Linear<V>) -> Self
AbsFunction::auto(input: Linear<V>) -> SelfSolver mathematical model
With
Kotlin registers all four helpers. Rust registers only a result variable and a binary side variable and encodes the same absolute value with
evaluate versus solver
evaluate directly evaluates polynomial and applies the sign test. The solver uses the binary decomposition, so it additionally depends on bigM being large enough. At a valid finite input, both describe the same absolute value; an undersized Big-M can make the solver model infeasible or exclude the correct value even though evaluate still succeeds.
Minimal current example
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.AbsFunction
import fuookami.ospf.kotlin.core.variable.RealVar
import fuookami.ospf.kotlin.math.algebra.number.Flt64
import fuookami.ospf.kotlin.math.symbol.Symbol
import fuookami.ospf.kotlin.math.symbol.inequality.eq
import fuookami.ospf.kotlin.math.symbol.monomial.LinearMonomial
import fuookami.ospf.kotlin.math.symbol.polynomial.LinearPolynomial
val x = RealVar("x")
val xPoly = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, x)),
constant = Flt64.zero
)
val abs = AbsFunction(
polynomial = xPoly,
converter = IntoValue.Identity,
name = "abs"
)
val value = abs.evaluate(mapOf<Symbol, Flt64>(x to Flt64(-3.0)))
check(value != null && (value eq Flt64(3.0)))use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::AbsFunction;
use ospf_rust_core::symbol::FunctionSymbol;
use ospf_rust_core::token::{MutableTokenList, Token, VecTokenList};
use ospf_rust_core::variable::{ContinuousVariableItem, VariableId};
let x = ContinuousVariableItem::create(VariableId::standalone(1), "x");
let token = Token::from_generic(x, 0);
token.set_result(-3.0);
let mut tokens = VecTokenList::new();
tokens.add_token(token);
let input = Linear::new(vec![LinearMonomial::new(1.0, 0)], 0.0);
let abs = AbsFunction::named("abs", input);
let value = <AbsFunction as FunctionSymbol>::calculate_value(&abs, &tokens, false);
assert_eq!(value, Some(3.0));Rust evaluation/registration coverage: p0_evaluation_tests.rs
Complete example: AbsTest.kt
Core validation: FunctionSymbolGenericRegistrationTest.kt