use ndarray as nd;
use ndarray_linalg::*;
use std::collections::HashMap;
use itertools::Itertools;
pub fn find_structure_constants(
basis: &[nd::Array2<c64>],
) -> HashMap<(usize, usize), (usize, c64)> {
use approx::AbsDiffEq;
use std::iter::FromIterator;
let n_dim = basis[0].shape()[0];
let n = n_dim * n_dim;
let commutator = |x: &nd::Array2<c64>, y: &nd::Array2<c64>| x.dot(y) - y.dot(x);
let matrix: Vec<_> = basis
.iter()
.map(|x| nd::ArrayView::from_shape(n, x.as_slice().unwrap()).unwrap())
.collect();
let matrix = nd::stack(nd::Axis(1), matrix.as_slice()).unwrap();
let mut struct_consts = HashMap::new();
for (i, t_a) in basis.iter().enumerate() {
for (j, t_b) in basis.iter().enumerate() {
if i == j {
continue;
}
let f_t_c = commutator(t_a, t_b);
let f_t_c = nd::Array::from_iter(f_t_c.iter().cloned());
let x = matrix.least_squares(&f_t_c).unwrap();
let x = x.solution;
let idx = x.iter().map(|x| x.abs_diff_ne(&c64::new(0., 0.), 1e-8));
if idx.clone().filter(|x| *x).count() > 1usize {
assert!(true, "This algebra does not satisfiey the lie algebra");
}
let idx = idx.into_iter().position(|x| x);
if let Some(idx) = idx {
struct_consts.insert((i, j), (idx, x[idx]));
}
}
}
struct_consts
}
pub fn find_d_coefficients(basis: &[nd::Array2<c64>]) -> HashMap<(usize, usize, usize), c64> {
use approx::AbsDiffEq;
use std::iter::FromIterator;
let n_dim = basis[0].shape()[0];
let n = n_dim * n_dim;
let anti_commutator = |x: &nd::Array2<c64>, y: &nd::Array2<c64>| x.dot(y) + y.dot(x);
let eye: nd::Array2<c64> = nd::Array2::eye(n_dim);
let matrix: Vec<_> = basis
.iter()
.map(|x| nd::ArrayView::from_shape(n, x.as_slice().unwrap()).unwrap())
.collect();
let matrix = nd::stack(nd::Axis(1), matrix.as_slice()).unwrap();
let mut struct_consts = HashMap::new();
for (i, t_a) in basis.iter().enumerate() {
for (j, t_b) in basis.iter().enumerate() {
let mut f_t_c = anti_commutator(t_a, t_b);
if i == j {
f_t_c = f_t_c - &eye / c64::new(n_dim as f64, 0.);
}
let f_t_c = nd::Array::from_iter(f_t_c.iter().cloned());
let x = matrix.least_squares(&f_t_c).unwrap();
let x = x.solution;
let idx = x.iter().map(|x| x.abs_diff_ne(&c64::new(0., 0.), 1e-8));
for (c, val) in idx.clone().into_iter().enumerate() {
if val {
struct_consts.insert((i, j, c), x[c] / c64::new(2., 0.));
}
}
}
}
struct_consts
}
pub fn su_commutator(
l_a: &ndarray::Array2<c64>,
l_b: &ndarray::Array2<c64>,
f_ijk: &HashMap<(usize, usize), (usize, c64)>,
basis: &[nd::Array2<c64>],
) -> nd::Array2<c64> {
let n_dim = basis[0].shape()[0];
let mut res: nd::Array2<c64> = nd::Array2::zeros((n_dim, n_dim));
for (i_i, l_i) in l_a.iter().enumerate() {
for (i_j, l_j) in l_b.iter().enumerate() {
let (i_k, f) = match f_ijk.get(&(i_i, i_j)) {
Some(x) => x,
None => continue,
};
let coeff = l_i * l_j * f;
if coeff.abs() > 1e-8 {
let prod = coeff * basis.get(*i_k).unwrap();
res = res + prod;
}
}
}
res
}
pub fn cross(
l_a: &ndarray::Array2<c64>,
l_b: &ndarray::Array2<c64>,
f_ijk: &HashMap<(usize, usize), (usize, c64)>,
) -> nd::Array2<c64> {
let n_dim = l_a.shape()[0];
let mut res: nd::Array2<c64> = nd::Array2::zeros((l_a.shape()[0], l_a.shape()[1]));
for (i_i, l_i) in l_a.iter().enumerate() {
for (i_j, l_j) in l_b.iter().enumerate() {
for k in 0..n_dim {
let (i_k, f) = match f_ijk.get(&(i_i, i_j)) {
Some(x) => x,
None => continue,
};
if k != *i_k {
continue;
}
res[[k, 0]] += f * l_i * l_j;
}
}
}
res
}
pub fn dot(
l_a: &ndarray::Array2<c64>,
l_b: &ndarray::Array2<c64>,
d_ijk: &HashMap<(usize, usize, usize), c64>,
) -> nd::Array2<c64> {
let n_dim = l_a.shape()[0];
let mut res: nd::Array2<c64> = nd::Array2::zeros((l_a.shape()[0], l_a.shape()[1]));
for (i_i, l_i) in l_a.iter().enumerate() {
for (i_j, l_j) in l_b.iter().enumerate() {
for k in 0..n_dim {
let perms = vec![i_i, i_j, k].into_iter().permutations(3);
for perm in perms {
let key = (perm[0], perm[1], perm[2]);
match d_ijk.get(&key) {
Some(d) => {
res[[k, 0]] += d * l_i * l_j;
break;
}
None => continue,
};
}
}
}
}
res
}