immut/context API
Luna-Flow/luna-poly/immut/context 提供 ContextPolynomial[A],即绑定到 VariableContext 的不可变多变量多项式。各项通过上下文按名字引用变量;该包还提供按名字求值、部分求值,以及用标量或多项式对变量进行同时代换(也支持 Luna-Flow/type_theory 名字)。
多项式以 TermPolynomial 或 SparsePolynomial 形式存储;由你在构造时选择,这一选择只影响开销,不影响结果。这些类型由 immut 门面包重新导出,示例即使用该门面包。代换的数学原理见 immut/context 设计。
大多数操作成对出现:普通形式在违反契约时中止(abort),而 *_checked 形式改为返回 None。各项都列出了相应的契约违反情形。
类型
ContextPolynomial
上下文 中变量的多项式,连同 本身。
type ContextPolynomial[A] derive(@debug.Debug)
pub impl[A : Eq + @luna-generic.AddMonoid] Add for ContextPolynomial[A]
pub impl[A : Eq + @luna-generic.AddMonoid + Neg] Sub for ContextPolynomial[A]
pub impl[A : Eq + @luna-generic.AddMonoid + Mul] Mul for ContextPolynomial[A]
pub impl[A : Eq + @luna-generic.Zero + Neg] Neg for ContextPolynomial[A]
pub impl[A : Show + @luna-generic.Zero] Show for ContextPolynomial[A]
pub impl[A] @core.ContextualPolynomial for ContextPolynomial[A]
pub impl[A] @core.HasArity for ContextPolynomial[A]
pub impl[A] @core.HasContext for ContextPolynomial[A]
pub impl[A] @core.HasShape for ContextPolynomial[A]
pub impl[A] @core.HasTermCount for ContextPolynomial[A]
pub impl[A] @core.IsZero for ContextPolynomial[A]
没有 Eq 实例;请改为比较 to_terms()(以及 context())。
ContextSubstitutionValue
代换中某一变量的替换值:一个系数,或同一上下文上的多项式。
pub(all) enum ContextSubstitutionValue[A] {
Scalar(A)
Polynomial(ContextPolynomial[A])
}
构造器是类型导向的,因此在代换列表中可以直接写 Scalar(2) 和 Polynomial(q),无需限定。
构造
ContextPolynomial::from_named_terms_as_terms, ContextPolynomial::from_named_terms_as_sparse
由命名项构造多项式,每一项是一组 (variable, exponent) 因子和一个系数,存储为项数组或稀疏映射。同一变量的重复因子会将指数相加,相等的单项式会合并。当某个因子使用了上下文之外的变量时中止(abort)。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::from_named_terms_as_terms(@Luna-Flow/luna-poly/core.VariableContext, Array[(Array[(@Luna-Flow/luna-poly/core.Variable, UInt)], A)]) -> Self[A]
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::from_named_terms_as_sparse(@Luna-Flow/luna-poly/core.VariableContext, Array[(Array[(@Luna-Flow/luna-poly/core.Variable, UInt)], A)]) -> Self[A]
ContextPolynomial::from_named_terms_as_terms_checked, ContextPolynomial::from_named_terms_as_sparse_checked
与上面相同,但当某个因子使用了上下文中不包含的变量时返回 None。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::from_named_terms_as_terms_checked(@Luna-Flow/luna-poly/core.VariableContext, Array[(Array[(@Luna-Flow/luna-poly/core.Variable, UInt)], A)]) -> Self[A]?
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::from_named_terms_as_sparse_checked(@Luna-Flow/luna-poly/core.VariableContext, Array[(Array[(@Luna-Flow/luna-poly/core.Variable, UInt)], A)]) -> Self[A]?
ContextPolynomial::from_term_polynomial, ContextPolynomial::from_sparse_polynomial
将按下标寻址的多项式绑定到上下文:多项式的变量 成为上下文中下标为 的变量。
pub fn[A] ContextPolynomial::from_term_polynomial(@Luna-Flow/luna-poly/core.VariableContext, @term.TermPolynomial[A]) -> Self[A]
pub fn[A] ContextPolynomial::from_sparse_polynomial(@Luna-Flow/luna-poly/core.VariableContext, @sparse.SparsePolynomial[A]) -> Self[A]
ContextPolynomial::constant
上下文上的常数多项式 ,以稀疏形式存储。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::constant(@Luna-Flow/luna-poly/core.VariableContext, A) -> Self[A]
ContextPolynomial::variable
由上下文中的一个变量构成的多项式,以稀疏形式存储。当上下文不包含该变量时中止(abort)。
pub fn[A : Eq + @luna-generic.AddMonoid + @luna-generic.One] ContextPolynomial::variable(@Luna-Flow/luna-poly/core.VariableContext, @Luna-Flow/luna-poly/core.Variable) -> Self[A]
ContextPolynomial::variable_checked
与 variable 相同,但变量不在上下文中时返回 None。
pub fn[A : Eq + @luna-generic.AddMonoid + @luna-generic.One] ContextPolynomial::variable_checked(@Luna-Flow/luna-poly/core.VariableContext, @Luna-Flow/luna-poly/core.Variable) -> Self[A]?
test "construction" {
let ctx = @immut.VariableContext::from_names(["x", "y"])
let x = ctx.require_variable("x")
let y = ctx.require_variable("y")
let p = @immut.ContextPolynomial::from_named_terms_as_sparse(ctx, [
([(x, 2U)], 1),
([(x, 1U), (y, 1U)], 3),
([(y, 1U), (x, 1U)], 1),
([], 4),
])
inspect(p, content="4 + 1 * x^2 + 4 * x * y")
let q : @immut.ContextPolynomial[Int] = @immut.ContextPolynomial::variable(ctx, y)
inspect(q, content="1 * y")
let stranger = @immut.VariableContext::from_names(["z"]).require_variable("z")
let missing : @immut.ContextPolynomial[Int]? = @immut.ContextPolynomial::variable_checked(ctx, stranger)
assert_true(missing is None)
}
查询与转换
ContextPolynomial::context
返回多项式所绑定的上下文。
pub fn[A] ContextPolynomial::context(Self[A]) -> @Luna-Flow/luna-poly/core.VariableContext
ContextPolynomial::to_terms
按存储顺序返回按下标寻址的项:项存储为降序,稀疏存储为升序。
pub fn[A] ContextPolynomial::to_terms(Self[A]) -> Array[(@Luna-Flow/luna-poly/core.ExponentVector, A)]
ContextPolynomial::to_term_polynomial, ContextPolynomial::to_sparse_polynomial
以所请求的按下标寻址存储形式返回该多项式,必要时进行转换。上下文会被丢弃。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::to_term_polynomial(Self[A]) -> @term.TermPolynomial[A]
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::to_sparse_polynomial(Self[A]) -> @sparse.SparsePolynomial[A]
ContextPolynomial::term_count, ContextPolynomial::arity, ContextPolynomial::is_zero, ContextPolynomial::shape
项数、使用中的变量个数(所用的最大下标加一)、是否没有任何项,以及 PolynomialShape::Contextual(context~, arity~, term_count~)。
pub fn[A] ContextPolynomial::term_count(Self[A]) -> Int
pub fn[A] ContextPolynomial::arity(Self[A]) -> Int
pub fn[A] ContextPolynomial::is_zero(Self[A]) -> Bool
pub fn[A] ContextPolynomial::shape(Self[A]) -> @Luna-Flow/luna-poly/core.PolynomialShape
ContextPolynomial::to_string
使用上下文中的变量名,按存储顺序把各项渲染为 c * x^2 * y 的形式;零多项式打印为系数零。
pub fn[A : Show + @luna-generic.Zero] ContextPolynomial::to_string(Self[A]) -> String
求值
ContextPolynomial::eval
按下标给出取值进行求值,与 TermPolynomial::eval 相同:values[i] 是上下文中变量 的取值。当 values.length() < arity() 时中止(abort)。
pub fn[A : @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval(Self[A], Array[A]) -> A
ContextPolynomial::eval_checked
与 eval 相同,但当 values 短于 arity() 时返回 None。
pub fn[A : @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_checked(Self[A], Array[A]) -> A?
ContextPolynomial::eval_named
按变量给出取值进行求值。上下文中下标小于 arity() 的每个变量都必须恰好赋值一次;对上下文中更靠后的变量的赋值会被接受并忽略。遇到上下文之外的变量、缺失的赋值或重复的赋值时中止(abort)。
pub fn[A : @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_named(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, A)]) -> A
ContextPolynomial::eval_named_checked
与 eval_named 相同,但在同样的情形下返回 None。
pub fn[A : @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_named_checked(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, A)]) -> A?
test "evaluation" {
let ctx = @immut.VariableContext::from_names(["x", "y"])
let x = ctx.require_variable("x")
let y = ctx.require_variable("y")
let p = @immut.ContextPolynomial::from_named_terms_as_terms(ctx, [([(x, 2U)], 1), ([(x, 1U), (y, 1U)], 3)])
inspect(p.eval([2, 5]), content="34")
inspect(p.eval_named([(y, 5), (x, 2)]), content="34")
assert_true(p.eval_named_checked([(x, 2)]) is None)
assert_true(p.eval_named_checked([(x, 2), (x, 3), (y, 5)]) is None)
}
部分求值与代换
下面的所有形式都返回同一上下文上的多项式;被赋值的变量只是不再出现在其中。替换是同时进行的,一遍完成:替换多项式本身不会再被代换。
ContextPolynomial::substitute
把列出的每个变量替换为标量或基于相等上下文的多项式,未列出的变量保持不变。当变量不在上下文中、某变量被列出两次,或替换多项式的上下文不同时中止(abort)。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::substitute(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, ContextSubstitutionValue[A])]) -> Self[A]
ContextPolynomial::substitute_checked
与 substitute 相同,但在同样的情形下返回 None。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::substitute_checked(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, ContextSubstitutionValue[A])]) -> Self[A]?
ContextPolynomial::substitute_names
与 substitute 相同,但变量以 Luna-Flow/type_theory 的 Name 值指定,并在多项式的上下文中解析。当名字不在上下文中时也会中止(abort);两个同名条目视为重复。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::substitute_names(Self[A], Array[(@Luna-Flow/type_theory/core.Name, ContextSubstitutionValue[A])]) -> Self[A]
ContextPolynomial::substitute_names_checked
与 substitute_names 相同,但在同样的情形下返回 None。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::substitute_names_checked(Self[A], Array[(@Luna-Flow/type_theory/core.Name, ContextSubstitutionValue[A])]) -> Self[A]?
ContextPolynomial::eval_partial, ContextPolynomial::eval_partial_checked
对部分变量代入标量:eval_partial(a) 就是把每个值包装为 Scalar 后的 substitute,失败情形相同。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_partial(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, A)]) -> Self[A]
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_partial_checked(Self[A], Array[(@Luna-Flow/luna-poly/core.Variable, A)]) -> Self[A]?
ContextPolynomial::eval_partial_named, ContextPolynomial::eval_partial_named_checked
使用 type_theory 名字的同类操作:以标量为值的 substitute_names。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_partial_named(Self[A], Array[(@Luna-Flow/type_theory/core.Name, A)]) -> Self[A]
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::eval_partial_named_checked(Self[A], Array[(@Luna-Flow/type_theory/core.Name, A)]) -> Self[A]?
无论输入采用何种存储,每次代换的结果都以稀疏形式存储。
test "substitution" {
let ctx = @immut.VariableContext::from_names(["x", "y"])
let x = ctx.require_variable("x")
let y = ctx.require_variable("y")
let p = @immut.ContextPolynomial::from_named_terms_as_sparse(ctx, [([(x, 2U)], 1), ([(y, 1U)], 1)])
let y_plus_1 = @immut.ContextPolynomial::from_named_terms_as_sparse(ctx, [([(y, 1U)], 1), ([], 1)])
inspect(p.substitute([(x, Polynomial(y_plus_1))]), content="1 + 3 * y + 1 * y^2")
inspect(p.eval_partial([(x, 3)]), content="9 + 1 * y")
let named = p.eval_partial_named([(y.to_type_theory_name(), 10)])
inspect(named, content="10 + 1 * x^2")
assert_true(p.substitute_checked([(x, Scalar(1)), (x, Scalar(2))]) is None)
assert_true(p.substitute_names_checked([(@tt_core.Name::new("w"), Scalar(1))]) is None)
}
算术
ContextPolynomial::add, ContextPolynomial::sub, ContextPolynomial::mul, ContextPolynomial::neg
运算符 +、-、* 和一元 -。当两个上下文不同时,二元运算符会中止(abort)。两个项存储的操作数得到项存储的结果,两个稀疏操作数得到稀疏结果,混合操作数得到稀疏结果。取负保持存储形式不变。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::add(Self[A], Self[A]) -> Self[A]
pub fn[A : Eq + @luna-generic.AddMonoid + Neg] ContextPolynomial::sub(Self[A], Self[A]) -> Self[A]
pub fn[A : Eq + @luna-generic.AddMonoid + Mul] ContextPolynomial::mul(Self[A], Self[A]) -> Self[A]
pub fn[A : Eq + @luna-generic.Zero + Neg] ContextPolynomial::neg(Self[A]) -> Self[A]
ContextPolynomial::add_checked, ContextPolynomial::mul_checked
与 + 和 * 相同,但上下文不同时返回 None。
pub fn[A : Eq + @luna-generic.AddMonoid] ContextPolynomial::add_checked(Self[A], Self[A]) -> Self[A]?
pub fn[A : Eq + @luna-generic.AddMonoid + Mul] ContextPolynomial::mul_checked(Self[A], Self[A]) -> Self[A]?
ContextPolynomial::pow
以相同存储形式返回 ;pow(0) 是常数一。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::pow(Self[A], UInt) -> Self[A]
test "arithmetic" {
let ctx = @immut.VariableContext::from_names(["x"])
let x = ctx.require_variable("x")
let a = @immut.ContextPolynomial::from_named_terms_as_terms(ctx, [([(x, 1U)], 1)])
let b = @immut.ContextPolynomial::constant(ctx, 1)
inspect((a + b).pow(2), content="1 + 2 * x + 1 * x^2")
let other = @immut.ContextPolynomial::constant(@immut.VariableContext::from_names(["t"]), 1)
assert_true(a.add_checked(other) is None)
assert_true(a.mul_checked(b) is Some(_))
}
泛型访问
ContextPolynomial::ops
返回 ContextOps 记录:from_terms 构造项存储的多项式,eval_named_checked、add_checked 和 mul_checked 即上面的方法。
pub fn[A : Eq + @luna-generic.AddMonoid + Mul + @luna-generic.One] ContextPolynomial::ops() -> @Luna-Flow/luna-poly/core.ContextOps[Self[A], A]
test "ops" {
let ctx = @immut.VariableContext::from_names(["x"])
let x = ctx.require_variable("x")
let ops = @immut.ContextPolynomial::ops()
let p = ops.from_terms(ctx, [(@immut.ExponentVector::from_array([1U]), 2)])
debug_inspect(ops.eval_named_checked(p, [(x, 5)]), content="Some(10)")
}
已弃用
为源码兼容而保留的隐藏方法形式:
| 已弃用 | 替代方案 |
|---|---|
p.output(logger) | to_string 或字符串插值 |
p.to_repr() | Repr(p) 或 debug_inspect |