Skip to content

Commit

Permalink
Progresively interactive NSGA-II (#634)
Browse files Browse the repository at this point in the history
* Development environment set up with pytest

* Adding dummy functions that mock up the I/O of value functions

* Passing smoke test for problem constructor

* Have the solutions (P) being sorted by ranking

* Now also testing whether the P in the result are sorted properly

* Added test for the objective function

* Trying to standardize P versus F

* Adding the value fucnction to the optimization constructors

* Have the inequality constraint basically working (- some rounding err)

* Fixed the false negative test

* Fixing false negative test in the objective function

* Have a basic equality test and implementation in place

* Successfully ran an optimization smoke test, though the values look bad

* Have first step of a plotter working

* Have a contour graph working... which isn't want I wanted to do at all

* Have the contour lines lined up with P!

* Experimenting with different SOO optimization techniques

* Pulling the objective function out of the _evaluate function

* Made a test for the independent objective function, plus opt smoke test

* Pulled the equality constraint function into a stand alone function

* Pulled the inequality constraints out of the _evaluate func

* Finished basic 1D array compatibility

* Have a smoke test for scipy's minimize working

* Successfully tested the scipy solver methods!

* Refactoring a few things

* More refactoring

* Making the value function plotter generic

* Utter mess

* Rooted out that nasty problem with P's dimensionality

* Changed vf for the value function library to mvf to avoid confusion

* Pulling more functionality into the create_vf functions

* Finalizing plotting

* Adding some test data to play with

* have the first veresion of the polynomial value function

* Making skeleton code for creating polynomial VF

* Removing a near duplicate test

* Tidying up testing and vf generation code

* Have the inequality constraint test set up

* Pulled the part of the poly value function that calculates S

* Fixing several compatibility problems

* Got a first version of polynomial inequality constraints working

* Have the 2D version of the poly constraint working

* Have a basic equality constraint working

* Fixing the scipy optimization for polynomial value functions

* Magically rewrote the S calc function after much head scratching

* Have the product calculator working

* Adding some dimensionality tests and squeezing S output

* Fixing (untransposing) the linear value function, and adding +tests

* Fixing errors in the S calculation

* Updating testing data for the new utility function

* Fixing a bug in the inequality constraint calcuation

* I added bounds to the scipy opt, and pymoo optimization for poly vf

* Making the optimization a bit quickier in a lazy way

* Cleaning up the vf tester script

* Making the result of the vf into a more complete result object

* Added a maximization/minimization parameter to vf creation

* Made minimization the default

* Have the first basic version of a comparator working

* Have ZDT1 with the dashboard visualizer set up

* Adding a class for PI-NSGA-II-VF

* Selecting eta most scattered points + plotting

* First swing at the rank prompt

* Have VF optimization tied into the optimization with some crude plots

* Fixing various issues with plotting

* Allowing the user to see the solutions to choose among

* Have the grey trail of previous generations working

* Fixed the plotting scale

* Fixing plotting plus first steps for validation

* Adding a validation function

* Hooked a custom dominator function into pi-nsga-ii

* Pulling the vf dominator out of the pi-nsga-2 code

* Now have the value function parameters hooked into the domination obj

* Have things working... perhaps

* Another max/min bug. (I think it's working!)

* Adding updates from pico

* Forgot to incorporate nds code as well

* Adding a half-working domination graph

* Fixing a bug with the value function dominance

* Forgot some supporting code for the domination plot

* Pairwise Comparison

added argument to pinsga2 to allow the user to pick either absolute or pairwise ranking, and implemented pairwise ranking in _prompt_for_ranks

* Have VF and optimization methods integrated into the optimization

* Updating the VF optimization from min to max

* Adding hessian matrix for trust constraint method

* Moving this to the pymoo example directory

* Tidying up this exmaple code

* Making methods non-static + some variable name tweaks

* fixed flattening bug

now using offset to track rank for equivalent rankings

* Freshing this up a bit

* Removing min/max option

* Threading a delta variable throughout the value function

* Have partial ordering working

* Added some skeleton code for an abstract class

* AutomatedDM + documentation

* Switched to proper ranking type

* Tied rankings working

* Incorporating chagnes to max eps, ranking, and validation

* Fixing the index starting at 1 bug, + adding a final ranking message

* Adding an option for choosing the display sign for prompts

* AutomatedDM + pairwise ranking

can now auto rank by evaluating pairs of solutions instead of all, if wanted

* Fixing yet another failed run falling through the cracks

* Updated testing script

* Cleaning examples and helper code

* Cleaning up temporary code changes

* Fixing an infinite loop bug when no fit can be found

* Have smarter warnings integrated into the algorithm

* Fixing a bug with tau being hard coded

* Polishing documentation

* Removing the work-in-progress dashboard module for now

---------

Co-authored-by: e-spinner <[email protected]>
  • Loading branch information
kroppian and e-spinner authored Aug 25, 2024
1 parent 9a435a8 commit b35626e
Show file tree
Hide file tree
Showing 11 changed files with 2,241 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/source/algorithms/algorithms.csv
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
:ref:`Improved Stochastic Ranking Evolutionary Strategy <nb_isres>`, ISRES, single, x, An improved version of SRES being able to deal dependent variables efficiently.
:ref:`NSGA-II <nb_nsga2>`, NSGA2, multi, x, Well-known multi-objective optimization algorithm based on non-dominated sorting and crowding.
:ref:`R-NSGA-II <nb_rnsga2>`, RNSGA2, multi, x, An extension of NSGA-II where reference/aspiration points can be provided by the user.
:ref:`PI-NSGA-II <nb_pinsga2>`, PINSGA2, multi, x, An interactive version of NSGA-II that uses user preference to guide the optimization towards desired solutions.
:ref:`NSGA-III <nb_nsga3>`, NSGA3, many, x, An improvement of NSGA-II developed for multi-objective optimization problems with more than two objectives.
:ref:`U-NSGA-III <nb_unsga3>`, UNSGA3, many, x, A generalization of NSGA-III to be more efficient for single and bi-objective optimization problems.
:ref:`R-NSGA-III <nb_rnsga3>`, RNSGA3, many, x, Allows defining aspiration points for NSGA-III to incorporate the user's preference.
Expand Down
203 changes: 203 additions & 0 deletions docs/source/algorithms/moo/pinsga2.ipynb

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions docs/source/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -771,3 +771,16 @@ @article{mosade
year={2010},
publisher={Springer}
}



@article{piemovf,
title={An interactive evolutionary multiobjective optimization method based on progressively approximated value functions},
author={Deb, Kalyanmoy and Sinha, Ankur and Korhonen, Pekka J and Wallenius, Jyrki},
journal={IEEE Transactions on Evolutionary Computation},
volume={14},
number={5},
pages={723--739},
year={2010},
publisher={IEEE}
}
90 changes: 90 additions & 0 deletions examples/algorithms/moo/pinsga2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from pymoo.algorithms.moo.pinsga2 import PINSGA2
from pymoo.optimize import minimize
from pymoo.problems.multi import ZDT1
from pymoo.problems.multi import ZDT3
import pymoo.gradient.toolbox as anp
import matplotlib.pyplot as plt
from pymoo.visualization.scatter import Scatter
from pymoo.util import value_functions as mvf


# Additional example from original PI-EMO-VF literature
class ZDT1_max(ZDT1):

def _evaluate(self, x, out, *args, **kwargs):
f1 = x[:, 0]
g = 1 + 9.0 / (self.n_var - 1) * anp.sum(x[:, 1:], axis=1)
f2 = (10 - anp.power((f1 * g), 0.5)) / g

f1 = -1 * f1;
f2 = -1 * f2;

out["F"] = anp.column_stack([f1, f2])



def plot_eta_F(context, algorithm):


# Next highlight the eta selctions
if len(algorithm.eta_F) > 0:

# Plot the historical PO fronts
plot = Scatter().add(algorithm.historical_F, facecolors= '#f5f5f5', edgecolors='#f5f5f5')

# The current PO front
plot.add(algorithm.paused_F)

# Starred items for the DM
plot.add(algorithm.eta_F, s=500, marker='*', facecolors='red')


else:
F = algorithm.pop.get("F")
plot = Scatter().add(F)


plot.plot_if_not_done_yet()

return plot.fig


def plot_vf(context, algorithm):

# This option prevents us from plotting vf every single
if not algorithm.vf_plot_flag and algorithm.vf_plot:
return algorithm.vf_plot

# This option is if a vf has been calculated and we want to plot it
elif len(algorithm.eta_F) > 0 and (algorithm.vf_res is not None) and algorithm.vf_plot_flag:
plot = mvf.plot_vf(algorithm.eta_F * -1, algorithm.vf_res.vf, show=False)

algorithm.vf_plot_flag = False;

algorithm.vf_plot = plot.gcf()

return plot.gcf()

# This option is if we have not calculated a vf and we just want to show the PF
else:
F = algorithm.pop.get("F")

plt.scatter(F[:, 0], F[:, 1], color='blue')

algorithm.vf_plot = plt.gcf()

return algorithm.vf_plot


problem = ZDT3()

# opt_method can be trust-constr, SLSQP, ES, or GA
# vf_type can be linear or poly
algorithm = PINSGA2(pop_size=30, opt_method="trust-constr", vf_type="poly")

res = minimize(problem,
algorithm,
('n_gen', 200),
seed=1,
verbose=True)

70 changes: 70 additions & 0 deletions examples/misc/value_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from pymoo.util import value_functions as mvf
import numpy as np

## Examples from Sinha's code
P = np.array([[3.6, 3.9],
[2.5, 4.1],
[5.5, 2.5],
[0.5, 5.2],
[6.9, 1.8]])
ranks = [1,2,2,3,4]
#ranks = [1,4,3,5,2]

# This is a great example. Illustrates the when polynomial versus linear works
# when the problem is changed from.
# TODO Also doesn't work for scimin minimization. It does that weird thing where
# multiple lines are drawn on the contour
#P = np.array([[1, 5],
# [2, 3],
# [3, 2],
# [4, 1]])
#
#ranks = [3,4,2,1]


#P = np.array([[4, 4],
# [4, 3],
# [2, 4],
# [4, 1],
# [1, 3]]);
#
#ranks = [1,2,3,4,5]


# Partial ordering example
P = np.array([[3.6, 3.9], [2.5, 4.1], [5.5, 2.5], [0.5, 5.2], [6.9, 1.8]])

ranks = [1, 2, 3, 3, 4]

# opt_method can be trust-constr, SLSQP, ES, or GA
opt_method = "trust-constr"

# linear or poly
fnc_type = "poly"


if fnc_type == "linear":

vf_res = mvf.create_linear_vf(P, ranks, method=opt_method)

elif fnc_type == "poly":

vf_res = mvf.create_poly_vf(P, ranks, method=opt_method)

else:

print("function not supported")

if vf_res.fit:

print("Final parameters:")
print(vf_res.params)

print("Final epsilon:")
print(vf_res.epsilon)

mvf.plot_vf(P, vf_res.vf)




Loading

0 comments on commit b35626e

Please sign in to comment.