Rust API 参考:求值与 JIT

oCAS 的求值系统将符号表达式编译为栈式虚拟机指令序列,然后在数值类型上高效执行。支持三种执行后端:解释器(通用)、JIT 编译(Cranelift 生成原生机器码)、SIMD 批量求值(向量化处理多组参数)。

模块路径:ocas_eval

编译管线:

Atom (arena-backed)
  → EvalTree (owned intermediate, 可选常量折叠优化)
  → Instr sequence (编译 + 优化 pass)
  → ExpressionEvaluator (栈式 VM 解释器)
  → 或 JitCompiledFunction (Cranelift, feature = "jit")
  → 或 VectorEvaluator (SIMD 批量, feature = "simd")

Feature flags:

Flag功能
jit启用 Cranelift JIT 编译后端
simd启用 SIMD 批量求值(pulp,运行时检测 SSE2/AVX2/AVX-512)
fast-poly启用快速多项式求值优化

导入方式:

#![allow(unused)]
fn main() {
use ocas_eval::{
    ExpressionEvaluator, EvaluationDomain, PowfExtension,
    FunctionMap, EvalTree,
    Instr, Instruction, Slot,
    EvaluationError,
    StreamingEvaluator,
    compile_atom, compile_atom_with,
    compile_atoms_multi, compile_atoms_multi_with,
};
use ocas_eval::instruction::BuiltinOp;

// JIT (feature = "jit")
use ocas_eval::jit::{JitCompiledFunction, JitCompiledF32, JitEngine, FloatWidth};

// SIMD (feature = "simd")
use ocas_eval::simd::{VectorEvaluator, VectorEvaluatorF32};
}

EvalTree

签名:

#![allow(unused)]
fn main() {
pub enum EvalTree {
    Num(f64),
    Var(String),
    Fun(String, Vec<EvalTree>),
    Add(Vec<EvalTree>),
    Mul(Vec<EvalTree>),
    Pow(Box<EvalTree>, Box<EvalTree>),
}
}

功能:arena 无关的、拥有所有权的中间表示。从 Atom 转换而来,断开与 arena 生命周期的绑定,使编译管线可自由进行多遍优化。

变体:

变体说明
Num(f64)数值常量
Var(String)变量引用
Fun(String, Vec<EvalTree>)命名函数应用
Add(Vec<EvalTree>)求和
Mul(Vec<EvalTree>)乘积
Pow(Box<EvalTree>, Box<EvalTree>)幂运算 base^exp

EvalTree::from_atom

签名:pub fn from_atom(atom: Atom<'_>) -> Self

功能:从 Atom 转换为拥有的 EvalTree。递归遍历表达式树,将 arena 句柄转为独立数据。

参数:

参数类型说明
atomAtom<'_>源表达式

返回值:拥有的 EvalTree。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::AtomArena;
use ocas_eval::EvalTree;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let atom = ctx.add(&[ctx.var("x"), ctx.num(2)]);
let tree = EvalTree::from_atom(atom);
// tree = Add([Var("x"), Num(2.0)])
}

EvalTree::fold_constants

签名:pub fn fold_constants(&self) -> EvalTree

功能:折叠常量子树并应用代数恒等式。在编译前运行,减少指令数。

优化规则:

模式规则
Add删除零项;全常量项求和;单项折叠
Mul吸收零因子;删除单位因子;全常量因子求积;单因子折叠
Powx^1 → x,x^0 → 1,Num^Num 直接求值
Fun内建函数的全常量参数直接求值(外部函数不折叠,可能有副作用)

返回值:优化后的新 EvalTree。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::EvalTree;

let tree = EvalTree::Add(vec![
    EvalTree::Num(3.0),
    EvalTree::Mul(vec![
        EvalTree::Num(0.0),
        EvalTree::Var("x".into()),
    ]),
]);
let folded = tree.fold_constants();
assert_eq!(folded, EvalTree::Num(3.0));
// 输出:3 + 0*x → 3
}

ExpressionEvaluator<T>

签名:

#![allow(unused)]
fn main() {
pub struct ExpressionEvaluator<T: EvaluationDomain> { /* private fields */ }
}

功能:编译好的表达式,可反复执行数值求值。持有指令序列、预分配栈、常量表和可选的用户自定义函数注册表。类型参数 T 实现 EvaluationDomain,通常为 f64。

编译方法

ExpressionEvaluator::compile

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn compile(atom: Atom<'_>) -> Result<Self>
}
}

功能:将 Atom 编译为可执行求值器。内部先转为 EvalTree,再折叠常量、生成指令序列。

参数:

参数类型说明
atomAtom<'_>源表达式

