I wrote a fractal tree using the usual side-effecting kind of turtle graphics and it occurred to me that a purer approach would build up paths algebraically from simpler paths as follows, using three kinds of primitive paths and three operations on paths:
Since concatenation and scaling distribute over superposition, I've chosen to analogize concatenation and scaling to multiplication and superposition to addition; both operations are associative, and superposition is commutative. (This means our multiplication operation is non-commutative, as in matrix multiplication.) o(0) is the identity element for both path concatenation and superposition.
(What happens if you concatenate onto the end of a superposition, (p + q) s? You could pick either p's endpoint or q's endpoint, making superposition no longer commutative and suggesting that it really ought to just be a gsave-grestore pair, or you could take the superposition's start point as its endpoint.)
This algebra turns out to be almost a vector space augmented with a vector–vector product similar to the cross-product; it fails to be a vector space because there are no additive inverses, and more seriously because n(pq) = (np)(nq) if n is a scalar factor, rather than (np)q as the vector-space axioms would demand.
The usual translation, uniform scaling, and rotation operations can be expressed by string rewriting. Path p translated by distance d at angle θ is just o(θ) dg o(-θ) (p), and the other two operations are provided natively by the notation as n(p) and o(θ) (p).
In this notation the fractal tree of the other page can be defined as
t = f (o(.85) .79t + o(-.35) .66t)
which, at least to my eyes, is considerably more pleasant than the imperative specification that page actually uses. It also makes it easy to show that the tree, in whatever sense it can be said to exist, has no finite positive length, while by contrast the tree u = f (o(1) .25u + o(-1) .25u) has total length 2 — we can define length straightforwardly as follows:
This gives us that len(u) = 1 + 0 + 0.25 len(u) + 0 + 0.25 len(u) = 1 + 0.5 len(u), whose unique solution is len(u) = 2. (The analogous exercise for t above says that len(t) ≈ -2.22.)
A perhaps more interesting computation on such self-referentially-defined paths might be to compute some kind of bounding area beyond which they are guaranteed not to extend. A slight variation on the length computation above provides a very conservative approximation — given some path p we can define a quantity r(p) as follows:
If some positive r exists, then p is guaranteed to be contained within a circle of radius r(p) centered on the starting point.
For t above, we have r(t) = 1 + 0.79 r(t) if we assume that it's positive, from which we have r(t) < 4.77. This is a fairly loose approximation, but it's finite and of the right order of magnitude; to get an arbitrarily close approximation, we can recurse into the definition of t sufficiently deep and place reduced-size circles as necessary. Such an algorithm can efficiently produce a reliable visual rendering of such an infinite object.
(Rotated, translated ellipses might be a better kind of bounding volume, although they have five dimensions instead of three.)
Circular and infinite rectangular arrays can be expressed easily with similarly self-referential formulas. A circular array
C(m, p) = p + o(2π/m) C(m, p)
is actually a finite object, geometrically speaking, as long as m is integer or at least rational. An infinite rectangular array is more troublesome:
R(a, b, p) = p + ag R(a, b, p) + o(π/2) bg o(-π/2) R(a, b, p)
Reliable finite-time rendering of such an object requires the computation of a negated bounding volume to prove that certain infinite branches of the recursion tree will be entirely out of view — perhaps similar to the modal interval arithmetic being used for some ray-tracing work nowadays.
The formula for the tree above is a finite-order approximation of t above: