L-Breeder Help: Genetic Engineering tutorial

# ---- Tutorial ----

## Genetic Engineering Tutorial:

The following tutorial is modified from the file TUTOR.TXT (version 1.0) written by Cees van der Mark jr., and distributed with the software package Lparser 4.0 by L.Lapre

> The first thing to understand is that there are two stages in translating an L-system to a 3 dimensional form: parsing and interpreting.

> - Parsing an L-system results in a single (albeit often very long) line of text: the L-string.
> - Interpreting this L-string relies on translating the characters in thestring into movements of a cursor in 3D space. This cursor (or "turtle" as it is sometimes called in computer aided design) has an orientation: i.e. it possesses a defined forwards (and backwards) direction. Certain characters are treated as special, specifying particular movements to the turtle: for example, the character "F" tells it to move forward by one full length, and connect the point moved from, to the point moved to, by a line. Other special characters and the movements to which they correspond are detailed in the L-systems help file. It should be noted that uppercase and lowercase letters are always treated as different characters in the program.

> ### Example 1: the simplest system

> Consider the following simple example: (anything after a "#" sign is treated by the parser as a comment):

>     1      # recursion depth
>     30     # default angle
>     50     # thichness variable: width as % of height
>     F      # The axiom: any lines following this axiom are "rules"
>     @      # end of file mark

> #### Parsing

> Parsing is done by taking the axiom and substituting any rules into it. The string of characters formed by doing so is the L-string. Since there are no rules in this particular L-system, the L-string formed is the same as the axiom, namely

> > F

> #### Interpreting

> As mentioned before, the character "F" is a special character which tells the turtle to move forwards by a full length and draw a connecting line between the original and destination points. The width of the line is calculated from a "thickness" variable (in this L-system implementation, the third line of the L-system specifies the default width as a percentage of the height of a line). Initially, the turtle points straight upwards, so the single F produced by parsing is interpreted as a single, upright line, 50% less thick than it is high. If you parse and display this L-system therefore, you should just see a bar standing up straight. Try typing this L-system description in, and parsing+viewing the result.

> ### Example 2: introducing rules

> Now try the next file:

>     1     # recursion depth
>     30    # default angle
>     50    # thickness
>     +A    # axiom
>     A=F   # a rule
>     @

> #### Parsing

> In this case, we have one rule: "A=F". The axiom is "+A", so we set the initial L-string to "+A". We then substitute the rule into this L-string, so replacing A with F in the string "+A", we end up with the final L-string

> > +F

> #### Interpreting

> We read the L-string from left to right, so the first character we encounter is "+". If we look at the meaning of the character "+" in the L-systems help file, we should find that it tells the turtle to turn left around the up vector (i.e. rotate clockwise in the XY plane), so the forward direction of the turtle is now at an angle. The default amount to rotate is given by the "default angle" variable on the second line of the L-system description: in this example it is 30 degrees. Viewing the result should show the same bar as before, but now tilted in an angle of 30 degrees to the vertical.
> Try the file with different angle and thickness settings, so you get used to it.

> ### Example 3: introducing recursion

> Now we tackle the recursion depth: recursion is a loop which occurs when parsing the L-system, so that substitution of all the defined rules occurs n times, where n is the recursion depth.

> Consider this example:

>     4      # the recursion depth
>     30
>     50
>     A      # the axiom
>     A=+FA
>     @

> #### Parsing

> Remember that recursion occurs during parsing. This L-system will recurse (or loop) 4 times when parsed: lets just see what that looks like when written down:

> Loop number | Axiom before substitution | Rule(s) to substitute | Axiom after substitution | 1 | A | A=+FA | +FA
> 2 | +FA | A=+FA | +F+FA
> 3 | +F+FA | A=+FA | +F+F+FA
> 4 | +F+F+FA | A=+FA | +F+F+F+FA

> In every loop the A gets an "+F" added because we defined A to become +FA.

> #### Interpreting

> The final L-string is thus

