SICP Exercise 1.16 ... what does "invariant quantity" hint mean? - recursion

I see there are a few other questions around this exercise but none specifically are asking what is meant within the hint... "define the state transition in such a way that the product abn is unchanged from state to state".
They also mention that this idea of using an "invariant quantity" is a powerful idea with respect to "iterative algorithms". By the way, this problem calls for the design of a "logarithmic" exponent algorithm that has a space complexity of O(1).
Mainly I just have no idea what is meant by this hint and am pretty confused. Can anyone give me a nudge in what is meant by this? The only thing I can really find about "invariant quantities" are described using examples in physics which only makes this concept more opaque.
Exercise description in full:
Exercise 1.16: Design a procedure that evolves an iterative exponentiation process that uses successive squaring and uses a logarithmic number of steps, as does fast-expt. (Hint: Using the observation that (bn/2)2 = (b2)n/2, keep, along with the exponent n and the base b, an additional state variable a, and define the state transformation in such a way that the product abn is unchanged from state to state.
At the beginning of the process a is taken to be 1, and the answer is given by the value of a at the end of the process. In general, the technique of defining an invariant quantity that remains unchanged from state to state is a powerful way to think about the design of iterative algorithms.)
Thanks in advance.

This is not about any "logarithmic exponentiation", which is a very vague and confusing terminology.
As the quote you provided says, it is about exponentiation function that takes logarithmic number of steps to get its final result.
So we want to develop a function, exp(b,n), which would take O(log n) time to finish.
The numbers involved are all integers.
So how do we calculate bn? We notice that
b^n = b * b * b * b *... * b
`------n times------/ O(n) time process
and, when n is even,
b^n = b * b * b * b * ... * b *
`------n/2 times-----/
b * b * b * b * ... * b
`------n/2 times-----/
= (b^(n/2))^2 ; viewed from the side
= (b^2)^(n/2) ; viewed from above
and when n is odd,
b^n = b * b * b * b * ... * b *
`------n/2 times-----/
b * b * b * b * ... * b *
`------n/2 times-----/
b
`--1 time--/
= (b^(n/2))^2 * b
= (b^2)^(n/2) * b
Note that both expression fall into same category if we write the first one as (b^2)^(n/2) * 1.
Also note that the equation
b^n = (b )^(n ) * { a where a = 1 }
= (b ^2)^(n/2) * { a where a = ... }
= (b' )^(n' ) * { a' }
means that to calculate b^n * a is the same as to calculate b'^n' * a' with the changed values of { b' = b^2 ; n' = n/2 ; a' = {if {n is even} then {a} else {a * b}} }.
So we don't actually compute either of the sides of that equation. Instead we keep the triples { b, n, a } at each step and transform them according to that rule
{ b, n, a } --> { b', n', a' } --> ...
with the initial values of b and n as given to us, and the first a equal to 1; and know that the final result calculated from any of the triples would be the same if we'd actually calculated it somehow. We still don't know how exactly we'd do that; just that it would be the same. That's the "invariant" part.
So what all this is good for? Well, since the chain { n --> n/2 --> ... } will certainly reach a point where n == 1, we know that at that point we can break the chain since
c^1 * d == c * d
and this one simple multiplication of these two numbers will produce the same result as the initial formula.
Which is the final result of the function.
And that's the meaning of the hint: maintain the state of the computation as a (here) triple of numbers (or just three variables named b, n, a), and implement your computation as a chain of state-transforming steps. When the chain is broken according to some test (here, n == 1), we've reached our destination and can calculate the final result according to some simple rule (here, c * d).
This gives us a nice and powerful methodology for problem solving.
Oh, and we also know that the length of that chain of changing states is O(log n), since we halve that n at each step.

when fast-exp execute, the trace looks something like this
b^14 = (b^2)^7 ; where: b' = b^2; a = 1, n = 7
b^14 = (b^2)^6 * b^2 ; where: b' = b^2; a = b^2, n = 6
b^14 = ((b^2)^2)^3 *b^2 ; where: b' = b^2^2 ; a = b^2, n = 3
b^14 = ((b^2)^2)^2 *b^2 *(b^2)^2 ; where: b' = b^2^2; a = b^2*(b^2)^2, n = 2
notice that all these statements have the general form of b^n = b'^n' * a', and this does not change

Related

Keeping exact wave form in memory

Let's say I have a program that calculates the value of the sine wave at time t. The sine wave is of the form sin(f*t + phi). Amplitude is 1.
If I only have one sin term all is fine. I can easily calculate the value at any time t.
But, at runtime, the wave form becomes modified when it combines with other waves. sin(f1 * t + phi1) + sin(f2 * t + phi2) + sin(f3 * t + phi3) + ...
The simplest solution is to have a table with columns for phi and f, iterate over all rows, and sum the results. But to me it feels that once I reach thousands of rows, the computation will become slow.
Is there a different way of doing this? Like combining all the sines into one statement/formula?
If you have a Fourier series (i.e. f_i = i f for some f) you can use the Clenshaw recurrence relation which is significantly faster than computing all the sines (but it might be slightly less accurate).
In your case you can consider the sequence:
f_k = exp( i ( k f t + phi_k) ) , where i is the imaginary unit.
Notice that Im(f_k) = sin( k f t + phi_k ), that is your sequence.
Also
f_k = exp( i ( k f t + phi_k) ) = exp( i k f t ) exp( i phi_k )
Hence you have a_k = exp(i phi_k). You can precompute these values and store them in an array. For simplicity from now on assume a_0 = 0.
Now, exp( i (k + 1) f t) = exp(i k f t) * exp(i f t), so alpha_k = exp(i f t) and beta_k = 0.
You can now apply the recurrence formula, in C++ you can do something like this:
complex<double> clenshaw_fourier(double f, double t, const vector< complex<double> > & a )
{
const complex<double> alpha = exp(f * t * i);
complex<double> b = 0;
for (int k = a.size() - 1; k >0; -- k )
b = a[k] + alpha * b;
return a[0] + alpha * b;
}
Assuming that a[k] == exp( i phi_k ).
The real part of the answer is the sum of cos(k f t + phi_k), while the imaginary part is the sum of sin(k f t + phi_k).
As you can see this only uses addition and multiplications, except for exp(f * t * i) that is only computed once.
There are different bases (plural of basis) that can be advantageous (i.e. compact) for representing different waveforms. The most common and well-known one is that which you mention, called the Fourier basis usually. Daubechies wavelets for example are a relatively recent addition that cope with more discontinuous waveforms much better than a Fourier basis does. But this is really a math topic and probably if you post on Math Overflow you will get better answers.

Separate a number into fixed part

What is the algorithm to find the number way to separate number M to p part and no two part equal.
Example:
M = 5, P = 2
they are (1,4) (2,3). If P = 3 then no partition availabe, i.e
not (1,2,2) because there two 2 in partition.
In the expanded product
(1+x)(1+x2)(1+x3)...(1+xn)
find the coefficient of x^n. This gives the number of any possibility to represent n as sum of different numbers, i.e., a variable number of terms.
You want the number of possibilites to have
n = i1+i2+...+iP with i1 < i2 < ... < iP
which can be realized by setting
i1=j1, i2=i1+j2=j1+j2, ...
iP=iP-1+jP=j1+j2+...+jP with all jk > 0
so that the original task is the same as counting all the ways that one can solve
n = P * j1+(P-1) * j2+...+1 * jP with all jk > 0, but unrelated among each other.
The corresponding generator function is the product of the geometric series of the powers of x, omitting the constant term,
(x+x2+x3+...) * (x2+x4+x6+...) * (x3+x6+x9+...) * ... * (xP+x2*P+x3*P+...)
= xP*(P+1)/2 * (1+x+x2+...) * (1+x2+x4+...) * (1+x3+x6+...) * ... * (1+xP+x2*P+...)
Clearly, one needs n >= P*(P+1)/2 to get any solution at all. For P=3 that bound is n >= 6, so that n=5 has indeed no solutions in that case.
Algorithm
count = new double[N]
for k=0..N-1 do count[k] = 1
for j=2..P do
for k=j..N-1 do
count[k] += count[k-j]
Then count[k] contains the number of combinations for n=P*(P+1)/2+k.

Calculate bessel function in MATLAB using Jm+1=2mj(m) -j(m-1) formula

I tried to implement bessel function using that formula, this is the code:
function result=Bessel(num);
if num==0
result=bessel(0,1);
elseif num==1
result=bessel(1,1);
else
result=2*(num-1)*Bessel(num-1)-Bessel(num-2);
end;
But if I use MATLAB's bessel function to compare it with this one, I get too high different values.
For example if I type Bessel(20) it gives me 3.1689e+005 as result, if instead I type bessel(20,1) it gives me 3.8735e-025 , a totally different result.
such recurrence relations are nice in mathematics but numerically unstable when implementing algorithms using limited precision representations of floating-point numbers.
Consider the following comparison:
x = 0:20;
y1 = arrayfun(#(n)besselj(n,1), x); %# builtin function
y2 = arrayfun(#Bessel, x); %# your function
semilogy(x,y1, x,y2), grid on
legend('besselj','Bessel')
title('J_\nu(z)'), xlabel('\nu'), ylabel('log scale')
So you can see how the computed values start to differ significantly after 9.
According to MATLAB:
BESSELJ uses a MEX interface to a Fortran library by D. E. Amos.
and gives the following as references for their implementation:
D. E. Amos, "A subroutine package for Bessel functions of a complex
argument and nonnegative order", Sandia National Laboratory Report,
SAND85-1018, May, 1985.
D. E. Amos, "A portable package for Bessel functions of a complex
argument and nonnegative order", Trans. Math. Software, 1986.
The forward recurrence relation you are using is not stable. To see why, consider that the values of BesselJ(n,x) become smaller and smaller by about a factor 1/2n. You can see this by looking at the first term of the Taylor series for J.
So, what you're doing is subtracting a large number from a multiple of a somewhat smaller number to get an even smaller number. Numerically, that's not going to work well.
Look at it this way. We know the result is of the order of 10^-25. You start out with numbers that are of the order of 1. So in order to get even one accurate digit out of this, we have to know the first two numbers with at least 25 digits precision. We clearly don't, and the recurrence actually diverges.
Using the same recurrence relation to go backwards, from high orders to low orders, is stable. When you start with correct values for J(20,1) and J(19,1), you can calculate all orders down to 0 with full accuracy as well. Why does this work? Because now the numbers are getting larger in each step. You're subtracting a very small number from an exact multiple of a larger number to get an even larger number.
You can just modify the code below which is for the Spherical bessel function. It is well tested and works for all arguments and order range. I am sorry it is in C#
public static Complex bessel(int n, Complex z)
{
if (n == 0) return sin(z) / z;
if (n == 1) return sin(z) / (z * z) - cos(z) / z;
if (n <= System.Math.Abs(z.real))
{
Complex h0 = bessel(0, z);
Complex h1 = bessel(1, z);
Complex ret = 0;
for (int i = 2; i <= n; i++)
{
ret = (2 * i - 1) / z * h1 - h0;
h0 = h1;
h1 = ret;
if (double.IsInfinity(ret.real) || double.IsInfinity(ret.imag)) return double.PositiveInfinity;
}
return ret;
}
else
{
double u = 2.0 * abs(z.real) / (2 * n + 1);
double a = 0.1;
double b = 0.175;
int v = n - (int)System.Math.Ceiling((System.Math.Log(0.5e-16 * (a + b * u * (2 - System.Math.Pow(u, 2)) / (1 - System.Math.Pow(u, 2))), 2)));
Complex ret = 0;
while (v > n - 1)
{
ret = z / (2 * v + 1.0 - z * ret);
v = v - 1;
}
Complex jnM1 = ret;
while (v > 0)
{
ret = z / (2 * v + 1.0 - z * ret);
jnM1 = jnM1 * ret;
v = v - 1;
}
return jnM1 * sin(z) / z;
}
}

Calculate Triangle From Area And Angles

I'm trying to calculate triangles base on the Area and the angles. If Angle-B is 90° then the formula works, but in my case, the angle can be from 0.1° to 179.8°. The formula assumes that the angle is 90, so I was thinking that there might be something that is hidden that could work for very angle. Here is the formula:
The formula in code would be:
Height = sqrt((2 * Area) / (tan(Angle-A)));
I'm looking for the second half of the formula. Would the next part of the formula be something like this:
cos(sin(AngleB))
Okay, new try: If my calculations are correct, side B equals sqrt(2*area*sin(angle-B)/(sin(angle-A)*sin(angle-C))
Since Area = 1/2 * A * B * sin(c) = 1/2 * C * B * sin(a) = 1/2 * A * C * sin(b) we get:
A = 2 * area / (B * sin(c)) and using this we get:
C = sin(c) * B / sin(b) and when we place that back into the equation of area, we get:
B = sqrt(2*area*sin(angle-B)/(sin(angle-A)*sin(angle-C))
When you know one side and all the angles, calculating the other sides should be easy using normal trigonometry.
tziki's answer is correct, but I'd like to elaborate on how it's derived.
We start with angles and area as knowns. I'm going to use the labels in the OP's diagram for this explanation.
First we have the basic truth that the area of a triangle is half the product of its base and height: Area = base * height / 2. We want to be able to determine the relationship between base and height so that we can reduce this equation to one unknown and solve for base.
Another important thing to know is that the height of the triangle is proportional to Side-A: height = Side-A * sin(Angle-B). So knowing Side-A will give us the height.
Now we need to establish a relationship between Side-A and Side-C (the base). The most appropriate rule here is the sine law: Side-A/sin(A) = Side-C/sin(C). We re-arrange this equation to find Side-A in terms of Side-C: Side-A = Side-C * sin(A)/sin(C).
We can now insert this result into the height equation to get the formula for height in terms of Side-C only: height = Side-C * sin(A) * sin(B) / sin(C)
Using Side-C as the base in the area equation, we can now find the area in terms of Side-C only: Area = Side-C^2 * sin(A) * sin(B) / 2sin(C)
Then re-arrange this equation to find Side-C in terms of Area:
Side-C = SQRT(2 * Area * sin(C) / (sin(B) * (sin(A)))
And that gives you one side. This can be repeated to find the other sides, or you can use a different approach to find the other sides knowing this one.
You already have your answer, but I had to solve this kind of exercise for a job interview some time ago. It's not hard, and it didn't took me much time to arrive to the following solution.
Read it through and it should be self explanatory.
Create a Python module that solves triangles by aplying the sin and cosin theorems.
The module receives as parameters some of a triangle's values and, if possible, returns the values of all it's angles and side lengths.
The parameters are received as a dict and it should be able to be called stand-alone from the command line.
from __future__ import division
import sys, logging
from math import radians, degrees, acos, cos, sin, sqrt, asin
class InconsistentDataError(TypeError):
pass
class InsufficientDataError(TypeError):
pass
class NonUpdatable(dict):
"""Dictionary whose items can be set only once."""
def __setitem__(self, i, y):
if self.get(i, None):
raise InconsistentDataError()
super(NonUpdatable, self).__setitem__(i, y)
def get_known_sides(**kwarg):
"""Filter from the input elements the Side elements."""
return dict([i for i in kwarg.iteritems() if i[0].isupper()])
def get_known_angles(**kwarg):
"""Filter from the input elements the Angle elements."""
return dict([i for i in kwarg.iteritems() if i[0].islower()])
def get_opposite_angle(C, B, A):
"""
Get the angle corresponding to C.
Keyword arguments:
A -- right side of the angle (real number > 0)
B -- left side of the angle (real number > 0)
C -- side opposite to the angle (real number > 0)
Returns:
angle opposite to C
"""
return degrees(acos((A**2 + B**2 - C**2) / (2 * A * B)))
def get_side(A, B, c):
"""
Calculate the Side corresponding to the Angle c.
Keyword arguments:
A -- left side of C (real number > 0)
B -- right side of C (real number > 0)
c -- angle opposite to side C (real number)
Returns:
side C, opposite to c
"""
return sqrt(A**2 + B**2 - 2*A*B*cos(radians(c)))
def get_overlapping_angle(known_angles, known_sides):
"""
Calculate the Angle of a known side, knowing the angle to another known side.
Keyword arguments:
known_angles -- (dict of angles)
known_sides -- (dict of sides)
Returns:
angle of the known side, to which there is no known angle
"""
a = (set([i.lower() for i in known_sides.iterkeys()]) -
set([i.lower() for i in known_angles.iterkeys()])).pop()
b = (set([i.lower() for i in known_sides.iterkeys()]) &
set([i.lower() for i in known_angles.iterkeys()])).pop()
y = (known_sides[a.upper()]/known_sides[b.upper()]) * sin(radians(known_angles[b.lower()]))
if y > 1: y = 1 #Rounding error fix --- y = 1.000000000001; asin(y) -> Exception
return {a.lower(): degrees(asin(y))}
def get_angles(A, B, C):
"""
Calculate all the angles, given the length of all the sides.
Keyword arguments:
A -- side A (real number > 0)
B -- side B (real number > 0)
C -- side C (real number > 0)
Returns:
dict of angles
"""
sides = {"A":A,"B":B,"C":C}
_sides = sides.keys()
angles = {}
for side in sides.keys():
angles[side.lower()] = get_opposite_angle(
sides[_sides[0]],
sides[_sides[1]],
sides[_sides[2]])
_sides.append(_sides.pop(0))
return angles
def get_triangle_values(**kwargs):
"""Calculate the missing values of a triangle based on the known values."""
known_params = kwargs
angles = NonUpdatable({
"a":0,
"b":0,
"c":0,
})
sides = NonUpdatable({
"A":0,
"B":0,
"C":0,
})
if len(known_params) < 3:
raise InsufficientDataError("Three parameters are needed to calculate triangle's values.")
if str(known_params.keys()).islower():
raise TypeError("At least one length needed.")
known_sides = NonUpdatable(get_known_sides(**known_params))
sides.update(known_sides)
known_angles = NonUpdatable(get_known_angles(**known_params))
angles.update(known_angles)
if len(known_angles) == 3 and sum(known_angles.itervalues()) != 180:
raise InconsistentDataError("One of the sides is too long.")
if len(known_sides) == 3:
x=[side for side in known_sides.itervalues() if (sum(known_sides.itervalues()) - side) < side]
if len(x):
raise InconsistentDataError("One of the sides is too long.")
for angle, value in get_angles(**known_sides).iteritems():
# Done this way to force exception when overwriting a
# user input angle, otherwise it would be a simple assignment.
# >>> angles = get_angles(**known_sides)
# This means inconsistent input data.
angles[angle] = value
else: # There are angles given and not enough sides.
if len(known_angles) > 1:
#2 angles given. Get last angle and calculate missing sides
for angle, val in angles.iteritems():
if val == 0:
angles[angle] = 180. - sum(angles.itervalues())
known_sides = known_sides.items()
for side, length in sides.iteritems():
if length == 0:
sides[side] = known_sides[0][1] / \
sin(radians(angles[known_sides[0][0].lower()])) * \
sin(radians(angles[side.lower()]))
else:
unknown_side = (set(sides.keys()) - set(known_sides.keys())).pop()
chars = [ord(i.lower()) for i in known_params.iterkeys()]
chars.sort()
if chars[0] < chars[1] < chars[2]:
sides[unknown_side] = get_side(known_sides.values()[0], known_sides.values()[1], known_angles[unknown_side.lower()])
angles = get_angles(**sides)
else:
known_angles.update(get_overlapping_angle(known_angles, known_sides))
angles.update(known_angles)
for angle, val in angles.iteritems():
if val == 0:
angles[angle] = 180. - sum(angles.itervalues())
sides[unknown_side] = get_side(known_sides.values()[0], known_sides.values()[1], angles[unknown_side.lower()])
angles.update(sides)
return angles
if __name__ == "__main__":
try:
values = get_triangle_values( **eval(sys.argv[1], {}, {}) )
except IndexError, e:
values = get_triangle_values(A=10,B=10,C=10)
except InsufficientDataError, e:
print "Not enough data!"
exit(1)
except InconsistentDataError, e:
print "Data is inconsistent!"
exit(1)
print values
A, B and C are the side lengths and a, b and c are the angles, so c is the angle opposite to the side C.
Tests
How about calculating the lengths of two of the sides of a triangle where the third size is assigned a length of 1 (using the law of sines on the angles, with that side assigned length 1), then scale the triangle until its area matches the area you have? Then you can calculate the height fairly easily. http://en.wikipedia.org/wiki/Triangle_area#Using_trigonometry
If I made no mistake the length of a side x between two angles a and b should be the following.
________________
/ 2A 2A
x = / ------ + ------
\/ tan(a) tan(b)
So to calculate side-C you but in angle-A and angle-B.
(Now double checked it - seems to be correct.)
The formula you give for Side-A seems to be correct IF the triangle is isosceles, i.e., Angle-B = Angle-C (you get this using the law of sines and the sine formula for the area). If it is not isosceles, you seem to need to know the other angles; the general formula is:
Side-A = sqrt(2*Area*sin(Angle-A)/(sin(Angle-B)*sin(Angle-C)))
Of course, I did this in my head, so check the math ;)
Edit: Ok, fixed the formula after checkin on paper.

Solving a linear equation

I need to programmatically solve a system of linear equations in C, Objective C, or (if needed) C++.
Here's an example of the equations:
-44.3940 = a * 50.0 + b * 37.0 + tx
-45.3049 = a * 43.0 + b * 39.0 + tx
-44.9594 = a * 52.0 + b * 41.0 + tx
From this, I'd like to get the best approximation for a, b, and tx.
Cramer's Rule
and
Gaussian Elimination
are two good, general-purpose algorithms (also see Simultaneous Linear Equations). If you're looking for code, check out GiNaC, Maxima, and SymbolicC++ (depending on your licensing requirements, of course).
EDIT: I know you're working in C land, but I also have to put in a good word for SymPy (a computer algebra system in Python). You can learn a lot from its algorithms (if you can read a bit of python). Also, it's under the new BSD license, while most of the free math packages are GPL.
You can solve this with a program exactly the same way you solve it by hand (with multiplication and subtraction, then feeding results back into the equations). This is pretty standard secondary-school-level mathematics.
-44.3940 = 50a + 37b + c (A)
-45.3049 = 43a + 39b + c (B)
-44.9594 = 52a + 41b + c (C)
(A-B): 0.9109 = 7a - 2b (D)
(B-C): 0.3455 = -9a - 2b (E)
(D-E): 1.2564 = 16a (F)
(F/16): a = 0.078525 (G)
Feed G into D:
0.9109 = 7a - 2b
=> 0.9109 = 0.549675 - 2b (substitute a)
=> 0.361225 = -2b (subtract 0.549675 from both sides)
=> -0.1806125 = b (divide both sides by -2) (H)
Feed H/G into A:
-44.3940 = 50a + 37b + c
=> -44.3940 = 3.92625 - 6.6826625 + c (substitute a/b)
=> -41.6375875 = c (subtract 3.92625 - 6.6826625 from both sides)
So you end up with:
a = 0.0785250
b = -0.1806125
c = -41.6375875
If you plug these values back into A, B and C, you'll find they're correct.
The trick is to use a simple 4x3 matrix which reduces in turn to a 3x2 matrix, then a 2x1 which is "a = n", n being an actual number. Once you have that, you feed it into the next matrix up to get another value, then those two values into the next matrix up until you've solved all variables.
Provided you have N distinct equations, you can always solve for N variables. I say distinct because these two are not:
7a + 2b = 50
14a + 4b = 100
They are the same equation multiplied by two so you cannot get a solution from them - multiplying the first by two then subtracting leaves you with the true but useless statement:
0 = 0 + 0
By way of example, here's some C code that works out the simultaneous equations that you're placed in your question. First some necessary types, variables, a support function for printing out an equation, and the start of main:
#include <stdio.h>
typedef struct { double r, a, b, c; } tEquation;
tEquation equ1[] = {
{ -44.3940, 50, 37, 1 }, // -44.3940 = 50a + 37b + c (A)
{ -45.3049, 43, 39, 1 }, // -45.3049 = 43a + 39b + c (B)
{ -44.9594, 52, 41, 1 }, // -44.9594 = 52a + 41b + c (C)
};
tEquation equ2[2], equ3[1];
static void dumpEqu (char *desc, tEquation *e, char *post) {
printf ("%10s: %12.8lf = %12.8lfa + %12.8lfb + %12.8lfc (%s)\n",
desc, e->r, e->a, e->b, e->c, post);
}
int main (void) {
double a, b, c;
Next, the reduction of the three equations with three unknowns to two equations with two unknowns:
// First step, populate equ2 based on removing c from equ.
dumpEqu (">", &(equ1[0]), "A");
dumpEqu (">", &(equ1[1]), "B");
dumpEqu (">", &(equ1[2]), "C");
puts ("");
// A - B
equ2[0].r = equ1[0].r * equ1[1].c - equ1[1].r * equ1[0].c;
equ2[0].a = equ1[0].a * equ1[1].c - equ1[1].a * equ1[0].c;
equ2[0].b = equ1[0].b * equ1[1].c - equ1[1].b * equ1[0].c;
equ2[0].c = 0;
// B - C
equ2[1].r = equ1[1].r * equ1[2].c - equ1[2].r * equ1[1].c;
equ2[1].a = equ1[1].a * equ1[2].c - equ1[2].a * equ1[1].c;
equ2[1].b = equ1[1].b * equ1[2].c - equ1[2].b * equ1[1].c;
equ2[1].c = 0;
dumpEqu ("A-B", &(equ2[0]), "D");
dumpEqu ("B-C", &(equ2[1]), "E");
puts ("");
Next, the reduction of the two equations with two unknowns to one equation with one unknown:
// Next step, populate equ3 based on removing b from equ2.
// D - E
equ3[0].r = equ2[0].r * equ2[1].b - equ2[1].r * equ2[0].b;
equ3[0].a = equ2[0].a * equ2[1].b - equ2[1].a * equ2[0].b;
equ3[0].b = 0;
equ3[0].c = 0;
dumpEqu ("D-E", &(equ3[0]), "F");
puts ("");
Now that we have a formula of the type number1 = unknown * number2, we can simply work out the unknown value with unknown <- number1 / number2. Then, once you've figured that value out, substitute it into one of the equations with two unknowns and work out the second value. Then substitute both those (now-known) unknowns into one of the original equations and you now have the values for all three unknowns:
// Finally, substitute values back into equations.
a = equ3[0].r / equ3[0].a;
printf ("From (F ), a = %12.8lf (G)\n", a);
b = (equ2[0].r - equ2[0].a * a) / equ2[0].b;
printf ("From (D,G ), b = %12.8lf (H)\n", b);
c = (equ1[0].r - equ1[0].a * a - equ1[0].b * b) / equ1[0].c;
printf ("From (A,G,H), c = %12.8lf (I)\n", c);
return 0;
}
The output of that code matches the earlier calculations in this answer:
>: -44.39400000 = 50.00000000a + 37.00000000b + 1.00000000c (A)
>: -45.30490000 = 43.00000000a + 39.00000000b + 1.00000000c (B)
>: -44.95940000 = 52.00000000a + 41.00000000b + 1.00000000c (C)
A-B: 0.91090000 = 7.00000000a + -2.00000000b + 0.00000000c (D)
B-C: -0.34550000 = -9.00000000a + -2.00000000b + 0.00000000c (E)
D-E: -2.51280000 = -32.00000000a + 0.00000000b + 0.00000000c (F)
From (F ), a = 0.07852500 (G)
From (D,G ), b = -0.18061250 (H)
From (A,G,H), c = -41.63758750 (I)
Take a look at the Microsoft Solver Foundation.
With it you could write code like this:
SolverContext context = SolverContext.GetContext();
Model model = context.CreateModel();
Decision a = new Decision(Domain.Real, "a");
Decision b = new Decision(Domain.Real, "b");
Decision c = new Decision(Domain.Real, "c");
model.AddDecisions(a,b,c);
model.AddConstraint("eqA", -44.3940 == 50*a + 37*b + c);
model.AddConstraint("eqB", -45.3049 == 43*a + 39*b + c);
model.AddConstraint("eqC", -44.9594 == 52*a + 41*b + c);
Solution solution = context.Solve();
string results = solution.GetReport().ToString();
Console.WriteLine(results);
Here is the output:
===Solver Foundation Service Report===
Datetime: 04/20/2009 23:29:55
Model Name: Default
Capabilities requested: LP
Solve Time (ms): 1027
Total Time (ms): 1414
Solve Completion Status: Optimal
Solver Selected: Microsoft.SolverFoundation.Solvers.SimplexSolver
Directives:
Microsoft.SolverFoundation.Services.Directive
Algorithm: Primal
Arithmetic: Hybrid
Pricing (exact): Default
Pricing (double): SteepestEdge
Basis: Slack
Pivot Count: 3
===Solution Details===
Goals:
Decisions:
a: 0.0785250000000004
b: -0.180612500000001
c: -41.6375875
For a 3x3 system of linear equations I guess it would be okay to roll out your own algorithms.
However, you might have to worry about accuracy, division by zero or really small numbers and what to do about infinitely many solutions. My suggestion is to go with a standard numerical linear algebra package such as LAPACK.
Are you looking for a software package that'll do the work or actually doing the matrix operations and such and do each step?
The the first, a coworker of mine just used Ocaml GLPK. It is just a wrapper for the GLPK, but it removes a lot of the steps of setting things up. It looks like you're going to have to stick with the GLPK, in C, though. For the latter, thanks to delicious for saving an old article I used to learn LP awhile back, PDF. If you need specific help setting up further, let us know and I'm sure, me or someone will wander back in and help, but, I think it's fairly straight forward from here. Good Luck!
Template Numerical Toolkit from NIST has tools for doing that.
One of the more reliable ways is to use a QR Decomposition.
Here's an example of a wrapper so that I can call "GetInverse(A, InvA)" in my code and it will put the inverse into InvA.
void GetInverse(const Array2D<double>& A, Array2D<double>& invA)
{
QR<double> qr(A);
invA = qr.solve(I);
}
Array2D is defined in the library.
In terms of run-time efficiency, others have answered better than I. If you always will have the same number of equations as variables, I like Cramer's rule as it's easy to implement. Just write a function to calculate determinant of a matrix (or use one that's already written, I'm sure you can find one out there), and divide the determinants of two matrices.
Personally, I'm partial to the algorithms of Numerical Recipes. (I'm fond of the C++ edition.)
This book will teach you why the algorithms work, plus show you some pretty-well debugged implementations of those algorithms.
Of course, you could just blindly use CLAPACK (I've used it with great success), but I would first hand-type a Gaussian Elimination algorithm to at least have a faint idea of the kind of work that has gone into making these algorithms stable.
Later, if you're doing more interesting linear algebra, looking around the source code of Octave will answer a lot of questions.
From the wording of your question, it seems like you have more equations than unknowns and you want to minimize the inconsistencies. This is typically done with linear regression, which minimizes the sum of the squares of the inconsistencies. Depending on the size of the data, you can do this in a spreadsheet or in a statistical package. R is a high-quality, free package that does linear regression, among a lot of other things. There is a lot to linear regression (and a lot of gotcha's), but as it's straightforward to do for simple cases. Here's an R example using your data. Note that the "tx" is the intercept to your model.
> y <- c(-44.394, -45.3049, -44.9594)
> a <- c(50.0, 43.0, 52.0)
> b <- c(37.0, 39.0, 41.0)
> regression = lm(y ~ a + b)
> regression
Call:
lm(formula = y ~ a + b)
Coefficients:
(Intercept) a b
-41.63759 0.07852 -0.18061
function x = LinSolve(A,y)
%
% Recursive Solution of Linear System Ax=y
% matlab equivalent: x = A\y
% x = n x 1
% A = n x n
% y = n x 1
% Uses stack space extensively. Not efficient.
% C allows recursion, so convert it into C.
% ----------------------------------------------
n=length(y);
x=zeros(n,1);
if(n>1)
x(1:n-1,1) = LinSolve( A(1:n-1,1:n-1) - (A(1:n-1,n)*A(n,1:n-1))./A(n,n) , ...
y(1:n-1,1) - A(1:n-1,n).*(y(n,1)/A(n,n)));
x(n,1) = (y(n,1) - A(n,1:n-1)*x(1:n-1,1))./A(n,n);
else
x = y(1,1) / A(1,1);
end
For general cases, you could use python along with numpy for Gaussian elimination. And then plug in values and get the remaining values.

Resources