First, we have a procedure that takes one triangle as input, and returns
three triangles with a side length of half the original. This is the basic
generation step for the gasket.

Note that it returns 3 triangles, NOT a list of 3 triangles.

OneToThree:=proc(tri) local mid1, mid2, mid3; mid1:=[(tri[1][1]+tri[2][1])/2,(tri[1][2]+tri[2][2])/2]; mid2:=[(tri[2][1]+tri[3][1])/2,(tri[2][2]+tri[3][2])/2]; mid3:=[(tri[3][1]+tri[1][1])/2,(tri[3][2]+tri[1][2])/2]; RETURN( [tri[1], mid1, mid3, tri[1] ], [mid1, tri[2], mid2, mid1 ], [mid2, tri[3], mid3, mid2 ]); end:

Now we write `gasket`, which takes a list of triangles as input, and
applies `OneToThree` to each triangle. It then repeats the process
on THAT list, numsteps times.

gasket:=proc(start,numsteps) local triangles, i, k; triangles:=start; for i from 1 to numsteps do triangles:=[seq(OneToThree(triangles[k]), k=1..nops(triangles))]; od; RETURN(triangles); end:

Finally, we have a handy utility routine that allows us to plot several disjoint curves (our triangles) on the same plot, with no axes.

PlotCurves:= proc(curvelist) local i; plots[display]( PLOT( seq(CURVES(curvelist[i]),i=1..nops(curvelist))), axes=none,scaling=constrained); end:

Now we are ready to make a Sierpinski gasket.

`FirstTri` is an equlateral triangle of side length 2, which we use for
our "level 0" gasket.

FirstTri := evalf([ [0,0], [1,sqrt(3)], [2,0], [0,0] ]): PlotCurves([FirstTri]);

We can now refine this a few times to get a level 3 gasket:

l3:= gasket([FirstTri], 3): PlotCurves(l3);

If we want, we can use the previous figure (`l3`) as input, and refine it
further. Thus, the following should give us a level 6 gasket:

l6:= gasket(l3 , 3): PlotCurves(l6);

Had we been so inclined, we could have written the gasket procedure recursively instead of iteratively. Here is one way to do that:

cheese:=proc(trilist,n) local i; if (n<=0) then RETURN(op(trilist)); else RETURN( seq(cheese([OneToThree(trilist[i])], n-1), i=1..nops(trilist))); fi; end:

This works by using `OneToThree` to triple each triangle in the list, as
`gasket` does. It then calls itself on the resulting list of 3
triangles, asking for one level less of decoration. When the number of
levels to go gets to zero, the input is returned (stripped of one level of
nesting).

As a consequence, notice that the output is a bunch of triangles, NOT a
list of triangles as in `gasket`. This means that we have to wrap the
result in brackets before we can feed it into `PlotCurves`.

The procedure `cheese` is not a better way than `gasket` to
make the Sierpinski gasket; they are just two different ways of doing the same
thing.

Here is the result.

PlotCurves([cheese([FirstTri],6)]);