How to evenly distribute points around the perimeter of a rectangle - algorithm

I'm looking for a way to distribute points along a portion of the perimeter of a rectangle. These points needs to be evenly far away from each other.
I have a rectangular (usually square) bounds, and 2 points (ps and pe) along that perimeter that mark the allowed range for points. Here I've marked the allowed range in red:
I need to place n points along that segment (usually 1-3). These points need to be evenly spaced at a distance d. So the distance between n0..n1 and n1..n2 etc should all be d. The boundary points also count for the purposes of distribution, so the distance between the first and last points and ps/pe should be d as well.
This seemed like a straightforward task going in but I quickly realised the naive method doesn't work here. Taking the length of the segment and dividing by n+1 doesn't factor in corners. For example: n = 1, puts the point too close to pe:
My math is pretty rusty (day job doesn't require much of it usually), but I've tried several different approaches and none have quite worked out. I was able to solve for n = 1 using vectors, by finding the midpoint between ps and pe, finding a perpendicular vector and then intersecting that with the segment, like below. I have no idea how to make this approach work if n is something else though, or even if it can be done.
One final note, if completely even distribution is impracticable then a good enough approximation is fine. Ideally the approximation is off by roughly the same amount throughout the range (instead of say, worse on the edges).

I am going to suggest an algorithm, but since the derivation is a bit mathematically messy, I did not have enough time to think it through carefully and to check it carefully for correctness. Plus I might have included some redundant checks, which if one proves some proper inequalities may become redundant and one may prove the existence of a solution may always exist under reasonable assumptions. I believe the idea is correct, but I might have made some mistakes writing this thing up, so be careful.
Because according to your comment, having only one corner inside the segment along the boundary of the square is enough to solve the rest of the cases due to symmetry, I will focus on the one corner case.
Your polygonal segment with one 90 degree corner is divided into a pair of perpendicular straight line segments, the first one of length l1 and the second of length l2. These two lengths are given to you. You also want to add on the polygonal segment, which is of total length l1 + l2, a given number of n points so that the euclidean straight line distance between any two consecutive points is the same. Call that unknown distance d. When you do that you are going to end up with n1 full segments of unknown length d on l1 and n2 full segments of unknown length d on l2 so that
n1 + n2 = n
In general, you will also end up with an extra segment of length d1 <= d on l1 with one end at the 90 degree corner. Analogously, you will also have an extra segment of length d2 <= d on l2 with one end at the 90 degree corner. Thus, the two segments d1 and d2 share a common end and are perpendicular, so they form a right-angled triangle. According to Pythagoras' theorem, these two segments satisfy the equation
d1^2 + d2^2 = d^2
If we combine all the equations and information up to now, we obtain a system of equations and restrictions which are:
n1*d + d1 = l1
n2*d + d2 = l2
d1^2 + d2^2 = d^2
n1 + n2 = n
n1 and n2 are non-negative integers
where the variables d, d1, d2, n1, n2 are unknown while l1, l2, n are given.
From the first two equations, you can express d1 and d2 and substitute in the third equation:
d1 = l1 - n1*d
d2 = l2 - n2*d
(l1 - n1*d)^2 + (l2 - n2*d)^2 = d^2
n1 + n2 = n
n1 and n2 are non-negative integers
In the special case, when one wants to add only one point, i.e. n = 1, one has either n1 = n = 1 or n2 = n = 1 depending on whether l1 > l2 or l1 <= l2 respectively.
Say l1 > l2. Then n1 = n = 1 and n2 = 0 so
d1 = l1 - d
d2 = l2
(l1 - d)^2 + l2^2 = d^2
Expand the equation, simplify it and solve for d:
l1^2 - 2*l1*d + d^2 + l2^2 = d^2
l1^2 + l2^2 - 2*l1*d = 0
d = (l1^2 + l2^2) / (2*l1)
Next, let us go back to the general case. You have to solve the system
(l1 - n1*d)^2 + (l2 - n2*d)^2 = d^2
n1 + n2 = n
n1 and n2 are non-negative integers
where the variables d, n1, n2 are unknown while l1, l2, n are given. Expand the first equation:
l1^2 - 2 * l1 * n1 * d + n1^2 * d^2 + l2^2 - 2 * l2 * n2 * d + n2^2 * d^2 = d^2
n1 + n2 = n
n1 and n2 are non-negative integers
and group the terms together
(n1^2 + n2^2 - 1) * d^2 - 2 * (l1*n1 + l2*n2) * d + (l1^2 + l2^2) = 0
n1 + n2 = n
n1 and n2 are non-negative integers
The first equation is a quadratic equation in d
(n1^2 + n2^2 - 1) * d^2 - 2 * (l1*n1 + l2*n2) * d + (l1^2 + l2^2) = 0
By the quadratic formula you expect two solutions (in general, you choose whichever is positive.
If both are positive and d < l1 and d < l2, you may have two solutions):
d = ( (l1*n1 + l2*n2) +- sqrt( (l1*n1 + l2*n2)^2 - (l1^2 + l2^2)*(n1^2 + n2^2 - 1) ) ) / (n1^2 + n2^2 - 1)
n1 + n2 = n
n1 and n2 are non-negative integers
Now, if you can find appropriate n1 and n2, you can calculate the necessary d using the quadratic formula above.
For solutions to exist, the expression in the square root has to be non-negative, so you have the inequality restriciton
d = ( (l1*n1 + l2*n2) +- sqrt( (l1*n1 + l2*n2)^2 - (l1^2 + l2^2)*(n1^2 + n2^2 - 1) ) ) / (n1^2 + n2^2 - 1)
(l1*n1 + l2*n2)^2 - (l1^2 + l2^2)*(n1^2 + n2^2 - 1) >= 0
n1 + n2 = n
n1 and n2 are non-negative integers
Simplify the inequality espression:
(l1*n1 + l2*n2)^2 - (l1^2 + l2^2)*(n1^2 + n2^2 - 1) = (l1^2 + l2^2) - (l1*n2 - l2*n1)^2
which brings us to the following system
d = ( (l1*n1 + l2*n2) +- sqrt( (l1^2 + l2^2) - (l1*n2 - l2*n1)^2 ) ) / (n1^2 + n2^2 - 1)
(l1^2 + l2^2) - (l1*n2 - l2*n1)^2 >= 0
n1 + n2 = n
n1 and n2 are non-negative integers
Factorizing the inequality,
d = ( (l1*n1 + l2*n2) +- sqrt( (l1^2 + l2^2) - (l1*n2 - l2*n1)^2 ) ) / (n1^2 + n2^2 - 1)
(sqrt(l1^2 + l2^2) - l1*n2 + l2*n1) * (sqrt(l1^2 + l2^2) + l1*n2 - l2*n1) >= 0
n1 + n2 = n
n1 and n2 are non-negative integers
So you have two cases for these restrictions:
Case 1:
d = ( (l1*n1 + l2*n2) +- sqrt( (l1^2 + l2^2) - (l1*n2 - l2*n1)^2 ) ) / (n1^2 + n2^2 - 1)
sqrt(l1^2 + l2^2) - l1*n2 + l2*n1 >= 0
sqrt(l1^2 + l2^2) + l1*n2 - l2*n1 >= 0
n1 + n2 = n
n1 and n2 are positive integers
or
Case 2:
d = ( (l1*n1 + l2*n2) +- sqrt( (l1^2 + l2^2) - (l1*n2 - l2*n1)^2 ) ) / (n1^2 + n2^2 - 1)
sqrt(l1^2 + l2^2) - l1*n2 + l2*n1 <= 0
sqrt(l1^2 + l2^2) + l1*n2 - l2*n1 <= 0
n1 + n2 = n
n1 and n2 are positive integers
we focus on case 1 and see that case 2 is not possible. Start by expressing n2 = n - n1, then substitute it in each of the two inequalities and isolate n1 on one side of each inequality. This procedure yields:
Case1:
d = ( (l1*n1 + l2*n2) +- sqrt( (l1^2 + l2^2) - (l1*n2 - l2*n1)^2 ) ) / (n1^2 + n2^2 - 1)
( l1*n - sqrt(l1^2 + l2^2) ) / (l1 + l2) <= n1 <= ( l1*n + sqrt(l1^2 + l2^2) ) / (l1 + l2)
n1 + n2 = n
n1 and n2 are positive integers
One can see that case 2 inverts the inequalities, which is impossible because the left side is less than the right one.
So the algorithm could be something like this:
function d = find_d(l1, l2, n)
{
if n = 1 and l1 > l2 {
return d = (l1^2 + l2^2) / (2*l1)
} else if n = 1 and l1 <= l2 {
return d = (l1^2 + l2^2) / (2*l2)
}
for integer n1 >= 0 starting from floor( ( l1*n - sqrt(l1^2 + l2^2) ) / (l1 + l2) ) to floor( ( l1*n + sqrt(l1^2 + l2^2) ) / (l1 + l2) ) + 1
{
n2 = n - n1
D = (l1^2 + l2^2) - (l1*n2 - l2*n1)^2
if D >= 0
{
d1 = ( (l1*n1 + l2*n2) - sqrt( D ) ) / (n1^2 + n2^2 - 1)
d2 = ( (l1*n1 + l2*n2) + sqrt( D ) ) / (n1^2 + n2^2 - 1)
if 0 < d1 < max(l1, l2) {
return d1
} else if 0 < d2 < max(l1, l2) {
return d2
} else {
return "could not find a solution"
}
}
}
}

This is a preliminary version, so I suggest to approach with some caution. I did not have enough time to check the algorithm whether there might be some close to degenerate cases, for which one may have to add somewhere few short loops with if statements. However, in general, this will probably work almost always. I am just posting a python implementation but when I find a bit more time and if you want me to, I can write down the math behind this algorithm. Some of the ideas from this algorithm can simplify the previous one for one corner.
import numpy as np
import math
import matplotlib.pyplot as plt
def sq_root(x, m, K):
return math.sqrt(x**2 - (K - m*x)**2)
def f(x, n, L):
return sq_root(x, n[0], L[0]) + sq_root(x, n[2], L[2]) + n[1]*x - L[1]
def df(x, n, L):
return ((1-n[0]**2)*x + L[0]*n[0])/sq_root(x, n[0], L[0]) + ((1-n[2]**2)*x + L[2]*n[2])/sq_root(x, n[2], L[2]) + n[1]
#Solving the nonlinear equation for d by using Newton's method:
def solve_f(n, L):
x = sum(L) / (sum(n) + 2)
y = f(x, n, L)
while abs(y) >= 0.0000001:
x = x - y / df(x, n, L)
y = f(x, n, L)
return x - y / df(x, n, L)
def find_n(L, N):
x0 = sum(L) / (N + 1)
# x <= x0
n = np.array([0,0,0])
n[0] = math.floor(L[0]/x0)
n[2] = math.floor(L[2]/x0)
n[1] = N - n[0] - n[2] - 1
return n
def find_d(L, N):
if N==1:
d2 = (L[2]**2 + L[1]**2 - L[0]**2)/(2*L[1])
return math.sqrt(L[0]**2 + d2**2), np.array([0,0,0])
n = find_n(L, N)
return solve_f(n, L), n
def find_the_points(L, N):
d, n = find_d(L, N)
d2 = math.sqrt(d**2 - (L[0]-n[0]*d)**2)
#d3 = math.sqrt(d**2 - (L[2]-n[2]*d)**2)
p = np.zeros((sum(n) + 3, 2))
p[ 0] = np.array([0, L[1]-L[0]])
p[-1] = np.array([L[1], L[1]-L[2]])
e_x = np.array([1,0])
e_y = np.array([0,1])
corner = np.array([0,L[1]])
for i in range(n[0]):
p[i+1] = p[0] + (i+1)*d*e_y
for i in range(n[1]+1):
p[n[0]+i+1] = corner + (d2 + i*d)*e_x
for i in range(n[2]):
p[-(2+i)] = p[-1] + (i+1)*d*e_y
return p, d, n
'''
Test example:
'''
# lengths of the three straight segments along the edges of a square of edge_length L2:
L1 = 5
L2 = 7
L3 = 3
L = np.array([L1, L2, L3])
N = 7
# N = number of points to be added
# If there are two corners then number of segments aligned with edges of square is N - 1
# total number of equidistant segments is N + 1
# n = n[0], n[1], n[2] represents the number of segments aligned with each
# striaght segment from the rectangular polyline along square's boundary
points, d, n = find_the_points(L, N)
print(points)
print(d)
print(n)
plt.figure()
plt.plot(points[:,0], points[:,1])
for j in range(points.shape[0]):
plt.plot(points[j,0], points[j,1], 'ro')
axx = plt.gca()
axx.set_aspect('equal')
plt.show() # if you need...

Pythagoras to the rescue.
Considering the case where n = 2 with one corner1. Rest of the cases will be likely similar just with more edge cases and possible configurations2.
Let us name the length of the vertical segment i and length of the horizontal segment j.
We are looking for a points X, Y, so that distance dist(ps,x) = dist(x,y) = dist(y,pe)
First, let's assume that the corner lies between points X and Y. In that case, we are looking for the solution of this equation:
x2 = (i - x)2 + (j - x)2 where i and j are known.
If the abovementioned equation has no solution, it means that the corner has to lie either between ps and X or between Y and pe. I will only cover the case of ps and X since the other one is symetrical:
x2 = i2 + (j-2x)2 is the equation for this case.
For more points and corners, there will just be more possible configurations of points and corners. However since the distance should be equal and the lengths are known, a series of quadratic equations will be most likely enough. The case for 5+ points and three corners will be a wee bit iffy though.
1 The case for n=1 will be nearly the same as the asymmetric variant of the n=2 that I will cover.
2Which will make them rather ugly.

The points on any one of the sides are to be equidistant according to the problem. Just guess the distance and use binary search to find the solution to any degree of accuracy. There's a slightly tricky part in determining how many points lie on each rectangle side. (Hopefully it's just "slightly." :)

