use std::sync::Arc;
use num_bigint::BigInt;
use num_traits::One;
use serde::Deserialize;
use serde::Serialize;
use crate::symbolic::core::Expr;
use crate::symbolic::matrix;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LieAlgebraElement(pub Expr);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LieAlgebra {
pub name: String,
pub basis: Vec<LieAlgebraElement>,
pub dimension: usize,
}
pub fn lie_bracket(
x: &Expr,
y: &Expr,
) -> Result<Expr, String> {
let xy = matrix::mul_matrices(x, y);
let yx = matrix::mul_matrices(y, x);
if !matches!(xy, Expr::Matrix(_)) || !matches!(yx, Expr::Matrix(_)) {
return Err("Operands for \
lie_bracket \
must be valid \
matrices."
.to_string());
}
Ok(matrix::sub_matrices(&xy, &yx))
}
pub fn exponential_map(
x: &Expr,
order: usize,
) -> Result<Expr, String> {
let (rows, cols) = matrix::get_matrix_dims(x).ok_or_else(|| {
"Input must be a valid \
matrix."
.to_string()
})?;
if rows != cols {
return Err("Matrix must be \
square for \
exponential map."
.to_string());
}
let n = rows;
let mut result = matrix::identity_matrix(n);
let mut x_power = x.clone();
let mut factorial = BigInt::one();
for i in 1..=order {
factorial *= i;
let factor = Expr::new_div(Expr::BigInt(BigInt::one()), Expr::BigInt(factorial.clone()));
let term = matrix::scalar_mul_matrix(&factor, &x_power);
result = matrix::add_matrices(&result, &term);
x_power = matrix::mul_matrices(&x_power, x);
}
Ok(result)
}
pub fn adjoint_representation_group(
g: &Expr,
x: &Expr,
) -> Result<Expr, String> {
let g_inv = matrix::inverse_matrix(g);
if let Expr::Variable(s) = &g_inv {
if s.starts_with("Error:") {
return Err(format!(
"Failed to invert \
group element g: {s}"
));
}
}
let gx = matrix::mul_matrices(g, x);
let gxg_inv = matrix::mul_matrices(&gx, &g_inv);
Ok(gxg_inv)
}
pub fn adjoint_representation_algebra(
x: &Expr,
y: &Expr,
) -> Result<Expr, String> {
lie_bracket(x, y)
}
pub fn commutator_table(algebra: &LieAlgebra) -> Result<Vec<Vec<Expr>>, String> {
let n = algebra.dimension;
let mut table = Vec::with_capacity(n);
for i in 0..n {
let mut row = Vec::with_capacity(n);
for j in 0..n {
let bracket = lie_bracket(&algebra.basis[i].0, &algebra.basis[j].0)?;
row.push(bracket);
}
table.push(row);
}
Ok(table)
}
pub fn check_jacobi_identity(algebra: &LieAlgebra) -> Result<bool, String> {
let n = algebra.dimension;
let basis = &algebra.basis;
for i in 0..n {
for j in 0..n {
for k in 0..n {
let x = &basis[i].0;
let y = &basis[j].0;
let z = &basis[k].0;
let yz = lie_bracket(y, z)?;
let term1 = lie_bracket(x, &yz)?;
let zx = lie_bracket(z, x)?;
let term2 = lie_bracket(y, &zx)?;
let xy = lie_bracket(x, y)?;
let term3 = lie_bracket(z, &xy)?;
let sum = matrix::add_matrices(&matrix::add_matrices(&term1, &term2), &term3);
if !matrix::is_zero_matrix(&sum) {
return Ok(false);
}
}
}
}
Ok(true)
}
#[must_use]
pub fn so3_generators() -> Vec<LieAlgebraElement> {
let lz = Expr::Matrix(vec![
vec![
Expr::Constant(0.0),
Expr::Constant(-1.0),
Expr::Constant(0.0),
],
vec![
Expr::Constant(1.0),
Expr::Constant(0.0),
Expr::Constant(0.0),
],
vec![
Expr::Constant(0.0),
Expr::Constant(0.0),
Expr::Constant(0.0),
],
]);
let ly = Expr::Matrix(vec![
vec![
Expr::Constant(0.0),
Expr::Constant(0.0),
Expr::Constant(1.0),
],
vec![
Expr::Constant(0.0),
Expr::Constant(0.0),
Expr::Constant(0.0),
],
vec![
Expr::Constant(-1.0),
Expr::Constant(0.0),
Expr::Constant(0.0),
],
]);
let lx = Expr::Matrix(vec![
vec![
Expr::Constant(0.0),
Expr::Constant(0.0),
Expr::Constant(0.0),
],
vec![
Expr::Constant(0.0),
Expr::Constant(0.0),
Expr::Constant(-1.0),
],
vec![
Expr::Constant(0.0),
Expr::Constant(1.0),
Expr::Constant(0.0),
],
]);
vec![
LieAlgebraElement(lx),
LieAlgebraElement(ly),
LieAlgebraElement(lz),
]
}
#[must_use]
pub fn so3() -> LieAlgebra {
let basis = so3_generators();
LieAlgebra {
name: "so(3)".to_string(),
dimension: basis.len(),
basis,
}
}
#[must_use]
pub fn su2_generators() -> Vec<LieAlgebraElement> {
let i = Expr::Variable("i".to_string());
let half = Expr::new_div(Expr::BigInt(One::one()), Expr::BigInt(BigInt::from(2)));
let i_half = Expr::new_mul(i.clone(), half);
let sx = matrix::scalar_mul_matrix(
&i_half,
&Expr::Matrix(vec![
vec![Expr::Constant(0.0), Expr::Constant(1.0)],
vec![Expr::Constant(1.0), Expr::Constant(0.0)],
]),
);
let sy = matrix::scalar_mul_matrix(
&i_half,
&Expr::Matrix(vec![
vec![
Expr::Constant(0.0),
Expr::Mul(Arc::new(Expr::Constant(-1.0)), Arc::new(i.clone())),
],
vec![i, Expr::Constant(0.0)],
]),
);
let sz = matrix::scalar_mul_matrix(
&i_half,
&Expr::Matrix(vec![
vec![Expr::Constant(1.0), Expr::Constant(0.0)],
vec![Expr::Constant(0.0), Expr::Constant(-1.0)],
]),
);
vec![
LieAlgebraElement(sx),
LieAlgebraElement(sy),
LieAlgebraElement(sz),
]
}
#[must_use]
pub fn su2() -> LieAlgebra {
let basis = su2_generators();
LieAlgebra {
name: "su(2)".to_string(),
dimension: basis.len(),
basis,
}
}