Public
Edited
Nov 8, 2024
Insert cell
md`# Modular Square Roots`
Insert cell
/*
class Number.Real extends Number.Complex {} // ℝ in ℂ
class Number.Algebraic extends Number.Real {} // 𝔸 in ℝ
class Number.Rational extends Number.Algebraic {} // ℚ in 𝔸
class Number.Integer extends Number.Rational {} // ℤ in ℚ
class Number.Natural extends Number.Integer {} // ℕ in ℤ
class Number.Prime extends Number.Natural {} // ℙ in ℕ

// any algebraic number field is a finite degree (and hence algebraic) field extension of ℚ
// quadratic irrationals are really a field extension of rational field ℚ, as ℚ(√c)
class Number.Quadratic extends Number.Algebraic {} // 𝔸_2 in ℝ

// "extends" should really be read as "restricts"...
// the idea is to inherit the wider field operations (and elements)...
// but some subset of operations can be redefined, e.g. as optimizations...
// or, if just for specific elements, to ensure specific closure properties

// the above inclusion map should really be defined in terms of representation space...
// ℂ allows [ℝ,ℝ]...
// ℝ restricted to [ℝ,0]...
// or in other direction...
// ℕ^+ restricted to [...ℙ] -- a multiset of ℙ, counting multiplicity...
// ℕ extending further to allow 0
// ℤ extending by ℕ by allowing negative unit into product, -1
// ℚ extending ℤ by allowing negative prime powers
// 𝔸_2 (quadratic fields) extending ℚ by allowing half-int prime powers into product
// 𝔸 extending ℚ extending ℤ by allowing prime power fractional denominator to be any integer?
// perhaps ℚ better written as 𝔸_1... and ℤ as 𝔸_0?
// ℂ extends ℝ as 𝔸_2 extends ℚ, by allowing negative base with half-int prime powers (imaginary unit)
// other interesting spaces, like the line of pure imaginary numbers...
// gaussian integers ℤ[i]...

// repr should carry its "units" along with it...
// allows for various optimizations, but also for dimensional analysis...
// can represent things like signed distances without losing data within richer algebras
// could even track *relations* between dimensions...

// dimension: base quantity along with units of measure
// abstract number: 5
// concrete number: associated with the things being counted, e.g. 5 apples
// denominate number: concrete number with a unit of measure attached with it, e.g. 5 inches
// dimensional homogenuity:
// any physically meaningful equation (or inequality) will have same dimension on both sides
// quantity calculus: a physical quantity as the product of a "numerical value" and a "reference quantity"
// suggests that all such quantities must be "constructable"?
// unit vectors as units of direction?
// radian: algebraically equal to 1, but symbolizes angle, or a ratio with π)
// steradian: square radian, unit of solid angle...gives an area when projected onto a sphere
*/
class Integers {
toTex () {
return 'ℤ'
}
show () {
return tex`${this.toTex()}`
}
}
Insert cell
/*
https://www.math3ma.com/blog/whats-a-quotient-group-really-part-2
ℤ/5ℤ -- all the integers that aren't multiples of 5

1+5ℤ ... {…,-9,-4,1,6,11,…} ... called the coset [1]

*/
Insert cell
= Integer
Insert cell
class Coset {
constructor ({ order, index }) {
this.order = (order)
this.index = (index)
}

setNotation(n = 2) {
n = Math.max(0,Math.min(n,5))
const pos = []
const neg = []
for (let k = 1; k <= n; ++k) {
pos.push(this.index.add(this.order.times(k)))
neg.unshift(this.index.subtract(this.order.times(k)))
}
const list = [].concat(neg, [ this.index ], pos)
return tex`\{…,${ list.join(',') },…\}`
}
toTex () {
return `[${this.index}] = ${this.index}+${this.order}ℤ`
}

show () {
return tex`${this.toTex()}`
}

// TODO show method on actual class
class () {
return tex`ℤ/${this.order}ℤ`
}
}
Insert cell
new Coset({ order: 5, index: 3 }).class()
Insert cell
class QuotientGroup {
static get def () {
// from https://www.math3ma.com/blog/whats-a-quotient-group-really-part-1
return md`
Let G be a group and let N be a normal subgroup of G.
Then ${tex`G/N = \{gN : g ∈ G\}`} is the set of all cosets of N in G
and is called the quotient group of N in G.
Alternatively: G/N, the quotient group of N in G, is (sorta) all elements in G that are not in N.

- ${tex`nℤ ⊂ ℤ`} means: You live in nℤ iff you're an integer and a multiple of n
- ${tex`SL_n(F) ⊂ GL_n(F)`} means: You live in ${tex`SL_n(F)`} iff you're an invertible n×n matrix with entries in a field F, and your determinate is 1
- ${tex`ker ϕ ⊂ G`} means: You live in ker ϕ iff you get sent to the identity e ∈ H under a homomorphism ϕ : G → H
- ${tex`Z(G) ⊂ G`} means: You live in Z(G) (the center of G) iff you commute with every element of G
- ${tex`[G,G] ⊂ G`} means: You live in [G,G] (the commutator subgroup) iff you look like a finite product of things of the form ${tex`g h g^{-1} h^{-1}`} where g, h ∈ G
- and so on...
`
}
}
Insert cell
QuotientGroup.def
Insert cell
// Cardinal number: "how many"
// Ordinal: "in which position"
// difference is only in whether the sets are ordered...
// https://www.quora.com/What-is-the-difference-between-ordinal-numbers-and-cardinal-numbers
// Every finite set can be well ordered simply by counting its elements and labelling the elements with count.
// The count provides an order-preserving bijection between any two finite sets of the same cardinality.
// ~ indistiguishable for finite values
// very different for transfinite values
// cardinal = ordinal (mod order)

// √∞ using surreal numbers:
// https://thatsmaths.com/2012/11/22/the-root-of-infinity-its-surreal/
Insert cell
// class Cardinal {
// constructor ({ index }) {
// this.index = index
// }
// get tex () {
// return `ℵ_{${this.index}}`
// }
// }
Insert cell
// ℕ.orderType = LimitOrder.one
Insert cell
md`
### IndexedFamily
* An ordered pair is a family indexed by the two element set ${tex`\bold{2}`} = {1, 2}.
* An n-tuple is a family indexed by ${tex`\bold{n}`}.
* An infinite sequence is a family indexed by the natural numbers.
* A list is an n-tuple for an unspecified n, or an infinite sequence.
* An n×m matrix is a family indexed by the cartesian product n×m.
* A net is a family indexed by a directed set.
`
Insert cell

// if we allow modulus of Infinity...
// negative unit: Infinity - 1 mod Infinity: -1...
// or some such... gives us a notion of sign on natural numbers...
// but different behavior for succ/pred ops... must keep track of half-plane
// "successor" becomes truly negative? something like that
class ModularIntegers extends Integers {
constructor ({ modulus }) {
super()
Object.assign(this, { modulus })
}

toTex () {
return `ℤ/${this.modulus}ℤ`
}
index (n) {
}

static of (modulus) {
return new ModularIntegers({ modulus })
}
}
Insert cell
ModularIntegers.of(73).show()
Insert cell
/*
class UnitaryDivisor ... Bag<ℙ>... or UniqueArray<ℙ^n>, unique on ℙ, indexed by ℙ magnitude order (or power?)
class UnitaryDivisorList

coordinate vectors:
e_1 = (1,0,0,...,0); e_2 = (0,1,0,...,0); e_n = (0,0,...,0,1)
form a basis of F^n called standard basis
any n-vector can be uniquely expressed as a linear combination of these vectors:
(x_1, x_2, ..., x_n) = x_1 e_1 + x_2 e_2 + ... + x_n e_n
(x_1, x_2, ..., x_n) called the "Cartesian coordinates" of the vector
standard basis represented by prime power divisors
at least for square free numbers... verify for powers, but should remain true
square operation is idempotent for mod sqrts of 1
power successor/predecessor is an involution
all even powers will square back to unit element...
all odd powers will be identical to unit
(for modular sqrts of 1, the square operation is an involution)

class UnitaryModularSquareRootList ... with generator 𝔤=1
class ModularSquareRootList extends UnitaryModularSquareRootList ... with generator 𝔤>1


square roots of 1 mod n:
generated in bitwise-ascending order:
2σ̂ (σ̂, n/σ̂)^-1 - 1 (mod n)
where σ̂ is any of 2^ω unitary divisors of n
can be generated over space of bit strings of length ω
n/σ̂ analogous to bitwise negation of rad(n) bit vector
"reciprocates" unitary divisor, giving complementary unitary divisor
number of the form 2k-1 must always be odd?

generated in bitwise-descending order?
1 - 2σ̂ (σ̂, n/σ̂)^-1 (mod n)
just negative of above

*/
Insert cell
// good symbol for Hall divisor function
tex`\hat\sigma\left(n\right)`
Insert cell
/*


𝟘: product of all prime-power factors, equal to c... or 0 (mod c)
∏ σ̂(c)^[1,1,...]

from bit vector perspective
from base 2 perspective, would represent 2^ω - 1... and looks like -1 (mod 2^ω)
the context of mod 2^ω index representatives, counting backward:
0 becomes unreachable -- it's the (2^ω + 1)th element
1 becomes the (2^ω)th element -- representing zero
2-adic extension would mean adding more and more dimensions to bit vector...
assuming factor base vector is extended with 0s, this has no impact
assuming the convention 0^0 = 1
extension by 0s in one interpretation identical to extension by 1s in another
just like for standard relationship between weighted and p-adic representations
and analagously, involves a shift by 1 unit
unital sqrt rep "1" gives a "stationary" action


𝟙: product of no prime-power factors
∏ 0^[1,1,...]


0^v_2 : returns termwise complement
(-1)^v_2 : alternation, 0 -> 1, 1 -> -1 ... mod 2 sign

hall divisor factor base maps identically to (dual) boolean algebra
f_v := [5,7,17,37]
ω := 4
c := ∏ f_vec = 22015
𝟘 := ∏ [0,0,0,0]^f_v = 0^5 * 0^7 * 0^17 * 0^37 = 1
𝟙 := ∏ [1,1,1,1]^f_v = 1^5 * 1^7 * 1^17 * 1^37 = 22015 = 0 (mod c)
ê_1 := [1,0,0,0]
ê_2 := [0,1,0,0]
ê_3 := [0,0,1,0]
ê_4 := [0,0,0,1]
|σ̂_v| := 2^ω = 16
σ̂_v := can be mapped to base 2 expansion of numbers in range [0...2^ω-1]
each bit position n maps to the ê_n unit vector
e.g. "5" --> 0101_b = ∏ [1,0,1,0]^f_v = 1^5 * 0^7 * 1^17 * 0^37 = 85

negation: ¬[1,0,1,0] = ~0101_b = 1010_b = "10" --> 0^5 * 1^7 * 0^17 * 1^37 = 259
logical negation equivalent to xor with universe: c xor a = ~a
negation always a parity inversion: a + ~a = 1 (mod 2)
corresponds to division by "universe" c, e.g. c / 85 = 259
essentially, functions as "reciprocation" operation, seemingly by c ~= 𝟘?
c only represents 𝟘 in bitwise interpretation
in divisor value interpretation, c represents... what?
"reciprocal" obviously not (mod c) -- but rather, (mod 2^ω - 1)?
none of these divisors (of c) can have multiplicative inverses (mod c)
relationship between base 2 hall divisor index encoding and complementary reps?

negation always reverses bitwise population parity... population inversion

sqrts can be paired into gaussian integers to give 2^(2ω) points in plane
negation would flip sign on both coordinates
conjugation would only flip sign of second coordinate
multiplication by i: something like conjugate transpose?
i(a,b) = i(a+bi) --> (ai+bi^2) = ai-b = (-b,a)
composed with conjugation: conjugate∘complexify
(i(a,b))^* = (-b,a)^* --> (-b,-a)
equivalent to swap⋅negate (commutative)
swap∘negate: -(a,b)^S = -(b,a) = (-b,-a)
negate∘swap: (-(a,b))^S = (-a,-b)^R = (-b,-a)
self-dual: swap∘negate = negate∘swap

s in opposite order complexify∘swap:
i(a,b)^S --> i(b,a) = bi+ai^2 = bi-a = (-a,b)

equivalent to conjugate∘swap
((a,b)^S)^* = (b,-a)^S = (-b,a)
dual to swap∘conjugate:
((a,b)^*)^S = (a,-b)^S = (-b,a)

operations
noop: +(a,b) = ( a, b) = + (a+bi) = a +bi
negate: -(a,b) = (-a,-b) = - (a+bi) = -a -bi
imagify: i(a,b) = (-b, a) = i(a+bi) = ai+bi^2 = ai-b = -b+ai
nimagify: ī(a,b) = ( b,-a) = -i(a+bi) = -ai-bi^2 = -ai+b = b-ai

conjugate precompositions
conj: +(a,b)^* = ( a,-b) = + (a+bi)^* = + (a-bi) = a-bi
nconj: -(a,b)^* = (-a, b) = - (a+bi)^* = - (a-bi) = -a+bi
swap: i(a,b)^* = ( b, a) = i(a+bi)^* = i(a-bi) = ai-bi^2 = ai+b = b+ai
nswap: ī(a,b)^* = (-b,-a) = -i(a+bi)^* = -i(a-bi) = -ai+bi^2 = -ai-b = -b-ai

conjugate postcompositions
conj: (+(a,b))^* = ( a,-b) = (+ (a+bi))^* = ( a+bi)^* = a-bi
nconj: (-(a,b))^* = (-a, b) = (- (a+bi))^* = (-a-bi)^* = -a+bi
nswap: (i(a,b))^* = (-b,-a) = ( i(a+bi))^* = (-b+ai)^* = -b-ai
swap: (ī(a,b))^* = ( b, a) = (-i(a+bi))^* = ( b-ai)^* = b+ai

norm of a Gaussian integer
its product with its conjugate:
N(a+bi) = (a+bi)(a-bi) = a^2 + b^2
non-negative integer which is a sum of two squares

norm is multiplicative:
N(zw) = N(z) N(w)
for every pair of Gaussian integers z,w

units:
units of the ring of Gaussian integers
Gaussian integers whose multiplicative inverse is also a Gaussian integer
are precisely the Gaussian integers with norm 1
1, –1, i, –i


pure rotations:
noop = spinu = i^0 P = i^±(4n+0) P
imagify = spinh = i^1 P = i^±(4n+1) P
imagify = spinq = i^2 P = i^±(4n+2) P
nimagify = spint = i^3 P = i^±(4n+3) P

compositions
invexify∘negate
conjugate∘swap
((a,b)^S)^* = (b,-a)^S = (-b,a)
conjugate∘swap
((a,b)^S)^* = (b,-a)^S = (-b,a)

a transpose operation should flip axis of travel, e.g. along xor field...
e.g. multiplying by

at divisor "value" level:
multiplication (mod c) represented by bitwise union: <a_v | b_v> = ab mod c
[1,0,1,0] | [0,0,1,1] = [1,0,1,1] --> 5*17^2*37 (mod c) = 5*17*37 = c/7
x ∨ y = x + y - xy ???
division (mod c) represented by bitwise intersection <a_v & b_v> = ab mod c
fact that 1111_b ~= 0 suggests that unit vectors ê_n are actually *reciprocal* vectors?
thinking about this in terms of a divisibility lattice:
1111: not divisible by any of the other (lesser) terms
1110: divisible by all but first factor
1100: divisible by all but first two factors

alternating bit patterns have specific properties forced by symmetry:
for even ω:
for odd a: ~a = 2a
for even a: ~a = a/2
for odd ω:
for odd a: ~a = 2a+1
for even a: ~a = (a-1)/2
circular rotation: represents all cases, and in either direction
other palindromic representations have similar symmetry-forced invariants

if basis ordered by factor magnitude:
last ê, ê_ω, will have smallest lattice spacing
first ê, ê_1, will have largest lattice spacing
bit-reversal analogous to flipping sort order of factor list?

c/<ê_n> punches a hole in the all 1s vector at the nth place (antivector of clifford algebra?)

multivalued logic
NOT replaced with 1-x
AND replaced with multiplication
OR defined via De Morgan


questions, from https://www.desmos.com/calculator/awvoacftas
is sum over all roots always given by this: (1+2^(ω-1))*c ???


modular pseudo-inverse:
you can divide phideal field by index of least populated place (height?)...
rescales all places back down to 1
unitary divisors are those where least populated place is the modulus x itself?
certainly all factors... but likely also the hall divisors?
dividing mod by x looks like a fractional part operator?
integral part would then be x^2?
in some cases the least populated could be some inner element < x (must divide x? x-1?)
in all cases, spacing between populated places can be rescaled to unity
pos x covers 1/8 of ℤ[i], the Gaussian integers (disregarding the origin point)
how to handle origin point? gcd(0,N) = N for all N ∈ ℤ?
recovers the complete set of integers in x, rather than just multiplicative group mod c (boundary)
non-coprime x places (gcd(x,c) > 1) reintroduced with extra rescaling...as fractional elements?
does the equivalency between -floor(c/x) and d/dx mod(c,x) still hold? with some modifications?
does the mapping to rational elements still apply (by multiplication with "unit" at position 1)?
can also render in circle space...
congruences are equidistant points on straight line at some angle θ from (x,0,0) origin



*/
Insert cell
((parseInt('1011100',2)*parseInt('1101111',2)) % 2**7).toString(2)
Insert cell
((parseInt('11111111',2)-parseInt('00001011',2)) % 2**7).toString(2)
Insert cell
/*
totient(n): φ(n)
φ(n) = ∑[k=1 to n] gcd(k,n) cos(2πk/n)

φ(p^k) = p^(k-1) (p-1) = p^k (1-1/p)
for p prime, k≥1
special case: φ(p) = p-1

there are p^k - p^(k-1) numbers all relatively prime to p^k



// totient
φ(n) = φ(p_1^k_1) φ(p_2^k_2) ... φ(p^r k_r)
= n (1-1/p_1) (1 - 1/p_2) ... (1 - 1/p_r)
= n ∏[i=1 to r] (1 - 1/p_i)
= n ∏[i=1 to r] (p_i - 1)/p_i
= n / ∏ p_i ∏ (p_i - 1)
= n / rad(n) * ∏ (p_i - 1)
φ(36) = φ(2^2*3^2) = 36 (1-1/2) (1-1/3) = 36 (1/2) (2/3) = 12




discrete fourier transform of gcd, evaluated at 1

φ(n) = IntegersMod(n).MultiplicativeGroup.size
φ(mn) = φ(m)φ(n) d/φ(d) -- where d = gcd(m,n)
special cases:
φ(2m) = for m even: 2φ(m) ; for m odd: φ(m)
φ(n^m) = n^(m-1) φ(n)
φ(m) φ(n) = φ(lcm(m,n)) φ(gcd(m,n))
similar to: mn = lcm(m,n) gcd(m,n)

φ(n) always even for n≥3

if n has r distinct odd prime factors, 2^r | φ(n)
assuming n odd, there are 2^r square roots of 1 mod n... and 2^r divides φ(n)
φ(n)/n = φ(rad(n)) / rad(n)
= ∏[i=1 to r] (1 - 1/p_i)
= ∏[i=1 to r] (p_i - 1)/p_i
since all p are odd primes, all numerators in product are even, all denominators are odd
each numerator in product contains (at least) one factor of two for each distinct odd p
= ∏[i=1 to r] φ(p_i)/p_i
= ∏[i=1 to r] φ(p_i) ∏[i=1 to r] 1/p_i
since all p_i are coprime:
∏ φ(p_i) = φ(∏ p_i) = φ(rad(n))
and sum of reciprocals of primes is by definition 1/rad(n)
∏ 1/p_i = 1 / ∏ p_i = 1 / rad(n)
= φ(rad(n)) / rad(n)

φ(rad(n)) = ∏[i=1 to r] (p_i - 1)
= ∏[i=1 to r] mod((p_i - 1)!, p_i)
= ∏[i=1 to r] mod(p_i!/p_i, p_i)

if n even, 2^(r+1) square roots of 1? does above still hold?
ln(φ(rad(n)) / rad(n))
= ln(∏[i=1 to r] (p_i-1)/p_i)
= ∑[i=1 to r] (ln(p_i-1) - ln(p_i))
= ∑[i=1 to r] ln(p_i-1) - ∑[i=1 to r] ln(p_i))
= ∑[i=1 to r] ln(p_i-1) + ∑[i=1 to r] ln(1/p_i))

for any a>1 and n>6 such that 4 does not divide n there exists an l≥2n such that l|φ(a^n-1)
φ(n)/n = φ(rad(n))/rad(n)

∑[k in (ℤ/nℤ)^*] gcd(n,k-1) ...
where for all elements k in multiplicative group of integers mod n




// cototient
φ_c(n) = n - φ(n)

// number of primitive roots mod n
φ(φ(n))

// charmichael function, exponent of multiplicative group of integers mod n
λ(n) = lcm(λ(p_1^e_1), λ(p_2^e_2), ..., λ(p_n^e_n))
for prime power:
for power of an odd prime, and 2 or 4:
λ(p^k) = φ(p^k) = p^(k-1) (p-1)
for powers of 2 greater than 4:
λ(2^k) = φ(2^k)/2 = p^(k-2) (p-1) = 2^(k-2)

λ(n) | φ(n)

λ(lcm(a,b)) = lcm(λ(a),λ(b))
λ(2^k) ≤ 2^(k-2)
with equality when k>2

a | b ==> λ(a) | λ(b)

maximum possible radix exponent for primitive roots modulo n
radix exponent for a primitive root of unity is a divisor of λ(n)
*/
Insert cell
Object.keys(Integer).filter((i) => !Number.isFinite(+i))
Insert cell
Integer = Value.Integer
Insert cell
IntegerList = Value.IntegerList
Insert cell
IntegerList.of(3,-4,5).abs([2,2,-3]).show()
Insert cell
IntegerList.of(3,4,5).add(2)+""
Insert cell
IntegerList.of(3,4,5).toTex()
Insert cell
Value.Prime.from(5).pow(3)
Insert cell
a = Space.Integers.modulo(5)
Insert cell
new Space.Primes()[Symbol.iterator]().take(3)
Insert cell
new Space.Primes()
Insert cell
//[...Set.Primes]
Insert cell
new Space.Primes().size
Insert cell
Value.Cardinal.zero()
Insert cell
Value.Prime.from(3).pow(2)
Insert cell
Value.Integer.one.divide + ""
Insert cell
Value.Integer()
Insert cell
Value = {
// first extend Number.prototype with some extra ops
// TODO these aren't yet quite right...but meh...
Number.prototype.add = function (n) {
return this + n;
};

Number.prototype.sub = function (n) {
return this - n;
};

Number.prototype.mul = function (n) {
return this * n;
};

Number.prototype.pow = function (n) {
return this ** n;
};

Number.prototype.div = function (n) {
return this / n;
};

// modular
// TODO refine in terms of mod numbers

Number.prototype.mod = function (n) {
return this % n;
};

Number.prototype.powmod = function (n, m) {
// return this ** n % m
// TODO lift to rational, handle negatives, etc...
return Value.Natural.from(this).powmod(n, m);
};

Number.prototype.minv = function (m) {
return Integer(this).modInv(m);
};

// comparison
// TODO define in terms of a single primitive, e.g. lt?
// define cmp as ternary compare?
// define lte, gte composites?
Number.prototype.lt = function (n) {
return this < n;
};

Number.prototype.eq = function (n) {
return this == n;
};

Number.prototype.gt = function (n) {
return this > n;
};

// unary

Number.prototype.floor = function () {
return Math.floor(this);
};

Number.prototype.ceil = function () {
return Math.ceil(this);
};

Number.prototype.round = function () {
return Math.round(this);
};

Number.prototype.trunc = function () {
return Math.trunc(this);
};

// TODO ast forms representing the underlying operation
Number.prototype.Power = (n) => {
return new Value.Power({ base: this, power: n });
};
// Number.prototype.PowerMod(n,m)

// Array.prototype.toTex = Array.prototype.toString
Boolean.prototype.toTex = function () {
return this ? "⊤" : "⊥";
};
Number.prototype.toTex = Number.prototype.toString;
String.prototype.toTex = String.prototype.toString;

Object.prototype.show = function () {
return tex`${this.toTex ? this.toTex() : String(this)}`;
};

const Value = class extends Number {
constructor(input) {
super(input);
this.input = input;
}
};

const _BigInteger = await require("big-integer@1.6.43/BigInteger");
const Integer = _BigInteger;
Value.Integer = Integer;

Integer.from = (n) => new Integer(n);
Integer.is = (n) => n instanceof Integer || Number.isInteger(n);

// Integer.prototype.neg = Integer.prototype.negate
// Integer.prototype.sub = Integer.prototype.subtract
// Integer.prototype.mul = Integer.prototype.multiply
// Integer.prototype.div = Integer.prototype.divide;

Integer.prototype.toTex = function () {
return String(this);
};

Integer.prototype.show = Object.prototype.show;

const binomial = (n, k) => {
// use shorter side for loop
k = n - k < k ? n - k : k;
// use add with array for avoiding overflow by mul n*(n-1)
const a = Array.from({ length: k + 1 }).fill(Integer.zero);
a[0] = Integer.one;
for (let i = 0; i < n; i++) {
for (let j = k; j >= 1; j--) a[j] = a[j].add(a[j - 1]);
}
return a[k] || Integer.zero;
};

Integer.binomial = (n, k) => {
if (n < 0) return (-1) ** k * binomial(n + k - 1, k);
if (n >= 0) return binomial(n, k);
};

Value.IntegerList = class IntegerList extends Array {
constructor(...args) {
super(...args.map((arg) => new Integer(arg)));
}

static of(...args) {
return new IntegerList(...args);
}

static is(a) {
if (!a) return false;
if (a instanceof IntegerList) return true;
try {
return a.every((n) => Integer.from(n));
} catch (err) {
return false;
}
}

static zeros(length) {
return IntegerList.from({ length }).fill(Integer.zero);
}

static ones(length) {
return IntegerList.from({ length }).fill(Integer.one);
}

neg() {
return this.map((a) => a.negate());
}

abs() {
return this.map((a) => a.abs());
}

sign() {
return this.map((a) => a.sign());
}

_thread(op, b) {
// if (typeof this[op] !== 'function') throw new TypeError('operation not available: ' + op)

// thread operation component-wise over list
if (Array.isArray(b)) {
return this.map((a, i) => a[op](b[i] || Integer.zero));
}
return this.map((a, i) => a[op](b));
}

add(b) {
return this._thread("add", b);
}

sub(b) {
return this._thread("subtract", b);
}

mul(b) {
return this._thread("multiply", b);
}

div(b) {
return this._thread("divide", b);
}

mod(b) {
return this._thread("mod", b);
}

pow(b) {
return this._thread("pow", b);
}

modPow(b) {
return this._thread("modPow", b);
}

minv(b) {
return this._thread("minv", b);
}

sum() {
return this.reduce((a, b) => a.add(b), Integer.zero);
}

// join () {
// return '[' + Array.prototype.join.call(this, '+') + ']'
// }

prod() {
return this.reduce((a, b) => a.multiply(b), Integer.one);
}

gcd() {
return this.reduce((a, b) => Integer.gcd(a, b));
}

// could be: this.prod().div(this.gcd())
lcm() {
return this.reduce((a, b) => Integer.lcm(a, b));
}

min() {
return this.reduce((a, b) => Integer.min(a, b));
}

max() {
return this.reduce((a, b) => Integer.max(a, b));
}

toTex() {
return `[${this.map((a) => a.toTex()).join(",")}]`;
}
};

// Quantity: how "many" of something...
// like a discrete magnitude, absolute value without respect to direction
// e.g. "unsigned" types
// thus "Cardinal" should just be for infinite cardinals
// all finite cardinals are 1-1 with finite ordinals... and naturals (including 0?)...
// all infinite cardinals are limit ordinals (but 1-1? LimitOrdinals more fine-grained?)...
Value.Quantity = class Quantity extends Value {
constructor(count) {
if (count instanceof Quantity) return count;
let value = count;
// coerce to int
try {
value = Integer(count);
count = value;
} catch (err) {
count = Integer(0);
}
super(value);
// assert value is non-negative
if (value.sign) throw new TypeError("c ∉ ℕ");

// TODO rework to track approx vs. exact values...
// alternatively, track count (integral part) separate from unit fraction?
this.count = count;
this.value = value;
}

// get [Symbol.toStringTag()] {
// // TODO
// }
};

Value.Cardinal = class Cardinal extends Value.Quantity {
constructor({ index = 0, finite = false } = {}) {
super((index + 1 - finite) / finite);
this.index = index;
this.finite = finite;
}

get [Symbol.toStringTag]() {
return "κ ∈ ℵ";
}

static from(index) {
const finite = Number.isInteger(index);
if (!finite) index = 0;
return new Cardinal({ finite: false });
}

// aleph-naught
static zero() {
return new Cardinal({ finite: false });
}

toString() {
return this.finite ? `|{${this.index}}|` : `|∞|`;
}

get tex() {
return this.finite
? tex`|\mathbf{${this.index}}|`
: tex`ℵ_{${this.index}}`;
}
};

Value.Ordinal = class Ordinal extends Value.Cardinal {};

Value.Natural = class Natural extends Value {
constructor(input = 0) {
if (input instanceof Natural) return input;
// coerce to int
const value = Integer(input);
super(value);
this.input = input;
this.value = value;
// assert value is non-negative
if (value.sign) throw new TypeError("n ∉ ℕ");
}

static is(n) {
try {
return n.gt(0) || n.eq(0);
} catch (err) {
return false;
}
}

static from(n) {
return new Natural(n);
}

add(n) {
return this.value.add(n);
}

sub(n) {
return this.value.subtract(n);
}

mul(n) {
return this.value.multiply(n);
}

pow(n) {
return this.value.pow(n);
}

div(n) {
return this.value.divide(n);
}

// reduce value modulo m
mod(n) {
return this.value.mod(n);
}

minv(n) {
return this.value.modInv(n);
}

// power n, reduced modulo m
// TODO reduce to pow in class representing integers mod m
// ... so mod(m).pow(n) would yield IntegersMod(m).get(...).pow(n), or some such...
// TODO refine to allow fractional powers (at least for factorized modulus?)
powmod(n, m) {
let v = this.value;
if (n < 0) {
v = v.modInv(m);
n = -n;
}
return v.modPow(n, m);
}

// comparison

lt(n) {
return this.value.lt(n);
}

eq(n) {
return this.value.eq(n);
}

gt(n) {
return this.value.gt(n);
}

// unary

floor() {
return this;
}

ceil() {
return this;
}

round() {
return this;
}

trunc() {
return this;
}

// async factorization () {
// // TODO find prime factorization
// return this._factorMap
// }

// TODO: partialFactorization
// keep track of aspects of integral multiples, powers, and which bases are known prime
// extend algebraic operations to propagate this information

// factorization as "bag" vs. radical as "set"...
// totient identities apply -- make general statements applying to both...
// relational algebra makes similar distinction:
// http://infolab.stanford.edu/~ullman/fcdb/aut07/slides/ra.pdf
// set union is idempotent: S ∪ S = S
// bag union is idempotent: B ∪ B ≠ B does not hold in general...
// if x appears n times in S, then it appears 2n times in S ∪ S
// {1} ∪ {1} = {1,1} ≠ {1}
// B1 ∪ B2 = B2 ∪ B1
// commutivity of bag union holds as it does for set union
// B1 ∪ B2 = B1 ∩ B2 holds iff bags are coprime (no bases in common)
// bag intersection/union have min/max relationships for multiplicity of factors
};

Value.Factor = class Factor extends Value.Natural {
constructor(base, multiplicity = 1) {
base = Value.Natural.from(base);
multiplicity = Value.Natural.from(multiplicity);
if (multiplicity.eq(1)) return base; // b**1 = b for all b
if (base.eq(1)) return base; // 1**p = 1 for all p
if (multiplicity.eq(0)) return Value.Natural.from(1); // b**0 = 1 for all b
if (base.eq(0)) return Value.Natural.from(0); // 0**p = 0 for all p ≠ 0

// TODO indeterminate form?
super(base.pow(multiplicity));
}
};

Value.Power = class extends Value.Factor {};

// arithmetic on prime factor exponents omits the concept of addition?
// or rather, it's a different ring structure entirely
// addition --> integer multiplication, p_i^(e_i+x_i) = p_i^e_i*p_i^x_i
// outer addition less algebraically coherent: (p_i^e_i)+x_i
// can be interpreted as componentwise affine shifts
// addition on the bottom meaningful via binomial expansion: (p_i+x_i)^e_i
// multiplication --> integer exponentiation: p_i^(e_i*x_i) = (p_i^e_i)^x_i
// mutiplication on the bottom transforms like pure product: (p_i x_i)^e_i = p_i^e_i x_i^e_i
// outside mutiplication looks like coefficients: (p_i^e_i) x_i
// only algebraically relevant when x_i has relation with p_i or powers with relation with e_i
// thus, exponentiation --> (one level of) integer tetration?
// adjacent exponentiation ambiguous: p_i^e_i^x_i -- usually interpeted as p_i^(e_i^x_i)
// exponentiation on the top the exponent vector: p_i^(e_i^x_i)
// though "prefix" exponentiation is a common notation for tetration: ^x_i p_i^e_i
// outside exponentiation transforms to multiplication: (p_i^e_i)^x_i = p_i^(e_i x_i)
// bottom exponentiation identical (up to commutativity of [e,x]): (p_i^x_i)^e_i = p_i^(x_i e_i)
// also, without -1, it'd be a rig (ring w/o negation) like ℕ...
// but 1 is additive identity, not multiplicative...
// is there a notion of `e`, which would be the multiplicative identity?
// adding -1 generates ℚ?
// is there a sensible notion of "successor" without integer addition?
// TODO extends FactoredNatural, restricted to a single prime factor, with multiplicity 1
Value.Prime = class Prime extends Value.Factor {
// TODO this should probably extend prime power object, since it specializes
// a prime power is just a "degenerate" factor/exponent bag with a single prime factor element
constructor(base, multiplicity = 1) {
if (base instanceof Prime) return base;

super(base, multiplicity);
// assert primality (probable)
if (!Prime.is(this.value)) throw new TypeError("p ∉ ℙ");
}

static from(n) {
return new Prime(n);
}

static is(n) {
return (typeof n.isPrime === "function" && n.isPrime()) || false;
}

fromIndex(n) {
// TODO iterate over primes gen for nth prime
// e.g. primes().get(n)
}

// // TODO specialize pow function for primes to generate prime powers?

// Jordan totient function, a generalization of Euler totient (which is just k=1)
// https://en.wikipedia.org/wiki/Jordan%27s_totient_function
totient(k = 1) {
if (k.eq(1)) {
if (this.multiplicity.eq(1)) return this.sub(1);
}
}

carmichael() {
if (this.multiplicity.eq(1)) {
return this.totient();
}
// TODO
}
};

// TODO detecting perfect powers
// consider all possible values for k across each of the divisors of n, up to k ≤ log_2(n)
// can be simplified by only testing prime values of k
// since minimal value of k must necessarily be prime
// if full factorization of n is known, e.g. n = ∏ p_i^{α_i}
// then n is perfect power iff gcd(α) > 1 -- that is, exponent vector has common factor
// gcd represents the maximal power for which n is a perfect power
// n is also a perfect power to power dividing

// TODO call this PrimaryNumber, a la abstract algebra, e.g. "primary" ideals?
Value.Prime.Power = class PrimePower extends Value.Power {
constructor(prime, power = 1) {
prime = Value.Prime.from(prime);
power = Value.Natural.from(power);
// prime^1 just prime
if (power.eq(1)) return prime;
const value = prime.pow(power);
super(value);
this.prime = prime;
this.power = power;
}

// // specialize to return prime power
// pow (n) {
// return new PrimePower(this.prime, this.power.add(n))
// }

// TODO MultiplicativeGroup... gets extended to GF(n)
};

// represents a value, fully factored into primes
Value.Factorization = class Factorization extends Value.Quantity {
constructor(factors) {
super(factors.prod());
this.factors = factors;
}

rad() {
return new Factorization(this.factors.rad());
}

// TODO define padic valuation, padic norms, etc...

// TODO
get MultiplicativeGroup() {
// NB definitely memoize multiplicative group
// also need to memoize factorized natural
// const value = this.factors.reduce...
// Object.defineProperty(this, 'MultiplicativeGroup', { value })
// return value
}

// Jordan totient function, a generalization of Euler totient (which is just k=1)
// https://en.wikipedia.org/wiki/Jordan%27s_totient_function
totient(k = 1) {
if (k.eq(1)) {
if (this.multiplicity.eq(1)) return this.sub(1);
}
// TODO exact integer arithmetic instead? just sum over divisors instead
let n = this.value.pow(k);
for (let p of this.rad().factors) {
n *= 1 - p ** -k;
}
return n;
}

// TODO return positive sqrt of k mod each prime power of factorization, if one exists
// for now, just support primes 3 (mod 4)
// NB can use LegendreSymbol
sqrt(k) {
if (this.multiplicity.eq(1)) throw new Error("NYI for ℙ^n | n>1");
const p = this.value;
if (p.gcd(k).gt(0)) return Integer(0);
const mod4 = p.mod(4);
if (mod4.eq(3)) {
// r = ±k^((p+1)/4)
return k.modPow(p.add(1).divide(4), p);
}
}
};

// nominal number: symbolic... no order of magnitude implied

// TODO Tuple, List (∞-dimensional tuple)
// Vector, VectorTranspose, Matrix, SymmetricMatrix, etc...
// start with matrix, then define vector via refinement...
// essentially, just a redefinition of ops when certain invariants are satisfied
// uses more optimized version of ops rather than fully generic version
// same approach makes sense for scalars... starting from Complex?
// rather than outright replacing ops, use a dispatch strategy

// a vector space has a base field
// all elements of a vector are of the same type, ops form a field...
// a module over a ring generalizes the notion of a vector space over a field
// scalars are the elements of the given ring (with identity)
// a multiplication (on the left and/or on the right) is defined
// between elements of the ring and elements of the module

// 𝑛×1 matrix: column vector
// 1×𝑛 matrix: row vector

/*
from https://math.stackexchange.com/questions/748010/difference-between-tuple-and-row-matrix
tuple space: ℝ^𝑛 := ℝ×⋯×ℝ -- numbers arranged in columns
row space: ℝ^{1,𝑛} -- defined as the space of "numbers arranged in a row"
difference emphasized in notation using different brackets: () vs. [], respectively
suggestive of relational algebra... each ℝ represents a "column"
both operands to a given relational operation must have same "relation schema"
*/

Value.Bag = class Bag extends Map {
set(k, v) {
if (!Number.isInteger(v))
throw new TypeError("Entry values must be integer");
return super.set(k, (this.get(k) || 0).add(v));
}

factors() {
return new Set([...this.keys()].sort());
}
};

// Value.FactorBag = class extends Bag {

// }

return Value;
}
Insert cell
new Value.Prime(17)
Insert cell
IntegerList.of(3,4,2).show()
Insert cell
b = new Value.Bag([['a',4],['b',2],['a',-1],['d',-2]])
Insert cell
b.factors()
Insert cell
new Space.Naturals
Insert cell
Space = {
const Space = class extends Set {
// TODO base class for input domains
// represents generated sets... e.g. using set builder notation?
}
Space.Primes = class extends Space {
get [Symbol.toStringTag]() {
return 'p ∈ ℙ'
}

*[Symbol.iterator] () {
yield* primes()
}
get size () {
return Value.Cardinal.zero()
}
}

Space.Naturals = class {
get [Symbol.toStringTag]() {
return 'n ∈ ℕ'
}
*[Symbol.iterator] () {
for (let n = Value.Natural.zero();; n = n.add(1)) {
yield n
}
}
has (n) {
return Value.Natural.is(n)
}
}

Space.Integers = class {
// static *enumerate() {
// yield* naturals()
// }
// represents a range of integers by canonical representative
// always a set of natural numbers in range [0,modulo)
constructor ({ origin = 0, unit = 1, modulus = Infinity, index = 0 } = {}) {
const m = Number(modulus)
if (m === Infinity) return Integers
if (m === 0) throw new Error('ℤ/0ℤ NYI')
if (!Number.isInteger(m) || !Number.isFinite(m)) throw new TypeError('m ∉ ℤ')
if (m < 0) throw new TypeError('n ∉ ℕ')
// super()
this.modulus = modulus
this.origin = origin
this.modulus = modulus
}
// TODO iterators...
// iterate over all values, looping around (and keeping track of winds?)
// iterate over all canonical representatives (iterates over all equivalence classes, takes canonical rep)
// iterate along ideal?
// can be read integers "upto" n, the ring ℤ/nℤ
// finite positive value represents the characteristic of addition ring?
// infinite modulus represents ℤ, the ring of all integers -- a ring of characteristic 0
// what does ℤ/0ℤ represent? isomorphic to ℤ...
static modulo(n = Infinity) {
if (n === Infinity) return Integers
if (n === 0) throw new Error('ℤ/0ℤ NYI')
if (n > 0 && Number.isInteger(n)) {
return new Integers(n)
}
}
// // successor operation
// get next (n) {
// return ...
// }
get size () {
return this.modulus
}
}
return Space
}
Insert cell
Value.Prime.from(3).pow(5)
Insert cell
IntegerList.from([2,3,5]).lcm()
Insert cell
c = 5 * 7 * 17 * 37
Insert cell
/*

unitary divisors, mod square roots...

parameters for square roots mod c
c: a given natural modulus
λ: a given square (mod c)... jacobi(λ|c) = 1
σ̂_x: one of the 2^ω unitary divisors of c...
σ̂_x^*: conjugate unitary divisor, σ̂_x^* = c / σ̂_x... σ̂_x σ̂_x^* = 0 (mod c)
ρ̂_x: one of the 2^ω square roots of 1 (mod c)... σ̂_x^2 = 1 (mod c)
= 2 σ̂_x ( σ̂_x^-1 mod c/σ̂_x ) - 1
ρ_x: one of the 2^ω square roots of λ (mod c), card(ρ) ≤ 2^ω (roots may be duplicate)

given ρ_x, a square root of λ (mod c), one can generate all square roots of λ:
ρ_x ⋅ ρ̂ (mod c)

ρ × ρ̂ gives every square root of λ, one element per ρ per ρ̂
|ρ_y × ρ̂_x| = 2^ω * 2^ω = 2^(2ω) ... but duplicate points may exist
assuming roots generated from hall divisor ordering...
initial root ρ_x will run along diagonal, as it is scaled by initial root ρ̂_1, always 1
antidiagonal should contain -ρ_x, as final root ρ̂_{2^ω} is always -1

points have symmetry along x,y axes, diagonal and anti-diagonal about center of fundamental square (c/2,c/2)

for any element of ρ̂ (some √1 (mod c)):
ρ̂^-1 ≡ ρ̂
ρ̂^k ≡ 1 for k even, ρ̂ for k odd

apparent identities (assuming hall divisor ordering, 1-based indexing)
ρ̂_{n} ρ̂_{2^ω + 1 - n} = c-1 ≡ -1 (mod c)

for any element of ρ (some √λ (mod c)):



given two ρ̂, square roots of 1 (mod c)
path transition action given by:
ρ_x (ρ̂_β - ρ̂_α) (mod c)

generates xor bit board (nimber sum)

easy to determine smallest element of (1)^(1/2)...
what about (2)^(1/2) -- is there a simple formula?

*/
Insert cell
{
const a = []
for (let p = 0; p <= 36; p++) {
a.push(Value.Natural.from(404).pow(p).mod(c))
}
return a
}
Insert cell
// represents an array of residue classes modulo an array of moduli?
class ResidueNumber extends Value.Natural {
constructor (value, system) {
super(value)
this.input = value
this.value = Integer(value).mod(system.size)
this.system = system
this.residues = system.moduli.map((m) => value.mod(m))
// TODO this isn't right -- ensure coprimality...
}

toTex () {
return tex`${this.system.moduli.map((m) => `${this.value.mod(m)}_{${m}}`).join(' ')}`
}

index () {
const M_r = this.system.size
// N = ∑[i..] r_i T_i M_i (mod M_r)
// = ∑[i..] r_i ((M_r / m_i)^-1 (mod m_i)) (M_r/m_i) (mod M_r)
// TODO if we calculate sums lazily we could skip the first mod(M_r)
// would rewrite the second to apply before the sum...
// or, treat the arrays as vectors over the scalar field M_r (or modules over scalar ring M_r)...
// and rewrite sum to reduce more optimally
return this.system.weights.map((w, i) => w.times(this.residues[i]).mod(M_r)).sum().mod(M_r)
}
}
Insert cell
{
const rns = ResidueNumberSystem.of(11,13,29)
return rns.get(828).index()
}
Insert cell
25840-7106
Insert cell
ResidueNumberSystem.of(19,11,29,17).weights.sum().show()
Insert cell
ResidueNumberSystem.of(19)
Insert cell
// degenerate ResidueNumberSystem containing just a single moduli is just a ResidueClass mod m
// is the difference between a 1-dimensional vector and a scalar really worth preserving?
// in this case, it's the difference between the "base field" (or ring) and vector (module) space
// the ring has certain properties, while the "space" has a separate set of properties
// but maybe no reason not to imbue the ring with all those properties of module space?
Insert cell
class ResidueClass extends Value.Natural {
constructor (value, modulus) {
super(value)
this.input = value
this.modulus = Integer(modulus)
this.value = Integer(value).mod(modulus)
}
static of (n,m) {
return new ResidueClass(n,m)
}
toTex () {
return tex`⟨${this.value}⟩_{${this.modulus}}`
}
}
Insert cell
ResidueClass.of(31,11).toTex()
Insert cell
/*
for any RNS of coprime moduli...
the direct product of quotient rings of Z/m_iZ for each moduli m_i
isomorphic to quotient ring Z/nZ where n is product of moduli: ∏_i m_i
the weights should all be idempotents in ring Z/nZ
if moduli are coprime, each moduli must consist of distinct prime powers

multiplying residue weight w by all hall divisors mod n:
gives alternating ±w
sign and contiguous size of alternation span both related to factors associated with idempotent w

each weight in an RNS is associated with a distinct set of prime powers associated w/ modulus...
the weight modulo its associated modulus is 1
a given weight modulo every other modulus in set has to be 0
since recovery of weighted representation from RNS residues is a sum...
and "primary" (unit) square root of 1 must be 1 for all moduli, 1*1*1*1...
since weighted representation is sum of residues times weights, only one residue * weight could be 1
except assuming weights all sum to M-1, should actually give negative unit instead?

for any given modular square root, weights for each moduli remain the same...
so to find a square root mod RNS product, you just need a square root mod any one modulus
(or any unitary divisor of moduli product, assuming coprime moduli)
as the squared weight at this modulus squared remains 1 at this modulus (and remains zero elsewhere)
this square root can be multiplied by each unital square root to recover all square roots

if 4th roots only available for all prime factors being in 1 (mod 4) equivalence class...
are all nth roots available only for numbers such that all factors equivalent to 1 (mod n) ??
relationship with class number -- 1 mod 4 factors related to pairs of imaginary fields?
you can get weights for any arbitrary grouping of hall divisors...
represents various levels of parallel vs. serial calculation powers?
total number of possible RNS combinations: 2^ω(M)
where ω(M) represents number of prime divisors of moduli product M
weights should have factors in common with overall modulus product M
gcd(w_i, M) = M/m_i ??
combining two m_i together (taking product) reduces length of m_i list by 1...
two m_i which are multiplied gives one new weight which is just the sum of previous weights ??
all other m_i values left unchanged ??

sum of weights equals M-1?

if you calculate a square root for any given modulus
*/
Insert cell
{
const rns = ResidueNumberSystem.of(9,11,29)
return rns.weights.show()
}
Insert cell
{
const rns = ResidueNumberSystem.of(9,11,29)
const xs = [3,1,7]
return rns.weights.map((n, i) => n.times(xs[i]))
}
Insert cell
2233 % 29
Insert cell
{
const rns = ResidueNumberSystem.of(9,11,29)
return rns.weights.concat(
// first set should be identical to second set
// since weights should all be idempotents
rns.weights.pow(2).mod(rns.prod())
).show()
}
Insert cell
{
const rns = ResidueNumberSystem.of(9,11,29)
return rns.weights.map((w,i) => w.mod(rns.moduli[i])).show()
}
Insert cell
[(9*11*29-2233)%9,(9*11*29-2233)%11,(9*11*29-2233)%29]
Insert cell
md`
Every residue number system of coprime moduli falls into a class of systems determined by the cardinality of its dynamic range ${tex`|M_r| = N`}, which counts the number of representable multi-modular residue classes.

Each cardinality ${tex`N`} has ${tex`2^ω`} systems, where ${tex`ω`} is the count of distinct primes in factorization of number associated with size of dynamic range ${tex`N`}. Each such system can be associated with one of the ${tex`2^ω`} unitary divisors of ${tex`N`}, given by ${tex`σ̂_n`}.

These ${tex`2^ω`} systems may also be classified by how many moduli exist each system. This tells us how the available prime power factors are grouped together as moduli components. This also tells us which of the ${tex`2^ω`} idempotents to use as weights when reassembling sets of system residues back into representative residue class mod N, so we'll call these the weight classes.

Each of these weight classes has cardinality given by the binomial coefficient ${tex`ω\choose{k}`}, where ${tex`k`} represents the number of prime factors contributing to unital divisor ${tex`σ̂_n`} associated with system. More concretely, we could think of this as the number of 1s in the binary expansion of ${tex`n`} -- it's hamming weight.

Each of the ${tex`\binom{ω}{k}`} available systems in weight class ${tex`k`} will consist of length-${tex`k`} vectors, linear combinations of ${tex`k`} moduli.

* ${tex`\binom{ω}{0} = 1`} unique system with one component, no weights ${tex`≠1`}
* for 0 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for ω factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}
* ${tex`\binom{ω}{1} = ω`} available systems with one weight ${tex`≠1`}
* for 1 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for ω-1 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}
* ${tex`\binom{ω}{k}`} available systems with k weights ${tex`≠1`}
* for k factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for w-k factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}
* ...
* ${tex`\binom{ω}{ω-k}`} available systems with all but k weights ${tex`≠1`}
* for ω-k factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for k factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}
* ${tex`\binom{ω}{ω-1} = ω`} available systems with all but one weight ${tex`≠1`}
* for ω-1 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for 1 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}
* ${tex`\binom{ω}{ω} = 1`} unique system with ${tex`ω`} components, all weights ${tex`≠1`}
* for ω factors ${tex`p_i^{e_i}`}, ${tex`N ≡ -1 \pmod {p_i^{e_i}}`}
* for 0 factors ${tex`p_i^{e_i}`}, ${tex`N ≡ +1 \pmod {p_i^{e_i}}`}

We can think of these weight classes as representing systems which choose k elements from a factor set with cardinality ω.
`
Insert cell
md`
Binomial theorem:
${tex.block`(x + y)^n = \sum_{i=0}^n \binom{n}{i} x^i y^{n-i}`}

Freshman's dream:

For all ${tex`p ∈ ℙ`}:

${tex.block`(x + y)^p ≡ x + y ≡ x^p + y^p \pmod{p}`}

`
Insert cell
{
const rns = ResidueNumberSystem.of(5,11,29)
return rns.weights.show()
}
Insert cell
// TODO implement partial factorization class... build residue system on top
// (assert coprimality? not strictly necessary)
class ResidueNumberSystem {
constructor(moduli) {
this.moduli = IntegerList.from(moduli);
}

static of(...args) {
return new ResidueNumberSystem(args);
}

// dynamic range, cardinality of the set of unique representatives
get size() {
if (this._size) return this._size;
return (this._size = this.moduli.lcm());
}

prod() {
if (this._prod) return this._prod;
return (this._prod = this.moduli.prod());
}

// https://krex.k-state.edu/dspace/bitstream/handle/2097/14111/AvikSengupta2012.pdf?sequence=3&isAllowed=y
get weights() {
if (this._weights) return this._weights;

// elements M_i: M_r / m_i, where m_i is ith element of moduli set
// elements T_i: multiplicative inverse M_i mod m_i
// N = ∑[i..] r_i T_i M_i (mod M_r)

// weight vector components appear to be idempotent elements, at least for hall-divisor-set systems?
// 2^ω hall divisors, and 2^ω idempotents
const M_r = this.size; // M/m_i * (M/m_i)^-1 (mod M)
return (this._weights = this.moduli.map((m_i) =>
M_r.divide(m_i).times(M_r.divide(m_i).modInv(m_i)).mod(M_r)
));
}

// forward conversion: conversion from conventional number to RNS rep
get(n) {
return new ResidueNumber(n, this);
}

// reverse conversion: conversion from RNS rep to conventional number
// TODO not right...
index(residues) {
const moduli = this.moduli;
const prod = this.prod();
let i = 0;
let terms = [];
for (let x_i of residues) {
const m_i = moduli[i];
const M_i = Value.Natural.from(prod.divide(m_i));
const M_i_inv = Value.Natural.from(M_i.powmod(-1, m_i));
terms.push(Value.Natural.from(M_i_inv.mul(x_i).mod(m_i)).mul(M_i));
++i;
}
return terms;
}

// repr (n) {
// n = new Integer(n)
// n.mod()
// }

representations() {
const max = Math.min(2000, 1 + this.size);
const reps = [];
for (let n = 0; n < max; ++n) {
const rs = this.moduli.map((m) => Integer.from(n).mod(m));
reps.push(rs);
// bail early if we hit a zero
if (n > 0 && rs.every((r) => +r === 0)) {
return reps;
}
}
return reps;
}

tabulate() {
return html`
<table>
<thead>
<th>n</th>
<th>${this.moduli.join("</th>\n<th>")}</th>
<th>r_i w_i</th>
<th>r_i w_i mod m_i</th>
<th>∑ r_i w_i</th>
<th>∑ mod M</th>
<th>∑ / M</th>
</thead>
<tbody>
${this.representations().map(
(rep, n) => `<tr>
<th>${n}</th>
<td>${rep.join(`</td>\n<td>`)}</td>
<td>${rep.map((m, i) => m.times(this.weights[i]))}</td>
<td>${rep
.map((m, i) => m.times(this.weights[i]))
.mod(this.moduli)}</td>
<td>${rep.map((m, i) => m.times(this.weights[i])).sum()}</td>
<td>${rep
.map((m, i) => m.times(this.weights[i]))
.sum()
.mod(this.size)}</td>
<td>${rep
.map((m, i) => m.times(this.weights[i]))
.sum()
.divide(this.size)}</td>
</tr>`
)}
</tbody>
</table>
`;
}
}
Insert cell
{
const rns = new ResidueNumberSystem([2,3,5])
return rns.get(14).toTex()
// 0_2 2_3 4_5... 0 mod 2 -1 mod 3 -1 mod 5 ... (2n)(3n+2)(5n+4) mod (2*3*5) = [ℤ/30ℤ : 14]
/*
TODO an rns instance can be represented on phideal cone...
each modulus associated with a specific column
each residue element
*/
}
Insert cell
{
const rns = new ResidueNumberSystem([5,11,13,43])
return rns.get(16).toTex()
}
Insert cell
{
const rns = ResidueNumberSystem.of(11,13,29)
// return rns.index([1,5,3,16])
return rns.get(315).toTex()
}
Insert cell
tex`${ResidueNumberSystem.of(11,13,29).weights}`
Insert cell
(Value.Natural.from(13)).powmod(-1,58)
Insert cell
ResidueNumberSystem.of(3*5,7,11).weights.show()
Insert cell
// ex_rns.weights.show()
ex_rns.weights[0].times(17 % 5)
Insert cell
169**3 % (5*13*17)
Insert cell
((5*13*17-715)**4) % (5*13*17)
Insert cell
Integer(183 * 463).mod(5*13*17)+0
Insert cell
ex_rns.get(47**1).toTex()
Insert cell
1105+((1-885)%1105)
Insert cell
Integer(885+1).modInv(5*13*17)
Insert cell
Integer(29).modInv(3*5*7)
Insert cell
(105 - (8 + 1/105))
Insert cell
/*
idempotents mod 5*13*17:
- 5,13,17: 221,170,715
- 5,13*17: 221,885
- 5*13,17: 391,715
- 5*17,13: 936,170
0: 0 0 0 1
715: 0 0 1 17
170: 0 1 0 13
885: 0 1 1 13*17
221: 1 0 0 5
936: 1 0 1 5*17
391: 1 1 0 5*13
1: 1 1 1 5*13*17

thus, negatives of idempotents are involutions:
(-1,0,-1)^2 gives (1,0,1) ... that is, 169^2 gives 936 mod 5*13*17...
thus, 169^3 (and any other odd *positive* power) will give 169
but cannot be taken to a *negative* power -- no inverse, due to 0 coefficients in factor(s)

1 - idempotent flips "bits" (when viewing idempotent as bits
in terms of associated factors, represents M / factor_vector
idempotent - 1 gives flips "bits", and gives basis complement... equal to -(1 - idempotent)

1 + idempotent gives "bits" plus 1 in RNS (e.g. 1,1,0,1,0 becomes 2,2,1,2,1)
mod inverse should always exist (for odd modulus) since all factor wheels get rolled up, no zeros
easy to calculate, as inverse of 1 is trivial, 2 has simple closed form...

when summing product of residues with idempotents
the latter must serve to isolate the residue "wheels" for the appropriate factors
you could probably use any (coprime) scale factor to modify ordering but get same dynamic range
for some factor k, 0,0,0 -> k,k,k -> 2k,2k,2k -> ...
this would look precisely like the mod(kc,x) "phideal" stripes in the mod cone
"orbits" can be stabilized by k^-1 (mod c), giving some kind of pseudo-unit?
addition in residue wheels behaves identically to scalar multiplication?
multiplying any sqrt by set of unital sqrts gives all sqrts...
this is just scalar multiplication of (±1,...) vectors
which should look like a "rotation" by the rk, where r is sqrt instance scalar
what does this look like in terms of mixed fraction repr?

*/
Insert cell
Integer(885).modInv(13*17)
Insert cell
(7324)%Number(ex_rns.size.value)
Insert cell
(9*771 + 163*925 + 64*826 + 79*946 + (1*385 + 4*231 + 2*330 + 9*210)) % 1155
Insert cell
(999*1155 + (1 - 715)) % 1155
Insert cell
/*

1,0,0,0: 385 = 1 - 771
0,1,0,0: 231 = 1 - 925
0,0,1,0: 330 = 1 - 826
0,0,0,1: 210 = 1 - 946

pairwise orthagonal idempotents, summing to 1 with above pairing
0,1,1,1: 771 = 1 - 385 ... 385 * 2 + 1
1,0,1,1: 925 = 1 - 231 ... 231 * 4 + 1
1,1,0,1: 826 = 1 - 330
1,1,1,0: 946 = 1 - 210

take a random element, say index 394: 1,4,2,9
394 mod 3,5,7,11 = 1*385 + 4*231 + 2*330 + 9*210 = 385 + 924 + 660 + 1890 = 3859 mod 1155 = 394

394 mod 3,5*7*11 = 1*385 + 9*771 = 7324 mod 1155 = 394
394 mod 5,3*7*11 = 4*231 + 163*925 = 151699 mod 1155 = 394
394 mod 7,3*5*11 = 2*330 + 64*826 = 53524 mod 1155 = 394
394 mod 11,3*5*7 = 9*210 + 79*946 = 76624 mod 1155 = 394

sums of first column above must yield 394 mod 1155
we can rewrite weights of second column in terms of first column
1*385 + 9*771 = 1*385 + 9*(1-385) = 1*385 + 9*1 - 9*385 = 9 - 8*385
but meh...

can also be formulated:
[385,231,330,210]^T • [1,4,2,9] ... mod (3,5,7,11)
[385,771]^T • [1,9] ... mod (3,5*7*11)
[231,925]^T • [4,163] ... mod (5,3*7*11)
[330,826]^T • [2,64] ... mod (7,3*5*11)
[210,946]^T • [9,79] ... mod (11,3*5*7) ... (9,79) mod (11,105) = 394 mod 1155
[394]^T • [1,4,2,9] ... mod (3*5*7*11) ... (394) mod 1155

complete set of idempotents in RNS 3*5*7*11
1000: 385
0111: 771
0100: 231
1011: 925
0010: 330
1101: 826
0001: 210
1110: 946
1100: 616
0011: 540
1001: 595
0110: 561
1010: 715
0101: 441
0000: 0 (...or 1155?)
1111: 1

paths to 1156:
0000+1111 1155+1
0001+0010+0100+1000 210+330+231+385

0001+0110+1000 210+561+385
0001+0010+1100 210+330+616
0001+0100+1010 210+231+715
0010+0100+1001 330+231+595
0010+0101+1000 330+441+385
0011+0100+1000 540+231+385

0001+1110 210+946
0010+1101 330+826
0100+1011 231+925
0111+1000 771+385

0011+1100 540+616
0101+1010 441+715
0110+1001 561+595


run length encoding of integer compositions
https://oeis.org/wiki/Orderings_of_compositions#Binary_representation_ordering_of_the_compositions
maps to ordered prime signature
decreasing lex order for the 2^(k-1) integer compositions for k=5:
(5)
(4,1) (3,2) (2,3) (1,4)
(3,1,1) (2,2,1) (2,1,2) (1,3,1) (1,2,2) (1,1,3)
(2,1,1,1) (1,2,1,1) (1,1,2,1) (1,1,1,2)
(1,1,1,1,1)
partitions (unique compositions after sorting)
(5)
(4,1) (3,2)
(3,1,1) (2,2,1)
(2,1,1,1)
(1,1,1,1,1)
*/
Insert cell
ex_rns.weights.show()
Insert cell
1155-274
Insert cell
[
386, 769,
694, 461,
496, 659,
736, 419,
274, 881,
34, 1121,
76, 1079,
1154, 1,
].map((u) => `${u}: ${(((1+u)*(1-u)/4) % 1155) * 4 / 1155}`)

