The time-corrected Verlet numerical integration formula - math

There is a commonly used verlet-integration formula on the web by Johnathan Dummer, called Time-Corrected Verlet. However I've read several forum posts, that people get weird or unexpected results with it in certain conditions.
Formula by Johnathan Dummer:
x1 = x + (x – x0) * dt / dt0 + a * dt^2
There is also a stackoverflow answer, which states that Dummer's time-corrected formula is broken and the poster presents his own derivation as the correct one.
Suggested correct formula by a stackoverflow answer
x1 = x + (x – x0) * dt / dt0 + a * dt * (dt + dt0) / 2
Well, is Dummer's formula really broken? If yes, is the derivation of the poster better?
PS: It is also weird that Dummer uses the verlet integration formula x1 = x - x0 + a * dt^2 on his website instead of the correct x1 = 2x - x0 + a * dt^2.

The wikipedia page Verlet integration - Non-constant time differences presents the two formula, without referenced. I've not checked the derivation myself but the reasoning for the second improved formula looks sound.
I've downloaded Dummer's spreadsheet and modified one of the formula to use the correction. The results are much better.
The exact results are in yellow, we see that just using the normal Verlet algorithm with fluctuating frame-rate is bad. Dummer's time-correct varient in red is pretty good, but a little off. The dark green version with the improved correction is much better.
For projectiles under gravity which has a quadratic solution you may find that the improved version is exact. When the degree gets a bit higher it will vary from the true path and it might be worth testing to see if we still get a better approximation.
Doing the same calculation for a sin curve shows the improved method is considerably better. Here Time-correct Verlet is drifting quite a bit. The improved version is better, only a little bit off the exact answer.
For the PS. Note that if you set dt=dt0 in the TCV formula
x1 = x + (x – x0) * dt / dt0 + a * dt^2
you get
x1 = x + x – x0 + a * dt^2
= 2 x – x0 + a * dt^2
the original Verlet formula.

The true derivation is based on Taylor formulas
x(t-h0) = x(t) - x'(t)*h0 + 0.5*x''(t)*h0^2 + O(h0^3)
x(t+h1) = x(t) + x'(t)*h1 + 0.5*x''(t)*h1^2 + O(h1^3)
and now eliminate x'(t) from these two formulas to get a Verlet-like formula
h0*x(t+h1) + h1*x(t-h0) = (h0+h1)*x(t) + 0.5*a(t)*h0*h1*(h0+h1) +O(h^3)
which makes a propagation formula
x(t+h1) = (1+h1/h0)*x(t) - h1/h0*x(t-h0) + 0.5*a(t)*h1*(h0+h1)
= x(t) + (x(t)-x(t-h0))*h1/h0 + 0.5*a(t)*h1*(h0+h1)
so that indeed the corrected formula is the correct one.
Note that if you use velocity Verlet steps
Verlet(dt) {
v += a * 0.5*dt
x += v*dt
a = acceleration(x)
v += a * 0.5*dt
}
then each step is indepentently symplectic, so that the change of step size between steps is absolutely unproblematic.
Notice that the main advantages of Verlet and other similar symplectic schemes over Runge-Kutta methods etc. crucially depends on using a fixed step. In detail, the modified energy function (and other more than quadratic constants of motion) that is largely constant under the numerical method is a modification of the exact energy where the difference scales with the step size. So when changing the step size a different modification gives a constant energy. Frequent changes of the step size allow thus, possibly, arbitrary changes of the energy level.

I decided to quit being lazy and show some kind of derivation of how the original Verlet method looks with a variable step size. Because it seems like this faulty adaptation by Dummer is more pervasive than I thought, which is saddening. I also noticed that, as the above answer points out, the correct version is now on wikipedia alongside the Dummer one, though it was added after my "suggested correct answer".
When I look at Verlet method, I see that it looks a lot like leapfrog, velocity Verlet, implicit Euler etc., which look like second-order versions of modified midpoint, and some of them may be identical. In each of these, to some degree they have a leapfrog idea where integration of acceleration (into velocity) and integration of constant velocity (into position) are each staggered so that they overlap by half. This brings things like time-reversibility and stability, which are more important for the 'realism' of a simulation than accuracy is. And the 'realism', the believability, is more important for video games. We don't care if something moves to a slightly different position than it's exact mass would have truly caused, so long as it looks and feels realistic. We're not calculating where to point our high-powered satellite telescopes to look at features on distant objects, or future celestial events. Here, stability and efficiency takes priority here over mathematical accuracy. So, it seems like leapfrog method is appropriate. When you adapt leapfrog for variable time step, it loses some of this advantage, and it loses some of it's appeal for game physics. Stormer-Verlet is like leapfrog, except it uses the average velocity of the previous step instead of a separately maintained velocity. You can adapt this Stormer-Verlet in the same way as leapfrog. To integrate velocity forward with a fixed acceleration, you use half the length of the previous step and half the length of the next step, because they are staggered. If the steps were fixed like true leapfrog, they would be the same length and so the two half lengths sum to one. I use h for step size, a/v/p for acceleration/velocity/position, and hl/pl for 'last' as in previous step. These aren't really equations, more like assignment operations.
Original leapfrog:
v = v + a*h
p = p + v*h
With variable time step:
v = v + a*hl/2 + a*h/2
p = p + v*h
Factor a/2:
v = v + a*(hl + h)/2
p = p + v*h
Use previous position (p - pl)/hl for initial velocity:
v = (p - pl)/hl + a*(hl + h)/2
p = p + v*h
Substitute, we don't need v:
p = p + ( (p - pl)/hl + a*(hl + h)/2)*h
Distribute h:
p = p + (p - pl)*h/hl + a*h*(h + hl)/2
The result is not as simple or fast as the original Stormer form of Verlet, 2p - pl + a*h^2. I hope this makes some sense. You would omit the last step in actual code, no need to multiply h twice.