返回值:Ok(ExpressionEvaluator<T>) 或编译错误。

错误:见 EvaluationError。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.mul(&[ctx.var("x"), ctx.var("x")]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
assert_eq!(eval.param_count(), 1);
assert_eq!(eval.result_count(), 1);
}

ExpressionEvaluator::compile_with

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn compile_with(atom: Atom<'_>, map: FunctionMap<T>) -> Result<Self>
}
}

功能:编译表达式,并传入用户自定义函数注册表。表达式中出现的 ExternalFun 节点通过 map 解析。

参数:

参数类型说明
atomAtom<'_>源表达式
mapFunctionMap<T>自定义函数注册表(无外部函数时传入空映射)

返回值:Ok(ExpressionEvaluator<T>) 或编译/解析错误。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, FunctionMap};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.fun("myfunc", &[ctx.var("x")]);

let mut fmap = FunctionMap::<f64>::new();
fmap.register("myfunc", 1, Box::new(|args| args[0] * args[0]));

let eval = ExpressionEvaluator::compile_with(expr, fmap).unwrap();
let result = eval.evaluate(&[3.0]).unwrap();
assert_eq!(result, vec![9.0]);
// 输出:myfunc(3) = 3² = 9
}

ExpressionEvaluator::compile_multi

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn compile_multi(atoms: &[Atom<'_>]) -> Result<Self>
}
}

功能:将多个 Atom 编译为单个多输出求值器。跨所有输出共享常量、公共子表达式(CSE)和栈槽位,避免重复计算。

参数:

参数类型说明
atoms&[Atom<'_>]多个表达式

返回值:Ok(ExpressionEvaluator<T>),result_count() == atoms.len()。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let x = ctx.var("x");
let expr1 = ctx.mul(&[x, x]);       // x²
let expr2 = ctx.add(&[x, ctx.num(1)]); // x+1

let eval: ExpressionEvaluator<f64> =
    ExpressionEvaluator::compile_multi(&[expr1, expr2]).unwrap();
let results = eval.evaluate(&[3.0]).unwrap();
assert_eq!(results, vec![9.0, 4.0]);
// 输出:x²=9, x+1=4
}

ExpressionEvaluator::compile_multi_with

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn compile_multi_with(atoms: &[Atom<'_>], map: FunctionMap<T>) -> Result<Self>
}
}

功能:compile_multi 的带函数映射版本(map 直接传入,而非 Option)。

执行方法

ExpressionEvaluator::evaluate

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn evaluate(&self, params: &[T]) -> Result<Vec<T>>
}
}

功能:用给定参数值执行编译好的表达式。每次调用分配新的栈和结果缓冲区。

参数:

参数类型说明
params&[T]参数值,长度必须等于 param_count()

返回值:Ok(Vec<T>),长度等于 result_count()。

错误:

错误条件
WrongArityparams.len() != param_count()
DivisionByZero求值过程中遇到除零
FunctionNotFound外部函数未注册

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let result = eval.evaluate(&[3.0]).unwrap();
assert_eq!(result[0], 10.0);
// 输出:3² + 1 = 10
}

ExpressionEvaluator::evaluate_with_stack

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> ExpressionEvaluator<T> {
    pub fn evaluate_with_stack(
        &self,
        params: &[T],
        stack: &mut Vec<T>,
        results: &mut Vec<T>,
    ) -> Result<()>
}
}

功能:使用调用者提供的缓冲区执行求值,避免每次调用的堆分配。流式和批处理场景应优先使用此方法。

参数:

参数类型说明
params&[T]参数值
stack&mut Vec<T>栈缓冲区(自动 resize 到 stack_size())
results&mut Vec<T>结果缓冲区(自动填充)

返回值:Ok(()) 或求值错误。

访问器

ExpressionEvaluator::param_count

签名:pub fn param_count(&self) -> usize

功能:返回期望的参数个数。

ExpressionEvaluator::result_count

签名:pub fn result_count(&self) -> usize

功能:返回输出结果个数(单输出表达式为 1,compile_multi 创建的可能大于 1)。

ExpressionEvaluator::stack_size

签名:pub fn stack_size(&self) -> usize

功能:返回求值所需栈大小(参数 + 常量 + 临时值 + 输出)。evaluate_with_stack 的 stack 参数应预分配此容量。


JIT 编译(feature = "jit")

JIT 后端使用 Cranelift 将指令序列编译为原生机器码,常量嵌入为立即数,调用 libm 进行超越函数计算。性能通常比解释器快 10 倍以上。

ExpressionEvaluator::compile_jit

签名:

#![allow(unused)]
fn main() {
#[cfg(feature = "jit")]
impl ExpressionEvaluator<f64> {
    pub fn compile_jit(&self) -> Result<JitCompiledFunction>
}
}

功能:将当前求值器的指令序列编译为双精度(f64)原生代码。

返回值:Ok(JitCompiledFunction) 或编译错误。

错误:

错误条件
UnsupportedOperation包含 JIT 无法降低的指令(如外部函数、sec/csc/cot)
JitCompilationErrorCranelift 后端编译失败

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let jit = eval.compile_jit().unwrap();
let result = jit.call(&[3.0]);
assert_eq!(result, vec![10.0]);
// 输出:3² + 1 = 10(原生机器码执行)
}

ExpressionEvaluator::compile_jit_f32

签名:

#![allow(unused)]
fn main() {
#[cfg(feature = "jit")]
impl ExpressionEvaluator<f64> {
    pub fn compile_jit_f32(&self) -> Result<JitCompiledF32>
}
}

功能:将指令序列编译为单精度(f32)原生代码。常量从 f64 窄化为 f32;结果精度为 f32。

错误:与 compile_jit 相同。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.mul(&[ctx.var("x"), ctx.num(2)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let jit_f32 = eval.compile_jit_f32().unwrap();
let result = jit_f32.call(&[3.0_f32]);
assert_eq!(result, vec![6.0_f32]);
// 输出:3 × 2 = 6(f32 精度)
}

JitCompiledFunction

签名:

#![allow(unused)]
fn main() {
pub struct JitCompiledFunction { /* private fields */ }
}

功能:JIT 编译好的双精度函数,可反复调用。

JitCompiledFunction::call

签名:pub fn call(&self, params: &[f64]) -> Vec<f64>

功能:用给定参数调用 JIT 编译的函数。每次分配新的结果向量。

参数:

参数类型说明
params&[f64]参数值

返回值:结果向量,长度等于 result_count()。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let jit = eval.compile_jit().unwrap();
let result = jit.call(&[3.0]);
assert_eq!(result, vec![10.0]);
// 输出:x²+1 在 x=3 时的值 10
}

JitCompiledFunction::call_into

签名:pub fn call_into(&self, params: &[f64], results: &mut [f64])

功能:调用 JIT 函数,结果写入调用者提供的缓冲区,避免每次调用的堆分配。results.len() 必须至少为 result_count()。

参数:

参数类型说明
params&[f64]参数值
results&mut [f64]结果缓冲区

示例:

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let jit = eval.compile_jit().unwrap();
let mut buf = vec![0.0_f64; jit.result_count()];
jit.call_into(&[42.0], &mut buf);
assert_eq!(buf, vec![1765.0]);
// 结果在 buf 中(42² + 1 = 1765),无堆分配
}

JitCompiledFunction::param_count

签名:pub fn param_count(&self) -> usize

功能:返回期望的参数个数。

JitCompiledFunction::result_count

签名:pub fn result_count(&self) -> usize

功能:返回结果个数。

JitCompiledF32

签名:

#![allow(unused)]
fn main() {
pub struct JitCompiledF32 { /* private fields */ }
}

功能:JIT 编译好的单精度函数。API 与 JitCompiledFunction 完全对称,参数和返回值为 f32。

JitCompiledF32::call

签名:pub fn call(&self, params: &[f32]) -> Vec<f32>

JitCompiledF32::call_into

签名:pub fn call_into(&self, params: &[f32], results: &mut [f32])

JitCompiledF32::param_count

签名:pub fn param_count(&self) -> usize

JitCompiledF32::result_count

签名:pub fn result_count(&self) -> usize

JitEngine

签名:

#![allow(unused)]
fn main() {
pub struct JitEngine;
}

功能:JIT 编译引擎的入口点。提供底层 compile 方法,可直接从指令序列编译。

JitEngine::compile

签名:

#![allow(unused)]
fn main() {
impl JitEngine {
    pub fn compile(
        instructions: &[Instr],
        param_count: usize,
        constants: &[f64],
        result_indices: &[usize],
    ) -> Result<JitCompiledFunction>

    pub fn compile_f32(
        instructions: &[Instr],
        param_count: usize,
        constants: &[f32],
        result_indices: &[usize],
    ) -> Result<JitCompiledF32>
}
}

功能:将指令序列编译为可调用的 JIT 函数。compile 生成双精度 JitCompiledFunction,compile_f32 生成单精度 JitCompiledF32(libm 调用使用 *f 符号变体)。这是 ExpressionEvaluator::compile_jit / compile_jit_f32 的底层实现。内部 compile_module 返回 JIT 模块(由调用者保持存活)与入口函数指针,但对外只暴露编译好的函数对象。

