1use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6
7use super::functions::*;
8use std::collections::HashMap;
9
10#[allow(dead_code)]
12#[derive(Debug, Clone)]
13pub struct Divisor {
14 pub components: Vec<(String, i32)>,
15 pub is_effective: bool,
16 pub is_prime: bool,
17}
18#[allow(dead_code)]
19impl Divisor {
20 pub fn zero() -> Self {
22 Self {
23 components: Vec::new(),
24 is_effective: true,
25 is_prime: false,
26 }
27 }
28 pub fn prime(name: &str) -> Self {
30 Self {
31 components: vec![(name.to_string(), 1)],
32 is_effective: true,
33 is_prime: true,
34 }
35 }
36 pub fn degree(&self) -> i32 {
38 self.components.iter().map(|(_, c)| c).sum()
39 }
40 pub fn linear_equiv_description(&self) -> String {
42 format!("Div class of degree {}", self.degree())
43 }
44}
45#[allow(dead_code)]
47#[derive(Debug, Clone)]
48pub struct ChernClass {
49 pub vector_bundle: String,
50 pub rank: usize,
51 pub classes: Vec<String>,
52}
53#[allow(dead_code)]
54impl ChernClass {
55 pub fn new(bundle: &str, rank: usize) -> Self {
57 let classes = (0..=rank).map(|i| format!("c_{}({})", i, bundle)).collect();
58 Self {
59 vector_bundle: bundle.to_string(),
60 rank,
61 classes,
62 }
63 }
64 pub fn total_chern_class(&self) -> String {
66 self.classes.join(" + ")
67 }
68 pub fn grr_applies(&self) -> bool {
70 true
71 }
72}
73#[derive(Debug, Clone)]
78pub struct AffineVariety {
79 pub ambient_dim: usize,
81 pub equations: Vec<String>,
83}
84impl AffineVariety {
85 pub fn new(ambient_dim: usize, equations: Vec<String>) -> Self {
87 Self {
88 ambient_dim,
89 equations,
90 }
91 }
92 pub fn empty(n: usize) -> Self {
94 Self::new(n, vec!["1".to_string()])
95 }
96 pub fn affine_space(n: usize) -> Self {
98 Self::new(n, vec![])
99 }
100 pub fn num_equations(&self) -> usize {
102 self.equations.len()
103 }
104 pub fn codimension_estimate(&self) -> usize {
106 self.equations.len().min(self.ambient_dim)
107 }
108 pub fn dimension_estimate(&self) -> usize {
110 self.ambient_dim.saturating_sub(self.codimension_estimate())
111 }
112 pub fn is_empty_variety(&self) -> bool {
114 self.equations.iter().any(|eq| eq.trim() == "1")
115 }
116 pub fn is_full_space(&self) -> bool {
118 self.equations.is_empty()
119 }
120}
121#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct ProjectivePoint {
127 pub coords: Vec<i64>,
129}
130impl ProjectivePoint {
131 pub fn new(coords: Vec<i64>) -> Option<Self> {
134 if coords.iter().all(|&c| c == 0) {
135 None
136 } else {
137 Some(Self { coords })
138 }
139 }
140 pub fn dim(&self) -> usize {
142 self.coords.len().saturating_sub(1)
143 }
144 pub fn normalize(&self) -> Self {
146 let g = self
147 .coords
148 .iter()
149 .fold(0i64, |acc, &x| gcd(acc.abs(), x.abs()));
150 if g == 0 {
151 return self.clone();
152 }
153 let sign = self
154 .coords
155 .iter()
156 .find(|&&c| c != 0)
157 .map(|&c| if c < 0 { -1i64 } else { 1i64 })
158 .unwrap_or(1);
159 Self {
160 coords: self.coords.iter().map(|&c| sign * c / g).collect(),
161 }
162 }
163 pub fn equiv(&self, other: &ProjectivePoint) -> bool {
165 if self.coords.len() != other.coords.len() {
166 return false;
167 }
168 let n = self.coords.len();
169 for i in 0..n {
170 for j in 0..n {
171 if self.coords[i] * other.coords[j] != self.coords[j] * other.coords[i] {
172 return false;
173 }
174 }
175 }
176 true
177 }
178}
179#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct DivisorClass {
184 pub degree: i64,
186 pub genus: i64,
188 pub label: String,
190}
191impl DivisorClass {
192 pub fn new(degree: i64, genus: i64, label: impl Into<String>) -> Self {
194 Self {
195 degree,
196 genus,
197 label: label.into(),
198 }
199 }
200 pub fn zero(genus: i64) -> Self {
202 Self::new(0, genus, "O")
203 }
204 pub fn canonical(genus: i64) -> Self {
206 Self::new(2 * genus - 2, genus, "K")
207 }
208 pub fn add(&self, other: &DivisorClass) -> Self {
210 assert_eq!(self.genus, other.genus, "genus must match");
211 Self::new(
212 self.degree + other.degree,
213 self.genus,
214 format!("{}+{}", self.label, other.label),
215 )
216 }
217 pub fn neg(&self) -> Self {
219 Self::new(-self.degree, self.genus, format!("-{}", self.label))
220 }
221 pub fn sub(&self, other: &DivisorClass) -> Self {
223 self.add(&other.neg())
224 }
225 pub fn is_effective(&self) -> bool {
227 self.degree >= 0
228 }
229 pub fn is_canonical(&self) -> bool {
231 self.degree == 2 * self.genus - 2
232 }
233}
234#[allow(dead_code)]
236#[derive(Debug, Clone)]
237pub struct ProjectiveVariety {
238 pub name: String,
239 pub ambient_dim: usize,
240 pub degree: usize,
241 pub is_smooth: bool,
242 pub is_irreducible: bool,
243}
244#[allow(dead_code)]
245impl ProjectiveVariety {
246 pub fn projective_space(n: usize) -> Self {
248 Self {
249 name: format!("P^{}", n),
250 ambient_dim: n,
251 degree: 1,
252 is_smooth: true,
253 is_irreducible: true,
254 }
255 }
256 pub fn hypersurface(n: usize, d: usize) -> Self {
258 Self {
259 name: format!("V_{}(P^{})", d, n),
260 ambient_dim: n,
261 degree: d,
262 is_smooth: true,
263 is_irreducible: true,
264 }
265 }
266 pub fn expected_dim(&self) -> usize {
268 if self.ambient_dim > 0 {
269 self.ambient_dim - 1
270 } else {
271 0
272 }
273 }
274 pub fn bezout_bound(&self, other_degree: usize) -> usize {
276 self.degree * other_degree
277 }
278}
279#[derive(Debug, Clone, PartialEq, Eq)]
281pub struct AffineScheme {
282 pub ring: String,
284}
285impl AffineScheme {
286 pub fn new(ring: impl Into<String>) -> Self {
288 Self { ring: ring.into() }
289 }
290 pub fn spec_z() -> Self {
292 Self::new("Int")
293 }
294 pub fn affine_n_space(base_ring: &str, n: usize) -> Self {
296 let vars: Vec<String> = (1..=n).map(|i| format!("x{}", i)).collect();
297 Self::new(format!("{}[{}]", base_ring, vars.join(", ")))
298 }
299 pub fn krull_dim_estimate(&self) -> Option<usize> {
301 if self.ring.contains('[') {
302 let inner = self.ring.split('[').nth(1)?;
303 let vars = inner.trim_end_matches(']');
304 Some(vars.split(',').count())
305 } else if self.ring == "Int" || self.ring == "Z" {
306 Some(1)
307 } else {
308 None
309 }
310 }
311}
312#[derive(Debug, Clone)]
316pub struct Sheaf<T: Clone> {
317 sections: std::collections::HashMap<String, T>,
319 restriction_labels: Vec<(String, String)>,
321}
322impl<T: Clone> Sheaf<T> {
323 pub fn new() -> Self {
325 Self {
326 sections: std::collections::HashMap::new(),
327 restriction_labels: Vec::new(),
328 }
329 }
330 pub fn add_section(&mut self, open_set: impl Into<String>, section: T) {
332 self.sections.insert(open_set.into(), section);
333 }
334 pub fn section(&self, open_set: &str) -> Option<&T> {
336 self.sections.get(open_set)
337 }
338 pub fn add_restriction(&mut self, source: impl Into<String>, target: impl Into<String>) {
340 self.restriction_labels.push((source.into(), target.into()));
341 }
342 pub fn num_sections(&self) -> usize {
344 self.sections.len()
345 }
346}
347#[derive(Debug, Clone, PartialEq, Eq)]
349pub struct ProjectiveSpace {
350 pub dim: usize,
352}
353impl ProjectiveSpace {
354 pub fn new(dim: usize) -> Self {
356 Self { dim }
357 }
358 pub fn projective_line() -> Self {
360 Self::new(1)
361 }
362 pub fn projective_plane() -> Self {
364 Self::new(2)
365 }
366 pub fn num_coordinates(&self) -> usize {
368 self.dim + 1
369 }
370 pub fn euler_characteristic(&self) -> i64 {
372 (self.dim as i64) + 1
373 }
374 pub fn betti_numbers(&self) -> Vec<u64> {
376 let mut betti = vec![0u64; 2 * self.dim + 1];
377 for k in 0..=self.dim {
378 betti[2 * k] = 1;
379 }
380 betti
381 }
382}
383#[derive(Debug, Clone, PartialEq, Eq)]
385pub struct Morphism {
386 pub source: String,
388 pub target: String,
390}
391impl Morphism {
392 pub fn new(source: impl Into<String>, target: impl Into<String>) -> Self {
394 Self {
395 source: source.into(),
396 target: target.into(),
397 }
398 }
399 pub fn identity(scheme: impl Into<String>) -> Self {
401 let s = scheme.into();
402 Self {
403 source: s.clone(),
404 target: s,
405 }
406 }
407 pub fn is_identity(&self) -> bool {
409 self.source == self.target
410 }
411 pub fn compose(&self, other: &Morphism) -> Option<Morphism> {
414 if self.target == other.source {
415 Some(Morphism::new(self.source.clone(), other.target.clone()))
416 } else {
417 None
418 }
419 }
420}
421#[derive(Debug, Clone, PartialEq, Eq)]
426pub enum EllipticCurvePoint {
427 Infinity,
429 Affine { x: i64, y: i64 },
431}
432#[allow(dead_code)]
434#[derive(Debug, Clone)]
435pub struct ModuliProblem {
436 pub objects: String,
437 pub equivalence: String,
438 pub coarse_moduli_space: Option<String>,
439 pub has_fine_moduli: bool,
440}
441#[allow(dead_code)]
442impl ModuliProblem {
443 pub fn elliptic_curves() -> Self {
445 Self {
446 objects: "elliptic curves over k".to_string(),
447 equivalence: "isomorphism".to_string(),
448 coarse_moduli_space: Some("A^1_j".to_string()),
449 has_fine_moduli: false,
450 }
451 }
452 pub fn vector_bundles(n: usize, degree: i32) -> Self {
454 Self {
455 objects: format!("rank-{} bundles of degree {}", n, degree),
456 equivalence: "S-equivalence".to_string(),
457 coarse_moduli_space: Some(format!("M({},{})", n, degree)),
458 has_fine_moduli: false,
459 }
460 }
461 pub fn fine_moduli_description(&self) -> String {
463 if self.has_fine_moduli {
464 format!("Fine moduli space exists for {}", self.objects)
465 } else {
466 format!("Only coarse moduli exists for {}", self.objects)
467 }
468 }
469}
470#[derive(Debug, Clone)]
472pub struct EllipticCurveF {
473 pub a: i64,
475 pub b: i64,
477 pub p: i64,
479}
480impl EllipticCurveF {
481 pub fn new(a: i64, b: i64, p: i64) -> Self {
484 Self { a, b, p }
485 }
486 pub fn is_nonsingular(&self) -> bool {
488 let disc = mod_reduce(
489 4 * pow_mod(self.a, 3, self.p) + 27 * pow_mod(self.b, 2, self.p),
490 self.p,
491 );
492 disc != 0
493 }
494 pub fn on_curve(&self, x: i64, y: i64) -> bool {
496 let lhs = mod_reduce(y * y, self.p);
497 let rhs = mod_reduce(pow_mod(x, 3, self.p) + self.a * x + self.b, self.p);
498 lhs == rhs
499 }
500 pub fn points(&self) -> Vec<EllipticCurvePoint> {
502 let mut pts = vec![EllipticCurvePoint::Infinity];
503 for x in 0..self.p {
504 for y in 0..self.p {
505 if self.on_curve(x, y) {
506 pts.push(EllipticCurvePoint::Affine { x, y });
507 }
508 }
509 }
510 pts
511 }
512 pub fn point_count(&self) -> usize {
514 self.points().len()
515 }
516 pub fn add(&self, p_pt: &EllipticCurvePoint, q_pt: &EllipticCurvePoint) -> EllipticCurvePoint {
518 match (p_pt, q_pt) {
519 (EllipticCurvePoint::Infinity, q) => q.clone(),
520 (p, EllipticCurvePoint::Infinity) => p.clone(),
521 (
522 EllipticCurvePoint::Affine { x: x1, y: y1 },
523 EllipticCurvePoint::Affine { x: x2, y: y2 },
524 ) => {
525 if x1 == x2 && mod_reduce(y1 + y2, self.p) == 0 {
526 return EllipticCurvePoint::Infinity;
527 }
528 let lambda = if x1 == x2 && y1 == y2 {
529 let num = mod_reduce(3 * pow_mod(*x1, 2, self.p) + self.a, self.p);
530 let den = mod_reduce(2 * y1, self.p);
531 mod_mul(num, mod_inv(den, self.p), self.p)
532 } else {
533 let num = mod_reduce(y2 - y1, self.p);
534 let den = mod_reduce(x2 - x1, self.p);
535 mod_mul(num, mod_inv(den, self.p), self.p)
536 };
537 let x3 = mod_reduce(pow_mod(lambda, 2, self.p) - x1 - x2, self.p);
538 let y3 = mod_reduce(lambda * (x1 - x3) - y1, self.p);
539 EllipticCurvePoint::Affine { x: x3, y: y3 }
540 }
541 }
542 }
543 pub fn scalar_mul(&self, n: u64, pt: &EllipticCurvePoint) -> EllipticCurvePoint {
545 let mut result = EllipticCurvePoint::Infinity;
546 let mut addend = pt.clone();
547 let mut k = n;
548 while k > 0 {
549 if k & 1 == 1 {
550 result = self.add(&result, &addend);
551 }
552 addend = self.add(&addend, &addend);
553 k >>= 1;
554 }
555 result
556 }
557 pub fn point_order(&self, pt: &EllipticCurvePoint, max_order: u64) -> Option<u64> {
560 if matches!(pt, EllipticCurvePoint::Infinity) {
561 return Some(1);
562 }
563 let mut current = pt.clone();
564 for n in 1..=max_order {
565 current = self.add(¤t, pt);
566 if matches!(current, EllipticCurvePoint::Infinity) {
567 return Some(n + 1);
568 }
569 }
570 None
571 }
572}
573#[allow(dead_code)]
575#[derive(Debug, Clone)]
576pub struct AffineSchemeData {
577 pub ring: String,
578 pub is_integral: bool,
579 pub is_noetherian: bool,
580 pub dimension: Option<usize>,
581}
582#[allow(dead_code)]
583impl AffineSchemeData {
584 pub fn affine_space(n: usize) -> Self {
586 Self {
587 ring: format!("k[x1,...,x{}]", n),
588 is_integral: true,
589 is_noetherian: true,
590 dimension: Some(n),
591 }
592 }
593 pub fn point() -> Self {
595 Self {
596 ring: "k".to_string(),
597 is_integral: true,
598 is_noetherian: true,
599 dimension: Some(0),
600 }
601 }
602 pub fn is_variety(&self) -> bool {
604 self.is_integral && self.is_noetherian
605 }
606}