Fractal string systems

The set of all strings over an alphabet \Sigma is self-similar. To see why, delete the first symbol from every nonempty string and you’re back to the same set of strings. The following program lets you pick a base — the size of \Sigma — and then identify a subset \Sigma'\subset\Sigma of symbols to retain. Strings containing only symbols in \Sigma' are retained; equivalently, strings containing any symbol in \Sigma-\Sigma' are deleted. As an example, set base to 3 under the keyboard model (so that \Sigma=\lbrace0,1,2\rbrace) and then clear the checkbox labeled 1 (\Sigma'=\lbrace0,2\rbrace). This deletes all strings containing the symbol 1 (color-coded green). For n = 4, you may recognize the resulting scene graph as the standard Cantor set. Importantly, this keyboard model, which maps strings to geometry, is defined for alphabet \Sigma= \lbrace0, 1, 2\rbrace of size 3, but gets applied to an alphabet \Sigma'=\lbrace0,2\rbrace of size 2. Gaps in the scene graph result.

Fractal string systems

To underscore the fractal nature of the set of all strings, we highlight the string set as a whole instead of the individual strings that comprise it. To do this, paint the entire scene a single color by setting the one color checkbox. Now the standard Cantor set is easy to see. To produce the Sierpinski carpet, set base to 9 under the squares model and uncheck 4. In general, the program provides two parameters to visualize the self-similarity of the set of strings over an alphabet with b' symbols. First, choice of model. Second, setting base equal to some value b>b' but retaining only b' of the symbols. The larger alphabet that the model assumes produces geometries exhibiting fractal-like patterns of gaps, of empty space.

Our implementation generalizes the applyModel function. The following function gets called with an includeSet containing the symbols to be retained (i.e., symbols whose checkboxes are set). The scene graph r passed to applyModel represents the modified alphabet of just the symbols contained in includeSet.

function applyModel(n, r, op, base, includeSet) {
    root = new THREE.Object3D();  
    root.add(r.clone());
    if (n > 1) {
        rp = applyModel(n-1, r, op, base, includeSet)
        for (let i of includeSet) {
            root.add(op(rp.clone(), i, base)); 
        }
    }
    return root;
}