This week, we look at using Genetic Algorithms to solve geometric problems via Grasshopper’s built-in genetic algorithm engine, Galapagos.  Genetic algorithms attempt to mimic the way lifeforms evolve over time, on the basis that if it’s good enough for creating all life as we know it, it’s probably a fairly good tool for helping us develop design solutions.

There are two main things to consider when we are setting up a grasshopper model to use Galapagos.  The first are the input parameters that we are going to use as genomes.  Each genome is a value that controls certain aspects of the design – the height of a wall, for instance, the width of a window, the number of columns etc.  Galapagos will modify these values for us and attempt to find the ‘best’ solution.  At present, galapagos can only do this through modifying sliders, which places a slight limitation on the way we set up the grasshopper definition because it means that everything we want it to be possible to change has to be controlled via a slider.  We can still include other parameters (linked geometry, strings etc.) but galapagos will not be able to modify them for us.  At each generation, grasshopper will fiddle (technical term) with these values and come up with a variety of different combinations.  The best sets of values will pass on to the next generation (either directly or through ‘breeding’ with another value set) – the rest will be eliminated.  The idea is that the population at each generation will become more and more suitable to the task at hand and hence you will be given ever improving solutions to whatever problem you are trying to solve.

The second, possibly more difficult part, is coming up with a way of assessing your model and turning that assessment into a single numerical value that you can use to express the ‘fitness’ of a given design, i.e. giving it a score based on how ‘good’ it is.  This gets especially tricky if you need to consider more than one criteria that are not all of the same importance, since then you need to weight each criteria’s contribution to the final score.  This is mathematically quite easy (you just need to multiply it by a certain factor) but determining what these weightings should be in order to give the best results can take a bit of trial and error.  For some more on this I recommend this blog entry by the mighty David Rutten himself.

Indeed, if you’re thinking of using Galapagos you should probably leaf through the rest of David’s blog – he did write the thing, after all.

For my part, here are two annotated examples that use it:

The first (the idea for which I think I probably stole of of David anyway) uses galapagos to arrange a catenary so that it passes through (or at least, close to) a point, while (as a secondary consideration) minimising the length of the catenary.

Not breathtakingly useful, I know, but it should help to demonstrate the basics.  Get it here: Example6a.ghx (Right click, save target as)

The next one does something a little bit cleverer.  Given a certain set of points, we use metaballs (a form of implicit surface, although in grasshopper they only creates curves, which represent a 2D ‘slice’ through a metaball) to cover as many points as it can while also keeping the total covered area as small as possible.  In this abstract form again this is probably not particularly useful but hopefully it is easy to see how it might be modified for use in masterplanning, for example.

Get it here: Example6b.ghx (Right click, save blahdy blah)

As an optimisation tool, genetic algorithms leave something to be desired.  They need a large pool of test cases at each cycle and are highly random in the way that they work, meaning that they can take many many times longer than a more ‘straightforward’ optimisation routine would and may in the end not actually find the most optimum possible solution anyway.  For this reason, they tend to fall onto the ‘often discussed, rarely used’ pile.  However, they are also a lot more ‘creative’ – possibly throwing up solutions that you might never have considered otherwise.  Given that we are all evolved creatures ourselves, it could be argued that all ‘designs’ are really the product of a genetic algorithm that has been running for several billion years.

This week, we create our own universe.  Specifically, we create a universe with two physical laws:

F = ma, or Newton’s second law of motion

F = G(m1*m2)/r^2, or Newton’s law of universal gravitation

Using those laws, we’re going to simulate a ‘solar system’ of different bodies and plot the paths they make moving under gravitation.  To do this we’re going to use an iterative algorithm; calculating the forces that the planets exert on each other, moving them a little bit, re-calculating the forces based on their new positions, moving them again and so on.

First up, we’re going to create a class to represent the ‘planets’ in our solar system.  We’re going to do this separately using Visual Studio, then compile it as a DLL, a library of code that does nothing on its own but that can be used freely by other bits of code.  There are a couple of advantages to doing it this way – we can re-use this bit of code easily if we need to and we can minimise our time spent using grasshopper’s horrible built-in script editor.

To create the dll, open up Visual Studio/Visual Basic Express and create a new ‘class library’ project.  DLLs are used a lot – RhinoCommon itself is stored in a DLL, and since we want to use some of the RhinoCommon types (points, vectors etc.) our first task is to reference that dll to let Visual Studio know where it is and that we want to use it.  To do this, go to Project->Properties->References and add one to RhinoCommon.dll (should be somewhere in your grasshopper install directory).  Then add this code:


'Before we can use anything from RhinoCommon, we need to reference the .dll
'You can do this in Project->Properties->References

'This imports the Rhino.Geometry namespace so we don't have to type it out every time we use something from there
Imports Rhino.Geometry

