Rust API 参考:张量

oCAS 提供带显式指标管理的基础张量代数。Tensor 携带命名指标槽(上标/下标)、可选的对称性元数据,并可转换为 Atom 表达式进行符号处理。自 0.22.0 起,额外提供基于图同构的规范化引擎和 Young 投影子。

模块路径:ocas_atom::tensor(mod.rs)、ocas_atom::tensor::spec、ocas_atom::tensor::canon、ocas_atom::tensor::dummy、ocas_atom::tensor::young

导入方式:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{
    IndexPosition, IndexSlot, Symmetry, Tensor,
    contract, Contracted, TensorProduct,
    symmetrise_sign,
};
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::tensor::canon::{canonicalize_tensors, CanonicalTensor, TensorCanonError};
use ocas_atom::tensor::dummy::{refresh_dummies, DummyError};
use ocas_atom::tensor::young::{YoungTableau, young_project};
}

IndexPosition

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IndexPosition {
    Upper,
    Lower,
}
}

功能:指标在张量中的位置(方差)。Upper 表示逆变指标(上标),Lower 表示协变指标(下标)。缩并要求两个相同标签的指标具有相反的位置。

变体:

变体含义
Upper逆变指标(上标),物理中对应反变向量
Lower协变指标(下标),物理中对应协变向量

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::IndexPosition;

assert_eq!(IndexPosition::Upper, IndexPosition::Upper);
assert_ne!(IndexPosition::Upper, IndexPosition::Lower);
// 输出:所有断言通过
}

IndexSlot

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IndexSlot<'a> { /* private fields */ }
}

功能:张量的单个指标槽,由指标标签(Atom)和位置(IndexPosition)组成。Copy 类型,可廉价复制。

IndexSlot::new

签名:pub fn new(label: Atom<'a>, position: IndexPosition) -> Self

功能:创建一个新的指标槽。

参数:

参数类型说明
labelAtom<'a>指标标签表达式(通常为变量名如 mu、i)
positionIndexPosition指标位置:Upper 或 Lower

返回值:IndexSlot<'a>

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{IndexSlot, IndexPosition};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let mu = IndexSlot::new(ctx.var("mu"), IndexPosition::Upper);
let nu = IndexSlot::new(ctx.var("nu"), IndexPosition::Lower);
assert_eq!(mu.position(), IndexPosition::Upper);
assert_eq!(nu.position(), IndexPosition::Lower);
// 输出:所有断言通过
}

IndexSlot::label

签名:pub fn label(&self) -> Atom<'a>

功能:返回指标标签表达式。

返回值:Atom<'a> — 指标标签的 Atom 句柄。

IndexSlot::position

签名:pub fn position(&self) -> IndexPosition

功能:返回指标的位置(Upper 或 Lower)。

返回值:IndexPosition

参见:IndexPosition


Symmetry

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Symmetry {
    None,
    Symmetric,
    Antisymmetric,
}
}

功能:张量指标槽的对称性。这是建议性元数据——contract 等运算不会自动对称化;对称性由下游消费者(如规范化引擎或 Young 投影子)使用。

变体:

变体含义
None无对称性(一般张量)
Symmetric对称:任意交换指标槽不改变张量
Antisymmetric反对称:交换任意两个指标槽改变符号

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::Symmetry;

assert_eq!(Symmetry::None, Symmetry::None);
assert_ne!(Symmetry::Symmetric, Symmetry::Antisymmetric);
// 输出:所有断言通过
}

Tensor

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Tensor<'a> { /* private fields */ }
}

功能:命名张量对象,由名称(Symbol)、指标槽列表(Vec<IndexSlot>)和对称性(Symmetry)组成。可通过 to_atom 降级为标准 Atom 表达式节点。

Tensor::new

