Is there an easy way to solve linear Diophantine equations with inequalities?
For example, say I have $a_1x_1 + a_2x_2 \equiv k \mod m$ where:
- $a_1, a_2, k, m$ are given
I already know $b_1, b_2$ such that $a_1b_1 \equiv a_2b_2 \equiv 1 \mod m$, so if either of the $x_1$ or $x_2$ is given, I can calculate the other one:
$x_1 = (k - a_2x_2)b_1 \bmod m \\ x_2 = (k - a_1x_1)b_2 \bmod m$
I wish to solve for $x_1, x_2$ where $0 < x_1 < x_{max}$, $0 < x_2 < x_{max}$.
For example, $a_1 = 12345678987601, a_2 = 45678901, k = 135990606993339, m = 2^{48}-1, x_{max}=10^6.$
I can find $b_1 = 179768904497071, b_2 = 154376496085921$ easily, but other than a brute-force search, I'm not sure how to find the values $x_1$ and $x_2$ (in this case $x_1 = 50603, x_2 = 12481$ but that's because I created this example)
Note: I used tmyklebu's solution and implemented in Python with numpy and sympy:
import numpy as np
from sympy.matrices import Matrix
# thanks to user tmyklebu http://math.stackexchange.com/a/1151038/120
def reduce_lattice(L, verbose=False):
"""repeated pseudo-Gram-Schmidt orthogonalization
until we get no more progress
"""
N = L.shape[0]
get_norm = lambda M: sum(np.amax(np.abs(M),1))
Lnorm = None
Lnew = L.copy()
Lnew_norm = get_norm(Lnew)
while Lnorm != Lnew_norm:
for i in xrange(N):
v = Lnew[i]
num = np.dot(Lnew,v)
den = np.sum(Lnew**2, axis=1)
k = [int(np.round(x)) for x in num*1.0/den]
k[i] = 0 # don't subtract multiples of self
vnew = v-np.dot(k,Lnew)
Lnew[i] = vnew
Lnorm = Lnew_norm
Lnew_norm = get_norm(Lnew)
return Lnew
def solve_eqn(a1,a2,k,m,xmax):
B = int(np.ceil(np.abs(xmax)))
L = np.array([[m*B,0,0],
[a1*B,1,0],
[a2*B,0,1]], dtype=object)
L1 = reduce_lattice(L)
L2 = Matrix(L1.T)
exact_coords=L2.LUsolve(Matrix(3,1,[k*B,0,0]))
int_coords = Matrix(3,1,[int(c.round()) for c in exact_coords])
soln = [int(c) for c in L2*int_coords]
assert soln[0] == k*B
return soln[1:]
and got:
>>> solve_eqn(a1=12345678987601, a2=45678901,
k=135990606993339, m=(1<<48)-1, xmax=1000000 )
[50603, 12481]
:-)