Finite Difference Method for Solving ODEs Algorithm - algorithm

I'm trying to devise an algorithm for the finite difference method, but I'm a bit confused. The ODE in question is y''-5y'+10y = 10x, with y(0)=0 and y(1)=100. So I need a way to somehow obtain the coefficients that will multiply "y_i" from the relation:
And then store the resultant coefficients into a matrix, which will be the matrix of the system I'll solve trough Gauss-Jordan. The question boils down to how to obtain these coefficients and move them to the matrix. I thought about working out the coefficients by hand and then just inputing the matrix, but I need to do this for steps of size 0.1, 0.001 and 0.001, so that's really not a viable option here.

Let us assume the more general case of the ODE
c1 * y''(x) + c2 * y'(x) + c3 * y(x) + c4 * x = 0
with the boundary conditions
y(0) = lo
y(1) = hi
And you want to solve this for x ∈ [0, 1] with a step size of h = 1 / n (where n + 1 is the number of samples). We want to solve for the yi = y(h * i). The yi range from i ∈ [0, n]. To do this, we want to solve a linear system
A y = b
Every interior yi will impose a single linear constraint. Hence, we have n - 1 rows in A and n - 1 columns corresponding to the unknown yi.
To set up A and b, we can simply slide a window over our unknown yi (I assume zero-based indexing).
A = 0 //the zero matrix
b = 0 //the zero vector
for i from 1 to n - 1
//we are going to create the constraint for yi and store it in row i-1
//coefficient for yi+1
coeff = c1 / h^2 + c2 / h
if i + 1 < n
A(i - 1, i) = coeff
else
b(i - 1) -= coeff * hi //we already know yi+1
//coefficient for yi
coeff = -2 * c1 / h^2 - c2 / h + c3
A(i - 1, i - 1) = coeff
//coefficient for yi-1
coeff = c1 / h^2
if i - 1 > 0
A(i - 1, i - 2) = coeff
else
b(i - 1) -= coeff * lo //we already know yi-1
//coefficient for x
b(i - 1) -= c4 * i * h
next

Related

Given the sequence Y as input, chooses a sequence X such the value of C is maximum

Given two sequences of integers X = (x1, x2, . . . , xn) and Y = (y1, y2, . . . , yn) such that 1 ≤ xi ≤ yi for all 1 ≤ i ≤ n.
And let C = Summation(from i=2 to n) |xi − xi-1|
Given the sequence Y as input, I have to choose a sequence X that maximizes C.
Here's what I tried :
I can easily observe that for Summation(i=2 to n) | xi - xi-1 | to be maximum either xi = yi or xi = 1 for all i in n.
But I do not know how to represent it mathematically.
|Xi - Xi-1| is maximized when Xi=MAX(Yi) and Xi-1=MIN(Yi) or Xi=MIN(Yi) and Xi-1=MAX(Yi).
So if 1 ≤ xi ≤ yi for all 1 ≤ i ≤ n. (A), would not hold, the X sequence would be:
X = MAX(yi), MIN(yi), MAX(yi), MIN(yi)....
or
X = MIN(yi), MAX(yi), MIN(yi), MAX(Yi)....
Now, because we need to fulfill (A) the above sequence is transformed to:
MAX(yi) -> MAX(Yi) such that MAX(Yi)<=Yi <=> MAX(Yi)=Yi
MIN(Yi) -> MIN(Yi) such that MIN(Yi)<=Yi <=> MIN(Yi)=1
So, in conclusion, X sequence is:
X = 1, Y2, 1, Y4....
or
X = Y1, 1, Y3, 1 ...
Calculating the Sum(|Xi-Xi-1|) for both the above, will give you the result.
EDIT:
As you correctly observe, each Xi will either be Yi or 1. That means, for a given Y sequence of Length N, the Number of valid X sequences are 2^N. So an easy (brute force, not optimal for sure) algorithm would be to create all this sequences, compute corresponding sum, and take the one that Sum is maximum.
As you correctly observed, for every i there are only 2 options: either xi = 1 or xi = yi. That still leaves 2n sequences to brute-force, though.
Luckily we can do better. We can just loop over the indices and keep track of two maximum sums:
the maximum sum given that xi = 1, let's call that maxLow, and
the maximum sum given that xi = yi, let's call that maxHigh
in the end we just need to take the maximum of those two.
Now we just need a way to update those two maximum sums but that's easy. There are 4 cases:
for xi-1 = 1 and xi = 1: maxLow = maxLow + |1 - 1|
for xi-1 = yi-1 and xi = 1: maxLow = maxHigh + |1 - yi-1|
for xi-1 = 1 and xi = yi: maxHigh = maxLow + |yi - 1|
for xi-1 = yi-1 and xi = yi: maxHigh = maxHigh + |yi - yi-1|
In code:
maxLow = 0
maxHigh = 0
for i = 2; i <= n; i++ {
maxLow = max(maxLow, maxHigh + Y[i-1] - 1)
maxHigh = max(maxLow + Y[i] - 1, maxHigh + abs(Y[i] - Y[i-1]))
}
result = max(maxLow, maxHigh)
This clearly runs in O(n) time.