> > +F+F+F+FA

> The character "A" is not a special character, so it is ignored when interpreting the L-string. Try to imagine what form this L-sting should generate. First comes an angle of 30 degrees, followed by a full length, then another angle change of 30 degrees and again a full length and so forth. If you repeat this often enough it should became a circle. Try it out: you should see an open ended circle. Try increasing the recursion level, and the circle will be ever moe complete.
> [Question 3a: What recursion depth would be necessary to draw a complete circle (hint: how many degrees are there in a circle?)][Answer]
> [Question 3b: What do you think would happen if you increased the recursion depth in example 2, and why?][Answer]

> ### Example 4: introducing multiple rules

> We can also try out the "-" character, which rotates the turtle orientation in a right-hand manner around the up vector (rotating anticlockwise in the XY plane). We will try this out using two rules:

>     4
>     30
>     50
>     AB      # the axiom
>     A=+FA   # rule 1
>     B=-FB   # rule 2
>     @

> #### Parsing

> If we have more than one rule, the rules are all substituted into the L-string at the same time.
> [Question 4a: What will the L-string be in this example?][Answer]

> #### Interpreting

> Neither A nor B are special characters, so they are ignored in the interpretation step.
> [Question 4b: What do you think this object will look like? Try it out.][Answer]

> ### Example 5: the [] operation

> As you must have noticed, when drawing an L-system, each new length is started from where the previous length finished. There is a way to reset the turtle so that we can return to a previous point, and not have to keep on drawing from the same point at which we left off. This is by using square brackets. Everything between "[]" symbols is drawn but at the closing bracket, the drawing position and orientation return to those that were in operation before the opening bracket.

> An example will explain this more clearly:

>     4
>     30
>     50
>     [A][B]    # the axiom
>     A=+FA
>     B=+FB
>     @

> #### Interpreting

> The final string will be [+F+F+F+FA][-F-F-F-FB]. To draw it, we start from the bottom, draw the first string [+F+F+F+FA], than again starting from the bottom draw the second string [-F-F-F-FB]. We can make this as complex as we want, for example, by nesting square brackets within square brackets, but I advise against just randomly trying out things in the files without knowing what you are doing: it's fun, but you will learn little from it.

> ### Example 6: 3D and colour

> So far we have only drawn lines in a single plane, since we have only be using the "+" and "-" characters which rotate left and right around the up vector. The "^" and "&" characters pitch up and down around the left vector (rotate clockwise and anticlockwise in the YZ plane), and if we use them, it will extend our L-system form into 3 dimensions. In addition, we can use the colour command "c": another special character which tells the turtle to change the colour of the drawing pen.

> Try this:

>     4
>     30
>     50
>     [A]c[B]c[C]c[D]
>     A=+FA
>     B=-FB
>     C=^FC
>     D=&FD
>     @

> The final string is

> > [+F+F+F+FA]c[-F-F-F-FB]c[^F^F^F^FC]c[&F&F&F&FD]

> and you should be able to work out what it will look like. Try editing out the rules one by one and then viewing the result: it should become clear which definition becomes which object in the L-system form.

> Try deeper recursions and view the results.
> [Question 6a What happens if the "c" command is in between the brackets instead outside them? Why?][Answer]

