10/15/19 7:38

# Motivation

The goal is to learn and explore L-Systems, as well as experiment with Jupyter Notebooks.

The purpose is to be able to model a basic L-System, then move on to more complex systems, with a focus on correctness of the model then visualization.

### Note

We will work on a concrete example first, then create a framework that can adapt to any (a large amount) L-System.

### Resources

We will be using the examples from the L-Systems Wikipedia Article.

https://en.wikipedia.org/wiki/L-system#Examples_of_L-systems

# Start

#setup
from enum import Enum
from collections import Iterable
 util

# from https://stackoverflow.com/a/40857703/
def flatten(items):
"""Yield items from any nested iterable; see Reference."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
for sub_x in flatten(x):
yield sub_x
else:
yield x

## Variables

We will use an enum to hold the variables of the current L-System

class Variable(Enum):
A = 'A'
B = 'B'

# for shorthand, we can use the following
A = Variable.A
B = Variable.B

## Constants

This system has no constants, so we will not create an enum for it this time.

## Axiom

This is the starting point/initial setup

axiom = Variable.A

## Rules

We can think of rules as text replacements, or state function transitions. Something like that.

The algae example has two rules, $\begin{equation} (A \rightarrow AB), (B \rightarrow A) \end{equation}$

We will be implementing these rules as one function.

def rule(v: Variable) -> List[Variable]
def rule(var: Variable) -> list:
if var == A:
return [A, B]
elif var == B:
return [A]
else:
print("FATAL: Unknown Variable: " + str(var))


Let’s inspect the results

rule(A)
[<Variable.A: 'A'>, <Variable.B: 'B'>]
rule(B)
[<Variable.A: 'A'>]

## System State

We will model the system state with the following Class

from typing import NamedTuple

class LSystem(NamedTuple):
n: int       # the iteration number
state: list  # the variables


## Initial State

We can describe our initial state as:

* n = 0
* state = axiom = [A]
algae_initial = LSystem(n=0, state=[axiom])

### Inspect

algae_initial
LSystem(n=0, state=[<Variable.A: 'A'>])
algae_sys = LSystem(n=0, state=[axiom])

## Transition

Let’s define a transition function that can be used to model what happens in one iteration.

def transition(sys: LSystem, rule_func) -> LSystem:
new_state = []
# for each letter, apply the rule function
# and save the result to the new state
for letter in sys.state:
new_state += rule_func(letter)

return LSystem(sys.n + 1, list(flatten(new_state)))

### Inspect

sys1 = transition(algae_sys, rule)
sys2 = transition(sys1, rule)
sys3 = transition(sys2, rule)

## Evaluate

This function will evalute an LSystem $$n$$ number of times and output the final system

def evaluate(sys: LSystem, rule_func, n: int) -> LSystem:
for _ in range(n):
sys = transition(sys, rule_func)

return sys

This function converts the state list of an LSystem to a string for easier comprehension and comparison/validation with the examples in the wikipedia article.

def state2str(sys_state: list) -> str:
return ''.join([letter.value for letter in sys_state])

### Inspect

algae7 = evaluate(algae_sys, rule, 7)
algae7str = state2str(algae7.state)
print(algae7str)
ABAABABAABAABABAABABAABAABABAABAAB

### Verify

The example for $$n = 7$$ in wikipedia gives the following result: $$ABAABABAABAABABAABABAABAABABAABAAB$$. Let’s see if our result matches this.

algae7str == 'ABAABABAABAABABAABABAABAABABAABAAB'  # Success!
True

# Final Remarks

The purpose of the notebook was to explore L Systems, and correctly implement an example from Wikipedia. In this notebook, we have successfully implemented Example 1: Algae.