use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use std::collections::HashMap;
use super::functions::*;
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct FourierMukaiData {
pub source_scheme: String,
pub target_scheme: String,
pub kernel_label: String,
pub source_cohomology: Vec<usize>,
pub target_cohomology: Vec<usize>,
}
impl FourierMukaiData {
pub fn new(source: &str, target: &str, kernel: &str) -> Self {
Self {
source_scheme: source.to_string(),
target_scheme: target.to_string(),
kernel_label: kernel.to_string(),
source_cohomology: Vec::new(),
target_cohomology: Vec::new(),
}
}
pub fn set_source_cohomology(&mut self, ranks: Vec<usize>) {
self.source_cohomology = ranks;
}
pub fn set_target_cohomology(&mut self, ranks: Vec<usize>) {
self.target_cohomology = ranks;
}
pub fn is_point_like_source(&self) -> bool {
self.source_cohomology.iter().enumerate().all(
|(n, &r)| {
if n == 0 {
r == 1
} else {
r == 0
}
},
)
}
pub fn is_point_like_target(&self) -> bool {
self.target_cohomology.iter().enumerate().all(
|(n, &r)| {
if n == 0 {
r == 1
} else {
r == 0
}
},
)
}
pub fn is_likely_equivalence(&self) -> bool {
self.is_point_like_source() && self.is_point_like_target()
}
pub fn source_euler_characteristic(&self) -> i64 {
self.source_cohomology
.iter()
.enumerate()
.map(|(n, &r)| if n % 2 == 0 { r as i64 } else { -(r as i64) })
.sum()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct ModelCategoryData {
pub objects: Vec<String>,
pub morphisms: Vec<(usize, usize, String)>,
pub weak_equivalences: Vec<usize>,
pub fibrations: Vec<usize>,
pub cofibrations: Vec<usize>,
}
impl ModelCategoryData {
pub fn new() -> Self {
Self::default()
}
pub fn add_object(&mut self, name: &str) -> usize {
let idx = self.objects.len();
self.objects.push(name.to_string());
idx
}
pub fn add_morphism(&mut self, src: usize, tgt: usize, label: &str) -> usize {
let idx = self.morphisms.len();
self.morphisms.push((src, tgt, label.to_string()));
idx
}
pub fn mark_weak_equivalence(&mut self, m_idx: usize) {
if !self.weak_equivalences.contains(&m_idx) {
self.weak_equivalences.push(m_idx);
}
}
pub fn mark_fibration(&mut self, m_idx: usize) {
if !self.fibrations.contains(&m_idx) {
self.fibrations.push(m_idx);
}
}
pub fn mark_cofibration(&mut self, m_idx: usize) {
if !self.cofibrations.contains(&m_idx) {
self.cofibrations.push(m_idx);
}
}
pub fn is_acyclic_fibration(&self, m_idx: usize) -> bool {
self.weak_equivalences.contains(&m_idx) && self.fibrations.contains(&m_idx)
}
pub fn is_acyclic_cofibration(&self, m_idx: usize) -> bool {
self.weak_equivalences.contains(&m_idx) && self.cofibrations.contains(&m_idx)
}
pub fn is_cofibrant(&self, obj_idx: usize) -> bool {
self.morphisms
.iter()
.enumerate()
.filter(|(_, (src, tgt, _))| *src == 0 && *tgt == obj_idx)
.all(|(m_idx, _)| self.cofibrations.contains(&m_idx))
}
pub fn counts(&self) -> (usize, usize, usize) {
(
self.weak_equivalences.len(),
self.fibrations.len(),
self.cofibrations.len(),
)
}
}
#[derive(Debug, Clone, Default)]
pub struct ChainComplex {
pub groups: Vec<ChainGroup>,
pub boundaries: Vec<Vec<Vec<i64>>>,
}
impl ChainComplex {
pub fn new() -> Self {
Self::default()
}
pub fn add_group(&mut self, rank: usize, name: &str) {
self.groups.push(ChainGroup::new(rank, name));
}
pub fn add_boundary(&mut self, matrix: Vec<Vec<i64>>) {
self.boundaries.push(matrix);
}
pub fn compute_betti_numbers(&self) -> Vec<i64> {
let n = self.groups.len();
(0..n)
.map(|i| {
let ker = if i > 0 && i - 1 < self.boundaries.len() {
let d = &self.boundaries[i - 1];
let cols = self.groups[i].rank;
kernel_rank(d, cols) as i64
} else {
self.groups[i].rank as i64
};
let img = if i < self.boundaries.len() && i + 1 < self.groups.len() {
let d = &self.boundaries[i];
let cols = self.groups[i + 1].rank;
image_rank(d, cols) as i64
} else {
0
};
ker - img
})
.collect()
}
pub fn euler_characteristic(&self) -> i64 {
self.compute_betti_numbers()
.iter()
.enumerate()
.map(|(i, &b)| if i % 2 == 0 { b } else { -b })
.sum()
}
pub fn is_exact_at(&self, n: usize) -> bool {
let betti = self.compute_betti_numbers();
betti.get(n).copied().unwrap_or(0) == 0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChainGroup {
pub rank: usize,
pub name: String,
}
impl ChainGroup {
pub fn new(rank: usize, name: &str) -> Self {
Self {
rank,
name: name.to_string(),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct SpectralSequence {
pub pages: Vec<HashMap<(i32, i32), usize>>,
pub page_num: usize,
}
impl SpectralSequence {
pub fn new() -> Self {
Self::default()
}
pub fn add_page(&mut self, page: HashMap<(i32, i32), usize>) {
self.pages.push(page);
self.page_num = self.pages.len().saturating_sub(1);
}
pub fn e_term(&self, page: usize, p: i32, q: i32) -> Option<usize> {
self.pages.get(page)?.get(&(p, q)).copied()
}
pub fn converges_at(&self) -> usize {
if self.pages.len() < 2 {
return self.page_num;
}
for r in 1..self.pages.len() {
if self.pages[r] == self.pages[r - 1] {
return r;
}
}
self.page_num
}
}
#[derive(Debug, Clone, Default)]
pub struct DGCategoryData {
pub objects: Vec<String>,
pub hom_complexes: HashMap<(usize, usize), ChainComplex>,
}
impl DGCategoryData {
pub fn new() -> Self {
Self::default()
}
pub fn add_object(&mut self, name: &str) -> usize {
let idx = self.objects.len();
self.objects.push(name.to_string());
idx
}
pub fn set_hom(&mut self, i: usize, j: usize, complex: ChainComplex) {
self.hom_complexes.insert((i, j), complex);
}
pub fn get_hom(&self, i: usize, j: usize) -> Option<&ChainComplex> {
self.hom_complexes.get(&(i, j))
}
pub fn ext_degree(&self, i: usize, j: usize, n: usize) -> Option<i64> {
let cx = self.get_hom(i, j)?;
let betti = cx.compute_betti_numbers();
betti.get(n).copied()
}
pub fn are_quasi_isomorphic(&self, i: usize, j: usize) -> bool {
if let Some(cx) = self.get_hom(i, j) {
let betti = cx.compute_betti_numbers();
betti.iter().enumerate().all(|(n, &b)| n == 0 || b == 0)
} else {
false
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ChowGroupData {
pub scheme: String,
pub codimension: usize,
pub cycles: HashMap<String, i64>,
}
impl ChowGroupData {
pub fn new(scheme: &str, codimension: usize) -> Self {
Self {
scheme: scheme.to_string(),
codimension,
cycles: HashMap::new(),
}
}
pub fn add_cycle(&mut self, subvariety: &str, coefficient: i64) {
let entry = self.cycles.entry(subvariety.to_string()).or_insert(0);
*entry += coefficient;
}
pub fn degree(&self) -> i64 {
self.cycles.values().sum()
}
pub fn is_zero(&self) -> bool {
self.cycles.values().all(|&c| c == 0)
}
pub fn intersection_number(&self, other: &ChowGroupData) -> i64 {
self.degree() * other.degree()
}
pub fn cycle_class(&self) -> i64 {
self.degree()
}
}
#[derive(Debug, Clone, Default)]
pub struct SpectralSequencePage {
pub r: usize,
pub groups: HashMap<(i32, i32), usize>,
pub differentials: Vec<((i32, i32), (i32, i32), usize)>,
}
impl SpectralSequencePage {
pub fn new(r: usize) -> Self {
Self {
r,
groups: HashMap::new(),
differentials: Vec::new(),
}
}
pub fn set_group(&mut self, p: i32, q: i32, rank: usize) {
self.groups.insert((p, q), rank);
}
pub fn add_differential(&mut self, p: i32, q: i32, image_rank: usize) {
let target = (p - self.r as i32, q + self.r as i32 - 1);
self.differentials.push(((p, q), target, image_rank));
}
pub fn compute_next_page(&self) -> HashMap<(i32, i32), usize> {
let mut next: HashMap<(i32, i32), usize> = HashMap::new();
for (&(p, q), &rank) in &self.groups {
let incoming_src = (p + self.r as i32, q - self.r as i32 + 1);
let incoming_im: usize = self
.differentials
.iter()
.filter(|(src, tgt, _)| *src == incoming_src && *tgt == (p, q))
.map(|(_, _, im)| *im)
.sum();
let outgoing_im: usize = self
.differentials
.iter()
.filter(|(src, _, _)| *src == (p, q))
.map(|(_, _, im)| *im)
.sum();
let ker_rank = rank.saturating_sub(outgoing_im);
let next_rank = ker_rank.saturating_sub(incoming_im);
next.insert((p, q), next_rank);
}
next
}
pub fn is_degenerate(&self) -> bool {
self.differentials.iter().all(|(_, _, im)| *im == 0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtGroup {
pub m_name: String,
pub n_name: String,
pub degree: usize,
pub rank: usize,
}
impl ExtGroup {
pub fn new(m: &str, n: &str, degree: usize, rank: usize) -> Self {
Self {
m_name: m.to_string(),
n_name: n.to_string(),
degree,
rank,
}
}
pub fn is_zero(&self) -> bool {
self.rank == 0
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct TiltingTheoryData {
pub algebra_a: String,
pub tilting_module: String,
pub algebra_b: String,
pub indecomposable_summands: Vec<String>,
pub self_ext_ranks: Vec<usize>,
}
impl TiltingTheoryData {
pub fn new(algebra_a: &str, tilting_module: &str) -> Self {
Self {
algebra_a: algebra_a.to_string(),
tilting_module: tilting_module.to_string(),
algebra_b: format!("End_{}({})", algebra_a, tilting_module),
indecomposable_summands: Vec::new(),
self_ext_ranks: Vec::new(),
}
}
pub fn add_summand(&mut self, summand: &str) {
self.indecomposable_summands.push(summand.to_string());
}
pub fn set_self_ext(&mut self, n: usize, rank: usize) {
if n == 0 {
return;
}
let idx = n - 1;
if idx >= self.self_ext_ranks.len() {
self.self_ext_ranks.resize(idx + 1, 0);
}
self.self_ext_ranks[idx] = rank;
}
pub fn satisfies_tilting_condition(&self) -> bool {
self.self_ext_ranks.iter().all(|&r| r == 0)
}
pub fn n_summands(&self) -> usize {
self.indecomposable_summands.len()
}
pub fn is_progenerator(&self) -> bool {
!self.indecomposable_summands.is_empty()
}
}
#[derive(Debug, Clone, Default)]
pub struct TriangulatedCategoryData {
pub objects: Vec<String>,
pub triangles: Vec<(usize, usize, usize)>,
}
impl TriangulatedCategoryData {
pub fn new() -> Self {
Self::default()
}
pub fn add_object(&mut self, name: &str) -> usize {
let idx = self.objects.len();
self.objects.push(name.to_string());
idx
}
pub fn add_triangle(&mut self, x: usize, y: usize, z: usize) {
assert!(
x < self.objects.len() && y < self.objects.len() && z < self.objects.len(),
"triangle vertex index out of range"
);
self.triangles.push((x, y, z));
}
pub fn is_distinguished(&self, x: usize, y: usize, z: usize) -> bool {
self.triangles.contains(&(x, y, z))
}
pub fn triangle_count(&self) -> usize {
self.triangles.len()
}
pub fn check_octahedral(&self, cone_xy: usize, cone_xz: usize, cone_yz: usize) -> bool {
self.is_distinguished(cone_xy, cone_xz, cone_yz)
}
}
#[derive(Debug, Clone, Default)]
pub struct MixedHodgeStructureData {
pub weight: i32,
pub hodge_numbers: HashMap<(i32, i32), usize>,
}
impl MixedHodgeStructureData {
pub fn new(weight: i32) -> Self {
Self {
weight,
hodge_numbers: HashMap::new(),
}
}
pub fn set_hodge_number(&mut self, p: i32, q: i32, value: usize) {
self.hodge_numbers.insert((p, q), value);
self.hodge_numbers.insert((q, p), value);
}
pub fn hodge_number(&self, p: i32, q: i32) -> usize {
*self.hodge_numbers.get(&(p, q)).unwrap_or(&0)
}
pub fn total_dimension(&self) -> usize {
let mut dim = 0usize;
for (&(p, q), &h) in &self.hodge_numbers {
if p <= q {
if p == q {
dim += h;
} else {
dim += 2 * h;
}
}
}
dim
}
pub fn satisfies_hodge_symmetry(&self) -> bool {
for (&(p, q), &h) in &self.hodge_numbers {
if self.hodge_number(q, p) != h {
return false;
}
}
true
}
pub fn is_pure(&self) -> bool {
self.hodge_numbers
.iter()
.all(|(&(p, q), &h)| h == 0 || p + q == self.weight)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct SemiorthogonalDecompositionData {
pub components: Vec<String>,
pub hom_nonzero: Vec<Vec<bool>>,
}
impl SemiorthogonalDecompositionData {
pub fn new(component_labels: Vec<String>) -> Self {
let n = component_labels.len();
Self {
components: component_labels,
hom_nonzero: vec![vec![false; n]; n],
}
}
pub fn set_hom_nonzero(&mut self, i: usize, j: usize) {
if i < self.components.len() && j < self.components.len() {
self.hom_nonzero[i][j] = true;
}
}
pub fn is_semiorthogonal(&self) -> bool {
let n = self.components.len();
for i in 0..n {
for j in (i + 1)..n {
if self.hom_nonzero[i][j] {
return false;
}
}
}
true
}
pub fn n_components(&self) -> usize {
self.components.len()
}
pub fn nonzero_hom_pairs(&self) -> Vec<(usize, usize)> {
let n = self.components.len();
let mut pairs = Vec::new();
for i in 0..n {
for j in 0..n {
if self.hom_nonzero[i][j] {
pairs.push((i, j));
}
}
}
pairs
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct BridgelandStabilityData {
pub objects: Vec<String>,
pub charges: Vec<(f64, f64)>,
}
impl BridgelandStabilityData {
pub fn new() -> Self {
Self::default()
}
pub fn add_object(&mut self, name: &str, re: f64, im: f64) {
self.objects.push(name.to_string());
self.charges.push((re, im));
}
pub fn phase(&self, idx: usize) -> f64 {
if idx >= self.charges.len() {
return 0.0;
}
let (re, im) = self.charges[idx];
let arg = im.atan2(re);
let phi = arg / std::f64::consts::PI;
if phi <= 0.0 {
phi + 1.0
} else {
phi
}
}
pub fn mass(&self, idx: usize) -> f64 {
if idx >= self.charges.len() {
return 0.0;
}
let (re, im) = self.charges[idx];
(re * re + im * im).sqrt()
}
pub fn support_property_holds(&self) -> bool {
self.charges
.iter()
.all(|(re, im)| re.abs() > 1e-12 || im.abs() > 1e-12)
}
pub fn destabilises(&self, j: usize, i: usize) -> bool {
self.phase(j) > self.phase(i)
}
pub fn semistable_objects(&self) -> Vec<usize> {
(0..self.objects.len())
.filter(|&i| !(0..self.objects.len()).any(|j| j != i && self.destabilises(j, i)))
.collect()
}
}
#[derive(Debug, Clone, Default)]
pub struct AbelianGroup {
pub generators: Vec<String>,
pub relations: Vec<Vec<i64>>,
}
impl AbelianGroup {
pub fn new(generators: Vec<String>, relations: Vec<Vec<i64>>) -> Self {
AbelianGroup {
generators,
relations,
}
}
pub fn free(n: usize) -> Self {
let gens = (0..n).map(|i| format!("e{}", i)).collect();
AbelianGroup {
generators: gens,
relations: Vec::new(),
}
}
pub fn trivial() -> Self {
AbelianGroup {
generators: vec!["e".into()],
relations: vec![vec![1]],
}
}
pub fn cyclic(n: i64) -> Self {
AbelianGroup {
generators: vec!["t".into()],
relations: vec![vec![n]],
}
}
pub fn rank(&self) -> usize {
self.generators.len()
}
}
#[derive(Debug, Clone, Default)]
pub struct SpecChainComplex {
pub groups: Vec<AbelianGroup>,
pub differentials: Vec<Vec<Vec<i64>>>,
}
impl SpecChainComplex {
pub fn new(groups: Vec<AbelianGroup>, differentials: Vec<Vec<Vec<i64>>>) -> Self {
SpecChainComplex {
groups,
differentials,
}
}
pub fn len(&self) -> usize {
self.groups.len()
}
pub fn is_empty(&self) -> bool {
self.groups.is_empty()
}
}
#[derive(Debug, Clone, Default)]
pub struct CochainComplex {
pub groups: Vec<AbelianGroup>,
pub coboundaries: Vec<Vec<Vec<i64>>>,
}
impl CochainComplex {
pub fn new(groups: Vec<AbelianGroup>, coboundaries: Vec<Vec<Vec<i64>>>) -> Self {
CochainComplex {
groups,
coboundaries,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct HomologyGroup {
pub degree: i32,
pub free_rank: usize,
pub torsion: Vec<u64>,
}
impl HomologyGroup {
pub fn new(degree: i32, free_rank: usize, torsion: Vec<u64>) -> Self {
HomologyGroup {
degree,
free_rank,
torsion,
}
}
pub fn zero(degree: i32) -> Self {
HomologyGroup {
degree,
free_rank: 0,
torsion: Vec::new(),
}
}
pub fn is_zero(&self) -> bool {
self.free_rank == 0 && self.torsion.is_empty()
}
}
#[derive(Debug, Clone, Default)]
pub struct SpecChainMap {
pub source: usize,
pub target: usize,
pub maps: Vec<Vec<Vec<i64>>>,
}
impl SpecChainMap {
pub fn new(source: usize, target: usize, maps: Vec<Vec<Vec<i64>>>) -> Self {
SpecChainMap {
source,
target,
maps,
}
}
}
#[derive(Debug, Clone)]
pub struct SpecShortExactSequence {
pub groups: [AbelianGroup; 3],
pub maps: [Vec<Vec<i64>>; 2],
}
impl SpecShortExactSequence {
pub fn new(
a: AbelianGroup,
b: AbelianGroup,
c: AbelianGroup,
f: Vec<Vec<i64>>,
g: Vec<Vec<i64>>,
) -> Self {
SpecShortExactSequence {
groups: [a, b, c],
maps: [f, g],
}
}
}
#[derive(Debug, Clone, Default)]
pub struct LongExactSequence {
pub groups: Vec<AbelianGroup>,
pub maps: Vec<Vec<Vec<i64>>>,
}
impl LongExactSequence {
pub fn new(groups: Vec<AbelianGroup>, maps: Vec<Vec<Vec<i64>>>) -> Self {
LongExactSequence { groups, maps }
}
}
#[derive(Debug, Clone)]
pub struct SpecExtGroup {
pub p: usize,
pub q: usize,
pub group: HomologyGroup,
}
impl SpecExtGroup {
pub fn new(p: usize, q: usize, group: HomologyGroup) -> Self {
SpecExtGroup { p, q, group }
}
}
#[derive(Debug, Clone)]
pub struct TorGroup {
pub p: usize,
pub q: usize,
pub group: HomologyGroup,
}
impl TorGroup {
pub fn new(p: usize, q: usize, group: HomologyGroup) -> Self {
TorGroup { p, q, group }
}
}