poly API

poly 包通过在 Dual[T] 上求值,对 Luna-Flow/luna-poly 中的多项式在某点处求导。它支持稠密一元多项式和单变量稀疏多项式。方法的原理见 poly 设计。

源码:src/poly/poly.mbt。

导入

import {
  "Luna-Flow/autodiff/poly",
  "Luna-Flow/luna-poly/immut/dense",
  "Luna-Flow/luna-poly/immut/sparse",
}

示例中用 @poly 表示本包,用 @dense 和 @sparse 表示 luna-poly 的包。@poly.DensePolynomial 和 @poly.SparsePolynomial 与 @dense.DensePolynomial 和 @sparse.SparsePolynomial 是同一类型。

每个函数都要求 T : Eq + Semiring:Semiring 用于算术运算,Eq 则是因为 luna-poly 在构建提升后的多项式时会对系数做规范化。不需要 NatHomomorphism 或除法,因此整数多项式同样适用。

稠密多项式

eval_dual

在对偶数输入处对稠密多项式求值。

pub fn[T : Eq + @luna-generic.Semiring] eval_dual(@dense.DensePolynomial[T], @dual.Dual[T]) -> @dual.Dual[T]

对于 x=a+bεx = a + b\varepsilon,结果为 p(a)+p′(a) b εp(a) + p'(a)\,b\,\varepsilon。系数通过 Dual::constant 提升,提升后的多项式用 DensePolynomial::eval(Horner 法则)求值。代价:O(deg⁡p)O(\deg p) 次对偶数运算,外加一个存放提升后系数的数组。可用它把多项式嵌入更大的被求导计算中,例如 eval_dual(p, x.sin())。

dense_value_and_derivative_at

返回 (p(x),p′(x))(p(x), p'(x))。

pub fn[T : Eq + @luna-generic.Semiring] dense_value_and_derivative_at(@dense.DensePolynomial[T], T) -> (T, T)

它就是把 eval_dual(p, Dual::variable(x)) 拆分成两个分量。

dense_derivative_at

返回 p′(x)p'(x)。

pub fn[T : Eq + @luna-generic.Semiring] dense_derivative_at(@dense.DensePolynomial[T], T) -> T
test "dense polynomial derivative" {
  // p(x) = 1 + 2x + x^3
  let p = @dense.DensePolynomial::from_coefficients([1.0, 2.0, 0.0, 1.0])
  assert_eq(@poly.dense_value_and_derivative_at(p, 3.0), (34.0, 29.0))
  assert_eq(@poly.dense_derivative_at(p, 3.0), 29.0)
  let y = @poly.eval_dual(p, @autodiff.Dual::new(3.0, 4.0))
  assert_eq(y, @autodiff.Dual::new(34.0, 116.0)) // p'(3) * 4
}

单变量稀疏多项式

这些函数把 SparsePolynomial 视为关于其第一个变量的多项式:用单一赋值 [x] 对其求值。

sparse_univariate_eval_dual

在对偶数输入处对单变量稀疏多项式求值。

pub fn[T : Eq + @luna-generic.Semiring] sparse_univariate_eval_dual(@sparse.SparsePolynomial[T], @dual.Dual[T]) -> @dual.Dual[T]

结果为 p(a)+p′(a) b εp(a) + p'(a)\,b\,\varepsilon。系数通过 Dual::constant 提升,每一项 c xec\,x^e 用二进制快速幂求值,因此代价为 O(∑termslog⁡e)O(\sum_{\text{terms}} \log e) 次对偶数运算,缺失的次数不产生任何开销。

sparse_univariate_value_and_derivative_at

对单变量稀疏多项式返回 (p(x),p′(x))(p(x), p'(x))。

pub fn[T : Eq + @luna-generic.Semiring] sparse_univariate_value_and_derivative_at(@sparse.SparsePolynomial[T], T) -> (T, T)

sparse_univariate_derivative_at

对单变量稀疏多项式返回 p′(x)p'(x)。

pub fn[T : Eq + @luna-generic.Semiring] sparse_univariate_derivative_at(@sparse.SparsePolynomial[T], T) -> T
test "sparse polynomial derivative" {
  // p(x) = 4 - x + 2x^3
  let p = @sparse.SparsePolynomial::from_array([
    ([3U], 2.0),
    ([1U], -1.0),
    ([0U], 4.0),
  ])
  assert_eq(@poly.sparse_univariate_value_and_derivative_at(p, 2.0), (18.0, 23.0))
  assert_eq(@poly.sparse_univariate_derivative_at(p, 2.0), 23.0)
}

兼容名称

早期版本使用较短的名称。它们仍然可用,没有被弃用,并会调用上面的函数。

名称等同于
value_and_derivative_atdense_value_and_derivative_at
derivative_atdense_derivative_at
eval_sparse_dualsparse_univariate_eval_dual
sparse_value_and_derivative_atsparse_univariate_value_and_derivative_at
sparse_derivative_atsparse_univariate_derivative_at

value_and_derivative_at

pub fn[T : Eq + @luna-generic.Semiring] value_and_derivative_at(@dense.DensePolynomial[T], T) -> (T, T)

derivative_at

pub fn[T : Eq + @luna-generic.Semiring] derivative_at(@dense.DensePolynomial[T], T) -> T

eval_sparse_dual

pub fn[T : Eq + @luna-generic.Semiring] eval_sparse_dual(@sparse.SparsePolynomial[T], @dual.Dual[T]) -> @dual.Dual[T]

sparse_value_and_derivative_at

pub fn[T : Eq + @luna-generic.Semiring] sparse_value_and_derivative_at(@sparse.SparsePolynomial[T], T) -> (T, T)

sparse_derivative_at

pub fn[T : Eq + @luna-generic.Semiring] sparse_derivative_at(@sparse.SparsePolynomial[T], T) -> T

新代码中请优先使用较长的名称:它们明确指出了所针对的表示形式和导数种类。

重新导出的类型

DensePolynomial

pub using @dense {type DensePolynomial}

SparsePolynomial

pub using @sparse {type SparsePolynomial}

Dual

pub using @dual {type Dual}