Related

Finding sum in less than O(N)

Question:
In less O(n) find a number K in sequence 1,2,3...N such that sum of 1,2,3...K is exactly half of sum of 1,2,3..N
Maths:
I know that the sum of the sequence 1,2,3....N is N(N+1)/2.
Therefore our task is to find K such that:
K(K+1) = 1/2 * (N)(N+1)/2 if such a K exists.
Pseudo-Code:
sum1 = n(n+1)/2
sum2 = 0
for(i=1;i<n;i++)
{
sum2 += i;
if(sum2 == sum1)
{
index = i
break;
}
}
Problem: The solution is O(n) but I need better such as O(n), O(log(n))...
You're close with your equation, but you dropped the divide by 2 from the K side. You actually want
K * (K + 1) / 2 = N * (N + 1) / (2 * 2)
Or
2 * K * (K + 1) = N * (N + 1)
Plugging that into wolfram alpha gives the real solutions:
K = 1/2 * (-sqrt(2N^2 + 2N + 1) - 1)
K = 1/2 * (sqrt(2N^2 + 2N + 1) - 1)
Since you probably don't want the negative value, the second equation is what you're looking for. That should be an O(1) solution.
The other answers show the analytical solutions of the equation
k * (k + 1) = n * (n + 1) / 2 Where n is given
The OP needs k to be a whole number, though, and such value may not exist for every chosen n.
We can adapt the Newton's method to solve this equation using only integer arithmetics.
sum_n = n * (n + 1) / 2
k = n
repeat indefinitely // It usually needs only a few iterations, it's O(log(n))
f_k = k * (k + 1)
if f_k == sum_n
k is the solution, exit
if f_k < sum_n
there's no k, exit
k_n = (f_k - sum_n) / (2 * k + 1) // Newton step: f(k)/f'(k)
if k_n == 0
k_n = 1 // Avoid inifinite loop
k = k - k_n;
Here there is a C++ implementation.
We can find all the pairs (n, k) that satisfy the equation for 0 < k < n ≤ N adapting the algorithm posted in the question.
n = 1 // This algorithm compares 2 * k * (k + 1) and n * (n + 1)
sum_n = 1 // It finds all the pairs (n, k) where 0 < n ≤ N in O(N)
sum_2k = 1
for every n <= N // Note that n / k → sqrt(2) when n → ∞
while sum_n < sum_2k
n = n + 1 // This inner loop requires a couple of iterations,
sum_n = sum_n + n // at most.
if ( sum_n == sum_2k )
print n and k
k = k + 1
sum_2k = sum_2k + 2 * k
Here there is an implementation in C++ that can find the first pairs where N < 200,000,000:
N K K * (K + 1)
----------------------------------------------
3 2 6
20 14 210
119 84 7140
696 492 242556
4059 2870 8239770
23660 16730 279909630
137903 97512 9508687656
803760 568344 323015470680
4684659 3312554 10973017315470
27304196 19306982 372759573255306
159140519 112529340 12662852473364940
Of course it becomes impractical for too large values and eventually overflows.
Besides, there's a far better way to find all those pairs (have you noticed the patterns in the sequences of the last digits?).
We can start by manipulating this Diophantine equation:
2k(k + 1) = n(n + 1)
introducing u = n + 1 → n = u - 1
v = k + 1 k = v - 1
2(v - 1)v = (u - 1)u
2(v2 - v) = u2 + u
2(4v2 - 4v) = 4u2 + 4u
2(4v2 - 4v) + 2 = 4u2 - 4u + 2
2(4v2 - 4v + 1) = (4u2 - 4u + 1) + 1
2(2v - 1)2 = (2u - 1)2 + 1
substituting x = 2u - 1 → u = (x + 1)/2
y = 2v - 1 v = (y + 1)/2
2y2 = x2 + 1
x2 - 2y2 = -1
Which is the negative Pell's equation for 2.
It's easy to find its fundamental solutions by inspection, x1 = 1 and y1 = 1. Those would correspond to n = k = 0, a solution of the original Diophantine equation, but not of the original problem (I'm ignoring the sums of 0 terms).
Once those are known, we can calculate all the other ones with two simple recurrence relations
xi+1 = xi + 2yi
yi+1 = yi + xi
Note that we need to "skip" the even ys as they would lead to non integer solutions. So we can directly use theese
xi+2 = 3xi + 4yi → ui+1 = 3ui + 4vi - 3 → ni+1 = 3ni + 4ki + 3
yi+2 = 2xi + 3yi vi+1 = 2ui + 3vi - 2 ki+1 = 2ni + 3ki + 2
Summing up:
n k
-----------------------------------------------
3* 0 + 4* 0 + 3 = 3 2* 0 + 3* 0 + 2 = 2
3* 3 + 4* 2 + 3 = 20 2* 3 + 3* 2 + 2 = 14
3*20 + 4*14 + 3 = 119 2*20 + 3*14 + 2 = 84
...
It seems that the problem is asking to solve the diophantine equation
2K(K+1) = N(N+1).
By inspection, K=2, N=3 is a solution !
Note that technically this is an O(1) problem, because N has a finite value and does not vary (and if no solution exists, the dependency on N is even meanignless).
The condition you have is that the sum of 1..N is twice the sum of 1..K
So you have N(N+1) = 2K(K+1) or K^2 + K - (N^2 + N) / 2 = 0
Which means K = (-1 +/- sqrt(1 + 2(N^2 + N)))/2
Which is O(1)