参数:

参数类型说明
instructions&[Instr]指令序列
param_countusize参数个数
constants&[f64](compile)/ &[f32](compile_f32)常量值(嵌入为立即数)
result_indices&[usize]结果槽索引

FloatWidth

签名:

#![allow(unused)]
fn main() {
pub enum FloatWidth {
    F32,
    F64,
}
}

功能:JIT 代码生成的浮点宽度选择。F32 使用 *f 变体的 libm 函数(如 sinf),F64 使用标准 libm。


SIMD 批量求值(feature = "simd")

VectorEvaluator 使用 pulp 库实现运行时检测的 SIMD 向量化求值。在 x86_64 上自动选择 SSE2(2 路 f64)、AVX2(4 路 f64)或 AVX-512(8 路 f64)。f32 版本的通道数翻倍。

VectorEvaluator

签名:

#![allow(unused)]
fn main() {
pub struct VectorEvaluator { /* private fields */ }
}

功能:双精度 SIMD 批量求值器。将多组输入参数分为 SIMD 宽度的 chunk 并行处理,余量回退到标量。

ExpressionEvaluator::compile_vector_evaluator

签名:

#![allow(unused)]
fn main() {
#[cfg(feature = "simd")]
impl ExpressionEvaluator<f64> {
    pub fn compile_vector_evaluator(&self) -> Result<VectorEvaluator>
}
}

功能:从编译好的 ExpressionEvaluator 创建 SIMD 批量求值器。构造时检测 SIMD 宽度,预分配栈和常量缓冲区。若表达式包含外部函数(SIMD 模式不支持),返回 UnsupportedOperation。

参数:

参数类型说明
self&ExpressionEvaluator<f64>源求值器

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, simd::VectorEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let simd_eval = eval.compile_vector_evaluator().unwrap();
}

VectorEvaluator::evaluate

签名:

#![allow(unused)]
fn main() {
impl VectorEvaluator {
    pub fn evaluate(&self, params: &[Vec<f64>]) -> Result<Vec<Vec<f64>>>
}
}

功能:批量求值。params[i] 是第 i 个参数的所有采样点。所有 params[i] 长度必须相同。返回 Vec<Vec<f64>>,其中 result[j][i] 是第 i 个采样点的第 j 个输出。

参数:

参数类型说明
params&[Vec<f64>]参数向量,每个 Vec 长度相同

返回值:Ok(Vec<Vec<f64>>) 或求值错误。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, simd::VectorEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.mul(&[ctx.var("x"), ctx.var("x")]), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let simd_eval = eval.compile_vector_evaluator().unwrap();
let x_values: Vec<f64> = (0..1000).map(|i| i as f64 * 0.01).collect();
let results = simd_eval.evaluate(&[x_values]).unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].len(), 1000);
assert_eq!(results[0][0], 1.0);
// results[0] 包含 1000 个 x²+1 的值,SIMD 并行计算
}

VectorEvaluatorF32

签名:

#![allow(unused)]
fn main() {
pub struct VectorEvaluatorF32 { /* private fields */ }
}

功能:单精度 SIMD 批量求值器。通道数是 VectorEvaluator 的两倍(如 AVX2 上为 8 路 f32 vs 4 路 f64)。

ExpressionEvaluator::compile_vector_evaluator_f32

签名:

#![allow(unused)]
fn main() {
#[cfg(feature = "simd")]
impl ExpressionEvaluator<f64> {
    pub fn compile_vector_evaluator_f32(&self) -> Result<VectorEvaluatorF32>
}
}

功能:从 f64 求值器创建 f32 SIMD 求值器,常量窄化为 f32。外部函数同样不支持(返回 UnsupportedOperation)。

VectorEvaluatorF32::evaluate

签名:pub fn evaluate(&self, params: &[Vec<f32>]) -> Result<Vec<Vec<f32>>>

功能:单精度批量求值,接口与 VectorEvaluator::evaluate 对称。


StreamingEvaluator<'a, T>

签名:

#![allow(unused)]
fn main() {
pub struct StreamingEvaluator<'a, T: EvaluationDomain> {
    evaluator: &'a ExpressionEvaluator<T>,
    params: Vec<T>,
    stack: Vec<T>,
    results: Vec<T>,
}
}

功能:流式求值器,复用内部缓冲区,处理任意长的输入流时内存使用恒定。所有 scratch 内存(参数暂存、求值栈、结果缓冲区)在创建时一次性分配,每行复用。

StreamingEvaluator::new

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> StreamingEvaluator<'_, T> {
    pub fn new(evaluator: &ExpressionEvaluator<T>) -> StreamingEvaluator<'_, T>
}
}

