@aleph-ai/tinyaleph 1.5.7 → 1.6.1
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.
- package/core/alexander-module.js +1469 -0
- package/core/arithmetic-link-kernel.js +1338 -0
- package/core/emotion.js +565 -0
- package/core/gravity.js +714 -0
- package/core/hilbert.js +506 -3
- package/core/index.js +132 -4
- package/core/nonlocal.js +744 -0
- package/core/oracle.js +662 -0
- package/examples/01-hello-world.js +69 -0
- package/examples/02-basic-hash.js +90 -0
- package/examples/02-observer-stack.js +385 -0
- package/examples/03-quantum-coin.js +136 -0
- package/examples/05-symbolic-resonance.js +146 -0
- package/examples/06-symbol-database.js +150 -0
- package/examples/07-semantic-inference.js +223 -0
- package/examples/08-compound-symbols.js +219 -0
- package/examples/README.md +170 -0
- package/examples/ai/01-embeddings.js +155 -0
- package/examples/ai/02-semantic-memory.js +243 -0
- package/examples/ai/03-reasoning.js +243 -0
- package/examples/ai/04-knowledge-graph.js +279 -0
- package/examples/ai/05-llm-integration.js +333 -0
- package/examples/ai/06-agent.js +294 -0
- package/examples/ai/07-hybrid-ai.js +223 -0
- package/examples/ai/08-entropy-reasoning.js +259 -0
- package/examples/ai/09-concept-learning.js +271 -0
- package/examples/ai/10-prompt-primes.js +312 -0
- package/examples/ai/11-rag.js +332 -0
- package/examples/ai/12-neuro-symbolic.js +321 -0
- package/examples/ai/README.md +80 -0
- package/examples/arithmetic-topology/01-legendre-symbol.js +78 -0
- package/examples/arithmetic-topology/02-redei-symbol.js +126 -0
- package/examples/arithmetic-topology/03-alk-kuramoto.js +138 -0
- package/examples/arithmetic-topology/04-alexander-module.js +117 -0
- package/examples/arithmetic-topology/05-signature-memory.js +118 -0
- package/examples/arithmetic-topology/README.md +291 -0
- package/examples/bioinformatics/01-dna-encoding.js +108 -0
- package/examples/bioinformatics/02-central-dogma.js +162 -0
- package/examples/bioinformatics/03-protein-folding.js +206 -0
- package/examples/bioinformatics/04-dna-computing.js +192 -0
- package/examples/bioinformatics/05-molecular-binding.js +209 -0
- package/examples/book-operators-demo.js +155 -0
- package/examples/chat.js +105 -0
- package/examples/crt-homology/01-residue-encoding.js +87 -0
- package/examples/crt-homology/02-birkhoff-attention.js +100 -0
- package/examples/crt-homology/03-homology-loss.js +132 -0
- package/examples/crt-homology/04-crt-resoformer.js +132 -0
- package/examples/crt-homology/README.md +67 -0
- package/examples/crypto/01-password-hash.js +210 -0
- package/examples/crypto/02-key-derivation.js +210 -0
- package/examples/crypto/03-hmac.js +229 -0
- package/examples/crypto/04-file-integrity.js +263 -0
- package/examples/crypto/05-content-hash.js +263 -0
- package/examples/crypto/README.md +99 -0
- package/examples/demo-modular.js +223 -0
- package/examples/demo-two-layer.js +196 -0
- package/examples/discrete/01-integer-sine-table.js +120 -0
- package/examples/discrete/02-codebook-tunneling.js +118 -0
- package/examples/discrete/03-canonical-fusion.js +135 -0
- package/examples/discrete/04-tick-gate.js +139 -0
- package/examples/discrete/README.md +142 -0
- package/examples/emotion-demo.js +200 -0
- package/examples/formal-semantics/01-typed-terms.js +156 -0
- package/examples/formal-semantics/02-reduction.js +202 -0
- package/examples/formal-semantics/03-lambda-translation.js +206 -0
- package/examples/formal-semantics/04-enochian-language.js +257 -0
- package/examples/formal-semantics/README.md +98 -0
- package/examples/gravity-demo.js +190 -0
- package/examples/math/01-quaternions.js +237 -0
- package/examples/math/02-octonions.js +192 -0
- package/examples/math/03-prime-factorization.js +215 -0
- package/examples/math/04-vector-spaces.js +210 -0
- package/examples/math/05-gaussian-primes.js +234 -0
- package/examples/math/README.md +93 -0
- package/examples/nonlocal-demo.js +237 -0
- package/examples/oracle-demo.js +204 -0
- package/examples/physics/01-oscillator.js +177 -0
- package/examples/physics/02-lyapunov.js +201 -0
- package/examples/physics/03-collapse.js +183 -0
- package/examples/physics/04-kuramoto.js +212 -0
- package/examples/physics/05-entropy.js +226 -0
- package/examples/physics/05-sync-models.js +298 -0
- package/examples/physics/06-primeon-ladder.js +233 -0
- package/examples/physics/07-kuramoto-coupled-ladder.js +298 -0
- package/examples/physics/README.md +126 -0
- package/examples/quantum/01-prime-hunter.js +79 -0
- package/examples/quantum/02-entanglement-demo.js +79 -0
- package/examples/quantum/03-wave-analysis.js +63 -0
- package/examples/resonance/01-prime-hilbert-space.js +140 -0
- package/examples/resonance/02-prime-resonance-network.js +221 -0
- package/examples/resonance/03-resoformer.js +349 -0
- package/examples/resonance/04-resoformer-training.js +329 -0
- package/examples/resonance/05-language-model.js +484 -0
- package/examples/resonance/README.md +238 -0
- package/examples/run-examples.js +427 -0
- package/examples/scientific/01-single-qubit.js +185 -0
- package/examples/scientific/02-two-qubit.js +209 -0
- package/examples/scientific/03-quantum-circuits.js +270 -0
- package/examples/scientific/04-measurement.js +229 -0
- package/examples/scientific/05-algorithms.js +245 -0
- package/examples/scientific/06-random.js +225 -0
- package/examples/scientific/07-wavefunction.js +192 -0
- package/examples/scientific/README.md +118 -0
- package/examples/semantic/01-vocabulary.js +186 -0
- package/examples/semantic/02-similarity.js +263 -0
- package/examples/semantic/03-word-algebra.js +295 -0
- package/examples/semantic/04-clustering.js +348 -0
- package/examples/semantic/05-classification.js +386 -0
- package/examples/semantic/06-dna-encoding.js +228 -0
- package/examples/semantic/07-search.js +304 -0
- package/examples/semantic/08-qa-system.js +278 -0
- package/examples/semantic/README.md +116 -0
- package/examples/topology/01-108-invariant.js +81 -0
- package/examples/topology/02-trefoil-constants.js +112 -0
- package/examples/topology/03-gauge-symmetry.js +112 -0
- package/examples/topology/04-free-energy-dynamics.js +124 -0
- package/examples/topology/README.md +129 -0
- package/index.js +32 -0
- package/modular.js +63 -2
- package/package.json +8 -3
- package/physics/alk-kuramoto.js +817 -0
- package/physics/index.js +23 -2
|
@@ -0,0 +1,1469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete Alexander Modules for Prime Sets
|
|
3
|
+
*
|
|
4
|
+
* Implements module-theoretic signature extraction based on:
|
|
5
|
+
* "Complete Alexander Modules for Prime Sets: Crowell Exact Sequences,
|
|
6
|
+
* Iwasawa Modules, and Resonance-Signature Extraction"
|
|
7
|
+
*
|
|
8
|
+
* Key concepts:
|
|
9
|
+
* - ψ-Differential modules A_ψ: Universal differentials satisfying
|
|
10
|
+
* d(g₁g₂) = d(g₁) + ψ(g₁)d(g₂)
|
|
11
|
+
* - Crowell exact sequence: 0 → N^ab → A_ψ → I_{Z[H]} → 0
|
|
12
|
+
* - Fitting ideals E_d(A_ψ): Characteristic invariants
|
|
13
|
+
* - Module signature Σ_{k,S,ℓ,ψ}: Stable memory object for prime sets
|
|
14
|
+
*
|
|
15
|
+
* @module core/alexander-module
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
import { isPrime, firstNPrimes, factorize } from './prime.js';
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// POLYNOMIAL AND IDEAL UTILITIES
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Laurent Polynomial Class
|
|
28
|
+
*
|
|
29
|
+
* Polynomials in Z[t, t⁻¹] (the group ring Z[Z])
|
|
30
|
+
* Used for Alexander polynomial representation.
|
|
31
|
+
*/
|
|
32
|
+
class LaurentPolynomial {
|
|
33
|
+
/**
|
|
34
|
+
* Create a Laurent polynomial
|
|
35
|
+
*
|
|
36
|
+
* @param {Object|Map|Array} coeffs - Coefficients indexed by power
|
|
37
|
+
* Object: { power: coeff } e.g., { 0: 1, 1: -1, 2: 1 } = 1 - t + t²
|
|
38
|
+
* Array: [a₀, a₁, a₂, ...] for non-negative powers
|
|
39
|
+
*/
|
|
40
|
+
constructor(coeffs = {}) {
|
|
41
|
+
this.coeffs = new Map();
|
|
42
|
+
|
|
43
|
+
if (Array.isArray(coeffs)) {
|
|
44
|
+
coeffs.forEach((c, i) => {
|
|
45
|
+
if (c !== 0) this.coeffs.set(i, c);
|
|
46
|
+
});
|
|
47
|
+
} else if (coeffs instanceof Map) {
|
|
48
|
+
for (const [k, v] of coeffs) {
|
|
49
|
+
if (v !== 0) this.coeffs.set(k, v);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
for (const [k, v] of Object.entries(coeffs)) {
|
|
53
|
+
if (v !== 0) this.coeffs.set(parseInt(k), v);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get coefficient at power n
|
|
60
|
+
*/
|
|
61
|
+
get(n) {
|
|
62
|
+
return this.coeffs.get(n) || 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Set coefficient at power n
|
|
67
|
+
*/
|
|
68
|
+
set(n, value) {
|
|
69
|
+
if (value === 0) {
|
|
70
|
+
this.coeffs.delete(n);
|
|
71
|
+
} else {
|
|
72
|
+
this.coeffs.set(n, value);
|
|
73
|
+
}
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get minimum power with non-zero coefficient
|
|
79
|
+
*/
|
|
80
|
+
get minPower() {
|
|
81
|
+
if (this.coeffs.size === 0) return 0;
|
|
82
|
+
return Math.min(...this.coeffs.keys());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get maximum power with non-zero coefficient
|
|
87
|
+
*/
|
|
88
|
+
get maxPower() {
|
|
89
|
+
if (this.coeffs.size === 0) return 0;
|
|
90
|
+
return Math.max(...this.coeffs.keys());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get degree (maxPower - minPower)
|
|
95
|
+
*/
|
|
96
|
+
get degree() {
|
|
97
|
+
return this.maxPower - this.minPower;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if polynomial is zero
|
|
102
|
+
*/
|
|
103
|
+
get isZero() {
|
|
104
|
+
return this.coeffs.size === 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Add two Laurent polynomials
|
|
109
|
+
*/
|
|
110
|
+
add(other) {
|
|
111
|
+
const result = new LaurentPolynomial(this.coeffs);
|
|
112
|
+
for (const [k, v] of other.coeffs) {
|
|
113
|
+
result.set(k, result.get(k) + v);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Subtract
|
|
120
|
+
*/
|
|
121
|
+
subtract(other) {
|
|
122
|
+
const result = new LaurentPolynomial(this.coeffs);
|
|
123
|
+
for (const [k, v] of other.coeffs) {
|
|
124
|
+
result.set(k, result.get(k) - v);
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Multiply two Laurent polynomials
|
|
131
|
+
*/
|
|
132
|
+
multiply(other) {
|
|
133
|
+
const result = new LaurentPolynomial();
|
|
134
|
+
for (const [k1, v1] of this.coeffs) {
|
|
135
|
+
for (const [k2, v2] of other.coeffs) {
|
|
136
|
+
result.set(k1 + k2, result.get(k1 + k2) + v1 * v2);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Scalar multiplication
|
|
144
|
+
*/
|
|
145
|
+
scale(scalar) {
|
|
146
|
+
const result = new LaurentPolynomial();
|
|
147
|
+
for (const [k, v] of this.coeffs) {
|
|
148
|
+
result.set(k, scalar * v);
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Evaluate at t = value
|
|
155
|
+
*/
|
|
156
|
+
evaluate(value) {
|
|
157
|
+
let result = 0;
|
|
158
|
+
for (const [k, v] of this.coeffs) {
|
|
159
|
+
result += v * Math.pow(value, k);
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Evaluate at t = e^(iθ) on unit circle
|
|
166
|
+
*/
|
|
167
|
+
evaluateOnCircle(theta) {
|
|
168
|
+
let re = 0, im = 0;
|
|
169
|
+
for (const [k, v] of this.coeffs) {
|
|
170
|
+
re += v * Math.cos(k * theta);
|
|
171
|
+
im += v * Math.sin(k * theta);
|
|
172
|
+
}
|
|
173
|
+
return { re, im, abs: Math.sqrt(re * re + im * im) };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Normalize: divide by leading coefficient and shift to min power 0
|
|
178
|
+
*/
|
|
179
|
+
normalize() {
|
|
180
|
+
if (this.isZero) return new LaurentPolynomial();
|
|
181
|
+
|
|
182
|
+
const shift = this.minPower;
|
|
183
|
+
const lead = this.get(this.maxPower);
|
|
184
|
+
const result = new LaurentPolynomial();
|
|
185
|
+
|
|
186
|
+
for (const [k, v] of this.coeffs) {
|
|
187
|
+
result.set(k - shift, v / lead);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Clone
|
|
195
|
+
*/
|
|
196
|
+
clone() {
|
|
197
|
+
return new LaurentPolynomial(this.coeffs);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* String representation
|
|
202
|
+
*/
|
|
203
|
+
toString() {
|
|
204
|
+
if (this.isZero) return '0';
|
|
205
|
+
|
|
206
|
+
const powers = [...this.coeffs.keys()].sort((a, b) => a - b);
|
|
207
|
+
const terms = [];
|
|
208
|
+
|
|
209
|
+
for (const k of powers) {
|
|
210
|
+
const c = this.coeffs.get(k);
|
|
211
|
+
if (c === 0) continue;
|
|
212
|
+
|
|
213
|
+
let term = '';
|
|
214
|
+
if (k === 0) {
|
|
215
|
+
term = c.toString();
|
|
216
|
+
} else if (k === 1) {
|
|
217
|
+
term = c === 1 ? 't' : c === -1 ? '-t' : `${c}t`;
|
|
218
|
+
} else if (k < 0) {
|
|
219
|
+
term = c === 1 ? `t^(${k})` : c === -1 ? `-t^(${k})` : `${c}t^(${k})`;
|
|
220
|
+
} else {
|
|
221
|
+
term = c === 1 ? `t^${k}` : c === -1 ? `-t^${k}` : `${c}t^${k}`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
terms.push(term);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return terms.join(' + ').replace(/\+ -/g, '- ');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create from array of roots (as Laurent poly (t - r₁)(t - r₂)...)
|
|
232
|
+
*/
|
|
233
|
+
static fromRoots(roots) {
|
|
234
|
+
let result = new LaurentPolynomial({ 0: 1 });
|
|
235
|
+
for (const r of roots) {
|
|
236
|
+
const factor = new LaurentPolynomial({ 0: -r, 1: 1 }); // (t - r)
|
|
237
|
+
result = result.multiply(factor);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Create the augmentation ideal generator (t - 1)
|
|
244
|
+
*/
|
|
245
|
+
static augmentationGenerator() {
|
|
246
|
+
return new LaurentPolynomial({ 0: -1, 1: 1 }); // t - 1
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// FITTING IDEAL CLASS
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Fitting Ideal Class
|
|
256
|
+
*
|
|
257
|
+
* The d-th Fitting ideal E_d(M) of a finitely presented module M
|
|
258
|
+
* is generated by (n-d) × (n-d) minors of a presentation matrix,
|
|
259
|
+
* where n is the number of generators.
|
|
260
|
+
*
|
|
261
|
+
* For Alexander modules, the 0-th Fitting ideal gives the
|
|
262
|
+
* Alexander polynomial (up to units).
|
|
263
|
+
*/
|
|
264
|
+
class FittingIdeal {
|
|
265
|
+
/**
|
|
266
|
+
* Create a Fitting ideal
|
|
267
|
+
*
|
|
268
|
+
* @param {number} degree - The degree d of E_d
|
|
269
|
+
* @param {LaurentPolynomial[]} generators - Generators of the ideal
|
|
270
|
+
*/
|
|
271
|
+
constructor(degree, generators = []) {
|
|
272
|
+
this.degree = degree;
|
|
273
|
+
this.generators = generators;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Check if ideal is trivial (equals entire ring)
|
|
278
|
+
*/
|
|
279
|
+
get isTrivial() {
|
|
280
|
+
return this.generators.some(g => {
|
|
281
|
+
// Ideal is trivial if some generator is a unit
|
|
282
|
+
return g.coeffs.size === 1 && Math.abs([...g.coeffs.values()][0]) === 1;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Check if ideal is zero
|
|
288
|
+
*/
|
|
289
|
+
get isZero() {
|
|
290
|
+
return this.generators.length === 0 ||
|
|
291
|
+
this.generators.every(g => g.isZero);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get primary generator (gcd of all generators)
|
|
296
|
+
* For principal ideals, this is unique up to units.
|
|
297
|
+
*/
|
|
298
|
+
get primaryGenerator() {
|
|
299
|
+
if (this.generators.length === 0) {
|
|
300
|
+
return new LaurentPolynomial();
|
|
301
|
+
}
|
|
302
|
+
if (this.generators.length === 1) {
|
|
303
|
+
return this.generators[0];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// For Laurent polynomials over Z, computing true gcd is complex.
|
|
307
|
+
// We return the first non-zero generator as approximation.
|
|
308
|
+
for (const g of this.generators) {
|
|
309
|
+
if (!g.isZero) return g;
|
|
310
|
+
}
|
|
311
|
+
return new LaurentPolynomial();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Compute characteristic polynomial Δ_d
|
|
316
|
+
* This is the generator of E_d when it's principal.
|
|
317
|
+
*/
|
|
318
|
+
get characteristicPolynomial() {
|
|
319
|
+
return this.primaryGenerator.normalize();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Evaluate ideal generators on unit circle
|
|
324
|
+
* Returns minimum absolute value (distance to zero locus).
|
|
325
|
+
*/
|
|
326
|
+
evaluateOnCircle(theta) {
|
|
327
|
+
const values = this.generators.map(g => g.evaluateOnCircle(theta));
|
|
328
|
+
const minAbs = Math.min(...values.map(v => v.abs));
|
|
329
|
+
return {
|
|
330
|
+
values,
|
|
331
|
+
minAbs,
|
|
332
|
+
theta
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Find zeros on unit circle (where |generator| is minimized)
|
|
338
|
+
*
|
|
339
|
+
* @param {number} samples - Number of sample points
|
|
340
|
+
* @returns {number[]} Angles where ideal vanishes approximately
|
|
341
|
+
*/
|
|
342
|
+
findCircleZeros(samples = 360) {
|
|
343
|
+
const zeros = [];
|
|
344
|
+
const threshold = 0.1;
|
|
345
|
+
|
|
346
|
+
for (let i = 0; i < samples; i++) {
|
|
347
|
+
const theta = (2 * Math.PI * i) / samples;
|
|
348
|
+
const { minAbs } = this.evaluateOnCircle(theta);
|
|
349
|
+
if (minAbs < threshold) {
|
|
350
|
+
zeros.push(theta);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return zeros;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Compute signature hash for content-addressable memory
|
|
359
|
+
*/
|
|
360
|
+
get signatureHash() {
|
|
361
|
+
const gen = this.characteristicPolynomial;
|
|
362
|
+
const coeffArray = [];
|
|
363
|
+
|
|
364
|
+
for (let k = gen.minPower; k <= gen.maxPower; k++) {
|
|
365
|
+
coeffArray.push(gen.get(k));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Simple hash: combine coefficients
|
|
369
|
+
let hash = 0;
|
|
370
|
+
for (let i = 0; i < coeffArray.length; i++) {
|
|
371
|
+
hash = ((hash << 5) - hash + coeffArray[i]) | 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return hash;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ============================================================================
|
|
379
|
+
// CROWELL EXACT SEQUENCE
|
|
380
|
+
// ============================================================================
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Crowell Exact Sequence Class
|
|
384
|
+
*
|
|
385
|
+
* Represents the exact sequence of Z[H]-modules:
|
|
386
|
+
* 0 → N^ab → A_ψ → I_{Z[H]} → 0
|
|
387
|
+
*
|
|
388
|
+
* Extended form:
|
|
389
|
+
* 0 → N^ab → A_ψ → Z[H] → Z → 0
|
|
390
|
+
*
|
|
391
|
+
* For prime sets, this connects:
|
|
392
|
+
* - N^ab: ψ-Galois module (Iwasawa module in cyclotomic case)
|
|
393
|
+
* - A_ψ: Complete Alexander module
|
|
394
|
+
* - I_{Z[H]}: Augmentation ideal
|
|
395
|
+
*/
|
|
396
|
+
class CrowellSequence {
|
|
397
|
+
/**
|
|
398
|
+
* Create a Crowell exact sequence
|
|
399
|
+
*
|
|
400
|
+
* @param {Object} groupData - Group-theoretic data
|
|
401
|
+
* @param {Object} groupData.G - The group G (presentation)
|
|
402
|
+
* @param {Object} groupData.H - The abelian quotient H
|
|
403
|
+
* @param {Object} groupData.N - The kernel N = ker(ψ)
|
|
404
|
+
*/
|
|
405
|
+
constructor(groupData) {
|
|
406
|
+
this.G = groupData.G;
|
|
407
|
+
this.H = groupData.H;
|
|
408
|
+
this.N = groupData.N;
|
|
409
|
+
|
|
410
|
+
this._Nab = null; // N^ab: ψ-Galois module
|
|
411
|
+
this._Apsi = null; // A_ψ: Alexander module
|
|
412
|
+
this._augIdeal = null; // I_{Z[H]}: Augmentation ideal
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get the ψ-Galois module N^ab
|
|
417
|
+
*/
|
|
418
|
+
get NabelianModule() {
|
|
419
|
+
if (!this._Nab) {
|
|
420
|
+
this._Nab = this._computeNab();
|
|
421
|
+
}
|
|
422
|
+
return this._Nab;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Get the Alexander module A_ψ
|
|
427
|
+
*/
|
|
428
|
+
get alexanderModule() {
|
|
429
|
+
if (!this._Apsi) {
|
|
430
|
+
this._Apsi = this._computeApsi();
|
|
431
|
+
}
|
|
432
|
+
return this._Apsi;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get augmentation ideal I_{Z[H]}
|
|
437
|
+
*/
|
|
438
|
+
get augmentationIdeal() {
|
|
439
|
+
if (!this._augIdeal) {
|
|
440
|
+
// For H = Z, the augmentation ideal is principal, generated by (t - 1)
|
|
441
|
+
this._augIdeal = new FittingIdeal(0, [
|
|
442
|
+
LaurentPolynomial.augmentationGenerator()
|
|
443
|
+
]);
|
|
444
|
+
}
|
|
445
|
+
return this._augIdeal;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Compute N^ab (abelianization of kernel)
|
|
450
|
+
* @private
|
|
451
|
+
*/
|
|
452
|
+
_computeNab() {
|
|
453
|
+
// For prime sets, N^ab is computed from the restricted ramification structure
|
|
454
|
+
// This is a simplified representation
|
|
455
|
+
return {
|
|
456
|
+
generators: this.N.generators || [],
|
|
457
|
+
relations: this.N.relations || [],
|
|
458
|
+
rank: this.N.rank || 0
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Compute A_ψ (Alexander module)
|
|
464
|
+
* @private
|
|
465
|
+
*/
|
|
466
|
+
_computeApsi() {
|
|
467
|
+
// The Alexander module is computed from the Fox derivatives
|
|
468
|
+
// of the group presentation
|
|
469
|
+
return {
|
|
470
|
+
presentationMatrix: this._computePresentationMatrix(),
|
|
471
|
+
rank: this.G.relations?.length || 0
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Compute presentation matrix (Fox derivative matrix)
|
|
477
|
+
* @private
|
|
478
|
+
*/
|
|
479
|
+
_computePresentationMatrix() {
|
|
480
|
+
// Fox derivative matrix: ∂r_i/∂x_j for relations r_i, generators x_j
|
|
481
|
+
// This is a matrix of Laurent polynomials
|
|
482
|
+
const numRelations = this.G.relations?.length || 0;
|
|
483
|
+
const numGenerators = this.G.generators?.length || 0;
|
|
484
|
+
|
|
485
|
+
const matrix = [];
|
|
486
|
+
for (let i = 0; i < numRelations; i++) {
|
|
487
|
+
const row = [];
|
|
488
|
+
for (let j = 0; j < numGenerators; j++) {
|
|
489
|
+
// Simplified: placeholder for actual Fox derivative
|
|
490
|
+
row.push(new LaurentPolynomial({ 0: 1 }));
|
|
491
|
+
}
|
|
492
|
+
matrix.push(row);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return matrix;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Check exactness at each position
|
|
500
|
+
*/
|
|
501
|
+
verifyExactness() {
|
|
502
|
+
// In a proper implementation, this would verify:
|
|
503
|
+
// 1. θ₁: N^ab → A_ψ is injective
|
|
504
|
+
// 2. im(θ₁) = ker(θ₂)
|
|
505
|
+
// 3. θ₂: A_ψ → I_{Z[H]} is surjective
|
|
506
|
+
return {
|
|
507
|
+
injectiveAtNab: true,
|
|
508
|
+
exactAtApsi: true,
|
|
509
|
+
surjectiveOntoAugIdeal: true
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Get splitting isomorphism (Morishita's result)
|
|
515
|
+
* A_ψ ≅ N^ab ⊕ Λ̂ where Λ̂ = Z_ℓ[[H]]
|
|
516
|
+
*/
|
|
517
|
+
getSplitting() {
|
|
518
|
+
return {
|
|
519
|
+
directSum: true,
|
|
520
|
+
components: ['N^ab', 'Λ̂'],
|
|
521
|
+
fittingShift: 1 // E_d(N^ab) = E_{d+1}(A_ψ)
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// ============================================================================
|
|
527
|
+
// ALEXANDER MODULE CLASS
|
|
528
|
+
// ============================================================================
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Complete Alexander Module
|
|
532
|
+
*
|
|
533
|
+
* The ψ-differential module A_ψ for a prime set S.
|
|
534
|
+
* Provides the module-theoretic invariant layer above coupling tensors.
|
|
535
|
+
*/
|
|
536
|
+
class AlexanderModule {
|
|
537
|
+
/**
|
|
538
|
+
* Create an Alexander module for a prime set
|
|
539
|
+
*
|
|
540
|
+
* @param {number[]} primes - The prime set S
|
|
541
|
+
* @param {Object} options - Configuration
|
|
542
|
+
* @param {number} options.ell - Base prime ℓ (default: 2)
|
|
543
|
+
* @param {string} options.field - Base field k (default: 'Q')
|
|
544
|
+
*/
|
|
545
|
+
constructor(primes, options = {}) {
|
|
546
|
+
this.primes = primes.filter(p => isPrime(p)).sort((a, b) => a - b);
|
|
547
|
+
this.r = this.primes.length;
|
|
548
|
+
|
|
549
|
+
if (this.r < 1) {
|
|
550
|
+
throw new Error('AlexanderModule requires at least 1 prime');
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
this.ell = options.ell || 2;
|
|
554
|
+
this.field = options.field || 'Q';
|
|
555
|
+
|
|
556
|
+
// Compute group-theoretic data
|
|
557
|
+
this._groupData = this._buildGroupData();
|
|
558
|
+
this._crowellSequence = null;
|
|
559
|
+
this._fittingIdeals = new Map();
|
|
560
|
+
this._signature = null;
|
|
561
|
+
|
|
562
|
+
this.metadata = {
|
|
563
|
+
created: Date.now(),
|
|
564
|
+
primeProduct: this.primes.reduce((a, b) => a * b, 1),
|
|
565
|
+
primeSum: this.primes.reduce((a, b) => a + b, 0)
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Build group-theoretic data from prime set
|
|
571
|
+
*
|
|
572
|
+
* The restricted-ramification Galois group G_S(k) = π₁(Spec(O_k) \ S)
|
|
573
|
+
* @private
|
|
574
|
+
*/
|
|
575
|
+
_buildGroupData() {
|
|
576
|
+
// For the prime set S = {p₁, ..., p_r}, we build:
|
|
577
|
+
// - G: restricted-ramification group (simplified presentation)
|
|
578
|
+
// - H: maximal abelian quotient
|
|
579
|
+
// - N: kernel of ψ: G → H
|
|
580
|
+
|
|
581
|
+
const generators = this.primes.map((p, i) => ({
|
|
582
|
+
index: i,
|
|
583
|
+
prime: p,
|
|
584
|
+
symbol: `σ_${p}`
|
|
585
|
+
}));
|
|
586
|
+
|
|
587
|
+
// Relations encode ramification structure
|
|
588
|
+
// For simplicity, we use trivial relations here
|
|
589
|
+
const relations = [];
|
|
590
|
+
|
|
591
|
+
// The abelianization H is free abelian of rank r
|
|
592
|
+
const H = {
|
|
593
|
+
rank: this.r,
|
|
594
|
+
generators: generators.slice(),
|
|
595
|
+
isAbelian: true
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
// For abelianization, N = [G, G] (commutator subgroup)
|
|
599
|
+
const N = {
|
|
600
|
+
generators: [], // Computed from commutators
|
|
601
|
+
relations: [],
|
|
602
|
+
rank: 0 // Depends on class field theory
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
return {
|
|
606
|
+
G: { generators, relations },
|
|
607
|
+
H,
|
|
608
|
+
N,
|
|
609
|
+
abelianization: H
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Get the Crowell exact sequence
|
|
615
|
+
*/
|
|
616
|
+
get crowellSequence() {
|
|
617
|
+
if (!this._crowellSequence) {
|
|
618
|
+
this._crowellSequence = new CrowellSequence(this._groupData);
|
|
619
|
+
}
|
|
620
|
+
return this._crowellSequence;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Compute d-th Fitting ideal E_d(A_ψ)
|
|
625
|
+
*
|
|
626
|
+
* @param {number} d - Degree of Fitting ideal
|
|
627
|
+
* @returns {FittingIdeal} The ideal E_d
|
|
628
|
+
*/
|
|
629
|
+
computeFittingIdeal(d) {
|
|
630
|
+
if (this._fittingIdeals.has(d)) {
|
|
631
|
+
return this._fittingIdeals.get(d);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const ideal = this._computeFitting(d);
|
|
635
|
+
this._fittingIdeals.set(d, ideal);
|
|
636
|
+
return ideal;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Compute Fitting ideal from presentation matrix
|
|
641
|
+
* @private
|
|
642
|
+
*/
|
|
643
|
+
_computeFitting(d) {
|
|
644
|
+
// The d-th Fitting ideal is generated by (n-d) × (n-d) minors
|
|
645
|
+
// of the presentation matrix, where n = number of generators
|
|
646
|
+
|
|
647
|
+
const n = this.r;
|
|
648
|
+
|
|
649
|
+
if (d >= n) {
|
|
650
|
+
// E_d = entire ring for d ≥ n
|
|
651
|
+
return new FittingIdeal(d, [new LaurentPolynomial({ 0: 1 })]);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (d === 0) {
|
|
655
|
+
// E_0 is the principal ideal generated by the Alexander polynomial
|
|
656
|
+
const alexPoly = this._computeAlexanderPolynomial();
|
|
657
|
+
return new FittingIdeal(0, [alexPoly]);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// For intermediate d, compute minors
|
|
661
|
+
// This is a simplified version
|
|
662
|
+
const minorSize = n - d;
|
|
663
|
+
const generators = this._computeMinors(minorSize);
|
|
664
|
+
return new FittingIdeal(d, generators);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Compute Alexander polynomial
|
|
669
|
+
*
|
|
670
|
+
* For a prime set, this is related to the characteristic polynomial
|
|
671
|
+
* of the Iwasawa module when interpreted via class field theory.
|
|
672
|
+
* @private
|
|
673
|
+
*/
|
|
674
|
+
_computeAlexanderPolynomial() {
|
|
675
|
+
// For a single prime p, the Alexander polynomial is trivial: 1
|
|
676
|
+
// For multiple primes, it encodes the ramification structure
|
|
677
|
+
|
|
678
|
+
if (this.r === 1) {
|
|
679
|
+
return new LaurentPolynomial({ 0: 1 });
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Construct polynomial from prime signatures
|
|
683
|
+
// This is a simplified heuristic based on prime residue classes
|
|
684
|
+
const coeffs = {};
|
|
685
|
+
|
|
686
|
+
// The polynomial structure depends on the Galois group
|
|
687
|
+
// Use prime-derived coefficients as approximation
|
|
688
|
+
for (let i = 0; i <= this.r; i++) {
|
|
689
|
+
const coeff = this._computeAlexanderCoeff(i);
|
|
690
|
+
if (coeff !== 0) {
|
|
691
|
+
coeffs[i] = coeff;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Ensure symmetric (palindromic) structure
|
|
696
|
+
// Alexander polynomials satisfy Δ(t⁻¹) = t^(-deg) Δ(t) up to sign
|
|
697
|
+
const poly = new LaurentPolynomial(coeffs);
|
|
698
|
+
return this._symmetrize(poly);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Compute Alexander polynomial coefficient
|
|
703
|
+
* @private
|
|
704
|
+
*/
|
|
705
|
+
_computeAlexanderCoeff(i) {
|
|
706
|
+
if (i === 0) return 1;
|
|
707
|
+
if (i === this.r) return 1;
|
|
708
|
+
|
|
709
|
+
// Use prime residue structure
|
|
710
|
+
let coeff = 0;
|
|
711
|
+
const combos = this._combinations(this.primes, i);
|
|
712
|
+
|
|
713
|
+
for (const combo of combos) {
|
|
714
|
+
const prod = combo.reduce((a, b) => a * b, 1);
|
|
715
|
+
const sign = this._computeSign(combo);
|
|
716
|
+
coeff += sign;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return coeff;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Compute sign from prime combo
|
|
724
|
+
* @private
|
|
725
|
+
*/
|
|
726
|
+
_computeSign(primes) {
|
|
727
|
+
// Based on Legendre symbol structure
|
|
728
|
+
let sign = 1;
|
|
729
|
+
for (let i = 0; i < primes.length; i++) {
|
|
730
|
+
for (let j = i + 1; j < primes.length; j++) {
|
|
731
|
+
const leg = this._legendreSymbol(primes[i], primes[j]);
|
|
732
|
+
sign *= leg;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return sign;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Simple Legendre symbol computation
|
|
740
|
+
* @private
|
|
741
|
+
*/
|
|
742
|
+
_legendreSymbol(a, p) {
|
|
743
|
+
if (p === 2 || !isPrime(p)) return 0;
|
|
744
|
+
a = ((a % p) + p) % p;
|
|
745
|
+
if (a === 0) return 0;
|
|
746
|
+
|
|
747
|
+
// Euler's criterion
|
|
748
|
+
let result = 1;
|
|
749
|
+
let exp = (p - 1) / 2;
|
|
750
|
+
let base = a;
|
|
751
|
+
|
|
752
|
+
while (exp > 0) {
|
|
753
|
+
if (exp % 2 === 1) {
|
|
754
|
+
result = (result * base) % p;
|
|
755
|
+
}
|
|
756
|
+
base = (base * base) % p;
|
|
757
|
+
exp = Math.floor(exp / 2);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
return result === 1 ? 1 : -1;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Make polynomial symmetric/palindromic
|
|
765
|
+
* @private
|
|
766
|
+
*/
|
|
767
|
+
_symmetrize(poly) {
|
|
768
|
+
if (poly.isZero) return poly;
|
|
769
|
+
|
|
770
|
+
const min = poly.minPower;
|
|
771
|
+
const max = poly.maxPower;
|
|
772
|
+
const result = new LaurentPolynomial();
|
|
773
|
+
|
|
774
|
+
for (let k = min; k <= max; k++) {
|
|
775
|
+
const c1 = poly.get(k);
|
|
776
|
+
const c2 = poly.get(max + min - k);
|
|
777
|
+
const avg = Math.round((c1 + c2) / 2);
|
|
778
|
+
result.set(k, avg);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Compute minors of presentation matrix
|
|
786
|
+
* @private
|
|
787
|
+
*/
|
|
788
|
+
_computeMinors(size) {
|
|
789
|
+
// Simplified: return generators based on prime structure
|
|
790
|
+
const generators = [];
|
|
791
|
+
|
|
792
|
+
if (size <= 0) {
|
|
793
|
+
generators.push(new LaurentPolynomial({ 0: 1 }));
|
|
794
|
+
return generators;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// Each minor corresponds to a subset of relations/generators
|
|
798
|
+
const subsets = this._combinations(this.primes, size);
|
|
799
|
+
|
|
800
|
+
for (const subset of subsets) {
|
|
801
|
+
const minor = this._computeMinorFromSubset(subset);
|
|
802
|
+
if (!minor.isZero) {
|
|
803
|
+
generators.push(minor);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if (generators.length === 0) {
|
|
808
|
+
generators.push(new LaurentPolynomial({ 0: 1 }));
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
return generators;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Compute minor from prime subset
|
|
816
|
+
* @private
|
|
817
|
+
*/
|
|
818
|
+
_computeMinorFromSubset(primes) {
|
|
819
|
+
// The minor is a determinant of the Fox derivative matrix
|
|
820
|
+
// For simplified implementation, use product-sum formula
|
|
821
|
+
const coeffs = {};
|
|
822
|
+
|
|
823
|
+
for (let i = 0; i <= primes.length; i++) {
|
|
824
|
+
const sign = (i % 2 === 0) ? 1 : -1;
|
|
825
|
+
const binomial = this._binomial(primes.length, i);
|
|
826
|
+
coeffs[i] = sign * binomial;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
return new LaurentPolynomial(coeffs);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Binomial coefficient
|
|
834
|
+
* @private
|
|
835
|
+
*/
|
|
836
|
+
_binomial(n, k) {
|
|
837
|
+
if (k < 0 || k > n) return 0;
|
|
838
|
+
if (k === 0 || k === n) return 1;
|
|
839
|
+
|
|
840
|
+
let result = 1;
|
|
841
|
+
for (let i = 0; i < k; i++) {
|
|
842
|
+
result = result * (n - i) / (i + 1);
|
|
843
|
+
}
|
|
844
|
+
return Math.round(result);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Generate all k-combinations of array
|
|
849
|
+
* @private
|
|
850
|
+
*/
|
|
851
|
+
_combinations(arr, k) {
|
|
852
|
+
if (k === 0) return [[]];
|
|
853
|
+
if (arr.length === 0) return [];
|
|
854
|
+
|
|
855
|
+
const [first, ...rest] = arr;
|
|
856
|
+
const withFirst = this._combinations(rest, k - 1).map(c => [first, ...c]);
|
|
857
|
+
const withoutFirst = this._combinations(rest, k);
|
|
858
|
+
|
|
859
|
+
return [...withFirst, ...withoutFirst];
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Get Alexander polynomial Δ₀(A_ψ)
|
|
864
|
+
*/
|
|
865
|
+
get alexanderPolynomial() {
|
|
866
|
+
return this.computeFittingIdeal(0).characteristicPolynomial;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Get all Fitting ideals up to degree d
|
|
871
|
+
*/
|
|
872
|
+
getAllFittingIdeals(maxDegree = 3) {
|
|
873
|
+
const ideals = {};
|
|
874
|
+
for (let d = 0; d <= maxDegree; d++) {
|
|
875
|
+
ideals[d] = this.computeFittingIdeal(d);
|
|
876
|
+
}
|
|
877
|
+
return ideals;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Get module signature Σ_{k,S,ℓ,ψ}
|
|
882
|
+
*/
|
|
883
|
+
get signature() {
|
|
884
|
+
if (!this._signature) {
|
|
885
|
+
this._signature = this._computeSignature();
|
|
886
|
+
}
|
|
887
|
+
return this._signature;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Compute module signature
|
|
892
|
+
* @private
|
|
893
|
+
*/
|
|
894
|
+
_computeSignature() {
|
|
895
|
+
const fittingIdeals = this.getAllFittingIdeals();
|
|
896
|
+
const alexPoly = this.alexanderPolynomial;
|
|
897
|
+
|
|
898
|
+
// Signature components
|
|
899
|
+
const signatureData = {
|
|
900
|
+
primes: this.primes.slice(),
|
|
901
|
+
ell: this.ell,
|
|
902
|
+
field: this.field,
|
|
903
|
+
fittingDegrees: {},
|
|
904
|
+
alexanderPolynomial: alexPoly.toString(),
|
|
905
|
+
characteristicValues: [],
|
|
906
|
+
hash: 0
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
// Collect Fitting ideal degrees
|
|
910
|
+
for (const [d, ideal] of Object.entries(fittingIdeals)) {
|
|
911
|
+
signatureData.fittingDegrees[d] = {
|
|
912
|
+
degree: parseInt(d),
|
|
913
|
+
isTrivial: ideal.isTrivial,
|
|
914
|
+
isZero: ideal.isZero,
|
|
915
|
+
generatorDegree: ideal.characteristicPolynomial.degree
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// Evaluate Alexander polynomial on roots of unity
|
|
920
|
+
const numRoots = 12;
|
|
921
|
+
for (let k = 0; k < numRoots; k++) {
|
|
922
|
+
const theta = (2 * Math.PI * k) / numRoots;
|
|
923
|
+
const val = alexPoly.evaluateOnCircle(theta);
|
|
924
|
+
signatureData.characteristicValues.push({
|
|
925
|
+
k,
|
|
926
|
+
theta,
|
|
927
|
+
abs: val.abs,
|
|
928
|
+
re: val.re,
|
|
929
|
+
im: val.im
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Compute signature hash
|
|
934
|
+
signatureData.hash = this._computeSignatureHash(signatureData);
|
|
935
|
+
|
|
936
|
+
return signatureData;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Compute signature hash
|
|
941
|
+
* @private
|
|
942
|
+
*/
|
|
943
|
+
_computeSignatureHash(sig) {
|
|
944
|
+
// Combine prime signature with Alexander polynomial coefficients
|
|
945
|
+
let hash = 0;
|
|
946
|
+
|
|
947
|
+
// Include primes
|
|
948
|
+
for (const p of sig.primes) {
|
|
949
|
+
hash = ((hash << 5) - hash + p) | 0;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Include characteristic values
|
|
953
|
+
for (const cv of sig.characteristicValues) {
|
|
954
|
+
hash = ((hash << 5) - hash + Math.round(cv.abs * 1000)) | 0;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return hash >>> 0; // Ensure unsigned
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Check if two Alexander modules have equivalent signatures
|
|
962
|
+
*/
|
|
963
|
+
static equivalentSignatures(sig1, sig2, tolerance = 0.01) {
|
|
964
|
+
if (sig1.primes.length !== sig2.primes.length) return false;
|
|
965
|
+
if (sig1.ell !== sig2.ell) return false;
|
|
966
|
+
|
|
967
|
+
// Compare characteristic values
|
|
968
|
+
for (let i = 0; i < sig1.characteristicValues.length; i++) {
|
|
969
|
+
const v1 = sig1.characteristicValues[i];
|
|
970
|
+
const v2 = sig2.characteristicValues[i];
|
|
971
|
+
if (Math.abs(v1.abs - v2.abs) > tolerance) return false;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
return true;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Get JSON representation
|
|
979
|
+
*/
|
|
980
|
+
toJSON() {
|
|
981
|
+
return {
|
|
982
|
+
primes: this.primes,
|
|
983
|
+
ell: this.ell,
|
|
984
|
+
field: this.field,
|
|
985
|
+
alexanderPolynomial: this.alexanderPolynomial.toString(),
|
|
986
|
+
signature: this.signature,
|
|
987
|
+
metadata: this.metadata
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Create from JSON
|
|
993
|
+
*/
|
|
994
|
+
static fromJSON(json) {
|
|
995
|
+
return new AlexanderModule(json.primes, {
|
|
996
|
+
ell: json.ell,
|
|
997
|
+
field: json.field
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Get statistics
|
|
1003
|
+
*/
|
|
1004
|
+
get stats() {
|
|
1005
|
+
const alexPoly = this.alexanderPolynomial;
|
|
1006
|
+
const sig = this.signature;
|
|
1007
|
+
|
|
1008
|
+
return {
|
|
1009
|
+
numPrimes: this.r,
|
|
1010
|
+
ell: this.ell,
|
|
1011
|
+
alexanderDegree: alexPoly.degree,
|
|
1012
|
+
signatureHash: sig.hash,
|
|
1013
|
+
meanCharacteristicValue: sig.characteristicValues.reduce(
|
|
1014
|
+
(sum, v) => sum + v.abs, 0
|
|
1015
|
+
) / sig.characteristicValues.length
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// ============================================================================
|
|
1021
|
+
// MODULE SIGNATURE CLASS
|
|
1022
|
+
// ============================================================================
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Module Signature
|
|
1026
|
+
*
|
|
1027
|
+
* A content-addressable memory key derived from Alexander module invariants.
|
|
1028
|
+
* Provides stable "field memory" for prime sets.
|
|
1029
|
+
*
|
|
1030
|
+
* Uses:
|
|
1031
|
+
* - Content-addressable key (prime-set identifier)
|
|
1032
|
+
* - Resonance attractor fingerprint
|
|
1033
|
+
* - Alignment target for operator evolution
|
|
1034
|
+
*/
|
|
1035
|
+
class ModuleSignature {
|
|
1036
|
+
/**
|
|
1037
|
+
* Create a module signature
|
|
1038
|
+
*
|
|
1039
|
+
* @param {AlexanderModule} module - Source Alexander module
|
|
1040
|
+
*/
|
|
1041
|
+
constructor(module) {
|
|
1042
|
+
this.module = module;
|
|
1043
|
+
this._data = null;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Get signature data
|
|
1048
|
+
*/
|
|
1049
|
+
get data() {
|
|
1050
|
+
if (!this._data) {
|
|
1051
|
+
this._data = this.module.signature;
|
|
1052
|
+
}
|
|
1053
|
+
return this._data;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* Get signature hash (content-addressable key)
|
|
1058
|
+
*/
|
|
1059
|
+
get hash() {
|
|
1060
|
+
return this.data.hash;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Get primes
|
|
1065
|
+
*/
|
|
1066
|
+
get primes() {
|
|
1067
|
+
return this.data.primes;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Get Alexander polynomial string
|
|
1072
|
+
*/
|
|
1073
|
+
get alexanderPolynomial() {
|
|
1074
|
+
return this.data.alexanderPolynomial;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Get characteristic values (for fingerprinting)
|
|
1079
|
+
*/
|
|
1080
|
+
get fingerprint() {
|
|
1081
|
+
return this.data.characteristicValues.map(v => v.abs);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Compute distance between two signatures
|
|
1086
|
+
*/
|
|
1087
|
+
distanceTo(other) {
|
|
1088
|
+
const fp1 = this.fingerprint;
|
|
1089
|
+
const fp2 = other.fingerprint;
|
|
1090
|
+
|
|
1091
|
+
if (fp1.length !== fp2.length) {
|
|
1092
|
+
throw new Error('Fingerprint length mismatch');
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
let sumSq = 0;
|
|
1096
|
+
for (let i = 0; i < fp1.length; i++) {
|
|
1097
|
+
const diff = fp1[i] - fp2[i];
|
|
1098
|
+
sumSq += diff * diff;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
return Math.sqrt(sumSq);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* Check if signatures are equivalent
|
|
1106
|
+
*/
|
|
1107
|
+
isEquivalentTo(other, tolerance = 0.01) {
|
|
1108
|
+
return AlexanderModule.equivalentSignatures(this.data, other.data, tolerance);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Get compact string representation
|
|
1113
|
+
*/
|
|
1114
|
+
toString() {
|
|
1115
|
+
return `ModuleSignature[${this.primes.join(',')}|${this.hash.toString(16)}]`;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Export as content-addressable memory entry
|
|
1120
|
+
*/
|
|
1121
|
+
toMemoryEntry() {
|
|
1122
|
+
return {
|
|
1123
|
+
key: this.hash,
|
|
1124
|
+
primes: this.primes,
|
|
1125
|
+
fingerprint: this.fingerprint,
|
|
1126
|
+
polynomial: this.alexanderPolynomial,
|
|
1127
|
+
created: Date.now()
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// ============================================================================
|
|
1133
|
+
// SIGNATURE MEMORY CLASS
|
|
1134
|
+
// ============================================================================
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Signature Memory
|
|
1138
|
+
*
|
|
1139
|
+
* Content-addressable memory store for module signatures.
|
|
1140
|
+
* Enables resonance-based retrieval and alignment.
|
|
1141
|
+
*/
|
|
1142
|
+
class SignatureMemory {
|
|
1143
|
+
constructor() {
|
|
1144
|
+
this.signatures = new Map(); // hash → signature
|
|
1145
|
+
this.primeIndex = new Map(); // prime → [hashes]
|
|
1146
|
+
this.metadata = {
|
|
1147
|
+
created: Date.now(),
|
|
1148
|
+
totalEntries: 0
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* Store a signature
|
|
1154
|
+
*/
|
|
1155
|
+
store(signature) {
|
|
1156
|
+
const hash = signature.hash;
|
|
1157
|
+
|
|
1158
|
+
if (this.signatures.has(hash)) {
|
|
1159
|
+
return { stored: false, reason: 'already exists', hash };
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
this.signatures.set(hash, signature);
|
|
1163
|
+
|
|
1164
|
+
// Index by primes
|
|
1165
|
+
for (const p of signature.primes) {
|
|
1166
|
+
if (!this.primeIndex.has(p)) {
|
|
1167
|
+
this.primeIndex.set(p, []);
|
|
1168
|
+
}
|
|
1169
|
+
this.primeIndex.get(p).push(hash);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
this.metadata.totalEntries++;
|
|
1173
|
+
|
|
1174
|
+
return { stored: true, hash };
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* Retrieve signature by hash
|
|
1179
|
+
*/
|
|
1180
|
+
get(hash) {
|
|
1181
|
+
return this.signatures.get(hash) || null;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/**
|
|
1185
|
+
* Check if signature exists
|
|
1186
|
+
*/
|
|
1187
|
+
has(hash) {
|
|
1188
|
+
return this.signatures.has(hash);
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Find signatures containing a specific prime
|
|
1193
|
+
*/
|
|
1194
|
+
findByPrime(prime) {
|
|
1195
|
+
const hashes = this.primeIndex.get(prime) || [];
|
|
1196
|
+
return hashes.map(h => this.signatures.get(h)).filter(Boolean);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Find closest signature to query
|
|
1201
|
+
*/
|
|
1202
|
+
findClosest(querySignature, topK = 5) {
|
|
1203
|
+
const results = [];
|
|
1204
|
+
|
|
1205
|
+
for (const [hash, sig] of this.signatures) {
|
|
1206
|
+
try {
|
|
1207
|
+
const distance = querySignature.distanceTo(sig);
|
|
1208
|
+
results.push({ hash, signature: sig, distance });
|
|
1209
|
+
} catch (e) {
|
|
1210
|
+
// Skip incompatible signatures
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
results.sort((a, b) => a.distance - b.distance);
|
|
1215
|
+
return results.slice(0, topK);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* Find equivalent signatures
|
|
1220
|
+
*/
|
|
1221
|
+
findEquivalent(querySignature, tolerance = 0.01) {
|
|
1222
|
+
const equivalent = [];
|
|
1223
|
+
|
|
1224
|
+
for (const [hash, sig] of this.signatures) {
|
|
1225
|
+
if (querySignature.isEquivalentTo(sig, tolerance)) {
|
|
1226
|
+
equivalent.push({ hash, signature: sig });
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
return equivalent;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Get all signatures
|
|
1235
|
+
*/
|
|
1236
|
+
getAll() {
|
|
1237
|
+
return [...this.signatures.values()];
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Get memory statistics
|
|
1242
|
+
*/
|
|
1243
|
+
get stats() {
|
|
1244
|
+
const allPrimes = new Set();
|
|
1245
|
+
for (const sig of this.signatures.values()) {
|
|
1246
|
+
for (const p of sig.primes) {
|
|
1247
|
+
allPrimes.add(p);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
return {
|
|
1252
|
+
totalSignatures: this.signatures.size,
|
|
1253
|
+
uniquePrimes: allPrimes.size,
|
|
1254
|
+
primeIndex: this.primeIndex.size,
|
|
1255
|
+
created: this.metadata.created
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Clear all signatures
|
|
1261
|
+
*/
|
|
1262
|
+
clear() {
|
|
1263
|
+
this.signatures.clear();
|
|
1264
|
+
this.primeIndex.clear();
|
|
1265
|
+
this.metadata.totalEntries = 0;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
/**
|
|
1269
|
+
* Export memory to JSON
|
|
1270
|
+
*/
|
|
1271
|
+
toJSON() {
|
|
1272
|
+
const entries = [];
|
|
1273
|
+
for (const [hash, sig] of this.signatures) {
|
|
1274
|
+
entries.push({
|
|
1275
|
+
hash,
|
|
1276
|
+
primes: sig.primes,
|
|
1277
|
+
fingerprint: sig.fingerprint,
|
|
1278
|
+
polynomial: sig.alexanderPolynomial
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
return { entries, metadata: this.metadata };
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* Import memory from JSON
|
|
1286
|
+
*/
|
|
1287
|
+
static fromJSON(json, moduleFactory) {
|
|
1288
|
+
const memory = new SignatureMemory();
|
|
1289
|
+
|
|
1290
|
+
for (const entry of json.entries) {
|
|
1291
|
+
const module = moduleFactory(entry.primes);
|
|
1292
|
+
const signature = new ModuleSignature(module);
|
|
1293
|
+
memory.store(signature);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
return memory;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// ============================================================================
|
|
1301
|
+
// SIGNATURE EXTRACTOR
|
|
1302
|
+
// ============================================================================
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* Signature Extractor
|
|
1306
|
+
*
|
|
1307
|
+
* Extracts module signatures from prime sets and manages
|
|
1308
|
+
* the signature extraction pipeline.
|
|
1309
|
+
*/
|
|
1310
|
+
class SignatureExtractor {
|
|
1311
|
+
/**
|
|
1312
|
+
* Create a signature extractor
|
|
1313
|
+
*
|
|
1314
|
+
* @param {Object} options - Configuration
|
|
1315
|
+
* @param {number} options.ell - Base prime (default: 2)
|
|
1316
|
+
* @param {SignatureMemory} options.memory - Optional memory store
|
|
1317
|
+
*/
|
|
1318
|
+
constructor(options = {}) {
|
|
1319
|
+
this.ell = options.ell || 2;
|
|
1320
|
+
this.memory = options.memory || new SignatureMemory();
|
|
1321
|
+
this._cache = new Map();
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Extract signature from prime set
|
|
1326
|
+
*
|
|
1327
|
+
* @param {number[]} primes - Prime set S
|
|
1328
|
+
* @param {Object} options - Extraction options
|
|
1329
|
+
* @returns {ModuleSignature} The extracted signature
|
|
1330
|
+
*/
|
|
1331
|
+
extract(primes, options = {}) {
|
|
1332
|
+
const key = primes.sort((a, b) => a - b).join(',');
|
|
1333
|
+
|
|
1334
|
+
if (this._cache.has(key)) {
|
|
1335
|
+
return this._cache.get(key);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
const module = new AlexanderModule(primes, {
|
|
1339
|
+
ell: options.ell || this.ell,
|
|
1340
|
+
field: options.field || 'Q'
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
const signature = new ModuleSignature(module);
|
|
1344
|
+
|
|
1345
|
+
this._cache.set(key, signature);
|
|
1346
|
+
|
|
1347
|
+
if (options.store !== false) {
|
|
1348
|
+
this.memory.store(signature);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
return signature;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Extract signatures from multiple prime sets
|
|
1356
|
+
*/
|
|
1357
|
+
extractBatch(primeSets, options = {}) {
|
|
1358
|
+
return primeSets.map(primes => this.extract(primes, options));
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1362
|
+
* Find resonant signatures (closest matches)
|
|
1363
|
+
*/
|
|
1364
|
+
findResonant(primes, topK = 5) {
|
|
1365
|
+
const querySig = this.extract(primes, { store: false });
|
|
1366
|
+
return this.memory.findClosest(querySig, topK);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* Get alignment target for operator evolution
|
|
1371
|
+
* Returns the closest signature in memory.
|
|
1372
|
+
*/
|
|
1373
|
+
getAlignmentTarget(primes) {
|
|
1374
|
+
const matches = this.findResonant(primes, 1);
|
|
1375
|
+
return matches.length > 0 ? matches[0].signature : null;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* Clear cache
|
|
1380
|
+
*/
|
|
1381
|
+
clearCache() {
|
|
1382
|
+
this._cache.clear();
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Get extractor statistics
|
|
1387
|
+
*/
|
|
1388
|
+
get stats() {
|
|
1389
|
+
return {
|
|
1390
|
+
cacheSize: this._cache.size,
|
|
1391
|
+
memoryStats: this.memory.stats,
|
|
1392
|
+
ell: this.ell
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// ============================================================================
|
|
1398
|
+
// INTEGRATION UTILITIES
|
|
1399
|
+
// ============================================================================
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* Create Alexander module from prime set
|
|
1403
|
+
*/
|
|
1404
|
+
function createAlexanderModule(primes, options = {}) {
|
|
1405
|
+
return new AlexanderModule(primes, options);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* Extract signature from prime set (convenience function)
|
|
1410
|
+
*/
|
|
1411
|
+
function extractSignature(primes, options = {}) {
|
|
1412
|
+
const module = new AlexanderModule(primes, options);
|
|
1413
|
+
return new ModuleSignature(module);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* Create signature memory store
|
|
1418
|
+
*/
|
|
1419
|
+
function createSignatureMemory() {
|
|
1420
|
+
return new SignatureMemory();
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* Create signature extractor
|
|
1425
|
+
*/
|
|
1426
|
+
function createSignatureExtractor(options = {}) {
|
|
1427
|
+
return new SignatureExtractor(options);
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// ============================================================================
|
|
1431
|
+
// EXPORTS
|
|
1432
|
+
// ============================================================================
|
|
1433
|
+
|
|
1434
|
+
export {
|
|
1435
|
+
// Polynomial utilities
|
|
1436
|
+
LaurentPolynomial,
|
|
1437
|
+
FittingIdeal,
|
|
1438
|
+
|
|
1439
|
+
// Crowell exact sequence
|
|
1440
|
+
CrowellSequence,
|
|
1441
|
+
|
|
1442
|
+
// Alexander module
|
|
1443
|
+
AlexanderModule,
|
|
1444
|
+
|
|
1445
|
+
// Signature classes
|
|
1446
|
+
ModuleSignature,
|
|
1447
|
+
SignatureMemory,
|
|
1448
|
+
SignatureExtractor,
|
|
1449
|
+
|
|
1450
|
+
// Factory functions
|
|
1451
|
+
createAlexanderModule,
|
|
1452
|
+
extractSignature,
|
|
1453
|
+
createSignatureMemory,
|
|
1454
|
+
createSignatureExtractor
|
|
1455
|
+
};
|
|
1456
|
+
|
|
1457
|
+
export default {
|
|
1458
|
+
LaurentPolynomial,
|
|
1459
|
+
FittingIdeal,
|
|
1460
|
+
CrowellSequence,
|
|
1461
|
+
AlexanderModule,
|
|
1462
|
+
ModuleSignature,
|
|
1463
|
+
SignatureMemory,
|
|
1464
|
+
SignatureExtractor,
|
|
1465
|
+
createAlexanderModule,
|
|
1466
|
+
extractSignature,
|
|
1467
|
+
createSignatureMemory,
|
|
1468
|
+
createSignatureExtractor
|
|
1469
|
+
};
|