Calculating 1^X + 2^X + ... + N^X mod 1000000007

Is there any algorithm to calculate (1^x + 2^x + 3^x + ... + n^x) mod 1000000007?
Note: a^b is the b-th power of a.
The constraints are 1 <= n <= 10^16, 1 <= x <= 1000. So the value of N is very large.
I can only solve for O(m log m) if m = 1000000007. It is very slow because the time limit is 2 secs.
Do you have any efficient algorithm?
There was a comment that it might be duplicate of this question, but it is definitely different.
You can sum up the series
1**X + 2**X + ... + N**X
with the help of Faulhaber's formula and you'll get a polynomial with an X + 1 power to compute for arbitrary N.
If you don't want to compute Bernoulli Numbers, you can find the the polynomial by solving X + 2 linear equations (for N = 1, N = 2, N = 3, ..., N = X + 2) which is a slower method but easier to implement.
Let's have an example for X = 2. In this case we have an X + 1 = 3 order polynomial:
A*N**3 + B*N**2 + C*N + D
The linear equations are
A + B + C + D = 1 = 1
A*8 + B*4 + C*2 + D = 1 + 4 = 5
A*27 + B*9 + C*3 + D = 1 + 4 + 9 = 14
A*64 + B*16 + C*4 + D = 1 + 4 + 9 + 16 = 30
Having solved the equations we'll get
A = 1/3
B = 1/2
C = 1/6
D = 0
The final formula is
1**2 + 2**2 + ... + N**2 == N**3 / 3 + N**2 / 2 + N / 6
Now, all you have to do is to put an arbitrary large N into the formula. So far the algorithm has O(X**2) complexity (since it doesn't depend on N).
There are a few ways of speeding up modular exponentiation. From here on, I will use ** to denote "exponentiate" and % to denote "modulus".
First a few observations. It is always the case that (a * b) % m is ((a % m) * (b % m)) % m. It is also always the case that a ** n is the same as (a ** floor(n / 2)) * (a ** (n - floor(n/2)). This means that for an exponent <= 1000, we can always complete the exponentiation in at most 20 multiplications (and 21 mods).
We can also skip quite a few calculations, since (a ** b) % m is the same as ((a % m) ** b) % m and if m is significantly lower than n, we simply have multiple repeating sums, with a "tail" of a partial repeat.
I think Vatine’s answer is probably the way to go, but I already typed
this up and it may be useful, for this or for someone else’s similar
problem.
I don’t have time this morning for a detailed answer, but consider this.
1^2 + 2^2 + 3^2 + ... + n^2 would take O(n) steps to compute directly.
However, it’s equivalent to (n(n+1)(2n+1)/6), which can be computed in
O(1) time. A similar equivalence exists for any higher integral power
x.
There may be a general solution to such problems; I don’t know of one,
and Wolfram Alpha doesn’t seem to know of one either. However, in
general the equivalent expression is of degree x+1, and can be worked
out by computing some sample values and solving a set of linear
equations for the coefficients.
However, this would be difficult for large x, such as 1000 as in your
problem, and probably could not be done within 2 seconds.
Perhaps someone who knows more math than I do can turn this into a
workable solution?
Edit: Whoops, I see Fabian Pijcke had already posted a useful link about Faulhaber's formula before I posted.
If you want something easy to implement and fast, try this:
Function Sum(x: Number, n: Integer) -> Number
P := PolySum(:x, n)
return P(x)
End
Function PolySum(x: Variable, n: Integer) -> Polynomial
C := Sum-Coefficients(n)
P := 0
For i from 1 to n + 1
P += C[i] * x^i
End
return P
End
Function Sum-Coefficients(n: Integer) -> Vector of Rationals
A := Create-Matrix(n)
R := Reduced-Row-Echelon-Form(A)
return last column of R
End
Function Create-Matrix(n: Integer) -> Matrix of Integers
A := New (n + 1) x (n + 2) Matrix of Integers
Fill A with 0s
Fill first row of A with 1s
For i from 2 to n + 1
For j from i to n + 1
A[i, j] := A[i-1, j] * (j - i + 2)
End
A[i, n+2] := A[i, n]
End
A[n+1, n+2] := A[n, n+2]
return A
End
Explanation
Our goal is to obtain a polynomial Q such that Q(x) = sum i^n for i from 1 to x. Knowing that Q(x) = Q(x - 1) + x^n => Q(x) - Q(x - 1) = x^n, we can then make a system of equations like so:
d^0/dx^0( Q(x) - Q(x - 1) ) = d^0/dx^0( x^n )
d^1/dx^1( Q(x) - Q(x - 1) ) = d^1/dx^1( x^n )
d^2/dx^2( Q(x) - Q(x - 1) ) = d^2/dx^2( x^n )
... .
d^n/dx^n( Q(x) - Q(x - 1) ) = d^n/dx^n( x^n )
Assuming that Q(x) = a_1*x + a_2*x^2 + ... + a_(n+1)*x^(n+1), we will then have n+1 linear equations with unknowns a1, ..., a_(n+1), and it turns out the coefficient cj multiplying the unknown aj in equation i follows the pattern (where (k)_p = (k!)/(k - p)!):
if j < i, cj = 0
otherwise, cj = (j)_(i - 1)
and the independent value of the ith equation is (n)_(i - 1). Explaining why gets a bit messy, but you can check the proof here.
The above algorithm is equivalent to solving this system of linear equations.
Plenty of implementations and further explanations can be found in https://github.com/fcard/PolySum. The main drawback of this algorithm is that it consumes a lot of memory, even my most memory efficient version uses almost 1gb for n=3000. But it's faster than both SymPy and Mathematica, so I assume it's okay. Compare to Schultz's method, which uses an alternate set of equations.
Examples
It's easy to apply this method by hand for small n. The matrix for n=1 is
| (1)_0 (2)_0 (1)_0 | | 1 1 1 |
| 0 (2)_1 (1)_1 | = | 0 2 1 |
Applying a Gauss-Jordan elimination we then obtain
| 1 0 1/2 |
| 0 1 1/2 |
Result = {a1 = 1/2, a2 = 1/2} => Q(x) = x/2 + (x^2)/2
Note the matrix is always already in row echelon form, we just need to reduce it.
For n=2:
| (1)_0 (2)_0 (3)_0 (2)_0 | | 1 1 1 1 |
| 0 (2)_1 (3)_1 (2)_1 | = | 0 2 3 2 |
| 0 0 (3)_2 (2)_2 | | 0 0 6 2 |
Applying a Gauss-Jordan elimination we then obtain
| 1 1 0 2/3 | | 1 0 0 1/6 |
| 0 2 0 1 | => | 0 1 0 1/2 |
| 0 0 1 1/3 | | 0 0 1 1/3 |
Result = {a1 = 1/6, a2 = 1/2, a3 = 1/3} => Q(x) = x/6 + (x^2)/2 + (x^3)/3
The key to the algorithm's speed is that it doesn't calculate a factorial for every element of the matrix, instead it knows that (k)_p = (k)_(p-1) * (k - (p - 1)), therefore A[i,j] = (j)_(i-1) = (j)_(i-2) * (j - (i - 2)) = A[i-1, j] * (j - (i - 2)), so it uses the previous row to calculate the current one.

is there any O(logn) solution for [1+2a+3a^2+4a^3+....+ba^(b-1)] MOD M

Suppose we have a series summation
s = 1 + 2a + 3a^2 + 4a^3 + .... + ba^(b-1)
i need to find s MOD M, where M is a prime number and b is relatively big integer.
I have found an O((log n)^2) divide and conquer solution.
where,
g(n) = (1 + a + a^2 + ... + a^n) MOD M
f(a, b) = [f(a, b/2) + a^b/2*(f(a,b/2) + b/2*g(b/2))] MOD M, where b is even number
f(a,b) = [f(a,b/2) + a^b/2*(f(a,b/2) + b/2*g(b/2)) + ba(b-1)] MOD M, where b is odd number
is there any O(log n) solution for this problem?
Yes. Observe that 1 + 2a + 3a^2 + ... + ba^(b-1) is the derivative in a of 1 + a + a^2 + a^3 + ... + a^b. (The field of formal power series covers a lot of tricks like this.) We can evaluate the latter with automatic differentiation with dual numbers in time O(log b) arithmetic ops. Something like this:
def fdf(a, b, m):
if b == 0:
return (1, 0)
elif b % 2 == 1:
f, df = fdf((a**2) % m, (b - 1) / 2, m)
df *= 2 * a
return ((1 + a) * f % m, (f + (1 + a) * df) % m)
else:
f, df = fdf((a**2) % m, (b - 2) / 2, m)
df *= 2 * a
return ((1 + (a + a**2) * f) % m, (
(1 + 2 * a) * f + (a + a**2) * df) % m)
The answer is fdf(a, b, m)[1]. Note the use of the chain rule when we go from the derivative with respect to a**2 to the derivative with respect to a.

Tetranacci Numbers in Log(n)

I have stumbled upon a problem, which requires me to calculate the nth Tetranacci Number in O(log n).
I have seen several solutions for doing this for Fibonacci Numbers
I was looking to follow a similar procedure (Matrix Multiplication/Fast Doubling) to achieve this, but I am not sure how to do it exactly (take a 4 by 4 matrix and 1 by 4 in a similar fashion doesn't seem to work). With dynamic programming/general loops/any other basic idea, I am not able to achieve sub-linear runtime. Any help appreciated!
Matrix multiplication of course works. Here's how to derive the matrix.
What we want is to find the entries that make the equation
[a b c d] [T(n-1)] [T(n) ]
[e f g h] [T(n-2)] [T(n-1)]
[i j k l] [T(n-3)] = [T(n-2)]
[m n o p] [T(n-4)] [T(n-3)]
true for all n. Expand.
a T(n-1) + b T(n-2) + c T(n-3) + d T(n-4) = T(n)
e T(n-1) + f T(n-2) + g T(n-3) + h T(n-4) = T(n-1)
i T(n-1) + j T(n-2) + k T(n-3) + l T(n-4) = T(n-2)
m T(n-1) + n T(n-2) + o T(n-3) + p T(n-4) = T(n-3)
The obvious settings here are a = b = c = d = 1 (using the recurrence) and e = j = o = 1 and f = g = h = i = k = l = m = n = p = 0 (basic algebra).
The initial vector is
[T(3)] [1]
[T(2)] [0]
[T(1)] = [0]
[T(0)] [0]
by definition.
I have derived the Tetranacci doubling formulas from the corresponding matrix as described in the other answers. The formulas are:
T(2n) = T(n+1)*(2*T(n+2) - T(n+1)) + T(n)*(2*T(n+3) - 2*T(n+2) - 2*T(n+1) - T(n))
T(2n+1) = T(n)^2 + T(n+2)^2 + T(n+1)*(2*T(n+3) - 2*T(n+2) - T(n+1))
T(2n+2) = T(n+1)*(2*T(n) + T(n+1)) + T(n+2)*(2*T(n+3) - T(n+2))
T(2n+3) = T(n+1)^2 + T(n+3)^2 + T(n+2)*(2*T(n) + 2*T(n+1) + T(n+2))
With these, we can implement the "fast doubling" method. Here's one such implementation in Python, whose native support for arbitrary-sized integers is very convenient:
def tetranacci_by_doubling(n):
if n >= 0:
a, b, c, d = 0, 0, 0, 1 # T(0), T(1), T(2), T(3)
else: # n < 0
a, b, c, d = 1, 0, 0, 0 # T(-1), T(0), T(1), T(2)
# unroll the last iteration to avoid computing unnecessary values.
for i in reversed(range(1, abs(n).bit_length())):
w = b*(2*c - b) + a*(2*(d - c - b) - a)
x = a*a + c*c + b*(2*(d - c) - b)
y = b*(2*a + b) + c*(2*d - c)
z = b*b + d*d + c*(2*(a + b) + c)
a, b, c, d = w, x, y, z
if (n >> i) & 1 == 1:
a, b, c, d = b, c, d, a + b + c + d
if n & 1 == 0:
return b*(2*c - b) + a*(2*(d - c - b) - a) # w
else: # n & 1 == 1
return a*a + c*c + b*(2*(d - c) - b) # x
def tetranacci(n):
a, b, c, d = 0, 0, 0, 1 # T(0), T(1), T(2), T(3)
# offset by 3 to reduce excess computation for large positive `n`
n -= 3
if n >= 0:
for _ in range(+n):
a, b, c, d = b, c, d, a + b + c + d
else: # n < 0
for _ in range(-n):
a, b, c, d = d - c - b - a, a, b, c
return d
# sanity check
print(all(tetranacci_by_doubling(n) == tetranacci(n) for n in range(-1000, 1001)))
I would've liked to adjust the doubling formulas to be T(2n-3),T(2n-2),T(2n-1),T(2n) in terms of T(n-3),T(n-2),T(n-1),T(n) to slightly reduce excess computation for large n, but simplifying the shifted formulas is tedious.
Update
Swapped to an iterative version since I figured out how to make it cleanly handle negative n with minimal duplication. Originally, this was the sole advantage of the recursive version.
Incorporated a technique that's described in several papers about computing Fibonacci & Lucas numbers--which is to perform the final doubling step manually after the loop to avoid computing extra unneeded values. This results in about ~40%-50% speed-up for large n (>= 10^6)! This optimization could also be applied to the recursive version, as well.
The speed-up due to the unrolling of the last iteration is pretty interesting. It suggests that nearly half of the computational work is done in the final step. This kind of makes sense, since the number of digits in T(n) (and therefore the cost of arithmetic) approximately doubles when n doubles, and we know that 2^n ~= 2^0 + 2^1 + ... + 2^(n-1). Applying the optimization to similar Fibonacci/Lucas doubling algorithms produces a similar speed-up of ~40%--although, if you're computing Fibonacci/etc. modulo some 64-bit M, I suspect this optimization isn't as valuable.
From the OEIS, this is the (1,4) entry of the nth power of
1 1 0 0
1 0 1 0
1 0 0 1
1 0 0 0
To compute the nth power of that matrix in O(log n) operations, you can use exponentiation by squaring. There might be a slightly simpler recurrence, but you should be able to implement the general technique.

Θ notation for the sum of a geometric series

I have a question about geometric series. Why is
1 + c + c2 + ... + cn = Θ(cn)
when c > 1? I understand why it is Θ(n) if c = 1 and it is Θ(1) if c < 1, but I just can't figure out why it is Θ(cn) if c>1.
Thanks!
The sum of the first n terms of the geometric series
c0 + c1 + ... + cn-1
is given by the quantitiy
(cn - 1) / (c - 1)
Note that if c > 1, then this quantity is bounded from above by cn - 1 and from below by cn-1 - 1 / c. Therefore, it is O(cn) and Ω(cn), so it is Θ(cn).
Hope this helps!
Let c > 1 and g(c) = 1 + c + c2 + ... + cn.
The first thing to realize is that for some n we have S(n) = (cn+1 - 1) / (c - 1) where S(n) is the sum of the series.
So we have that (cn+1 - cn) / (c-1) <= (cn+1 - 1) / (c - 1) = S(n) since cn >= 1.
So (cn+1 - cn) / (c-1) = (cn(c-1)) / (c-1) = cn <= S(n)
Thus we have that S(n) >= cn.
Now that we have found our lower bound, let's look for the upper bound.
Observe that S(n) = (cn+1 - 1) / (c - 1) <= (cn+1) / (c - 1) = ((cn) c) / (c -1).
To simply our view of the algebra a bit, let y = c / (c-1) and substitute it into the equation above.
Hence, S(n) <= y * cn where y is just some constant since c is! This is an important observation since now it is just a multiple of cn.
So now we have found our upper bound as well.
Thus we have cn <= S(n) <= y * cn.
Therefore, S(n) = Θ(cn) when c > 1.

Resources