Insert cell
// involution/idempotent correspondance:
// https://en.wikipedia.org/wiki/Idempotent_(ring_theory)#Relation_with_involutions

// if a is an idempotent of the endomorphism ring...
// then the endomorphism f = 1 − 2a is an R module involution of M
// that is, f is an R homomorphism such that f^2 is the identity endomorphism of M
// (is this just a fancy way of f is a square roots of the identity?)
// TODO relation w/ the metric, mass function in https://arxiv.org/pdf/1802.02263.pdf
// metric: f(r) = 1 - 2 m(r)/r
// mass function: m(r) = r/2 (1 - f(r))
// where it can be helpful to interpret m(r) as total mass inside radius r
// or rather, associated with surface of sphere of radius r?

// an idempotent element a of R and its associated involution f gives rise to two involutions of the module R,
// depending on viewing R as a left or right module...
// (this seems to suggest that sign/parity split below is related to commutativity?)

// this process can be reversed if 2 is an invertible element of R:
// if b is an involution then 2^−1 (1−b) and 2^−1 (1+b) are orthogonal idempotents
// (complementary projectors as general clifford numbers, e.g. https://en.wikipedia.org/wiki/Paravector)
// TODO even better: https://arxiv.org/pdf/1905.08102.pdf

// 2^-1 = 578
Integer(2)
.modInv(1155)
.times(1 + 386)
.mod(1155) //.plus(1155)

