How to build a Gray-code generator in Picat? - picat

Encouraged by the knowledge I've gained from the answer to my previous post, I aim to generate Gray-codes of given length. The procedure hamming seems to work correctly, however, the Picat system finds no solution. Where's the mistake here?
import cp.
main => gray(2).
gray(CodeLen) =>
CodeNr is 2**CodeLen,
Codes = new_array(CodeNr, CodeLen),
Codes :: 0..1,
foreach(CodeNr1 in 1..CodeNr)
CodeNr2 = cond(CodeNr1 == CodeNr, 1, CodeNr1 + 1),
hamming(Codes[CodeNr1], Codes[CodeNr2], 0, H),
H #= 1
% the Hamming distance between 2 consecutive codes is 1
end,
solve(Codes),
printf("%w\n", Codes).
hamming([], [], A, H) ?=> H #= A.
hamming([H1|T1], [H2|T2], A, H) ?=>
H1 #!= H2,
A1 #= A + 1,
hamming(T1, T2, A1, H).
hamming([H1|T1], [H2|T2], A, H) ?=>
H1 #= H2,
A1 #= A + 0,
hamming(T1, T2, A1, H).

The reason that the model don't print anything is that you are using list constructs ([H|T]) on the array matrix Code which is not allowed. You have to convert the rows of the matrix (which are arrays) to lists. This can be done in two ways:
Convert the array matrix Code matrix to a list matrix with array_matrix_to_list_matrix() (requires that the util package is loaded):
import util.
% ....
gray(CodeLen) =>
CodeNr is 2**CodeLen,
Codes = new_array(CodeNr, CodeLen).array_matrix_to_list_matrix, % <--
Codes :: 0..1,
% ....
Convert the array parameters in the call to hamming/4 to lists with theto_list() function. E.g.:
% ...
foreach(CodeNr1 in 1..CodeNr)
CodeNr2 = cond(CodeNr1 == CodeNr, 1, CodeNr1 + 1),
% hamming(Codes[CodeNr1], Codes[CodeNr2], 0, H), % Original
hamming(Codes[CodeNr1].to_list, Codes[CodeNr2].to_list, 0, H), % <---
H #= 1
% the Hamming distance between 2 consecutive codes is 1
end,
% ...
Update.
Here's a constraint model that solves the problem of generating different rows that was indicated in the comment. It uses a simpler version of hamming_distance by just counting the number of different bits with sum. Also, for symmetry, I require that the first and last row also have a Hamming distance of 1. (This was in the original code.)
To require different rows, the constraint to_num/3 is used to converts a number to digits in an array (given a base, here 2). These numbers (which must be distinct) are in the CodesNum list.
import cp,util.
main =>
go.
go ?=>
gray(5),
nl,
% fail,
nl.
go => true.
% First solution for N=2..10
go2 ?=>
foreach(N in 2..10)
println(n=N),
if time(gray(N)) then
true
else
println(nope)
end,
nl
end,
nl.
go2 => true.
gray(CodeLen) =>
CodeNr is 2**CodeLen,
println(codeNr=CodeNr),
Codes = new_array(CodeNr, CodeLen).array_matrix_to_list_matrix,
Codes :: 0..1,
CodesNum = new_list(CodeNr), % array -> integer
CodesNum :: 0..CodeNr,
foreach(CodeNr1 in 1..CodeNr)
to_num(Codes[CodeNr1],2,CodesNum[CodeNr1]),
CodeNr2 = cond(CodeNr1 == CodeNr, 1, CodeNr1 + 1),
hamming_distance(Codes[CodeNr1], Codes[CodeNr2], 1),
end,
% around the corner
% hamming_distance(Codes[1], Codes[CodeNr],1),
all_different(CodesNum),
CodesNum[1] #= 0, % symmetry breaking
Vars = CodesNum ++ Codes.vars,
solve($[ff,updown],Vars),
printf("%w\n", Codes),
println(codesNum=CodesNum),nl.
% Hamming distance of As and Bs
hamming_distance(As, Bs,Diff) =>
Diff #= sum([(A #!= B) : {A,B} in zip(As,Bs)]).
% Convert Num to/from a list of digits in List (base Base)
to_num(List, Base, Num) =>
Len = length(List),
Num #= sum([List[I]*Base**(Len-I) : I in 1..Len]).
to_num(List, Num) =>
to_num(List, 10, Num).
It solves N=4 in 0s:
n = 4
codeNr = 16
[[0,0,0,0],[1,0,0,0],[1,1,0,0],[1,1,1,0],[1,1,1,1],[1,1,0,1],[1,0,0,1],[1,0,1,1],[1,0,1,0],[0,0,1,0],[0,1,1,0],[0,1,1,1],[0,0,1,1],[0,0,0,1],[0,1,0,1],[0,1,0,0]]
codesNum = [0,8,12,14,15,13,9,11,10,2,6,7,3,1,5,4]
CPU time 0.0 seconds.
The model solves N=2..7 (first solution) quite fast, but it struggles with N=8, and I don't have the time to test different search heuristics to make it faster.
Here's some another approach for solving the gray code but without constraint modelling and it's much faster: http://hakank.org/picat/gray_code.pi
Update2 Here's a much faster version of hamming/4. It use a reification (boolean) variable B to check if H1 and H2 are different and can then be used as the value to add to A0.
hamming2([], [], A, A).
hamming2([H1|T1], [H2|T2], A0, H) :-
B :: 0..1,
H1 #!= H2 #<=> B #= 1,
A1 #= A0 + B,
hamming2(T1, T2, A1, H).

