Skip to content

二次乘积 ​

ProductFunction 将两个线性多项式的乘积表示为二次中间表达式。

NOTE

普通中间表达式是 left⋅right,没有公开结果变量。registerConstraints 不提交独立约束;展开后的多项式由目标函数或外层约束直接消费。

契约 ​

  • 输入:left: LinearPolynomial<V> 和 right: LinearPolynomial<V>。
  • 输出表达式:展开后的 QuadraticPolynomial<V>,即 left⋅right。
  • 中间符号直接求值会把两个线性表达式求值后相乘;token 表中缺少符号时沿求值路径返回 null。
  • 泛型值要求 V : RealNumber<V>, V : Ring<V>, V : NumberField<V>,并配合 IntoValue<V> 转换器。
  • 即使输入表达式使部分项退化为线性,该符号仍属于二次中间符号。

定义与数学模型 ​

对于

left=cl+∑iaixi,right=cr+∑jbjzj,

展开式为

left⋅right=clcr+cr∑iaixi+cl∑jbjzj+∑i,jaibjxizj.

中间符号的多项式就是该展开式;仅表示表达式不需要辅助 y。

求解器数学模型 ​

Kotlin ​

作为中间表达式使用时不创建辅助变量,也不独立提交约束;求解器直接在目标函数或其他约束中接收二次展开式

p(x)=left(x)right(x).

registerConstraints 不提交独立约束,也不创建 y=p(x) 的桥接变量;如果需要这种关系,应使用专用桥接符号。

Rust ​

Rust 同样不创建辅助变量,直接把 left(x)right(x) 的二次展开式交给使用它的目标或约束;两边现在具有一致的表达式级求解器契约。

当前 API ​

Kotlin ​

源码:Product.kt(ProductFunction)

kotlin
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.ProductFunction
import fuookami.ospf.kotlin.core.token.AutoTokenTable
import fuookami.ospf.kotlin.math.algebra.number.Flt64
import fuookami.ospf.kotlin.math.symbol.Quadratic
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 x = RealVar("x")
val y = RealVar("y")
val left = LinearPolynomial(
    listOf(LinearMonomial(Flt64.one, x)), Flt64.two
)
val right = LinearPolynomial(
    listOf(LinearMonomial(Flt64.one, y)), -Flt64.one
)
val product = ProductFunction(
    left = left,
    right = right,
    converter = IntoValue.Identity,
    name = "product"
)
val tokens = AutoTokenTable<Flt64>(Quadratic, false)
tokens.add(listOf(x, y))
val value = product.prepare(
    mapOf<Symbol, Flt64>(x to Flt64.two, y to Flt64(5.0)),
    tokens,
    IntoValue.Identity
)
check(value == Flt64(16.0))
tokens.close()

Rust ​

Rust 通过 ProductFunction<V> 提供相同的表达式级乘积。构造器为:

rust
ProductFunction::new(id: u64, name: &str, left: Linear<V>, right: Linear<V>) -> ProductFunction<V>

相关公开操作包括 left_polynomial、right_polynomial、prepare、FunctionSymbol::calculate_value 和 QuadraticIntermediateSymbol::to_quadratic_polynomial。Rust 实现不注册辅助 token,也不返回机理约束,与 Kotlin 的 registerConstraints 空操作契约一致。

rust
use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::ProductFunction;
use ospf_rust_core::symbol::QuadraticIntermediateSymbol;

let left = Linear::new(vec![LinearMonomial::new(1.0, 0)], 2.0);
let right = Linear::new(vec![LinearMonomial::new(1.0, 1)], -1.0);
let product = ProductFunction::new(7, "product", left, right);
let expanded = product.to_quadratic_polynomial();
assert_eq!(*expanded.constant(), -2.0);

泛型边界是实现使用的 Rust 算术 trait(求值时还需要 Clone + Debug + Send + Sync + 'static、Add、Mul 和 Zero)。默认类型为 f64,也是最小示例的选择。

evaluate 与 solver 的差异 ​

中间求值 API(prepare、带 token 表的 evaluate 和结果列表 evaluate)直接计算乘积。二次机制注册把展开后的多项式作为二次表达式使用。直接调用 registerConstraints 不会增加约束行,也不会创建自由的乘积结果变量。

边界、tolerance 与 Undefined ​

两个线性输入都必须可求值;token 值缺失时返回 null。该算术没有基于 tolerance 的分类,也没有 TruthValue.Undefined 状态。大系数或大乘积仍必须能由所选泛型数值和 solver 表示。

示例与测试 ​

kotlin
import fuookami.ospf.kotlin.core.solver.value.IntoValue
import fuookami.ospf.kotlin.core.symbol.function.ProductFunction
import fuookami.ospf.kotlin.core.token.AutoTokenTable
import fuookami.ospf.kotlin.math.algebra.number.Flt64
import fuookami.ospf.kotlin.math.symbol.Quadratic
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 x = RealVar("x")
val y = RealVar("y")
val left = LinearPolynomial(
    listOf(LinearMonomial(Flt64.one, x)), Flt64.two
)
val right = LinearPolynomial(
    listOf(LinearMonomial(Flt64.one, y)), -Flt64.one
)
val product = ProductFunction(
    left = left,
    right = right,
    converter = IntoValue.Identity,
    name = "product"
)
val tokens = AutoTokenTable<Flt64>(Quadratic, false)
tokens.add(listOf(x, y))
val value = product.prepare(
    mapOf<Symbol, Flt64>(x to Flt64.two, y to Flt64(5.0)),
    tokens,
    IntoValue.Identity
)
check(value == Flt64(16.0))
tokens.close()
rust
use ospf_rust_core::symbol::FunctionSymbol;
use ospf_rust_core::symbol::flatten::{Linear, LinearMonomial};
use ospf_rust_core::symbol::function::ProductFunction;
use ospf_rust_core::token::{MutableTokenList, Token, VecTokenList};
use ospf_rust_core::variable::{ContinuousVariableItem, VariableId};

let x = ContinuousVariableItem::create(VariableId::standalone(0), "x");
let y = ContinuousVariableItem::create(VariableId::standalone(1), "y");
let mut tokens = VecTokenList::<f64>::new();
let tx = Token::from_generic(x, 0);
tx.set_result(2.0);
tokens.add_token(tx);
let ty = Token::from_generic(y, 1);
ty.set_result(5.0);
tokens.add_token(ty);
let product = ProductFunction::new(
    8,
    "product",
    Linear::new(vec![LinearMonomial::new(1.0, 0)], 2.0),
    Linear::new(vec![LinearMonomial::new(1.0, 1)], -1.0),
);
assert_eq!(product.calculate_value(&tokens, false), Some(16.0));

相关页面 ​