a rust-based framework for symbolic and numerical tensor computation
Bern University
Tensors are pervasive in High Energy Physics.
We wanted a library that implements tensor contractions, and arithmetic, component wise and synergises well with symbolica.
Evaluating:
Not really
Atom
Each tensor needs at minimum ae index Structure
. The Structure
encodes the indices of the tensor, including the representation and dimensionality
let mink = Representation::Lorentz(Dimension(4));
let mu = Slot::from((AbstractIndex(0),mink));
let bis = Representation::Bispinor(Dimension(4));
let i = Slot::from((AbstractIndex(1),bis));
let j = Slot::from((AbstractIndex(2),bis));
let structure = NamedStructure::new(&[mu,i,j],"γ");
Represents: \[ \gamma^{\mu}_{ij} \]
Now we can add data to this structure.
let iunit = Complex::<f64>::i();
let mut gamma = SparseTensor::empty(structure);
gamma.set(&[0, 0, 0], 1.);
gamma.set(&[1, 1, 0], 1.);
gamma.set(&[2, 2, 0], -1.);
gamma.set(&[3, 3, 0], -1.);
gamma.set(&[0, 3, 1], 1.);
gamma.set(&[1, 2, 1], 1.);
gamma.set(&[2, 1, 1], -1.);
gamma.set(&[3, 0, 1], -1.);
gamma.set(&[0, 3, 2], -iunit);
gamma.set(&[1, 2, 2], iunit);
gamma.set(&[2, 1, 2], iunit);
gamma.set(&[3, 0, 2], -iunit);
gamma.set(&[0, 2, 3], 1.);
gamma.set(&[1, 3, 3], -1.);
gamma.set(&[2, 0, 3], -1.);
gamma.set(&[3, 1, 3], 1.);
The tensor can be symbolic, or parametric!
let nu = Slot::from((AbstractIndex(1), mink));
let structure = NamedStructure::from_slots(vec![mu, nu], "T");
let symbolicT: SymbolicTensor = SymbolicTensor::from_named(&structure).unwrap();
println!("{}", symbolicT); // T(lor(4,0),lor(4,1))
let paramT: DenseTensor<Atom, _> = symbolicT.shadow().unwrap();
let t12: Atom = paramT.get(&[1, 2]).unwrap());// T(1,2)
Iterate along specific dimensions:
Arithmetic, when structures match:
Contractions, when indices match:
consider this triangle diagram:
The numerator spinor structure looks like
\[p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2} \gamma_\rho \gamma_{\mu_3})\]
\[p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2} \gamma_\rho \gamma_{\mu_3})\]
Usually we turn this into dot products by repeatedly applying the defining relation:
\[\left\{ \gamma_\mu, \gamma_\nu \right\} = \gamma_\mu \gamma_\nu + \gamma_\nu \gamma_\mu = 2 \eta_{\mu \nu} I_4\]
\[2 p_1^{\mu_1} p_2^{\mu_2}p_{3,\rho} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2}) \\ -p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2} \gamma_{\mu_3}\gamma_\rho)\]
Usually we turn this into dot products by repeatedly applying the defining relation:
\[\left\{ \gamma_\mu, \gamma_\nu \right\} = \gamma_\mu \gamma_\nu + \gamma_\nu \gamma_\mu = 2 \eta_{\mu \nu} I_4\]
\[2 p_1^{\mu_1} p_2^{\mu_2}p_{3,\rho} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2}) \\ -2 p_2 \cdot p_3 p_1^{\mu_1} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_\rho) \\ +p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_3}\gamma_{\mu_2} \gamma_\rho) \]
Usually we turn this into dot products by repeatedly applying the defining relation:
\[\left\{ \gamma_\mu, \gamma_\nu \right\} = \gamma_\mu \gamma_\nu + \gamma_\nu \gamma_\mu = 2 \eta_{\mu \nu} I_4\]
\[-4(p_1 \cdot p_2) p_{3,\mu}\eta_{\nu\rho} \\ +4(p_1\cdot p_2)p_{3,\nu}\eta_{\mu\rho} \\ -4(p_1\cdot p_2)p_{3,\rho}\eta_{\mu\nu} \\ +4(p_1\cdot p_3)p_{2,\mu}\eta_{\nu\rho} \\ -4(p_1\cdot p_3)p_{2,\nu}\eta_{\mu\rho} \\ -4(p_1\cdot p_3)p_{2,\rho}\eta_{\mu\nu} \\ -4p_{1,\mu} (p_2\cdot p_3)\eta_{\nu\rho} \\ +4p_{1,\mu} p_{2,\nu}p_{3,\rho} \\ +4p_{1,\mu} p_{2,\rho}p_{3,\nu} \\ -4p_{1,\nu}(p_2\cdot p_3)\eta_{\mu\rho} \\ +4p_{1,\nu}p_{2,\mu}p_{3,\rho} \\ +4p_{1,\nu}p_{2,\rho}p_{3,\mu} \\ +4p_{1,\rho}(p_2\cdot p_3)\eta_{\mu\nu} \\ -4p_{1,\rho}p_{2,\mu}p_{3,\nu} \\ +4p_{1,\rho}p_{2,\nu}p_{3,\mu} \]
Exponential growth of the terms:
If you do componentwise contraction on the unmodified trace:
\[p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3} \mathrm{Tr} (\gamma_\mu \gamma_{\mu_1} \gamma_\nu \gamma_{\mu_2} \gamma_\rho \gamma_{\mu_3})\]
The scaling is linear in the chain length!
Consider a string of tensors
Example
\[\bar{v}_{i_1} u_{i_3}p_1^{\mu_1} p_2^{\mu_2}p_3^{\mu_3}p_4^{\mu_4}p_5^{\mu_5}p_6^{\mu_6}p_7^{\mu_7} \gamma_{i_1 i_2}^{\mu_1} \\ \gamma_{i_2 i_3}^{\nu} \gamma_{i_4 i_5}^{\nu} \gamma_{i_5 i_6}^{\mu_2} \gamma_{i_6 i_7}^{\mu_3} \gamma_{i_7 i_8}^{\mu_4} \gamma_{i_8 i_9}^{\mu_5} \gamma_{i_9 i_4}^{\mu_6}\]
We can model a string of tensors, with repeated indices as a graph, each edge is an index, each node a tensor.
Example
We can model a string of tensors, with repeated indices as a graph, each edge is an index, each node a tensor.
Example
let γ1: MixedTensor<_> = gamma(1.into(), (1.into(), 2.into())).into();
println!("{}", γ1.to_symbolic().unwrap());
//γ(lor(4,1),spin(4,1),spina(4,2))
let γ2: MixedTensor<_> = gamma(10.into(), (2.into(), 3.into())).into();
// ...
let p1: MixedTensor<_> = param_mink_four_vector(1.into(), "p1").into();
/// ...
let u: MixedTensor<_> = param_four_vector(1.into(), "u").into();
println!("{}", u.to_symbolic().unwrap());
// u(spin(4,1))
let net: TensorNetwork<NumTensor> = TensorNetwork::from(vec![u,v,p1,p2,
p3,p4,p5,p6,
γ1,γ2,γ3,γ4,
γ5,γ6,γ7,γ8]);
println!("{}",net.dot());
Spenso understands a specific format of symbolica expressions and can recognise known tensors with numerical counterparts:
let structure = NamedStructure::from_slots(vec![mu, i, j], "γ");
let p_struct = NamedStructure::from_slots(vec![mu], "p");
let t_struct = NamedStructure::from_slots(vec![i, j, k], "T");
let gamma_sym = SymbolicTensor::from_named(&structure).unwrap();
let p_sym = SymbolicTensor::from_named(&p_struct).unwrap();
let t_sym = SymbolicTensor::from_named(&t_struct).unwrap();
let f = gamma_sym.contract(&p_sym).unwrap().contract(&t_sym).unwrap();
println!("{}", *f.get_atom());
Spenso | Spenso Compiled | Hardcoded Fortran |
---|---|---|
104 μs | 16 μs | 31μs |
We can use a compiled version of the stacked shadowing using symbolica!
If you want to check it out it is on crates.io:
https://crates.io/crates/spenso
And on github:
https://github.com/alphal00p/spenso