quatint 0.0.6__cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
- 3a49525171c7d4218706__mypyc.cpython-311-aarch64-linux-gnu.so +0 -0
- quatint/__init__.cpython-311-aarch64-linux-gnu.so +0 -0
- quatint/quat.cpython-311-aarch64-linux-gnu.so +0 -0
- quatint-0.0.6.dist-info/METADATA +172 -0
- quatint-0.0.6.dist-info/RECORD +10 -0
- quatint-0.0.6.dist-info/WHEEL +7 -0
- quatint-0.0.6.dist-info/licenses/LICENSE +19 -0
- quatint-0.0.6.dist-info/top_level.txt +3 -0
- quatint-stubs/__init__.pyi +1 -0
- quatint-stubs/quat.pyi +70 -0
|
Binary file
|
|
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-311-aarch64-linux-gnu.so,sha256=B4CcdT7OQIPblTLJbQmbI6kh5oegiSTqxy0MQexWxS8,754272
|
|
2
|
+
quatint/__init__.cpython-311-aarch64-linux-gnu.so,sha256=27OaVN67-BFgMWcHZeotrpq_BLo_yDbB_wK1kl5q1eQ,202952
|
|
3
|
+
quatint/quat.cpython-311-aarch64-linux-gnu.so,sha256=hifLJE4PgTognLMNV-TFvb__EA3i135y3BlqAiGPyC4,202952
|
|
4
|
+
quatint-stubs/__init__.pyi,sha256=QvqwCQcUL96TTqoLt-TGx36pkZMvhAmcb2QfQBhmnm8,166
|
|
5
|
+
quatint-stubs/quat.pyi,sha256=gyebchLIv9z7nbCbezFsiLC5Pnpm-7OnxJZIxWU7V9I,3044
|
|
6
|
+
quatint-0.0.6.dist-info/METADATA,sha256=XeaEm7oRzfvTwT_wrDaw1ScafiFLAjpDeSzc_BAl8RY,5273
|
|
7
|
+
quatint-0.0.6.dist-info/WHEEL,sha256=nENvFvUt2sTxh7qTwFTbrHft1Jd6WkcTog-2x3-pWGY,193
|
|
8
|
+
quatint-0.0.6.dist-info/top_level.txt,sha256=5Ii4PDUZslezIEwK0uNjzWWkUXsBRi96NKCuuYLNDGA,50
|
|
9
|
+
quatint-0.0.6.dist-info/RECORD,,
|
|
10
|
+
quatint-0.0.6.dist-info/licenses/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
|
|
@@ -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 @@
|
|
|
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): ...
|