签名:pub fn new(name: Symbol, slots: Vec<IndexSlot<'a>>) -> Self

功能:创建一个新张量,默认对称性为 Symmetry::None。

参数:

参数类型说明
nameSymbol张量名称(interned 字符串,如 "g"、"Riemann")
slotsVec<IndexSlot<'a>>指标槽列表,顺序有意义

返回值:Tensor<'a>

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let slots = vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("nu"), IndexPosition::Lower),
];
let t = Tensor::new(Symbol::new("g"), slots);
assert_eq!(t.rank(), 2);
assert_eq!(t.name().as_str(), "g");
// 输出:所有断言通过
}

Tensor::with_symmetry

签名:pub fn with_symmetry(mut self, symmetry: Symmetry) -> Self

功能:Builder 方法,设置张量的对称性。消费并返回 self。

参数:

参数类型说明
symmetrySymmetry目标对称性

返回值:Self — 设置了对称性的张量。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition, Symmetry};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let slots = vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("nu"), IndexPosition::Upper),
];
let sym = Tensor::new(Symbol::new("g"), slots.clone())
    .with_symmetry(Symmetry::Symmetric);
let anti = Tensor::new(Symbol::new("epsilon"), slots)
    .with_symmetry(Symmetry::Antisymmetric);

assert_eq!(sym.symmetry(), Symmetry::Symmetric);
assert_eq!(anti.symmetry(), Symmetry::Antisymmetric);
// 输出:所有断言通过
}

Tensor::name

签名:pub fn name(&self) -> Symbol

功能:返回张量名称。

返回值:Symbol — interned 字符串句柄。

Tensor::slots

签名:pub fn slots(&self) -> &[IndexSlot<'a>]

功能:返回指标槽的切片引用。

返回值:&[IndexSlot<'a>]

Tensor::symmetry

签名:pub fn symmetry(&self) -> Symmetry

功能:返回张量的对称性。

返回值:Symmetry

Tensor::rank

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

功能:返回张量的阶(指标槽数量)。

返回值:usize

Tensor::dummy_labels

签名:pub fn dummy_labels(&self) -> Vec<Atom<'a>>

功能:返回哑指标标签列表。哑指标定义为在所有槽中恰好出现两次的标签(一次 Upper、一次 Lower),即缩并候选。

返回值:Vec<Atom<'a>> — 哑指标标签列表。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

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

// A^μ_μ:mu 出现两次(Upper + Lower)→ 哑指标
let t = Tensor::new(Symbol::new("A"), vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("mu"), IndexPosition::Lower),
]);
assert_eq!(t.dummy_labels().len(), 1);
// 输出:1 个哑指标
}

Tensor::to_atom

签名:pub fn to_atom(&self, ctx: &'a AtomArena<'a>) -> Atom<'a>

功能:将张量降级为标准 Atom 函数节点 name(slot₁, slot₂, …)。不应用对称化——原子保留 self 的槽顺序。

参数:

参数类型说明
ctx&'a AtomArena<'a>表达式 arena

返回值:Atom<'a> — 函数节点表达式。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let t = Tensor::new(Symbol::new("g"), vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("nu"), IndexPosition::Lower),
]);
let atom = t.to_atom(&ctx);
println!("{}", atom);  // g(mu, nu)
// 输出:g(mu, nu)
}

参见:Atom


contract

签名:

#![allow(unused)]
fn main() {
pub fn contract<'a>(
    ctx: &'a AtomArena<'a>,
    a: &Tensor<'a>,
    b: &Tensor<'a>,
) -> Contracted<'a>
}

功能:通过求和共享哑指标来缩并两个张量。两个具有相同标签但相反位置的槽会缩并。结果保留存活的自由指标,顺序为 (a 的自由槽, b 的自由槽)。

参数:

参数类型说明
ctx&'a AtomArena<'a>表达式 arena
a&Tensor<'a>第一个张量
b&Tensor<'a>第二个张量

