quatint 0.0.6__cp310-cp310-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: quatint
3
+ Version: 0.0.6
4
+ Summary: A quatint class, for using quaternions backed by integers and half-integers (Hurwitz integers).
5
+ Author-email: Ryan Heard <ryanwheard@gmail.com>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/rheard/quatint
8
+ Keywords: complex,math
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: sympy<=1.12.1
21
+ Dynamic: license
22
+ Dynamic: license-file
23
+
24
+ # quatint
25
+
26
+ Exact (integer-backed) quaternion arithmetic for the **Hurwitz integers**.
27
+
28
+ `quatint` provides a fast, mypyc-friendly `hurwitzint` type that behaves like a small, practical numeric object: addition/subtraction/multiplication/power, norms and conjugation, plus **left/right Euclidean division**, **left/right gcd**, and **deterministic factorization** utilities.
29
+
30
+ ## Why this exists
31
+
32
+ Python’s built-in numeric types don’t provide an exact, integer-backed quaternion type—especially not one that can represent the Hurwitz order `(a + b i + c j + d k) / 2` without floating point.
33
+
34
+ `quatint` keeps everything as integers under the hood while still letting you work with both:
35
+ - **Lipschitz integers**: $a, b, c, d ∈ Z$
36
+ - **Hurwitz “half” integers**: $(a + b i + c j + d k)/2$ with a parity constraint
37
+
38
+ ## Key features
39
+
40
+ - **Exact arithmetic** (no floats required for quaternion values)
41
+ - **Hurwitz order representation** with parity enforcement
42
+ - **Non-commutative multiplication**
43
+ - **Reduced norm** $N(q) ∈ Z$ and quaternion conjugation
44
+ - **Euclidean division** (norm-Euclidean) via:
45
+ - `divmod(a, b)` for **left-quotient** division (`a = q*b + r`)
46
+ - `a.rdivmod(b)` (or `quatint.rdivmod(a, b)`) for **right-quotient** division (`a = b*q + r`)
47
+ - **Left/right gcd** (`gcd_left`, `gcd_right`) built on the corresponding division
48
+ - **Deterministic factorization** into `content`, `unit`, and Hurwitz primes (by prime norms)
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ python -m pip install quatint
54
+ ````
55
+
56
+ This project is designed to compile cleanly with **mypyc** for speed (CI/test setups often ensure the compiled artifact is what’s running).
57
+
58
+ ## Quick start
59
+
60
+ ```python
61
+ from quatint import hurwitzint
62
+
63
+ a = hurwitzint(1, 2, 3, 4)
64
+ b = hurwitzint(2, 3, 4, 5)
65
+
66
+ print(a) # (1+2i+3j+4k)
67
+ print(a * b) # quaternion product (non-commutative)
68
+ print(b * a) # generally different
69
+ ```
70
+
71
+ ### Half-integers (Hurwitz elements)
72
+
73
+ Use `half=True` to provide numerator components of a `/2` element:
74
+
75
+ ```python
76
+ from quatint import hurwitzint
77
+
78
+ h = hurwitzint(1, 3, 5, 7, half=True)
79
+ print(h) # (1+3i+5j+7k)/2
80
+ ```
81
+
82
+ ### Division (left-quotient)
83
+
84
+ `divmod(a, b)` defines quotient on the **left**:
85
+
86
+ ```python
87
+ from quatint import hurwitzint
88
+
89
+ a = hurwitzint(2, 3, 4, 53)
90
+ b = hurwitzint(1, 2, 3, 4)
91
+
92
+ q, r = divmod(a, b)
93
+ assert q * b + r == a
94
+ ```
95
+
96
+ ### Right-division (right-quotient)
97
+
98
+ Use `rdivmod` (method or helper) to define quotient on the **right**:
99
+
100
+ ```python
101
+ from quatint import hurwitzint, rdivmod
102
+
103
+ a = hurwitzint(2, 3, 4, 53)
104
+ b = hurwitzint(1, 2, 3, 4)
105
+
106
+ q, r = rdivmod(a, b)
107
+ assert b * q + r == a
108
+ ```
109
+
110
+ ### GCD (left and right)
111
+
112
+ Because multiplication is non-commutative, there are *two* natural gcd notions:
113
+
114
+ ```python
115
+ from quatint import hurwitzint
116
+
117
+ a = hurwitzint(2, 3, 4, 53)
118
+ b = hurwitzint(1, 2, 3, 4)
119
+
120
+ gl = a.gcd_left(b) # common left divisor (a = gl*x, b = gl*y)
121
+ gr = a.gcd_right(b) # common right divisor (a = x*gr, b = y*gr)
122
+ ```
123
+
124
+ ### Factorization
125
+
126
+ Factorization returns a compact normal form:
127
+
128
+ * `content`: maximal positive integer scalar dividing the element (in the Hurwitz sense)
129
+ * `unit`: a norm-1 Hurwitz unit (deterministically chosen)
130
+ * `primes`: Hurwitz primes (each with prime rational norm), normalized via unit migration
131
+
132
+ ```python
133
+ from quatint import hurwitzint
134
+
135
+ n = hurwitzint(2, 3, 4, 53)
136
+
137
+ fr = n.factor_right()
138
+ assert fr.prod_right() == n
139
+
140
+ fl = n.factor_left()
141
+ assert fl.prod_left() == n
142
+ ```
143
+
144
+ ## Representation & guarantees
145
+
146
+ ### Internal representation
147
+
148
+ Values are stored in **numerator units**:
149
+
150
+ > `(A + B i + C j + D k) / 2`
151
+
152
+ This means:
153
+
154
+ * Lipschitz integers are stored with **even** numerators.
155
+ * True Hurwitz half-integers are stored with **odd** numerators.
156
+ * The constructor enforces the parity constraint.
157
+
158
+ ### Scalar coercions
159
+
160
+ `int` and `float` inputs are accepted as scalars and converted via `int(...)` (i.e., truncation semantics). Quaternion values themselves remain exact.
161
+
162
+ ## Public API (high level)
163
+
164
+ * `hurwitzint(a=0, b=0, c=0, d=0, *, half=False)`
165
+ * `hurwitzint.conjugate()`
166
+ * `abs(h)` → reduced norm `N(h)` (an `int`)
167
+ * `divmod(a, b)` → left-quotient Euclidean division
168
+ * `a.rdivmod(b)` / `rdivmod(a, b)` → right-quotient Euclidean division
169
+ * `a.gcd_left(b)` / `gcd_left(a, b)`
170
+ * `a.gcd_right(b)` / `gcd_right(a, b)`
171
+ * `a.factor_left()` / `a.factor_right()` → `HurwitzFactorization`
172
+ * `HurwitzFactorization.prod_left()` / `.prod_right()`
@@ -0,0 +1,10 @@
1
+ 3a49525171c7d4218706__mypyc.cpython-310-darwin.so,sha256=d7ojk4kagK1csDZa-LDGsAL2Ngu_utrwxzNm44BxlTo,442592
2
+ quatint/quat.cpython-310-darwin.so,sha256=DYWuvS3p3HFnAvjdO7CaVIvaE3d1zMCf0-pIFwwkAlI,50584
3
+ quatint/__init__.cpython-310-darwin.so,sha256=TZ6lDEaClc-LdudorMbw_V0_QjoLgTlyHwbPfVmclxU,50592
4
+ quatint-0.0.6.dist-info/RECORD,,
5
+ quatint-0.0.6.dist-info/WHEEL,sha256=11kMdE9gzbsaQG30fRcsAYxBLEVRsqJo098Y5iL60Xo,136
6
+ quatint-0.0.6.dist-info/top_level.txt,sha256=5Ii4PDUZslezIEwK0uNjzWWkUXsBRi96NKCuuYLNDGA,50
7
+ quatint-0.0.6.dist-info/METADATA,sha256=XeaEm7oRzfvTwT_wrDaw1ScafiFLAjpDeSzc_BAl8RY,5273
8
+ quatint-0.0.6.dist-info/licenses/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
9
+ quatint-stubs/quat.pyi,sha256=gyebchLIv9z7nbCbezFsiLC5Pnpm-7OnxJZIxWU7V9I,3044
10
+ quatint-stubs/__init__.pyi,sha256=QvqwCQcUL96TTqoLt-TGx36pkZMvhAmcb2QfQBhmnm8,166
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-macosx_11_0_arm64
5
+ Generator: delocate 0.13.0
6
+
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ 3a49525171c7d4218706__mypyc
2
+ quatint
3
+ quatint-stubs
@@ -0,0 +1 @@
1
+ from quatint.quat import gcd_left as gcd_left, gcd_right as gcd_right, hurwitzint as hurwitzint, prod_left as prod_left, prod_right as prod_right, rdivmod as rdivmod
quatint-stubs/quat.pyi ADDED
@@ -0,0 +1,70 @@
1
+ from _typeshed import Incomplete
2
+ from dataclasses import dataclass
3
+ from typing import ClassVar, Iterable, Iterator, Literal
4
+
5
+ OTHER_OP_TYPES = int | float
6
+ OP_TYPES: Incomplete
7
+
8
+ @dataclass(frozen=True)
9
+ class HurwitzFactorization:
10
+ content: int
11
+ unit: hurwitzint
12
+ primes: tuple['hurwitzint', ...]
13
+ direction: Literal['left', 'right']
14
+ def prod(self): ...
15
+ def prod_right(self): ...
16
+ def prod_left(self): ...
17
+
18
+ def mod_sqrt_prime(n: int, p: int) -> int | None: ...
19
+
20
+ class hurwitzint:
21
+ a: int
22
+ b: int
23
+ c: int
24
+ d: int
25
+ UNITS: ClassVar[list['hurwitzint']]
26
+ def __init__(self, a: int = 0, b: int = 0, c: int = 0, d: int = 0, *, half: bool = False) -> None: ...
27
+ @property
28
+ def is_lipschitz(self) -> bool: ...
29
+ @property
30
+ def den(self) -> int: ...
31
+ def conjugate(self) -> hurwitzint: ...
32
+ def components2(self) -> tuple[int, int, int, int]: ...
33
+ def __add__(self, other: OP_TYPES) -> hurwitzint: ...
34
+ def __radd__(self, other: OTHER_OP_TYPES) -> hurwitzint: ...
35
+ def __sub__(self, other: OP_TYPES) -> hurwitzint: ...
36
+ def __rsub__(self, other: OTHER_OP_TYPES) -> hurwitzint: ...
37
+ def __neg__(self) -> hurwitzint: ...
38
+ def __pos__(self) -> hurwitzint: ...
39
+ def __mul__(self, other: OP_TYPES) -> hurwitzint: ...
40
+ def __rmul__(self, other: OTHER_OP_TYPES) -> hurwitzint: ...
41
+ def __pow__(self, exp: int) -> hurwitzint: ...
42
+ def __divmod__(self, other: OP_TYPES) -> tuple['hurwitzint', 'hurwitzint']: ...
43
+ def __truediv__(self, other: OP_TYPES) -> hurwitzint: ...
44
+ def __rtruediv__(self, other: OTHER_OP_TYPES) -> hurwitzint: ...
45
+ def __floordiv__(self, other: OP_TYPES) -> hurwitzint: ...
46
+ def __rfloordiv__(self, other: OTHER_OP_TYPES) -> hurwitzint: ...
47
+ def __mod__(self, other: OP_TYPES) -> hurwitzint: ...
48
+ def rdivmod(self, other: OP_TYPES) -> tuple['hurwitzint', 'hurwitzint']: ...
49
+ def rtruediv(self, other: OP_TYPES) -> hurwitzint: ...
50
+ def rfloordiv(self, other: OP_TYPES) -> hurwitzint: ...
51
+ def rmod(self, other: OP_TYPES) -> hurwitzint: ...
52
+ def __abs__(self) -> int: ...
53
+ def __bool__(self) -> bool: ...
54
+ def __iter__(self) -> Iterator[int]: ...
55
+ def __len__(self) -> int: ...
56
+ def __getitem__(self, idx: int) -> int: ...
57
+ def __eq__(self, other: object) -> bool: ...
58
+ def __hash__(self) -> int: ...
59
+ def gcd_right(self, other: OP_TYPES, *, normalize: bool = True) -> hurwitzint: ...
60
+ def gcd_left(self, other: OP_TYPES, *, normalize: bool = True) -> hurwitzint: ...
61
+ def content(self) -> int: ...
62
+ def factor_right(self) -> HurwitzFactorization: ...
63
+ def factor_left(self) -> HurwitzFactorization: ...
64
+
65
+ def units() -> list['hurwitzint']: ...
66
+ def rdivmod(a: hurwitzint, b: OP_TYPES) -> tuple['hurwitzint', 'hurwitzint']: ...
67
+ def gcd_left(a: hurwitzint, b: OP_TYPES) -> hurwitzint: ...
68
+ def gcd_right(a: hurwitzint, b: OP_TYPES) -> hurwitzint: ...
69
+ def prod_right(x: Iterable[OP_TYPES], start: OP_TYPES | None = None): ...
70
+ def prod_left(x: Iterable[OP_TYPES], start: OP_TYPES | None = None): ...