// 386 (1,3) : -,+,+,+ 1̅111 386 = 771-385 = 770-384
// 2^-1 (1-386) -> 385 : 1,0,0,0 -770 1̅000 11000 24
// 2^-1 (1+386) -> 771 : 0,1,1,1 +771 0111 00111 7
// 769 (3,1) : +,-,-,- 11̅1̅1̅
// 2^-1 (1-769) -> 771 : 0,1,1,1 -384 01̅1̅1̅ 10111 23
// 2^-1 (1+769) -> 385 : 1,0,0,0 +385 1000 01000 8
// 770/2 ^^^

// 694 (3,1) : +,-,+,+ 11̅11 694 = 925-231 = 924-230
// 2^-1 (1-694) -> 231 : 0,1,0,0 -924 01̅00 10100 20 -924 = -[ 0,-1, 0, 0]
// 2^-1 (1+694) -> 925 : 1,0,1,1 +925 1011 01011 11 +925 = +[ 1, 0, 1, 1]
// 461 (1,3) : -,+,-,- 1̅11̅1̅
// 2^-1 (1-461) -> 925 : 1,0,1,1 -230 1̅01̅1̅ 11011 27 -230 = -[-1, 0,-1,-1]
// 2^-1 (1+461) -> 231 : 0,1,0,0 +231 0100 00100 4 +231 = +[ 0, 1, 0, 0]
// 462/2 ^^^

