Skip to content

二值化 ​

契约 ​

BinaryzationFunction<V> 将一个线性多项式 p 映射为二值结果。当前契约是带正间隔 ε(即构造器的 tolerance 参数)的正值二值化:

y=Bin(p)={1,p≥εundefined,0<p<ε0,p≤0

输入不必是二值变量,也可以是任意带有 V : RealNumber<V> & NumberField<V> 的 LinearPolynomial<V>。

定义与真值表 ​

py
p≥ε1
0<p<εnull
p≤00

结果是二值变量,不是 p 的数值副本。

边界、tolerance 与 Undefined ​

evaluate() 按关系 p > 0 与间隔 ε 对 p 进行三值判定:p≥ε 返回 1,p≤0 返回 0,间隔内返回 null;缺少多项式求值结果时同样返回 null。

求解器注册使用 tolerance 参数(默认 NONZERO_TOLERANCE = 1e-10)作为 ε。如果 a 是结果变量,M 是选定的 Big-M 值,核心指示约束为:

p−Ma≤0,p−M′a≥ε−M′.

因此 a=0 要求 p≤0,而 a=1 要求 p≥ε。开区间 0<p<ε 是求解器间隔:evaluate() 在该区间返回 null,线性化模型同样没有有效分支。

省略 bigM 时,实现根据多项式有限范围推导;必要时回退到 BIG_M_DEFAULT = 1e6。

当前 API ​

Kotlin ​

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 ​

源码:binaryzation.rs

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 等价编码。

rust
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

求解器数学模型 ​

令结果变量 a 为二值变量,ε 为正值容差。实际传给求解器的约束为

p−Ma≤0,p−M′a≥ε−M′.

因此 a=0⇒p≤0,a=1⇒p≥ε。Kotlin 只创建 name_bin;Rust 使用相同的两分支思想,但阈值、Big-M 与方法由构造器选择。区间 0<p<ε 没有可行分支。

evaluate() 与求解器模型的差异 ​

求值器与求解器模型在间隔上表现一致:两者都把 0<p<ε 视为定义域之外(evaluate() 返回 null,注册的约束在该区间没有可行分支)。如果模型可能产生该区间内的值,函数会返回“无值”,而不是具有误导性的 1。

当前最小示例 ​

kotlin
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)
}
rust
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 测试 ​

相关页面 ​