Related

21 matchsticks # of possible games

I am sure everyone is familiar with the famous 21 matchsticks game where each person picks up 1,2 or 3 matches and the last person to pick up a match loses.
Let's simplify the game and assume that it is only possible to pick 1 or 2 matches. My question is, how many games are possible?
I know this is very easy to solve recursively, however, I am trying to come up with a combinatorial solution.
To provide an example, let's reduce 21 to just 4 matches. The number of possible games would be 5. {'MCM', 'MMMM', 'CC', 'CMM', 'MMC'}. Where C represents removing 2 matches and M represents removing a single match.
Symbolic method allows us to deduce that the generating function for this combinatorial class is
f(z) = 1/(1 - z - z^2 - z^3)
At this point, we can obtain the answer through a power series expansion, e.g. see here. The coefficient on z^21 will give the number of possible games in "21 matchsticks" (it might be 233317).
Looking back, suppose that players were allowed to take one match only. Then, there would be only one possible scenario. For each game length (power of z), there is only one game outcome:
1/(1 - z) = 1*1 + 1*z + 1*z^2 + 1*z^3 + 1*z^4 + 1*z^5 + ...
If players are allowed to take one or two matches, we have multiple scenarios:
1/(1 - z - z^2) = 1*1 + 1*z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + ...
The coefficients recover the Fibonacci sequence and can be interpreted as a number of integer compositions of n using only numbers 1 and 2.
Allowing for taking one, two or three matches leads to the following expansion,
1/(1 - z - z^2 - z^3) = 1*1 + 1*z + 2*z^2 + 4*z^3 + 7*z^4 + 13*z^5 + ...
which can be found in this OEIS sequence, cordially named the "Tribonacci numbers".
It is possible to arrive at the 233317 answer using pen, paper and a shifted generalization of the Pascal triangle, although I would leave that task to someone else.
As an aside, I highly recommend the book "Analytic Combinatorics" by Philippe Flajolet and Robert Sedgewick for their introduction to the symbolic method and beyond.

How does one find a recurrence equation (for this pseudocode)?

I've been tasked with finding the answers for the questions below, but honestly I'm completely lost as where to start. I'm not looking for straight answers per say (although they would be appreciated), but rather how I can find/derive them. I understand recursion, I just don't understand how to find a recurrence equation.
a.) Give the recurrence for the expected running time of RANDOM.
b.) Give the exact recurrence equation for the expected number of recursive calls executed by a call to RANDOM(n).
c.) Give the exact recurrence equation for the expected number of times the rerun statements on line 14 is executed, in all called to RANDOM(n), recursive or not.
Pseudocode:
Function RANDOM(u)
if u = 1 then
return(1)
else
assign x=0 with probability 1/2, or
assign x=1 with probability 1/3, or
assign x=2 with probability 1/6
if x=0 then
return(RANDOM(u-1) + RANDOM(u-2))
end-if
if x=1 then
return(RANDOM(u) + 2*RANDOM(u-1))
end-if
if x=2 then
return(3*RANDOM(u) + RANDOM(u) + 3)
end-if
end-if
end-RANDOM
First of all it is important to note that, since the questions ask for run time / no. of calls, the coefficients in front of the recursive calls to RANDOM don't matter (because none of the answers depend on the actual return value).
Also, since the questions ask for expected quantities, you can mix the appropriate recursive calls probabilistically.
a)
Starting off quite easy. Probabilistic mixing of functions:
T(u) = [1/2] * [T(u-1) + T(u-2)] +
[1/3] * [T(u) + T(u-1)] +
[1/6] * [T(u) + T(u) ] // + constant amount of work
b)
Same as before, but remember to add one for each call:
N(u) = [1/2] * [N(u-1) + N(u-2) + 2] +
[1/3] * [N(u) + N(u-1) + 2] +
[1/6] * [N(u) + N(u) + 2] // no constants here
c)
This is trickier than the other two. It seems contradictory that the question asks for "[all calls to RANDOM(u)] whether recursive or not", but only the ones on line 14 which are recursive...
Anyways ignoring this minor detail, the key thing to note is that the call to RANDOM(u) on line 11 can also produce the required recursive calls, without contributing to the total count itself. Adapting the above:
R(u) = [1/3] * [R(u) ] + // don't add 1 here
[1/6] * [R(u) + R(u) + 2] // add 2 as before
Note that the question probably expects you to rearrange all of the T(u), N(u), R(u) terms to the LHS. I'll leave that to you since it is trivial.

