首个非零索引
FirstFunction 返回输入多项式中值严格大于 epsilon 的第一个元素的从零开始索引。如果没有输入通过该判定,则返回输入数量。
契约
- 输入:有序、通常应非空的
List<LinearPolynomial<V>>。 - 输出:
中的数值索引,以线性多项式 result暴露。 - 选择条件:
p_i > epsilon,不是abs(p_i) > epsilon;负值永远不会被选中。 epsilon是Flt64参数(默认1e-6),系数和结果通过转换器使用泛型V。- 直接
evaluate遇到缺失输入值时返回null。
定义与数学模型
设输入值为
设
返回索引为
因此全为 false 时返回 null。
求解器数学模型
Kotlin 先通过两约束正值指标模型把
公开结果为
当前 Kotlin 注册还会额外传入单调约束
Rust 不创建 zero_if_none 后把结果固定为零。因此 Rust 返回被选值,不是 Kotlin 的首个索引。
当前 API
Kotlin
FirstFunction(
polynomials: List<LinearPolynomial<V>>,
epsilon: Flt64 = Flt64(1e-6),
converter: IntoValue<V>,
name: String,
displayName: String? = null
)Rust
源码:first.rs
Rust 有同名辅助函数,但不是 Kotlin 阈值函数的一一对应替代。FirstFunction::new 接收候选 Linear<V> 值以及等长的、已经计算好的 Vec<BinaryVariableItem> 条件变量;它没有 epsilon 参数,也不会在内部创建 BinaryzationFunction。公开访问器为 result_variable()、polynomials() 和 condition_variables()。没有任何条件命中时,直接求值返回 None(zero_if_none 为 true 时返回零),机理约束也将结果限定为零;而 Kotlin 返回输入数量 n。若需要 Kotlin 的阈值契约,应为每个输入组合一个 BinaryzationFunction,再传入其指示变量。
FirstFunction::new(
id: u64,
name: &str,
polynomials: Vec<Linear<V>>,
conditions: Vec<BinaryVariableItem>,
) -> Self
FirstFunction::result_variable(&self) -> &ContinuousVariableItem
FirstFunction::polynomials(&self) -> &[Linear<V>]
FirstFunction::condition_variables(&self) -> &[BinaryVariableItem]evaluate 与 solver 的差异
直接求值从索引 0 扫描列表并使用调用者的 epsilon。solver 注册先构造二值化函数;其当前约束容差是共享的 NONZERO_TOLERANCE,再连接首个命中数组。因此当 epsilon 非默认值时,阈值附近的直接求值和 solver 判定可能不同。
边界、tolerance 与 Undefined
首个命中结果不是布尔值,也不是从 1 开始的索引。由于使用严格 >,等于 epsilon 时不会选中。空列表不是有用的模型输入,调用者应至少提供一个多项式。直接求值遇到缺失符号时返回 null;Big-M 无法推导或多项式值非法时,底层二值化注册失败。
当前最小示例
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.FirstFunction
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
import fuookami.ospf.kotlin.core.variable.RealVar
val x0 = RealVar("x0")
val x1 = RealVar("x1")
val first = FirstFunction(
polynomials = listOf(
LinearPolynomial(listOf(LinearMonomial(Flt64.one, x0)), Flt64.zero),
LinearPolynomial(listOf(LinearMonomial(Flt64.one, x1)), Flt64.zero)
),
converter = IntoValue.Identity,
name = "first"
)
val value = first.evaluate(
mapOf<Symbol, Flt64>(x0 to Flt64.zero, x1 to Flt64.two)
)
check(value != null && value == Flt64.one)use ospf_rust_core::symbol::flatten::Linear;
use ospf_rust_core::symbol::function::FirstFunction;
use ospf_rust_core::symbol::FunctionSymbol;
use ospf_rust_core::token::{MutableTokenList, Token, VecTokenList};
use ospf_rust_core::variable::{BinaryVariableItem, VariableId};
let c0 = BinaryVariableItem::create(VariableId::standalone(1), "c0");
let c1 = BinaryVariableItem::create(VariableId::standalone(2), "c1");
let function = FirstFunction::new(
1,
"first",
vec![Linear::new(vec![], 10.0), Linear::new(vec![], 20.0)],
vec![c0.clone(), c1.clone()],
);
let mut tokens = VecTokenList::new();
let token0 = Token::from_generic(c0.clone(), c0.index());
token0.set_result(0.0);
tokens.add_token(token0);
let token1 = Token::from_generic(c1.clone(), c1.index());
token1.set_result(1.0);
tokens.add_token(token1);
let value = <FirstFunction as FunctionSymbol>::calculate_value(&function, &tokens, false);
assert_eq!(value, Some(20.0));测试与示例
- Core 测试:
FirstFunctionGenericEvaluateTest.kt - 示例目录(当前没有专门的首个索引文件):linear_function
- Rust 实现与求值:
first.rs、p0_evaluation_tests.rs