功能:创建流式求值器,预分配所有缓冲区。

参数:

参数类型说明
evaluator&ExpressionEvaluator<T>源求值器(借用)

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, StreamingEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.var("x"), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let mut stream = StreamingEvaluator::new(&eval);
}

StreamingEvaluator::for_each

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> StreamingEvaluator<'_, T> {
    pub fn for_each<I, S, F>(&mut self, rows: I, mut sink: F) -> Result<usize>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<[T]>,
        F: FnMut(&[T]),
}
}

功能:处理输入流的每一行,对每行结果调用 sink 回调。内存使用恒定,不随行数增长。

参数:

参数类型说明
rowsI: IntoIterator<Item = S>输入行迭代器,每行 AsRef<[T]> 长度等于 param_count()
sinkFnMut(&[T])结果回调,&[T] 长度等于 result_count(),仅在回调内有效

返回值:Ok(处理的行数) 或求值错误。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, StreamingEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.var("x"), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let mut stream = StreamingEvaluator::new(&eval);
let rows = (0..1_000_000).map(|i| [i as f64]);
let n = stream.for_each(rows, |results| {
    // results[0] 为当前行的 x+1,仅在回调内有效
}).unwrap();
assert_eq!(n, 1_000_000);
}

参见:StreamingEvaluator::evaluate_chunk

StreamingEvaluator::evaluate_chunk

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain + PowfExtension> StreamingEvaluator<'_, T> {
    pub fn evaluate_chunk<S: AsRef<[T]>>(&mut self, rows: &[S]) -> Result<Vec<Vec<T>>>
}
}

功能:处理一批行并收集所有结果。适用于有界批次;无界流应使用 for_each。

参数:

参数类型说明
rows&[S]输入行切片

返回值:Ok(Vec<Vec<T>>),每个 Vec<T> 对应一行的结果。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, StreamingEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.var("x"), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let mut stream = StreamingEvaluator::new(&eval);
let rows: Vec<[f64; 1]> = (0..100).map(|i| [i as f64]).collect();
let all_results = stream.evaluate_chunk(&rows).unwrap();
assert_eq!(all_results.len(), 100);
assert_eq!(all_results[0][0], 1.0); // x=0 → 0+1=1
assert_eq!(all_results[99][0], 100.0); // x=99 → 99+1=100
}

FunctionMap<T>

签名:

#![allow(unused)]
fn main() {
pub struct FunctionMap<T: EvaluationDomain> {
    entries: Vec<(String, FunctionEntry<T>)>,
    name_to_idx: HashMap<String, usize>,
    aliases: HashMap<String, String>,
}
}

功能:用户自定义函数注册表。允许在表达式求值期间调用注册的外部函数。名称查找不区分大小写,支持别名。

FunctionMap::new

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain> FunctionMap<T> {
    pub fn new() -> Self
}
}

功能:创建空的函数映射。

FunctionMap::register

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain> FunctionMap<T> {
    pub fn register(&mut self, name: &str, arity: usize, func: Box<dyn Fn(&[T]) -> T + Send + Sync>)
}
}

功能:注册一个外部函数。

参数:

参数类型说明
name&str函数名(不区分大小写)
arityusize期望的参数个数
funcBox<dyn Fn(&[T]) -> T + Send + Sync>函数实现

示例:

#![allow(unused)]
fn main() {
use ocas_eval::FunctionMap;

let mut fmap = FunctionMap::<f64>::new();
fmap.register("square", 1, Box::new(|args| args[0] * args[0]));
fmap.register("add3", 3, Box::new(|args| args[0] + args[1] + args[2]));
}

FunctionMap::register_alias

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain> FunctionMap<T> {
    pub fn register_alias(&mut self, alias: &str, canonical: &str)
}
}

功能:为已注册的函数名添加别名。查找 alias 时会重定向到 canonical。

FunctionMap::resolve

签名:

#![allow(unused)]
fn main() {
impl<T: EvaluationDomain> FunctionMap<T> {
    pub fn resolve(&self, name: &str) -> Option<&FunctionEntry<T>>
}
}

功能:按名称查找函数(解析别名和大小写)。

FunctionMap::index_of

签名:pub fn index_of(&self, name: &str) -> Option<usize>

功能:返回函数在映射中的索引(用于指令中的 fn_idx)。

FunctionMap::call_by_index

签名:pub fn call_by_index(&self, idx: usize, args: &[T]) -> Option<T>

功能:按索引调用函数。

FunctionMap::len / is_empty

