[Home]

J tutorial

# Spirograph

Have you seen spirographs? They are mathmatical toys to produce intricate, pleasing curves. A common incarnation consists of a gear rotating inside a toothed ring. A pen passes through a hole in the gear and touches the paper underneath. On rotating the gear two circular motions are superposed, and a spiral curve results.

It is easy to work out a parametric form of the curve. Each curcular motion is like $$(R\cos (\omega t + \phi), R\sin(\omega t+\phi)).$$ So if are superposing two such we should get $$(R_1\cos (\omega_1 t+\phi_1), R_1\sin(\omega_1 t+\phi_1)) + (R_2\cos (\omega_2 t+\phi_2), R_2\sin(\omega_2 t+\phi_2)).$$ It is not very difficult to code this up in any language that allows graphical output. We shall use J for this.

J is a strange language that achieves everything by combining some simple functions. The simple functions accept either one or two arguments. While this may sound like too much restriction, it isn't. Each argument is allowed to be a list (so you may pack as much info in a single argument, as you like. The advantage is that we can use the functions like operators like +, - etc in other languages. For example, let us write a function g that will take $\omega$ and $\phi$ and a list of $t$-values as input and produce $\sin(\omega t+ \phi)$ and $\cos(\omega t+ \phi).$ We shall package $\omega$ and $\phi$ into a single list, and the $t$-values into another. So we shall write
3 1 g t

to mean $\sin(3 t+ 1)$ and $\cos(3 t+ 1).$

Since we are packaging $\omega$ and $\phi$ into a single list, we should better be able to take them out, as well, when needed. The syntax is 0{x and 1{x. So the following code snippet hardly comes as a surprise
val=.(1{x) + (0{x) * y

Next you want to take $\sin$ and $\cos$ of these. J has a single function to compute both. It is called o.. Thus we want to do 2 o. val and 1 o. val and then to make a matrix with threse two as rows. J is great at factoring out code. since the o. val part is common to both, J will allow to factor that out. As a first effort, we may try 2 1 o. val. This produces an error. J is confused to see two lists on both sides. By default it tried to match the first element of the left hand list with the first element of the right hand list, and so on. This leads to an error as the two lists differ in length. Actually, we wanted to say: for each number in the left hand list, process the entire right hand side. J has a way of saying this: a number is of rank 0 and the entire right hand side has rank _. So we write 2 1 o."0 _ val.
g=.4 : '(2{x) * (2 1) o."(0 _)  (1{x) + (0{x) * y '
plot;/(3 1 1 g t) + (1 0 2g t)
plot;/((3 1 1)& g + (1 0 2) & g) t