Related

Check whether a subset with sum divisible by m exists

Given a set of non-negative distinct integers, and a value m, determine if there is a subset of the given set with sum divisible by m.
The solution on geeksforgeeks states that-
If n > m there will always be a subset with sum divisible by m (which is easy to prove with pigeonhole principle). So we need to handle only cases of n <= m.
Can somebody please explain what this case means and what is its relation to pigeonhole principle? Also how is this case different from n <= m?
Making this a bit more verbose of this:
Label the numbers a1, a2, ... an in any order. Now consider the sums:
b1=a1
b2=a1+a2
b3=a1+a2+a3
...
bn=a1+a2+...+an
These are either all unique numbers or one of the as are 0 (which is divisible by m).
Now if any of the bs are divisible by m we are done.
Otherwise:
The remainders of some non-divisible number/m can be in the range of 1...(m-1). So there are m-1 numbers of possible remainders`.
Since numbers b1...bn weren't divisible by m they must have remainders in the range of 1...(m-1). So you must pair n numbers of bs (pigeons) with m-1 remainders (pigeonholes).
We have more pigeons than pigeonholes => there must be at least two pigeons in the same pigeonhole.
That means: there must be at least two bs with the same remainder: call them bi, bj (i<j). Since all of our bs are unique and bi % m == bj % m (the remainders of bi/m and bj/m are the same) => bi - bj = x * m (where x is a positive integer). Therefore bi - bj is divisible by m and bi - bj = ai+1 + ... + aj. Therefore ai+1 + ... + aj is divisible by m which is exactly what we wanted to proof.
Let us create a new set of numbers (i.e. a[ ] array) by doing prefix sum of given values (i.e. value[ ] array).
a[0] = value[0]
a[1] = value[0] + value[1]
a[n] = value[0] + value[1] + .... + value[n]
Now we have n new numbers. If any of them are divisible by m we are done.
If we divide the a[ ] array elements with m, we can get remainders in range of [1, m - 1].
But, we have a total of n values.
So, there exist two numbers 0<=i,j<=n in a such that a[i] mod(m) == a[j] mod(m).
Due to the above statement, we can say that a[i] - a[j] is divisible by m.
Now, let's consider i > j.
We also know that, a[i] = value[i] + value[i - 1] + ... + value[0] and a[j] = value[j] + value[j - 1] + ... + value[0].
So, a[i] - a[j] = value[i] + value[i - 1] + ... + value[i - j + 1] is also divisible by m.

creating an array of numbers whose frequency resembles bell curve

I want to create an array A [1 ,1 , 2, 2 ,2 , 5, 5 ,5 ,....] with numbers from [a,b] such that
An histogram where Y-Axis is the frequency of the number in the array and X-axis is [a,b] resembles a bell curve.
Bell Curve
The sum of frequency(i)*i for all i in [a,b] is approximately around a large number K
Many functions are available in python like numpy.random.normal or scipsy.stats.truncnorm but I am not able to fully understand their use and how they can help me to create such an array.
The first point is easy, for the second point, I'm assuming you want the "integral" of freq * x to be close to K (making each x * freq(x) ~ K is mathematically impossible). You can do that by adjusting sample size.
First step: bell curve shaped integer numbers between a and b, use scipy.stats.truncnorm. From the docs:
Notes
The standard form of this distribution is a standard normal truncated to the range [a, b] --- notice that a and b are defined over
the domain of the standard normal. To convert clip values for a
specific mean and standard deviation, use::
a, b = (myclip_a - my_mean) / my_std, (myclip_b - my_mean) / my_std
Take a normal in the -3, 3 range, so the curve is nice. Adjust mean and standard deviation so -3, 3 becomes a, b:
from scipy.stats import truncnorm
a, b = 10, 200
loc = (a + b) / 2
scale = (b - a) / 6
n = 100
f = truncnorm(-3,3, loc=(a+b)/2,scale=(b-a)/6)
Now, since frequency is related to the probability density function: sum(freq(i) * i ) ~ n * sum(pdf(i) * i). Therefore, n = K / sum(pdf(i) * i). This can be obtained as:
K = 200000
i = np.arange(a, b +1)
n = int(K / i.dot(f.pdf(i)))
Now generate integer random samples, and check function:
samples = f.rvs(size=n).astype(np.int)
import matplotlib.pyplot as plt
plt.hist(samples, bins = 20)
print(np.histogram(samples, bins=b-a+1)[0].dot(np.arange(a,b+1)))
>> 200315

Understanding implementation of DC3/Skew algorithm to create Suffix Array linear time

I am trying to understand implementation of linear time suffix array creation algorithm by Karkkainen, P. Sanders. Details of algorithm can be found here.
I managed to understand overall concept but failing to match it with provided implementation and hence not able to grasp it clearly.
Here are initial code paths which are confusing me.
As per paper : n0, n1, n2 represent number of triplets starting at i mod 3 = (0,1,2)
As per code : n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3; => How these initialisations has been derived?
As per paper : We need to create T` which is concatenation of triplets at i mod 3 != 0
As per code : n02 = n0 + n2; s12 = [n02] ==> How came n02? It should be n12 i.e n1 + n2.
As per code : for (int i = 0, j = 0; i < n + (n0 - n1); i++) fill s12 with triplets such that i%3 != 0; => Why for loop runs for n + (n0 - n1) times ? It should be simply n1 + n2. Should't be ?
I am not able to proceed because of these :( Please to help.
Consider the following example where the length of the input is n=13:
STA | CKO | WER | FLO | W
As per code : n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3; => How these initialisations has been derived?
Note that the number of triplets i mod3 = 0 is n/3 if n mod3 = 0 and n/3+1 otherwise (if n mod3 = 1 or n mod3 = 2). In the current example n/3 = 4 but since the last triplet 'W' is not complete it is not counted in the integer division. A 'trick' to make this computation directly is to use (n+2)/3. Effectively, if n mod3 = 0 then the result of the integer divisions (n+2)/3 and n/3 will be the same. However, if n mod3 = 1 or 2 then the result of (n+2)/3 will be n/3+1. The same applies to n1 and n2.
As per code : n02 = n0 + n2; s12 = [n02] ==> How came n02? It should be n12 i.e n1 + n2.
As per code : for (int i = 0, j = 0; i < n + (n0 - n1); i++) fill s12 with triplets such that i%3 != 0; => Why for loop runs for n + (n0 - n1) times ? It should be simply n1 + n2. Should't be ?
Both questions have the same answer. In our example we'd have a B12 buffer like this:
B12 = B1 U B2 = {TA KO ER LO}
So you'd first sort the suffixes and end up with a suffix array of B12, which has 8 elements. To proceed to the merging step we first need to compute the suffix array of B0, which is obtained by sorting the tuples (B0(i),rank(i+1))... But this concrete case in which the last triplet has only one element (W) has a problem, because rank(i+1) is not defined for the last element of B0:
B0 = {0,3,6,9,12}
which sorted alphabetically results in
SA0 = {3, 9, 0, ?, ?}
Since the indices 6 and 12 contain a 'W', it is not enough to sort alphabetically, we need to check which goes first in the rank table, so let's check the rank of their suffixes.. oh, wait! rank(13) is not defined!
And that's why we add a dummy 0 to the last triplet of the input when the last triplet only contains one element (if n mod3 = 0). So then the size of B12 is n0+n2, no matter the size of n1, and one needs to add an extra element to B12 if B0 is larger than B1 (in which case n0-n1 = 1).
Hope it was clear.

How to implement Frobenius pseudoprime algorithm?

Someone told me that the Frobenius pseudoprime algorithm take three times longer to run than the Miller–Rabin primality test but has seven times the resolution. So then if one where to run the former ten times and the later thirty times, both would take the same time to run, but the former would provide about 233% more analyse power. In trying to find out how to perform the test, the following paper was discovered with the algorithm at the end:
A Simple Derivation for the Frobenius Pseudoprime Test
There is an attempt at implementing the algorithm below, but the program never prints out a number. Could someone who is more familiar with the math notation or algorithm verify what is going on please?
Edit 1: The code below has corrections added, but the implementation for compute_wm_wm1 is missing. Could someone explain the recursive definition from an algorithmic standpoint? It is not "clicking" for me.
Edit 2: The erroneous code has been removed, and an implementation of the compute_wm_wm1 function has been added below. It appears to work but may require further optimization to be practical.
from random import SystemRandom
from fractions import gcd
random = SystemRandom().randrange
def find_prime_number(bits, test):
number = random((1 << bits - 1) + 1, 1 << bits, 2)
while True:
for _ in range(test):
if not frobenius_pseudoprime(number):
break
else:
return number
number += 2
def frobenius_pseudoprime(integer):
assert integer & 1 and integer >= 3
a, b, d = choose_ab(integer)
w1 = (a ** 2 * extended_gcd(b, integer)[0] - 2) % integer
m = (integer - jacobi_symbol(d, integer)) >> 1
wm, wm1 = compute_wm_wm1(w1, m, integer)
if w1 * wm != 2 * wm1 % integer:
return False
b = pow(b, (integer - 1) >> 1, integer)
return b * wm % integer == 2
def choose_ab(integer):
a, b = random(1, integer), random(1, integer)
d = a ** 2 - 4 * b
while is_square(d) or gcd(2 * d * a * b, integer) != 1:
a, b = random(1, integer), random(1, integer)
d = a ** 2 - 4 * b
return a, b, d
def is_square(integer):
if integer < 0:
return False
if integer < 2:
return True
x = integer >> 1
seen = set([x])
while x * x != integer:
x = (x + integer // x) >> 1
if x in seen:
return False
seen.add(x)
return True
def extended_gcd(n, d):
x1, x2, y1, y2 = 0, 1, 1, 0
while d:
n, (q, d) = d, divmod(n, d)
x1, x2, y1, y2 = x2 - q * x1, x1, y2 - q * y1, y1
return x2, y2
def jacobi_symbol(n, d):
j = 1
while n:
while not n & 1:
n >>= 1
if d & 7 in {3, 5}:
j = -j
n, d = d, n
if n & 3 == 3 == d & 3:
j = -j
n %= d
return j if d == 1 else 0
def compute_wm_wm1(w1, m, n):
a, b = 2, w1
for shift in range(m.bit_length() - 1, -1, -1):
if m >> shift & 1:
a, b = (a * b - w1) % n, (b * b - 2) % n
else:
a, b = (a * a - 2) % n, (a * b - w1) % n
return a, b
print('Probably prime:\n', find_prime_number(300, 10))
You seem to have misunderstood the algorithm completely due to not being familiar with the notation.
def frobenius_pseudoprime(integer):
assert integer & 1 and integer >= 3
a, b, d = choose_ab(integer)
w1 = (a ** 2 // b - 2) % integer
That comes from the line
W0 ≡ 2 (mod n) and W1 ≡ a2b−1 − 2 (mod n)
But the b-1 doesn't mean 1/b here, but the modular inverse of b modulo n, i.e. an integer c with b·c ≡ 1 (mod n). You can most easily find such a c by continued fraction expansion of b/n or, equivalently, but with slightly more computation, by the extended Euclidean algorithm. Since you're probably not familiar with continued fractions, I recommend the latter.
m = (integer - d // integer) // 2
comes from
n − (∆/n) = 2m
and misunderstands the Jacobi symbol as a fraction/division (admittedly, I have displayed it here even more like a fraction, but since the site doesn't support LaTeX rendering, we'll have to make do).
The Jacobi symbol is a generalisation of the Legendre symbol - denoted identically - which indicates whether a number is a quadratic residue modulo an odd prime (if n is a quadratic residue modulo p, i.e. there is a k with k^2 ≡ n (mod p) and n is not a multiple of p, then (n/p) = 1, if n is a multiple of p, then (n/p) = 0, otherwise (n/p) = -1). The Jacobi symbol lifts the restriction that the 'denominator' be an odd prime and allows arbitrary odd numbers as 'denominators'. Its value is the product of the Legendre symbols with the same 'numerator' for all primes dividing n (according to multiplicity). More on that, and how to compute Jacobi symbols efficiently in the linked article.
The line should correctly read
m = (integer - jacobi_symbol(d,integer)) // 2
The following lines I completely fail to understand, logically, here should follow the calculation of
Wm and Wm+1 using the recursion
W2j ≡ Wj2 − 2 (mod n)
W2j+1 ≡ WjWj+1 − W1 (mod n)
An efficient method of using that recursion to compute the required values is given around formula (11) of the PDF.
w_m0 = w1 * 2 // m % integer
w_m1 = w1 * 2 // (m + 1) % integer
w_m2 = (w_m0 * w_m1 - w1) % integer
The remainder of the function is almost correct, except of course that it now gets the wrong data due to earlier misunderstandings.
if w1 * w_m0 != 2 * w_m2:
The (in)equality here should be modulo integer, namely if (w1*w_m0 - 2*w_m2) % integer != 0.
return False
b = pow(b, (integer - 1) // 2, integer)
return b * w_m0 % integer == 2
Note, however, that if n is a prime, then
b^((n-1)/2) ≡ (b/n) (mod n)
where (b/n) is the Legendre (or Jacobi) symbol (for prime 'denominators', the Jacobi symbol is the Legendre symbol), hence b^((n-1)/2) ≡ ±1 (mod n). So you could use that as an extra check, if Wm is not 2 or n-2, n can't be prime, nor can it be if b^((n-1)/2) (mod n) is not 1 or n-1.
Probably computing b^((n-1)/2) (mod n) first and checking whether that's 1 or n-1 is a good idea, since if that check fails (that is the Euler pseudoprime test, by the way) you don't need the other, no less expensive, computations anymore, and if it succeeds, it's very likely that you need to compute it anyway.
Regarding the corrections, they seem correct, except for one that made a glitch I previously overlooked possibly worse:
if w1 * wm != 2 * wm1 % integer:
That applies the modulus only to 2 * wm1.
Concerning the recursion for the Wj, I think it is best to explain with a working implementation, first in toto for easy copy and paste:
def compute_wm_wm1(w1,m,n):
a, b = 2, w1
bits = int(log(m,2)) - 2
if bits < 0:
bits = 0
mask = 1 << bits
while mask <= m:
mask <<= 1
mask >>= 1
while mask > 0:
if (mask & m) != 0:
a, b = (a*b-w1)%n, (b*b-2)%n
else:
a, b = (a*a-2)%n, (a*b-w1)%n
mask >>= 1
return a, b
Then with explanations in between:
def compute_wm_wm1(w1,m,n):
We need the value of W1, the index of the desired number, and the number by which to take the modulus as input. The value W0 is always 2, so we don't need that as a parameter.
Call it as
wm, wm1 = compute_wm_wm1(w1,m,integer)
in frobenius_pseudoprime (aside: not a good name, most of the numbers returning True are real primes).
a, b = 2, w1
We initialise a and b to W0 and W1 respectively. At each point, a holds the value of Wj and b the value of Wj+1, where j is the value of the bits of m so far consumed. For example, with m = 13, the values of j, a and b develop as follows:
consumed remaining j a b
1101 0 w_0 w_1
1 101 1 w_1 w_2
11 01 3 w_3 w_4
110 1 6 w_6 w_7
1101 13 w_13 w_14
The bits are consumed left-to-right, so we have to find the first set bit of m and place our 'pointer' right before it
bits = int(log(m,2)) - 2
if bits < 0:
bits = 0
mask = 1 << bits
I subtracted a bit from the computed logarithm just to be entirely sure that we don't get fooled by a floating point error (by the way, using log limits you to numbers of at most 1024 bits, about 308 decimal digits; if you want to treat larger numbers, you have to find the base-2 logarithm of m in a different way, using log was the simplest way, and it's just a proof of concept, so I used that here).
while mask <= m:
mask <<= 1
Shift the mask until it's greater than m,so the set bit points just before m's first set bit. Then shift one position back, so we point at the bit.
mask >>= 1
while mask > 0:
if (mask & m) != 0:
a, b = (a*b-w1)%n, (b*b-2)%n
If the next bit is set, the value of the initial portion of consumed bits of m goes from j to 2*j+1, so the next values of the W sequence we need are W2j+1 for a and W2j+2 for b. By the above recursion formula,
W_{2j+1} = W_j * W_{j+1} - W_1 (mod n)
W_{2j+2} = W_{j+1}^2 - 2 (mod n)
Since a was Wj and b was Wj+1, a becomes (a*b - W_1) % n and b becomes (b * b - 2) % n.
else:
a, b = (a*a-2)%n, (a*b-w1)%n
If the next bit is not set, the value of the initial portion of consumed bits of m goes from j to 2*j, so a becomes W2j = (Wj2 - 2) (mod n), and b becomes
W2j+1 = (Wj * Wj+1 - W1) (mod n).
mask >>= 1
Move the pointer to the next bit. When we have moved past the final bit, mask becomes 0 and the loop ends. The initial portion of consumed bits of m is now all of m's bits, so the value is of course m.
Then we can
return a, b
Some additional remarks:
def find_prime_number(bits, test):
while True:
number = random(3, 1 << bits, 2)
for _ in range(test):
if not frobenius_pseudoprime(number):
break
else:
return number
Primes are not too frequent among the larger numbers, so just picking random numbers is likely to take a lot of attempts to hit one. You will probably find a prime (or probable prime) faster if you pick one random number and check candidates in order.
Another point is that such a test as the Frobenius test is disproportionally expensive to find that e.g. a multiple of 3 is composite. Before using such a test (or a Miller-Rabin test, or a Lucas test, or an Euler test, ...), you should definitely do a bit of trial division to weed out most of the composites and do the work only where it has a fighting chance of being worth it.
Oh, and the is_square function isn't prepared to deal with arguments less than 2, divide-by-zero errors lurk there,
def is_square(integer):
if integer < 0:
return False
if integer < 2:
return True
x = integer // 2
should help.

Lattice Points in a 2D plane

Given 2 point in a 2D plane, how many lattice points lie within these two point?
For example, for A (3, 3) and B (-1, -1) the output is 5. The points are: (-1, -1), (0, 0), (1, 1), (2, 2) and (3, 3).
Apparently by "lattice points lie within two points" you mean (letting LP stand for lattice point) the LP's on the line between two points (A and B).
The equation of line AB is y = m*x + b for some slope and intercept numbers m and b. For cases of interest, we can assume m, b are rational, because if either is irrational there is at most 1 LP on AB. (Proof: If 2 or more LP's are on line, it has rational slope, say e/d, with d,e integers; then y=b+x*e/d so at LP (X,Y) on line, d*b = d*Y-X*e, which is an integer, hence b is rational.)
In following, we suppose A = (u,v) and B = (w,z), with u,w and v,z having rational differences, and typically write y = mx+b with m=e/d and b=g/f.
Case 1. A, B both are LP's: Let q = gcd(u-w,v-z); take d = (u-w)/q and e = (v-z)/q and it's easily seen that there are q+1 lattice points on AB.
Case 2a. A is an LP, B isn't: If u-w = h/i and v-z = j/k
then m = j*i/(h*k). Let q = gcd(j*i,h*k), d = h*k/q, e=j*i/q, w' = u + d*floor((w-u)/d) and similarly for z', then solve (u,v),(w',z') as in case 1. For case 2b swap A and B.
Case 3. Neither A nor B is an LP: After finding an LP C on the extended line through A,B, use arithmetic like in Case 2 to find LP A' inside line segment AB and apply case 2. To find A', if m = e/d, b = g/f, note that f*d*y = d*g + e*f*x is of the form p*x + q*y = r, a simple Diophantine equation that is solvable for C=(x,y) iff gcd(p,q) divides r.
Complexity: gcd(m,n) is O(ln(min(m,n)) so algorithm complexity is typically O(ln(Dx)) or O(ln(Dy)) if A,B are separated by x,y distances Dx,Dy.

Resources