// 496 (3,1) : +,+,-,+ 111̅1 496 = 826-330 = 825-329
// 2^-1 (1-496) -> 330 : 0,0,1,0 -825 001̅0 10010 18 -825 = -[ 0, 0,-1, 0]
// 2^-1 (1+496) -> 826 : 1,1,0,1 +826 1101 01101 13 +826 = +[ 1, 1, 0, 1]
// 659 (1,3) : -,-,+,- 1̅1̅11̅
// 2^-1 (1-659) -> 826 : 1,1,0,1 -329 1̅1̅01̅ 11101 29 -329 = -[-1,-1, 0,-1]
// 2^-1 (1+659) -> 330 : 0,0,1,0 +330 0010 00010 2 +330 = +[ 0, 0, 1, 0]
// 660/2 ^^^

// 736 (3,1) : +,+,+,- 1111̅ 736 = 946-210
// 2^-1 (1-736) -> 210 : 0,0,0,1 -945 0001̅ 10001 17
// 2^-1 (1+736) -> 946 : 1,1,1,0 +946 1110 01110 14
// 419 (1,3) : -,-,-,+ 1̅1̅1̅1
// 2^-1 (1-419) -> 946 : 1,1,1,0 -209 1̅1̅1̅0 11110 30
// 2^-1 (1+419) -> 210 : 0,0,0,1 +210 0001 00001 1
// 420/2 ^^^