返回值:Contracted<'a>

  • 无缩并对时返回 Contracted::Product,包含原始两个张量
  • 部分缩并时返回 Contracted::Product,包含一个携带自由槽的新张量
  • 完全缩并(无自由槽)时返回 Contracted::Scalar

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition, contract, Contracted};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

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

// A^μ B_μ → 标量
let a = Tensor::new(Symbol::new("A"), vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
]);
let b = Tensor::new(Symbol::new("B"), vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Lower),
]);
match contract(&ctx, &a, &b) {
    Contracted::Scalar(expr) => println!("scalar: {}", expr),
    Contracted::Product(tp) => {
        for f in &tp.factors {
            println!("free: {} (rank {})", f.name().as_str(), f.rank());
        }
    }
}
// 输出:scalar: A(mu)*B(mu)
}

参见:Contracted、TensorProduct


Contracted

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Contracted<'a> {
    Product(TensorProduct<'a>),
    Scalar(Atom<'a>),
}
}

功能:缩并两个张量的结果。当无自由指标存活时为标量表达式;否则为含自由槽的张量积。

变体:

变体类型说明
ProductTensorProduct<'a>部分缩并或无缩并,含自由指标的张量积
ScalarAtom<'a>完全缩并为标量表达式

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition, contract, Contracted};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

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

// A^μ_ν B^ν_ρ → 部分缩并,剩余 A^μ_ρ
let a = Tensor::new(Symbol::new("A"), vec![
    IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("nu"), IndexPosition::Lower),
]);
let b = Tensor::new(Symbol::new("B"), vec![
    IndexSlot::new(ctx.var("nu"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("rho"), IndexPosition::Lower),
]);
match contract(&ctx, &a, &b) {
    Contracted::Product(tp) => {
        assert_eq!(tp.factors.len(), 1);
        assert_eq!(tp.factors[0].rank(), 2); // mu, rho
    }
    Contracted::Scalar(_) => panic!("expected partial contraction"),
}
// 输出:部分缩并,剩余 2 个自由指标
}

TensorProduct

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TensorProduct<'a> {
    pub factors: Vec<Tensor<'a>>,
}
}

功能:缩并后保留自由槽的张量积。factors 包含缩并后的存活张量,其槽按 (a 的自由槽, b 的自由槽) 顺序拼接。

字段:

字段类型说明
factorsVec<Tensor<'a>>缩并后的张量因子列表

参见:contract、Contracted


symmetrise_sign

签名:pub fn symmetrise_sign(tensor: &Tensor<'_>) -> i64

功能:对张量的指标槽按标签升序排列,并返回反对称化的符号。

  • Symmetry::None 或 Symmetry::Symmetric:返回 +1
  • Symmetry::Antisymmetric:返回排列奇偶性(偶排列 +1,奇排列 -1)

注意:这不是置换群下的完全规范化(那需要图同构);仅为对称张量提供稳定的等价比较顺序。

参数:

参数类型说明
tensor&Tensor<'_>输入张量

返回值:i64 — +1 或 -1。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::{Tensor, IndexSlot, IndexPosition, Symmetry, symmetrise_sign};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let slots = vec![
    IndexSlot::new(ctx.var("a"), IndexPosition::Upper),
    IndexSlot::new(ctx.var("b"), IndexPosition::Upper),
];
let anti = Tensor::new(Symbol::new("epsilon"), slots)
    .with_symmetry(Symmetry::Antisymmetric);

let sign = symmetrise_sign(&anti);
// 若 a < b 则排列不变,sign = +1
// 输出:+1
}

SymmetrySpec

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Default)]
pub struct SymmetrySpec {
    pub symmetric_subsets: Vec<Vec<usize>>,
    pub antisymmetric_subsets: Vec<Vec<usize>>,
    pub cyclic: Option<Vec<usize>>,
}
}

功能:张量的细粒度对称性规格,用于规范化引擎。比 Symmetry 枚举更灵活——可以为不同的槽位子集指定不同的对称行为。

