# Featured Algorithms: l-systems

## L-systems ("Lindenmayer systems")

- Developed 1968 by Hungarian botanist Aristid Lindenmayer (1925–1989).
- Used to model growth processes of plant development.
- Can also be used to generate self-similar fractals.

----

### L-system basics

- Consist of:
    - Symbols used to make strings.
    - Rules to expand each symbol into longer string of symbols.
    - Initial "axiom" string from which to begin.
    - Loop.
- Loop applies rules to each symbol of new longer string at each pass.
- Produces self-similarity.

----

#### Simple example

- Symbols: `A`, `B`
- Rules: `A => AB`, `B => A`
- Axiom: `A`

<!-- end list -->

- Produces:

        pass 0 : A
        pass 1 : AB
        pass 2 : ABA
        pass 3 : ABAAB
        pass 4 : ABAABABA
        pass 5 : ABAABABAABAAB
        pass 6 : ABAABABAABAABABAABABA
        pass 7 : ABAABABAABAABABAABABAABAABABAABAAB 

----

##### Breakdown of example^[Adapted from University of Hamburg Biology webpages at http://www.biologie.uni-hamburg.de/b-online/e28_3/lsys.html/]

                 A
                _|_
               A   B
              _|   |
             A B   A
            _| |   |_
           A B A   A B
          _| | |_  |_ \   
         A B A A B A B A

    [etc.]

----

### In world of graphics and fractals

- "Turtle graphics".
- Symbols in resulting list mean "draw line" or "do nothing".
- Also add non-transforming symbols (*constants*) that mean 
    - "turn by angle *n*".
    - "begin branch".
    - etc.

----

#### L-system fractal example one^[Taken from one of the L-Systems Turtle
     Graphics Renderer demos at http://www.kevs3d.co.uk/dev/lsystems]

- Symbols: `A`, `B`
    - both mean "draw forward".
- Constants: `+`, `-`
    - `+` means "turn left by angle".
    - `-` means "turn right by angle".
- Rules: 
    - `A => B-A-B`
    - `B => A+B+A`
- Angle = 60 degrees
- Axiom: `A`

----

##### Graphic result of above L-system ("Sierpinksi Triangle")^[Image generated
      using L-Systems Turtle Graphics Renderer at
      http://www.kevs3d.co.uk/dev/lsystems] 

- 6 iterations:

\begin{figure}
\includegraphics[scale=0.20]{/Users/medward2/lisp/sc/workshops/resources/sierpinsky-60-6-lstgr-html5c.png}
\end{figure}

----

#### L-system fractal example two^[Adapted from one of the L-Systems Turtle
     Graphics Renderer demos at http://www.kevs3d.co.uk/dev/lsystems]

- Symbols: `F`, `X`
    - `F` means "draw forward".
    - `X` means "draw nothing" (i.e. constant).
- Constants: `-`, `+`, `[`, `]`
    - `-` means "turn left by angle".
    - `+` means "turn right by angle".
    - `[` means "create node and begin branch".
    - `]` means "end branch and return to most recent node".
- Rules: 
    - `X => F-[[X]+X]+F[+FX]-X`
    - `F => FF`
- Angle = 25 degrees
- Axiom: `X`

----

##### Graphic result of above L-system^[Image generated using L-Systems Turtle
      Graphics Renderer at http://www.kevs3d.co.uk/dev/lsystems]

- 6 iterations:

\begin{figure}
\includegraphics[scale=0.2]{/Users/medward2/lisp/sc/workshops/resources/plant-fractal-25-6-lstgr-html5c.png}
\end{figure}

----

### L-Systems in slippery chicken

- Creates self-similar lists based on elements, rules, and axiom.
    - No constants.
- Generates sequence of key references from rules.
- Uses these to retrieve data from `assoc-list` object. 
- `assoc-list` object stores data associated with each key reference.
- Data used in Fibonacci-based transitions.

----

#### First create an `l-for-lookup` object

- Use `make-l-for-lookup`.
- List of elements (keys with data).
- List of rules based on the elements.

<!-- end list -->

- For example, to create `l-for-lookup` based on rules `(A=>AB)` and `(B=>A)`:

        (make-l-for-lookup 'l-sys
                           '((1 ((a)))
                             (2 ((b))))
                           '((1 (1 2)) (2 (1))))

----

#### Then get L-system sequence from that object

#### Method one: Get L-sequence

- Specify `l-for-lookup` object to access.
- Specify axiom.
- Specify length of list to return.

~~~~
    (let* ((lfl (make-l-for-lookup 'l-sys
                                   '((1 ((a)))
                                     (2 ((b))))
                                   '((1 (1 2)) (2 (1))))))
       (get-l-sequence lfl 1 29))
       
    => (1 2 1 1 2 1 2 1 1 2 1 1 2 1 2 1 1 2 1 2 1 1 2 1 1 2 1 2 1)
       (18 11)
~~~~

- (18 11) shows the statistical distribution of the two elements.
- Strictly speaking, no list of elements required for corresponding
  `l-for-lookup` object '((1 ((a))) ....

----

##### Method two: Return data associated with keys

- `do-simple-lookup`.
    - Specify `l-for-lookup` object to access.
    - Specify axiom.
    - Specify length of list to return.

<!-- end list -->

    (let* ((lfl (make-l-for-lookup 'l-sys
                                   '((1 ((a)))
                                     (2 ((b))))
                                   '((1 (1 2)) (2 (1))))))
       (flatten (do-simple-lookup lfl 1 29)))

    => (A B A A B A B A A B A A B A B A A B A B A A B A A B A B A)

----

### Combining L-systems and Fibonacci-based transitions

#### `do-lookup`

- Data of at least one element must be sublists for transitions to be evident.
- For example, gradually replacing `A` with `C`:

<!-- end list -->

    (let* ((lfl (make-l-for-lookup 'l-sys-a
                                   '((1 ((a) (c)))
                                     (2 ((b))))
                                   '((1 (1 2)) (2 (1))))))
       (do-lookup lfl 1 73))

    => 
    (A B A A B A B A A B A C B A B A A B A B C A B A A B A B C A B A C B A B A
     C B A B C A B C C B A B C A B C B A C B C A B C B C A B C C B C B C C B)

----

### Non-L-system use of L-system object data

#### `get-linear-sequence`

- No rules necessary.
- Create list by collecting *next* element from data each time accessed.
    - When last data element collected, return to head of data list.
- Use data element collected as key for next collection.
    - All data elements must also be keys.

<!-- end list -->

\small 

    (let* ((lfl (make-l-for-lookup 'lfl-test
                                   '((1 ((2 3)))
                                     (2 ((3 1 2)))
                                     (3 ((1))))
                                   nil)))
       (get-linear-sequence lfl 1 23))

    => (1 2 3 1 3 1 2 1 3 1 2 2 3 1 3 1 2 1 3 1 2 2 3)

\normalsize

----

### Exercise: L-SYSTEMS

See http://michael-edwards.org/sc/workshop-exercises.lsp

