Optimization Plug-In for Grasshopper: How to use Galapagos' interface and gene pool?

Just to let you know, I got the genepool to work! :smile:
Example code is attached (with sliders, too).

genepool.gh (10.9 KB)

Cheers,
Thomas

PS: One needs to include Microsoft.CSharp.dll in order to use the dynamic keyword.

Yeah that’s probably the most useful missing standard reference in the C# component. I may add it to the GH for Rhino6 version and hope it doesn’t break anything.

1 Like

Just a follow-up question to David regarding the display of the wires in Galapagos:
There’s no setting for the special wires in the Grasshopper API, correct?
Instead, I would need to recreate their look and feel from scratch, right?

Yup, you’ll have to draw them entirely yourself.

@DavidRutten , @ParamDesSing
I have a related question regarding Galapagos and other optimization components:
How do you generally link evaluation models into the optimizers? Is there a way to treat them as anonymous functions / delegates? Or are you working with sth. like “wait until objectiveFunctionValue has changed”?
How was it realized in Galapagos?

Thanks,
Christoph

Hi Christoph,

In terms of waiting, I’m using a WaitHandle in C#, to check if the definition has been recomputed.

The solver runs as a separate process, and I interact with it via a hidden command line.
(Because the library I’m using requires NumPy and SciPy, as well as other plug-ins not available in IronPython.)

1 Like

FYI, I’ve ported my code from a C# component to a plug-in, which created some issues with the WaitHandle.
The below solution is probably better anyway.

doc.NewSolution(true, GH_SolutionMode.CommandLine);
while (doc.SolutionState != GH_ProcessStep.PostProcess) { }

Thanks @ParamDesSing !

sorry, but how do you declare “doc”?
Is this wrong?: GH_Document doc = new GH_Document();

Because trying this will pop up the msgbox forever, even though nothing is happening in the document:

    protected override void SolveInstance(IGH_DataAccess DA)
    {
        doc.NewSolution(true, GH_SolutionMode.CommandLine);
        while (doc.SolutionState != GH_ProcessStep.PostProcess)
        {
             MessageBox.Show ("hi");

        }
    }

Hi @Christoph1,

You can use:

GH_Document doc = Component.OnPingDocument();

Cheers,
Thomas

OptimiTest.gh (3.5 KB)
cs files.zip (2.3 KB)

I don’t know, I just can’t figure it out… I couldn’t manage it with (doc.SolutionState != GH_ProcessStep.PostProcess) { }.
However, I managed to make something functioning at least a bit, but it never breaks out of the while loop. For some reason, properties of my optimizer class instance “opti” are not maintained, but purged.
I appreciate any help a lot!

namespace GHOptimizationTest
{
  public class GHOptimizationTestComponent : GH_Component
   {
    GH_Document doc;
    IGH_Component Component;

    public GHOptimizationTestComponent()
        : base("GHOptimizationTest", "Nickname",
            "Description",
            "Category", "Subcategory")
    {
    }

    protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
    {
        pManager.AddIntegerParameter ("f(x*)", "f(x*)", "optimum", GH_ParamAccess.item);
        pManager.AddIntegerParameter("x", "x", "decision variable", GH_ParamAccess.item);
        pManager.AddIntegerParameter("f(x)", "f(x)", "objective function value", GH_ParamAccess.item);
    }

    protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
    {
    }

    protected override void SolveInstance(IGH_DataAccess DA)
    {
        Component = this;
        doc = Component.OnPingDocument();

        //component input
        int fopt = new int();                   //expected optimum
        int x = new int();                      //decision variable
        int fx = new int();                     //objective function value
        if (!DA.GetData(0, ref fopt)) { return; }
        if (!DA.GetData(1, ref x)) { return; } 
        if (!DA.GetData(2, ref fx)) { return; }

        //getting number slider for decision variable, which also updates objective function value once changed
        List<Grasshopper.Kernel.Special.GH_NumberSlider> sliders = new List<Grasshopper.Kernel.Special.GH_NumberSlider>();
        foreach (IGH_Param param in Component.Params.Input)
        {
            Grasshopper.Kernel.Special.GH_NumberSlider slider = param.Sources[0] as Grasshopper.Kernel.Special.GH_NumberSlider;
            if (slider != null)
                sliders.Add(slider);
        }


        Optimizer opti = new Optimizer(fopt);       //initializing optimizer
        while(opti.terminate != true)               //run until termination criterion fullfilled
        {
            doc.NewSolution(false);
            opti.maximize(x, fx);                   //optimize
            sliders[0].SetSliderValue(opti.xNew);        //update decision variable slider
        }
    }
}
}

and this one is the optimizer class (as a test only simply incrementing a variable)

class Optimizer
{
    private int fopti;
    public bool terminate;
    public int xNew;

    public Optimizer(int _fopti)
    {
        this.fopti = _fopti;         //expected optimum value
        this.terminate = false;
    }

    public void maximize(int x, int fx)
    {
        int _xNew = x;

        if (fx < fopti )        //optimum not yet found
        {
            _xNew = x + 1;       //changing decision variable x
        }
        else if (fx >= fopti)   //optimum found
        {
            this.terminate = true;
            MessageBox.Show("optimum found: " + fx);
        }
        this.xNew = _xNew;
    }
}

Just from looking at this code, I think that the problem is that you’re not updating fx.

fx is updated indirectly by sliders[0] which is the variable. Please see picture below.

Actually, everything works and the slider goes up to 10, calling the MessageBox “optimum found” from the optimizer class. But then it doesn’t break out of the while-loop in SolveInstance(), because, as I saw in the debugger, properties of my instance “opti” of the optimizer class, such as “opti.xNew” and “opti.terminate” are not stored, but purged after every iteration.

I suspect it has something to do with how Grasshopper recomputes and expires components?

Ah, I think you’re right about the component expiration.
That’s why you should run your code in a separate window, as discussed in this thread:

http://discourse.mcneel.com/t/gh-document-newsolution-crashing-rhino/14744

1 Like

Thanks Thomas!
I tried to follow David’s example code from the thread you mentioned, however in Visual Studio and not in the c# script component.

Unfortunately, now I’m getting an “object has expired” error, exactly when I try to change the slider value.

I found this forum topic, discussing exactly what I am trying to do and mentioning the problems I now encounter:
http://discourse.mcneel.com/t/how-can-i-get-a-number-slider-object-and-set-a-value/12407/6

Have you managed to do it the “inert”-way, David was describing? If so, how do you access and work with the fitness-evaluation components, without changing the number-sliders?

Would there be a chance that you upload a super simple example about this?

Thanks a lot! Christoph

Hi Christoph,

It sounds to me like you’re running some code in the component instead of in a separate window.

Below is a simplified excerpt from the code I’m using with a C# component. (All of which runs in the window, and not in the component). Also have a look at the Grasshopper definition I shared earlier in this thread (15 December).

//Get Sliders
private List<Grasshopper.Kernel.Special.GH_NumberSlider> getSliders(IGH_Component component)
{
	// Collect all sliders that are plugged into the first input parameter of the script component.
	List<Grasshopper.Kernel.Special.GH_NumberSlider> sliders = new List<Grasshopper.Kernel.Special.GH_NumberSlider>();

	foreach (IGH_Param param in component.Params.Input[0].Sources)
	{
	  Grasshopper.Kernel.Special.GH_NumberSlider slider = param as Grasshopper.Kernel.Special.GH_NumberSlider;
	  if (slider != null) sliders.Add(slider);
	}
	return sliders;
}

//Set Sliders
private void setSliders(IGH_Component component, decimal[] parameters, List<Grasshopper.Kernel.Special.GH_NumberSlider> sliders)
{
	for(int i = 0; i < sliders.Count; i++) sliders[i].SetSliderValue(parameters[i]);
}

//Get Objective Value
private double getObjectiveValue(IGH_Component component)
{
	GH_Structure<IGH_Goo> objectiveTree = (GH_Structure<IGH_Goo>) component.Params.Input[1].VolatileData;
	IGH_Goo objective = objectiveTree.First();

	double objectiveValue;
	objective.CastTo<double>(out objectiveValue);
	return objectiveValue;
}

Finally it works! Thanks a million times!

The bit I missed was basically avoiding SolveInstance() to run again, with this:

        if (_form != null)
            return;

or in my case, instead of a form, just a class instance

        if (opti != null)
            return;

Thomas, I owe you many glasses of beer! :smiley:

Hi all,

Trying to use Thomas’ custom C# component in Rhino 6, GH build 1.0.0007, and am getting this error:

“1. Error (CS1703): An assembly with the same identity ‘Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ has already been imported. Try removing one of the duplicate references.”

I tried commenting out “using Microsoft.CSharp.RuntimeBinder”, no luck.

Does anyone see any issues running this code in GH for Rhino6? Or, are there new solutions for accessing the gene pool component within a custom C# component?

Thomas’ original file, in case you dont wanna scroll up:
genepool.gh (11.6 KB)

Hi Scott,

Have a look at this GitHub repository, which provides a shell for optimization in Grasshopper, including support for genepools. The code for genepools is in Grasshopper_InOut.cs.

I haven’t looked at it in a while. but for all I know it should still work.
(I had a look at the component I posted here, but I have no idea why it isn’t working anymore.)

Cheers,
Thomas

Hi Thomas,

I’m a PhD student working on evolutionary architecture, and I’m interested in writing a galapagos-like component, with a novel solver. I have your FrOG repo which looks very promising, but it references the GalapagosLibrary.dll. I assume this was relevant in Rhino 5, but I now have Rhino 8, and I can’t find the .dll Do you know where to find it?

Thank you very much,
Paul Kalnitz

Hi Paul,

I’m Thomas’ PhD student :smiley:
These are dll’s we reference in Opossum:
galapagos_dll.zip (253.0 KB)

Hope this helps!
Max