签名:pub fn len(&self) -> usize / pub fn is_empty(&self) -> bool

功能:返回已注册函数数量 / 判断是否为空。

FunctionEntry<T>

签名:

#![allow(unused)]
fn main() {
pub struct FunctionEntry<T: EvaluationDomain> {
    pub arity: usize,
    // private func field
}
}

功能:已注册的外部函数条目。arity 为期望的参数个数。


指令集

Slot

签名:

#![allow(unused)]
fn main() {
pub enum Slot {
    Param(usize),
    Const(usize),
    Temp(usize),
}
}

功能:求值器栈中的命名槽位。用于公开的 Instruction 类型,以语义而非原始索引引用栈位置。

变体说明
Param(usize)参数槽,0 基索引
Const(usize)常量槽,0 基索引
Temp(usize)临时值槽,0 基索引

Instruction

签名:

#![allow(unused)]
fn main() {
pub enum Instruction {
    Add(Slot, Vec<Slot>),
    Mul(Slot, Vec<Slot>),
    Pow(Slot, Slot, i64),
    Powf(Slot, Slot, Slot),
    Fun(Slot, Symbol, Slot),
    ExternalFun(Slot, usize, Vec<Slot>),
    Assign(Slot, Slot),
}
}

功能:自文档化的公开指令。与内部 Instr 不同,使用 Slot 而非原始索引,便于检查和序列化。

变体格式说明
Adddst = sum(sources)求和
Muldst = product(sources)求积
Powdst = base^exp整数次幂
Powfdst = base^exp浮点次幂
Fundst = builtin(src)内建函数
ExternalFundst = fns[idx](srcs...)外部函数
Assigndst = src复制

Instr

签名:

#![allow(unused)]
fn main() {
pub enum Instr {
    Add { dst: usize, srcs: Vec<usize> },
    Mul { dst: usize, srcs: Vec<usize> },
    Pow { dst: usize, base: usize, exp: i64 },
    Powf { dst: usize, base: usize, exp: usize },
    BuiltinOp { dst: usize, op: BuiltinOp, src: usize },
    ExternalFun { dst: usize, fn_idx: usize, srcs: Vec<usize> },
    Copy { dst: usize, src: usize },
}
}

功能:内部索引式指令,由 ExpressionEvaluator 执行。所有索引是栈中的绝对位置。

栈布局:

[params (param_count)] [constants (const_count)] [temporaries (temp_count)] [outputs (result_count)]
变体说明
Add { dst, srcs }stack[dst] = stack[srcs[0]] + stack[srcs[1]] + ...
Mul { dst, srcs }stack[dst] = stack[srcs[0]] * stack[srcs[1]] * ...
Pow { dst, base, exp }stack[dst] = stack[base]^exp,exp 为 i64
Powf { dst, base, exp }stack[dst] = stack[base]^stack[exp],浮点指数
BuiltinOp { dst, op, src }stack[dst] = op(stack[src])
ExternalFun { dst, fn_idx, srcs }stack[dst] = fns[fn_idx](&stack[srcs...])
Copy { dst, src }stack[dst] = stack[src]

BuiltinOp

签名:

#![allow(unused)]
fn main() {
pub enum BuiltinOp {
    Sin, Cos, Tan,
    Sec, Csc, Cot,
    Exp, Log,
    Sqrt, Abs,
}
}

功能:预解析的内建函数操作码。编译器在编译时将 Symbol 名称转换为 BuiltinOp 变体,避免在热路径上进行字符串匹配。

变体数学说明
Sin$\sin(x)$正弦
Cos$\cos(x)$余弦
Tan$\tan(x)$正切
Sec$\sec(x) = 1/\cos(x)$正割
Csc$\csc(x) = 1/\sin(x)$余割
Cot$\cot(x) = 1/\tan(x)$余切
Exp$e^x$指数函数
Log$\ln(x)$自然对数
Sqrt$\sqrt{x}$平方根
Abs$x

BuiltinOp::from_name

签名:pub fn from_name(name: &str) -> Option<Self>

功能:尝试从函数名解析为内建操作码。不区分大小写。"log" 和 "ln" 均映射到 Log。

参数:

参数类型说明
name&str函数名

返回值:Some(BuiltinOp) 或 None(非内建函数)。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::instruction::BuiltinOp;

assert_eq!(BuiltinOp::from_name("sin"), Some(BuiltinOp::Sin));
assert_eq!(BuiltinOp::from_name("Log"), Some(BuiltinOp::Log));
assert_eq!(BuiltinOp::from_name("ln"), Some(BuiltinOp::Log));
assert_eq!(BuiltinOp::from_name("myfunc"), None);
}