字段:

字段类型说明
symmetric_subsetsVec<Vec<usize>>对称的槽位子集列表。同一子集内的槽位可互换
antisymmetric_subsetsVec<Vec<usize>>反对称的槽位子集列表。交换子集内两个槽位翻转符号
cyclicOption<Vec<usize>>循环置换的槽位子集

SymmetrySpec::none

签名:pub fn none() -> Self

功能:无对称性——所有槽位独立。

返回值:SymmetrySpec

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::SymmetrySpec;

let spec = SymmetrySpec::none();
assert!(spec.symmetric_subsets.is_empty());
assert!(spec.antisymmetric_subsets.is_empty());
assert!(spec.cyclic.is_none());
// 输出:所有断言通过
}

SymmetrySpec::fully_symmetric

签名:pub fn fully_symmetric(rank: usize) -> Self

功能:所有槽位完全对称。创建一个包含全部 0..rank 槽位的对称子集。

参数:

参数类型说明
rankusize张量阶数(槽位总数)

返回值:SymmetrySpec

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::SymmetrySpec;

let spec = SymmetrySpec::fully_symmetric(3);
assert_eq!(spec.symmetric_subsets, vec![vec![0, 1, 2]]);
// 输出:对称子集 = [[0, 1, 2]]
}

SymmetrySpec::fully_antisymmetric

签名:pub fn fully_antisymmetric(rank: usize) -> Self

功能:所有槽位完全反对称。创建一个包含全部 0..rank 槽位的反对称子集。

参数:

参数类型说明
rankusize张量阶数(槽位总数)

返回值:SymmetrySpec

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::SymmetrySpec;

let spec = SymmetrySpec::fully_antisymmetric(4);
assert_eq!(spec.antisymmetric_subsets, vec![vec![0, 1, 2, 3]]);
// 输出:反对称子集 = [[0, 1, 2, 3]]
}

SymmetrySpec::is_slot_hidden

签名:pub fn is_slot_hidden(&self, pos: usize) -> bool

功能:检查给定槽位位置是否应在图编码中"隐藏"(即不参与规范化比较)。对称槽位和循环槽位被隐藏。

参数:

参数类型说明
posusize槽位位置索引

返回值:bool — true 表示该槽位隐藏。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::SymmetrySpec;

let spec = SymmetrySpec::fully_symmetric(2);
assert!(spec.is_slot_hidden(0));   // 在对称子集中
assert!(spec.is_slot_hidden(1));   // 在对称子集中

let none = SymmetrySpec::none();
assert!(!none.is_slot_hidden(0));  // 不在任何子集中
// 输出:所有断言通过
}

TensorRegistry

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Default)]
pub struct TensorRegistry { /* private fields */ }
}

功能:张量规范化的完整注册表。记录哪些函数头是张量以及它们的对称性规格,同时管理指标维度组分配(防止跨维度的哑指标重命名冲突)。

TensorRegistry::new

签名:pub fn new() -> Self

功能:创建空注册表。

返回值:TensorRegistry

TensorRegistry::register

签名:pub fn register(&mut self, name: Symbol, spec: SymmetrySpec)

功能:注册一个张量名称及其对称性规格。

参数:

参数类型说明
nameSymbol张量函数头名称
specSymmetrySpec对称性规格

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::Symbol;

let mut reg = TensorRegistry::new();
reg.register(Symbol::new("g"), SymmetrySpec::fully_symmetric(2));
reg.register(Symbol::new("Riemann"), SymmetrySpec::none());
reg.register(Symbol::new("epsilon"), SymmetrySpec::fully_antisymmetric(4));
// 输出:注册了 3 个张量
}

TensorRegistry::set_index_group

签名:pub fn set_index_group(&mut self, label: Symbol, group: u64)

功能:设置指标标签的维度组标识符。不同组的哑指标不会被重命名为相同的规范名,从而避免跨维度冲突。

