I have the following function -((A N1 P (A B k (a N1 + aa P - r) + a aa (b B - bb) k R + 2 A B r R))/k) -- (1)
This function can be rewritten as: - A R P N1 d/k --- (2)
where:
R is (k (aa B m - a mm + A B r))/(a aa (b B - bb) k + A B r)
P is (-a^2 b k mm - A B m r +
a k (aa bb m + A b B r))/(A (a aa (b B - bb) k + A B r))
N1 is (-aa^2 bb k m + A mm r +
aa k (a b mm - A bb r))/(A (a aa (b B - bb) k + A B r))
d is a aa (b B - bb) k + A B r
How can I make these substitutions in (1) to arrive at (2) in Mathematica?
Edit: I had made a small error in the coding for "d". I have edited the equation now.
As per suggestion, I have evaluated both expressions in (1) and (2) to ensure that it is of equal magnitude.
{a, A, aa, b, B, bb, k, m, mm, r} = RandomReal[{0, 20}, 10];
R = (k (aa B m - a mm + A B r))/(a aa (b B - bb) k + A B r);
P = (-a^2 b k mm - A B m r +
a k (aa bb m + A b B r))/(A (a aa (b B - bb) k + A B r));
N1 = (-aa^2 bb k m + A mm r +
aa k (a b mm - A bb r))/(A (a aa (b B - bb) k + A B r));
d = a aa (b B - bb) k + A B r;
{-((A N1 P (A B k (a N1 + aa P - r) + a aa (b B - bb) k R +
2 A B r R))/k), -A R P N1 d/k}
{-39976.5, -39976.5}
I can't guarantee the following workflow will succeed universally, but it works well here. It combines three ideas: (1) polynomial algebra to get closer to a nice result; (2) substitution to expand the variables; and (3) "collapsing" combinations of the variables ("terms") into single variables.
The setup
Begin by establishing the input: variables is just a list of the atomic variable names; terms is a list of the values to expand R, P, N1, and d into; and x is the original polynomial.
variables = {a, aa, b, bb, d, k, mm, r, A, B, R, P, N1};
terms = {(k (aa B m - a mm + A B r))/(a aa (b B - bb) k + A B r),
(-a^2 b k mm - A B m r + a k (aa bb m + A b B r))/(A (a aa (b B - bb) k + A B r)),
(-aa^2 bb k m + A mm r + aa k (a b mm - A bb r))/(A (a aa (b B - bb) k + A B r)),
a aa (b B - bb) k + A B r};
x = ((A N1 P (A B k (a N1 + aa P - r) + a aa (b B - bb) k R + 2 A B r R))/k);
From this information we can construct a list of replacement rules for the terms. These will carry out the substitution step.
rules = (Rule ## #) & /# Transpose[{{R, P, N1, d}, terms}]
For instance, the fourth component of Rules is
d -> a aa (b B - bb) k + A B r
and the first three components are comparable expressions for R, P, and N1, respectively.
The analysis
PolynomialReduce gives us a first crack at expressing x as a (rational) linear combination of terms plus any remainder that might fall out.
{parts, remainder} = PolynomialReduce[x, terms, variables]
{{0, 0, 0, (A N1 P R)/k}, a A^2 B N1^2 P + A^2 aa B N1 P^2 - A^2 B N1 P r + (A^2 B N1 P r R)/k}
The first piece, parts, contains the coefficients {0, 0, 0, (A N1 P R)/k}: the coefficients of the first three terms are zero and the coefficient of the last term (which eventually will be expressed as d) is A N1 P R/k, whence the result is that x has been expanded into the linear combination 0(R) + 0(P) + 0(N1) + (A N1 P R/k) d plus the remainder.
We have already made progress, but now it's time to work with the remainder. To do so, apply the substitution rules: Simplify[remainder /. rules]. To recreate x, this remainder needs to be added to the preceding linear combination. Let's do it all at once:
parts . rules [[;; , 1]] + Simplify[remainder /. rules]
(A d N1 P R)/k
Notice how using the target patterns in rules has implicitly collapsed a aa (b B - bb) k + A B r into d while the rules themselves simplified the remainder to 0. In general the remainder won't get that simple--but at least it's likely to be simpler than what you started with.
Closing comments
I believe that general manipulation of such algebraic expressions in an effort to twist one form into another that is "simple" in some sense is an NP-hard problem, so YMMV. My experience is that you have to experiment with simplifying complex expressions and augment that with your own algebraic skills as well as your sense of what form the simplification is likely to take.
For a quick check, we substitute in some random numbers to try to verify the original and reformatted expressions are equal. I replace D with d because D is predefined as a function in Mathematica and otherwise make no changes.
{a, A, aa, b, B, bb, k, m, mm, r}=RandomReal[{0,20},10];
R=(k (aa B m - a mm + A B r))/(a aa (b B - bb) k + A B r);
P=(-a^2 b k mm - A B m r + a k (aa bb m + A b B r))/(A (a aa (b B - bb) k + A B r));
N1=(-aa^2 bb k m + A mm r + aa k (a b mm - A bb r))/(A (a aa (b B - bb) k + A B r));
d=A (a aa (b B - bb) k + A B r);
{-((A N1 P (A B k (a N1 + aa P - r) + a aa (b B - bb) k R + 2 A B r R))/k),A R P N1 d/k}
which this time happens to give
{21112.3,-65366.1}
So the two expressions do not seem to be equal and I must have misunderstood. Can you explain what I need to do differently to verify the two expressions are equal?
Related
Suppose n be an integer > 2. How do we find 3 positive integers a, b, c, such that n = a+b+c and that their least common multiple, lcm(a,b,c), are as small as possible?
For example, 17 = 2+5+10 and lcm(2,5,10) = 10. However, 17=(1+8+8) and lcm(1,8,8)=8 also is possible. Thus, in this problem, the division of 17 into 1,8,8 is better than 2,5,10.
2 < n < 2^31
I have no idea about it, because the number might go up to 2^31.
I already know if n%3=0 then a=b=c=n/3, but I don't know how to do it when n%3!=0.
Assume without loss of generality that a ≥ b ≥ c. By an averaging argument, a ≥ n/3. If lcm(a, b, c) < 2n/3, then since a divides lcm(a, b, c), we must have lcm(a, b, c) = a, and b and c divide a.
If n is a power of two, then the optimal solution is n/2, n/4, n/4. Proof: the quoted solution is valid, so lcm(a, b, c) ≤ n/2. Since n/2 < 2n/3, it follows that b and c divide a ≤ n/2. Accordingly, a must be even, and b and c must be both odd or both even. If b and c are both odd, then a/2 ≥ b ≥ c, and so a + b + c = n only if b = c = a/2 = n/4. If b and c are both even, then we divide everything by 2 and argue by induction.
If n is not a power of two, then let its least odd prime divisor be p (find p using Pollard's rho or maybe sieving primes up to √231 and trial division); the optimal solution is (n/p) (p−1)/2, (n/p) (p−1)/2, n/p. Proof: the quoted solution is valid, so lcm(a, b, c) ≤ (n/p) (p−1)/2. Since (n/p) (p−1)/2 < 2n/3, it follows that b and c divide a ≤ (n/p) (p−1)/2. We must have b = a, or else a/2 ≥ b ≥ c would imply that n ≤ 2a ≤ 2 (n/p) (p−1)/2 = n (1 − 1/p), which is false. Accordingly, the solution has the form (n − c)/2, (n − c)/2, c. The optimal solution takes c to be the largest proper divisor of n having the same parity as n, which is c = n/p.
So here is an algorithm that is supposed to return the polynomial value of P(x) of a given polynomial with any given x.
A[] is the coefficient array and P[] the power of x array.
(e.g. x^2 +2*x + 1 would have: A[] = {1,2,1} , P[]= {2,1,0})
Also, recPower() = O(logn)
int polynomial(int x, int A[], int P[], int l, int r)
{
if (r - l == 1)
return ( A[l] * recPower(x, P[l]) ) + ( A[r] * recPower (x, P[r]) );
int m = (l + r) / 2;
return polynomial(x, A, P, l, m) + polynomial(x, A, P, m, r);
}
How do I go about calculating this time complexity? I am perplexed due to the if statement. I have no idea what the recurrence relation will be.
Following observation might help: As soon as we have r = l + 1, we spend O(logn) time and we are done.
My answer requires good understanding of Recursion Tree. So proceed wisely.
So our aim is to find : after how many iterations will we be able to tell that we have r = l + 1?
Lets find out:
Focusing on return polynomial(x, A, P, l, m) + polynomial(x, A, P, m, r);
Let us first consider left function polynomial(x, A, P, l, m). Key thing to note is that l , remains constant , in all subsequent left function called recursively.
By left function I mean polynomial(x, A, P, l, m) and by right function I mean
polynomial(x, A, P, m, r).
For left function polynomial(x, A, P, l, m), We have:
First iteration
l = l and r = (l + r)/2
Second iteration
l = l and r = (l + (l + r)/2)/2
which means that
r = (2l + l + r)/2
Third iteration
l = l and r = (l + (l + (l + r)/2)/2)/2
which means that
r = (4l + 2l + l + r)/4
Fourth iteration
l = l and r = (l + (l + (l + (l + r)/2)/2)/2)/2
which means that
r = (8l + 4l + 2l + l + r)/8
This means in nth iteration we have:
r = (l(1 + 2 + 4 + 8 +......2^n-1) + r)/2^n
and terminating condition is r = l + 1
Solving (l(1 + 2 + 4 + 8 +......2^n-1) + r)/2^n = l + 1, we get
2^n = r - l
This means that n = log(r - l). One might say that in all subsequent calls of left function we ignored the other call, that is right function call. The reason is this:
Since in the right function call we l = m, where m is already a reduced , as we take the mean, and r = r, which is even more averaged this asymptotically wont have any effect on time complexity.
So our recursion tree will have maximum depth = log(r - l). Its true that not all levels will be fully populated, but for the sake of simplicity, we assume this in asymptotic analysis. So after reaching a depth of log(r - l), we call function recPower, which takes O(logn) time. Total nodes (assuming all levels above are full) at depth log(r - l) is 2^(log(r - l) - 1). For a single node , we take O(logn) time.
Therefore we have total time = O( logn*(2^(log(r - l) - 1)) ).
This might help:
T(#terms) = 2T(#terms/2) + a
T(2) = 2logn + b
Where a and b are constants, and #terms refer to number of terms in polynomial.
This recurrence relation can be solved using Master's Theorem or using the Recursion tree method.
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.
Foo(A,f,l)
**Precondition: A[f ...l] is an array of integers, f,l are two naturals ≥ 1 with f ≤ l.
if (f = l) then
return A[f]
else
m ← floor of((f+l)/2)
return min(Foo(A,f,m), Foo(A,m + 1,l))
end if
Correct me if I'm wrong, but I think this code returns the smallest integer of the array. But how do I figure out what the recurrence relation that describe the time complexity in terms of array A? Could you please guide me to the solution so I can understand? I don't even know where to begin.
The recurrence relation we can recover from the structure of the pseudocode. We can let T(n) represent the time taken by the algorithm as a function of the input size. For n = 1, the time is constant, say T(1) = a. Our question now is for larger n, how can we express T(n)?
We will be in the else clause for n > 1. We do some extra work - let's call it b - and then call the function twice, once for an input of size floor(n/2) and once for an input of size ceiling(n/2). So we can write this part of the recursion as T(n) = b + T(floor(n/2)) + T(ceiling(n/2)). We can now write out some terms.
n T(n)
1 a
2 b + a + a = b + 2a
3 b + b + 2a + a = 2b + 3a
4 b + b + 2a + b + 2a = 3b + 4a
5 b + b + 2a + 2b + 3a = 4b + 5a
... ...
k = (k-1)b + (k)a = kb - b + ka = k(a + b) - b
We find a guess that T(n) = (a + b)n - b for some constants a and b that depend upon the cost of amounts of work we might take as constant (note that computing (f + l) / 2 is not really constant in terms of n, but it will not change our analysis). We can prove this using mathematical induction:
T(1) = a = (a + b)(1) - b is right;
Assume that T(n) = (a + b)n - b for all n <= k.
Does T(k + 1) = (a + b)(k + 1) - b hold? Remember that T(k + 1) = b + T(floor((k+1)/2)) + T(ceiling((k+1)/2). Suppose k+1 is even and m = (k+1)/2. Then T(k+1) = b + 2T(m) = b + 2[(a + b)(m) - b] = b + 2(m)(a+b) - 2b = (2m)(a+b) - b = (k+1)(a+b) - b, as required. The case wherek + 1` is odd is left as an exercise.
This is linear.
You're right. It returns the smallest integer of the array.
And the complexity is
O(nlog(n)); n = size of the array
Explanation: In each call, you are breaking the array into two equal parts which calls up to f=l. It calls the function O(log(n)) times for each number in the array. So, total complexity is O(nlog(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.