> Notice that "+" in these files means "rotate left by 30 degrees". You can specify a different angle for any particular rotation by placing a number in round brackets after it, so "+(10)F" means "rotate left by 10 degrees, then draw a full length". Try it out by replacing the rule "C=^FC" with "C=^(10)FC" in the above example. The value "10" is said to be a parameter of the "^" character.
> [Question 6b What do you think might happen if you gave the character "F" a parameter, for example, replacing "C=^FC" with "C=^F(10)C? Try it out][Answer]

> ### Example 7: fractals

> It is very easy to obtain fractal-like forms with L-systems (although the forms will not repeat themselves at any level of detail, like a true fractal). For example, we can repeat the shape of the previous example, calling the basic form "E", and then insert "E" onto each branch at every recursion. The form is then recursively placed on each of its own branches:

>     8
>     10
>     50
>     E
>     E=[A][B][C][D]
>     A=c+FAE
>     B=c-FBE
>     C=c^FCE
>     D=c&FDE
>     @

> Try it out: as you can see: "E" is inserted onto every branch. Try changing the default angle and see what it looks like. Now let's try something more well known:

> ### Example 8: the Koch snowflake

> The Koch snowflake is a famous fractal form which you will find described in any book on fractals. Let's try to produce it as an L-system.

> Let's do it by the book:

> > "The construction of the Koch curve proceeds in stages. In each stage the number of segments increases by a factor of four."

> The initiator (the smallest form of the fractal) is "F" of course, the generator (the smallest fractal part still having the form of the fractal) is a line like:

>              _/\_

> The angles are clearly 45 degrees, so the generator should be defined as:

>     4               # no need for deep recursion yet.
>     45              # the angle of 45 degrees.
>     50              # well... 50 is a good thickness.
>     ++A             # The axiom. "++" makes the final form horizontal.
>     A=+F-F++F-F-    # Could equally be A=+F-F+(90)F-F-
>     @

> So, that's simple, but now it gets a bit more complex: We just made the generator, this is the form that must be substituted into itself. We could do this by specifying the same form again as another rule, and substituting one rule into the other:

>     4
>     45
>     50
>     ++-B         # The axiom. "++-" makes the final form horizontal
>     A=+F-F++F-F-
>     B=+A-A++A-A-
>     @

> As you see, both rule A and rule B are the same generator. We could get carried away and repetitively define C D E (not F!) G etc, like:

>     4
>     45
>     50
>     ++---D      # The axiom. "++---" makes the final form horizontal
>     A=+F-F++F-F-
>     B=+A-A++A-A-
>     C=+B-B++B-B-
>     D=+C-C++C-C-
>     @

> If you view this file the snowflake KOCH fractal is there. However, if we wanted to have a snowflake that had a fractal depth of 100, this method would take a lot of typing, and you would run out of letters for all the rules. In fact, the snowflake form in this example was generated without resorting to recursion.
> [Question 8a: What is it about this L-system that means that it is not fully recursive?][Answer]

> A clever thing that we can do with the L-system parser used here is to redefine "special characters" such as "F" and "+" as rules, by putting something like

> > F=F+

> after the axiom. In the parsing stage, these will get substituted like a normal rules, since it is only in the interpretation stage that "special characters" have any special meaning.

> With this in mind, we can try out the following file:

>     4
>     45
>     50
>     F
>     F=+F-F++F-F-
>     @

> Can you see why this produces the snowflake? Now we can use the recursion depth value to produce ever more detailed snowflakes! Try it, but keep the level below 12 :)

> ### Example 9: the Pythagoras tree

> It is probably a good idea to try another fractal like object. This is a simple one, called the Pythagoras tree. It starts with a branch, then on the end of this branch, two branches are added at angles of 45 degrees with the original, each of length 1/SQRT(2) times the parent branch. This is repeated, so that these two branches also have 2 branches added at 45 degrees with lengths of 1/SQRT(2) times the previous length, and so on, all in the same plane...

> Let's try to make this form, starting from the base form (F) and working our way up:

>     5
>     45
>     10
>     F
>     @

> This is the base (or mean) branch. Now we have to place the two branches on it, each of length 1/SQRT(2) (or approximately 0.7071) times the mean branch. We can use the character "'" to do this. This character reduces the default length by 10%, but this 10% value can be overriden by using a parameter. The command '(0.7071) should thus do the trick. The L-system can then look something like this:

>     5
>     45
>     10
>     A
>     A=F[+'(0.7071)F][-'(0.7071)F]
>     @

> As you see, I used the branching commands [] to do the job. Now the only thing that remains is to make it recursive! Calculating the lengths is a rule like 0.7071*0.7071*0.7071.....etc, each recursion the length is decreased by the same factor. It is easier if we make the "'(0.7071)" part of the algorithm into a rule, so that recursion is easy:

>     5
>     45
>     10
>     A
>     A=F[+BF][-BF]
>     B='(0.7071)
>     @

> We have now incorporated B into A, but there is still no recursion, as A references B, but B does not reference A. The final form is made by incorporating the initial form into itself. (This sounds cryptic huh...:)

> Like this:

>     5
>     45
>     10
>     A
>     A=[+BFA][-BFA]
>     B='(0.7071)
>     @

> Try this at recursion level 10: it looks pretty doesn't it! However, it is still all in one plane, and it seems a shame not to use the full 3 dimensional potential of the the L-systems program.

> If we add branching in the other two directions as well, maybe that will do the trick. Try this

>     5
>     45
>     10
>     A
>     A=[+BFA][-BFA][^BFA][&BFA]
>     B='(0.7071)
>     @

> Viewing the output shows a 3D tree, but the basic form of the fractal is lost. Clearly this is not the way to do it. To get a good 3D model one should make a so called rotation model of the fractal, i.e. turning it 90 degrees (in this case) on its central axis, continuously writing the 2D model, just like rotation models with mathematical integration. The next file shows the form into four directions. As you can see, I code the form twice (definitions A and B), enclosed them with [], so the starting point does not alter, and put them together just by adding them to each other in the command "AB".

>     9
>     45
>     10
>     AB
>     A=[F[+FCA][-FCA]]
>     B=[F[^FCB][&FCB]]
>     C='(0.7071)
>     @

> The following is also possible :)

>     #--------L-System--C.J.van der Mark-----
>     #--------Pythagoras semi 3D form--------
>     5
>     5
>     10
>     Y
>     Y=X<X
>     X=A>B>A>B>A>B>A>B>A>B>A>B>A>B>A>B>A>B
>     A=[F[+(45)FCA][-(45)FCA]]
>     B=[F[^(45)FCB][&(45)FCB]]
>     C='(0.7071)
>     @

> ## Answers to questions

> (click on the question numbers to take you back to the main text)

> ### Answers to questions in Example 3

> - Question 3a Since there are 360 degrees in a circle, and the angle moved each time is 30 degrees, the number of recursions needed to complete the circle is 360/30 = 12.
> - Question 3b Nothing would happen if you increased the recursion level in example 2, as once the rule has been substituted once into the axiom, the L-string does not contain any more rule characters. Further substitution into the L-string does not occur at greater recursion levels.

> ### Answers to questions in Example 4

> - Question 4a The final string should be

>   > +F+F+F+FA-F-F-F-FB

> - Question 4b It should take the form of an "S" shape.

> ### Answers to questions in Example 6

> - Question 6a If the "c" character is inside the brackets, the final string will be

>   > [+F+F+F+FAcccc][-F-F-F-FBcccc][^F^F^F^FCcccc][&F&F&F&FDcccc]

>   which means that the colour changes will occur after each "branch" has been drawn. Since the [] operation resets the colour as well as the position and orientation of the turtle, the colour will revert to the original colour every time a branch is drawn, and so the entire form will have a uniform colour.
> - Question 6b The "F" character takes a parameter which alters the amount moved forwards. The default amount is defined as 100%, so that F(50) produces a line which is half the length of a normal line (in fact, the character "Z" does exactly this), and F(200) produces a line which is twice as long as normal.

> ### Answers to questions in Example 8

> - Question 8a The L-system in this case is not fully recursive because it does not contain rules which contain themselves directly (such as "A=AF") or indirectly (such as "A=BF" "B=+A-"). This means that past a certain level of recursion, the L-string will not contain any rule characters, and so will not be substituted into.

>     Cees van der Mark jr.   cvdmark@xs4all.nl / http://www.xs4all.nl/~cvdmark
>             -----------  modified and html-ified by -----------
>     Yan Wong                yan.wong@oum.ox.ac.uk