参数:

参数类型说明
labelSymbol指标标签(如 "mu"、"i")
groupu64组标识符。0 表示默认/未分组

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::TensorRegistry;
use ocas_atom::Symbol;

let mut reg = TensorRegistry::new();
reg.set_index_group(Symbol::new("mu"), 1);  // 时空指标
reg.set_index_group(Symbol::new("i"), 2);   // 内部指标
assert_eq!(reg.index_group(Symbol::new("mu")), 1);
assert_eq!(reg.index_group(Symbol::new("i")), 2);
assert_eq!(reg.index_group(Symbol::new("other")), 0); // 默认组
// 输出:所有断言通过
}

TensorRegistry::spec

签名:pub fn spec(&self, name: Symbol) -> Option<&SymmetrySpec>

功能:查找已注册张量的对称性规格。

参数:

参数类型说明
nameSymbol张量名称

返回值:Option<&SymmetrySpec> — 未注册时返回 None。

TensorRegistry::index_group

签名:pub fn index_group(&self, label: Symbol) -> u64

功能:查找指标标签的维度组。未设置的标签返回 0。

参数:

参数类型说明
labelSymbol指标标签

返回值:u64 — 组标识符。

参见:SymmetrySpec


canonicalize_tensors

签名:

#![allow(unused)]
fn main() {
pub fn canonicalize_tensors<'a>(
    ctx: &'a AtomArena<'a>,
    expr: Atom<'a>,
    registry: &TensorRegistry,
) -> Result<CanonicalTensor<'a>, TensorCanonError>
}

功能:将张量表达式规范化为与指标命名无关的唯一规范形。内部将表达式编码为图(张量头→头顶点、指标槽→槽顶点、缩并→边),运行 McKay 细化-个体化算法计算规范标号,然后重建表达式并重命名哑指标。

对于和表达式(Add),逐项规范化并验证所有项具有相同的自由指标集。

参数:

参数类型说明
ctx&'a AtomArena<'a>表达式 arena
exprAtom<'a>待规范化的张量表达式(Mul of Fun 节点)
registry&TensorRegistry张量注册表(对称性规格 + 指标组)

返回值:Result<CanonicalTensor<'a>, TensorCanonError>

错误:

错误变体说明
ContractedMoreThanOnce(Symbol)某个指标标签被缩并超过两次
BadContraction(Symbol)两个相同标签的槽具有相同位置(不是上/下对)
NotATensor(Symbol)表达式中出现未在注册表中注册的函数头
InconsistentOpenIndices和表达式中各项的自由指标不一致
UnsupportedPower表达式中出现不支持的幂次节点

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::tensor::canon::canonicalize_tensors;
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let mut reg = TensorRegistry::new();
reg.register(Symbol::new("T"), SymmetrySpec::none());

// T(i, j) 和 T(j, i) 是不同的(无对称性)
let t_ij = ctx.fun("T", &[ctx.var("i"), ctx.var("j")]);
let t_ji = ctx.fun("T", &[ctx.var("j"), ctx.var("i")]);

let ct1 = canonicalize_tensors(&ctx, t_ij, &reg).unwrap();
let ct2 = canonicalize_tensors(&ctx, t_ji, &reg).unwrap();
// 无对称性时,T(i,j) ≠ T(j,i)
// 注意:无对称性时 T(i,j) 与 T(j,i) 的规范形不同
}

参见:CanonicalTensor、TensorCanonError、TensorRegistry


CanonicalTensor

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct CanonicalTensor<'a> {
    pub canonical_form: Atom<'a>,
    pub external_indices: Vec<Atom<'a>>,
    pub dummy_indices: Vec<Atom<'a>>,
}
}

功能:张量规范化的结果。

字段:

字段类型说明
canonical_formAtom<'a>规范化后的表达式(哑指标已重命名)
external_indicesVec<Atom<'a>>自由(外部)指标列表
dummy_indicesVec<Atom<'a>>哑指标列表(已重命名为 d0、d1、…)

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::tensor::canon::canonicalize_tensors;
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let mut reg = TensorRegistry::new();
reg.register(Symbol::new("T"), SymmetrySpec::none());
reg.register(Symbol::new("U"), SymmetrySpec::none());

let prod = ctx.mul(&[ctx.fun("T", &[ctx.var("i"), ctx.var("j")]),
                      ctx.fun("U", &[ctx.var("j"), ctx.var("k")])]);
let ct = canonicalize_tensors(&ctx, prod, &reg).unwrap();

println!("规范形: {}", ct.canonical_form);
println!("外部指标: {:?}", ct.external_indices);
println!("哑指标: {:?}", ct.dummy_indices);
// 输出:规范形含重命名后的哑指标,外部指标为 i, k
}

TensorCanonError

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TensorCanonError {
    ContractedMoreThanOnce(Symbol),
    BadContraction(Symbol),
    NotATensor(Symbol),
    InconsistentOpenIndices,
    UnsupportedPower,
}
}

功能:张量规范化过程中可能产生的错误。

变体:

变体说明
ContractedMoreThanOnce(Symbol)指标标签被缩并超过两次(出现 3 次以上)
BadContraction(Symbol)两个相同标签的槽具有相同方差(不是有效的上/下对)
NotATensor(Symbol)出现未在 TensorRegistry 中注册的函数头
InconsistentOpenIndices和表达式中各项的自由指标集不一致
UnsupportedPower表达式中出现不支持的幂次节点

refresh_dummies

签名:

#![allow(unused)]
fn main() {
pub fn refresh_dummies<'a>(
    ctx: &'a AtomArena<'a>,
    expr: Atom<'a>,
    registry: &TensorRegistry,
) -> Result<Atom<'a>, DummyError>
}

功能:重命名张量表达式中的哑指标以避免与外部(自由)指标冲突。恰好出现两次的标签(一次上标、一次下标)被替换为按维度组分配的新名称(d0、d1、…)。外部指标保持不变。

参数:

参数类型说明
ctx&'a AtomArena<'a>表达式 arena
exprAtom<'a>待处理的张量表达式
registry&TensorRegistry张量注册表(用于维度组分配)

返回值:Result<Atom<'a>, DummyError>

错误:

错误变体说明
OverContracted(Symbol)某个指标标签出现超过两次
BadContraction(Symbol)两个相同标签的槽具有相同方差

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::tensor::dummy::refresh_dummies;
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

let arena = Arena::new();
let ctx = AtomArena::new(&arena);
let mut reg = TensorRegistry::new();
reg.register(Symbol::new("T"), SymmetrySpec::none());
reg.register(Symbol::new("U"), SymmetrySpec::none());

// T(i,j) * U(j,i):i 和 j 都恰好出现两次 → 哑指标
let expr = ctx.mul(&[ctx.fun("T", &[ctx.var("i"), ctx.var("j")]),
                      ctx.fun("U", &[ctx.var("j"), ctx.var("i")])]);
let refreshed = refresh_dummies(&ctx, expr, &reg).unwrap();
println!("{}", refreshed);
// 输出:哑指标被重命名为 d0, d1(按维度组分配)
}

参见:DummyError、TensorRegistry


DummyError

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DummyError {
    OverContracted(Symbol),
    BadContraction(Symbol),
}
}

功能:哑指标操作的错误类型。

变体:

变体说明
OverContracted(Symbol)指标标签出现超过两次(不是合法的缩并候选)
BadContraction(Symbol)两个相同标签的槽具有相同方差(不是上/下对)

YoungTableau

签名:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct YoungTableau {
    pub row_lengths: Vec<usize>,
}
}

