二值化
契约
BinaryzationFunction<V> 将一个线性多项式 tolerance 参数)的正值二值化:
输入不必是二值变量,也可以是任意带有 V : RealNumber<V> & NumberField<V> 的 LinearPolynomial<V>。
定义与真值表
| 1 | |
null | |
| 0 |
结果是二值变量,不是
边界、tolerance 与 Undefined
evaluate() 按关系 p > 0 与间隔 1,0,间隔内返回 null;缺少多项式求值结果时同样返回 null。
求解器注册使用 tolerance 参数(默认 NONZERO_TOLERANCE = 1e-10)作为
因此 evaluate() 在该区间返回 null,线性化模型同样没有有效分支。
省略 bigM 时,实现根据多项式有限范围推导;必要时回退到 BIG_M_DEFAULT = 1e6。
当前 API
Kotlin
BinaryzationFunction(
polynomial: LinearPolynomial<V>,
converter: IntoValue<V>,
bigM: V? = null,
name: String = "bin",
displayName: String? = null,
tolerance: V? = null
)伴生 invoke 使用相同参数,但 name 为必填。converter 是必需参数;旧的标量构造器不属于当前 API。
Rust
Rust 提供 BinaryzationFunction::new(id, name, input, threshold, big_m, method) 及命名/自动工厂。便捷构造器包括 with_big_m/named_big_m/auto_big_m(严格使用 input > threshold,阈值为零时与 Kotlin 的正值测试一致)和 with_threshold/named_threshold/auto_threshold(使用 input >= threshold)。BinaryzationMethod 可取 BigM、Threshold、Indicator 或 SOS1;后两者在当前机理层使用 Big-M 等价编码。
BinaryzationFunction::new(
id: u64,
name: &str,
input: Linear<V>,
threshold: V,
big_m: V,
method: BinaryzationMethod,
) -> Self
BinaryzationFunction::named_big_m(name: impl AsRef<str>, input: Linear<V>, big_m: V) -> Self
BinaryzationFunction::named_threshold(name: impl AsRef<str>, input: Linear<V>, threshold: V) -> Self求解器数学模型
令结果变量
因此 name_bin;Rust 使用相同的两分支思想,但阈值、Big-M 与方法由构造器选择。区间
evaluate() 与求解器模型的差异
求值器与求解器模型在间隔上表现一致:两者都把 evaluate() 返回 null,注册的约束在该区间没有可行分支)。如果模型可能产生该区间内的值,函数会返回“无值”,而不是具有误导性的 1。
当前最小示例
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.BinaryzationFunction
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.monomial.LinearMonomial
import fuookami.ospf.kotlin.math.symbol.polynomial.LinearPolynomial
fun main() {
val x = RealVar("x")
val xPoly = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, x)),
constant = Flt64.zero
)
val function = BinaryzationFunction(
polynomial = xPoly,
converter = IntoValue.Identity,
name = "bin"
)
check(function.evaluate(mapOf<Symbol, Flt64>(x to Flt64(2.0))) == Flt64.one)
check(function.evaluate(mapOf<Symbol, Flt64>(x to Flt64.zero)) == Flt64.zero)
check(function.evaluate(mapOf<Symbol, Flt64>(x to Flt64(-1.0))) == Flt64.zero)
}use ospf_rust_core::symbol::flatten::Linear;
use ospf_rust_core::symbol::function::BinaryzationFunction;
use ospf_rust_core::symbol::FunctionSymbol;
use ospf_rust_core::token::VecTokenList;
let input = Linear::new(vec![], 2.0);
let function = BinaryzationFunction::named_big_m("bin", input, 10.0);
let value = <BinaryzationFunction as FunctionSymbol>::calculate_value(
&function,
&VecTokenList::<f64>::new(),
false,
);
assert_eq!(value, Some(1.0));源码与 core 测试
- Implementation:
Binaryzation.kt - Core regression test:
FunctionSymbolRegressionTest.kt - Core result-polynomial contract test:
LegacyResultPolynomialContractTest.kt - Complete example:
BinTest.kt - Rust implementation:
binaryzation.rs - Rust core coverage:
p0_evaluation_tests.rs