Best way to find the Coordinates of a Point on a Line-Segment a specified Distance Away from another Point [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
Image of the problem at:
In my code I have 4 points: Q, R ,S , T.
I know the following
Coordinates for R, T, and S;
That segment RT < RQ < RS;
I need to figure out the coordinates of Q.
I already know point Q can be found on the line segment TS. However I need to get the coordinates for Q and I need it to be a relatively efficient calculation.
I have several solutions for this problem but they are all so convoluted and long I know I must be doing something wrong. I feel certain there must a simple elegant way to solve this. The best solution would be one that minimizes the number of more intensive calculations but that also isn't ridiculously long.
Q is the intersecting point between a circle of radius d around R and the line TS, which leads to a quadratic equation with a number of parameters in the coefficients. I don't know if the following if “the best” solution (it may even be better to use a numerical solver in between), but it is completely worked out. Because I think it's more readable, I've changed your coordinate names to put T at (T1, T2), S at (S1, S2) and, to keep the formulas shorter, R at (0, 0) – just adjust S and T and the returned values accordingly.
tmp1 = S1^2 - S2*T2 - S1*T1 + S2^2;
tmp2 = sqrt(- S1^2*T2^2 + S1^2*d^2 + 2*S1*S2*T1*T2 - 2*S1*T1*d^2 -
S2^2*T1^2 + S2^2*d^2 - 2*S2*T2*d^2 + T1^2*d^2 + T2^2*d^2);
tmp3 = S1^2 - 2*S1*T1 + S2^2 - 2*S2*T2 + T1^1 + T2^2;
t = (tmp1 + tmp2)/tmp3;
if (0 > t || t > 1) {
// pick the other solution instead
t = (tmp1 - tmp2)/tmp3;
}
Q1 = S1+t*(T1-S1);
Q2 = S2+t*(T2-S2);
Obviously, I take no warranties that I made no typos etc. :-)
EDIT: Alternatively, you could also get a good approximation by some iterative method (say, Newton) to find a zero of dist(S+t*(T-S), R)-d, as a function of t in [0,1]. That would take nine seven multiplications and one division per Newton step, if I count correctly. Re-using the names from above, that would look something like this:
t = 0.5;
d2 = d^2;
S1T1 = S1 - T1;
S2T2 = S2 - T2;
do {
tS1T1 = S1 - t*S1T1;
tS2T2 = S2 - t*S2T2;
f = tS1T1*tS1T1 + tS2T2*tS2T2 - d2;
fp = 2*(S1T1*tS1T1 + S2T2*tS2T2);
t = t + f/fp;
} while (f > eps);
Set eps to control your required accuracy, but do not set it too low – computing f does involve a subtraction that will have serious cancellation problems near the solution.
Since there are two solutions Q on the (TS) line (with only one solution between T and S), any solution probably involves some choice of sign, or arccos(), etc.
Therefore, a good solution is probably to put Q on the (TS) line like so (with vectors implied):
(1) TQ(t) = t * TS
(where O is some origin). Requiring that Q be at a distance d from R gives a 2nd degree equation in t, which is easy to solve (again, vectors are implied):
d^2 = |RQ(t)|^2 = |RT + TQ(t)|^2
The coordinates of Q can then be obtained by putting a solution t0 into equation (1), via OQ(t0) = OT + TQ(t). The solution 0 <= t <= 1 must be chosen, so that Q lies between T and S.
Now, it may happen that the final formula has some simple interpretation in terms of trigonometric functions… Maybe you can tell us what value of t and what coordinates you find with this method and we can look for a simpler formula?

Minimizing a function containing an integral

Does anyone know how to minimize a function containing an integral in MATLAB? The function looks like this:
L = Int(t=0,t=T)[(AR-x)dt], A is a system parameter and R and x are related through:
dR/dt = axRY - bR, where a and b are constants.
dY/dt = -xRY
I read somewhere that I can use fminbnd and quad in combination but I am not able to make it work. Any suggestions?
Perhaps you could give more details of your integral, e.g. where is the missing bracket in [AR-x)dt]? Is there any dependence of x on t, or can we integrate dR/dt = axR - bR to give R=C*exp((a*x-b)*t)? In any case, to answer your question on fminbnd and quad, you could set A,C,T,a,b,xmin and xmax (the last two are the range you want to look for the min over) and use:
[x fval] = fminbnd(#(x) quad(#(t)A*C*exp((a*x-b)*t)-x,0,T),xmin,xmax)
This finds x that minimizes the integral.
If i didn't get it wrong you are trying to minimize respect to t:
\int_0^t{(AR-x) dt}
well then you just need to find the zeros of:
AR-x
This is just math, not matlab ;)
Here's some manipulation of your equations that might help.
Combining the second and third equations you gave gives
dR/dt = -a*(dY/dt)-bR
Now if we solve for R on the righthand side and plug it into the first equation you gave we get
L = Int(t=0,t=T)[(-A/b*(dR/dt + a*dY/dt) - x)dt]
Now we can integrate the first term to get:
L = -A/b*[R(T) - R(0) + Y(T) - Y(0)] - Int(t=0,t=T)[(x)dt]
So now all that matters with regards to R and Y are the endpoints. In fact, you may as well define a new function, Z which equals Y + R. Then you get
L = -A/b*[Z(T) - Z(0)] - Int(t=0,t=T)[(x)dt]
This next part I'm not as confident in. The integral of x with respect to t will give some function which is evaluated at t = 0 and t = T. This function we will call X to give:
L = -A/b*[Z(T) - Z(0)] - X(T) + X(0)
This equation holds true for all T, so we can set T to t if we want to.
L = -A/b*[Z(t) - Z(0)] - X(t) + X(0)
Also, we can group a lot of the constants together and call them C to give
X(t) = -A/b*Z(t) + C
where
C = A/b*Z(0) + X(0) - L
So I'm not sure what else to do with this, but I've shown that the integral of x(t) is linearly related to Z(t) = R(t) + Y(t). It seems to me that there are many equations that solve this. Anyone else see where to go from here? Any problems with my math?