功能:Young 盘,由行长度列表定义形状(如 [2, 1] 表示 □□/□)。Young 投影子实现经典对称子 $c_\lambda = a_\lambda \cdot b_\lambda$:对行内置换 $\sigma \in R$ 与列内置换 $\tau \in C$ 的所有组合求和,每项带列置换奇偶符号 $\operatorname{sgn}(\tau)$。

这是显式展开(非 BSGS 群论实现):结果是 $\prod r_i! \cdot \prod c_j!$ 个项的和(行、列阶乘之积),每项符号 ±1,不做 Hook 长度归一化。

字段:

字段类型说明
row_lengthsVec<usize>每行的格子数

YoungTableau::new

签名:pub fn new(row_lengths: Vec<usize>) -> Self

功能:从行长度创建 Young 盘。

参数:

参数类型说明
row_lengthsVec<usize>每行的格子数列表。总格子数应等于张量阶数

返回值:YoungTableau

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::young::YoungTableau;

// [2, 1] = □□/□(3 格)
let tab = YoungTableau::new(vec![2, 1]);
assert_eq!(tab.total_boxes(), 3);

// [1, 1, 1] = 全反对称
let anti = YoungTableau::new(vec![1, 1, 1]);
assert_eq!(anti.total_boxes(), 3);

// [3] = 全对称
let sym = YoungTableau::new(vec![3]);
assert_eq!(sym.total_boxes(), 3);
// 输出:所有断言通过
}

YoungTableau::total_boxes

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

功能:返回盘中总格子数(等于张量阶数)。

返回值:usize


young_project

签名:

#![allow(unused)]
fn main() {
pub fn young_project<'a>(
    ctx: &'a AtomArena<'a>,
    tensor_expr: Atom<'a>,
    tableau: &YoungTableau,
) -> Atom<'a>
}

功能:对张量表达式应用 Young 投影子。将 $T(i_1, i_2, \dots, i_n)$ 展开为置换和:

$$\sum_\sigma \text{sign}(\sigma) \cdot T(i_{\sigma(1)}, i_{\sigma(2)}, \dots, i_{\sigma(n)})$$

当前实现不做 Hook 长度积归一化——每项系数仅为 $\pm 1$。对于全反对称盘 [1, 1, …, 1],得到标准交替和。

参数:

参数类型说明
ctx&'a AtomArena<'a>表达式 arena
tensor_exprAtom<'a>张量表达式(Fun 节点)
tableau&YoungTableauYoung 盘形状

返回值:Atom<'a> — 投影后的表达式(Add 节点,各项带符号)。

示例:

#![allow(unused)]
fn main() {
use ocas_atom::tensor::young::{YoungTableau, young_project};
use ocas_atom::AtomArena;
use ocas_core::arena::Arena;

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

// 全反对称 [1, 1]:f(a, b) → f(a, b) - f(b, a)
let f_ab = ctx.fun("f", &[ctx.var("a"), ctx.var("b")]);
let result = young_project(&ctx, f_ab, &YoungTableau::new(vec![1, 1]));
println!("{}", result);
// 输出:f(a,b) - f(b,a)

// 全对称 [2]:g(a, b) → g(a, b) + g(b, a)
let g_ab = ctx.fun("g", &[ctx.var("a"), ctx.var("b")]);
let result = young_project(&ctx, g_ab, &YoungTableau::new(vec![2]));
println!("{}", result);
// 输出:g(a,b) + g(b,a)

// 全反对称 [1, 1, 1]:h(a, b, c) → 6 项交错和(系数 ±1,未归一化)
let h = ctx.fun("h", &[ctx.var("a"), ctx.var("b"), ctx.var("c")]);
let result = young_project(&ctx, h, &YoungTableau::new(vec![1, 1, 1]));
println!("{}", result);
// 输出:h(a,b,c) - h(b,a,c) - ...(6 项,各项系数 ±1)
}

参见:YoungTableau、SymmetrySpec


设计不变量

Atom 是 Copy 的 arena 句柄

