I am investigating/evaluating technical ways to solve quadratic diophantine systems of equations. My concrete problem can be boiled down into the following two steps:
- Loading a Textfile that contains lines of tuples
[sqrt(s), sqrt(t), sqrt(u), s, t, u, t+u, t+u-s, t-s]where each element is an integer. A cutout of this file is given below. - For each line in this file: Search an integer quadruple
[w,x,y,z]that solves the following system of equation:[x^2-w^2=s],[y^2-w^2=t],[z^2-y^2=u],[z^2-w^2=t+u],[z^2-x^2=t+u-s]and[y^2-x^2=t-s].
Here is a cutout of the Textfile:
520, 533, 756, 270400, 284089, 571536, 855625, 585225, 13689
672, 680, 153, 451584, 462400, 23409, 485809, 34225, 10816
756, 765, 520, 571536, 585225, 270400, 855625, 284089, 13689
612, 740, 2688, 374544, 547600, 7225344, 7772944, 7398400, 173056
644, 725, 2040, 414736, 525625, 4161600, 4687225, 4272489, 110889
What I tried so far is to use a z3 solver, which compiles and runs, but is unfortunatelly slow:
import pandas as pd
import sys
from z3 import Ints, solve
def main() -> int:
df = pd.read_csv('tuples.txt', header=None)
tuples = df.to_numpy()
x, y, z, w = Ints('x y z w')
for row in tuples:
s=int(row[3])
t=int(row[4])
u=int(row[5])
solve(x*x-w*w==s, y*y-w*w==t, z*z-y*y==u, w!=0)
return 0
if __name__ == '__main__':
sys.exit(main())
I would be greatful for any alternative approaches (best practices) to solve such diophantine systems in Python.
Created quite huge but very fast solution for you in Python. It should solve much faster than any Mathematica code or
z3-solver code doing similar stuff. Of course after pre-computations stage, which is done just once and then can be re-used on multiple runs (they save all computed data to cache files).Following solution does two precomputations. First one takes several minutes, it precomputes 2.7 GB file that is a big filter of squares. This size is tweakable and can be smaller. This file is computed only once (unless you change settings) and re-used on each run. This precomputation is single-core (but after some efforts I can make it multi-core).
Second precomputation takes more time, this one is multi-core, it uses all CPU cores. This precomputation produces quite small file, less than 1 GB even for large params values. This precomputes table which stores all possible Pythagorean Right Triangles with integer sides.
Precomputation is done for all cathetuses smaller than
limitsize. Change current settingslimit = 100_000to something bigger, probably 1M in your case. If this table is too small then it will fail to find some solutions for large cathetuses. Pre-computed table is also stored on disk and re-used (not computed again) on each run.This second precomputation calculates following tables of right triangles. It iterates through all possible first integer cathetus A (up to limit) and finds all possible second integer cathetus B (up to limit) such that
A^2 + B^2 = C^2, where C is also integer. Then for each A it stores a set of B's that satisfy this equation. C is not stored as it can be easily computed out of A and B.In order to make search of B fast I build two filters. For example we have any integer K0 and K1. We can easily see that if X is a square then X % K0 is a square and so is X % K1. So we can build a table of size K0 such that table[X % K0] is 1 if it is a square mod K0 and 0 otherwise. This gives us a fast filter for remove all such X that are definitely non square (i.e. table[X % K0] is 0). Second K1 filter is used for second stage of extra filtering.
Following Python code can be run straight away, without dependencies, it auotomatically fetches S T U file from your GitHub and caches it on disk.
After two above pre-computations are done all thousands s/t/u solutions are computed within 1-2 seconds. Finally all solutions are stored in JSON format to file
stu_solutions.100000.Found Almost Solutions (with non-integer Z) can be dumped by command:
cat stu_solutions.100000 | grep falseFound Precise Solutions (with integer Z) can be dumped by command:
cat stu_solutions.100000 | grep trueRemaining lines of this file contain either solutions with error (if table was too small for them), or with zero solutions, when w, x, y can't be found. In case of errors you have to build bigger table (second pre-computation), by setting bigger
limit = ....It is necessary to set limit at least as big as
Max(Sqrt(s), Sqrt(t)). But better to set it several times bigger. Bigger is table higher is chance of finding all possible solutions. Limit needs to be at most as big as biggest possiblew.To run following Python code you have to install one time PIP packages
python -m pip install numba numpy requests.Try it online!
Output:
Examples of all found Almost-solutions (where only Z is not integer) for 50K limit: