use amari_enumerative::{IntersectionResult, SchubertCalculus};
use crate::schubert_type::SchubertType;
#[derive(Debug, Clone)]
pub struct Intersection {
kind: IntersectionKind,
multiplicity: u64,
decomposition: Vec<SchubertType>,
}
impl Intersection {
fn structural_zero() -> Self {
Self {
kind: IntersectionKind::StructuralZero,
multiplicity: 0,
decomposition: Vec::new(),
}
}
fn geometric_zero() -> Self {
Self {
kind: IntersectionKind::GeometricZero,
multiplicity: 0,
decomposition: Vec::new(),
}
}
fn positive(multiplicity: u64, decomposition: Vec<SchubertType>) -> Self {
Self {
kind: IntersectionKind::Positive,
multiplicity,
decomposition,
}
}
pub fn kind(&self) -> IntersectionKind {
self.kind
}
pub fn multiplicity(&self) -> u64 {
self.multiplicity
}
pub fn decomposition(&self) -> &[SchubertType] {
&self.decomposition
}
pub fn into_schubert(self) -> Option<SchubertType> {
if self.kind == IntersectionKind::Positive && !self.decomposition.is_empty() {
Some(self.decomposition.into_iter().next().unwrap())
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntersectionKind {
StructuralZero,
GeometricZero,
Positive,
Underdetermined,
}
impl IntersectionKind {
pub fn is_zero(&self) -> bool {
matches!(self, Self::StructuralZero | Self::GeometricZero)
}
}
pub fn check_intersection(a: &SchubertType, b: &SchubertType) -> Intersection {
let mut calc = SchubertCalculus::new(a.grassmannian_dim());
let classes = [a.as_inner().clone(), b.as_inner().clone()];
let result = calc.multi_intersect(&classes);
match result {
IntersectionResult::Empty => {
let total_codim = a.codimension() + b.codimension();
let dim = calc.grassmannian_dimension();
if total_codim > dim {
Intersection::structural_zero()
} else {
Intersection::geometric_zero()
}
}
IntersectionResult::Finite(n) => Intersection::positive(n, Vec::new()),
IntersectionResult::PositiveDimensional {
dimension: _,
degree,
} => {
let multiplicity = degree.unwrap_or(1);
Intersection::positive(multiplicity, Vec::new())
}
}
}