Atom<'a> 是指向 arena 中节点的 Copy 句柄。IndexSlot<'a> 也是 Copy。这意味着张量可以廉价复制和比较——结构相等等价于指针相等(hash-consing)。

显式指标匹配

oCAS 的张量代数使用显式指标匹配而非爱因斯坦求和约定。缩并必须手动调用 contract,指标按标签和位置(上/下)配对。

对称性是建议性的

Symmetry 枚举和 SymmetrySpec 是元数据,不会被 contract 等基础运算自动使用。完全的对称性处理需要:

  1. 规范化(canonicalize_tensors)—— 图同构级别的对称性强制
  2. Young 投影(young_project)—— 显式置换展开

图同构引擎

0.22.0 的规范化基于 McKay 细化-个体化图同构算法(实现在 tensor::graph 模块)。该引擎是一个独立的 nauty 实现,提供:

  • 1-WL 颜色细化(邻居签名 + 边数据 + 方向)
  • 公平划分 + 个体化-细化 DFS
  • 路径不变量剪枝 + 自同构轨道
  • 规范形 = 字典序最大证书

完整示例

use ocas_atom::tensor::{
    IndexPosition, IndexSlot, Symmetry, Tensor,
    contract, Contracted, symmetrise_sign,
};
use ocas_atom::tensor::spec::{SymmetrySpec, TensorRegistry};
use ocas_atom::tensor::canon::canonicalize_tensors;
use ocas_atom::tensor::dummy::refresh_dummies;
use ocas_atom::tensor::young::{YoungTableau, young_project};
use ocas_atom::{AtomArena, Symbol};
use ocas_core::arena::Arena;

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

    // 1. 创建带对称性的度规张量 g_μν
    let g = Tensor::new(Symbol::new("g"), vec![
        IndexSlot::new(ctx.var("mu"), IndexPosition::Lower),
        IndexSlot::new(ctx.var("nu"), IndexPosition::Lower),
    ]).with_symmetry(Symmetry::Symmetric);
    println!("g rank = {}, symmetry = {:?}", g.rank(), g.symmetry());
    // 输出:g rank = 2, symmetry = Symmetric

    // 2. 缩并 g^μν A_ν → 部分缩并
    let g_inv = Tensor::new(Symbol::new("g"), vec![
        IndexSlot::new(ctx.var("mu"), IndexPosition::Upper),
        IndexSlot::new(ctx.var("nu"), IndexPosition::Upper),
    ]);
    let a = Tensor::new(Symbol::new("A"), vec![
        IndexSlot::new(ctx.var("nu"), IndexPosition::Lower),
    ]);
    match contract(&ctx, &g_inv, &a) {
        Contracted::Product(tp) => {
            println!("缩并后自由指标数: {}", tp.factors[0].rank());
            // 输出:缩并后自由指标数: 1 (mu)
        }
        _ => {}
    }

    // 3. 规范化:T(i,j)*U(j,k) 中 j 被重命名
    let mut reg = TensorRegistry::new();
    reg.register(Symbol::new("T"), SymmetrySpec::none());
    reg.register(Symbol::new("U"), SymmetrySpec::none());

    let prod = ctx.mul(&[
        ctx.fun("T", &[ctx.var("i"), ctx.var("j")]),
        ctx.fun("U", &[ctx.var("j"), ctx.var("k")]),
    ]);
    let ct = canonicalize_tensors(&ctx, prod, &reg).unwrap();
    println!("规范形: {}", ct.canonical_form);
    // 输出:规范形含 d0, d1 等哑指标

    // 4. Young 投影:全反对称化 f(a, b)
    let f = ctx.fun("f", &[ctx.var("a"), ctx.var("b")]);
    let anti = young_project(&ctx, f, &YoungTableau::new(vec![1, 1]));
    println!("反对称化: {}", anti);
    // 输出:f(a,b) - f(b,a)
}

参见