逻辑非
契约
NotFunction<V> 接受一个线性多项式并暴露二值结果。多项式为零时结果恰为 1,非零时结果为 0。API 对 V : RealNumber<V> & NumberField<V> 泛型化。
该运算是当前非零指示量的反相,不是假定输入已有二值变量的布尔取反。
定义与真值表
对于线性多项式
| zero | 1 |
| nonzero | 0 |
边界、tolerance 与 Undefined
evaluate() 将求值结果与精确的零比较,缺少输入时返回 null。它没有 Undefined 返回分支。
求解器的非零指示量使用 tolerance indicatorVar = 0 表示 indicatorVar = 1 要求
当前默认值为 NONZERO_TOLERANCE = 1e-10 和 STRICT_BOUNDARY = NONZERO_TOLERANCE * 16 + 16 * 2^-52。省略 bigM 时根据多项式有限范围推导,没有范围时回退到 BIG_M_DEFAULT = 1e6。
当前 API
Kotlin
NotFunction(
polynomial: LinearPolynomial<V>,
converter: IntoValue<V>,
bigM: V? = null,
tolerance: V? = null,
strictBoundary: V? = null,
name: String = "not",
displayName: String? = null
)伴生 invoke 接受 polynomial、converter、bigM、name 和 displayName;需要显式设置 tolerance 或 strictBoundary 时使用主构造器。
Rust
Rust 在与 OrFunction、XorFunction 相同的模块中暴露 NotFunction:
NotFunction::new(id: u64, name: &str, polynomial: Linear<V>) -> NotFunction<V>结果、非零指示量和 side 辅助量分别通过 result_variable()、indicator_variable() 和 side_variable() 取得。Rust 使用共享的非零指示默认值,没有 Kotlin 的逐实例 tolerance 或 strictBoundary 参数;evaluate 仍把精确零作为 NOT 的真值。
求解器数学模型
对于 name,实现创建:
name_not_nz:非零指示量 (a);name_not_side:非零检测使用的符号侧辅助量;name_not:二值结果 (y)。
一般多项式路径下三个变量都在 helperVariables 中。当多项式为单个二值变量时,两种实现都会改走直接二元路径:只注册 name_not,唯一注册的约束是补关系
实现把这些蕴含展开成线性不等式后,再添加
公开的 resultPolynomial 是 name_not 的单位系数多项式;约束注册到 AbstractLinearMechanismModel。
Rust 同样注册非零指标和补关系
evaluate() 与求解器模型的差异
求值器把所有精确非零值视为 NOT 的假分支,即使其绝对值小于 strictBoundary。求解器有零带、严格非零带和不可分类间隔。不要在不调整边界或模型数值格点的情况下把间隔内的值用于求解器。
示例与测试
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.NotFunction
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 = NotFunction(
polynomial = xPoly,
converter = IntoValue.Identity,
name = "not"
)
check(function.evaluate(mapOf<Symbol, Flt64>(x to Flt64.zero)) == Flt64.one)
check(function.evaluate(mapOf<Symbol, Flt64>(x to Flt64(3.0))) == Flt64.zero)
}use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::NotFunction;
let input = Linear::new(vec![LinearMonomial::new(1.0, 0)], 0.0);
let not = NotFunction::new(1, "not", input);
let _result = not.result_variable();源码与 core 测试:
- Implementation:
And.kt - Core generic registration test:
FunctionSymbolGenericRegistrationTest.kt - Complete example:
NotTest.kt
Rust 源码与回归覆盖:and.rs 和 gurobi_linear_function_kotlin_parity.rs。