// 274 (2,2) : +,-,+,- 11̅11̅ 274 = 715-441
// 2^-1 (1-274) -> 441 : 0,1,0,1 -714 01̅01̅ 10101 21
// 2^-1 (1+274) -> 715 : 1,0,1,0 +715 1010 01010 10
// 881 (2,2) : -,+,-,+ 1̅11̅1
// 2^-1 (1-881) -> 715 : 1,0,1,0 -440 1̅01̅0 11010 26
// 2^-1 (1+881) -> 441 : 0,1,0,1 +441 0101 00101 5
// 882/2 ^^^

// 34 (2,2) : +,-,-,+ 11̅1̅1 34 = 595-561
// 2^-1 (1-34) -> 561 : 0,1,1,0 -594 01̅1̅0 10110 22
// 2^-1 (1+34) -> 595 : 1,0,0,1 +595 1001 01001 9
// 1121 (2,2) : -,+,+,- 1̅111̅
// 2^-1 (1-1121)-> 595 : 1,0,0,1 -560 1̅001̅ 11001 25
// 2^-1 (1+1121)-> 561 : 0,1,1,0 +561 0110 00110 6
// 1122/2 ^^^

// 76 (2,2) : +,+,-,- 111̅1̅ 76 = 616-540
// 2^-1 (1-76) -> 540 : 0,0,1,1 -615 001̅1̅ 10011 19
// 2^-1 (1+76) -> 616 : 1,1,0,0 +616 1100 01100 12
// 1079 (2,2) : -,-,+,+ 1̅1̅11
// 2^-1 (1-1079)-> 616 : 1,1,0,0 -539 1̅1̅00 11100 28
// 2^-1 (1+1079)-> 540 : 0,0,1,1 +540 0011 00011 3
// 1080/2 ^^^

// 1154 (0,4) : -,-,-,- 1̅1̅1̅1̅ 1154 = 1155-1 = 1154-0
// 2^-1 (1-1154)-> 1 : 1,1,1,1 -1154 1̅1̅1̅1̅ 11111 31
// 2^-1 (1+1154)-> 0 : 0,0,0,0 +1155 0000 00000 0
// 1 (4,0) : +,+,+,+ 1111
// 2^-1 (1-1) -> 0 : 0,0,0,0 -0 0̅0̅0̅0̅ 10000 16
// 2^-1 (1+1) -> 1 : 1,1,1,1 +1 1111 01111 15
// 2/2 ^^^

// ***
// for each pair of involutions (±√1 elements)
// there is an even element u_e and an odd element u_o
// 1 ± u_e and 1 ± u_o generate 4 distinct idempotent
// these values actually generate twice each idempotent
// 2 P_u = 1 - u
// 1 - u_e, 1 - u_o idempotent elements always considered negative
// 1 + u_e, 1 + u_o idempotent elements always considered positive
// 1 + u_e is really just 1 - (-u_e)
// where the complement of u_e is treated separately from u_o
// key invariant for these 4 associated idempotent elements:
// sign and parity must be preserved through squaring
// introduces an extra bit for the sign during calculation
// but this is inferrable from idempotent u element parity and sign
// another invariant is in idempotent "shape"
// totality of elements within each component modulus across all 4 idempotents:
// should exactly 1, 1̅ each, and two 0s
// perhaps better to just use a sign bit

// does this hold for general squarefree odd moduli?
// * P_{1-u_e} : max neg
// * P_{1+u_e} : max pos
// * P_{1-u_o} : min neg
// * P_{1+u_o} : min pos

// ...
Insert cell

// perhaps idempotent elements
// ...

// each unital sqrt u is one with RNS rep with all elements ±1,±1,±1,±1
// each u is associated with exactly one pair P^± of idempotents: (1+u)/2 and (1-u)/2
// idempotent pairs (1+u)(1-u), when multiplied together, always give -0?
// except for the positive trivial idempotent 1, where as (1-1)(1+1) never reaches into negatives
// parity between unsigned values in each P^± pair always the same (except at trivial idempotents)
// sign and parity of signed values in each P^± pair always differ (except at trivial idempotents)
// each u has a complement, u̅ -- another unital sqrt with its own pair of idempotents
// for odd modulus: complement always has opposite parity
// for even modulus: complement always has same parity

// each sqrt and its complement have a related pair of idempotents...
// the two are similar but not the same: 16 *distinct* pairs of idempotents, one per u -- 32 total
// P^- = (1-u), P^+ = (1+u)
// P̅^- = (1-u̅), P̅^+ = (1+u̅)
// one way to think of this as something like -1 * P^+ = P̅^-
// the overbar "negative" can be lifted out linearly to a -1 times positive projector
// we can extend our factor base with -1 as "prime at ∞"
// signed component vector of each idempotent can be encoded in dimished 2s-complement
// in this form, sum of base 2 values must equal 2^5 (for 4 factors)
// except for trivial idempotents, where things get crossed up
// existing allocation is somewhat arbitrary

// 1 of 4 items in every pair of pairs will be even and positive...
// this will be the P^+ value associated with the odd unital divisor
// this suggests odd unital divisor of pair could be called primary root u, with u̅ being even

// for odd unital sqrt, multiplying 1±u will give a doubly-even value...
// so should also be possible to pre-divide by 4, rather than using 2^-1
// this should never be true of the even unital sqrts
// though taking a look at 2^-1 mod 1155... in RNS this is [2,3,4,6], or ([0,0,0,0] - 1)/2 + 1
// why not allow a *half*-unit? spin 1/2? why not a third-unit (e.g. eisensteinians)?

// https://en.wikipedia.org/wiki/Idempotent_(ring_theory)#Lattice_of_idempotents
// very possible all of these parity shenanigans just accounts for lattice order direction

/*

root system

TODO sqrts of 4 vs. 4^-1 inverse at x=2 ... relation to dual space?
- square of any odd number is always 1 mod 4... ±1?
- square of any even number is always 0 mod 4
- justifies calling all even roots "negative" (for odd M, at least... which forces them odd)?
- what about roots which start in negative range? next square is 4...
- and a linear step would take an odd root at x=1 (for √1) to an even root at x=2 (for √4)

as RNS vector, principle √4 looks like [2,2,2,2]
a few others: 152: [2,2,2̅,2̅], 163: [2̅,2̅,2,2̅]
as RNS vector, (√4)^-1 almost looks like this: [½,½,½,½]
where -(√4)^-1 might be: [½̅,½̅,½̅,½̅]... or some such...
the point being, the RNS digits are *dead center* of relative modulus ±1/2


u + u̅ = M ~= 0


u = u^-1
this can't be true of projectors as they have no inverse (as zero divisors)


u^+ 769 11̅1̅1̅ = 1000 - 0111 = 1000 + 01̅1̅1̅
2^-1 (1-769) -> -384 -01̅1̅1̅
2^-1 (1+769) -> +385 +1000 385 - -384 = 769
u^- 386 -1̅111 = 0111 - 1̅000 = -11̅1̅1̅ = -(1000 - 01̅1̅1̅) = 01̅1̅1̅ - 1000
2^-1 (1-386) -> -770 -1̅000
2^-1 (1+386) -> +771 +0111 771 - -770 = 1541 = M + 386


+u = +461 (1 - +u)/2 = -230 (1 + +u)/2 = +231
+u̅ = +694 (1 - +u̅)/2 = -924 (1 + +u̅)/2 = +925
-u = -461 (1 - -u)/2 = +925 (1 + -u)/2 = +925
-u̅ = -694 (1 - -u̅)/2 = +925 ...TODO this is obviously off...


u +461 +1̅11̅1̅
(1-u)/2 -> -230 -1̅01̅1̅ = (1-√D)/2
(1+u)/2 -> +231 +0100 = (1+√D)/2
u̅ +694 +11̅11
(1-u̅)/2 -> -924 -01̅00 = (1-√D)/2
(1+u̅)/2 -> +925 +1011 = (1+√D)/2 ...TODO what's √D here? discriminant?


u = 461 = 1 − 2p ... -460/2 = p
u = 1̅11̅1̅ = 1 - 2p = 1 - 2()

√-924 = √231 = {231, 924}
√-230 = √925 = {155, 230, 265, 505, 650, 890, 925, 1000}



u^- : 496 111̅1 ... 0 111̅1
p^- : -825 -001̅0 1̅ 001̅0
p^+ : +826 +1101 1 1101
u^+ : 659 1̅1̅11̅ 0 1̅1̅11̅
p^- : -329 -1̅1̅01̅ 1̅ 1̅1̅01̅
p^+ : +330 +0010 1 0010

u^- 736 1111̅
2^-1 (1+736) -> +946 1110
2^-1 (1-736) -> -945 0001̅
u^+ 419 1̅1̅1̅1
2^-1 (1+419) -> +210 0001
2^-1 (1-419) -> -209 1̅1̅1̅0

u^- 274 11̅11̅
2^-1 (1+274) -> 715 1010
2^-1 (1-274) -> 714 01̅01̅
881 1̅11̅1
2^-1 (1+881) -> 441 0101
2^-1 (1-881) -> 440 1̅01̅0

34 +--+ 11̅1̅1 = 1001-0110
2^-1 (1+34) -> 595 1001
2^-1 (1-34) -> 594 01̅1̅0
1121 -++- 1̅111̅ = 0110-1001
2^-1 (1+1121)-> 561 0110
2^-1 (1-1121)-> 560 1̅001̅

76 ++-- 111̅1̅ = 1100-0011
2^-1 (1+76) -> 616 1100 616 1100 =
2^-1 (1-76) -> 540 0011 615 001̅1̅ = 1100-1111 = (1111-111̅1̅)/2
1079 --++ 1̅1̅11 = 0011-1100
2^-1 (1+1079)-> 540 0011 540 0011
2^-1 (1-1079)-> 616 1100 539 1̅1̅00 = 0011-1111 = (1111-1̅1̅11)/2

1154 ---- 1̅1̅1̅1̅
2^-1 (1-1154)-> 1 1111 1154 1̅1̅1̅1̅ 11111 31 00001111
2^-1 (1+1154)-> 0 0000 0 ?? 0000 00000 0 11110000
1 ++++ 1111
2^-1 (1-1) -> 0 : 0000 -0 ?? 0̅0̅0̅0̅ 10000 16
2^-1 (1+1) -> 1 : 1111 +1 1111 01111 15

very clearly related to paravectors: https://en.wikipedia.org/wiki/Paravector


k̂ = 111̅1̅ = 1100-0011 = 76
2P_k = (1+76) % (3,5,7,11) = (2,2,0,0) = 77
2P̅_k = (1-76) % (3,5,7,11) = -(0,0,2,2) = -75

K̂ = 1̅1̅11 = 0011-1100 = M-k̂ = 0000-111̅1̅ = 1079
2P_K = (1+1079) % (3,5,7,11) = (0,0,2,2) = 1080
2P̅_K = (1-1079) % (3,5,7,11) = -(2,2,0,0) = -1078


P_k = ½(1+k̂)
P̅_k = ½(1-k̂)

P_k - P̅_k = k̂
P_k + P̅_k = 1

P_k P̅_k = -0


*/
Insert cell
Insert cell
"e\u0302"
Insert cell
Insert cell
(3*3*3)%12
Insert cell
Insert cell
Integer(1-461).times(1+694).mod(1155)
Insert cell
Integer(2).modInv(1155).times(1 - -461).mod(1155)//.plus(1155)
Insert cell
(1-1154)+1155
Insert cell
((1+1154)*(1-1154))%1155
Insert cell
ex_rns.weights.show()
Insert cell
ex_rns = ResidueNumberSystem.of(3,5,7) // 5,13,17 // 5,11,19
Insert cell
// X = √[ floor(X^2/c) c + mod(X^2,c) ]
// mod component is like proper fraction component...
// - invariant for any sqrt of a given square
// floor component is like whole component of mixed fraction...
// - selection of specific sqrt element determined exclusively by floor component
// - value is quotient by integer division by modulus of square of sqrt element instance
// - how to write these values in terms of RNS? or should they be base-∞ component of MRS?
Insert cell

