Skip to content

Commit

Permalink
Merge pull request #24 from hrntsm/develop
Browse files Browse the repository at this point in the history
Release v0.2.0
  • Loading branch information
hrntsm authored May 2, 2022
2 parents d87295e + a3e17ac commit 7fbcc37
Show file tree
Hide file tree
Showing 19 changed files with 658 additions and 228 deletions.
6 changes: 3 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ dotnet_remove_unnecessary_suppression_exclusions = none
[*.cs]

# var preferences
csharp_style_var_elsewhere = false:silent
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
csharp_style_var_elsewhere = false:warning
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = true:warning

# Expression-bodied members
csharp_style_expression_bodied_accessors = true:silent
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -452,4 +452,4 @@ $RECYCLE.BIN/
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
Tunny/Python/
Tunny/Lib/
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

Please see [here](https://github.com/hrntsm/Tunny/releases) for the data released for each version.

## [0.2.0] -2022-05-02

### Added

- Restore progressbar
- Support Galapagos genepool input
- Result reflect button
- This feature reflecting multi objective optimization result to slider & genepool to use input model number.
- if input multi model number, the first one is reflect and popup notification about this.
- Support grid sampler

### Changed

- Restore feature was made asynchronous.
- Visualize graph axis name now use input objective's nickname.
- Update supported Rhino version to 7.13.
- Disable optimize window resize.

### Fixed

- Optimization does not stop when the value of Objective is null.
- When the objective values is null, optimizer try to get another variable and resolve solution.
- If it is 10 trial to get objectives in 1 optimize loop, optimizer throw error.
- Enable visualize param importances function
- this function need sklearn, but tunny's python package doesn't include it.
- Optimize window UI is broken when using Hi-DPI environment.
- Support multi DPI

## [0.1.1] -2022-04-17

### Fixed
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Tunny also support yak. So you can find Tunny in Rhinoceros package manager.

### Quick usage

![tunny](https://user-images.githubusercontent.com/23289252/163386009-c60e529e-20d1-4314-b9f5-df8bed3c791e.gif)
![tunny](https://user-images.githubusercontent.com/23289252/166186417-7541ccb9-efa0-4569-a068-373ebde1c0ed.gif)

### Component location

Expand All @@ -46,31 +46,31 @@ Tunny can be found in the same Params tab as Galapagos under Util if it has been

#### Variables

Connect a NumberSlider to Variables. No other components are supported.
This component support Number slider & GenePool.
Optimization is performed when this value is changed by Tunny.

It is recommended that components be given nicknames, as this makes it easier to understand the resulting process. Here it is named x, y, z.

![image](https://user-images.githubusercontent.com/23289252/163378057-3c0a6a84-4dd2-4d2a-a55d-3202f9abc8bf.png)
![image](https://user-images.githubusercontent.com/23289252/166185821-4b3da178-068b-444a-9d3f-9ee791c533b1.png)

#### Objectives

Optimization is performed to minimize the value input here. Multi-objective optimization is also supported.
Optimization is performed to minimize the value input here. Multi-objective optimization is also supported.

For multi-objective optimization, put the target values as a list in one Number component. Multiple Number components are not supported.
Each objective value have to be separated to a number component.
It is recommended to set nickname like input variables.

![image](https://user-images.githubusercontent.com/23289252/163378644-e066dfa8-c36d-4a56-92dd-206dff5eed92.png)
![image](https://user-images.githubusercontent.com/23289252/166185782-3d5ddb69-5912-4b65-8b59-c20f0f1cd6b2.png)

#### ModelMesh

This input is optional.

Mesh input is supported as a function to save the model during optimization.
If multiple meshes are entered as a list, only the first one will be saved.

If multiple meshes are entered as a list, only the first one will be saved.
Input of large size meshes is deprecated because it makes the analysis heavier.

![image](https://user-images.githubusercontent.com/23289252/163379419-40368cc4-8abd-40d0-94ca-d0a468796c57.png)
![image](https://user-images.githubusercontent.com/23289252/166185101-c82d1610-03a5-4906-920c-4ef33508716c.png)

### Optimization Window

Expand All @@ -94,8 +94,11 @@ Values that can be set and their meanings are as follows.
1. NSGA-II (Genetic algorithm)
1. CMA-ES (Evolution strategy)
1. Random
1. Grid
- Number of trial
- This number of trials will be performed.
- If the grid sampler is selected, the calculation is performed by dividing each entered Variable by this number.
- **Note** that the number of calculations is (Number of trial) to the power of (Number of Variable).
- Load if study file exists
- If the checkbox is checked and a file of optimization results is available, the results of the training will be used to perform ongoing optimization.
- Study Name
Expand All @@ -105,7 +108,7 @@ Values that can be set and their meanings are as follows.

#### Result Tab

![image](https://user-images.githubusercontent.com/23289252/163382006-3cb37a7e-ff38-4ced-8227-7c06a0621cd3.png)
![image](https://user-images.githubusercontent.com/23289252/166185559-a5e64659-df48-4777-85dc-7ed01f3752b7.png)

Values that can be set and their meanings are as follows.

Expand All @@ -128,6 +131,7 @@ Values that can be set and their meanings are as follows.
- The model with the number entered here is restored from the optimization results file and is the output of the component.
- The model number matches the tree structure of the output.
- -1 is input, the results of all models on the Pareto front will be the main focus.
- Clicking the Reflect button will cause Grasshopper to reflect the results of the model number inputted.

## Contact information

Expand Down
Binary file modified Sample/sample.gh
Binary file not shown.
6 changes: 3 additions & 3 deletions Tunny/Component/TunnyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private void DrawVariableWire(GH_Canvas canvas, Graphics graphics)
PointF p1 = param.Attributes.InputGrip;

int wireWidth = 1;
Color wireColor = Color.FromArgb(Convert.ToInt32("3300008B", 16));
var wireColor = Color.FromArgb(Convert.ToInt32("3300008B", 16));
if (Owner.Attributes.Selected)
{
wireWidth = 3;
Expand Down Expand Up @@ -88,7 +88,7 @@ private void DrawObjectiveWire(GH_Canvas canvas, Graphics graphics)
PointF p1 = param.Attributes.InputGrip;

int wireWidth = 2;
Color wireColor = Color.FromArgb(Convert.ToInt32("33008000", 16));
var wireColor = Color.FromArgb(Convert.ToInt32("33008000", 16));
if (Owner.Attributes.Selected)
{
wireWidth = 3;
Expand Down Expand Up @@ -122,7 +122,7 @@ private void DrawModelMeshWire(GH_Canvas canvas, Graphics graphics)
PointF p1 = param.Attributes.InputGrip;

int wireWidth = 2;
Color wireColor = Color.FromArgb(Convert.ToInt32("338B008B", 16));
var wireColor = Color.FromArgb(Convert.ToInt32("338B008B", 16));
if (Owner.Attributes.Selected)
{
wireWidth = 3;
Expand Down
21 changes: 12 additions & 9 deletions Tunny/Optimization/Loop.cs → Tunny/Optimization/OptimizeLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
using System.ComponentModel;
using System.Linq;

using Grasshopper.Kernel;

using Tunny.Component;
using Tunny.Solver;
using Tunny.UI;
using Tunny.Util;

namespace Tunny.Optimization
{
internal static class Loop
internal static class OptimizeLoop
{
private static BackgroundWorker s_worker;
private static TunnyComponent s_component;
Expand All @@ -19,15 +21,15 @@ internal static class Loop
public static string SamplerType;
public static string StudyName;

internal static void RunOptimizationLoopMultiple(object sender, DoWorkEventArgs e)
internal static void RunMultiple(object sender, DoWorkEventArgs e)
{
s_worker = sender as BackgroundWorker;
s_component = e.Argument as TunnyComponent;

s_component.GhInOutInstantiate();

double[] result = RunOptimizationLoop(s_worker);
List<decimal> decimalResults = result.Select(Convert.ToDecimal).ToList();
var decimalResults = result.Select(Convert.ToDecimal).ToList();

s_component.OptimizationWindow.GrasshopperStatus = OptimizationWindow.GrasshopperStates.RequestSent;
s_worker.ReportProgress(100, decimalResults);
Expand All @@ -43,14 +45,15 @@ internal static void RunOptimizationLoopMultiple(object sender, DoWorkEventArgs
private static double[] RunOptimizationLoop(BackgroundWorker worker)
{
List<Variable> variables = s_component.GhInOut.Variables;
List<IGH_Param> objectives = s_component.GhInOut.Objectives;

if (worker.CancellationPending)
{
return new[] { double.NaN };
}

var solver = new Optuna(s_component.GhInOut.ComponentFolder);
Dictionary<string, object> settings = new Dictionary<string, object>()
var optunaSolver = new Optuna(s_component.GhInOut.ComponentFolder);
var settings = new Dictionary<string, object>()
{
{ "nTrials", NTrials },
{ "loadIfExists", LoadIfExists },
Expand All @@ -60,13 +63,13 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker)
{ "nObjective", s_component.GhInOut.GetObjectiveValues().Count }
};

bool solverStarted = solver.RunSolver(
variables, EvaluateFunction, "OptunaTPE", settings, "", "");
bool solverStarted = optunaSolver.RunSolver(
variables, objectives, EvaluateFunction, "OptunaTPE", settings, "", "");

return solverStarted ? solver.XOpt : new[] { double.NaN };
return solverStarted ? optunaSolver.XOpt : new[] { double.NaN };
}

public static EvaluatedGHResult EvaluateFunction(IList<decimal> values, int progress)
private static EvaluatedGHResult EvaluateFunction(IList<decimal> values, int progress)
{
s_component.OptimizationWindow.GrasshopperStatus = OptimizationWindow.GrasshopperStates.RequestSent;

Expand Down
115 changes: 115 additions & 0 deletions Tunny/Optimization/RestoreLoop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;

using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;

using Rhino.FileIO;
using Rhino.Geometry;

using Tunny.Component;
using Tunny.Solver;
using Tunny.UI;
using Tunny.Util;

namespace Tunny.Optimization
{
internal static class RestoreLoop
{
private static BackgroundWorker s_worker;
private static TunnyComponent s_component;
public static string StudyName;
public static string[] NickNames;
public static int[] Indices;
public static string Mode;

internal static void Run(object sender, DoWorkEventArgs e)
{
s_worker = sender as BackgroundWorker;
s_component = e.Argument as TunnyComponent;

var modelMesh = new GH_Structure<GH_Mesh>();
var variables = new GH_Structure<GH_Number>();
var objectives = new GH_Structure<GH_Number>();

var optunaSolver = new Optuna(s_component.GhInOut.ComponentFolder);
ModelResult[] modelResult = optunaSolver.GetModelResult(Indices, StudyName);
if (modelResult.Length == 0)
{
TunnyMessageBox.Show("There are no restore models. Please check study name.", "Tunny", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

switch (Mode)
{
case "Restore":
for (int i = 0; i < modelResult.Length; i++)
{
SetVariables(variables, modelResult[i], NickNames);
SetObjectives(objectives, modelResult[i]);
SetModelMesh(modelMesh, modelResult[i]);
s_worker.ReportProgress(i * 100 / modelResult.Length);
}
break;
case "Reflect":
if (modelResult.Length > 1)
{
TunnyMessageBox.Show(
"You input multi restore model numbers, but this function only reflect variables to slider or genepool to first one.",
"Tunny",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
}
SetVariables(variables, modelResult[0], NickNames);
SetObjectives(objectives, modelResult[0]);
SetModelMesh(modelMesh, modelResult[0]);
s_worker.ReportProgress(100);
break;
}

s_component.Variables = variables;
s_component.Objectives = objectives;
s_component.ModelMesh = modelMesh;
s_worker.ReportProgress(100);

if (s_worker != null)
{
s_worker.CancelAsync();
}
TunnyMessageBox.Show("Restore completed successfully.", "Tunny");
}

private static void SetVariables(GH_Structure<GH_Number> objectives, ModelResult model, IEnumerable<string> nickName)
{
foreach (string name in nickName)
{
foreach (KeyValuePair<string, double> obj in model.Variables.Where(obj => obj.Key == name))
{
objectives.Append(new GH_Number(obj.Value), new GH_Path(0, model.Number));
}
}
}

private static void SetObjectives(GH_Structure<GH_Number> objectives, ModelResult model)
{
foreach (double obj in model.Objectives)
{
objectives.Append(new GH_Number(obj), new GH_Path(0, model.Number));
}
}

private static void SetModelMesh(GH_Structure<GH_Mesh> modelMesh, ModelResult model)
{
if (model.Draco == string.Empty)
{
return;
}
var mesh = (Mesh)DracoCompression.DecompressBase64String(model.Draco);
modelMesh.Append(new GH_Mesh(mesh), new GH_Path(0, model.Number));
}
}
}
Loading

0 comments on commit 7fbcc37

Please sign in to comment.