process-geometry 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. aeg_shakespeare/__init__.py +52 -0
  2. aeg_shakespeare/_legacy_api.py +299 -0
  3. aeg_shakespeare/analysis/__init__.py +12 -0
  4. aeg_shakespeare/analysis/abelian.py +69 -0
  5. aeg_shakespeare/analysis/algebraic.py +11 -0
  6. aeg_shakespeare/analysis/am.py +19 -0
  7. aeg_shakespeare/analysis/connection.py +74 -0
  8. aeg_shakespeare/analysis/decomposition.py +37 -0
  9. aeg_shakespeare/analysis/module.py +5 -0
  10. aeg_shakespeare/central.py +20 -0
  11. aeg_shakespeare/constraints.py +121 -0
  12. aeg_shakespeare/construction.py +303 -0
  13. aeg_shakespeare/core.py +59 -0
  14. aeg_shakespeare/cost.py +51 -0
  15. aeg_shakespeare/discovery/__init__.py +53 -0
  16. aeg_shakespeare/discovery/coefficient_extension.py +75 -0
  17. aeg_shakespeare/discovery/polynomial.py +342 -0
  18. aeg_shakespeare/discovery/selection.py +146 -0
  19. aeg_shakespeare/discovery/structured.py +201 -0
  20. aeg_shakespeare/families.py +31 -0
  21. aeg_shakespeare/frame.py +5 -0
  22. aeg_shakespeare/function_theory/__init__.py +100 -0
  23. aeg_shakespeare/function_theory/abel_jacobi.py +246 -0
  24. aeg_shakespeare/function_theory/abelian.py +129 -0
  25. aeg_shakespeare/function_theory/algebraic.py +105 -0
  26. aeg_shakespeare/function_theory/am.py +266 -0
  27. aeg_shakespeare/function_theory/intersection.py +321 -0
  28. aeg_shakespeare/function_theory/module.py +118 -0
  29. aeg_shakespeare/function_theory/period_matrix.py +155 -0
  30. aeg_shakespeare/function_theory/periods.py +216 -0
  31. aeg_shakespeare/function_theory/real_branch_cycles.py +286 -0
  32. aeg_shakespeare/function_theory/weierstrass.py +136 -0
  33. aeg_shakespeare/grammar.py +225 -0
  34. aeg_shakespeare/history_geometry.py +276 -0
  35. aeg_shakespeare/linear.py +70 -0
  36. aeg_shakespeare/presentation/__init__.py +23 -0
  37. aeg_shakespeare/presentation/budget.py +27 -0
  38. aeg_shakespeare/presentation/canonicalization.py +143 -0
  39. aeg_shakespeare/presentation/constraints.py +5 -0
  40. aeg_shakespeare/presentation/construction.py +19 -0
  41. aeg_shakespeare/presentation/grammar.py +15 -0
  42. aeg_shakespeare/presentation/history.py +45 -0
  43. aeg_shakespeare/presentation/morphism.py +66 -0
  44. aeg_shakespeare/presentation/relations.py +31 -0
  45. aeg_shakespeare/presentation/search.py +31 -0
  46. aeg_shakespeare/process/__init__.py +16 -0
  47. aeg_shakespeare/process/finite/__init__.py +43 -0
  48. aeg_shakespeare/process/finite/cocycle.py +166 -0
  49. aeg_shakespeare/process/finite/families.py +318 -0
  50. aeg_shakespeare/process/history.py +53 -0
  51. aeg_shakespeare/process/local/__init__.py +7 -0
  52. aeg_shakespeare/process/local/direction.py +88 -0
  53. aeg_shakespeare/process/local/frame.py +73 -0
  54. aeg_shakespeare/process/local/system.py +43 -0
  55. aeg_shakespeare/relations.py +374 -0
  56. aeg_shakespeare/rewrite.py +157 -0
  57. aeg_shakespeare/search.py +286 -0
  58. aeg_shakespeare/signature.py +155 -0
  59. process_geometry-0.0.3.dist-info/METADATA +305 -0
  60. process_geometry-0.0.3.dist-info/RECORD +63 -0
  61. process_geometry-0.0.3.dist-info/WHEEL +5 -0
  62. process_geometry-0.0.3.dist-info/licenses/LICENSE +24 -0
  63. process_geometry-0.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,31 @@