// TODO https://observablehq.com/@tmcw/enumerating-permutations to iterate over arbitrary size?
// better would be some kind of virtual scrolling table
// from http://iml.ece.mcgill.ca/people/professors/zilic/documents/oathesis.pdf
ex_rns.tabulate()
Insert cell
// html`
// <table>
// <thead>
// <th>n</th>
// <th>${this.moduli.join('</th>\n<th>')}</th>
// <th>r_i w_i</th>
// </thead>
// <tbody>
// ${ this.representations().map((rep,n) => `<tr>
// <th>${n}</th>
// <td>${rep.join(`</td>\n<td>`)}</td>
// <td>${rep.map((m,i) => m.times(this.weights[i])) }</td>
// <td>${rep.map((m,i) => m.times(this.weights[i])).mod(this.moduli) }</td>
// <td>${rep.map((m,i) => m.times(this.weights[i])).sum() }</td>
// <td>${rep.map((m,i) => m.times(this.weights[i])).sum().mod(this.size) }</td>
// <td>${rep.map((m,i) => m.times(this.weights[i])).sum().divide(this.size) }</td>
// </tr>`)
// }
// </tbody>
// </table>
// `
Insert cell
ResidueNumberSystem.of(11, 3).weights
Insert cell
{
// TODO assertions lib
assert(+new ResidueNumberSystem([2,3,4]).size.eq(12), 'expected 12')
assert(+new ResidueNumberSystem([2,3,5]).size.eq(30), 'expected 30')
}
Insert cell
ResidueNumberSystem.of(33, 89, 147).prod()
Insert cell
ResidueNumberSystem.of(3, 5, 7, 11).tabulate()
Insert cell
// TODO fix index
// ResidueNumberSystem.of(33, 89, 147).index + ""
Insert cell
// from pp 10 of http://stanwagon.com/public/frobeniusbylatticepoints.pdf
ResidueNumberSystem.of(33, 89, 147)
Insert cell
/*
classifying available RNS systems:
* up to permutation: bell numbers...
* blocks: stirling numbers of 2nd kind
* ordered bell numbers to count permutations
...although binary repr using prime factors is actually combinadics:
https://en.wikipedia.org/wiki/Combinatorial_number_system
which gives a meaning to different orderings when enumerated (e.g. via Gosper's hack)
permutation invariance related to factoradics, lehmer code
https://oeis.org/wiki/Factorial_numeral_system
when factors taken to be square-free, relate to primoradics...
https://oeis.org/wiki/Primorial_numeral_system

given 1 distinct prime (a):
1 RNS of dynamic range a
given 2 distinct primes (a,b):
2 RNS of dynamic range ab
[a,b],[ab]
[3,5],[15]
given 3 distinct primes (a,b,c):
[a,b,c],[ab,c],[bc,a],[ca,b],[abc]
[3,5,7],[15,7],[35,3],[21,5],[105]
given 4 distinct primes (a,b,c,d):
[a,b,c, d],[ab,c,d ],[bc,d ,a],[cd,a,b],
[3,5,7,11],[15,7,11],[35,11,3],[77,3,5]

also, combinatorics of prime signatures... link?

*/
Insert cell
md`## Quadratic fields

${tex`ℚ(\sqrt{r})`}: Obtained from ℚ by adjoining a radicand element, square-free integer √r
`
// https://arxiv.org/pdf/1001.5214.pdf
Insert cell
md`
surface of constant ±curvature:
${tex.block`\sin^2\left(\frac{\pi}{2w}x^2\right)=\cos^2\left(\frac{\pi}{2h}y^2\right)`}
±\epsilon on either side makes a closed checkerboard
`
Insert cell
/*
// from https://www.math3ma.com/blog/finitely-generated-modules-over-a-pid
All finitely generated abelian groups can be classified up to isomorphism. So if you run into an abelian group of order 24, for instance, you know it's going to have the same structure as one of:
* ℤ/24
* ℤ/3 ⊕ ℤ/8
* ℤ/3 ⊕ ℤ/4 ⊕ ℤ/2
* ℤ/3 ⊕ ℤ/2 ⊕ ℤ/2 ⊕ ℤ/2
*/
Insert cell
AdditiveRing = {
class AdditiveRing {
constructor (opts) {
this.zero = opts.zero || (0)
this.unit = opts.unit || (1)
this.char = opts.char || (0)
}
}
.prototype.AdditiveRing = function () {
return new AdditiveRing({ char: this })
}
return AdditiveRing
}
Insert cell
/*

digit: defined by a ring base b and a value v, instance is an element of the set [0,b)
generated by a unit u: u+u = 2u, u+u+u = 3u, u+u+...+u, b times: 0
base ~= ring characteristic
*/
class Digit extends Value {
constructor (opts) {
if (opts.value == null) throw new Error('Digit value required')
super(opts.value)
this.value = (opts.value)
this.base = (opts.base)
}
static of (value, base = 10) {
return new Digit({ value, base })
}
ring () {
return this.base.AdditiveRing()
}
toTex () {
return `${this.value.toTex()}_{${this.base.toTex()}}`
// NB omit subscript for base 10?
// return `${this.base}${this.base.eq(10) ? '' : `_{${this.base.show()}}`}`
}
// TODO allow base ring to take an alphabet of character reps
// each rep gets a distinct index... it's "order"
// can work with char reps directly, or their indices (isomorphism classes?)
}

/*
dirichlet character: like a digit, but sums to 1

*/
Insert cell
Digit.of(13,31).show()
Insert cell
/*
sort, rank, order in R:
https://towardsdatascience.com/r-rank-vs-order-753cc7665951
rank and order functions report on relative locations rather than relative values
range of values returned by rank and order is the range of indexes of values in the original sequence
rank: references position of value in the sorted vector, is in the same order as original sequence
order: returns position of original value and is in order of sorted sequence (smallest to largest value)
the order of the rank will always equal the rank of the order

data frame: matrix-like row/column table of data, but tracking stats, inferred types
*/
Insert cell
/*
TODO object representing congruence class modulo n
[ℤ/nℤ : k] gives index (order) of congruence class...
class itself actually represents a shifted ideal -- e.g. k+Xn (where X is any integer)
each distinct possible value of X gives a different repr of the same class...
in modular arithmetic, represents number of integral winds around the modulus
where canonical repr of congruence class -- least positive residue -- gives fractional part
what's left over after whole number of winds... analogous to an angle

Array.prototype.mod
[ 71, 5, 38 ].mod(7) == [ 1, 5, 3 ] // each element is not a number but a repr of a congruence class mod 7
// each element x_i of result vector represents x_i + 7Z

if congrugenerates a modular "vector"
just called an element of module
though if modulus is prime, represents a vector over base field Z/pZ
[ 71, 5, 38 ].div(7) == [ 10, 0, 5 ] // what are these guys called? the winding group?
// represents the integer part of of `x_i / m`, i.e. `floor(x_i / m)`
// space of possible values is Z -- so result represents a vector in Z
// also, d/dx floor(-x_i / m)

[ 71, 5, 38 ].divmod(7) == [ [10,1], [0,5], [5,3] ] // these pairs fully describe the original integers
idealize
function to take a singleton element and have it represent *all* multiples


eq, lt, gt, etc. (any boolean comparators):
allow an assert method on expr node to repr as assertions
render LHS op RHS, highlight if evaluates

different kinds of div, mod, etc...
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf

*/
Insert cell
// TODO: this is a goofy way to define this, but...
class LegendreSymbol extends Digit {
// p a prime, a an element of multiplicative group mod p
constructor (a, p) {
super({ base: p, value: a })
}
// value: a^((p-1)/2)^((p-1)/2)
// equal to 1 if a is a quadratic residue modulo p
// equal to -1 if a quadratic non-residue modulo p
// ... 0 if a divides p (by some definitions, e.g. http://www.math.leidenuniv.nl/~psh/ANTproc/02buhler.pdf)
// identities:
// (2|p) = (-1)^((p^2-1)/8)
// implies that 2 is a quadratic residue modulo p iff p ≡ ± 1 mod 8
// TODO: Atkin's square root algo...
// https://pdfs.semanticscholar.org/30a8/15db8aa4d811414bd44848992ee82fb20aca.pdf
}

