掩码
MaskingFunction 对线性多项式与二进制掩码的乘积建模:
本页以当前 ospf-kotlin-core 实现作为唯一契约。
契约
- 输入:
input: LinearPolynomial<V>与mask: AbstractVariableItem<*, *>。 - 掩码的语义是二进制变量(
BinVar)。 - 输出:
RealVar,通过resultPolynomial暴露。 evaluate在掩码缺失或等于零时返回零,否则求值并返回input(因此传入的非二进制非零值会被视为“开启”)。V必须实现RealNumber<V>与NumberField<V>,并配套IntoValue<V>转换器。
数学定义
对于有效二进制掩码,
当存在有限界
实现会在可能时从输入多项式取得
适用域与边界
求解器语义要求 mask 只能取 0 或 1。非零掩码值虽然会被 evaluate 接受,但不是二进制求解器模型的有效赋值。如果输入没有有限界,应显式传入 bigM;当前默认回退值为
当前 API
Kotlin
源码:Masking.kt(MaskingFunction)
MaskingFunction(
input: LinearPolynomial<V>,
mask: AbstractVariableItem<*, *>,
bigM: V? = null,
converter: IntoValue<V>,
name: String,
displayName: String? = null
)同一源码文件还包含 MaskingWithPolyMaskFunction 与 MaskingRangeFunction;它们是不同的 API,不应替代本页描述的二进制掩码契约。
Rust
Rust 提供二值变量对应物 MaskingFunction:
MaskingFunction::new(
id: u64,
name: &str,
input: Linear<V>,
mask_var: BinaryVariableItem,
) -> MaskingFunction<V>
MaskingFunction::with_big_m(
id: u64,
name: &str,
input: Linear<V>,
mask_var: BinaryVariableItem,
big_m: V,
) -> MaskingFunction<V>Rust 要求掩码本身是 BinaryVariableItem,而 Kotlin 接收抽象变量项并依赖调用方遵守二值契约。Rust 模块也直接提供两个 Kotlin 变体的对应物:MaskingWithPolyMaskFunction::new / with_big_m 接收 Linear<V> 掩码表达式并创建二值桥接变量;MaskingRangeFunction::new 接收线性掩码以及 lower、upper。result_variable()、mask_variable()/mask_bridge_variable() 和 big_m() 暴露 Rust 状态;没有 Kotlin 的 converter 或 displayName 参数。
求解器数学模型
令掩码
Kotlin 与 Rust 都使用这四条乘积线性化约束。Kotlin 依赖调用者保证掩码为二值变量;Rust 由类型直接保证。输入缺少有限界时以
evaluate 与 solver 的差异
evaluate 直接查找 mask:掩码缺失和精确为零都会返回零,其余值都会求值输入。solver 注册 resultVar 并假定掩码变量是二进制,因此只强制实现预期的两种情况。如果调用者用不完整映射或非二进制掩码做求值,这一差异会产生影响。
示例与测试
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.MaskingFunction
import fuookami.ospf.kotlin.core.variable.BinVar
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 mask = BinVar("mask")
val input = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, x)),
constant = Flt64.one
)
val masking = MaskingFunction(
input = input,
mask = mask,
bigM = Flt64(10.0),
converter = IntoValue.Identity,
name = "masking"
)
val value = masking.evaluate(mapOf<Symbol, Flt64>(x to Flt64(5.0), mask to Flt64.one))
check(value != null && (value eq Flt64(6.0)))use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::MaskingFunction;
use ospf_rust_core::variable::{BinaryVariableItem, VariableId};
let mask = BinaryVariableItem::create(VariableId::standalone(2), "mask");
let input = Linear::new(vec![LinearMonomial::new(1.0, 0)], 1.0);
let masking = MaskingFunction::with_big_m(1, "masking", input, mask, 10.0_f64);
assert_eq!(masking.big_m(), &10.0);
let _result = masking.result_variable();完整示例:MaskingTest.kt
Core 验证:MaxAndMaskingFunctionGenericEvaluateTest.kt 与 MaskingRangeFunctionDedicatedTest.kt。Rust 的范围独立测试为 function_symbol_masking_range.rs。
Rust 源码与 parity 覆盖:masking.rs 和 gurobi_linear_function_kotlin_parity.rs。
多项式掩码:MaskingWithPolyMaskFunction
此变体接收线性掩码表达式,而不是直接接收变量:
它创建 maskVar(BinVar)和 resultVar(RealVar),注册 maskPoly = maskVar,然后应用与 MaskingFunction 相同的四个 Big-M 约束。直接 evaluate 在掩码表达式缺失或恰为零时返回零,否则计算 input;求解器依靠二值等式约束保证预期的掩码域。
源码:Masking.kt(MaskingWithPolyMaskFunction)
val mask = BinVar("mask")
val input = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, x)),
constant = Flt64.one
)
val maskPoly = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, mask)),
constant = Flt64.zero
)
val polyMask = MaskingWithPolyMaskFunction(
input = input,
maskPoly = maskPoly,
bigM = Flt64(10.0),
converter = IntoValue.Identity,
name = "poly_mask"
)
val value = polyMask.evaluate(
mapOf<Symbol, Flt64>(x to Flt64(5.0), mask to Flt64.one)
)
check(value != null && (value eq Flt64(6.0)))当前没有此变体的专用示例或测试;可结合源码和共享掩码测试,并参考实际的linear_function 示例目录。
掩码范围:MaskingRangeFunction
构造器要求 lower <= upper,创建有符号的 RealVar/连续结果,并且只注册上述两个不等式;掩码表达式应当是二值的,但该类既不创建也不强制掩码为二值。负下界是合法的。当 m 为二值变量时,m=0 给出 y=0,m=1 给出 lower\le y\le upper。
源码:Masking.kt(MaskingRangeFunction)
val mask = BinVar("range_mask")
val maskPoly = LinearPolynomial(
monomials = listOf(LinearMonomial(Flt64.one, mask)),
constant = Flt64.zero
)
val rangeMask = MaskingRangeFunction(
mask = maskPoly,
lower = Flt64(2.0),
upper = Flt64(5.0),
converter = IntoValue.Identity,
name = "range_mask"
)
val value = rangeMask.evaluate(
mapOf<Symbol, Flt64>(mask to Flt64.one, rangeMask.resultVar to Flt64(4.0))
)
check(value != null && (value eq Flt64(4.0)))直接求值在掩码或 resultVar 缺失时返回 null/None;掩码为零时返回零,掩码非零时读取 resultVar,并将结果截断到缩放后的区间(掩码为负时交换端点)。注册约束直接使用有符号下界,因此在预期的二值掩码契约下支持负下界。Rust 的 zero_if_none = true 选项仍可像其他函数一样将缺失的多项式 token 代为零。专用测试覆盖负下界、缺失值和两条注册约束。
相关页面
abs:把数值拆为正部和负部。max与min:聚合候选多项式。slack与slack-range:其他有界线性变换。