use hexpr::ast::Hexpr;
use hexpr::parser::HExprParser;
#[test]
fn test_basic_frobenius_join() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[x x . x]").unwrap();
let expected = Hexpr::Frobenius {
sources: vec!["x".parse()?, "x".parse()?],
targets: vec!["x".parse()?],
};
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_basic_frobenius_split() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[x . x x]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["x".parse()?],
targets: vec!["x".parse()?, "x".parse()?],
}
);
Ok(())
}
#[test]
fn test_identity_shorthand() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[x y]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["x".parse()?, "y".parse()?],
targets: vec!["x".parse()?, "y".parse()?],
}
);
Ok(())
}
#[test]
fn test_named_identity() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[a]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["a".parse()?],
targets: vec!["a".parse()?],
}
);
Ok(())
}
#[test]
fn test_identity_via_composition() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("([x.][.x])").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Frobenius {
sources: vec!["x".parse()?],
targets: vec![],
},
Hexpr::Frobenius {
sources: vec![],
targets: vec!["x".parse()?],
},
])
);
Ok(())
}
#[test]
fn test_subtraction_pointfree() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("({[a] -} +)").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Tensor(vec![
Hexpr::Frobenius {
sources: vec!["a".parse()?],
targets: vec!["a".parse()?],
},
Hexpr::Operation("-".parse()?),
]),
Hexpr::Operation("+".parse()?),
])
);
Ok(())
}
#[test]
fn test_subtraction_pointed() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("([x y.] ([.y] - [z.]) [.x z] +)").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Frobenius {
sources: vec!["x".parse()?, "y".parse()?],
targets: vec![],
},
Hexpr::Composition(vec![
Hexpr::Frobenius {
sources: vec![],
targets: vec!["y".parse()?],
},
Hexpr::Operation("-".parse()?),
Hexpr::Frobenius {
sources: vec!["z".parse()?],
targets: vec![],
},
]),
Hexpr::Frobenius {
sources: vec![],
targets: vec!["x".parse()?, "z".parse()?],
},
Hexpr::Operation("+".parse()?),
])
);
Ok(())
}
#[test]
fn test_explicit_swap_relation() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[x y . y x]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["x".parse()?, "y".parse()?],
targets: vec!["y".parse()?, "x".parse()?],
}
);
Ok(())
}
#[test]
fn test_empty_inputs_outputs() {
let result = HExprParser::parse_hexpr("[.]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec![],
targets: vec![],
}
);
}
#[test]
fn test_discard_variable() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[x .]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["x".parse()?],
targets: vec![],
}
);
Ok(())
}
#[test]
fn test_create_variable() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[. x]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec![],
targets: vec!["x".parse()?],
}
);
Ok(())
}
#[test]
fn test_dispell_summon_named() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("[a b . c]").unwrap();
assert_eq!(
result,
Hexpr::Frobenius {
sources: vec!["a".parse()?, "b".parse()?],
targets: vec!["c".parse()?],
}
);
Ok(())
}
#[test]
fn test_complex_composition() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("(add sub mul)").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Operation("add".parse()?),
Hexpr::Operation("sub".parse()?),
Hexpr::Operation("mul".parse()?),
])
);
Ok(())
}
#[test]
fn test_complex_tensor() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("{add sub mul}").unwrap();
assert_eq!(
result,
Hexpr::Tensor(vec![
Hexpr::Operation("add".parse()?),
Hexpr::Operation("sub".parse()?),
Hexpr::Operation("mul".parse()?),
])
);
Ok(())
}
#[test]
fn test_nested_expressions() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("({add} (sub mul))").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Tensor(vec![Hexpr::Operation("add".parse()?)]),
Hexpr::Composition(vec![
Hexpr::Operation("sub".parse()?),
Hexpr::Operation("mul".parse()?),
]),
])
);
Ok(())
}
#[test]
fn test_names_with_dashes_and_underscores() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr("my-operation_2").unwrap();
assert_eq!(result, Hexpr::Operation("my-operation_2".parse()?));
Ok(())
}
#[test]
fn test_whitespace_handling() -> anyhow::Result<()> {
let result = HExprParser::parse_hexpr(" ( add sub ) ").unwrap();
assert_eq!(
result,
Hexpr::Composition(vec![
Hexpr::Operation("add".parse()?),
Hexpr::Operation("sub".parse()?),
])
);
Ok(())
}
#[test]
fn test_invalid_syntax() {
assert!(HExprParser::parse_hexpr("(").is_err());
assert!(HExprParser::parse_hexpr("[").is_err());
assert!(HExprParser::parse_hexpr("{").is_err());
assert!(HExprParser::parse_hexpr("").is_err());
}