EvaluationDomain trait

签名:

#![allow(unused)]
fn main() {
pub trait EvaluationDomain: Sized + Clone + 'static {
    fn from_f64(value: f64) -> Self;
    fn zero() -> Self;
    fn one() -> Self;
    fn add_ref(&self, other: &Self) -> Self;
    fn sub_ref(&self, other: &Self) -> Self;
    fn mul_ref(&self, other: &Self) -> Self;
    fn div_ref(&self, other: &Self) -> Result<Self>;
    fn neg_ref(&self) -> Self;
    fn powi_ref(&self, exp: i64) -> Self;
    fn resolve_builtin(name: &str, arg: &Self) -> Result<Self>;
}
}

功能:可作为求值域的类型的 trait。与代数 Domain trait 不同(Domain 是对象安全的、使用 &self 接收器),EvaluationDomain 使用静态方法和值操作,兼容 f64 等 Copy 类型。

方法:

方法签名说明
from_f64fn from_f64(f64) -> Self从 f64 创建值
zerofn zero() -> Self加法单位元
onefn one() -> Self乘法单位元
add_reffn add_ref(&self, &Self) -> Self加法
sub_reffn sub_ref(&self, &Self) -> Self减法
mul_reffn mul_ref(&self, &Self) -> Self乘法
div_reffn div_ref(&self, &Self) -> Result<Self>除法,除零返回 DivisionByZero
neg_reffn neg_ref(&self) -> Self取反
powi_reffn powi_ref(&self, i64) -> Self整数次幂,exp == 0 时返回 1
resolve_builtinfn resolve_builtin(name: &str, &Self) -> Result<Self>执行内建函数

实现:

类型说明
f64标准双精度浮点(始终可用)
DoubleF64oCAS 双精度浮点(~31 位有效数字)

示例:

#![allow(unused)]
fn main() {
use ocas_eval::EvaluationDomain;

let x = f64::from_f64(3.0);
let y = f64::from_f64(2.0);
assert_eq!(x.add_ref(&y), 5.0);
assert_eq!(f64::resolve_builtin("sin", &std::f64::consts::FRAC_PI_2).unwrap(), 1.0);
}

PowfExtension trait

签名:

#![allow(unused)]
fn main() {
pub trait PowfExtension: EvaluationDomain {
    fn powf_ref(&self, exp: &Self) -> Result<Self>;
}
}

功能:浮点指数幂的扩展 trait。从 EvaluationDomain 分离出来,因为整数域无法有意义地计算 $a^b$($b$ 非整数)。

实现:f64、DoubleF64。

示例:

#![allow(unused)]
fn main() {
use ocas_eval::PowfExtension;

let base = 2.0_f64;
let exp = 0.5_f64;
let result = base.powf_ref(&exp).unwrap();
assert!((result - std::f64::consts::SQRT_2).abs() < 1e-15);
// 输出:2^0.5 ≈ 1.4142135623730951
}

编译函数

以下自由函数是 ExpressionEvaluator 编译方法的底层入口。

compile_atom

签名:

#![allow(unused)]
fn main() {
pub fn compile_atom<T: EvaluationDomain + PowfExtension>(
    atom: Atom<'_>,
) -> Result<ExpressionEvaluator<T>>
}

功能:将 Atom 编译为求值器。等价于 ExpressionEvaluator::compile。

compile_atom_with

签名:

#![allow(unused)]
fn main() {
pub fn compile_atom_with<T: EvaluationDomain + PowfExtension>(
    atom: Atom<'_>,
    function_map: Option<FunctionMap<T>>,
) -> Result<ExpressionEvaluator<T>>
}

功能:带可选函数映射的编译。

compile_tree / compile_tree_with

签名:

#![allow(unused)]
fn main() {
pub fn compile_tree<T: EvaluationDomain + PowfExtension>(
    tree: &EvalTree,
) -> Result<ExpressionEvaluator<T>>

pub fn compile_tree_with<T: EvaluationDomain + PowfExtension>(
    tree: &EvalTree,
    function_map: Option<FunctionMap<T>>,
) -> Result<ExpressionEvaluator<T>>
}

功能:从 EvalTree 编译。适用于需要先对 EvalTree 进行自定义优化再编译的场景。

compile_atoms_multi / compile_atoms_multi_with

签名:

