Skip to main content

amari_enumerative/
geometric_algebra.rs

1//! Integration between geometric algebra and enumerative geometry
2//!
3//! This module bridges the gap between Clifford algebra structures from amari-core
4//! and enumerative geometry computations, enabling geometric representations of
5//! algebraic varieties, Schubert cells, and moduli spaces.
6
7use crate::{
8    ChowClass, EnumerativeError, EnumerativeResult, IntersectionNumber, ProjectiveSpace,
9    SchubertClass,
10};
11use amari_core::{Multivector, Rotor};
12use num_rational::Rational64;
13use std::collections::HashMap;
14
15/// Common geometric algebra signatures for enumerative geometry
16pub mod signatures {
17    use amari_core::Multivector;
18
19    /// Euclidean 3D space Cl(3,0,0) - for real projective geometry
20    pub type Euclidean3D = Multivector<3, 0, 0>;
21
22    /// Projective space Cl(3,1,0) - adds point at infinity
23    pub type Projective3D = Multivector<3, 1, 0>;
24
25    /// Conformal space Cl(4,1,0) - adds conformal point
26    pub type Conformal4D = Multivector<4, 1, 0>;
27
28    /// Complex projective space Cl(2,0,0) ⊗ ℂ representation
29    pub type ComplexProjective = Multivector<4, 0, 0>;
30
31    /// Grassmannian representation Cl(k,n-k,0) for Gr(k,n)
32    pub type GrassmannianGA<const K: usize, const N_MINUS_K: usize> = Multivector<K, N_MINUS_K, 0>;
33}
34
35/// Geometric representation of an algebraic variety using multivectors
36#[derive(Debug, Clone)]
37pub struct GeometricVariety<const P: usize, const Q: usize, const R: usize> {
38    /// The underlying multivector representation
39    pub multivector: Multivector<P, Q, R>,
40    /// Dimension of the variety
41    pub dimension: usize,
42    /// Degree of the variety
43    pub degree: Rational64,
44    /// Additional geometric invariants
45    pub invariants: HashMap<String, f64>,
46}
47
48impl<const P: usize, const Q: usize, const R: usize> GeometricVariety<P, Q, R> {
49    /// Create a new geometric variety from a multivector
50    pub fn new(multivector: Multivector<P, Q, R>, dimension: usize, degree: Rational64) -> Self {
51        Self {
52            multivector,
53            dimension,
54            degree,
55            invariants: HashMap::new(),
56        }
57    }
58
59    /// Create a point variety (0-dimensional)
60    pub fn point(coordinates: &[f64]) -> EnumerativeResult<Self> {
61        if coordinates.len() != P + Q + R {
62            return Err(EnumerativeError::InvalidDimension(format!(
63                "Expected {} coordinates, got {}",
64                P + Q + R,
65                coordinates.len()
66            )));
67        }
68
69        let mut mv = Multivector::zero();
70        for (i, &coord) in coordinates.iter().enumerate() {
71            mv = mv + Multivector::basis_vector(i) * coord;
72        }
73
74        Ok(Self::new(mv, 0, Rational64::from(1)))
75    }
76
77    /// Create a line variety (1-dimensional) from two points
78    pub fn line_through_points(p1: &Self, p2: &Self) -> EnumerativeResult<Self> {
79        if p1.dimension != 0 || p2.dimension != 0 {
80            return Err(EnumerativeError::InvalidDimension(
81                "Line construction requires point varieties".to_string(),
82            ));
83        }
84
85        // Line as wedge product of two points in projective geometry
86        let line_mv = p1.multivector.outer_product(&p2.multivector);
87        Ok(Self::new(line_mv, 1, Rational64::from(1)))
88    }
89
90    /// Create a plane variety (2-dimensional) from three points
91    pub fn plane_through_points(p1: &Self, p2: &Self, p3: &Self) -> EnumerativeResult<Self> {
92        if p1.dimension != 0 || p2.dimension != 0 || p3.dimension != 0 {
93            return Err(EnumerativeError::InvalidDimension(
94                "Plane construction requires point varieties".to_string(),
95            ));
96        }
97
98        // Plane as wedge product of three points
99        let plane_mv = p1
100            .multivector
101            .outer_product(&p2.multivector)
102            .outer_product(&p3.multivector);
103        Ok(Self::new(plane_mv, 2, Rational64::from(1)))
104    }
105
106    /// Convert to a Chow class representation
107    pub fn to_chow_class(&self) -> ChowClass {
108        ChowClass::new(self.dimension, self.degree)
109    }
110
111    /// Compute the intersection with another geometric variety
112    pub fn intersect_with(&self, other: &Self) -> EnumerativeResult<Vec<Self>> {
113        // In geometric algebra, intersection can be computed using the meet operation
114        // Meet operation: a ∨ b = ⋆(⋆a ∧ ⋆b) where ⋆ is the Hodge dual
115        let self_dual = self.multivector.hodge_dual();
116        let other_dual = other.multivector.hodge_dual();
117        let intersection_mv = self_dual.outer_product(&other_dual).hodge_dual();
118        let intersection_dim = (P + Q + R).saturating_sub(self.dimension + other.dimension);
119
120        let intersection_degree = self.degree * other.degree;
121
122        Ok(vec![Self::new(
123            intersection_mv,
124            intersection_dim,
125            intersection_degree,
126        )])
127    }
128
129    /// Apply a rotor transformation to the variety
130    pub fn transform(&self, rotor: &Rotor<P, Q, R>) -> Self {
131        let transformed_mv = rotor.apply(&self.multivector);
132        Self {
133            multivector: transformed_mv,
134            dimension: self.dimension,
135            degree: self.degree,
136            invariants: self.invariants.clone(),
137        }
138    }
139
140    /// Compute the geometric degree (related to multivector magnitude)
141    pub fn geometric_degree(&self) -> f64 {
142        self.multivector.magnitude()
143    }
144
145    /// Check if this variety contains a given point
146    pub fn contains_point(&self, point: &Self) -> bool {
147        if point.dimension != 0 {
148            return false;
149        }
150
151        // In GA, point lies on variety if their meet equals the point
152        // Meet operation: a ∨ b = ⋆(⋆a ∧ ⋆b)
153        let self_dual = self.multivector.hodge_dual();
154        let point_dual = point.multivector.hodge_dual();
155        let meet = self_dual.outer_product(&point_dual).hodge_dual();
156        (meet - point.multivector.clone()).magnitude() < 1e-10
157    }
158}
159
160/// Geometric algebra enhanced Schubert class
161#[derive(Debug, Clone)]
162pub struct GeometricSchubertClass<const P: usize, const Q: usize, const R: usize> {
163    /// Standard Schubert class
164    pub schubert_class: SchubertClass,
165    /// Geometric algebra representation
166    pub multivector: Multivector<P, Q, R>,
167    /// Grassmannian parameters (k, n)
168    pub grassmannian_dim: (usize, usize),
169}
170
171impl<const P: usize, const Q: usize, const R: usize> GeometricSchubertClass<P, Q, R> {
172    /// Create a geometric Schubert class from a partition
173    pub fn new(partition: Vec<usize>, grassmannian_dim: (usize, usize)) -> EnumerativeResult<Self> {
174        let schubert_class = SchubertClass::new(partition, grassmannian_dim)?;
175
176        // Create multivector representation based on the Plücker embedding
177        let mut mv = Multivector::scalar(1.0);
178        for (i, &part) in schubert_class.partition.iter().enumerate() {
179            if part > 0 {
180                // Add basis blade corresponding to Schubert condition
181                // Use basis vector since there's no basis_blade method
182                let blade = Multivector::basis_vector(i + part);
183                mv = mv.outer_product(&blade);
184            }
185        }
186
187        Ok(Self {
188            schubert_class,
189            multivector: mv,
190            grassmannian_dim,
191        })
192    }
193
194    /// Compute geometric intersection with another Schubert class
195    pub fn geometric_intersection(&self, other: &Self) -> EnumerativeResult<Self> {
196        if self.grassmannian_dim != other.grassmannian_dim {
197            return Err(EnumerativeError::InvalidDimension(
198                "Schubert classes must be on the same Grassmannian".to_string(),
199            ));
200        }
201
202        // Geometric intersection via multivector product
203        let intersection_mv = self.multivector.geometric_product(&other.multivector);
204
205        // Combine partitions (simplified)
206        let mut new_partition = self.schubert_class.partition.clone();
207        for (i, &part) in other.schubert_class.partition.iter().enumerate() {
208            if i < new_partition.len() {
209                new_partition[i] = new_partition[i].saturating_add(part);
210            } else {
211                new_partition.push(part);
212            }
213        }
214
215        Ok(Self {
216            schubert_class: SchubertClass::new(new_partition, self.grassmannian_dim)?,
217            multivector: intersection_mv,
218            grassmannian_dim: self.grassmannian_dim,
219        })
220    }
221
222    /// Convert to standard Schubert class
223    pub fn to_schubert_class(&self) -> &SchubertClass {
224        &self.schubert_class
225    }
226}
227
228/// Geometric algebra enhanced projective space
229#[derive(Debug, Clone)]
230pub struct GeometricProjectiveSpace<const P: usize, const Q: usize, const R: usize> {
231    /// Standard projective space
232    pub projective_space: ProjectiveSpace,
233    /// Geometric algebra context
234    pub _phantom: std::marker::PhantomData<Multivector<P, Q, R>>,
235}
236
237impl<const P: usize, const Q: usize, const R: usize> GeometricProjectiveSpace<P, Q, R> {
238    /// Create a new geometric projective space
239    pub fn new(dimension: usize) -> Self {
240        Self {
241            projective_space: ProjectiveSpace::new(dimension),
242            _phantom: std::marker::PhantomData,
243        }
244    }
245
246    /// Create a variety from multivector coefficients
247    pub fn variety_from_multivector(
248        &self,
249        multivector: Multivector<P, Q, R>,
250        dimension: usize,
251        degree: Rational64,
252    ) -> GeometricVariety<P, Q, R> {
253        GeometricVariety::new(multivector, dimension, degree)
254    }
255
256    /// Compute intersection number using geometric algebra
257    pub fn geometric_intersection_number(
258        &self,
259        variety1: &GeometricVariety<P, Q, R>,
260        variety2: &GeometricVariety<P, Q, R>,
261    ) -> IntersectionNumber {
262        // Use geometric product magnitude as intersection multiplicity
263        let intersection_mv = variety1
264            .multivector
265            .geometric_product(&variety2.multivector);
266        let multiplicity = intersection_mv.magnitude();
267
268        IntersectionNumber::new(Rational64::from(multiplicity as i64))
269    }
270
271    /// Create a hyperplane from normal vector
272    pub fn hyperplane_from_normal(
273        &self,
274        normal: &[f64],
275    ) -> EnumerativeResult<GeometricVariety<P, Q, R>> {
276        if normal.len() != P + Q + R {
277            return Err(EnumerativeError::InvalidDimension(format!(
278                "Normal vector must have {} components",
279                P + Q + R
280            )));
281        }
282
283        let mut normal_mv = Multivector::zero();
284        for (i, &component) in normal.iter().enumerate() {
285            normal_mv = normal_mv + Multivector::basis_vector(i) * component;
286        }
287
288        Ok(GeometricVariety::new(
289            normal_mv,
290            self.projective_space.dimension - 1,
291            Rational64::from(1),
292        ))
293    }
294}
295
296/// Quantum K-theory for enumerative geometry
297///
298/// This module implements quantum K-theory, which extends classical K-theory
299/// by incorporating quantum corrections from rational curves. It provides
300/// tools for computing quantum K-theory rings and quantum products.
301pub mod quantum_k_theory {
302    use super::*;
303    use std::collections::BTreeMap;
304
305    /// Quantum K-theory ring element with geometric algebra enhancement
306    #[derive(Debug, Clone)]
307    pub struct QuantumKClass<const P: usize, const Q: usize, const R: usize> {
308        /// Geometric algebra representation
309        pub multivector: Multivector<P, Q, R>,
310        /// K-theory degree (virtual dimension)
311        pub k_degree: i32,
312        /// Quantum parameter q^n where n counts rational curves
313        pub q_power: i32,
314        /// Todd class corrections for coherent sheaves
315        pub todd_coefficients: Vec<Rational64>,
316        /// Chern character components
317        pub chern_character: BTreeMap<usize, Rational64>,
318    }
319
320    impl<const P: usize, const Q: usize, const R: usize> QuantumKClass<P, Q, R> {
321        /// Create a new quantum K-class
322        pub fn new(multivector: Multivector<P, Q, R>, k_degree: i32, q_power: i32) -> Self {
323            Self {
324                multivector,
325                k_degree,
326                q_power,
327                todd_coefficients: vec![Rational64::from(1)], // Todd class starts with 1
328                chern_character: BTreeMap::new(),
329            }
330        }
331
332        /// Create the structure sheaf of a point
333        pub fn structure_sheaf_point() -> Self {
334            Self::new(Multivector::scalar(1.0), 0, 0)
335        }
336
337        /// Create a line bundle with first Chern class c₁
338        pub fn line_bundle(c1: i64) -> Self {
339            let mut class = Self::new(Multivector::scalar(1.0), 0, 0);
340            class.chern_character.insert(1, Rational64::from(c1));
341            class
342        }
343
344        /// Create the tangent bundle of projective space
345        pub fn tangent_bundle_projective(dimension: usize) -> Self {
346            let mut class = Self::new(Multivector::scalar(1.0), dimension as i32, 0);
347            // Tangent bundle of P^n has Chern character e^H * (1 + H)^(n+1) / (1 + H) - 1
348            // where H is the hyperplane class
349            for i in 1..=dimension {
350                class.chern_character.insert(i, Rational64::from(1));
351            }
352            class
353        }
354
355        /// Quantum K-theory product incorporating Gromov-Witten corrections
356        pub fn quantum_product(&self, other: &Self) -> EnumerativeResult<Self> {
357            // Classical K-theory tensor product
358            let classical_mv = self.multivector.geometric_product(&other.multivector);
359            let classical_degree = self.k_degree + other.k_degree;
360
361            // Quantum corrections from curve counting
362            let mut quantum_power = self.q_power + other.q_power;
363            let mut result_class = Self::new(classical_mv, classical_degree, quantum_power);
364
365            // Combine Chern characters using the formula ch(E ⊗ F) = ch(E) * ch(F)
366            for (&deg1, &coeff1) in &self.chern_character {
367                for (&deg2, &coeff2) in &other.chern_character {
368                    let total_deg = deg1 + deg2;
369                    let combined_coeff = coeff1 * coeff2;
370                    *result_class
371                        .chern_character
372                        .entry(total_deg)
373                        .or_insert(Rational64::from(0)) += combined_coeff;
374                }
375            }
376
377            // Add quantum corrections from Gromov-Witten invariants
378            // In quantum K-theory, we get corrections from stable maps of curves
379            let gw_correction = self.compute_gw_correction(other)?;
380            quantum_power += gw_correction;
381            result_class.q_power = quantum_power;
382
383            Ok(result_class)
384        }
385
386        /// Compute Gromov-Witten corrections for quantum K-theory product
387        fn compute_gw_correction(&self, other: &Self) -> EnumerativeResult<i32> {
388            // Simplified GW correction computation
389            // In a full implementation, this would involve:
390            // 1. Integration over moduli spaces of stable maps
391            // 2. Virtual fundamental classes
392            // 3. Localization via torus actions
393
394            let total_degree = (self.k_degree + other.k_degree).abs();
395
396            // Basic correction: curves of degree d contribute q^d terms
397            if total_degree > 0
398                && self.has_positive_chern_class()
399                && other.has_positive_chern_class()
400            {
401                Ok(total_degree) // Simplified: each positive intersection contributes q^|degree|
402            } else {
403                Ok(0) // No quantum correction
404            }
405        }
406
407        /// Check if this class has positive Chern classes (indicating positivity)
408        fn has_positive_chern_class(&self) -> bool {
409            self.chern_character
410                .values()
411                .any(|&coeff| coeff > Rational64::from(0))
412        }
413
414        /// Compute the Chern character in cohomology
415        pub fn chern_character_total(&self) -> Rational64 {
416            self.chern_character.values().sum()
417        }
418
419        /// Euler characteristic χ(E) = ∫ ch(E) * td(T_X)
420        pub fn euler_characteristic(&self, ambient_dimension: usize) -> Rational64 {
421            let ch_total = self.chern_character_total();
422            let todd_correction = self.todd_class_value(ambient_dimension);
423            ch_total * todd_correction
424        }
425
426        /// Todd class value for the ambient space
427        fn todd_class_value(&self, dimension: usize) -> Rational64 {
428            // Todd class of projective space P^n is (1+H)^(n+1) / ((1+H-1)^(n+1)/H)
429            // Simplified: Todd(P^n) ≈ 1 for basic computations
430            if dimension == 0 {
431                Rational64::from(1)
432            } else {
433                // For P^n, Todd class gives binomial coefficient corrections
434                Rational64::from(1) + Rational64::from(dimension as i64) / Rational64::from(2)
435            }
436        }
437
438        /// Dual in quantum K-theory
439        pub fn dual(&self) -> Self {
440            let dual_mv = self.multivector.reverse(); // Use reverse as dual in GA
441            let mut dual_class = Self::new(dual_mv, -self.k_degree, -self.q_power);
442
443            // Dual Chern character: ch(E^*) = ch(E)^*
444            for (&deg, &coeff) in &self.chern_character {
445                dual_class.chern_character.insert(deg, -coeff);
446            }
447
448            dual_class
449        }
450
451        /// Apply Adams operations ψᵏ
452        pub fn adams_operation(&self, k: i32) -> Self {
453            let powered_mv = if k >= 0 {
454                // For positive k, we take a kind of "power" via geometric product
455                let mut result = self.multivector.clone();
456                for _ in 1..k {
457                    result = result.geometric_product(&self.multivector);
458                }
459                result
460            } else {
461                self.multivector
462                    .inverse()
463                    .unwrap_or_else(|| self.multivector.clone())
464            };
465
466            let mut adams_class = Self::new(powered_mv, self.k_degree * k, self.q_power * k);
467
468            // Adams operations on Chern character: ψᵏ(ch(E)) = Σ kⁱ chᵢ(E)
469            for (&deg, &coeff) in &self.chern_character {
470                let k_power = (k as i64).pow(deg as u32);
471                let adams_coeff = coeff * Rational64::from(k_power);
472                adams_class.chern_character.insert(deg, adams_coeff);
473            }
474
475            adams_class
476        }
477
478        /// Riemann-Roch theorem computation: χ(E) = ∫ ch(E) * td(X)
479        pub fn riemann_roch_euler(&self, ambient_todd: &[Rational64]) -> Rational64 {
480            let mut result = Rational64::from(0);
481
482            for (&deg, &ch_coeff) in &self.chern_character {
483                if deg < ambient_todd.len() {
484                    result += ch_coeff * ambient_todd[deg];
485                }
486            }
487
488            result
489        }
490
491        /// Localization formula for torus-equivariant quantum K-theory
492        pub fn localized_integral(
493            &self,
494            fixed_points: &[GeometricVariety<P, Q, R>],
495        ) -> EnumerativeResult<Rational64> {
496            let mut total = Rational64::from(0);
497
498            // Localization: ∫_X ω = Σ_{f∈X^T} ω(f) / e_T(N_f)
499            // where X^T are the torus fixed points and N_f is the normal bundle
500            for point in fixed_points {
501                let point_contribution = self.evaluate_at_point(point)?;
502                let normal_euler = self.normal_bundle_euler_class(point);
503
504                if normal_euler != Rational64::from(0) {
505                    total += point_contribution / normal_euler;
506                }
507            }
508
509            Ok(total)
510        }
511
512        /// Evaluate the K-theory class at a fixed point
513        fn evaluate_at_point(
514            &self,
515            point: &GeometricVariety<P, Q, R>,
516        ) -> EnumerativeResult<Rational64> {
517            // Simplified evaluation: use the geometric degree
518            let geometric_eval = point.geometric_degree();
519            Ok(Rational64::from(geometric_eval as i64))
520        }
521
522        /// Compute Euler class of normal bundle at fixed point
523        fn normal_bundle_euler_class(&self, _point: &GeometricVariety<P, Q, R>) -> Rational64 {
524            // Simplified normal bundle computation
525            // In practice, this depends on the specific torus action
526            Rational64::from((P + Q + R) as i64) // Simplified placeholder
527        }
528
529        /// Quantum cohomology to K-theory correspondence
530        pub fn from_quantum_cohomology(
531            _qh_class: &crate::QuantumCohomology,
532        ) -> EnumerativeResult<Self> {
533            // This implements the correspondence between quantum cohomology and quantum K-theory
534            // via the Gamma class and other characteristic classes
535
536            let multivector = Multivector::scalar(1.0); // Placeholder
537            let mut k_class = Self::new(multivector, 0, 0);
538
539            // Add Chern character from cohomology class
540            // In practice, this requires the Chern character map ch: K → H^*
541            k_class.chern_character.insert(0, Rational64::from(1));
542
543            Ok(k_class)
544        }
545    }
546
547    /// Quantum K-theory ring structure
548    #[derive(Debug)]
549    pub struct QuantumKRing<const P: usize, const Q: usize, const R: usize> {
550        /// Base ring generators
551        pub generators: Vec<QuantumKClass<P, Q, R>>,
552        /// Relations in the ring
553        pub relations: Vec<String>,
554        /// Quantum parameter
555        pub quantum_parameter: String,
556    }
557
558    impl<const P: usize, const Q: usize, const R: usize> Default for QuantumKRing<P, Q, R> {
559        fn default() -> Self {
560            Self::new()
561        }
562    }
563
564    impl<const P: usize, const Q: usize, const R: usize> QuantumKRing<P, Q, R> {
565        /// Create a new quantum K-theory ring
566        pub fn new() -> Self {
567            Self {
568                generators: Vec::new(),
569                relations: Vec::new(),
570                quantum_parameter: "q".to_string(),
571            }
572        }
573
574        /// Add a generator to the ring
575        pub fn add_generator(&mut self, class: QuantumKClass<P, Q, R>) {
576            self.generators.push(class);
577        }
578
579        /// Quantum K-theory ring of projective space
580        pub fn projective_space(dimension: usize) -> Self {
581            let mut ring = Self::new();
582
583            // Generator: line bundle O(1)
584            let line_bundle = QuantumKClass::line_bundle(1);
585            ring.add_generator(line_bundle);
586
587            // Relation: O(1)^(n+1) = 0 in K_0(P^n) tensored with Q
588            ring.relations.push(format!("L^{} = 0", dimension + 1));
589
590            ring
591        }
592
593        /// Quantum K-theory ring of Grassmannian Gr(k,n)
594        pub fn grassmannian(k: usize, n: usize) -> Self {
595            let mut ring = Self::new();
596
597            // Tautological bundles S and Q
598            let tautological_sub = QuantumKClass::new(Multivector::scalar(1.0), k as i32, 0);
599            let quotient_bundle = QuantumKClass::new(Multivector::scalar(1.0), (n - k) as i32, 0);
600
601            ring.add_generator(tautological_sub);
602            ring.add_generator(quotient_bundle);
603
604            // Quantum Pieri rules and other relations would go here
605            ring.relations.push("Quantum Pieri rules".to_string());
606
607            ring
608        }
609    }
610}
611
612#[cfg(test)]
613mod tests {
614    use super::*;
615
616    #[test]
617    fn test_point_creation() {
618        let point = GeometricVariety::<3, 0, 0>::point(&[1.0, 2.0, 3.0]).unwrap();
619        assert_eq!(point.dimension, 0);
620        assert_eq!(point.degree, Rational64::from(1));
621    }
622
623    #[test]
624    fn test_line_through_points() {
625        let p1 = GeometricVariety::<3, 0, 0>::point(&[1.0, 0.0, 0.0]).unwrap();
626        let p2 = GeometricVariety::<3, 0, 0>::point(&[0.0, 1.0, 0.0]).unwrap();
627        let line = GeometricVariety::line_through_points(&p1, &p2).unwrap();
628
629        assert_eq!(line.dimension, 1);
630        assert_eq!(line.degree, Rational64::from(1));
631    }
632
633    #[test]
634    fn test_geometric_projective_space() {
635        let gp2 = GeometricProjectiveSpace::<2, 1, 0>::new(2);
636        let hyperplane = gp2.hyperplane_from_normal(&[1.0, 1.0, 1.0]).unwrap();
637
638        assert_eq!(hyperplane.dimension, 1); // Codimension 1 in P²
639    }
640
641    #[test]
642    fn test_schubert_class_creation() {
643        let schubert = GeometricSchubertClass::<2, 2, 0>::new(vec![1], (2, 4)).unwrap();
644        assert_eq!(schubert.grassmannian_dim, (2, 4));
645        assert_eq!(schubert.schubert_class.partition, vec![1]);
646    }
647
648    // Quantum K-theory tests
649    #[test]
650    fn test_quantum_k_class_creation() {
651        use super::quantum_k_theory::QuantumKClass;
652
653        let mv = Multivector::<3, 0, 0>::scalar(1.0);
654        let qk_class = QuantumKClass::new(mv, 1, 0);
655
656        assert_eq!(qk_class.k_degree, 1);
657        assert_eq!(qk_class.q_power, 0);
658        assert_eq!(qk_class.todd_coefficients, vec![Rational64::from(1)]);
659    }
660
661    #[test]
662    fn test_line_bundle_creation() {
663        use super::quantum_k_theory::QuantumKClass;
664
665        let line_bundle = QuantumKClass::<3, 0, 0>::line_bundle(2);
666        assert_eq!(line_bundle.k_degree, 0);
667        assert_eq!(
668            *line_bundle.chern_character.get(&1).unwrap(),
669            Rational64::from(2)
670        );
671    }
672
673    #[test]
674    fn test_quantum_product_basic() {
675        use super::quantum_k_theory::QuantumKClass;
676
677        let bundle1 = QuantumKClass::<3, 0, 0>::line_bundle(1);
678        let bundle2 = QuantumKClass::<3, 0, 0>::line_bundle(1);
679
680        let product = bundle1.quantum_product(&bundle2).unwrap();
681
682        // Check that we get quantum corrections
683        assert!(product.q_power >= 0);
684        assert!(!product.chern_character.is_empty());
685    }
686
687    #[test]
688    fn test_adams_operations() {
689        use super::quantum_k_theory::QuantumKClass;
690
691        let line_bundle = QuantumKClass::<3, 0, 0>::line_bundle(2);
692        let adams_2 = line_bundle.adams_operation(2);
693
694        // Adams operation ψ² on line bundle with c₁=2 should give 2² = 4
695        assert_eq!(
696            *adams_2.chern_character.get(&1).unwrap(),
697            Rational64::from(4)
698        );
699    }
700
701    #[test]
702    fn test_euler_characteristic() {
703        use super::quantum_k_theory::QuantumKClass;
704
705        let structure_sheaf = QuantumKClass::<3, 0, 0>::structure_sheaf_point();
706        let euler_char = structure_sheaf.euler_characteristic(2);
707
708        // Structure sheaf of a point should have χ = 1
709        assert!(euler_char >= Rational64::from(0));
710    }
711
712    #[test]
713    fn test_dual_bundle() {
714        use super::quantum_k_theory::QuantumKClass;
715
716        let line_bundle = QuantumKClass::<3, 0, 0>::line_bundle(3);
717        let dual = line_bundle.dual();
718
719        // Dual of O(3) should be O(-3)
720        assert_eq!(dual.k_degree, -line_bundle.k_degree);
721        assert_eq!(*dual.chern_character.get(&1).unwrap(), Rational64::from(-3));
722    }
723
724    #[test]
725    fn test_quantum_k_ring_projective_space() {
726        use super::quantum_k_theory::QuantumKRing;
727
728        let ring = QuantumKRing::<3, 0, 0>::projective_space(2);
729        assert_eq!(ring.generators.len(), 1);
730        assert!(ring.relations.contains(&"L^3 = 0".to_string()));
731    }
732
733    #[test]
734    fn test_quantum_k_ring_grassmannian() {
735        use super::quantum_k_theory::QuantumKRing;
736
737        let ring = QuantumKRing::<4, 0, 0>::grassmannian(2, 4);
738        assert_eq!(ring.generators.len(), 2); // Tautological sub and quotient bundles
739        assert!(!ring.relations.is_empty());
740    }
741
742    #[test]
743    fn test_riemann_roch_computation() {
744        use super::quantum_k_theory::QuantumKClass;
745
746        let line_bundle = QuantumKClass::<3, 0, 0>::line_bundle(1);
747        let todd_classes = vec![Rational64::from(1), Rational64::from(1)];
748
749        let rr_result = line_bundle.riemann_roch_euler(&todd_classes);
750        assert!(rr_result >= Rational64::from(0));
751    }
752
753    #[test]
754    fn test_chern_character_total() {
755        use super::quantum_k_theory::QuantumKClass;
756
757        let mut bundle = QuantumKClass::<3, 0, 0>::new(Multivector::scalar(1.0), 2, 0);
758        bundle.chern_character.insert(0, Rational64::from(1));
759        bundle.chern_character.insert(1, Rational64::from(3));
760        bundle.chern_character.insert(2, Rational64::from(2));
761
762        let total = bundle.chern_character_total();
763        assert_eq!(total, Rational64::from(6)); // 1 + 3 + 2 = 6
764    }
765}