twosquares 0.0.5__cp39-cp39-win_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.
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: twosquares
3
+ Version: 0.0.5
4
+ Summary: A package for very efficiently decomposing a number n into all possible x**2 + y**2 = n solutions.
5
+ Author-email: Ryan Heard <ryanwheard@gmail.com>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/rheard/twosquares
8
+ Keywords: 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
+ Requires-Dist: quadint>=0.0.9
22
+ Dynamic: license
23
+ Dynamic: license-file
24
+
25
+ I've defined this process as "decomposing" a number $n$ into the possible solutions $x^2 + y^2 = n$.
26
+
27
+ # twosquares
28
+
29
+ `twosquares` exposes two simple methods for this number-theory task:
30
+
31
+ * `decompose_prime(p)` — find the unique non-negative pair (a, b) with $a^2 + b^2 = p$ for $p = 2$ or any prime $p \equiv 1 \bmod 4$.
32
+
33
+ * `decompose_number(n)` — find the unique non-negative pairs (a, b) with $a^2 + b^2 = n$ for any number $n$.
34
+
35
+ ### Algorithm
36
+ Here is an explanation for the algorithm in this repo:
37
+
38
+ This builds on the algorithm described by Stan Wagon (1990),
39
+ based on work by Serret and Hermite (1848), and Cornacchia (1908).
40
+
41
+ The first thing to know is that there is a deterministic algorithm to quickly find the 1 and only solution for primes $p$ that are $\equiv 1 \bmod 4$.
42
+ The solution is to simply use Euclid's algorithm. This is the heart of the general algorithm for any $n$, which is described here:
43
+
44
+ 1. Factor $n$. This is the hardest, most time-consuming step.
45
+ We'll say this factoring has the form $2^t * (p_1 ^ {k_1} * p_2 ^ {k_2} * ...) * (q_1 ^ {j_1} * q_2 ^ {j_2} * ...)$
46
+ Where $t$ is the 2's exponent, all of the primes $p$ are $\equiv 1 \bmod 4$, and all of the primes $q$ are $\equiv 3 \bmod 4$
47
+
48
+ 1. If any of primes $q$ (which are $\equiv 3 \bmod 4$) have an exponent $j$ that is odd, then there are no solutions.
49
+ 2. If there are no primes $p$ (that are $\equiv 1 \bmod 4$), there are no solutions.
50
+
51
+ 2. Construct a "base number" to use during the combinatorics later. We'll start with the 2's power, we will start the base number off as $(1 - i)^t$
52
+
53
+ 3. Now, for each prime $q^j$ in the factoring (the ones $\equiv 3 \bmod 4$):
54
+
55
+ 1. Multiply the base number by $q^{ j / 2 }$.
56
+ Note that from the rules laid out in step 1 above, $j$ is guaranteed to be even so this will always be an integer.
57
+
58
+ 4. Next will begin the combinatorics for the $p$ group, however 1 member of the $p$ group does not need to engage in this combinatorics (reasons why below).
59
+ So we'll select the first prime $p \equiv 1 \bmod 4$, and create it's "imaginary decomposition". This is a complex number $x+yi$ made from the solution $x^2 + y^2 = p$.
60
+ Multiply the base number by this number too.
61
+
62
+ 1. If the exponent for this $p$ (the $k$ value) was 1 then $p$ can be removed entirely from the group.
63
+ 2. If $k$ was greater than $1$, it should be decremented, and the remaining instances of $p$ in the factorization still need to undergo the following combinatorics.
64
+
65
+ 5. Now we need to use combinations of (`True`, `False`) of length $\sum k$ to drive the combinatorics going forward.
66
+ Python has a product method for this, or you can simply count up using binary numbers to `1<<sum(k)` and look at the bits of this counter.
67
+
68
+ For every possible combination of true/false called "choices":
69
+ 1. Start this solution with the base number.
70
+ 2. For each factor $p$ left, one time for each exponent $k$:
71
+
72
+ 1. Get the next "choice" (true/false)
73
+ 2. Get the "imaginary decomposition" of the factor, either $x+yi$ if the choice was true or the conjugate $x-yi$ if the choice was false
74
+ 3. Multiply the total number by this either positive or negative imaginary decomposition
75
+
76
+ 3. The real and imaginary part of the total number now constitute a solution for $x^2 + y^2 = n$! Amazing!!
77
+
78
+ 1. The numbers are then sorted so that $x < y$, and this is a solution that may or may not have been found already.
79
+
80
+ Doing this we can rapidly break any number $n$ up into all of its possible $x^2 + y^2$ solutions!
81
+
82
+ Note: Remember how we didn't do combinatorics for a single exponent of the $p$ group?
83
+ If that exponent of that base were included, we would simply get back the same solutions but in reverse order.
84
+ The problem uses addition and is associative, so we do not care about order.
85
+ Thus we can effectively halve the compute time with the combinatorics by excluding the other half of that particular exponent.
86
+
87
+ Note: That is not entirely true, as skipping all of the combinatorics with this number and 2 means we will not
88
+ get back all trivial solutions.
89
+ To get all trivial solutions with this package, pass the argument `no_trivial_solutions=True` to `decompose_number`.
90
+
91
+ ### Example
92
+
93
+ As an example, lets look at $n = 19890$.
94
+ This number's factorization looks like: $2 * 3^2 * 5 * 13 * 17$.
95
+ The set of primes $p$ (that are $\equiv 1 \bmod 4$) are $5$, $13$ and $17$ (all having an exponent $k$ of $1$).
96
+ The set of primes $q$ (that are $\equiv 3 \bmod 4$) is $3$, with the only exponent $j$ being 2.
97
+
98
+ Starting with the rules we can see that all of the primes $q$ have an even exponent ($2$ in this case) and there are primes in the $p$ group, so there must be at least 1 solution for this number!
99
+
100
+ The 2's exponent is $1$, so we will say our base number is $(1-i)^1$ or just $1 - i$
101
+
102
+ There is only a single prime in the $q$ group, so we will multiply the base number by $3$ which gives $3 - 3i$
103
+
104
+ We'll take the first prime in the $p$ group ($5$) and decompose that number, we find we get $5 = 1^2 + 2^2$.
105
+ We use this composition to construct a complex number $1 + 2i$. Now multiply the base number by this.
106
+ This is the real base number, which is $3 + 9i$
107
+
108
+ Now for combinatorics to produce all the different solutions. The remaining 2 primes $p$ have the following decompositions:
109
+
110
+ $13 = 2^2 + 3^2$
111
+
112
+ $17 = 1^2 + 4^2$
113
+
114
+ 1. Using the positive values: Multiply the base number by $2+3i$ and $1+4i$ (from the solutions for both of these primes),
115
+ and we get $-126 + 69i$, which using the absolute values of this is magically our first solution: $19890 = 123^2 + 69^2$
116
+
117
+ 2. Using the negative values: Multiply the base number by $2-3i$ and $1-4i$, and we get $-57 - 129i$,
118
+ which gives our next solution: $19890 = 57^2 + 129^2$
119
+
120
+ 3. Using positive for 13 and negative for 17: Multiply the base number by $2+3i$ and $1-4i$, and we get $141 - 3i$, which again gives our next solution: $19890 = 141^2 + 3^2$
121
+
122
+ 4. Lastly it should be obvious: Multiply the base number by $2-3i$ and $1+4i$, we get our final answer: $19890 = 111^2 + 87^2$
123
+
124
+ So in conclusion, the following are all equal to $19890$: $123^2 + 69^2$, $57^2 + 129^2$, 141^2 + 3^2, $111^2 + 87^2$
125
+
126
+ Everything laid out in this example is performed by the following Python code:
127
+
128
+ ```python
129
+ from twosquares import decompose_number
130
+
131
+ print(decompose_number(19890)) # prints {(69, 123), (57, 129), (3, 141), (87, 111)}
132
+ ```
133
+
134
+ ## Advanced Usage
135
+
136
+ It is possible to skip the factoring step and instead build a factored dictionary and pass that to `decompose_number` instead.
137
+ `decompose_number({2: 1, 3: 2, 5: 1, 13: 1, 17: 1})` will produce the same result as `decompose_number(19890)`.
138
+ If the factoring dictionary has been carefully crafted to comply with the rules laid out in step 1 of the algorithm section above,
139
+ then `limited_checks=True` can be passed as an argument to skip these validations.
140
+
141
+ It is an interesting fact that the upper bound of solutions can be quickly computed by $\prod (j + 1)$.
142
+ If a minimum number of solutions is required, this can be quickly validated by passing `check_count` as an integer.
143
+
144
+ Note that `decompose_prime` supports an optional argument `d` where the default is `1`.
145
+ This method actually is solving for the formula $p = x^2 + d * y^2$
@@ -0,0 +1,7 @@
1
+ twosquares.cp39-win_arm64.pyd,sha256=PmZJxufh4yp1K0KDAhwvcg_rskdbHv81kjdKryZeCas,77824
2
+ twosquares-0.0.5.dist-info/licenses/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
3
+ twosquares-stubs/__init__.pyi,sha256=cwSewHdqSKDVoEFrSwhVqCLX2kQG4u0STe9KgO1z2UY,270
4
+ twosquares-0.0.5.dist-info/METADATA,sha256=i3bcUQNz8tBnc57dYIIZw9TNoHSKiy8rbAkG2aVSCkw,8419
5
+ twosquares-0.0.5.dist-info/WHEEL,sha256=YAxRLiZl37bQf-KDOzxK44fDGobYtLXqUWtoDXKKYuE,99
6
+ twosquares-0.0.5.dist-info/top_level.txt,sha256=cmwZJ1cFpL4b3RqCi5RJt2KNOy2visqUEzW4ug0tapc,28
7
+ twosquares-0.0.5.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp39-cp39-win_arm64
5
+
@@ -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,2 @@
1
+ twosquares
2
+ twosquares-stubs
@@ -0,0 +1,5 @@
1
+ from functools import cache
2
+
3
+ @cache
4
+ def decompose_prime(p: int, d: int = 1) -> tuple[int, int]: ...
5
+ def decompose_number(n: dict | int, check_count: int | None = None, *, limited_checks: bool = False, no_trivial_solutions: bool = True) -> set[tuple[int, int]]: ...
Binary file