#![allow(unused)]
fn main() {
pub fn compile_atoms_multi<T: EvaluationDomain + PowfExtension>(
    atoms: &[Atom<'_>],
) -> Result<ExpressionEvaluator<T>>

pub fn compile_atoms_multi_with<T: EvaluationDomain + PowfExtension>(
    atoms: &[Atom<'_>],
    function_map: Option<FunctionMap<T>>,
) -> Result<ExpressionEvaluator<T>>
}

功能:将多个 Atom 编译为单个多输出求值器。跨输出共享 CSE 和常量。

compile_trees_multi

签名:

#![allow(unused)]
fn main() {
pub fn compile_trees_multi<T: EvaluationDomain + PowfExtension>(
    trees: &[&EvalTree],
) -> Result<ExpressionEvaluator<T>>
}

功能:将多个 EvalTree 编译为单个多输出求值器。


EvaluationError

签名:

#![allow(unused)]
fn main() {
#[non_exhaustive]
pub enum EvaluationError {
    UndefinedVariable { name: String },
    TypeMismatch { expected: String, found: String },
    DivisionByZero,
    FunctionNotFound { name: String },
    WrongArity { name: String, expected: usize, got: usize },
    JitCompilationError { message: String },
    UnsupportedOperation { message: String },
}
}

功能:求值过程中可能产生的错误。

变体说明
UndefinedVariable { name }表达式引用了未提供的变量
TypeMismatch { expected, found }类型不匹配(如期望浮点却得到整数)
DivisionByZero除零
FunctionNotFound { name }用户自定义函数未在注册表中找到
WrongArity { name, expected, got }函数调用参数个数错误
JitCompilationError { message }JIT 编译失败(Cranelift 后端错误)
UnsupportedOperation { message }请求的操作在当前域不支持

Display 格式:

undefined variable 'x'
type mismatch: expected float, found integer
division by zero
function 'f' not found
wrong arity for 'f': expected 2, got 1
JIT compilation error: <message>
unsupported operation: <message>

示例:

#![allow(unused)]
fn main() {
use ocas_eval::EvaluationError;

let err = EvaluationError::UndefinedVariable { name: "x".into() };
assert_eq!(err.to_string(), "undefined variable 'x'");

let err = EvaluationError::WrongArity {
    name: "f".into(),
    expected: 2,
    got: 1,
};
assert_eq!(err.to_string(), "wrong arity for 'f': expected 2, got 1");
}

使用模式

基本求值

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);

// 构建 x² + 2x + 1
let x = ctx.var("x");
let expr = ctx.add(&[
    ctx.mul(&[x, x]),
    ctx.mul(&[ctx.num(2), x]),
    ctx.num(1),
]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();

// 求值
let result = eval.evaluate(&[3.0]).unwrap();
assert_eq!(result[0], 16.0); // 9 + 6 + 1 = 16
}

JIT 热循环

#![allow(unused)]
fn main() {
use ocas_eval::ExpressionEvaluator;
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.fun("sin", &[ctx.var("x")]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let jit = eval.compile_jit().unwrap();

let mut results = vec![0.0; jit.result_count()];
for i in 0..1_000_000 {
    jit.call_into(&[i as f64 * 0.001], &mut results);
    // 使用 results[0]...
}
// 零分配热循环,原生机器码执行
}

SIMD 批量处理

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, simd::VectorEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.fun("exp", &[ctx.var("x")]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let simd = eval.compile_vector_evaluator().unwrap();

let x: Vec<f64> = (0..10000).map(|i| i as f64 * 0.001).collect();
let results = simd.evaluate(&[x]).unwrap();
// results[0] 包含 10000 个 e^x 的值
}

流式处理大数据集

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, StreamingEvaluator};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.add(&[ctx.var("x"), ctx.num(1)]);

let eval: ExpressionEvaluator<f64> = ExpressionEvaluator::compile(expr).unwrap();
let mut stream = StreamingEvaluator::new(&eval);

// 处理 100 万行,内存使用恒定
let rows = (0..1_000_000).map(|i| [i as f64]);
let n = stream.for_each(rows, |_results| {
    // 处理 results...
}).unwrap();
assert_eq!(n, 1_000_000);
}

自定义函数

#![allow(unused)]
fn main() {
use ocas_eval::{ExpressionEvaluator, FunctionMap};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let expr = ctx.fun("sigmoid", &[ctx.var("x")]);

let mut fmap = FunctionMap::<f64>::new();
fmap.register("sigmoid", 1, Box::new(|args| {
    1.0 / (1.0 + (-args[0]).exp())
}));

let eval = ExpressionEvaluator::compile_with(expr, fmap).unwrap();
let result = eval.evaluate(&[0.0]).unwrap();
assert!((result[0] - 0.5).abs() < 1e-15);
// 输出:sigmoid(0) = 0.5
}

参见:表达式系统(Atom、AtomArena)、数值积分(Vegas 使用求值器)、自动微分(HyperDual 域上的求值)