/*

quadratic reciprocity:
(a|b)(b|a) = (-1)((a-1)(b-1)/4), a,b odd

JacobiSymbol:

- generalizes the Legendre symbol and is defined, for an integer a and a positive odd positive integer b
by reverting to the Legendre symbol when b is an odd prime
- multiplicative in both the numerator and denominator,
- depends only on a mod b
- obeys the famous law of quadratic reciprocity

supplemental identities:
(-1|b) = (-1)^((b-1)/2)
(2|b) = (-1)^((b^2-1)/8)

idempotents in ℤ𝑛
correspond to factorizations of 𝑛 into two coprime factors
https://math.stackexchange.com/questions/175963/idempotents-in-mathbb-z-n
https://en.wikipedia.org/wiki/Peirce_decomposition

two-sided pierce decomposition:
writes A as the direct sum of eAe, eA(1−e), (1−e)Ae, and (1−e)A(1−e)
left decomposition:
writes A as the direct sum of eA and (1−e)A
right decomposition:
writes A as the direct sum of Ae and A(1−e)


a(−1) ≡ a^(φ(n)−1) (mod n)


modular square root methods:
https://www.rieselprime.de/ziki/Modular_square_root
python ipmlementations: https://projecteuler.chat/viewtopic.php?t=3506#p37848
https://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python



group theory:
https://www.youtube.com/watch?v=vYKdh5oQ4Zw&list=PLi01XoE8jYoi3SgnnGorR_XOW3IcK-TP6&index=8

NormalSubgroup: 5Z
normal subgroup of Z
also the coset 0+5Z
Coset: 2+5Z
e.g. congruence classes mod n
if shift is not 0
QuotientGroup: Z/5Z
*not* a subgroup of Z -- it's an entirely different group

adding cosets
(1+5Z) + (3+5Z) = 4+5Z

for an arbitrary group G and subgroup N
we can use N to generate a collection of non-overlapping cosets
N is a subgroup -- other cosets are simply sets
the collection of all cosets do not always form a group
when they don't, N is not a NormalSubgroup
thus, we cannot make a QuotientGroup (G/N?)
iff N a normal subgroup:
for any element y in G:
y^-1 N y = N
group of cosets is called FactorGroup, written G/N
in FactorGroup, the subgroup N is the identity element
inverse of xN is x^-1 N
SimpleGroup
only NormalSubgroup of group G is {e} and G
simple groups do not have any factor groups
they are the building blocks of other groups
as prime numbers are building blocks of integers
CyclicGroup
generated by a single element
Integers Z: infinite cyclic group
any abelian group that is finitely generated
can be broken into a finite number of cyclic groups
every cyclic group is either Z or Z/nZ


Homomorphism
mapping between groups which preserves the group structure
sends identities to identites and inverses to inverses
does not have to be invective nor surjective
if both (bijective), called an Isomorphism
Kernel: measures the degree to which a homomorphism is not injective (one-to-one)
if kernel contains more than one element, there is more than one element mapping to identity
kernel is a property of the homomorphism, not the groups
kernel is a subset of G, but also a subgroup

Order
given a group G with identity e
the order of x \in G is smallest positive integer n such that x^n = e
notation: |x| = n
if there is no such n, we say x has infinite order
order of the identity element in *any* group is 1
GL_2(R) -- general linear group of 2x2 matrices...
this rotation matrix has order 12:
3/√2 -1/2
1/2 3/√2
competing notions of "order"


MaximalNormalSubgroup
no bigger proper normal subgroup in G
*/
Insert cell
/*
Kepler's laws of planetary motion
https://en.wikipedia.org/wiki/Kepler%27s_laws_of_planetary_motion

1. the orbit of a planet is an ellipse with the Sun at one of the two foci
2. a line segment joining a planet and the Sun sweeps out equal areas during equal intervals of time
3. square of the orbital period of a planet is directly proportional to the cube of semi-major axis of its orbit

eccentricity:
e = 0: circle
0 < e < 1: ellipse (an ellipse which is not a circle)
e = 1: parabola
e > 1: hyperbola

e can be defined in terms of intersection of a plane and a double-napped cone associated with the conic section
if cone is oriented with its axis vertical, the eccentricity is:
e = sin(β) / sin(α)
where β is the angle between the plane and the horizontal
and α is the angle between the cone's slant generator and the horizontal
for β=0, the plane section is a circle
for β=α, the plane section is a parabola
the plane must not meet the vertex of the cone
e can also be defined as ratio of the linear eccentricity c to the semimajor axis a
e = c / a
c: linear eccentricity of an ellipse or hyperbola: distance between its center and either of its two foci

conic section equation eccentricity (e) linear ecc (c)
circle x^2 + y^2 = r^2 0 0
ellipse x^2/a^2 + y^2/b^2 = 1 √(1 - b^2/a^2) √(a^2 - b^2)
parabola x^2 = 4ay 1 ∞
hyperbola x^2/a^2 - y^2/b^2 = 1 √(1 + b^2/a^2) √(a^2 + b^2)

parabola, alt:
x^2/(4ay) = 1
y = x^2/4a
x = ±2√a√y
(x - 2√a√y)(x + 2√a√y) = 0


object in free fall (inertial body) experiences no forces, moves along a geodesic
in "natural" time units, distance from origin iterates perfect squares: 0,1,4,9,16,...
distance traveled in a given time step iterates odd naturals: 1,3,5,7,...
*/
Insert cell
Insert cell
import {primes} from '@mourner/fast-prime-generator'
Insert cell
Insert cell
itertools = require('https://bundle.run/itertools@1.3.2')
Insert cell
// generator prototype utils
// TODO do this in a way to force it to run before anything else?
// or better yet, just mix these into relevant helpers
init = {
const Generator = Object.getPrototypeOf(function* () {})

Generator.prototype.take = function (n) {
return [...itertools.itake(n, itertools.icompact(this))]
}

Generator.prototype.filter = function* (test) {
let result, index = -1
while (!(result = this.next()).done) {
if (test(result.value, ++index)) {
yield result.value
}
}
}
Generator.prototype.repeat = function* (times = Infinity) {
for (let i = 0; i < times; i++) {
yield* this
}
}

return Generator.constructor
}
Insert cell
init, primes().filter((n) => n % 4 === 1).take(5)
Insert cell
123, 'hello'
Insert cell
tex`ℤ/0ℤ ≅ ℤ`
Insert cell
/*
spin space
https://youtu.be/CdstICEbJyU?list=PLDlWMHnDwylijo0yfs3xUN9ad6-YZjPLT&t=4849

given D dimensional space, there are floor(D/2) indepdendent 2D planes
you can define 2-component spinners in each 2D independent plane...
in 10D you can define 5 independent planes...
so you have 2^5 components to your overall spinner

e.g. 6D: UVWXYZ: UV,WX,YZ, each can have 2-component spinners
* taken together, this allows for spinners with 2^3 = 8 overall components
* in terms of RNS...
* each pair of axes maps to a specific factor
* most granular of which would be an individual prime per plane (axis pair)
* makes sense in terms of imaginary elements mod p...
* even for those p which are -1 mod 4 have imaginary elements, just no imaginary unit elements
* can any quadratic residue can be interpreted as either a positive or negative element
* its square roots could be interpreted as either as pos or neg real or imag elements...
* except the 2^(D/2) square roots of 1, perhaps?
* and what of the quadratic nonresidues? associated w/ the impossible numbers?
* regardless, each facter has 2D plane for 2 spinner components

* https://youtu.be/vwSw8oH18Q4?list=PLDlWMHnDwylijo0yfs3xUN9ad6-YZjPLT&t=1354
* generators given by commutators for gamma matrices: boosting and rotating about x,y,z axes
* or rather, about the corresponding planes (which generalizes)

* klein gordon: https://youtu.be/pNEmmd9Mx5g?list=PLDlWMHnDwylijo0yfs3xUN9ad6-YZjPLT&t=1532
(mc)^2 𝛟 - ℏ^2 ∂_μ ∂^μ 𝛟 = 0

degrees of freedom:
https://youtu.be/pNEmmd9Mx5g?list=PLDlWMHnDwylijo0yfs3xUN9ad6-YZjPLT&t=1656
w/ respect to a particle
phase space typically twice as big as config space
w/ respect to a field
...

https://en.wikipedia.org/wiki/Ore_condition
eerily similar process of gauging a field (localizing a global symmetry by constructing covariant D)
relevant for non-commutative case of localization (introducing a field of fractions)
https://en.wikipedia.org/wiki/Localization_(commutative_algebra)#Non-commutative_case
microlocalization: https://en.wikipedia.org/wiki/Microlocal_analysis
see also: https://en.wikipedia.org/wiki/Invariant_basis_number

**** TODO explore...
weak interactions
cabibbo angle/CKM matrix for W^± mixing...
https://youtu.be/07WbjY1yh94?list=PLDlWMHnDwyljrnVxoGoBkHclt3VEkP0Kf&t=3566
weinberg angle θ_W interpretation
https://youtu.be/07WbjY1yh94?list=PLDlWMHnDwyljrnVxoGoBkHclt3VEkP0Kf&t=4414
Z^0 vertex factor projection functions for each family...
TODO reverse these bitches and write in terms of modsqrt field?
m_W / m_Z = cos(θ_W)
https://youtu.be/07WbjY1yh94?list=PLDlWMHnDwyljrnVxoGoBkHclt3VEkP0Kf&t=4593
summary of states/propagators/factors
https://youtu.be/lA5YqBc9znM?list=PLDlWMHnDwyljrnVxoGoBkHclt3VEkP0Kf&t=36

parity transform/vector/axial reprs
https://youtu.be/lA5YqBc9znM?list=PLDlWMHnDwyljrnVxoGoBkHclt3VEkP0Kf&t=1854

also: https://youtu.be/VDSirxP9V-A?list=PLDlWMHnDwylijo0yfs3xUN9ad6-YZjPLT&t=2540
requires inverting an odd number of coordinates (even number is just a rotation)
momentum is a true vector... true vectors pick up minus sign under P, axial do not
P transform: momentum changes direction, spin does not

tensors on complex space
https://youtu.be/93qt-qPl0Gc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=4243
breaking up tangent manifold into holomorphic, antiholomorphic contributions:
https://youtu.be/hLMbrVeQK2E?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=820

string theory stuffs
https://youtu.be/oSlLTDGoHyY?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2500
torus, modular group:
https://youtu.be/oSlLTDGoHyY?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3302
program of twisting... closed sets of solutions, modularly invariant partition functions
https://youtu.be/TZItA7ibi1Y?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2029
only happens for particular choices of g...
very clearly related to constructability (e.g. for closed roots of unity rotations)
winding mode
https://youtu.be/TZItA7ibi1Y?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3292
winding spectrum is infinite and quantized in manner analogous to momentum spectrum
e.g. floor fn... suggests winding mode (floor) as neg derivative of momentum (mod)
relationship to translation operator in spacetime (on periodic lattice)
same thing works for rotations though...
number of additional corrections related to transformation group...
https://youtu.be/TZItA7ibi1Y?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3606
e.g. rotation by π squares to I... R^2 = I... in Z_2, so 2 correction terms...
3 terms for R^3 = I, which gives 3 correction terms, etc.
these extra "winding state" terms have generic name: twisted sector states
related to how torus gets transformed when glued
https://youtu.be/TZItA7ibi1Y?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3651
forces antiperiodic boundary conditions, causing you to lose one critical solution:
the constant solution... the center of mass motion state of the string...lost...
the twisted sector states are localizes states... they can't move
they're stuck to the origin
creates a cone: https://youtu.be/TZItA7ibi1Y?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3995
cone is flat everywhere except at the tip...
which is not just curved but singularly curve
central counting, dimensional counting
https://youtu.be/D717CqbTvvg?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2252


GUT counting
https://youtu.be/EFlh_szaFcs?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3578

BH information paradox
entropy: what we could know but choose not to know about a system
https://youtu.be/csymLIL6h9U?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=774
similar to "forgetting" a factorization in RNS...
not strictly treating it as a "hyperplane" of factors, but as its own (primary?) factor
von neuman entropy
https://youtu.be/csymLIL6h9U?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2656
given a single state vector:
forming density matrix ρ will always be an idempotent: ρ^2 = ρ
has 0 entropy, as this is full description of the system
pure state is just an ensemble where 1 state's probability is 1, everything else 0
but you can start with a pure state, break it apart, and ignore a part of it (just consider a subsytem)
https://youtu.be/csymLIL6h9U?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2997
involves construction of reduced density matrix
purification: the reversal of this process
https://youtu.be/kS_8sDgA9y4?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2542
entanglement entropy
https://youtu.be/csymLIL6h9U?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3460
connection between different forms of entropy
https://youtu.be/kS_8sDgA9y4?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=477
classical entanglement (two prob distributions which don't factorize)
https://youtu.be/kS_8sDgA9y4?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=1057
...
*/
Insert cell
{
const w = 4;
return md`
~~~
${Array.from({ length: 2 * w + 1 })
.map((_, i) => {
return 3 ** i % (2 ** w - 1);
})
.map((n) => n.toString(2).padStart(w, "0"))
.join("\n")}
~~~`;
}
Insert cell
/*
differential forms

how to build, p-form counts in D=4:
0-form: (no indices) 0000
1-form: 0,1,2,3 0001,0010,0100,1000
2-form: 01,12,23,30,20,31 0011,0110,1100,1001,0101,1010
3-form: 012,013,023,123 0111,1011,1101,1110
4-form: 1234 1111


a form should be consider as an expansion in some basis set of forms
we have components and basis forms... basis forms made up of coordinate differentials
coordinate differentials must anticommute
general form:
(A ∧ B)_{x_1...x_{p+q}} = (p+q)!/(p!q!) A_{[x_1...x_p} B_{x_{p+1}...x+{p+q}]}
p=1, q=1:
(A ∧ B)_{xy} = 2 (1/2) (A_x B_y - A_y B_x) = A_x B_y - A_y B_x
p=1, q=2:
(A ∧ B)_{xyz} = 3 (1/6) ((A_x B_yz + A_y B_zx + A_z B_xy) - (A_x B_zy + A_y B_xz + A_z B_yx))
symmetric or anti-symmetric, depending on parity of p*q:
A ∧ B = (-1)^{pq} B ∧ A

integration
measure of integration
when you change coordinates, new measure given by jacobian on original measure

other notes...
https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=354
differential form A^(p) is a completely anti-symmetrical (0,p)-tensor
in 4D:
0-form: has 1 component... (0,0)-tensor, or scalar (in the sense of a scalar field?)
1-form: has 4 components...(0,1)-tensor, or dual vector
2-form: has 6 components...(0,2)-tensor
3-form: has 4 components...(0,3)-tensor
4-form: has 1 component... (0,4)-tensor, the "top form"

in D dimension, a p-form has choose(D,p) independent components in a totally anti-symmetric rank-p tensor
picking out distinct assignments without repetition
w/o anti-symmetrization requirement, number of independent components would actually grow
e.g. the Riemann curvature tensor is a 4-index tensor... has lots more than 1 component
B_{ij} = -B_{ji} (e.g. symmetric matrix), B_{ii} = 0 (e.g. traceless matrix)
https://youtu.be/bMs27e11trI?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=725
interesting to explore half-int binomials in relation to spinner index counting?
have nice properties for products, derivatives, integrals of differential forms
wedge product
product of p-form, q-form gives a (p+q)-form
A^(p) ∧ B^(q) -> C^(p+q)

https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=1157
to generate even permuations, do cyclic permutations
to generate odd permutations, do one flip, then do cyclic permutations of that
wedge product commutes if product of p*q is even... otherwise anti-commutes
https://youtu.be/bMs27e11trI?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=1819

exterior derivative: https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=1775

derivative of a p-form gives a (p+1)-form
taking derivative raises degree by 1
no exterior derivative of the top form
satisfies a modified leibnitz (product) rule
d(A ∧ B) = dA ∧ B + (-1)^p A ∧ dB
can take a meaningful derivative of p-forms without having to reference a metric
exterior derivative works the same on both flat and curved spaces
means you can do exterior calculus on a space w/o metric... no notion of distance... pure topology
d^2 = 0
https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2684
allows us to define difference between closed and exact forms
then you mod the space of closed forms by the space of exact forms
dimension of resulting vector space tells you about topological invariants of the space
gives you a systematic way to explore topology of spaces w/o looking at their embeddings

integral: https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=2854
a complete p-form (with components and basis vectors) contains a measure of integration over p dims
you can integrate a p-form over a p-dimensional space
the only p-dimensional spaces which arise in physics are the surfaces swept out by different objs
p-forms naturally associated with p-dimensional surfaces
a p-brane (a (p+1)-dim volume) natural couples to a (p+1)-form
p only labels the number of spatial directions
https://youtu.be/2e7CO4bp6oc?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3367

closed forms vs. exact forms
https://youtu.be/W2SzyNG-x_g?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=934
closed forms A^(p): derivative vanishes... somewhat like constant forms
exact forms B^(p): can be written as the derivative of another form
all exact forms are necessarily closed
the closed forms which aren't exact are the most interesting
https://youtu.be/W2SzyNG-x_g?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=1171
both the sets of forms are vector spaces, and we can take the quotient of two vector spaces, e.g.
ℝ^3_{xyz}/ℝ^2_{xy} ≡ ℝ^1_{z}
this just says to ignore the x and y components, and only changes in the z component matter
cohomology group H^p(M):
dimension of resulting quotient form is called the p-th Betti number
H^0(M)... p=0... can think of as a smooth function on a manifold M
gives number of disconnected components of the space
embedding spaces:
https://youtu.be/W2SzyNG-x_g?list=PLDlWMHnDwyliczXWRwjFwB5GCpi0DtB2Y&t=3513
surface of a 2-sphere can be embedded in ℝ^3 using:
x^2 + y^2 + y^2 = R^2
but try drawing x^2 + y^2 + y^2 + z^2 = R^2 ... (the 3-sphere?) embedded in ℝ^4


*/
Insert cell
/*
reparameterization symmetry
2 saddle parameterizations:
https://youtu.be/sV58Fy2s6ac?list=PL9_jI1bdZmz0hIrNCMQW1YmZysAiIYSSS&t=544
hyperbolic metric on unit disk, conformal metrics
https://youtu.be/sV58Fy2s6ac?list=PL9_jI1bdZmz0hIrNCMQW1YmZysAiIYSSS&t=3782
isometric embedding of flat torus in 3D:
https://youtu.be/sV58Fy2s6ac?list=PL9_jI1bdZmz0hIrNCMQW1YmZysAiIYSSS&t=4175
distance between any two points on that wrinkly mess...
exactly the same as the distance between corresponding points on flat square
induced area 2-form
https://youtu.be/FRvhgkGKfSM?list=PL9_jI1bdZmz0hIrNCMQW1YmZysAiIYSSS&t=2303
area 2-form dA of any immersed surface f(M):
dA = 1/2 < N,df ^ df >
when discretized on triangle mesh, just gives area of each triangle
https://youtu.be/FRvhgkGKfSM?list=PL9_jI1bdZmz0hIrNCMQW1YmZysAiIYSSS&t=3537
f describes shape of a surface patch via function:
f: M -> R^3
in terms of exterior calculus: R^3-valued differential 0-form on M
surface is embedded if no self-intersection, preserves global topology
differential "pushes forward" tangent vectors into R^3
exterior calc: differential is an R^3-valued differential 1-form
df(X) "stretches out" tangent vector X
surface is immersed if df is nondegenerate
induced metric g(X,Y) = < df(X), df(Y) >
give "true" inner product between tangent vectors *on the surface*


*/
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more