1
+ """Compatibility shim for the pre-refactor finite-family module path.
2
+
3
+ New code should import from ``aeg_shakespeare.process.finite``. The
4
+ implementation now physically lives under that semantic namespace.
5
+ """
6
+
7
+ from .process.finite.families import (
8
+ CharacterVerification,
9
+ FamilyAction,
10
+ FamilyActionVerification,
11
+ FamilyStep,
12
+ ProcessCharacter,
13
+ ProcessFamily,
14
+ character_invariance_residual,
15
+ transport_process_character,
16
+ verify_family_action,
17
+ verify_process_character,
18
+ )
19
+
20
+ __all__ = [
21
+ "ProcessFamily",
22
+ "FamilyStep",
23
+ "ProcessCharacter",
24
+ "CharacterVerification",
25
+ "verify_process_character",
26
+ "FamilyAction",
27
+ "FamilyActionVerification",
28
+ "verify_family_action",
29
+ "transport_process_character",
30
+ "character_invariance_residual",
31
+ ]
@@ -0,0 +1,5 @@
1
+ """Compatibility shim for the pre-refactor local process-frame module path."""
2
+
3
+ from .process.local.frame import ProcessFrame
4
+
5
+ __all__ = ["ProcessFrame"]
@@ -0,0 +1,100 @@
1
+ """Optional process-generated function-theory layers.
2
+
3
+ Addition/Multiplication (A/M) is the first concrete arithmetic theory.
4
+ Algebraic quotient profiles provide a second route for processes whose reduced
5
+ geometry forces elliptic/Abelian or higher-genus function languages. The
6
+ Abelian layer then exposes canonical holomorphic differentials, history lifts,
7
+ cycle intersections, branch-cut cycle constructions, period data, and finally
8
+ normalized history coordinates modulo the measured period lattice.
9
+ """
10
+
11
+ from .abel_jacobi import (
12
+ AbelJacobiHistoryIncrement,
13
+ NormalizedAbelianTorus,
14
+ abel_jacobi_history_increment,
15
+ normalized_abelian_torus,
16
+ )
17
+ from .abelian import (
18
+ AbelianIntegralProfile,
19
+ HyperellipticDifferential,
20
+ abelian_integral_profile,
21
+ holomorphic_differential_basis,
22
+ )
23
+ from .algebraic import HyperellipticProfile, hyperelliptic_profile
24
+ from .am import (
25
+ AMFunctionTheory,
26
+ AMPathFlow,
27
+ AMPowerWeight,
28
+ AMPrimitive,
29
+ AMState,
30
+ affine_am_frame,
31
+ )
32
+ from .intersection import (
33
+ LiftedCycleIntersection,
34
+ SampledIntersectionForm,
35
+ SampledRiemannProfile,
36
+ canonical_symplectic_form,
37
+ lifted_path_intersections,
38
+ sampled_intersection_form,
39
+ sampled_intersection_number,
40
+ sampled_riemann_profile,
41
+ )
42
+ from .module import ProcessFunctionModule, polynomial_am_module
43
+ from .period_matrix import AbelianCycleSystem, AbelianPeriodMatrix, compute_period_matrix
44
+ from .periods import (
45
+ GenusOneLattice,
46
+ LiftedSquareRootPath,
47
+ integrate_lifted_differential,
48
+ lift_square_root_path,
49
+ )
50
+ from .real_branch_cycles import (
51
+ ConstructedRealBranchCycles,
52
+ RealBranchCutPresentation,
53
+ RealBranchCycleSpec,
54
+ construct_real_branch_cycles,
55
+ real_branch_cut_presentation,
56
+ )
57
+ from .weierstrass import WeierstrassCubicProfile, weierstrass_cubic_profile
58
+
59
+ __all__ = [
60
+ "AbelJacobiHistoryIncrement",
61
+ "NormalizedAbelianTorus",
62
+ "abel_jacobi_history_increment",
63
+ "normalized_abelian_torus",
64
+ "AbelianIntegralProfile",
65
+ "HyperellipticDifferential",
66
+ "abelian_integral_profile",
67
+ "holomorphic_differential_basis",
68
+ "HyperellipticProfile",
69
+ "hyperelliptic_profile",
70
+ "AMFunctionTheory",
71
+ "AMPathFlow",
72
+ "AMPowerWeight",
73
+ "AMPrimitive",
74
+ "AMState",
75
+ "affine_am_frame",
76
+ "LiftedCycleIntersection",
77
+ "SampledIntersectionForm",
78
+ "SampledRiemannProfile",
79
+ "canonical_symplectic_form",
80
+ "lifted_path_intersections",
81
+ "sampled_intersection_form",
82
+ "sampled_intersection_number",
83
+ "sampled_riemann_profile",
84
+ "ProcessFunctionModule",
85
+ "polynomial_am_module",
86
+ "AbelianCycleSystem",
87
+ "AbelianPeriodMatrix",
88
+ "compute_period_matrix",
89
+ "GenusOneLattice",
90
+ "LiftedSquareRootPath",
91
+ "integrate_lifted_differential",
92
+ "lift_square_root_path",
93
+ "ConstructedRealBranchCycles",
94
+ "RealBranchCutPresentation",
95
+ "RealBranchCycleSpec",
96
+ "construct_real_branch_cycles",
97
+ "real_branch_cut_presentation",
98
+ "WeierstrassCubicProfile",
99
+ "weierstrass_cubic_profile",
100
+ ]
@@ -0,0 +1,246 @@
1
+ """Normalized Abelian history coordinates and the period-lattice quotient.
2
+
3
+ Primitive question
4
+ ------------------
5
+ Once a process quotient has emitted canonical holomorphic differentials, a
6
+ symplectic cycle system, and a Riemann-shaped period matrix, what does a lifted
7
+ history *measure* globally?
8
+
9
+ For a path ``gamma`` on a genus-``g`` curve the vector
10
+
11
+ u(gamma) = (integral_gamma omega_1, ..., integral_gamma omega_g)
12
+
13
+ records the Abelian-integral increment carried by that history. If ``A`` is
14
+ the A-period block, the normalized increment is
15
+
16
+ u_hat = A^{-1} u.
17
+
18
+ Closed A- and B-cycle histories then shift the normalized coordinate by
19
+
20
+ e_j and tau[:, j],
21
+
22
+ respectively. Thus the residual ambiguity after quotienting closed histories
23
+ is the lattice
24
+
25
+ Z^g + tau Z^g subset C^g.
26
+
27
+ Classical lineage
28
+ -----------------
29
+ This is the analytic construction underlying the Abel--Jacobi map and the
30
+ Jacobian of a compact Riemann surface. Choosing a base point and integrating a
31
+ basis of holomorphic one-forms sends points/divisors to ``C^g`` modulo the
32
+ period lattice. With A-normalized differentials the Jacobian has the standard
33
+ presentation
34
+
35
+ C^g / (Z^g + tau Z^g).
36
+
37
+ See Farkas--Kra, Forster, and Mumford in ``docs/REFERENCES.md``. Historically,
38
+ Abel's theorem and Jacobi inversion are the higher-genus continuation of the
39
+ elliptic-integral inversion story; Baker is retained in the bibliography as a
40
+ classical historical source.
41
+
42
+ Shakespeare reconstruction
43
+ ---------------------------
44
+ The package does not insert a ``Jacobian`` object merely because the curve has
45
+ genus ``g``. This module is enabled only after earlier executable layers have
46
+ produced:
47
+
48
+ 1. actual lifted histories;
49
+ 2. their period matrix;
50
+ 3. a sampled canonical symplectic intersection form; and
51
+ 4. the Riemann symmetry/positive-imaginary-part checks.
52
+
53
+ ``NormalizedAbelianTorus`` therefore accepts a *passing* ``SampledRiemannProfile``.
54
+ It is a numerical period-lattice presentation, not a claim that Shakespeare has
55
+ implemented divisor arithmetic or an algebraic Jacobian model.
56
+
57
+ ``AbelJacobiHistoryIncrement`` likewise represents the integral accumulated by
58
+ one lifted path. A genuine point-valued Abel--Jacobi map additionally requires
59
+ a chosen base point and a path from that base point. Keeping the object as a
60
+ history increment makes the dependence on path history explicit rather than
61
+ silently hiding it modulo periods.
62
+
63
+ Executable contract
64
+ -------------------
65
+ ``abel_jacobi_history_increment`` integrates the canonical differential basis
66
+ along a lifted path and normalizes by the measured A-period block. For the
67
+ cycle system that generated the period matrix:
68
+
69
+ A_j -> e_j,
70
+ B_j -> tau[:,j].
71
+
72
+ ``NormalizedAbelianTorus.lattice_shift(m,n)`` returns ``m + tau n`` for integer
73
+ vectors ``m,n``. ``matches_lattice_shift`` checks a *declared* lattice
74
+ relation; it deliberately does not solve the hard inverse problem of deciding
75
+ an arbitrary nearest/exact period relation.
76
+
77
+ Boundary
78
+ --------
79
+ All data inherit the numerical/sampling limitations of the current continuation,
80
+ intersection, and quadrature layers. The class is not a full Jacobian: it has
81
+ no divisor classes, theta functions, polarization machinery beyond the already
82
+ checked cycle pairing, algebraic group law, or Jacobi inversion solver. The
83
+ name ``NormalizedAbelianTorus`` is intentional. The classical identification
84
+ with the Jacobian is the shadow when the supplied Riemann-surface data are
85
+ mathematically valid.
86
+ """
87
+
88
+ from __future__ import annotations
89
+
90
+ from dataclasses import dataclass
91
+ from typing import Sequence
92
+
93
+ import sympy as sp
94
+
95
+ from .abelian import holomorphic_differential_basis
96
+ from .intersection import SampledRiemannProfile
97
+ from .period_matrix import AbelianPeriodMatrix
98
+ from .periods import LiftedSquareRootPath, integrate_lifted_differential
99
+
100
+ ComplexVector = tuple[complex, ...]
101
+
102
+
103
+ def _complex_matrix(rows: Sequence[Sequence[complex]]) -> sp.Matrix:
104
+ return sp.Matrix([[complex(value) for value in row] for row in rows])
105
+
106
+
107
+ def _complex_vector(values: Sequence[complex]) -> sp.Matrix:
108
+ return sp.Matrix([complex(value) for value in values])
109
+
110
+
111
+ def _as_complex_tuple(column: sp.Matrix) -> ComplexVector:
112
+ return tuple(complex(sp.N(column[index], 30)) for index in range(column.rows))
113
+
114
+
115
+ @dataclass(frozen=True)
116
+ class AbelJacobiHistoryIncrement:
117
+ """Raw and A-normalized Abelian-integral increment of one lifted history."""
118
+
119
+ periods: AbelianPeriodMatrix
120
+ path: LiftedSquareRootPath
121
+ raw: ComplexVector
122
+ normalized: ComplexVector
123
+
124
+ @property
125
+ def dimension(self) -> int:
126
+ return len(self.normalized)
127
+
128
+
129
+ @dataclass(frozen=True)
130
+ class NormalizedAbelianTorus:
131
+ """Numerical normalized lattice ``C^g / (Z^g + tau Z^g)``.
132
+
133
+ Construction is intentionally gated by a passing sampled Riemann profile so
134
+ callers cannot turn an arbitrary complex matrix into a Shakespeare
135
+ ``Jacobian-like`` representation without the currently available topology
136
+ and Riemann-shape evidence.
137
+ """
138
+
139
+ riemann: SampledRiemannProfile
140
+
141
+ def __post_init__(self) -> None:
142
+ if not self.riemann.passes:
143
+ raise ValueError("normalized Abelian torus requires a passing Riemann profile")
144
+
145
+ @property
146
+ def periods(self) -> AbelianPeriodMatrix:
147
+ return self.riemann.periods
148
+
149
+ @property
150
+ def dimension(self) -> int:
151
+ return self.periods.genus
152
+
153
+ @property
154
+ def tau(self) -> tuple[tuple[complex, ...], ...]:
155
+ return self.periods.tau
156
+
157
+ def a_shift(self, index: int) -> ComplexVector:
158
+ """Return the normalized lattice shift generated by A_index."""
159
+
160
+ if not 0 <= index < self.dimension:
161
+ raise IndexError("A-cycle index out of range")
162
+ return tuple(1.0 + 0j if row == index else 0j for row in range(self.dimension))
163
+
164
+ def b_shift(self, index: int) -> ComplexVector:
165
+ """Return the normalized lattice shift generated by B_index."""
166
+
167
+ if not 0 <= index < self.dimension:
168
+ raise IndexError("B-cycle index out of range")
169
+ return tuple(self.tau[row][index] for row in range(self.dimension))
170
+
171
+ def lattice_shift(
172
+ self,
173
+ a_coefficients: Sequence[int],
174
+ b_coefficients: Sequence[int],
175
+ ) -> ComplexVector:
176
+ """Return ``m + tau*n`` for integer coefficient vectors ``m,n``."""
177
+
178
+ if len(a_coefficients) != self.dimension or len(b_coefficients) != self.dimension:
179
+ raise ValueError("lattice coefficient vectors must have length g")
180
+ if any(not isinstance(value, int) for value in tuple(a_coefficients) + tuple(b_coefficients)):
181
+ raise TypeError("lattice coefficients must be integers")
182
+
183
+ return tuple(
184
+ complex(a_coefficients[row])
185
+ + sum(
186
+ self.tau[row][column] * b_coefficients[column]
187
+ for column in range(self.dimension)
188
+ )
189
+ for row in range(self.dimension)
190
+ )
191
+
192
+ def matches_lattice_shift(
193
+ self,
194
+ left: Sequence[complex],
195
+ right: Sequence[complex],
196
+ a_coefficients: Sequence[int],
197
+ b_coefficients: Sequence[int],
198
+ *,
199
+ tolerance: float = 1e-8,
200
+ ) -> bool:
201
+ """Check ``right-left = m+tau*n`` for caller-declared integer vectors."""
202
+
203
+ if tolerance <= 0:
204
+ raise ValueError("tolerance must be positive")
205
+ if len(left) != self.dimension or len(right) != self.dimension:
206
+ raise ValueError("torus coordinates must have length g")
207
+ shift = self.lattice_shift(a_coefficients, b_coefficients)
208
+ return max(
209
+ abs((complex(right[index]) - complex(left[index])) - shift[index])
210
+ for index in range(self.dimension)
211
+ ) <= tolerance
212
+
213
+
214
+ def normalized_abelian_torus(riemann: SampledRiemannProfile) -> NormalizedAbelianTorus:
215
+ """Construct the normalized period-lattice quotient from checked Riemann data."""
216
+
217
+ return NormalizedAbelianTorus(riemann=riemann)
218
+
219
+
220
+ def abel_jacobi_history_increment(
221
+ path: LiftedSquareRootPath,
222
+ periods: AbelianPeriodMatrix,
223
+ ) -> AbelJacobiHistoryIncrement:
224
+ """Integrate and A-normalize the canonical differential vector on ``path``."""
225
+
226
+ if path.curve != periods.cycles.curve:
227
+ raise ValueError("history path and period matrix must belong to the same curve")
228
+
229
+ differentials = holomorphic_differential_basis(path.curve)
230
+ raw = tuple(
231
+ integrate_lifted_differential(path, differential)
232
+ for differential in differentials
233
+ )
234
+
235
+ a_matrix = _complex_matrix(periods.a_periods)
236
+ if a_matrix.rows != len(raw) or a_matrix.cols != len(raw):
237
+ raise ValueError("A-period block and Abelian history dimension disagree")
238
+ normalized_column = a_matrix.inv() * _complex_vector(raw)
239
+ normalized = _as_complex_tuple(normalized_column)
240
+
241
+ return AbelJacobiHistoryIncrement(
242
+ periods=periods,
243
+ path=path,
244
+ raw=tuple(complex(value) for value in raw),
245
+ normalized=normalized,
246
+ )
@@ -0,0 +1,129 @@
1
+ """Abelian-integral structure emitted by a hyperelliptic process quotient.
2
+
3
+ Mathematical lineage
4
+ --------------------
5
+ Once an algebraic curve ``y^2 = P(x)`` has appeared, classical analysis does
6
+ not stop at its genus. One studies holomorphic differentials, integrates them
7
+ along paths, and compares the values after continuation around closed cycles.
8
+ For a genus-``g`` hyperelliptic curve a standard holomorphic basis is
9
+
10
+ dx/y, x dx/y, ..., x^(g-1) dx/y.
11
+
12
+ The first homology has rank ``2g``; integrating the ``g`` differentials over a
13
+ homology basis produces the period data behind the Jacobian. In genus one the
14
+ same construction gives the two-period lattice of elliptic-function theory.
15
+ See Forster, *Lectures on Riemann Surfaces*, and Farkas--Kra, *Riemann
16
+ Surfaces*. For an explicit hyperelliptic differential basis see also the
17
+ references collected in ``docs/REFERENCES.md``.
18
+
19
+ Shakespeare reconstruction
20
+ ---------------------------
21
+ The process-first order is deliberately the reverse of a named special-function
22
+ solver. A process first emits an algebraic quotient. This module then asks
23
+ which canonical differentials the quotient itself carries and how many global
24
+ cycle directions can contribute history residuals.
25
+
26
+ A ``HyperellipticDifferential`` is intentionally represented as a coefficient
27
+ of ``dx`` rather than as a SymPy differential object. This keeps the algebraic
28
+ backend simple while retaining the exact mathematical form ``x^k dx/y``. Its
29
+ ``pullback_coefficient`` method asks what the differential becomes along a
30
+ chosen process ``dx/dt``. For example, if a reduced process satisfies
31
+ ``dx/dt = y``, then ``dx/y`` pulls back to ``dt`` exactly.
32
+
33
+ Boundary
34
+ --------
35
+ This module does not choose homology cycles, analytically continue square-root
36
+ branches, compute period matrices, prove uniformization, or construct a
37
+ Jacobian as a complex torus. ``homology_rank = 2g`` is topological structure;
38
+ it is not a numerically computed period lattice. Concrete cycle integrals
39
+ belong in cited calibration tests until a genuinely reusable period engine is
40
+ forced by more than one example.
41
+ """
42
+
43
+ from __future__ import annotations
44
+
45
+ from dataclasses import dataclass
46
+
47
+ import sympy as sp
48
+
49
+ from .algebraic import HyperellipticProfile
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ class HyperellipticDifferential:
54
+ """One canonical differential ``x^power dx / y`` on a hyperelliptic curve."""
55
+
56
+ curve: HyperellipticProfile
57
+ power: int
58
+
59
+ def __post_init__(self) -> None:
60
+ if self.power < 0:
61
+ raise ValueError("differential power must be non-negative")
62
+
63
+ @property
64
+ def numerator(self) -> sp.Expr:
65
+ return self.curve.x ** self.power
66
+
67
+ @property
68
+ def coefficient(self) -> sp.Expr:
69
+ """Return the coefficient of ``dx`` in ``x^power dx/y``."""
70
+
71
+ return self.numerator / self.curve.y
72
+
73
+ def pullback_coefficient(self, dx_dt: sp.Expr) -> sp.Expr:
74
+ """Return the coefficient of ``dt`` after substituting ``dx=dx_dt*dt``."""
75
+
76
+ return sp.cancel(sp.sympify(dx_dt) * self.numerator / self.curve.y)
77
+
78
+
79
+ @dataclass(frozen=True)
80
+ class AbelianIntegralProfile:
81
+ """Canonical differential/homology profile of a generic smooth quotient.
82
+
83
+ ``abelian_dimension`` is the genus ``g`` and hence the number of independent
84
+ holomorphic differentials. ``homology_rank`` is ``2g``. These two numbers
85
+ are the dimensions that later enter the Abel--Jacobi/Jacobian construction;
86
+ no period values are claimed here.
87
+ """
88
+
89
+ curve: HyperellipticProfile
90
+ differentials: tuple[HyperellipticDifferential, ...]
91
+ abelian_dimension: int
92
+ homology_rank: int
93
+
94
+ def pullback_coefficients(self, dx_dt: sp.Expr) -> tuple[sp.Expr, ...]:
95
+ """Pull every canonical differential back along one reduced process."""
96
+
97
+ return tuple(
98
+ differential.pullback_coefficient(dx_dt)
99
+ for differential in self.differentials
100
+ )
101
+
102
+
103
+ def holomorphic_differential_basis(
104
+ curve: HyperellipticProfile,
105
+ ) -> tuple[HyperellipticDifferential, ...]:
106
+ """Return ``dx/y, x dx/y, ..., x^(g-1) dx/y`` for generic genus ``g``.
107
+
108
+ The routine requires the curve profile to have a generic smooth genus. For
109
+ genus zero the returned basis is empty.
110
+ """
111
+
112
+ genus = curve.generic_genus
113
+ if genus is None:
114
+ raise ValueError("holomorphic basis requires a generically smooth curve")
115
+ return tuple(HyperellipticDifferential(curve, power) for power in range(genus))
116
+
117
+
118
+ def abelian_integral_profile(curve: HyperellipticProfile) -> AbelianIntegralProfile:
119
+ """Attach canonical differential and first-homology dimensions to a curve."""
120
+
121
+ basis = holomorphic_differential_basis(curve)
122
+ genus = curve.generic_genus
123
+ assert genus is not None
124
+ return AbelianIntegralProfile(
125
+ curve=curve,
126
+ differentials=basis,
127
+ abelian_dimension=genus,
128
+ homology_rank=2 * genus,
129
+ )
@@ -0,0 +1,105 @@
1
+ """Algebraic-curve profiles for process quotients.
2
+
3
+ Mathematical lineage
4
+ --------------------
5
+ Elliptic and Abelian function theory historically did not begin as a catalogue
6
+ of special functions. Elliptic integrals led to inversion; inversion exposed
7
+ periods; periods produced complex tori; and the resulting function theory was
8
+ then algebraized by relations such as the Weierstrass cubic. Riemann surfaces,
9
+ algebraic curves, Abelian integrals, and Jacobians grew from this analytic and
10
+ geometric circle of ideas.
11
+
12
+ Shakespeare uses the same history in reverse as a calibration principle. A
13
+ primitive process may first force a constraint/invariant quotient. Only after
14
+ that quotient is visible do we ask what geometry and what function language are
15
+ adequate. Thus a relation ``y**2 = P(x)`` is not introduced because we already
16
+ know the answer is elliptic or hyperelliptic; it is an algebraic shadow emitted
17
+ by the process reduction.
18
+
19
+ Implementation
20
+ --------------
21
+ This module deliberately implements only a small, exact observable:
22
+ ``HyperellipticProfile`` records degree, discriminant, generic genus, and the
23
+ degeneration condition for ``y**2 = P(x)``. That is enough for classical tests
24
+ to distinguish genus-zero, genus-one, and higher-genus quotient regimes without
25
+ preloading the corresponding named function theory.
26
+
27
+ Boundary
28
+ --------
29
+ Genus is not a complete process normal form, and this module is not a general
30
+ algebraic-geometry engine. Period lattices, Abel-Jacobi maps, Jacobians, and
31
+ function-field compression belong to later layers and should be derived when a
32
+ calibration actually requires them.
33
+
34
+ See ``docs/08-function-theory-genus-hierarchy.md`` and
35
+ ``docs/09-literate-programming-and-mathematical-lineage.md``.
36
+ """
37
+
38
+ from __future__ import annotations
39
+
40
+ from dataclasses import dataclass
41
+
42
+ import sympy as sp
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class HyperellipticProfile:
47
+ """Exact profile of ``y**2 = polynomial(x)`` over symbolic parameters."""
48
+
49
+ x: sp.Symbol
50
+ y: sp.Symbol
51
+ polynomial: sp.Expr
52
+ degree: int
53
+ discriminant: sp.Expr
54
+ generic_genus: int | None
55
+
56
+ @property
57
+ def relation(self) -> sp.Expr:
58
+ return sp.expand(self.y**2 - self.polynomial)
59
+
60
+ @property
61
+ def generically_smooth(self) -> bool:
62
+ """Whether the discriminant is not identically zero."""
63
+
64
+ return sp.simplify(self.discriminant) != 0
65
+
66
+ @property
67
+ def degeneration_condition(self) -> sp.Expr:
68
+ """Parameter expression whose vanishing marks repeated branch points."""
69
+
70
+ return sp.factor(self.discriminant)
71
+
72
+
73
+ def hyperelliptic_profile(
74
+ x: sp.Symbol,
75
+ y: sp.Symbol,
76
+ polynomial: sp.Expr,
77
+ ) -> HyperellipticProfile:
78
+ """Analyze a process quotient in hyperelliptic form ``y**2 = P(x)``.
79
+
80
+ For square-free ``P`` of degree ``d >= 1``, the smooth projective
81
+ hyperelliptic curve has genus ``floor((d-1)/2)``. With symbolic parameters,
82
+ a nonzero discriminant means that this is the *generic* genus away from the
83
+ displayed degeneration locus.
84
+ """
85
+
86
+ polynomial = sp.expand(sp.sympify(polynomial))
87
+ try:
88
+ poly = sp.Poly(polynomial, x)
89
+ except sp.PolynomialError as exc:
90
+ raise ValueError("hyperelliptic polynomial must be polynomial in x") from exc
91
+
92
+ degree = int(poly.degree())
93
+ if degree < 1:
94
+ raise ValueError("hyperelliptic polynomial must have positive degree")
95
+ discriminant = sp.factor(sp.discriminant(poly.as_expr(), x))
96
+ generic_genus = (degree - 1) // 2 if discriminant != 0 else None
97
+
98
+ return HyperellipticProfile(
99
+ x=x,
100
+ y=y,
101
+ polynomial=polynomial,
102
+ degree=degree,
103
+ discriminant=discriminant,
104
+ generic_genus=generic_genus,
105
+ )