From 002c02557996ae5528bd8d64070950154947059d Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 16:17:39 +0900 Subject: [PATCH 01/18] Add restore progressbar --- .../Optimization/{Loop.cs => OptimizeLoop.cs} | 10 +- Tunny/Optimization/RestoreLoop.cs | 93 ++++++++++ Tunny/UI/OptimizationWindow.Designer.cs | 133 ++++++++------ Tunny/UI/OptimizationWindow.cs | 168 +++++++++--------- Tunny/UI/OptimizationWindow.resx | 5 +- 5 files changed, 264 insertions(+), 145 deletions(-) rename Tunny/Optimization/{Loop.cs => OptimizeLoop.cs} (89%) create mode 100644 Tunny/Optimization/RestoreLoop.cs diff --git a/Tunny/Optimization/Loop.cs b/Tunny/Optimization/OptimizeLoop.cs similarity index 89% rename from Tunny/Optimization/Loop.cs rename to Tunny/Optimization/OptimizeLoop.cs index 05b98755..a2b8e19f 100644 --- a/Tunny/Optimization/Loop.cs +++ b/Tunny/Optimization/OptimizeLoop.cs @@ -10,7 +10,7 @@ namespace Tunny.Optimization { - internal static class Loop + internal static class OptimizeLoop { private static BackgroundWorker s_worker; private static TunnyComponent s_component; @@ -19,7 +19,7 @@ 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; @@ -49,7 +49,7 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker) return new[] { double.NaN }; } - var solver = new Optuna(s_component.GhInOut.ComponentFolder); + var optunaSolver = new Optuna(s_component.GhInOut.ComponentFolder); Dictionary settings = new Dictionary() { { "nTrials", NTrials }, @@ -60,10 +60,10 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker) { "nObjective", s_component.GhInOut.GetObjectiveValues().Count } }; - bool solverStarted = solver.RunSolver( + bool solverStarted = optunaSolver.RunSolver( variables, EvaluateFunction, "OptunaTPE", settings, "", ""); - return solverStarted ? solver.XOpt : new[] { double.NaN }; + return solverStarted ? optunaSolver.XOpt : new[] { double.NaN }; } public static EvaluatedGHResult EvaluateFunction(IList values, int progress) diff --git a/Tunny/Optimization/RestoreLoop.cs b/Tunny/Optimization/RestoreLoop.cs new file mode 100644 index 00000000..74dec9f0 --- /dev/null +++ b/Tunny/Optimization/RestoreLoop.cs @@ -0,0 +1,93 @@ +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; + + internal static void Run(object sender, DoWorkEventArgs e) + { + s_worker = sender as BackgroundWorker; + s_component = e.Argument as TunnyComponent; + + var modelMesh = new GH_Structure(); + var variables = new GH_Structure(); + var objectives = new GH_Structure(); + + 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; + } + + 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); + } + 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 objectives, ModelResult model, IEnumerable nickName) + { + foreach (string name in nickName) + { + foreach (var 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 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 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)); + } + } +} \ No newline at end of file diff --git a/Tunny/UI/OptimizationWindow.Designer.cs b/Tunny/UI/OptimizationWindow.Designer.cs index 866f65a7..eb73571d 100644 --- a/Tunny/UI/OptimizationWindow.Designer.cs +++ b/Tunny/UI/OptimizationWindow.Designer.cs @@ -30,13 +30,13 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OptimizationWindow)); - this.runOptimizeButton = new System.Windows.Forms.Button(); - this.backgroundWorkerSolver = new System.ComponentModel.BackgroundWorker(); - this.stopButton = new System.Windows.Forms.Button(); + this.optimizeRunButton = new System.Windows.Forms.Button(); + this.optimizeBackgroundWorker = new System.ComponentModel.BackgroundWorker(); + this.optimizeStopButton = new System.Windows.Forms.Button(); this.nTrialNumUpDown = new System.Windows.Forms.NumericUpDown(); this.nTrialText = new System.Windows.Forms.Label(); this.loadIfExistsCheckBox = new System.Windows.Forms.CheckBox(); - this.progressBar = new System.Windows.Forms.ProgressBar(); + this.optimizeProgressBar = new System.Windows.Forms.ProgressBar(); this.samplerComboBox = new System.Windows.Forms.ComboBox(); this.SamplerTypeText = new System.Windows.Forms.Label(); this.studyNameLabel = new System.Windows.Forms.Label(); @@ -44,7 +44,8 @@ private void InitializeComponent() this.optimizeTabControl = new System.Windows.Forms.TabControl(); this.optimizeTabPage = new System.Windows.Forms.TabPage(); this.resultTabPage = new System.Windows.Forms.TabPage(); - this.RestoreButton = new System.Windows.Forms.Button(); + this.restoreProgressBar = new System.Windows.Forms.ProgressBar(); + this.restoreRunButton = new System.Windows.Forms.Button(); this.restoreModelNumTextBox = new System.Windows.Forms.TextBox(); this.restoreModelLabel = new System.Windows.Forms.Label(); this.openResultFolderButton = new System.Windows.Forms.Button(); @@ -52,33 +53,36 @@ private void InitializeComponent() this.VisualizeButton = new System.Windows.Forms.Button(); this.visualizeTypeLabel = new System.Windows.Forms.Label(); this.visualizeTypeComboBox = new System.Windows.Forms.ComboBox(); + this.restoreBackgroundWorker = new System.ComponentModel.BackgroundWorker(); + this.restoreStopButton = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.nTrialNumUpDown)).BeginInit(); this.optimizeTabControl.SuspendLayout(); this.optimizeTabPage.SuspendLayout(); this.resultTabPage.SuspendLayout(); this.SuspendLayout(); // - // runOptimizeButton - // - this.runOptimizeButton.Location = new System.Drawing.Point(13, 168); - this.runOptimizeButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.runOptimizeButton.Name = "runOptimizeButton"; - this.runOptimizeButton.Size = new System.Drawing.Size(120, 29); - this.runOptimizeButton.TabIndex = 0; - this.runOptimizeButton.Text = "RunOptimize"; - this.runOptimizeButton.UseVisualStyleBackColor = true; - this.runOptimizeButton.Click += new System.EventHandler(this.ButtonRunOptimize_Click); - // - // stopButton - // - this.stopButton.Location = new System.Drawing.Point(155, 168); - this.stopButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.stopButton.Name = "stopButton"; - this.stopButton.Size = new System.Drawing.Size(87, 29); - this.stopButton.TabIndex = 1; - this.stopButton.Text = "Stop"; - this.stopButton.UseVisualStyleBackColor = true; - this.stopButton.Click += new System.EventHandler(this.ButtonStop_Click); + // optimizeRunButton + // + this.optimizeRunButton.Location = new System.Drawing.Point(13, 168); + this.optimizeRunButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.optimizeRunButton.Name = "optimizeRunButton"; + this.optimizeRunButton.Size = new System.Drawing.Size(120, 29); + this.optimizeRunButton.TabIndex = 0; + this.optimizeRunButton.Text = "RunOptimize"; + this.optimizeRunButton.UseVisualStyleBackColor = true; + this.optimizeRunButton.Click += new System.EventHandler(this.OptimizeRunButton_Click); + // + // optimizeStopButton + // + this.optimizeStopButton.Enabled = false; + this.optimizeStopButton.Location = new System.Drawing.Point(155, 168); + this.optimizeStopButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.optimizeStopButton.Name = "optimizeStopButton"; + this.optimizeStopButton.Size = new System.Drawing.Size(87, 29); + this.optimizeStopButton.TabIndex = 1; + this.optimizeStopButton.Text = "Stop"; + this.optimizeStopButton.UseVisualStyleBackColor = true; + this.optimizeStopButton.Click += new System.EventHandler(this.OptimizeStopButton_Click); // // nTrialNumUpDown // @@ -121,13 +125,13 @@ private void InitializeComponent() this.loadIfExistsCheckBox.Text = "Load if study file exists"; this.loadIfExistsCheckBox.UseVisualStyleBackColor = true; // - // progressBar + // optimizeProgressBar // - this.progressBar.Location = new System.Drawing.Point(13, 204); - this.progressBar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(227, 29); - this.progressBar.TabIndex = 6; + this.optimizeProgressBar.Location = new System.Drawing.Point(13, 204); + this.optimizeProgressBar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.optimizeProgressBar.Name = "optimizeProgressBar"; + this.optimizeProgressBar.Size = new System.Drawing.Size(227, 29); + this.optimizeProgressBar.TabIndex = 6; // // samplerComboBox // @@ -186,11 +190,11 @@ private void InitializeComponent() this.optimizeTabPage.Controls.Add(this.studyNameTextBox); this.optimizeTabPage.Controls.Add(this.samplerComboBox); this.optimizeTabPage.Controls.Add(this.studyNameLabel); - this.optimizeTabPage.Controls.Add(this.runOptimizeButton); + this.optimizeTabPage.Controls.Add(this.optimizeRunButton); this.optimizeTabPage.Controls.Add(this.SamplerTypeText); - this.optimizeTabPage.Controls.Add(this.stopButton); + this.optimizeTabPage.Controls.Add(this.optimizeStopButton); this.optimizeTabPage.Controls.Add(this.nTrialNumUpDown); - this.optimizeTabPage.Controls.Add(this.progressBar); + this.optimizeTabPage.Controls.Add(this.optimizeProgressBar); this.optimizeTabPage.Controls.Add(this.nTrialText); this.optimizeTabPage.Controls.Add(this.loadIfExistsCheckBox); this.optimizeTabPage.Location = new System.Drawing.Point(4, 24); @@ -204,7 +208,9 @@ private void InitializeComponent() // // resultTabPage // - this.resultTabPage.Controls.Add(this.RestoreButton); + this.resultTabPage.Controls.Add(this.restoreStopButton); + this.resultTabPage.Controls.Add(this.restoreProgressBar); + this.resultTabPage.Controls.Add(this.restoreRunButton); this.resultTabPage.Controls.Add(this.restoreModelNumTextBox); this.resultTabPage.Controls.Add(this.restoreModelLabel); this.resultTabPage.Controls.Add(this.openResultFolderButton); @@ -221,28 +227,36 @@ private void InitializeComponent() this.resultTabPage.Text = "Result"; this.resultTabPage.UseVisualStyleBackColor = true; // - // RestoreButton + // restoreProgressBar + // + this.restoreProgressBar.Location = new System.Drawing.Point(17, 205); + this.restoreProgressBar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.restoreProgressBar.Name = "restoreProgressBar"; + this.restoreProgressBar.Size = new System.Drawing.Size(227, 29); + this.restoreProgressBar.TabIndex = 8; // - this.RestoreButton.Location = new System.Drawing.Point(172, 173); - this.RestoreButton.Name = "RestoreButton"; - this.RestoreButton.Size = new System.Drawing.Size(75, 23); - this.RestoreButton.TabIndex = 7; - this.RestoreButton.Text = "Restore"; - this.RestoreButton.UseVisualStyleBackColor = true; - this.RestoreButton.Click += new System.EventHandler(this.RestoreButton_Click); + // restoreRunButton + // + this.restoreRunButton.Location = new System.Drawing.Point(111, 172); + this.restoreRunButton.Name = "restoreRunButton"; + this.restoreRunButton.Size = new System.Drawing.Size(75, 23); + this.restoreRunButton.TabIndex = 7; + this.restoreRunButton.Text = "Restore"; + this.restoreRunButton.UseVisualStyleBackColor = true; + this.restoreRunButton.Click += new System.EventHandler(this.RestoreRunButton_Click); // // restoreModelNumTextBox // - this.restoreModelNumTextBox.Location = new System.Drawing.Point(6, 174); + this.restoreModelNumTextBox.Location = new System.Drawing.Point(17, 172); this.restoreModelNumTextBox.Name = "restoreModelNumTextBox"; - this.restoreModelNumTextBox.Size = new System.Drawing.Size(158, 23); + this.restoreModelNumTextBox.Size = new System.Drawing.Size(88, 23); this.restoreModelNumTextBox.TabIndex = 6; this.restoreModelNumTextBox.Text = "-1"; // // restoreModelLabel // this.restoreModelLabel.AutoSize = true; - this.restoreModelLabel.Location = new System.Drawing.Point(7, 156); + this.restoreModelLabel.Location = new System.Drawing.Point(6, 146); this.restoreModelLabel.Name = "restoreModelLabel"; this.restoreModelLabel.Size = new System.Drawing.Size(162, 15); this.restoreModelLabel.TabIndex = 5; @@ -308,6 +322,17 @@ private void InitializeComponent() this.visualizeTypeComboBox.Size = new System.Drawing.Size(175, 23); this.visualizeTypeComboBox.TabIndex = 0; // + // restoreStopButton + // + this.restoreStopButton.Enabled = false; + this.restoreStopButton.Location = new System.Drawing.Point(194, 172); + this.restoreStopButton.Name = "restoreStopButton"; + this.restoreStopButton.Size = new System.Drawing.Size(50, 23); + this.restoreStopButton.TabIndex = 9; + this.restoreStopButton.Text = "Stop"; + this.restoreStopButton.UseVisualStyleBackColor = true; + this.restoreStopButton.Click += new System.EventHandler(this.RestoreStopButton_Click); + // // OptimizationWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -333,12 +358,12 @@ private void InitializeComponent() #endregion - private System.Windows.Forms.Button runOptimizeButton; - private System.ComponentModel.BackgroundWorker backgroundWorkerSolver; - private System.Windows.Forms.Button stopButton; + private System.Windows.Forms.Button optimizeRunButton; + private System.ComponentModel.BackgroundWorker optimizeBackgroundWorker; + private System.Windows.Forms.Button optimizeStopButton; private System.Windows.Forms.NumericUpDown nTrialNumUpDown; private System.Windows.Forms.CheckBox loadIfExistsCheckBox; - private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.ProgressBar optimizeProgressBar; private System.Windows.Forms.ComboBox samplerComboBox; private System.Windows.Forms.Label SamplerTypeText; private System.Windows.Forms.Label nTrialText; @@ -352,9 +377,13 @@ private void InitializeComponent() private System.Windows.Forms.ComboBox visualizeTypeComboBox; private System.Windows.Forms.Button clearResultButton; private System.Windows.Forms.Button openResultFolderButton; - private System.Windows.Forms.Button RestoreButton; + private System.Windows.Forms.Button restoreRunButton; private System.Windows.Forms.TextBox restoreModelNumTextBox; private System.Windows.Forms.Label restoreModelLabel; + private System.Windows.Forms.ProgressBar restoreProgressBar; + private System.ComponentModel.BackgroundWorker backgroundWorker1; + private System.ComponentModel.BackgroundWorker restoreBackgroundWorker; + private System.Windows.Forms.Button restoreStopButton; } } diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index e75e526b..0e1316f2 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -7,11 +7,6 @@ using System.Windows.Forms; using Grasshopper.GUI; -using Grasshopper.Kernel.Data; -using Grasshopper.Kernel.Types; - -using Rhino.FileIO; -using Rhino.Geometry; using Tunny.Component; using Tunny.Optimization; @@ -38,20 +33,17 @@ public OptimizationWindow(TunnyComponent component) samplerComboBox.SelectedIndex = 0; visualizeTypeComboBox.SelectedIndex = 3; - backgroundWorkerSolver.DoWork += Loop.RunOptimizationLoopMultiple; - backgroundWorkerSolver.ProgressChanged += ProgressChangedHandler; - backgroundWorkerSolver.RunWorkerCompleted += ButtonStop_Click; - backgroundWorkerSolver.WorkerReportsProgress = true; - backgroundWorkerSolver.WorkerSupportsCancellation = true; - } - - private void ProgressChangedHandler(object sender, ProgressChangedEventArgs e) - { - var parameters = (IList)e.UserState; - UpdateGrasshopper(parameters); - - progressBar.Value = e.ProgressPercentage; - progressBar.Update(); + optimizeBackgroundWorker.DoWork += OptimizeLoop.RunMultiple; + optimizeBackgroundWorker.ProgressChanged += OptimizeProgressChangedHandler; + optimizeBackgroundWorker.RunWorkerCompleted += OptimizeStopButton_Click; + optimizeBackgroundWorker.WorkerReportsProgress = true; + optimizeBackgroundWorker.WorkerSupportsCancellation = true; + + restoreBackgroundWorker.DoWork += RestoreLoop.Run; + restoreBackgroundWorker.ProgressChanged += RestoreProgressChangedHandler; + restoreBackgroundWorker.RunWorkerCompleted += RestoreStopButton_Click; + restoreBackgroundWorker.WorkerReportsProgress = true; + restoreBackgroundWorker.WorkerSupportsCancellation = true; } private void UpdateGrasshopper(IList parameters) @@ -66,41 +58,6 @@ private void UpdateGrasshopper(IList parameters) private void OptimizationWindow_Load(object sender, EventArgs e) { - - } - - private void ButtonRunOptimize_Click(object sender, EventArgs e) - { - GH_DocumentEditor ghCanvas = Owner as GH_DocumentEditor; - ghCanvas.DisableUI(); - - runOptimizeButton.Enabled = false; - Loop.NTrials = (int)nTrialNumUpDown.Value; - Loop.LoadIfExists = loadIfExistsCheckBox.Checked; - Loop.SamplerType = samplerComboBox.Text; - Loop.StudyName = studyNameTextBox.Text; - - if (_component.GhInOut.GetObjectiveValues().Count > 1 && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random")) - { - MessageBox.Show("This sampler does not support multiple objectives optimization.", "Tunny", MessageBoxButtons.OK, MessageBoxIcon.Error); - ghCanvas.EnableUI(); - runOptimizeButton.Enabled = true; - return; - } - - backgroundWorkerSolver.RunWorkerAsync(_component); - - stopButton.Enabled = true; - } - - private void ButtonStop_Click(object sender, EventArgs e) - { - runOptimizeButton.Enabled = true; - stopButton.Enabled = false; - - //Enable GUI - var ghCanvas = Owner as GH_DocumentEditor; - ghCanvas?.EnableUI(); } private void VisualizeButton_Click(object sender, EventArgs e) @@ -119,63 +76,100 @@ private void ClearResultButton_Click(object sender, EventArgs e) File.Delete(_component.GhInOut.ComponentFolder + "/Tunny_Opt_Result.db"); } - private void RestoreButton_Click(object sender, EventArgs e) + private void FormClosingXButton(object sender, FormClosingEventArgs e) { - var modelMesh = new GH_Structure(); - var variables = new GH_Structure(); - var objectives = new GH_Structure(); - var nickName = _component.GhInOut.Sliders.Select(x => x.NickName).ToArray(); + var ghCanvas = Owner as GH_DocumentEditor; + ghCanvas?.EnableUI(); - var optuna = new Optuna(_component.GhInOut.ComponentFolder); - string studyName = studyNameTextBox.Text; + if (optimizeBackgroundWorker != null) + { + optimizeBackgroundWorker.CancelAsync(); + } - int[] num = restoreModelNumTextBox.Text.Split(',').Select(int.Parse).ToArray(); - ModelResult[] modelResult = optuna.GetModelResult(num, studyName); - foreach (ModelResult model in modelResult) + if (restoreBackgroundWorker != null) { - SetVariables(variables, model, nickName); - SetObjectives(objectives, model); - SetModelMesh(modelMesh, model); + restoreBackgroundWorker.CancelAsync(); } - _component.Variables = variables; - _component.Objectives = objectives; - _component.ModelMesh = modelMesh; - _component.ExpireSolution(true); } - private static void SetVariables(GH_Structure objectives, ModelResult model, IEnumerable nickName) + private void RestoreRunButton_Click(object sender, EventArgs e) { - foreach (string name in nickName) - { - foreach (var obj in model.Variables.Where(obj => obj.Key == name)) - { - objectives.Append(new GH_Number(obj.Value), new GH_Path(0, model.Number)); - } - } + optimizeRunButton.Enabled = false; + optimizeStopButton.Enabled = true; + + RestoreLoop.StudyName = studyNameTextBox.Text; + RestoreLoop.NickNames = _component.GhInOut.Sliders.Select(x => x.NickName).ToArray(); + RestoreLoop.Indices = restoreModelNumTextBox.Text.Split(',').Select(int.Parse).ToArray(); + + restoreBackgroundWorker.RunWorkerAsync(_component); } - private static void SetObjectives(GH_Structure objectives, ModelResult model) + private void RestoreStopButton_Click(object sender, EventArgs e) { - foreach (double obj in model.Objectives) + optimizeRunButton.Enabled = true; + optimizeStopButton.Enabled = false; + + if (restoreBackgroundWorker != null) { - objectives.Append(new GH_Number(obj), new GH_Path(0, model.Number)); + restoreBackgroundWorker.CancelAsync(); } + _component.ExpireSolution(true); } - private static void SetModelMesh(GH_Structure modelMesh, ModelResult model) + private void RestoreProgressChangedHandler(object sender, ProgressChangedEventArgs e) { - if (model.Draco == string.Empty) + restoreProgressBar.Value = e.ProgressPercentage; + restoreProgressBar.Update(); + } + + private void OptimizeRunButton_Click(object sender, EventArgs e) + { + GH_DocumentEditor ghCanvas = Owner as GH_DocumentEditor; + ghCanvas.DisableUI(); + + optimizeRunButton.Enabled = false; + OptimizeLoop.NTrials = (int)nTrialNumUpDown.Value; + OptimizeLoop.LoadIfExists = loadIfExistsCheckBox.Checked; + OptimizeLoop.SamplerType = samplerComboBox.Text; + OptimizeLoop.StudyName = studyNameTextBox.Text; + + if (_component.GhInOut.GetObjectiveValues().Count > 1 && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random")) { + MessageBox.Show("This sampler does not support multiple objectives optimization.", "Tunny", MessageBoxButtons.OK, MessageBoxIcon.Error); + ghCanvas.EnableUI(); + optimizeRunButton.Enabled = true; return; } - var mesh = (Mesh)DracoCompression.DecompressBase64String(model.Draco); - modelMesh.Append(new GH_Mesh(mesh), new GH_Path(0, model.Number)); + + optimizeBackgroundWorker.RunWorkerAsync(_component); + + optimizeStopButton.Enabled = true; + } - private void FormClosingXButton(object sender, FormClosingEventArgs e) + private void OptimizeStopButton_Click(object sender, EventArgs e) { + optimizeRunButton.Enabled = true; + optimizeStopButton.Enabled = false; + + if (optimizeBackgroundWorker != null) + { + optimizeBackgroundWorker.CancelAsync(); + } + + //Enable GUI var ghCanvas = Owner as GH_DocumentEditor; ghCanvas?.EnableUI(); + + } + + private void OptimizeProgressChangedHandler(object sender, ProgressChangedEventArgs e) + { + var parameters = (IList)e.UserState; + UpdateGrasshopper(parameters); + + optimizeProgressBar.Value = e.ProgressPercentage; + optimizeProgressBar.Update(); } } } \ No newline at end of file diff --git a/Tunny/UI/OptimizationWindow.resx b/Tunny/UI/OptimizationWindow.resx index 1789775b..9b924b14 100644 --- a/Tunny/UI/OptimizationWindow.resx +++ b/Tunny/UI/OptimizationWindow.resx @@ -117,9 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 17, 17 + + 255, 17 + From d93c0da87b6e601f637e074a5f1b1e6258d989e1 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 16:22:52 +0900 Subject: [PATCH 02/18] Update CHANGELOG.md --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25d2f0f..bfa2bd26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ 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. +## [UNRELEASED] + +### Added + +- Restore progressbar + +### Changed + +- Restore feature was made asynchronous. + + ## [0.1.1] -2022-04-17 ### Fixed From 1d695903f1e9ce20ec90cfb281b3c8a5f0c9363b Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 18:43:26 +0900 Subject: [PATCH 03/18] Add null objective support --- Tunny/Solver/Optuna.cs | 8 -------- Tunny/Solver/OptunaAlgorithm.cs | 25 ++++++++++++++++++++++--- Tunny/UI/OptimizationWindow.Designer.cs | 1 - Tunny/UI/OptimizationWindow.cs | 9 ++++++++- Tunny/Util/GrasshopperInOut.cs | 17 ++++++++++++++++- Tunny/Util/ModelResult.cs | 12 ++++++++++++ 6 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 Tunny/Util/ModelResult.cs diff --git a/Tunny/Solver/Optuna.cs b/Tunny/Solver/Optuna.cs index 236ad8cb..735e8fb1 100644 --- a/Tunny/Solver/Optuna.cs +++ b/Tunny/Solver/Optuna.cs @@ -207,12 +207,4 @@ private static void ParseTrial(ICollection modelResult, dynamic tri }); } } - - public class ModelResult - { - public int Number { get; set; } - public string Draco { get; set; } - public Dictionary Variables { get; set; } - public double[] Objectives { get; set; } - } } \ No newline at end of file diff --git a/Tunny/Solver/OptunaAlgorithm.cs b/Tunny/Solver/OptunaAlgorithm.cs index 1bd11be4..d655d8db 100644 --- a/Tunny/Solver/OptunaAlgorithm.cs +++ b/Tunny/Solver/OptunaAlgorithm.cs @@ -80,11 +80,30 @@ public void Solve() { int progress = i * 100 / nTrials; dynamic trial = study.ask(); - for (int j = 0; j < n; j++) + + //TODO: Is this the correct way to handle the case of null? + //Other than TPE, the value is returned at random when retrying, so the value will be anything but null. + //TPEs, on the other hand, search for a specific location determined by GP, + //so the value tends to remain the same even after retries and there is no way to get out. + int nullCount = 0; + while (nullCount < 10) { - xTest[j] = trial.suggest_uniform(NickName[j], Lb[j], Ub[j]); + for (int j = 0; j < n; j++) + { + xTest[j] = trial.suggest_uniform(NickName[j], Lb[j], Ub[j]); + } + result = EvalFunc(xTest, progress); + + if (result.ObjectiveValues.Contains(double.NaN)) + { + trial = study.ask(); + nullCount++; + } + else + { + break; + } } - result = EvalFunc(xTest, progress); trial.set_user_attr("geometry", result.ModelDraco); study.tell(trial, result.ObjectiveValues.ToArray()); } diff --git a/Tunny/UI/OptimizationWindow.Designer.cs b/Tunny/UI/OptimizationWindow.Designer.cs index eb73571d..8d932dce 100644 --- a/Tunny/UI/OptimizationWindow.Designer.cs +++ b/Tunny/UI/OptimizationWindow.Designer.cs @@ -381,7 +381,6 @@ private void InitializeComponent() private System.Windows.Forms.TextBox restoreModelNumTextBox; private System.Windows.Forms.Label restoreModelLabel; private System.Windows.Forms.ProgressBar restoreProgressBar; - private System.ComponentModel.BackgroundWorker backgroundWorker1; private System.ComponentModel.BackgroundWorker restoreBackgroundWorker; private System.Windows.Forms.Button restoreStopButton; } diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index 0e1316f2..c3270dc7 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -133,7 +133,14 @@ private void OptimizeRunButton_Click(object sender, EventArgs e) OptimizeLoop.SamplerType = samplerComboBox.Text; OptimizeLoop.StudyName = studyNameTextBox.Text; - if (_component.GhInOut.GetObjectiveValues().Count > 1 && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random")) + var objectiveValues = _component.GhInOut.GetObjectiveValues(); + if (objectiveValues.Count == 0) + { + ghCanvas.EnableUI(); + optimizeRunButton.Enabled = true; + return; + } + else if (objectiveValues.Count > 1 && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random")) { MessageBox.Show("This sampler does not support multiple objectives optimization.", "Tunny", MessageBoxButtons.OK, MessageBoxIcon.Error); ghCanvas.EnableUI(); diff --git a/Tunny/Util/GrasshopperInOut.cs b/Tunny/Util/GrasshopperInOut.cs index da93c58d..b2d47837 100644 --- a/Tunny/Util/GrasshopperInOut.cs +++ b/Tunny/Util/GrasshopperInOut.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Windows.Forms; using Grasshopper.Kernel; using Grasshopper.Kernel.Data; @@ -206,13 +207,27 @@ public List GetObjectiveValues() foreach (IGH_Param objective in _objectives) { - IGH_StructureEnumerator ghEnumerator = objective.VolatileData.AllData(true); + IGH_StructureEnumerator ghEnumerator = objective.VolatileData.AllData(false); + if (ghEnumerator.Count() > 1) + { + TunnyMessageBox.Show( + "Tunny doesn't handle list output.\n Separate each objective if you want multiple objectives", + "Tunny", + MessageBoxButtons.OK, + MessageBoxIcon.Error + ); + return new List(); + } foreach (IGH_Goo goo in ghEnumerator) { if (goo is GH_Number num) { values.Add(num.Value); } + else if (goo == null) + { + values.Add(double.NaN); + } } } diff --git a/Tunny/Util/ModelResult.cs b/Tunny/Util/ModelResult.cs new file mode 100644 index 00000000..1c992346 --- /dev/null +++ b/Tunny/Util/ModelResult.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Tunny.Util +{ + public class ModelResult + { + public int Number { get; set; } + public string Draco { get; set; } + public Dictionary Variables { get; set; } + public double[] Objectives { get; set; } + } +} \ No newline at end of file From d02c5153c14fbcf1083ae307795fd6a5ed9a18a5 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 18:50:58 +0900 Subject: [PATCH 04/18] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfa2bd26..37354587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release - Restore feature was made asynchronous. +### 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. ## [0.1.1] -2022-04-17 From 48421dad1b7440d6220af83fbbba0ba89609b6a8 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 22:42:02 +0900 Subject: [PATCH 05/18] Add objective nickname input --- Tunny/Optimization/OptimizeLoop.cs | 5 ++++- Tunny/Solver/ISolver.cs | 3 +++ Tunny/Solver/Optuna.cs | 25 +++++++++++++++---------- Tunny/Solver/OptunaAlgorithm.cs | 25 ++++++++++++++++++------- Tunny/Util/GrasshopperInOut.cs | 6 +++--- 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Tunny/Optimization/OptimizeLoop.cs b/Tunny/Optimization/OptimizeLoop.cs index a2b8e19f..f72879f7 100644 --- a/Tunny/Optimization/OptimizeLoop.cs +++ b/Tunny/Optimization/OptimizeLoop.cs @@ -3,6 +3,8 @@ using System.ComponentModel; using System.Linq; +using Grasshopper.Kernel; + using Tunny.Component; using Tunny.Solver; using Tunny.UI; @@ -43,6 +45,7 @@ internal static void RunMultiple(object sender, DoWorkEventArgs e) private static double[] RunOptimizationLoop(BackgroundWorker worker) { List variables = s_component.GhInOut.Variables; + List objectives = s_component.GhInOut.Objectives; if (worker.CancellationPending) { @@ -61,7 +64,7 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker) }; bool solverStarted = optunaSolver.RunSolver( - variables, EvaluateFunction, "OptunaTPE", settings, "", ""); + variables, objectives, EvaluateFunction, "OptunaTPE", settings, "", ""); return solverStarted ? optunaSolver.XOpt : new[] { double.NaN }; } diff --git a/Tunny/Solver/ISolver.cs b/Tunny/Solver/ISolver.cs index f7b9f73b..847b09f2 100644 --- a/Tunny/Solver/ISolver.cs +++ b/Tunny/Solver/ISolver.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Grasshopper.Kernel; + using Tunny.Optimization; using Tunny.Util; @@ -12,6 +14,7 @@ internal interface ISolver double[] FxOpt { get; } bool RunSolver( List variables, + List objectives, Func, int, EvaluatedGHResult> evaluate, string preset, Dictionary settings, diff --git a/Tunny/Solver/Optuna.cs b/Tunny/Solver/Optuna.cs index 735e8fb1..70ea5369 100644 --- a/Tunny/Solver/Optuna.cs +++ b/Tunny/Solver/Optuna.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Windows.Forms; +using Grasshopper.Kernel; + using Python.Runtime; using Tunny.Optimization; @@ -28,6 +30,7 @@ public Optuna(string componentFolder) public bool RunSolver( List variables, + List objectives, Func, int, EvaluatedGHResult> evaluate, string preset, Dictionary settings, string installFolder, string documentPath) @@ -36,14 +39,15 @@ public bool RunSolver( var lb = new double[dVar]; var ub = new double[dVar]; var integer = new bool[dVar]; - var nickName = new string[dVar]; + var varNickName = new string[dVar]; + string[] objNickName = objectives.Select(x => x.NickName).ToArray(); for (var i = 0; i < dVar; i++) { lb[i] = Convert.ToDouble(variables[i].LowerBond); ub[i] = Convert.ToDouble(variables[i].UpperBond); integer[i] = variables[i].Integer; - nickName[i] = variables[i].NickName; + varNickName[i] = variables[i].NickName; } EvaluatedGHResult Eval(double[] x, int progress) @@ -54,7 +58,7 @@ EvaluatedGHResult Eval(double[] x, int progress) try { - var tpe = new OptunaAlgorithm(lb, ub, nickName, settings, Eval); + var tpe = new OptunaAlgorithm(lb, ub, varNickName, objNickName, settings, Eval); tpe.Solve(); XOpt = tpe.Get_XOptimum(); FxOpt = tpe.Get_fxOptimum(); @@ -96,17 +100,18 @@ public void ShowResultVisualize(string visualize, string studyName) return; } + string[] nickNames = ((string)study.user_attrs["objective_names"]).Split(','); try { dynamic vis; switch (visualize) { case "contour": - vis = optuna.visualization.plot_contour(study); + vis = optuna.visualization.plot_contour(study, target_name: nickNames[0]); vis.show(); break; case "EDF": - vis = optuna.visualization.plot_edf(study); + vis = optuna.visualization.plot_edf(study, target_name: nickNames[0]); vis.show(); break; case "intermediate values": @@ -114,23 +119,23 @@ public void ShowResultVisualize(string visualize, string studyName) vis.show(); break; case "optimization history": - vis = optuna.visualization.plot_optimization_history(study); + vis = optuna.visualization.plot_optimization_history(study, target_name: nickNames[0]); vis.show(); break; case "parallel coordinate": - vis = optuna.visualization.plot_parallel_coordinate(study); + vis = optuna.visualization.plot_parallel_coordinate(study, targat_name: nickNames[0]); vis.show(); break; case "param importances": - vis = optuna.visualization.plot_param_importances(study); + vis = optuna.visualization.plot_param_importances(study, target_name: nickNames[0]); vis.show(); break; case "pareto front": - vis = optuna.visualization.plot_pareto_front(study); + vis = optuna.visualization.plot_pareto_front(study, target_names: nickNames); vis.show(); break; case "slice": - vis = optuna.visualization.plot_slice(study); + vis = optuna.visualization.plot_slice(study, target_name: nickNames[0]); vis.show(); break; default: diff --git a/Tunny/Solver/OptunaAlgorithm.cs b/Tunny/Solver/OptunaAlgorithm.cs index d655d8db..0a7383d2 100644 --- a/Tunny/Solver/OptunaAlgorithm.cs +++ b/Tunny/Solver/OptunaAlgorithm.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text; using Python.Runtime; @@ -11,20 +12,22 @@ public class OptunaAlgorithm { private double[] Lb { get; set; } private double[] Ub { get; set; } - private string[] NickName { get; set; } + private string[] VarNickName { get; set; } + private string[] ObjNickName { get; set; } private Dictionary Settings { get; set; } private Func EvalFunc { get; set; } private double[] XOpt { get; set; } private double[] FxOpt { get; set; } public OptunaAlgorithm( - double[] lb, double[] ub, string[] nickName, + double[] lb, double[] ub, string[] varNickName, string[] objNickName, Dictionary settings, Func evalFunc) { Lb = lb; Ub = ub; - NickName = nickName; + VarNickName = varNickName; + ObjNickName = objNickName; Settings = settings; EvalFunc = evalFunc; } @@ -74,6 +77,14 @@ public void Solve() directions: directions ); + var name = new StringBuilder(); + foreach (var objName in ObjNickName) + { + name.Append(objName + ","); + } + name.Remove(name.Length - 1, 1); + study.set_user_attr("objective_names", name.ToString()); + var xTest = new double[n]; var result = new EvaluatedGHResult(); for (int i = 0; i < nTrials; i++) @@ -90,7 +101,7 @@ public void Solve() { for (int j = 0; j < n; j++) { - xTest[j] = trial.suggest_uniform(NickName[j], Lb[j], Ub[j]); + xTest[j] = trial.suggest_uniform(VarNickName[j], Lb[j], Ub[j]); } result = EvalFunc(xTest, progress); @@ -112,13 +123,13 @@ public void Solve() { var values = (double[])study.best_params.values(); var keys = (string[])study.best_params.keys(); - var opt = new double[NickName.Length]; + var opt = new double[VarNickName.Length]; - for (int i = 0; i < NickName.Length; i++) + for (int i = 0; i < VarNickName.Length; i++) { for (int j = 0; j < keys.Length; j++) { - if (keys[j] == NickName[i]) + if (keys[j] == VarNickName[i]) { opt[i] = values[j]; } diff --git a/Tunny/Util/GrasshopperInOut.cs b/Tunny/Util/GrasshopperInOut.cs index b2d47837..76b89ce9 100644 --- a/Tunny/Util/GrasshopperInOut.cs +++ b/Tunny/Util/GrasshopperInOut.cs @@ -22,7 +22,7 @@ public class GrasshopperInOut private readonly List _inputGuids; private readonly TunnyComponent _component; private IGH_Param _modelMesh; - private List _objectives; + public List Objectives; public List Sliders; public readonly string ComponentFolder; @@ -134,7 +134,7 @@ private bool SetObjectives() return false; } - _objectives = _component.Params.Input[1].Sources.ToList(); + Objectives = _component.Params.Input[1].Sources.ToList(); return true; } @@ -205,7 +205,7 @@ public List GetObjectiveValues() { var values = new List(); - foreach (IGH_Param objective in _objectives) + foreach (IGH_Param objective in Objectives) { IGH_StructureEnumerator ghEnumerator = objective.VolatileData.AllData(false); if (ghEnumerator.Count() > 1) From 2ef3b627618714bbd151dff5eb78691b1e5f84c6 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Fri, 29 Apr 2022 22:47:35 +0900 Subject: [PATCH 06/18] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37354587..e383b244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,15 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release ### Changed - Restore feature was made asynchronous. +- Visualize graph axis name now use input objective's nickname. ### 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. ## [0.1.1] -2022-04-17 From a0b180317255189aaa58696fd1d5fecbf03a60d5 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 12:48:34 +0900 Subject: [PATCH 07/18] Add genepool support --- .gitignore | 2 +- Tunny/Tunny.csproj | 8 +++-- Tunny/Util/GrasshopperInOut.cs | 58 ++++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 083abaae..c5d3ff82 100644 --- a/.gitignore +++ b/.gitignore @@ -452,4 +452,4 @@ $RECYCLE.BIN/ !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -Tunny/Python/ \ No newline at end of file +Tunny/Lib/ \ No newline at end of file diff --git a/Tunny/Tunny.csproj b/Tunny/Tunny.csproj index 33c5607e..90e2e345 100644 --- a/Tunny/Tunny.csproj +++ b/Tunny/Tunny.csproj @@ -13,9 +13,13 @@ - + + + Lib\GalapagosComponents.dll + false + @@ -41,7 +45,7 @@ - + \ No newline at end of file diff --git a/Tunny/Util/GrasshopperInOut.cs b/Tunny/Util/GrasshopperInOut.cs index 76b89ce9..1d7ee2c7 100644 --- a/Tunny/Util/GrasshopperInOut.cs +++ b/Tunny/Util/GrasshopperInOut.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Windows.Forms; +using GalapagosComponents; + using Grasshopper.Kernel; using Grasshopper.Kernel.Data; using Grasshopper.Kernel.Special; @@ -21,6 +23,7 @@ public class GrasshopperInOut private readonly GH_Document _document; private readonly List _inputGuids; private readonly TunnyComponent _component; + private List _genePool; private IGH_Param _modelMesh; public List Objectives; public List Sliders; @@ -51,6 +54,7 @@ private bool SetInputs() private bool SetVariables() { Sliders = new List(); + _genePool = new List(); foreach (IGH_Param source in _component.Params.Input[0].Sources) { @@ -63,24 +67,29 @@ private bool SetVariables() return false; } - foreach (Guid guid in _inputGuids) + foreach (IGH_DocumentObject input in _inputGuids.Select(guid => _document.FindObject(guid, true))) { - IGH_DocumentObject input = _document.FindObject(guid, true); - - if (input is GH_NumberSlider slider) + switch (input) { - Sliders.Add(slider); + case GH_NumberSlider slider: + Sliders.Add(slider); + break; + case GalapagosGeneListObject genePool: + _genePool.Add(genePool); + break; } } - SetSliderValues(); + var variables = new List(); + SetInputSliderValues(variables); + SetInputGenePoolValues(variables); + Variables = variables; return true; } - private void SetSliderValues() + private void SetInputSliderValues(ICollection variables) { int i = 0; - var variables = new List(); foreach (GH_NumberSlider slider in Sliders) { @@ -122,10 +131,27 @@ private void SetSliderValues() variables.Add(new Variable(lowerBond, upperBond, isInteger, nickName)); } + } - Variables = variables; + private void SetInputGenePoolValues(ICollection variables) + { + int count = 0; + + foreach (GalapagosGeneListObject genePool in _genePool) + { + bool isInteger = genePool.Decimals == 0; + decimal lowerBond = genePool.Minimum; + decimal upperBond = genePool.Maximum; + + for (int j = 0; j < genePool.Count; j++) + { + string nickName = "genepool" + count++; + variables.Add(new Variable(lowerBond, upperBond, isInteger, nickName)); + } + } } + private bool SetObjectives() { if (_component.Params.Input[1].SourceCount == 0) @@ -183,9 +209,23 @@ private bool SetSliderValues(IList parameters) slider.Slider.RaiseEvents = true; } + foreach (GalapagosGeneListObject genePool in _genePool) + { + for (int j = 0; j < genePool.Count; j++) + { + genePool.set_NormalisedValue(j, GetNormalisedGenePoolValue(parameters[i++], genePool)); + genePool.ExpireSolution(false); + } + } + return true; } + private decimal GetNormalisedGenePoolValue(decimal unnormalized, GalapagosGeneListObject genePool) + { + return (unnormalized - genePool.Minimum) / (genePool.Maximum - genePool.Minimum); + } + private void Recalculate() { while (_document.SolutionState != GH_ProcessStep.PreProcess || _document.SolutionDepth != 0) { } From 87ca38e81325c869d8c859de500e7e9a0159901f Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 12:50:02 +0900 Subject: [PATCH 08/18] Update editorconfig to apply var setting --- .editorconfig | 6 +++--- Tunny/Component/TunnyAttributes.cs | 6 +++--- Tunny/Optimization/OptimizeLoop.cs | 6 +++--- Tunny/Optimization/RestoreLoop.cs | 2 +- Tunny/Solver/Optuna.cs | 20 ++++++++++---------- Tunny/Solver/OptunaAlgorithm.cs | 10 +++++----- Tunny/UI/MessageBox.cs | 2 +- Tunny/UI/OptimizationWindow.cs | 4 ++-- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.editorconfig b/.editorconfig index b5f39e6a..ea7e95b2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/Tunny/Component/TunnyAttributes.cs b/Tunny/Component/TunnyAttributes.cs index 0eb7e963..640c75c4 100644 --- a/Tunny/Component/TunnyAttributes.cs +++ b/Tunny/Component/TunnyAttributes.cs @@ -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; @@ -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; @@ -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; diff --git a/Tunny/Optimization/OptimizeLoop.cs b/Tunny/Optimization/OptimizeLoop.cs index f72879f7..18ddbfc8 100644 --- a/Tunny/Optimization/OptimizeLoop.cs +++ b/Tunny/Optimization/OptimizeLoop.cs @@ -29,7 +29,7 @@ internal static void RunMultiple(object sender, DoWorkEventArgs e) s_component.GhInOutInstantiate(); double[] result = RunOptimizationLoop(s_worker); - List 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); @@ -53,7 +53,7 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker) } var optunaSolver = new Optuna(s_component.GhInOut.ComponentFolder); - Dictionary settings = new Dictionary() + var settings = new Dictionary() { { "nTrials", NTrials }, { "loadIfExists", LoadIfExists }, @@ -69,7 +69,7 @@ private static double[] RunOptimizationLoop(BackgroundWorker worker) return solverStarted ? optunaSolver.XOpt : new[] { double.NaN }; } - public static EvaluatedGHResult EvaluateFunction(IList values, int progress) + private static EvaluatedGHResult EvaluateFunction(IList values, int progress) { s_component.OptimizationWindow.GrasshopperStatus = OptimizationWindow.GrasshopperStates.RequestSent; diff --git a/Tunny/Optimization/RestoreLoop.cs b/Tunny/Optimization/RestoreLoop.cs index 74dec9f0..43ccc892 100644 --- a/Tunny/Optimization/RestoreLoop.cs +++ b/Tunny/Optimization/RestoreLoop.cs @@ -65,7 +65,7 @@ private static void SetVariables(GH_Structure objectives, ModelResult { foreach (string name in nickName) { - foreach (var obj in model.Variables.Where(obj => obj.Key == name)) + foreach (KeyValuePair obj in model.Variables.Where(obj => obj.Key == name)) { objectives.Append(new GH_Number(obj.Value), new GH_Path(0, model.Number)); } diff --git a/Tunny/Solver/Optuna.cs b/Tunny/Solver/Optuna.cs index 70ea5369..4ebbc80c 100644 --- a/Tunny/Solver/Optuna.cs +++ b/Tunny/Solver/Optuna.cs @@ -36,13 +36,13 @@ public bool RunSolver( Dictionary settings, string installFolder, string documentPath) { int dVar = variables.Count; - var lb = new double[dVar]; - var ub = new double[dVar]; - var integer = new bool[dVar]; - var varNickName = new string[dVar]; + double[] lb = new double[dVar]; + double[] ub = new double[dVar]; + bool[] integer = new bool[dVar]; + string[] varNickName = new string[dVar]; string[] objNickName = objectives.Select(x => x.NickName).ToArray(); - for (var i = 0; i < dVar; i++) + for (int i = 0; i < dVar; i++) { lb[i] = Convert.ToDouble(variables[i].LowerBond); ub[i] = Convert.ToDouble(variables[i].UpperBond); @@ -52,7 +52,7 @@ public bool RunSolver( EvaluatedGHResult Eval(double[] x, int progress) { - List decimals = x.Select(Convert.ToDecimal).ToList(); + var decimals = x.Select(Convert.ToDecimal).ToList(); return evaluate(decimals, progress); } @@ -181,7 +181,7 @@ public ModelResult[] GetModelResult(int[] resultNum, string studyName) } else { - for (var i = 0; i < resultNum.Length; i++) + for (int i = 0; i < resultNum.Length; i++) { dynamic trial = study.trials[resultNum[i]]; ParseTrial(modelResult, trial); @@ -195,10 +195,10 @@ public ModelResult[] GetModelResult(int[] resultNum, string studyName) private static void ParseTrial(ICollection modelResult, dynamic trial) { - var values = (double[])trial.@params.values(); - var keys = (string[])trial.@params.keys(); + double[] values = (double[])trial.@params.values(); + string[] keys = (string[])trial.@params.keys(); var variables = new Dictionary(); - for (var i = 0; i < keys.Length; i++) + for (int i = 0; i < keys.Length; i++) { variables.Add(keys[i], values[i]); } diff --git a/Tunny/Solver/OptunaAlgorithm.cs b/Tunny/Solver/OptunaAlgorithm.cs index 0a7383d2..f4a2e461 100644 --- a/Tunny/Solver/OptunaAlgorithm.cs +++ b/Tunny/Solver/OptunaAlgorithm.cs @@ -78,14 +78,14 @@ public void Solve() ); var name = new StringBuilder(); - foreach (var objName in ObjNickName) + foreach (string objName in ObjNickName) { name.Append(objName + ","); } name.Remove(name.Length - 1, 1); study.set_user_attr("objective_names", name.ToString()); - var xTest = new double[n]; + double[] xTest = new double[n]; var result = new EvaluatedGHResult(); for (int i = 0; i < nTrials; i++) { @@ -121,9 +121,9 @@ public void Solve() if (nObjective == 1) { - var values = (double[])study.best_params.values(); - var keys = (string[])study.best_params.keys(); - var opt = new double[VarNickName.Length]; + double[] values = (double[])study.best_params.values(); + string[] keys = (string[])study.best_params.keys(); + double[] opt = new double[VarNickName.Length]; for (int i = 0; i < VarNickName.Length; i++) { diff --git a/Tunny/UI/MessageBox.cs b/Tunny/UI/MessageBox.cs index 10ebc481..0d80d948 100644 --- a/Tunny/UI/MessageBox.cs +++ b/Tunny/UI/MessageBox.cs @@ -6,7 +6,7 @@ class TunnyMessageBox { public static void Show(string message, string caption, MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information) { - using (Form f = new Form()) + using (var f = new Form()) { f.Owner = Grasshopper.Instances.DocumentEditor; f.TopMost = true; diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index c3270dc7..f89ac6a5 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -124,7 +124,7 @@ private void RestoreProgressChangedHandler(object sender, ProgressChangedEventAr private void OptimizeRunButton_Click(object sender, EventArgs e) { - GH_DocumentEditor ghCanvas = Owner as GH_DocumentEditor; + var ghCanvas = Owner as GH_DocumentEditor; ghCanvas.DisableUI(); optimizeRunButton.Enabled = false; @@ -133,7 +133,7 @@ private void OptimizeRunButton_Click(object sender, EventArgs e) OptimizeLoop.SamplerType = samplerComboBox.Text; OptimizeLoop.StudyName = studyNameTextBox.Text; - var objectiveValues = _component.GhInOut.GetObjectiveValues(); + List objectiveValues = _component.GhInOut.GetObjectiveValues(); if (objectiveValues.Count == 0) { ghCanvas.EnableUI(); From 5d6d429267a48d15ce6d494b2329a344e3a3c0e9 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 12:52:47 +0900 Subject: [PATCH 09/18] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e383b244..f2b7d2b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,13 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release ### Added - Restore progressbar +- Support Galapagos genepool input ### Changed - Restore feature was made asynchronous. - Visualize graph axis name now use input objective's nickname. +- Update supported Rhino version to 7.13. ### Fixed From 649e868f03d30ef6eab9ca33e0f36f4d457a8038 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 13:25:40 +0900 Subject: [PATCH 10/18] Fix genepool result restore --- Tunny/UI/OptimizationWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index f89ac6a5..628b13a6 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -98,7 +98,7 @@ private void RestoreRunButton_Click(object sender, EventArgs e) optimizeStopButton.Enabled = true; RestoreLoop.StudyName = studyNameTextBox.Text; - RestoreLoop.NickNames = _component.GhInOut.Sliders.Select(x => x.NickName).ToArray(); + RestoreLoop.NickNames = _component.GhInOut.Variables.Select(x => x.NickName).ToArray(); RestoreLoop.Indices = restoreModelNumTextBox.Text.Split(',').Select(int.Parse).ToArray(); restoreBackgroundWorker.RunWorkerAsync(_component); From f6ddddcbd2708c4edb933f3f107b2a6aec840351 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 14:12:29 +0900 Subject: [PATCH 11/18] Add feature reflecting MO restult to GH --- Tunny/Optimization/RestoreLoop.cs | 32 +++++++++++++--- Tunny/UI/OptimizationWindow.Designer.cs | 51 ++++++++++++++++--------- Tunny/UI/OptimizationWindow.cs | 27 ++++++++++++- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/Tunny/Optimization/RestoreLoop.cs b/Tunny/Optimization/RestoreLoop.cs index 43ccc892..85ed0e2b 100644 --- a/Tunny/Optimization/RestoreLoop.cs +++ b/Tunny/Optimization/RestoreLoop.cs @@ -24,6 +24,7 @@ internal static class RestoreLoop public static string StudyName; public static string[] NickNames; public static int[] Indices; + public static string Mode; internal static void Run(object sender, DoWorkEventArgs e) { @@ -42,13 +43,34 @@ internal static void Run(object sender, DoWorkEventArgs e) return; } - for (int i = 0; i < modelResult.Length; i++) + switch (Mode) { - SetVariables(variables, modelResult[i], NickNames); - SetObjectives(objectives, modelResult[i]); - SetModelMesh(modelMesh, modelResult[i]); - s_worker.ReportProgress(i * 100 / modelResult.Length); + 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; diff --git a/Tunny/UI/OptimizationWindow.Designer.cs b/Tunny/UI/OptimizationWindow.Designer.cs index 8d932dce..8f2bcabc 100644 --- a/Tunny/UI/OptimizationWindow.Designer.cs +++ b/Tunny/UI/OptimizationWindow.Designer.cs @@ -44,6 +44,7 @@ private void InitializeComponent() this.optimizeTabControl = new System.Windows.Forms.TabControl(); this.optimizeTabPage = new System.Windows.Forms.TabPage(); this.resultTabPage = new System.Windows.Forms.TabPage(); + this.restoreStopButton = new System.Windows.Forms.Button(); this.restoreProgressBar = new System.Windows.Forms.ProgressBar(); this.restoreRunButton = new System.Windows.Forms.Button(); this.restoreModelNumTextBox = new System.Windows.Forms.TextBox(); @@ -54,7 +55,7 @@ private void InitializeComponent() this.visualizeTypeLabel = new System.Windows.Forms.Label(); this.visualizeTypeComboBox = new System.Windows.Forms.ComboBox(); this.restoreBackgroundWorker = new System.ComponentModel.BackgroundWorker(); - this.restoreStopButton = new System.Windows.Forms.Button(); + this.restoreReflectButton = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.nTrialNumUpDown)).BeginInit(); this.optimizeTabControl.SuspendLayout(); this.optimizeTabPage.SuspendLayout(); @@ -127,10 +128,10 @@ private void InitializeComponent() // // optimizeProgressBar // - this.optimizeProgressBar.Location = new System.Drawing.Point(13, 204); + this.optimizeProgressBar.Location = new System.Drawing.Point(13, 205); this.optimizeProgressBar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.optimizeProgressBar.Name = "optimizeProgressBar"; - this.optimizeProgressBar.Size = new System.Drawing.Size(227, 29); + this.optimizeProgressBar.Size = new System.Drawing.Size(227, 28); this.optimizeProgressBar.TabIndex = 6; // // samplerComboBox @@ -208,6 +209,7 @@ private void InitializeComponent() // // resultTabPage // + this.resultTabPage.Controls.Add(this.restoreReflectButton); this.resultTabPage.Controls.Add(this.restoreStopButton); this.resultTabPage.Controls.Add(this.restoreProgressBar); this.resultTabPage.Controls.Add(this.restoreRunButton); @@ -227,19 +229,30 @@ private void InitializeComponent() this.resultTabPage.Text = "Result"; this.resultTabPage.UseVisualStyleBackColor = true; // + // restoreStopButton + // + this.restoreStopButton.Enabled = false; + this.restoreStopButton.Location = new System.Drawing.Point(96, 177); + this.restoreStopButton.Name = "restoreStopButton"; + this.restoreStopButton.Size = new System.Drawing.Size(50, 23); + this.restoreStopButton.TabIndex = 9; + this.restoreStopButton.Text = "Stop"; + this.restoreStopButton.UseVisualStyleBackColor = true; + this.restoreStopButton.Click += new System.EventHandler(this.RestoreStopButton_Click); + // // restoreProgressBar // - this.restoreProgressBar.Location = new System.Drawing.Point(17, 205); + this.restoreProgressBar.Location = new System.Drawing.Point(9, 207); this.restoreProgressBar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.restoreProgressBar.Name = "restoreProgressBar"; - this.restoreProgressBar.Size = new System.Drawing.Size(227, 29); + this.restoreProgressBar.Size = new System.Drawing.Size(235, 27); this.restoreProgressBar.TabIndex = 8; // // restoreRunButton // - this.restoreRunButton.Location = new System.Drawing.Point(111, 172); + this.restoreRunButton.Location = new System.Drawing.Point(21, 177); this.restoreRunButton.Name = "restoreRunButton"; - this.restoreRunButton.Size = new System.Drawing.Size(75, 23); + this.restoreRunButton.Size = new System.Drawing.Size(69, 23); this.restoreRunButton.TabIndex = 7; this.restoreRunButton.Text = "Restore"; this.restoreRunButton.UseVisualStyleBackColor = true; @@ -247,16 +260,16 @@ private void InitializeComponent() // // restoreModelNumTextBox // - this.restoreModelNumTextBox.Location = new System.Drawing.Point(17, 172); + this.restoreModelNumTextBox.Location = new System.Drawing.Point(9, 148); this.restoreModelNumTextBox.Name = "restoreModelNumTextBox"; - this.restoreModelNumTextBox.Size = new System.Drawing.Size(88, 23); + this.restoreModelNumTextBox.Size = new System.Drawing.Size(172, 23); this.restoreModelNumTextBox.TabIndex = 6; this.restoreModelNumTextBox.Text = "-1"; // // restoreModelLabel // this.restoreModelLabel.AutoSize = true; - this.restoreModelLabel.Location = new System.Drawing.Point(6, 146); + this.restoreModelLabel.Location = new System.Drawing.Point(3, 130); this.restoreModelLabel.Name = "restoreModelLabel"; this.restoreModelLabel.Size = new System.Drawing.Size(162, 15); this.restoreModelLabel.TabIndex = 5; @@ -322,16 +335,15 @@ private void InitializeComponent() this.visualizeTypeComboBox.Size = new System.Drawing.Size(175, 23); this.visualizeTypeComboBox.TabIndex = 0; // - // restoreStopButton + // restoreReflectButton // - this.restoreStopButton.Enabled = false; - this.restoreStopButton.Location = new System.Drawing.Point(194, 172); - this.restoreStopButton.Name = "restoreStopButton"; - this.restoreStopButton.Size = new System.Drawing.Size(50, 23); - this.restoreStopButton.TabIndex = 9; - this.restoreStopButton.Text = "Stop"; - this.restoreStopButton.UseVisualStyleBackColor = true; - this.restoreStopButton.Click += new System.EventHandler(this.RestoreStopButton_Click); + this.restoreReflectButton.Location = new System.Drawing.Point(152, 177); + this.restoreReflectButton.Name = "restoreReflectButton"; + this.restoreReflectButton.Size = new System.Drawing.Size(62, 23); + this.restoreReflectButton.TabIndex = 10; + this.restoreReflectButton.Text = "Reflect"; + this.restoreReflectButton.UseVisualStyleBackColor = true; + this.restoreReflectButton.Click += new System.EventHandler(this.RestoreReflectButton_Click); // // OptimizationWindow // @@ -383,6 +395,7 @@ private void InitializeComponent() private System.Windows.Forms.ProgressBar restoreProgressBar; private System.ComponentModel.BackgroundWorker restoreBackgroundWorker; private System.Windows.Forms.Button restoreStopButton; + private System.Windows.Forms.Button restoreReflectButton; } } diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index 628b13a6..e7af4997 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -98,6 +98,7 @@ private void RestoreRunButton_Click(object sender, EventArgs e) optimizeStopButton.Enabled = true; RestoreLoop.StudyName = studyNameTextBox.Text; + RestoreLoop.Mode = "Restore"; RestoreLoop.NickNames = _component.GhInOut.Variables.Select(x => x.NickName).ToArray(); RestoreLoop.Indices = restoreModelNumTextBox.Text.Split(',').Select(int.Parse).ToArray(); @@ -113,7 +114,31 @@ private void RestoreStopButton_Click(object sender, EventArgs e) { restoreBackgroundWorker.CancelAsync(); } - _component.ExpireSolution(true); + switch (RestoreLoop.Mode) + { + case "Restore": + _component.ExpireSolution(true); + break; + case "Reflect": + var decimalVar = _component.Variables.FlattenData() + .Select(x => (decimal)x.Value).ToList(); + _component.GhInOut.NewSolution(decimalVar); + break; + } + } + + private void RestoreReflectButton_Click(object sender, EventArgs e) + { + optimizeRunButton.Enabled = false; + optimizeStopButton.Enabled = true; + + RestoreLoop.StudyName = studyNameTextBox.Text; + RestoreLoop.Mode = "Reflect"; + RestoreLoop.NickNames = _component.GhInOut.Variables.Select(x => x.NickName).ToArray(); + RestoreLoop.Indices = restoreModelNumTextBox.Text.Split(',').Select(int.Parse).ToArray(); + + restoreBackgroundWorker.RunWorkerAsync(_component); + } private void RestoreProgressChangedHandler(object sender, ProgressChangedEventArgs e) From 540d80fb83b5e4cf219ae265d5e246b149c9f8a0 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sat, 30 Apr 2022 14:17:26 +0900 Subject: [PATCH 12/18] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2b7d2b7..e45a4d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release - Restore progressbar - Support Galapagos genepool input +- 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. ### Changed From 14a8c0b8e3a894b9cda893af17ec23b0d7b08047 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sun, 1 May 2022 13:15:44 +0900 Subject: [PATCH 13/18] Fix UI broken in Hi-DPI --- Tunny/Resources/app.manifest | 76 +++++++++++++++++++++++++ Tunny/Tunny.csproj | 4 +- Tunny/UI/OptimizationWindow.Designer.cs | 26 ++++----- Tunny/UI/OptimizationWindow.cs | 3 + 4 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 Tunny/Resources/app.manifest diff --git a/Tunny/Resources/app.manifest b/Tunny/Resources/app.manifest new file mode 100644 index 00000000..ec3b6c69 --- /dev/null +++ b/Tunny/Resources/app.manifest @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + diff --git a/Tunny/Tunny.csproj b/Tunny/Tunny.csproj index 90e2e345..68a24635 100644 --- a/Tunny/Tunny.csproj +++ b/Tunny/Tunny.csproj @@ -9,7 +9,9 @@ hrntsm true Tunny - false + true + Resources\TunnyIcon.ico + diff --git a/Tunny/UI/OptimizationWindow.Designer.cs b/Tunny/UI/OptimizationWindow.Designer.cs index 8f2bcabc..6d4776d1 100644 --- a/Tunny/UI/OptimizationWindow.Designer.cs +++ b/Tunny/UI/OptimizationWindow.Designer.cs @@ -44,6 +44,7 @@ private void InitializeComponent() this.optimizeTabControl = new System.Windows.Forms.TabControl(); this.optimizeTabPage = new System.Windows.Forms.TabPage(); this.resultTabPage = new System.Windows.Forms.TabPage(); + this.restoreReflectButton = new System.Windows.Forms.Button(); this.restoreStopButton = new System.Windows.Forms.Button(); this.restoreProgressBar = new System.Windows.Forms.ProgressBar(); this.restoreRunButton = new System.Windows.Forms.Button(); @@ -55,7 +56,6 @@ private void InitializeComponent() this.visualizeTypeLabel = new System.Windows.Forms.Label(); this.visualizeTypeComboBox = new System.Windows.Forms.ComboBox(); this.restoreBackgroundWorker = new System.ComponentModel.BackgroundWorker(); - this.restoreReflectButton = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.nTrialNumUpDown)).BeginInit(); this.optimizeTabControl.SuspendLayout(); this.optimizeTabPage.SuspendLayout(); @@ -229,6 +229,16 @@ private void InitializeComponent() this.resultTabPage.Text = "Result"; this.resultTabPage.UseVisualStyleBackColor = true; // + // restoreReflectButton + // + this.restoreReflectButton.Location = new System.Drawing.Point(152, 177); + this.restoreReflectButton.Name = "restoreReflectButton"; + this.restoreReflectButton.Size = new System.Drawing.Size(62, 23); + this.restoreReflectButton.TabIndex = 10; + this.restoreReflectButton.Text = "Reflect"; + this.restoreReflectButton.UseVisualStyleBackColor = true; + this.restoreReflectButton.Click += new System.EventHandler(this.RestoreReflectButton_Click); + // // restoreStopButton // this.restoreStopButton.Enabled = false; @@ -335,20 +345,10 @@ private void InitializeComponent() this.visualizeTypeComboBox.Size = new System.Drawing.Size(175, 23); this.visualizeTypeComboBox.TabIndex = 0; // - // restoreReflectButton - // - this.restoreReflectButton.Location = new System.Drawing.Point(152, 177); - this.restoreReflectButton.Name = "restoreReflectButton"; - this.restoreReflectButton.Size = new System.Drawing.Size(62, 23); - this.restoreReflectButton.TabIndex = 10; - this.restoreReflectButton.Text = "Reflect"; - this.restoreReflectButton.UseVisualStyleBackColor = true; - this.restoreReflectButton.Click += new System.EventHandler(this.RestoreReflectButton_Click); - // // OptimizationWindow // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(285, 298); this.Controls.Add(this.optimizeTabControl); this.Font = new System.Drawing.Font("Meiryo UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128))); diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index e7af4997..b9b79469 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -58,6 +58,9 @@ private void UpdateGrasshopper(IList parameters) private void OptimizationWindow_Load(object sender, EventArgs e) { + FormBorderStyle = FormBorderStyle.FixedSingle; + MaximizeBox = false; + MinimizeBox = false; } private void VisualizeButton_Click(object sender, EventArgs e) From 56425375fb7106135ddf6781f81ef7454d912b49 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sun, 1 May 2022 13:28:29 +0900 Subject: [PATCH 14/18] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e45a4d38..0c9aa062 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release - 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 @@ -29,6 +30,8 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release - 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 From 0eac7ca1a921a25c2e51b179768ad35ce63d4cd1 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sun, 1 May 2022 22:52:08 +0900 Subject: [PATCH 15/18] Add grid sampler --- Tunny/Solver/OptunaAlgorithm.cs | 23 ++++++++++++++++++++++- Tunny/UI/OptimizationWindow.Designer.cs | 3 ++- Tunny/UI/OptimizationWindow.cs | 10 ++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Tunny/Solver/OptunaAlgorithm.cs b/Tunny/Solver/OptunaAlgorithm.cs index f4a2e461..842ed39c 100644 --- a/Tunny/Solver/OptunaAlgorithm.cs +++ b/Tunny/Solver/OptunaAlgorithm.cs @@ -64,6 +64,20 @@ public void Solve() case "NSGA-II": sampler = optuna.samplers.NSGAIISampler(); break; + case "Grid": + var searchSpace = new Dictionary>(); + for (int i = 0; i < n; i++) + { + var numSpace = new List(); + for (int j = 0; j < nTrials; j++) + { + numSpace.Add(Lb[i] + (Ub[i] - Lb[i]) * j / (nTrials - 1)); + } + searchSpace.Add(VarNickName[i], numSpace); + } + nTrials = (int)Math.Pow(nTrials, n); + sampler = optuna.samplers.GridSampler(searchSpace); + break; default: sampler = optuna.samplers.TPESampler(); break; @@ -116,7 +130,14 @@ public void Solve() } } trial.set_user_attr("geometry", result.ModelDraco); - study.tell(trial, result.ObjectiveValues.ToArray()); + try + { + study.tell(trial, result.ObjectiveValues.ToArray()); + } + catch + { + break; + } } if (nObjective == 1) diff --git a/Tunny/UI/OptimizationWindow.Designer.cs b/Tunny/UI/OptimizationWindow.Designer.cs index 6d4776d1..86523355 100644 --- a/Tunny/UI/OptimizationWindow.Designer.cs +++ b/Tunny/UI/OptimizationWindow.Designer.cs @@ -141,7 +141,8 @@ private void InitializeComponent() "TPE", "NSGA-II", "CMA-ES", - "Random"}); + "Random", + "Grid"}); this.samplerComboBox.Location = new System.Drawing.Point(99, 8); this.samplerComboBox.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.samplerComboBox.Name = "samplerComboBox"; diff --git a/Tunny/UI/OptimizationWindow.cs b/Tunny/UI/OptimizationWindow.cs index b9b79469..305a84e6 100644 --- a/Tunny/UI/OptimizationWindow.cs +++ b/Tunny/UI/OptimizationWindow.cs @@ -168,9 +168,15 @@ private void OptimizeRunButton_Click(object sender, EventArgs e) optimizeRunButton.Enabled = true; return; } - else if (objectiveValues.Count > 1 && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random")) + else if (objectiveValues.Count > 1 + && (samplerComboBox.Text == "CMA-ES" || samplerComboBox.Text == "Random" || samplerComboBox.Text == "Grid")) { - MessageBox.Show("This sampler does not support multiple objectives optimization.", "Tunny", MessageBoxButtons.OK, MessageBoxIcon.Error); + TunnyMessageBox.Show( + "CMA-ES, Random and Grid samplers only support single objective optimization.", + "Tunny", + MessageBoxButtons.OK, + MessageBoxIcon.Error + ); ghCanvas.EnableUI(); optimizeRunButton.Enabled = true; return; From 28b909e6ed20177ba99563c4be7d99362cfad739 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Sun, 1 May 2022 22:54:08 +0900 Subject: [PATCH 16/18] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c9aa062..5e705048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,10 @@ Please see [here](https://github.com/hrntsm/Tunny/releases) for the data release - Restore progressbar - Support Galapagos genepool input -- Reflect button +- 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 From 6070379b2e79981ed63b6e966be19eca892c9425 Mon Sep 17 00:00:00 2001 From: hrntsm Date: Mon, 2 May 2022 14:01:56 +0900 Subject: [PATCH 17/18] Update sample.gh --- Sample/sample.gh | Bin 12630 -> 13498 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Sample/sample.gh b/Sample/sample.gh index 668ab4640fcd5c4a693b8cf9362c1ffb462da990..9e8af3f9a9b4ca5f89df2ffc6c889893e0b5858b 100644 GIT binary patch literal 13498 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 literal 12630 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 Date: Mon, 2 May 2022 14:02:34 +0900 Subject: [PATCH 18/18] Update Version related files --- CHANGELOG.md | 2 +- README.md | 24 ++++++++++++++---------- Tunny/Tunny.csproj | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e705048..6372b9e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ 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. -## [UNRELEASED] +## [0.2.0] -2022-05-02 ### Added diff --git a/README.md b/README.md index 733c18c8..183b65ea 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -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 @@ -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. @@ -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 diff --git a/Tunny/Tunny.csproj b/Tunny/Tunny.csproj index 68a24635..2a825658 100644 --- a/Tunny/Tunny.csproj +++ b/Tunny/Tunny.csproj @@ -2,7 +2,7 @@ net48 - 0.1.1 + 0.2.0 Tunny Tunny is an optimization component wrapped in optuna. .gha