'This is the class we will use to represent each 'planet'
'This could be adapted to any kind of agent, however
Public Class Planet

'Each planet has three 'physical' properties
Public position As Point3d
Public velocity As Vector3d
Public mass As Double

'So we can plot the trail of the planet we store all of it's previous points
Public path As List(Of Point3d)

'Constructor:
Public Sub New(ByVal initialPosition As Point3d, ByVal initialVelocity As Vector3d, _
ByVal initialMass As Double)

position = initialPosition
velocity = initialVelocity
mass = initialMass

path = New List(Of Point3d)
path.Add(New Point3d(position.X, position.Y, position.Z))

End Sub

''' <summary>
''' This sub gets called iteratively to update the position of the planet
''' </summary>
''' <remarks></remarks>
Public Sub Move()
position += velocity
path.Add(New Point3d(position.X, position.Y, position.Z))
End Sub

''' <summary>
''' This converts a force into a change in velocity
''' </summary>
''' <param name="force"></param>
''' <remarks></remarks>
Public Sub ApplyForce(ByVal force As Vector3d)
velocity += force / mass
End Sub

End Class

Then hit ‘Build’ to create our actual .dll. VS will put it in the folder for your project under Bin/Release.

Now for our grasshopper part.  Create a script component, right click on it, go to ‘Referenced assemblies’ and use the pop-up form to add a reference to our newly-created .dll.  This will allow us to use our ‘Planet’ class within the scripting component.

Set up the component’s inputs to take a list of points, P, a list of vectors, V, a list of doubles, M, and an integer, T.  These represent, respectively, our planet’s starting positions, initial velocities, masses and the length of time we want to simulate.  Then add this code:

Private Sub RunScript(ByVal P As List(Of Point3d), ByVal V As List(Of Vector3d), ByVal M As List(Of Double), ByVal T As Integer, ByRef Path As Object)

Dim planets As New List(Of Planet)

'First of all, we create our 'planets'.
'Here we recreate the behaviour Of the 'longest list' data matching option
For i As Integer = 0 To P.Count - 1
Dim position As Point3d = P(i)
'If values exist for the other parameters here then we use them
'otherwise, we use the last value in the list
Dim velocity As vector3d = V(math.Min(i, V.Count - 1))
Dim mass As Double = M(math.Min(i, M.Count - 1))
Dim planet As New Planet(position, velocity, mass)
planets.Add(planet)
Next

'All our simulation is going to take place in this loop
'Each step through this loop represents a discrete amount of time
'To simplify things, we've assumed this is equal to 1 time unit
For time As Integer = 0 To T

'First, we check every planet against every other planet and work out the forces each
'pair is exerting on each other
For j As Integer = 0 To planets.Count - 2

Dim planetA As Planet = planets(j)

'By checking each planet only against the planets later in the list, we ensure that each
'pair is only going to be checked once
For k As Integer = j + 1 To planets.Count - 1

Dim planetB As Planet = planets(k)
Dim F As Double
'Here we calculate the force using the formula:
'Force = (mass1 * mass2)/distance^2
'i.e. Newton's law of universal gravitation
F = (planetA.mass * planetB.mass) / planetA.position.DistanceTo(planetB.position) ^ 2
Dim direction As Vector3d = planetB.position - planetA.position
direction.Unitize
direction *= F

planetA.ApplyForce(direction)
planetB.ApplyForce(-direction)
Next

Next

'Now that we have worked out how each planet will be moving, we update their positions
For Each planet As Planet In Planets
planet.Move()
Next

Next

'NOTE: This part *should* work, but doesn't always due to a bug in RhinoCommon:
'=========================================================================================
'Dim outList As New List(Of Curve)
'For Each planet As Planet In Planets
'  Dim crv As Curve = Curve.CreateInterpolatedCurve(planet.path, 3)
'  outList.Add(crv)
'Next

'Path = outList
'=========================================================================================

'Since the above won't work reliably, we instead create a data tree, with the points that
'describe each planet's path stored in a separate branch.  This means we can feed them into
'an 'interpolate curve' component and get a separate curve for each planet.
Dim Tree As New DataTree(Of Point3d)

For z As Integer = 0 To planets.Count - 1
'For each planet we create a new path:
Dim TreePath As New GH_Path(z)
For Each pt As point3d In planets(z).path
'We then add each point to the tree, stipulating the path to use to store them
Tree.Add(pt, TreePath)
Next

Next

'And finally, we output our tree:
Path = Tree

End Sub 

Now plug the output path points into an ‘interpolate curve’ component, stick in some initial variables and you should have some interesting results, or at least interesting messes.  Note that the algorithm is quite sensitive to scale – if you don’t see anything it may just be that your planets are too far apart to have any effect on each other.

You can download the complete example here: http://www.vitruality.com/Teaching/PhysicsExample.zip

I used a script like this when we were in the initial stages of designing the Orbit as a way of defining the centreline of the lattice.  In the end however, this approach proved a bit to difficult to control.  If you play around with it a bit you will notice that it is extremely sensitive to initial conditions.  Move one of the starting positions even slightly and it will totally change the result you get.  Since for the Orbit we needed to have finer control over the form in order to get something that was structurally feasible (we were going for visually unstable, but not actually unstable), in the end we abandoned that idea and went for something a bit more manual.

But, while this script might not be particularly useful for this reason, this basic structure could be modified for any sort of physical simulation or agent-based generation (dynamic relaxation, boids, pheremone-based stuff, etc.).  The only things that you’d need to change would be the controlling equations (in this case, the gravitation formula)…

I didn’t actually know about this until I accidentally stumbled accross it in iplayer, but Cecil Balmond (my boss when I was in Arup’s AGU (Advanced Geometry Unit), until he went off to do his own thing) did a radio series for the BBC a little while ago about the evolution and use of mathematics in design.  As it turns out, they’re pretty good, and well worth a listen if you’re at all interested in anything ever.

You can listen to all three episodes here.

Episode 3 is where he gets into the sort of things that we actually do for a living, but episode 2 in particular is well worth listening to for the part where Cecil interviews the previously mentioned (and sadly recently deceased) Benoit Mandelbrot.  I geeked out a bit over that part and it sounds like Cecil did too.

Last year, I gave a lecture at the AADRL about fractals and their implementation, as part of a course I was teaching on generative and parametric design using Rhino.  For anybody interested in RhinoScript, here is the example code that I gave in that class to generate a very simple fractal – the Sierpiński triangle:

http://www.vitruality.com/Teaching/sierpinski triangle.rvb

The way you generate a pattern like this is easy:  You take a starting triangle, then draw three smaller touching triangles inside it (à la the Triforce), then draw three smaller triangles within each of those and so on forever (or, in the script’s case, until you reach a suitably tiny scale).

And so on and so on and so on...

Like I say, this is pretty simple as fractals go, but the key idea behind implementing them all in code is exactly the same.  They all need to have some function which performs a particular geometric operation and then calls itself, using the outputs of that operation as the inputs for the next cycle.  You could modify the script above to create any fractal you want just by replacing the specific parts that deal with subdividing the triangle.  The geometrical mathematics might become more complicated but the basic framework will remain the same.

During that class, I made the rookie mistake of saying ‘…and expanding this to three dimensions is pretty simple.’, to which one of the students reasonably responded ‘well, can you show us that, then.’ to which I said ‘um’.  And then, after I’d thought about it a bit more, did so:

www.vitruality.com/Teaching/Sierpinski%20Pyramid.rvb

For brevity’s sake, I actually ‘cheated’ a little in that script, since I ask the user to input the vertices (if I’d had more time, this could have been extracted from the input geometry itself, although due to the way Rhino stores BReps, this is a non-trivial operation) and then simply scale about those points to create the subdivisions.  The benefit to this however is that you can now use the same script for more than just pyramids.   Anyway.

Fractals are quite interesting not just because they’re quite pretty but also because a lot of the natural forms that surround us exhibit fractal-like structure.  Fern leaves and snow flakes are the most frequently cited examples, but also clouds, mountain ranges, galaxies and even the distribution of blood vessels in our own bodies also have self-similarity at different scales.

Looking at these forms as fractals has some interesting implications.  For instance, the coastline of Britain, which King of Fractals Benoît Mandelbrot demonstrated had fractal characteristics, is (practically) infinitely long.   This probably seems a bit counter-intuitive, even if it does explain why this program felt like it went on forever.  Trace around Britain on a map and you’ll be able to get out a certain measurement, but go to the coast itself with a measuring tape and you’ll realise the problem.  Do you measure around every headland?  Do you measure around every rock?  Every grain of sand?  Every atom?  The greater the level of detail you decide to include, the longer and longer your measurement will get.

Natural forms display fractal properties simply because they are produced by physical processes, which are in turn governed by physical laws which apply at all scales.  The oceanic currents that shape continents are driven by the same forces as the vortices that carve out rockpools, so in a sense it should really come as no surprise that we find fractals all around us.  Of course these patterns do begin to change slightly as you go down in scale and this is due to the intrinsic imbalance between the fundamental forces of nature.  At large scales gravity dominates – even though it is substantially weaker than the other three fundamental interactions it has influence over much larger distances.  As you head down towards the atomic scale gravity becomes insignificant and the attraction and repulsion between particles becomes the primary driver behind form.  For this reason no natural fractal is ever perfect but it is these ‘imperfections’ that allow the universe as we know it to exist in the first place.

Fractals show us impossible universes without scale, without limits, without variation, without us.  Dead, but pretty with it.

http://www.bbc.co.uk/programmes/b006mvlc
© 2012 VITRUALITY Suffusion theme by Sayontan Sinha