use crate::quiver_algebra::{checked_arith::Ring, path_algebra::PathAlgebra, quiver::BasisElt};
pub trait HasHomologicalDegree {
#[allow(clippy::result_unit_err)]
fn homological_degree(&self) -> Result<i64, ()>;
}
impl<VertexLabel, EdgeLabel> HasHomologicalDegree for BasisElt<VertexLabel, EdgeLabel>
where
VertexLabel: std::hash::Hash + Eq + Clone,
EdgeLabel: Eq + std::hash::Hash + Clone + HasHomologicalDegree,
{
fn homological_degree(&self) -> Result<i64, ()> {
match self {
BasisElt::Idempotent(_) => Ok(0),
BasisElt::Path(word) => word
.iter()
.try_fold(0i64, |acc, e| e.homological_degree().map(|d| acc + d)),
}
}
}
impl<VertexLabel, EdgeLabel, Coeffs, const OP_ALG: bool> HasHomologicalDegree
for PathAlgebra<VertexLabel, EdgeLabel, Coeffs, OP_ALG>
where
VertexLabel: std::hash::Hash + Eq + Clone,
EdgeLabel: Eq + std::hash::Hash + Clone + HasHomologicalDegree,
Coeffs: Ring,
{
fn homological_degree(&self) -> Result<i64, ()> {
let mut degree: Option<i64> = None;
for basis in self.iter().map(|(b, _)| b) {
let d = basis.homological_degree()?;
match degree {
None => degree = Some(d),
Some(existing) if existing == d => {}
Some(_) => return Err(()),
}
}
degree.ok_or(())
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct DegreeLabel<T> {
name: T,
degree: Option<i64>,
}
impl<'a, T> DegreeLabel<T>
where
T: 'a,
{
pub fn new(name: T, degree: i64) -> Self {
Self {
name,
degree: Some(degree),
}
}
pub fn new_deg_zero(name: T) -> Self {
Self {
name,
degree: Some(0),
}
}
pub fn dagger(rename: fn(&T) -> T) -> impl Fn(&Self) -> Self + 'a {
move |t| Self {
name: rename(&t.name),
degree: t.homological_degree().map(|z| -z - 1).ok(),
}
}
pub fn name(&self) -> &T {
&self.name
}
}
impl<T> HasHomologicalDegree for DegreeLabel<T> {
fn homological_degree(&self) -> Result<i64, ()> {
self.degree.ok_or(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::quiver_algebra::quiver::Quiver;
fn self_loop(v: &&str) -> DegreeLabel<String> {
DegreeLabel {
name: format!("omega_{v}"),
degree: Some(-2),
}
}
#[test]
fn ginzburg_cubic_degree_minus_3() {
let mut quiver: Quiver<&str, DegreeLabel<String>> = Quiver::new();
quiver.add_edge(
"v",
"v",
DegreeLabel {
name: "a".into(),
degree: Some(0),
},
);
let (_ginzburg_arc, _, _, cubic) = quiver.ginzburgify_and_cubic::<i64, true>(
DegreeLabel::<String>::dagger(|e_str| format!("{}*", e_str)),
self_loop,
);
assert_eq!(cubic.homological_degree(), Ok(-3));
assert!(cubic.all_parallel() == Ok(Some(("v", "v"))));
}
#[test]
fn ginzburg_cubic_a2() {
let mut quiver: Quiver<&str, DegreeLabel<String>> = Quiver::new();
quiver.add_edge(
"alpha",
"beta",
DegreeLabel {
name: "a".into(),
degree: Some(0),
},
);
let (_ginzburg_arc, _, _, cubic) = quiver.ginzburgify_and_cubic::<i64, true>(
DegreeLabel::<String>::dagger(|e_str| format!("{}*", e_str)),
self_loop,
);
assert_eq!(cubic.homological_degree(), Ok(-3));
assert!(cubic.all_parallel().is_err());
}
}