Minimum
MinFunction represents the minimum of one or more linear polynomials:
Contract
- Input: a non-empty
List<LinearPolynomial<V>>(n >= 1). - Output:
resultVar, a signedRealVar, exposed asresultPolynomial. evaluateevaluates every input and returns their minimum; a missing symbol value makes it returnnull.Vmust implementRealNumber<V>andNumberField<V>; pass the matchingIntoValue<V>converter.
Mathematical definition
The implementation uses binary selectorVars
With the selector for one candidate equal to zero, that candidate is forced to equal the result; the remaining inequalities force the result to be no greater than every candidate.
Domain and boundaries
The solver result is a signed RealVar; when every candidate has finite bounds, the result range is tightened to the candidate bounds, so a negative minimum is representable. Inferred Big-M values require finite candidate bounds; otherwise the current fallback is bigM must cover all candidate gaps. When bounds are inferred, each candidate's Big-M is that candidate's upper bound minus the lowest candidate lower bound.
Current API
Kotlin
MinFunction is declared in the same source file as MaxFunction (there is no separate implementation file): Max.kt (MinFunction)
MinFunction(
polynomials: List<LinearPolynomial<V>>,
bigM: V? = null,
converter: IntoValue<V>,
name: String = "min",
displayName: String? = null
)The companion factory also provides fromSymbols for LinearIntermediateSymbol<V> candidates.
Rust
Rust exposes MinFunction over flatten::Linear<V>:
MinFunction::new(id: u64, name: &str, polynomials: Vec<Linear<V>>, exact: bool) -> MinFunction<V>exact = true creates one binary selector per candidate and registers the exact selector model. exact = false keeps only the inequality envelope; unlike Kotlin, Rust has no bigM or converter argument on this constructor. The result is exposed by result_variable().
Solver mathematical model
With result exact = true pass
Here the selected candidate has exact = false keeps only
evaluate versus solver
evaluate directly folds the candidate values and does not apply the solver result-range tightening. Solver registration tightens the result range to the candidate bounds and relies on valid Big-M values; an undersized Big-M can exclude the true minimum.
Examples and tests
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.MinFunction
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 y = RealVar("y")
val xPoly = LinearPolynomial(listOf(LinearMonomial(Flt64.one, x)), Flt64.zero)
val yPoly = LinearPolynomial(listOf(LinearMonomial(Flt64.one, y)), Flt64.zero)
val min = MinFunction(
polynomials = listOf(xPoly, yPoly),
bigM = Flt64(10.0),
converter = IntoValue.Identity,
name = "min"
)
val value = min.evaluate(mapOf<Symbol, Flt64>(x to Flt64.two, y to Flt64(5.0)))
check(value != null && (value eq Flt64.two))use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::MinFunction;
let x = Linear::new(vec![LinearMonomial::new(1.0, 0)], 0.0);
let y = Linear::new(vec![LinearMonomial::new(1.0, 1)], 0.0);
let min = MinFunction::new(1, "min", vec![x, y], true);
assert!(min.exact());
let _result = min.result_variable();Complete example: MinTest.kt
Core validation: MaxAndMaskingFunctionGenericEvaluateTest.kt
Rust source and cross-language regression coverage: max.rs and gurobi_linear_function_kotlin_parity.rs.
MinMaxFunction and MaxMinFunction
Despite their names, MinMaxFunction computes the maximum by delegating every evaluation, helper-variable, and constraint operation to an inner MaxFunction. MaxMinFunction computes the minimum by delegating to an inner MinFunction. The names describe the optimization interpretation, not a different aggregation algorithm. Both wrappers accept the same polynomials, optional bigM, converter, name, and optional displayName parameters. Their fromSymbols factories accept List<LinearIntermediateSymbol<V>> and return a LinearFunctionSymbolAdapter; the adapter is only a bridge to the intermediate-symbol API.
Source: MinMax.kt (MinMaxFunction and MaxMinFunction)
val minMax = MinMaxFunction(
polynomials = listOf(xPoly, yPoly),
bigM = Flt64(10.0),
converter = IntoValue.Identity,
name = "min_max"
)
val maxMin = MaxMinFunction(
polynomials = listOf(xPoly, yPoly),
bigM = Flt64(10.0),
converter = IntoValue.Identity,
name = "max_min"
)