Inequality Indicator
InequalityFunction turns a comparison between a linear polynomial and a scalar into a binary result.
Contract
- Input:
lhs: LinearPolynomial<V>, scalarrhs: V, and aComparisonsign. - Direct
evaluatesupportsLE,LT,GE,GT,EQ, andNE. - Output:
result, a linear polynomial containing the binary flag. - Solver registration supports
LE/LT/GE/GT/EQ/NE;NEuses the same zero-band side encoding asEQ, with the result flag acting as the nonzero indicator. - Generic values use
V : RealNumber<V>, V : NumberField<V>and anIntoValue<V>converter.
Definition and mathematical model
Let
For EQ and NE, the solver uses a zero-band with tolerance and a side binary variable. For the other supported signs, two Big-M inequalities link the flag to the satisfied and violated branches. The exact direct-evaluation comparison is separate from the solver tolerance encoding.
Solver mathematical model
Let
| Relation | |||
|---|---|---|---|
GT | |||
GE | |||
LT | |||
LE |
For result
where one multiplier is the gap-relaxed GT/LT, LE/GE). Hence EQ and NE, both implementations additionally create a side binary and use the shared four-row zero/nonzero Big-M encoding: the EQ flag equals the complement of the nonzero flag, while the NE flag is the nonzero flag itself.
Current API
Kotlin
Source: Inequality.kt (InequalityFunction)
InequalityFunction(
lhs: LinearPolynomial<V>,
rhs: V,
sign: Comparison,
converter: IntoValue<V>,
bigM: V? = null,
tolerance: V? = null,
strictBoundary: V? = null,
name: String = "ineq",
displayName: String? = null
)The public factory exposes bigM but not the constructor's optional tolerance and strictBoundary; use the class constructor when those parameters must be customized.
Rust
Rust provides a direct flattened-expression counterpart, InequalityFunction. It takes one Linear<V>, a scalar right-hand value, an explicit InequalityKind, and Big-M:
InequalityFunction::new(
id: u64,
name: &str,
left: Linear<V>,
right: V,
kind: InequalityKind,
big_m: V,
) -> InequalityFunction<V>
InequalityFunction::less_equal(
id: u64,
name: &str,
left: Linear<V>,
right: V,
big_m: V,
) -> InequalityFunction<V>InequalityKind contains LessEqual, GreaterEqual, Less, Greater, Equal, and NotEqual; result_variable() returns the binary indicator and EQ/NE also allocate a side variable. Rust has a mechanism encoding for NotEqual as well as direct evaluation, matching the Kotlin encoding documented above. Rust has no Kotlin converter/tolerance parameters on the constructor; its mechanism uses fixed indicator tolerances and the supplied or inferred Big-M.
Evaluate versus solver
Direct evaluation classifies with the relation's gap (tolerance for LE/GE, strictBoundary for LT/GT, and the distance band for EQ/NE) and returns null inside the gap. Solver registration uses Big-M rows with the same thresholds; the gap is infeasible there rather than undefined. NE is fully supported: direct evaluation works, and registerConstraints writes the four-row zero/nonzero encoding.
Boundaries, tolerance, and Undefined
Missing polynomial symbols make evaluate return null, as does a value inside the relation's gap. Big-M must be positive, finite, representable, and large enough for the lhs-rhs range. EQ and NE additionally need a valid finite strict boundary for their side encoding. Invalid inputs (a non-positive Big-M, an invalid equality band) surface as a failed registration Result.
Examples and tests
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.InequalityFunction
import fuookami.ospf.kotlin.math.algebra.number.Flt64
import fuookami.ospf.kotlin.math.symbol.Symbol
import fuookami.ospf.kotlin.math.symbol.inequality.Comparison
import fuookami.ospf.kotlin.math.symbol.monomial.LinearMonomial
import fuookami.ospf.kotlin.math.symbol.polynomial.LinearPolynomial
import fuookami.ospf.kotlin.core.variable.RealVar
val x = RealVar("x")
val xPoly = LinearPolynomial(
listOf(LinearMonomial(Flt64.one, x)), Flt64.zero
)
val inequality = InequalityFunction(
lhs = xPoly,
rhs = Flt64.one,
sign = Comparison.LE,
converter = IntoValue.Identity,
bigM = Flt64(10.0),
name = "ineq"
)
val value = inequality.evaluate(mapOf<Symbol, Flt64>(x to Flt64.zero))
check(value == Flt64.one)use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::{InequalityFunction, InequalityKind};
let left = Linear::new(vec![LinearMonomial::new(1.0, 0)], 0.0);
let inequality = InequalityFunction::less_equal(
1,
"x_le_1",
left,
1.0_f64,
10.0_f64,
);
assert_eq!(inequality.inequality_kind(), InequalityKind::LessEqual);
let _result = inequality.result_variable();- Dedicated core test:
InequalityFunctionDedicatedTest.kt - Example directory (no dedicated inequality file): linear_function
Rust source and parity coverage: inequality.rs and gurobi_linear_function_kotlin_parity.rs.