Matrix transforms; concepts and theory, are there any free resources for learning practically? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I've been having fun rendering charts and graphs from co-ordinates lately, and I'm fascinated by using matrices to transform co-ordinate spaces.
I've been able to successfully scale and invert 2 dimensional co-ordinate spaces, but now my appetite is whetted. :)
Where can I go for clear, informative, (free), educational material on matrices, matrix math, especially as applies to 2 and 3 dimensional space?
Original answer: I'm not sure if you will like how mathematical courses typically introduce matrices. As a programmer, you might be happier with grabbing any decent 3D graphics book. It should certainly have very concrete 3x3 matrices. Also, find out the ones that will teach you projective transformations (projective geometry is a very beautiful area of low-dimensional geometry and easy to program).
Mini-course in matrix math with Python 3
Contents:
Matrices [Vector, __add__, reflect_y, rotate, dilate, transform]
Matrices: Overloaded [Matrix, __add__, __str__, __mul__, zero, det, inv, __pow__]
Bonus: Complex numbers
Matrices: The (R)evolution. It's already in the making (there's a summary at the end)
Preface: Based on my teaching experience, I think that the courses referenced by others are very good courses. That means if your goal is understanding matrices as mathematicians do then you should by all means get the whole course. But if your goals are more modest, here's my try at something more tailored to your needs (but still written with the goal to convey many theoretical concepts, kind of contradicting my original advice.)
How to use:
This post is long. You might consider printing this and going slow, like one part a day.
Code is essential. This is a course for programmers. Exercises are essential too.
You should take a look at the code companion which contains all this code and much more
It's "2 for the price of 1" special: you can also learn Python 3 here. And complex numbers.
I'll highly value any attempt to read this (do I officially qualify for the longest post ever?), so feel free to comment if you don't understand something (and also if you do).
Matrices
=
Vectors
Before matrices come vectors. You sure know how to handle the 2- and 3-dimensional vectors:
class Vector:
"""This will be a simple 2-dimensional vector.
In case you never encountered Python before, this string is a
comment I can put on the definition of the class or any function.
It's just one of many cool features of Python, so learn it here!
"""
def __init__(self, x, y):
self.x = x
self.y = y
now you can write
v = Vector(5, 3)
w = Vector(7, -1)
but it's not much fun by itself. Let's add more useful methods:
def __str__(self: 'vector') -> 'readable form of vector':
return '({0}, {1})'.format(self.x, self.y)
def __add__(self:'vector', v: 'another vector') -> 'their sum':
return Vector(self.x + v.x, self.y + v.y)
def __mul__(self:'vector', number: 'a real number') -> 'vector':
'''Multiplies the vector by a number'''
return Vector(self.x * number, self.y * number)
That makes things more interesting as we can now write:
print(v + w * 2)
and get the answer (19, 1) nicely printed as a vector (if the examples look unfamiliar, think how this code would look in C++).
Transformations
Now it's all cool to be able to write 1274 * w but you need more vector operations for the graphics. Here are some of them: you can flip the vector around the (0,0) point, you can reflect it around x or y axis, you can rotate it clockwise or counterclockwise (it's a good idea to draw a picture here).
Let's do some simple operations:
...
def flip(self:'vector') -> 'vector flipped around 0':
return Vector(-self.x, -self.y)
def reflect_x(self:'vector') -> 'vector reflected around x axis':
return Vector(self.x, -self.y)
print(v.flip(), v.reflect_x())
Question: is it possible to express flip(...) using the operations I had below? What about reflect_x?
Now you may wonder why I omitted reflect_y. Well, it's because I want you to stop for a moment and write your own version of it. Ok, here's mine:
def reflect_y(self:'vector') -> 'vector reflected around y axis':
return self.flip().reflect_x()
See, if you look at how this function computes, it's actually quite trivial. But suddenly an amazing thing happened: I was able to write a transformation using only the existing transformations flip and reflect_x. For all, I care, reflect_y could be defined in a derived class without access to x and y and it would still work!
Mathematicians would call these functions operators. They would say that reflect_y is an operator obtained by composition of operators flip and reflect_x which is
denoted by reflect_y = flip ○ reflect_x (you should see the small circle, a Unicode symbol 25CB).
Note: I will quite freely use the = symbol from now to denote that two operations produce the same result, like in the paragraph above. This is a "mathematical =", which cannot be expressed as a program.
So if I do
print(v.reflect_y())
I get the result (-5, 3). Go and picture it!
Question: Consider a composition reflect_y ◦ reflect_y. How would you name it?
Rotations
Those operations were nice and useful, but you are probably wondering why am so slow to introduce rotations. Ok, here I go:
def rotate(self:'vector', angle:'rotation angle') -> 'vector':
??????
At this point, if you know how to rotate vectors, you should go on and fill in the question marks. Otherwise please bear with me for one more simple case: counterclockwise rotation by 90 degrees. This one is not hard to draw on a piece of paper:
def rotate_90(self:'vector') -> 'rotated vector':
new_x = - self.y
new_y = self.x
return Vector(new_x, new_y)
Trying
x_axis = Vector(1, 0)
y_axis = Vector(0, 1)
print(x_axis.rotate_90(), y_axis.rotate_90())
now gives (0, 1) (-1, 0). Run it yourself!
Question: Prove that flip = rotate_90 ◦ rotate_90.
Anyway, I won't hide the secret ingredient for longer:
import math # we'll need math from now on
...
class Vector:
...
def rotate(self:'vector', angle:'rotation angle') -> 'rotated vector':
cos = math.cos(angle)
sin = math.sin(angle)
new_x = cos * self.x - sin * self.y
new_y = sin * self.x + cos * self.y
return Vector(new_x, new_y)
Now let's try something along the lines:
print(x_axis.rotate(90), y_axis.rotate(90))
If you expect the same result as before, (0, 1) (-1, 0), you're bound to be disappointed. That code prints:
(-0.448073616129, 0.893996663601) (-0.893996663601, -0.448073616129)
and boy, is it ugly!
Notation: I will say that we applied operation rotate(90) to x in the example above. The knowledge we gained is that rotate(90) != rotate_90.
Question: What happened here? How to express rotate_90 in terms of rotate? How to express flip in terms of rotate?
Dilations
Those rotations are certainly useful, but they are not everything you need to do even the 2D graphics. Consider the following transformations:
def dilate(self:'vector', axe_x:'x dilation', axe_y:'y dilation'):
'''Dilates a vector along the x and y axes'''
new_x = axe_x * self.x
new_y = axe_y * self.y
return Vector(new_x, new_y)
This dilate thing dilates the x and y axes in a possibly different way.
Exercise: Fill in the question marks in dilate(?, ?) = flip, dilate(?, ?) = reflect_x.
I will use this dilate function to demonstrate a thing mathematicians call commutativity: that is, for every value of parameters a, b, c, d you can be sure that
dilate(a, b) ◦ dilate(c, d) = dilate(c, d) ◦ dilate(a, b)
Exercise: Prove it. Also, is it true that for all possible values of parameters those below would hold?
`rotate(a) ◦ rotate(b) = rotate(b) ◦ rotate(a)`
`dilate(a, b) ◦ rotate(c) = rotate(c) ◦ dilate(a, b)`
`rotate(a) ◦ __mul__(b) = __mul__(b) ◦ rotate(a)`
Matrices
Let's summarize all the stuff we had around here, our operators on vector x
flip, reflect_x, *, rotate(angle), dilate(x, y)
from which one could make some really crazy stuff like
flip ◦ rotate(angle) ◦ dilate(x, y) ◦ rotate(angle_2) ◦ reflect_y + reflect_x = ???
As you create more and more complicated expressions, one would hope for some kind of order that would suddenly reduce all possible expressions to a useful form. Fear not! Magically, every expression of the form above can be simplified to
def ???(self:'vector', parameters):
'''A magical representation of a crazy function'''
new_x = ? * self.x + ? * self.y
new_y = ? * self.x + ? * self.y
return Vector(new_x, new_y)
with some numbers and/or parameters instead of ?s.
Example: Work out what the values of '?' are for __mul__(2) ◦ rotate(pi/4)
Another example: Same question for dilate(x, y) ◦ rotate(pi/4)
This allows us to write a universal function
def transform(self:'vector', m:'matrix') -> 'new vector':
new_x = m[0] * self.x + m[1] * self.y
new_y = m[2] * self.x + m[3] * self.y
return Vector(new_x, new_y)
which would take any 4-tuple of numbers, called matrix, and apply it to vector x. Here's an example:
rotation_90_matrix = (0, -1, 1, 0)
print(v, v.rotate_90(), v.transform(rotation_90_matrix))
which prints (5, 3) (-3, 5) (-3, 5). Note that if you apply transform with
any matrix to origin, you still get origin:
origin = Vector(0, 0)
print(origin.transform(rotation_90_matrix))
Exercise: what are the tuples m that describe flip, dilate(x, y), rotate(angle)?
As we part with the Vector class, here's an exercise for those who want to test both their vector math knowledge and Pythonic skills:
The final battle: Add to the Vector class all vector operations that you can come up with (how many standard operators can you overload for vectors? Check out my answer).
Matrices: Overloaded
=
As we found out in the previous section, a matrix can be thought of as a shorthand that allows us to encode a vector operation in a simple way. For example, rotation_90_matrix encodes the rotation by 90 degrees.
Matrix objects
Now as we shift our attention from vectors to matrices, we should by all means have a class
for matrix as well. Moreover, in that function Vector.transform(...) above the role of the matrix was somewhat misrepresented. It's more usual for m to be fixed while vector changes, so from now on our transformations will be methods of matrix class:
class Matrix:
def __init__(self:'new matrix', m:'matrix data'):
'''Create a new matrix.
So far a matrix for us is just a 4-tuple, but the action
will get hotter once The (R)evolution happens!
'''
self.m = m
def __call__(self:'matrix', v:'vector'):
new_x = self.m[0] * v.x + self.m[1] * v.y
new_y = self.m[2] * v.x + self.m[3] * v.y
return Vector(new_x, new_y)
If you don't know Python, __call__ overloads the meaning of (...) for matrices so I can use the standard notation for a matrix acting on a vector. Also, the matrices are usually written using a single uppercase letter:
J = Matrix(rotation_90_matrix)
print(w, 'rotated is', J(w))
Exercise: repeat this example with matrices from the previous exercise.
Addition
Now, let's find out what else we can do with matrices. Remember that matrix m is really just a way to encode an operation on vectors. Note that for two functions m1(x) and m2(x) I can create a new function (using lambda notation) m = lambda x: m1(x) + m2(x). It turns out if m1 and m2 were encoded by matrices, you can also encode this m using matrices!
Exercise: Think through any difficulties you might have with this statement.
You just have to add its data, like (0, 1, -1, 0) + (0, 1, -1, 0) = (0, 2, -2, 0). Here's how to add two tuples in Python, with some very useful and highly Pythonic techniques:
def __add__(self:'matrix', snd:'another matrix'):
"""This will add two matrix arguments.
snd is a standard notation for the second argument.
(i for i in array) is Python's powerful list comprehension.
zip(a, b) is used to iterate over two sequences together
"""
new_m = tuple(i + j for i, j in zip(self.m, snd.m))
return Matrix(new_m)
Now we can write expressions like J + J or even J + J + J, but to see the results we have to figure out how to print a Matrix. A possible way would be to print a 4-tuple of numbers, but let's take a hint from the Matrix.__call__ function that the numbers should be organized into a 2x2 block:
def as_block(self:'matrix') -> '2-line string':
"""Prints the matrix as a 2x2 block.
This function is a simple one without any advanced formatting.
Writing a better one is an exercise.
"""
return ('| {0} {1} |\n' .format(self.m[0], self.m[1]) +
'| {0} {1} |\n' .format(self.m[2], self.m[3]) )
If you look at this function in action you'll notice there is some room for improvement:
print((J + J + J).as_block())
Exercise: write a nicer function Matrix.__str__ that will round the
numbers and print them in the fields of fixed length.
Now you should be able to write the matrix for rotation:
def R(a: 'angle') -> 'matrix of rotation by a':
cos = math.cos(a)
sin = math.sin(a)
m = ( ????? )
return Matrix(m)
Exercise: Examine the code for Vector.rotate(self, angle) and fill in the question marks. Test with
from math import pi
print(R(pi/4) + R(-pi/4))
Multiplication
The most important thing we can do with one-parameter functions is compose them: f = lambda v: f1(f2(v)). How to mirror that with matrices? This requires us to examine how Matrix(m1) ( Matrix(m2) (v)) works. If you expand it, you'll notice that
m(v).x = m1[0] * (m2[0]*v.x + m2[1]*v.y) + m1[1] * (m2[2]*v.x + m2[3]*v.y)
and similarly for m(v).y, which, if you open the parentheses, looks suspiciously similar
to Matrix.__call__ using a new tuple m, such that m[0] = m1[0] * m2[0] + m1[2] * m2[2]. So let's take this as a hint for a new definiton:
def compose(self:'matrix', snd:'another matrix'):
"""Returns a matrix that corresponds to composition of operators"""
new_m = (self.m[0] * snd.m[0] + self.m[1] * snd.m[2],
self.m[0] * snd.m[1] + self.m[1] * snd.m[3],
???,
???)
return Matrix(new_m)
Exercise: Fill in the question marks here. Test it with
print(R(1).compose(R(2)))
print(R(3))
Math exercise: Prove that R(a).compose(R(b)) is always the same as R(a + b).
Now let me tell the truth: this compose function is actually how mathematicians decided to multiply matrices.
This makes sense as a notation: A * B is a matrix that describes operator A ○ B, and as we'll see next there are deeper reasons to call this 'multiplication' as well.
To start using multiplication in Python all we have to do is to order it so in a Matrix
class:
class Matrix:
...
__mul__ = compose
Exercise: Compute (R(pi/2) + R(pi)) * (R(-pi/2) + R(pi)). Try to find the answer yourself first on a piece of paper.
Rules for + and *
Let's make some good name for the matrix that corresponds to the dilate(a, b) operator. Now there's nothing wrong with D(a, b), but I'll
use a chance to introduce a standard notation:
def diag(a: 'number', b: 'number') -> 'diagonal 2x2 matrix':
m = (a, 0, 0, b)
return Matrix(m)
Try print(diag(2, 12345)) to see why it's called a diagonal matrix.
As the composition of operations was found before to be not always commutative, * operator won't be always commutative for matrices either.
Exercise: go back and refresh the commutativity thing if necessary. Then give examples of matrices A, B, made from R and diag,
such that A * B is not equal to B * A.
This is somewhat strange, since multiplication for numbers is always commutative, and raises the question whether compose really deserves to be called __mul__. Here's quite a lot of rules that + and * do satisfy:
A + B = B + A
A * (B + C) = A * B + A * C
(A + B) * C = A * C + B * C
(A * B) * C = A * (B * C)
There is an operation called A - B and (A - B) + B = A
Exercise: Prove these statements. How to define A - B in terms of +, *, and diag? What does A - A equal to? Add the method __sub__ to the class Matrix. What happens if you compute R(2) - R(1)*R(1)? What should it be equal to?
The (A * B) * C = A * (B * C) equality is called associativity and is especially nice since it means that we don't have to worry about putting parentheses in an expression
of the form A * B * C:
print(R(1) * (diag(2,3) * R(2)))
print((R(1) * diag(2,3)) * R(2))
Let's find analogues to regular numbers 0 and 1 and subtraction:
zero = diag(0, 0)
one = diag(1, 1)
With the following easily verifiable additions:
A + zero = A
A * zero = zero
A * one = one * A = A
the rules become complete, in the sense that there is a short name for them: ring axioms.
Mathematicians thus would say that matrices form a ring, and they indeed always use symbols + and * when talking about rings, and so shall we.
Using the rules it's possible to easily compute the expression from the previous section:
(R(pi/2) + R(pi)) * (R(-pi/2) + R(pi)) = R(pi/2) * R(-pi/2) + ... = one + ...
Exercise: Finish this. Prove that (R(a) + R(b)) * (R(a) - R(b)) = R(2a) - R(2b).
Affine Transformations
Time to return to how we defined matrices: they are a shortcut to some operations you can do with vectors, so it's something you can actually draw. You might want to take a pen or look at the materials that others suggested to see examples of different plane transformations.
Among the transformations, we'll be looking for the affine ones, those who look 'the same' everywhere (no bending). For example, a rotation around some point (x, y) qualifies. Now this one cannot be expressed as lambda v: A(v), but it can be written in the form lambda v: A(v) + b for some matrix A and vector b.
Exercise: find the A and b such that a rotation by pi/2 around the point (1, 0) has the form above. Are they unique?
Note that for every vector there is an affine transformation which is a shift by the vector.
An affine transformation may stretch or dilate shapes, but it should do in the same way everywhere. Now I hope you believe that the area of any figure changes by a constant number under the transformation. For a transformation given by matrix A this coefficient is called the determinant of A and can be computed applying the formula for an area to two vectors A(x_axis) and A(y_axis):
def det(self: 'matrix') -> 'determinant of a matrix':
return self.m[0]*self.m[3] - self.m[1] * self.m[2]
As a sanity check, diag(a, b).det() is equal to a * b.
Exercise: Check this. What happens when one of the arguments is 0? When it's negative?
As you can see, the determinant of rotation matrix is always the same:
from random import random
r = R(random())
print (r, 'det =', r.det())
One interesting thing about det is that it is multiplicative (it kind of follows from the definition if you meditate long enough):
A = Matrix((1, 2, -3, 0))
B = Matrix((4, 1, 1, 2))
print(A.det(), '*', B.det(), 'should be', (A * B).det())
Inverse
A useful thing you can do with matrices is writing a system of two linear equations
A.m[0]*v.x + A.m[1]*v.y = b.x
A.m[2]*v.x + A.m[3]*v.y = b.y
in a simpler way: A(v) = b. Let's solve the system as they teach in (some) high schools: multiply the first equation by A.m[3], second by -A.m1, and add (if in doubt, do this on a piece of paper) to solve for v.x.
If you really tried it, you should have got A.det() * v.x = (A.m[3]) * b.x + (-A.m[1]) * b.y, which suggests that you can always get v by multiplying b by some other matrix. This matrix is called inverse of A:
def inv(self: 'matrix') -> 'inverse matrix':
'''This function returns an inverse matrix when it exists,
or raises ZeroDivisionError when it doesn't.
'''
new_m = ( self.m[3] / self.det(), -self.m[1] / self.det(),
????? )
return Matrix(new_m)
As you see, this method fails loudly when the determinant of a matrix is zero. If you really want you can catch this exception with:
try:
print(zero.inv())
except ZeroDivisionError as e: ...
Exercise: Finish the method. Prove that inverse matrix doesn't exist when self.det() == 0. Write the method to divide matrices and test it. Use the inverse matrix to solve an equation A(v) = x_axis (A was defined above).
Powers
The main property of inverse matrix is that A * A.inv() always equals to one
Exercise: check that yourself. Explain why that should be so from the definition of the inverse matrix.
That's why mathematicians denote A.inv() by A-1. How about we write a
nice function to use A ** n notation for An? Note that the naive for i in range(n): answer *= self cycle is O(|n|) which is certainly too slow, because
this can be done with a complexity of log |n|:
def __pow__(self: 'matrix', n:'integer') -> 'n-th power':
'''This function returns n-th power of the matrix.
It does it more efficiently than a simple cycle. A
while loop goes over all bits of n, multiplying answer
by self ** (2 ** k) whenever it encounters a set bit.
...
Exercise: Fill in the details in this function. Test it with
X, Y = A ** 5, A ** -5
print (X, Y, X * Y, sep = '\n')
This function only works for integer values of n, even though for some matrices we can also define a fractional power, such as square root (in other words, a matrix B such that B * B = A).
Exercise: Find a square root of diag(-1, -1). Is this the only possible answer?
Find an example of a matrix that doesn't have a square root.
Bonus: Complex numbers
Here I'm going to introduce you to the subject in exactly one section!
Since it's a complex subject, I'm likely to fail, so please forgive me in advance.
First, similarly to how we have matrices zero and one, we can make a matrix out of any real number by doing diag(number, number). Matrices of that form can be added, subtracted, multiplied, inverted and the results would mimic what happens with the numbers themselves. So for all practical purposes, one can say that, e.g., diag(5, 5) is 5.
However, Python doesn't know yet how to handle expressions of the form A + 1 or 5 * B where A and B are matrices. If you're interested, you should by all means go and do the following exercise or look at my implementation (which uses a cool Python feature called decorator); otherwise, just know that it's been implemented.
Exercise for gurus: Change the operators in a Matrix class so that in all standard operations where one of the operands is a matrix and another a number, the number is automatically converted to the diag matrix. Also, add a comparison for equality.
Here's an example test:
print( 3 * A - B / 2 + 5 )
Now here's the first interesting complex number: the matrix J, introduced in the beginning and equal to Matrix((0, 1, -1, 0)), has a funny property that J * J == -1 (try it!). That means J is certainly not a normal number, but, as I just said, matrices and numbers easily mix together. For example,
(1 + J) * (2 + J) == 2 + 2 * J + 1 * J + J * J = 1 + 3 * J
using the rules listed sometime before. What happens if we test this in Python?
(1 + J) * (2 + J) == 1 + 3*J
That should happily say True. Another example:
(3 + 4*J) / (1 - 2*J) == -1 + 2*J
As you might have guessed, the mathematicians don't call those 'crazy numbers', but they do something similar - they call expressions of the form a + b*J complex numbers.
Because those are still instances of our Matrix class, we can do quite a lot of operations with those: addition, subtraction, multiplication, division, power - it's all already implemented! Aren't matrices amazing?
I have overlooked the question of how to print the result of an operation like E = (1 + 2*J) * (1 + 3*J) so that it looks like an expression with J rather than a 2x2 matrix. If you examine it carefully,
you'll see that you need to print the left column of that matrix in the format ... + ...J (just one more nice thing: it's exactly E(x_axis)!) Those who know the difference between str() and repr() should see it's natural to name a function that would produce expression of such form as repr().
Exercise: Write the function Matrix.__repr__ that would do exactly that and try some tests with it, like (1 + J) ** 3, first computing the result on paper and then trying it with Python.
Math question: What is the determinant of a + b*J? If you know what the absolute value of a complex number is: how they are connected? What is the absolute value of a? of a*J?
Matrices: The (R)evolution
=
In the final part of this trilogy, we will see that everything is a matrix. We'll start with general M x N matrices, and find out how vectors can be thought of as 1 x N matrices and why numbers are the same as diagonal matrices. As a side note, we'll explore the complex numbers as 2 x 2 matrices.
Finally, we will learn to write affine and projective transformations using matrices.
So the classes planned are [MNMatrix, NVector, Affine, Projective].
I guess if you were able to bear with me until here, you could be interested in this sequel, so I'd like to hear if I should continue with this (and where, since I'm pretty much sure I'm beyond what considered a reasonable length of a single document).
MIT has alot of their math courses' materials online at http://ocw.mit.edu/OcwWeb/Mathematics/. Once you have the basics down, they have the physics notes online too.
this is http://en.wikipedia.org/wiki/Computer_graphics. two of the key concepts are http://mathworld.wolfram.com/LinearTransformation.html, and http://mathworld.wolfram.com/AffineTransformation.html.
This MIT document is a must-have to get strong knowledge on the basics of Transformation.
http://stellar.mit.edu/S/course/6/fa08/6.837/courseMaterial/topics/topic2/lectureNotes/03_transform/03_transform.pdf
One of the best books for beginners is Carl Meyer's "Matrix Analysis and Applied Linear Algebra".
You can view the entire book online here (although it has a copyright watermark):
http://www.matrixanalysis.com/DownloadChapters.html
You might want to take a look at Chapter 5 pg. 326 - 332 which covers the rotations in 3 dimensional computer graphics
You may want to look at Geometric linear algebra by I-Hsiung Lin, Yixiong Lin (ISBN : 9812560874). The book is specifically geared towards what you want (linear transformations of 2 and 3-dimensional vector spaces) and treats it with a geometric approach in full, progressive detail (300 pages for each dimension). I'm afraid it's not free to buy, but you should be able to find it in any good university library. Otherwise Bookfinder should help you get it at a relatively modest price.
Jim Hefferon's free Linear Algebra textbook is really good. Unlike too many free ebooks, Jim has clearly taken the time to craft an excellent reader and introduction to linear algebra. It's not overly burdened with formal mathematical writing, which is often too dense with theorems and proofs to be easily comprehensible. It also contains lots of really excellent examples of real world applications of linear algebra - coordinate transformations being just one example. You can't beat the price, and it also comes with optional solutions to the exercises.
P.S. If coordinate transformations are your thing, you might be interested in differential geometry after you're done with linear algebra.
Those are the information that I found. Some of them might be valuable to You:
Theory:
Woflrams Information about matrices and additional ones on Wikipedia
Matrices by Pam Norton - very good book, available at Google Books for free.
Orthographic and perspective projections
3D transformations at MSDN
(Searching for "Matrices" at Google books gives You lots of lecutures, some of which are directly connected with transformations - this is one of the first results, but I cheer You to check more.)
Articles like this one, or maybe this or this are easily found with help of Google, so I will not post more.
There were also few questions about matrices on StackOverflow.com : Using 3d transformation matrices and How to apply a transformation matrix? are just first few examples, You can find more looking for the matrix or math tags.
I also encourage (I don't know if this is the right word, I am just learning English) You, to look for this kind of information in one of those books (though they are not free, but You can find large parts of older ones on Google Books):
Game programming gems 7
Game programming gems 6
Game programming gems 5
Game programming gems 4
Game programming gems 3
Game programming gems 2
Game programming gems
Each of those has section about math gems - and there are lots of neat tricks there. Those books are worth every cent.
There are also GPU Programming gems, so You might try them too.
Practice:
OpenGl Book at Wikipedia has section about matrices in OpenGl
(also, using matrices in OpenGl is described here and here)
Drawing 3D room in DirectX + info about matrix transformations.
If I will find more, I will edit and add links here, but to be honest - I found those links in about 10 minutes of using google. World's most popular browser stores data about everything - and yes, "everything" means matrices too.
Cheers, Mate.
I think you should spend a few days doing dot products and cross products with vectors in 3D. Then learn the relation between trig and vectors. After that the matrices will make a lot more sense to you.
MIT-OCW's course on Linear Algebra by Gilbert Strang. Incredible lectures by an incredible man; if your understanding of matrices is solely derived from programming sources (like MATLAB) then a course on Linear Algebra will definitely give you the fundamentals to do crazy things with matrices.
http://www.ocw.cn/OcwWeb/Mathematics/18-06Spring-2005/VideoLectures/index.htm

Resources