Computing all infix products for a monoid / semigroup

Introduction: Infix products for a group
Suppose I have a group
G = (G, *)
and a list of elements
A = {0, 1, ..., n} ⊂ ℕ
x : A -> G
If our goal is to implement a function
f : A × A -> G
such that
f(i, j) = x(i) * x(i+1) * ... * x(j)
(and we don't care about what happens if i > j)
then we can do that by pre-computing a table of prefixes
m(-1) = 1
m(i) = m(i-1) * x(i)
(with 1 on the right-hand side denoting the unit of G) and then implementing f as
f(i, j) = m(i-1)⁻¹ * m(j)
This works because
m(i-1) = x(0) * x(1) * ... * x(i-1)
m(j) = x(0) * x(1) * ... * x(i-1) * x(i) * x(i+1) * ... * x(j)
and so
m(i)⁻¹ * m(j) = x(i) * x(i+1) * ... * x(j)
after sufficient reassociation.
My question
Can we rescue this idea, or do something not much worse, if G is only a monoid, not a group?
For my particular problem, can we do something similar if G = ([0, 1] ⊂ ℝ, *), i.e. we have real numbers from the unit line, and we can't divide by 0?
Yes, if G is ([0, 1] ⊂ ℝ, *), then the idea can be rescued, making it possible to compute ranged products in O(log n) time (or more accurately, O(log z) where z is the number of a in A with x(a) = 0).
For each i, compute the product m(i) = x(0)*x(1)*...*x(i), ignoring any zeros (so these products will always be non-zero). Also, build a sorted array Z of indices for all the zero elements.
Then the product of elements from i to j is 0 if there's a zero in the range [i, j], and m(j) / m(i-1) otherwise.
To find if there's a zero in the range [i, j], one can binary search in Z for the smallest value >= i in Z, and compare it to j. This is where the extra O(log n) time cost appears.
General monoid solution
In the case where G is any monoid, it's possible to do precomputation of n products to make an arbitrary range product computable in O(log(j-i)) time, although its a bit fiddlier than the more specific case above.
Rather than precomputing prefix products, compute m(i, j) for all i, j where j-i+1 = 2^k for some k>=0, and 2^k divides both i and j. In fact, for k=0 we don't need to compute anything, since the values of m(i, i+1) is simply x(i).
So we need to compute n/2 + n/4 + n/8 + ... total products, which is at most n-1 things.
One can construct an arbitrary interval [i, j] from at O(log_2(j-i+1)) of these building blocks (and elements of the original array): pick the largest building block contained in the interval and append decreasing sized blocks on either side of it until you get to [i, j]. Then multiply the precomputed products m(x, y) for each of the building blocks.
For example, suppose your array is of size 10. For example's sake, I'll assume the monoid is addition of natural numbers.
i: 0 1 2 3 4 5 6 7 8 9
x: 1 3 2 4 2 3 0 8 2 1
2: ---- ---- ---- ---- ----
4 6 5 8 3
4: ----------- ----------
10 13
8: ----------------------
23
Here, the 2, 4, and 8 rows show sums of aligned intervals of length 2, 4, 8 (ignoring bits left over if the array isn't a power of 2 in length).
Now, suppose we want to calculate x(1) + x(2) + x(3) + ... + x(8).
That's x(1) + m(2, 3) + m(4, 7) + x(8) = 3 + 6 + 13 + 2 = 24.

Calculating a triangular root using add, subtract, and halve

The rule in a particular game is that a character's power is proportional to the triangular root of the character's experience. For example, 15-20 experience gives 5 power, 21-27 experience gives 6 power, 28-35 experience gives 7 power, etc. Some players are known to have achieved experience in the hundreds of billions.
I am trying to implement this game on an 8-bit machine that has only three arithmetic instructions: add, subtract, and divide by 2. For example, to multiply a number by 4, a program would add it to itself twice. General multiplication is much slower; I've written a software subroutine to do it using a quarter-square table.
I had considered calculating the triangular root T(p) through bisection search for the successive triangular numbers bounding an experience number from above and below. My plan was to use a recurrence identity for T(2*p) until it exceeds experience, then use that as the upper bound for a bisection search. But I'm having trouble finding an identity for T((x+y)/2) in the bisection that doesn't use either x*y or (x+y)^2.
Is there an efficient algorithm to calculate the triangular root of a number with just add, subtract, and halve? Or will I end up having to perform O(log n) multiplications, one to calculate each midpoint in the bisection search? Or would it be better to consider implementing long division to use Newton's method?
Definition of T(x):
T(x) = (n * (n + 1))/2
Identities that I derived:
T(2*x) = 4*T(x) - x
# e.g. T(5) = 15, T(10) = 4*15 - 5 = 55
T(x/2) = (T(x) + x/2)/4
# e.g. T(10) = 55, T(5) = (55 + 5)/4 = 15
T(x + y) = T(x) + T(y) + x*y
# e.g. T(3) = 6, T(7) = 28, T(10) = 6 + 28 + 21 = 55
T((x + y)/2) = (T(x) + T(y) + x*y + (x + y)/2)/4
# e.g. T(3) = 6, T(7) = 28, T(5) = (6 + 28 + 21 + 10/2)/4 = 15
Do bisection search, but make sure that y - x is always a power of two. (This does not increase the asymptotic running time.) Then T((x + y) / 2) = T(x) + T(h) + x * h, where h is a power of two, so x * h is computable with a shift.
Here's a Python proof of concept (hastily written, more or less unoptimized but avoids expensive operations).
def tri(n):
return ((n * (n + 1)) >> 1)
def triroot(t):
y = 1
ty = 1
# Find a starting point for bisection search by doubling y using
# the identity T(2*y) = 4*T(y) - y. Stop when T(y) exceeds t.
# At the end, x = 2*y, tx = T(x), and ty = T(y).
while (ty <= t):
assert (ty == tri(y))
tx = ty
ty += ty
ty += ty
ty -= y
x = y
y += y
# Now do bisection search on the interval [x .. x + h),
# using these identities:
# T(x + h) = T(x) + T(h) + x*h
# T(h/2) = (T(h) + h/2)/4
th = tx
h = x
x_times_h = ((tx + tx) - x)
while True:
assert (tx == tri(x))
assert (x_times_h == (x * h))
# Divide h by 2
h >>= 1
x_times_h >>= 1
if (not h):
break
th += h
th >>= 1
th >>= 1
# Calculate the midpoint of the search interval
tz = ((tx + th) + x_times_h)
z = (x + h)
assert (tz == tri(z))
# If the midpoint is below the target, move the lower bound
# of the search interval up to the midpoint
if (t >= tz):
tx = tz
x = z
x_times_h += ((th + th) - h)
return x
for q in range(1, 100):
p = triroot(q)
assert (tri(p) <= q < tri((p + 1)))
print(q, p)
As observed in the linked page on math.stackexchange.com there is a direct formula for the solution of this problem and being x = n*(n+1)/2 then the reverse is:
n = (sqrt(1+8*x) - 1)/2
Now there is the square root and other things but I would suggest to use this direct formula with an implementation like the following:
tmp = x + x; '2*x
tmp += tmp; '4*x
tmp += tmp + 1; '8*x + 1
n = 0;
n2 = 0;
while(n2 <= tmp){
n2 += n + n + 1; 'remember that (n+1)^2 - n^2 = 2*n + 1
n++;
}
'here after the loops n = floor(sqrt(8*x+1)) + 1
n -= 2; 'floor(sqrt(8*x+1)) - 1
n /= 2; '(floor(sqrt(8*x+1)) - 1) / 2
Of course this can be improved for better performances if neede like considering that integer values of floor(sqrt(8*x+1)) + 1 are even so n can be incremented with steps of 2 (rewriting the n2 calculation accordingly: n2 += n + n + n + n + 4 that can itself be written better than this).

number of integral solutions

Question from the interview at f2f interview at MS:
Determine the number of integral solutions of
x1 + x2 + x3 + x4 + x5 = N
where 0 <= xi <= N
So basically we need to find the number of partitions of N in at most 5 parts
Supposed to be solved with paper and pencil. Did not make much headway though, does anybody have a solution for this?
Assume numbers are strictly > 0.
Consider an integer segment [0, N]. The problem is to split it into 4 segments of positive length. Imagine we do that by putting 4 splitter dots between adjacent numbers. How many ways to do that ? C(N-1, 4).
Now, some numbers can be 0-s. Let k be number of non-zero numbers. We can choose them in C(5,k) ways, for each having C(N-1, k) splittings. Accumulating by all k in [0,5] range, we get
Sum[ C(5,k) * C(n-1,k); k = 0 to 5]
#Grigor Gevorgyan indeed gives the right way to figure out the solution.
think about when
1 <= xi
that's exactly dividing N points into 5 segments. it's equivalent to insert 4 "splitter dots" out of N-1 possible places ( between adjacent numbers). So the answer is C(N-1,4)
then what about when
0 <= xi
?
If you have the solution of X+5 points in
1 <= xi
whose answer is C(N-1,4)=C(X+5-1,4)=C(X+4,4)
then you simply remove one point from each set, and you have a solution of X points, with
0 <= xi
which means,the answer now is exactly equal to C(X+4,4)
Topcoder tutorials
Look for the section "Combination with repetition" : The specific case is explained under that section with diagrmatic illustration .(A picture is worth quite a few words!)
You have the answer here.
It is classical problem -
Number of options to put N balls in M boxes = c(M+N-1,N).
The combinations solution is more appropriate if a pen and paper solution was asked. It's also the classic solution. Here is a dynamic programming solution.
Let dp[i, N] = number of solutions of x1 + x2 + ... +xi = N.
Let's take x1 + x2 = N:
We have the solutions:
0 + N = N
1 + N - 1 = N
...
N + 0 = N
So dp[2, N] = N + 1 solutions.
Let's take x1 + x2 + x3 = N:
We have the solutions:
0 + (0 + N) = N
0 + (1 + N - 1) = N
...
0 + (N + 0) = N
...
Notice that there are N + 1 solutions thus far. Moving on:
1 + (0 + N - 1) = N
1 + (1 + N - 2) = N
...
1 + (N - 1 + 0) = N
...
Notice that there are another N solutions. Moving on:
...
N - 1 + (0 + 1) = N
N - 1 + (1 + 0) = N
=> +2 solutions
N + (0 + 0) = N
=> +1 solution
So we have dp[3, N] = dp[2, N] + dp[2, N - 1] + dp[2, N - 2] + ... + dp[2, 0].
Also notice that dp[k, 0] = 1
Since for each row of the matrix we need N summations, the complexity for computing dp[k, N] is O(k*N), which is just as much as would be needed for the combinatorics solution.
To keep the complexity for each row O(N), store s[i] = sum of the first i elements on the previous row. The memory used can also be reduced to O(N).

Rounding rationals in (0, 1) to the nearest unit fraction

What's a good algorithm for the following problem?
Given a rational a / b strictly between 0 and 1, find a natural n that minimizes |a / b - 1 / n|.
The simplest algorithm I can think of is to compare a / b and 1 / m for m = b, b - 1, …, stopping when a / b ≤ 1 / m, and then compare |a / b - 1 / m| and |a / b - 1 / (m + 1)|. That's O( b ). Can you do any better?
Let k = floor(b/a) and then n must equal either k or k+1. Try the 2 candidates and see which one wins. This is O(1).
That this is true follows from the fact that 1/(k+1) <= a/b <= 1/k which in turn follows from the inequalities k <= b/a <= k+1.
I believe that you can do this in O(1) by using continued fractions. Any rational number in the range (0, 1] can be written in the form
1 / (a0 + 1 / (a1 + 1 / (a2 + 1 / (... an))))
Moreover, this representation has some remarkable properties. For starters, if you truncate the representation at any point, you get an extremely good approximation to the rational number. In particular, if you just truncate this representation at
1 / a0
Then the fraction a/b will be between 1/a0 and 1/(a0+1). Consequently, if we can get the value of a0, then you can just check the above two numbers to see which is closer.
The second important property is that there is a great way of obtaining the value of a0: it's given by the quotient of b/a. In other words, you can find the closest fraction as follows:
Compute x = b / a using integer division.
Check whether 1/x or 1/(x+1) is closer to a/b and output that result.
If a and b fit into machine words, this runs in O(1) time.
As suggested in the comments, your best bet is to use Ceiling and Floor functions.
If your rational a / b is given as 0 <= x <= 1 then you can simply do this:
int Rationalize(double x)
{
int n1 = floor(1 / x);
int n2 = ceiling(1 / x);
double e1 = abs(x - 1.0 / n1);
double e2 = abs(x - 1.0 / n2);
if (e1 < e2) return n1;
else return n2;
}
(Where it's assumed abs, floor, and ceiling are predefined)

Resources