pymoo 0.6.1.6__cp312-cp312-macosx_10_13_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +110 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +91 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/cmopso.py +239 -0
  14. pymoo/algorithms/moo/ctaea.py +305 -0
  15. pymoo/algorithms/moo/dnsga2.py +80 -0
  16. pymoo/algorithms/moo/kgb.py +450 -0
  17. pymoo/algorithms/moo/moead.py +183 -0
  18. pymoo/algorithms/moo/mopso_cd.py +309 -0
  19. pymoo/algorithms/moo/nsga2.py +113 -0
  20. pymoo/algorithms/moo/nsga3.py +361 -0
  21. pymoo/algorithms/moo/pinsga2.py +370 -0
  22. pymoo/algorithms/moo/rnsga2.py +188 -0
  23. pymoo/algorithms/moo/rnsga3.py +246 -0
  24. pymoo/algorithms/moo/rvea.py +214 -0
  25. pymoo/algorithms/moo/sms.py +196 -0
  26. pymoo/algorithms/moo/spea2.py +191 -0
  27. pymoo/algorithms/moo/unsga3.py +49 -0
  28. pymoo/algorithms/soo/__init__.py +0 -0
  29. pymoo/algorithms/soo/convex/__init__.py +0 -0
  30. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  31. pymoo/algorithms/soo/nonconvex/brkga.py +162 -0
  32. pymoo/algorithms/soo/nonconvex/cmaes.py +556 -0
  33. pymoo/algorithms/soo/nonconvex/de.py +283 -0
  34. pymoo/algorithms/soo/nonconvex/direct.py +148 -0
  35. pymoo/algorithms/soo/nonconvex/es.py +213 -0
  36. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  37. pymoo/algorithms/soo/nonconvex/ga.py +95 -0
  38. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  39. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  40. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  41. pymoo/algorithms/soo/nonconvex/nrbo.py +191 -0
  42. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  43. pymoo/algorithms/soo/nonconvex/pattern.py +185 -0
  44. pymoo/algorithms/soo/nonconvex/pso.py +337 -0
  45. pymoo/algorithms/soo/nonconvex/pso_ep.py +307 -0
  46. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  47. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  48. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  49. pymoo/algorithms/soo/univariate/exp.py +46 -0
  50. pymoo/algorithms/soo/univariate/golden.py +65 -0
  51. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  52. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  53. pymoo/config.py +33 -0
  54. pymoo/constraints/__init__.py +3 -0
  55. pymoo/constraints/adaptive.py +66 -0
  56. pymoo/constraints/as_obj.py +56 -0
  57. pymoo/constraints/as_penalty.py +41 -0
  58. pymoo/constraints/eps.py +34 -0
  59. pymoo/constraints/from_bounds.py +36 -0
  60. pymoo/core/__init__.py +0 -0
  61. pymoo/core/algorithm.py +408 -0
  62. pymoo/core/callback.py +38 -0
  63. pymoo/core/crossover.py +79 -0
  64. pymoo/core/decision_making.py +102 -0
  65. pymoo/core/decomposition.py +76 -0
  66. pymoo/core/duplicate.py +163 -0
  67. pymoo/core/evaluator.py +116 -0
  68. pymoo/core/indicator.py +34 -0
  69. pymoo/core/individual.py +784 -0
  70. pymoo/core/infill.py +65 -0
  71. pymoo/core/initialization.py +44 -0
  72. pymoo/core/mating.py +39 -0
  73. pymoo/core/meta.py +21 -0
  74. pymoo/core/mixed.py +164 -0
  75. pymoo/core/mutation.py +44 -0
  76. pymoo/core/operator.py +46 -0
  77. pymoo/core/parameters.py +134 -0
  78. pymoo/core/plot.py +208 -0
  79. pymoo/core/population.py +180 -0
  80. pymoo/core/problem.py +373 -0
  81. pymoo/core/recorder.py +99 -0
  82. pymoo/core/repair.py +23 -0
  83. pymoo/core/replacement.py +96 -0
  84. pymoo/core/result.py +52 -0
  85. pymoo/core/sampling.py +45 -0
  86. pymoo/core/selection.py +61 -0
  87. pymoo/core/solution.py +10 -0
  88. pymoo/core/survival.py +107 -0
  89. pymoo/core/termination.py +70 -0
  90. pymoo/core/variable.py +415 -0
  91. pymoo/decomposition/__init__.py +0 -0
  92. pymoo/decomposition/aasf.py +24 -0
  93. pymoo/decomposition/asf.py +10 -0
  94. pymoo/decomposition/pbi.py +13 -0
  95. pymoo/decomposition/perp_dist.py +13 -0
  96. pymoo/decomposition/tchebicheff.py +11 -0
  97. pymoo/decomposition/util.py +13 -0
  98. pymoo/decomposition/weighted_sum.py +8 -0
  99. pymoo/docs.py +187 -0
  100. pymoo/experimental/__init__.py +0 -0
  101. pymoo/experimental/algorithms/__init__.py +0 -0
  102. pymoo/experimental/algorithms/gde3.py +57 -0
  103. pymoo/functions/__init__.py +135 -0
  104. pymoo/functions/compiled/__init__.py +0 -0
  105. pymoo/functions/compiled/calc_perpendicular_distance.cpp +27464 -0
  106. pymoo/functions/compiled/calc_perpendicular_distance.cpython-312-darwin.so +0 -0
  107. pymoo/functions/compiled/decomposition.cpp +28853 -0
  108. pymoo/functions/compiled/decomposition.cpython-312-darwin.so +0 -0
  109. pymoo/functions/compiled/info.cpp +7058 -0
  110. pymoo/functions/compiled/info.cpython-312-darwin.so +0 -0
  111. pymoo/functions/compiled/mnn.cpp +30095 -0
  112. pymoo/functions/compiled/mnn.cpython-312-darwin.so +0 -0
  113. pymoo/functions/compiled/non_dominated_sorting.cpp +35692 -0
  114. pymoo/functions/compiled/non_dominated_sorting.cpython-312-darwin.so +0 -0
  115. pymoo/functions/compiled/pruning_cd.cpp +29248 -0
  116. pymoo/functions/compiled/pruning_cd.cpython-312-darwin.so +0 -0
  117. pymoo/functions/compiled/stochastic_ranking.cpp +28042 -0
  118. pymoo/functions/compiled/stochastic_ranking.cpython-312-darwin.so +0 -0
  119. pymoo/functions/standard/__init__.py +1 -0
  120. pymoo/functions/standard/calc_perpendicular_distance.py +20 -0
  121. pymoo/functions/standard/decomposition.py +18 -0
  122. pymoo/functions/standard/hv.py +5 -0
  123. pymoo/functions/standard/mnn.py +78 -0
  124. pymoo/functions/standard/non_dominated_sorting.py +474 -0
  125. pymoo/functions/standard/pruning_cd.py +93 -0
  126. pymoo/functions/standard/stochastic_ranking.py +42 -0
  127. pymoo/gradient/__init__.py +24 -0
  128. pymoo/gradient/automatic.py +85 -0
  129. pymoo/gradient/grad_autograd.py +105 -0
  130. pymoo/gradient/grad_complex.py +35 -0
  131. pymoo/gradient/grad_jax.py +51 -0
  132. pymoo/gradient/numpy.py +22 -0
  133. pymoo/gradient/toolbox/__init__.py +19 -0
  134. pymoo/indicators/__init__.py +0 -0
  135. pymoo/indicators/distance_indicator.py +55 -0
  136. pymoo/indicators/gd.py +7 -0
  137. pymoo/indicators/gd_plus.py +7 -0
  138. pymoo/indicators/hv/__init__.py +59 -0
  139. pymoo/indicators/hv/approximate.py +105 -0
  140. pymoo/indicators/hv/exact.py +68 -0
  141. pymoo/indicators/hv/exact_2d.py +102 -0
  142. pymoo/indicators/igd.py +7 -0
  143. pymoo/indicators/igd_plus.py +7 -0
  144. pymoo/indicators/kktpm.py +151 -0
  145. pymoo/indicators/migd.py +55 -0
  146. pymoo/indicators/rmetric.py +203 -0
  147. pymoo/indicators/spacing.py +52 -0
  148. pymoo/mcdm/__init__.py +0 -0
  149. pymoo/mcdm/compromise_programming.py +19 -0
  150. pymoo/mcdm/high_tradeoff.py +40 -0
  151. pymoo/mcdm/pseudo_weights.py +32 -0
  152. pymoo/operators/__init__.py +0 -0
  153. pymoo/operators/control.py +190 -0
  154. pymoo/operators/crossover/__init__.py +0 -0
  155. pymoo/operators/crossover/binx.py +47 -0
  156. pymoo/operators/crossover/dex.py +125 -0
  157. pymoo/operators/crossover/erx.py +164 -0
  158. pymoo/operators/crossover/expx.py +53 -0
  159. pymoo/operators/crossover/hux.py +37 -0
  160. pymoo/operators/crossover/nox.py +25 -0
  161. pymoo/operators/crossover/ox.py +88 -0
  162. pymoo/operators/crossover/pcx.py +84 -0
  163. pymoo/operators/crossover/pntx.py +49 -0
  164. pymoo/operators/crossover/sbx.py +137 -0
  165. pymoo/operators/crossover/spx.py +5 -0
  166. pymoo/operators/crossover/ux.py +20 -0
  167. pymoo/operators/mutation/__init__.py +0 -0
  168. pymoo/operators/mutation/bitflip.py +17 -0
  169. pymoo/operators/mutation/gauss.py +60 -0
  170. pymoo/operators/mutation/inversion.py +42 -0
  171. pymoo/operators/mutation/nom.py +7 -0
  172. pymoo/operators/mutation/pm.py +96 -0
  173. pymoo/operators/mutation/rm.py +23 -0
  174. pymoo/operators/repair/__init__.py +0 -0
  175. pymoo/operators/repair/bounce_back.py +32 -0
  176. pymoo/operators/repair/bounds_repair.py +97 -0
  177. pymoo/operators/repair/inverse_penalty.py +91 -0
  178. pymoo/operators/repair/rounding.py +18 -0
  179. pymoo/operators/repair/to_bound.py +31 -0
  180. pymoo/operators/repair/vtype.py +11 -0
  181. pymoo/operators/sampling/__init__.py +0 -0
  182. pymoo/operators/sampling/lhs.py +76 -0
  183. pymoo/operators/sampling/rnd.py +52 -0
  184. pymoo/operators/selection/__init__.py +0 -0
  185. pymoo/operators/selection/rnd.py +75 -0
  186. pymoo/operators/selection/tournament.py +78 -0
  187. pymoo/operators/survival/__init__.py +0 -0
  188. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  189. pymoo/operators/survival/rank_and_crowding/classes.py +212 -0
  190. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  191. pymoo/optimize.py +72 -0
  192. pymoo/parallelization/__init__.py +15 -0
  193. pymoo/parallelization/dask.py +25 -0
  194. pymoo/parallelization/joblib.py +28 -0
  195. pymoo/parallelization/ray.py +31 -0
  196. pymoo/parallelization/starmap.py +24 -0
  197. pymoo/problems/__init__.py +157 -0
  198. pymoo/problems/dyn.py +47 -0
  199. pymoo/problems/dynamic/__init__.py +0 -0
  200. pymoo/problems/dynamic/cec2015.py +108 -0
  201. pymoo/problems/dynamic/df.py +451 -0
  202. pymoo/problems/dynamic/misc.py +167 -0
  203. pymoo/problems/functional.py +48 -0
  204. pymoo/problems/many/__init__.py +5 -0
  205. pymoo/problems/many/cdtlz.py +159 -0
  206. pymoo/problems/many/dcdtlz.py +88 -0
  207. pymoo/problems/many/dtlz.py +264 -0
  208. pymoo/problems/many/wfg.py +553 -0
  209. pymoo/problems/multi/__init__.py +14 -0
  210. pymoo/problems/multi/bnh.py +34 -0
  211. pymoo/problems/multi/carside.py +48 -0
  212. pymoo/problems/multi/clutch.py +104 -0
  213. pymoo/problems/multi/csi.py +55 -0
  214. pymoo/problems/multi/ctp.py +198 -0
  215. pymoo/problems/multi/dascmop.py +213 -0
  216. pymoo/problems/multi/kursawe.py +25 -0
  217. pymoo/problems/multi/modact.py +68 -0
  218. pymoo/problems/multi/mw.py +400 -0
  219. pymoo/problems/multi/omnitest.py +48 -0
  220. pymoo/problems/multi/osy.py +32 -0
  221. pymoo/problems/multi/srn.py +28 -0
  222. pymoo/problems/multi/sympart.py +94 -0
  223. pymoo/problems/multi/tnk.py +24 -0
  224. pymoo/problems/multi/truss2d.py +83 -0
  225. pymoo/problems/multi/welded_beam.py +41 -0
  226. pymoo/problems/multi/wrm.py +36 -0
  227. pymoo/problems/multi/zdt.py +151 -0
  228. pymoo/problems/multi_to_single.py +22 -0
  229. pymoo/problems/single/__init__.py +12 -0
  230. pymoo/problems/single/ackley.py +24 -0
  231. pymoo/problems/single/cantilevered_beam.py +34 -0
  232. pymoo/problems/single/flowshop_scheduling.py +113 -0
  233. pymoo/problems/single/g.py +874 -0
  234. pymoo/problems/single/griewank.py +18 -0
  235. pymoo/problems/single/himmelblau.py +15 -0
  236. pymoo/problems/single/knapsack.py +49 -0
  237. pymoo/problems/single/mopta08.py +26 -0
  238. pymoo/problems/single/multimodal.py +20 -0
  239. pymoo/problems/single/pressure_vessel.py +30 -0
  240. pymoo/problems/single/rastrigin.py +20 -0
  241. pymoo/problems/single/rosenbrock.py +22 -0
  242. pymoo/problems/single/schwefel.py +18 -0
  243. pymoo/problems/single/simple.py +13 -0
  244. pymoo/problems/single/sphere.py +19 -0
  245. pymoo/problems/single/traveling_salesman.py +79 -0
  246. pymoo/problems/single/zakharov.py +19 -0
  247. pymoo/problems/static.py +14 -0
  248. pymoo/problems/util.py +42 -0
  249. pymoo/problems/zero_to_one.py +27 -0
  250. pymoo/termination/__init__.py +23 -0
  251. pymoo/termination/collection.py +12 -0
  252. pymoo/termination/cv.py +48 -0
  253. pymoo/termination/default.py +45 -0
  254. pymoo/termination/delta.py +64 -0
  255. pymoo/termination/fmin.py +16 -0
  256. pymoo/termination/ftol.py +144 -0
  257. pymoo/termination/indicator.py +49 -0
  258. pymoo/termination/max_eval.py +14 -0
  259. pymoo/termination/max_gen.py +15 -0
  260. pymoo/termination/max_time.py +20 -0
  261. pymoo/termination/robust.py +34 -0
  262. pymoo/termination/xtol.py +33 -0
  263. pymoo/util/__init__.py +33 -0
  264. pymoo/util/archive.py +152 -0
  265. pymoo/util/cache.py +29 -0
  266. pymoo/util/clearing.py +82 -0
  267. pymoo/util/display/__init__.py +0 -0
  268. pymoo/util/display/column.py +52 -0
  269. pymoo/util/display/display.py +34 -0
  270. pymoo/util/display/multi.py +100 -0
  271. pymoo/util/display/output.py +53 -0
  272. pymoo/util/display/progress.py +54 -0
  273. pymoo/util/display/single.py +67 -0
  274. pymoo/util/dominator.py +67 -0
  275. pymoo/util/hv.py +21 -0
  276. pymoo/util/matlab_engine.py +39 -0
  277. pymoo/util/misc.py +447 -0
  278. pymoo/util/nds/__init__.py +0 -0
  279. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  280. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  281. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  282. pymoo/util/nds/find_non_dominated.py +54 -0
  283. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  284. pymoo/util/nds/non_dominated_sorting.py +94 -0
  285. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  286. pymoo/util/normalization.py +312 -0
  287. pymoo/util/optimum.py +42 -0
  288. pymoo/util/randomized_argsort.py +63 -0
  289. pymoo/util/ref_dirs/__init__.py +24 -0
  290. pymoo/util/ref_dirs/construction.py +89 -0
  291. pymoo/util/ref_dirs/das_dennis.py +52 -0
  292. pymoo/util/ref_dirs/energy.py +317 -0
  293. pymoo/util/ref_dirs/energy_layer.py +119 -0
  294. pymoo/util/ref_dirs/genetic_algorithm.py +64 -0
  295. pymoo/util/ref_dirs/incremental.py +69 -0
  296. pymoo/util/ref_dirs/misc.py +128 -0
  297. pymoo/util/ref_dirs/optimizer.py +59 -0
  298. pymoo/util/ref_dirs/performance.py +162 -0
  299. pymoo/util/ref_dirs/reduction.py +85 -0
  300. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  301. pymoo/util/reference_direction.py +258 -0
  302. pymoo/util/remote.py +55 -0
  303. pymoo/util/roulette.py +29 -0
  304. pymoo/util/running_metric.py +128 -0
  305. pymoo/util/sliding_window.py +25 -0
  306. pymoo/util/value_functions.py +720 -0
  307. pymoo/util/vectors.py +40 -0
  308. pymoo/util/vf_dominator.py +102 -0
  309. pymoo/vendor/__init__.py +0 -0
  310. pymoo/vendor/cec2018.py +398 -0
  311. pymoo/vendor/gta.py +617 -0
  312. pymoo/vendor/vendor_cmaes.py +421 -0
  313. pymoo/vendor/vendor_coco.py +81 -0
  314. pymoo/vendor/vendor_scipy.py +232 -0
  315. pymoo/version.py +1 -0
  316. pymoo/visualization/__init__.py +21 -0
  317. pymoo/visualization/app/__init__.py +0 -0
  318. pymoo/visualization/app/pso.py +61 -0
  319. pymoo/visualization/fitness_landscape.py +128 -0
  320. pymoo/visualization/heatmap.py +123 -0
  321. pymoo/visualization/matplotlib.py +61 -0
  322. pymoo/visualization/pcp.py +121 -0
  323. pymoo/visualization/petal.py +91 -0
  324. pymoo/visualization/radar.py +108 -0
  325. pymoo/visualization/radviz.py +68 -0
  326. pymoo/visualization/scatter.py +150 -0
  327. pymoo/visualization/star_coordinate.py +75 -0
  328. pymoo/visualization/util.py +296 -0
  329. pymoo/visualization/video/__init__.py +0 -0
  330. pymoo/visualization/video/callback_video.py +82 -0
  331. pymoo/visualization/video/one_var_one_obj.py +57 -0
  332. pymoo/visualization/video/two_var_one_obj.py +62 -0
  333. pymoo-0.6.1.6.dist-info/METADATA +209 -0
  334. pymoo-0.6.1.6.dist-info/RECORD +337 -0
  335. pymoo-0.6.1.6.dist-info/WHEEL +6 -0
  336. pymoo-0.6.1.6.dist-info/licenses/LICENSE +191 -0
  337. pymoo-0.6.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,720 @@
1
+ import numpy as np
2
+ import pymoo
3
+ import scipy
4
+ from pymoo.optimize import minimize as moomin
5
+ from scipy.optimize import minimize as scimin
6
+ from scipy.optimize import OptimizeResult
7
+ from pymoo.core.problem import Problem
8
+ import matplotlib.pyplot as plt
9
+ from scipy.optimize import NonlinearConstraint
10
+ from scipy.optimize import Bounds
11
+ from pymoo.algorithms.soo.nonconvex.es import ES
12
+ from pymoo.algorithms.soo.nonconvex.ga import GA
13
+ import math
14
+ from operator import mul
15
+ from functools import reduce
16
+ from pymoo.termination.default import DefaultSingleObjectiveTermination
17
+ import sys
18
+
19
+
20
+ # Input 1: A list of non-dominated points
21
+ # Input 2: The ranking of the given non-dominated points
22
+ # Input 3: constraint function for optimizing the value func
23
+ # Input 4: the skeleton utility function that we're trying to optimize
24
+ def create_vf(P, ranks, ineq_constr, vf="linear", delta=0.1, eps_max=1000, method="trust-constr", verbose=False):
25
+
26
+ if vf == "linear":
27
+ return create_linear_vf(P, ranks, delta, eps_max, method, verbose)
28
+ elif vf == "poly":
29
+ return create_poly_vf(P, ranks, delta, eps_max, method, verbose)
30
+
31
+ else:
32
+ raise ValueError("Value function '%d' not supported." % vf)
33
+
34
+ return lambda f_new: np.sum(f_new)
35
+
36
+ def create_poly_vf(P, ranks, delta=0.1, eps_max=1000, method="trust-constr", verbose=False):
37
+
38
+ if method == "trust-constr" or method == "SLSQP":
39
+ return create_vf_scipy_poly(P, ranks, delta, eps_max, method=method, verbose=verbose)
40
+ elif method == "ES":
41
+ return create_vf_pymoo_poly(P, ranks, delta, eps_max, method=method, verbose=verbose)
42
+ else:
43
+ raise ValueError("Optimization method %s not supported" % method)
44
+
45
+
46
+
47
+ def create_linear_vf(P, ranks, delta=0.1, eps_max=1000, method="trust-constr"):
48
+
49
+ if method == "trust-constr" or method == "SLSQP":
50
+ return create_vf_scipy_linear(P, ranks, delta, eps_max, method)
51
+ elif method == "ES":
52
+ return create_vf_pymoo_linear(P, ranks, delta, eps_max, method)
53
+ else:
54
+ raise ValueError("Optimization method %s not supported" % method)
55
+
56
+
57
+ def create_vf_scipy_poly(P, ranks, delta, eps_max, method="trust-constr", verbose=False):
58
+
59
+ # Gathering basic info
60
+ M = P.shape[1]
61
+
62
+ P_count = P.shape[0]
63
+
64
+ # Inequality constraints - check that each term of S in our obj is non-negative for each P
65
+ ineq_lb = [-np.inf] * (P_count*M)
66
+ ineq_ub = [0] * (P_count*M)
67
+
68
+ # Inequality constraints - check VF is monotonically increasing with user preference
69
+ ineq_lb += [-np.inf] * (P_count - 1)
70
+ ineq_ub += [0] * (P_count - 1)
71
+
72
+
73
+ # Equality constraints (Make sure all terms in VF add up to 1 per term of product)
74
+ for m in range(M):
75
+ ineq_lb.append(0)
76
+ ineq_ub.append(0)
77
+
78
+ P_sorted = _sort_P(P, ranks)
79
+ ranks.sort()
80
+
81
+ constr = NonlinearConstraint(_build_constr_poly(P_sorted, poly_vf, ranks, delta), ineq_lb, ineq_ub)
82
+
83
+ # Bounds on x
84
+ x_lb = []
85
+ x_ub = []
86
+ for m in range(M**2):
87
+ x_lb.append(0)
88
+ x_ub.append(1)
89
+
90
+ for m in range(M):
91
+ x_lb.append(-1000)
92
+ x_ub.append(1000)
93
+
94
+ x_lb.append(-1000)
95
+ x_ub.append(eps_max)
96
+
97
+ bounds = Bounds(x_lb, x_ub)
98
+
99
+ # Initial position
100
+ x0 = [1] * (M**2 + M + 1)
101
+
102
+ if method == 'trust-constr':
103
+ # The trust-constr method always finds the decision space linear
104
+ hess = lambda x: np.zeros((len(x0), len(x0)))
105
+ else:
106
+ hess = None
107
+
108
+ res = scimin(_obj_func,
109
+ x0,
110
+ constraints=constr,
111
+ bounds=bounds,
112
+ method=method,
113
+ hess=hess)
114
+
115
+ # package up results
116
+ vf = lambda P_in: poly_vf(P_in, res.x[0:-1])
117
+ params = res.x[0:-1]
118
+ epsilon = res.x[-1]
119
+
120
+ fit = _validate_vf(res, verbose)
121
+
122
+ return vfResults(vf, params, epsilon, fit)
123
+
124
+
125
+ def create_vf_scipy_linear(P, ranks, delta, eps_max, method="trust-constr", verbose=False):
126
+
127
+ # Gathering basic info
128
+ M = P.shape[1]
129
+
130
+ # Sort P
131
+ P_sorted = _sort_P(P, ranks)
132
+ ranks.sort()
133
+
134
+ # Inequality constraints
135
+ lb = [-np.inf] * (P.shape[0] - 1)
136
+ ub = [0] * (P.shape[0] - 1)
137
+
138
+ # Equality constraints
139
+ lb.append(0)
140
+ ub.append(0)
141
+
142
+ constr = NonlinearConstraint(_build_constr_linear(P_sorted, linear_vf, ranks, delta), lb, ub)
143
+
144
+ # Bounds on x
145
+ x_lb = []
146
+ x_ub = []
147
+
148
+ for m in range(M):
149
+ x_lb.append(0)
150
+ x_ub.append(1)
151
+
152
+ x_lb.append(-1000)
153
+ x_ub.append(eps_max)
154
+
155
+ bounds = Bounds(x_lb, x_ub)
156
+
157
+ # Initial position
158
+ x0 = [0.5] * (M+1)
159
+
160
+ if method == 'trust-constr':
161
+ # The trust-constr method always finds the decision space linear
162
+ hess = lambda x: np.zeros((len(x0), len(x0)))
163
+ else:
164
+ hess = None
165
+
166
+ res = scimin(_obj_func,
167
+ x0,
168
+ constraints= constr,
169
+ bounds=bounds,
170
+ method=method,
171
+ hess=hess)
172
+
173
+ # package up results
174
+ vf = lambda P_in: linear_vf(P_in, res.x[0:-1])
175
+ params = res.x[0:-1]
176
+ epsilon = res.x[-1]
177
+ fit = _validate_vf(res, verbose)
178
+
179
+ return vfResults(vf, params, epsilon, fit)
180
+
181
+ def create_vf_pymoo_linear(P, ranks, delta, eps_max, method="ES", verbose=False):
182
+
183
+ vf_prob = OptimizeLinearVF(P, ranks, delta, eps_max, linear_vf)
184
+
185
+ if method == "ES":
186
+ algorithm = ES()
187
+ elif method == "GA":
188
+ algorithm = GA()
189
+ else:
190
+ raise ValueError("Optimization method %s not supported" % method)
191
+
192
+ res = moomin(vf_prob,
193
+ algorithm,
194
+ ('n_gen', 200),
195
+ verbose=verbose,
196
+ seed=1)
197
+
198
+ vf = lambda P_in: linear_vf(P_in, res.X[0:-1])
199
+
200
+ if res.X is not None:
201
+ params = res.X[0:-1]
202
+ epsilon = res.X[-1]
203
+ else:
204
+ params = None
205
+ epsilon = -1000
206
+
207
+ fit = _validate_vf(res, verbose)
208
+
209
+ return vfResults(vf, params, epsilon, fit)
210
+
211
+
212
+ def create_vf_pymoo_poly(P, ranks, delta, eps_max, method="trust-constr", verbose=False):
213
+
214
+ vf_prob = OptimizePolyVF(P, ranks, delta, eps_max, poly_vf)
215
+
216
+ if method == "ES":
217
+ algorithm = ES()
218
+ elif method == "GA":
219
+ algorithm = GA()
220
+ else:
221
+ raise ValueError("Optimization method %s not supported" % method)
222
+
223
+ res = moomin(vf_prob,
224
+ algorithm,
225
+ ('n_gen', 100),
226
+ verbose=verbose,
227
+ seed=1)
228
+
229
+ vf = lambda P_in: poly_vf(P_in, res.X[0:-1])
230
+
231
+ if res.X is not None:
232
+ params = res.X[0:-1]
233
+ epsilon = res.X[-1]
234
+ else:
235
+ params = None
236
+ epsilon = -1000
237
+
238
+ fit = _validate_vf(res, verbose)
239
+
240
+ return vfResults(vf, params, epsilon, fit)
241
+
242
+
243
+ def linear_vf(P, x):
244
+
245
+ return np.matmul(P, x.T)
246
+
247
+ def poly_vf(P, x):
248
+
249
+ # find out M
250
+ M = P.shape[-1]
251
+
252
+ result = []
253
+
254
+ if len(x.shape) == 1:
255
+ x_len = 1
256
+ else:
257
+ x_len = x.shape[0]
258
+
259
+ # Calculate value for each row of x
260
+ for xi in range(x_len):
261
+
262
+ running_product = 1
263
+
264
+ # Get current x
265
+ if x_len == 1:
266
+ curr_x = x
267
+ else:
268
+ curr_x = x[xi, :]
269
+
270
+ S = _calc_S(P, curr_x)
271
+
272
+ # Multiply all of the S terms together along the final axis
273
+ product = np.prod(S, axis = len(np.shape(S))-1)
274
+
275
+ result.append(product)
276
+
277
+ return np.squeeze(np.array(result))
278
+
279
+
280
+ def plot_vf(P, vf, show=True):
281
+
282
+ plt.scatter(P[:,0], P[:,1], marker=".", color="red", s=200 )
283
+
284
+
285
+ for i in range(np.size(P,0)):
286
+ plt.annotate("P%d" % (i+1), (P[i,0], P[i,1]))
287
+
288
+ min_x = min(P[:,0])
289
+ min_y = min(P[:,1])
290
+ max_x = max(P[:,0])
291
+ max_y = max(P[:,1])
292
+
293
+ x,y = np.meshgrid(np.linspace(min_x, max_x, 1000), np.linspace(min_y, max_y, 1000))
294
+
295
+ z = vf(np.stack((x,y), axis=2))
296
+
297
+ values_at_P = []
298
+ for p in range(np.size(P,0)):
299
+ values_at_P.append(vf(P[p,:]))
300
+
301
+ values_at_P.sort()
302
+
303
+ plt.contour(x,y,z, levels=values_at_P)
304
+
305
+ plt.colorbar()
306
+
307
+ if show:
308
+ plt.show()
309
+
310
+ return plt
311
+
312
+
313
+
314
+ ## ---------------- Polynomial VF creation functions ------------------
315
+
316
+ def _ineq_constr_poly(x, P, vf, ranks, delta):
317
+ if len(x.shape) == 1:
318
+ return _ineq_constr_1D_poly(x, P, vf, ranks, delta)
319
+ else:
320
+ return _ineq_constr_2D_poly(x, P, vf, ranks, delta)
321
+
322
+
323
+ def _build_ineq_constr_poly(P, vf, ranks, delta):
324
+
325
+ ineq_func = lambda x : _ineq_constr_poly(x, P, vf, ranks, delta)
326
+
327
+ return ineq_func
328
+
329
+ def _eq_constr_poly(x):
330
+
331
+ M = math.floor(math.sqrt(6))
332
+
333
+ if len(x.shape) == 1:
334
+ result = []
335
+ for m in range(M):
336
+ result.append(-(sum(x[m*M:m*M+M]) - 1))
337
+
338
+ else:
339
+
340
+ pop_size = np.size(x,0)
341
+
342
+ result = []
343
+
344
+ for xi in range(pop_size):
345
+
346
+ result_for_xi = []
347
+
348
+ for m in range(M):
349
+
350
+ result_for_xi.append(-(sum(x[xi,m*M:m*M+M]) - 1))
351
+
352
+ result.append(result_for_xi)
353
+
354
+ result = np.array(result)
355
+
356
+ return result
357
+
358
+
359
+ def _build_constr_poly(P, vf, ranks, delta):
360
+
361
+ ineq_constr_func = _build_ineq_constr_poly(P, vf, ranks, delta)
362
+
363
+ return lambda x : np.append(ineq_constr_func(x), _eq_constr_poly(x))
364
+
365
+
366
+ def _ineq_constr_2D_poly(x, P, vf, ranks, delta):
367
+
368
+ pop_size = np.size(x,0)
369
+
370
+ P_count = P.shape[0]
371
+ M = P.shape[1]
372
+
373
+ S_constr_len = M * P_count
374
+ increasing_len = P_count - 1
375
+
376
+ G = np.ones((pop_size, S_constr_len + increasing_len))*-99
377
+
378
+ for xi in range(pop_size):
379
+
380
+ G[xi, :] = _ineq_constr_1D_poly(x[xi, :], P, vf, ranks, delta)
381
+
382
+ return G
383
+
384
+
385
+ def _ineq_constr_1D_poly(x, P, vf, ranks, delta):
386
+
387
+ ep = x[-1]
388
+
389
+ P_count = P.shape[0]
390
+ M = P.shape[1]
391
+
392
+ S_constr_len = M * P_count
393
+ increasing_len = P_count - 1
394
+
395
+ G = np.ones((1, S_constr_len + increasing_len))*-99
396
+
397
+ # Checking to make sure each S term in the polynomial objective function is non-negative
398
+ S = _calc_S(P, x[0:-1]) * -1
399
+
400
+ G[:, 0:S_constr_len] = S.reshape(1, S_constr_len)
401
+
402
+
403
+ # Pair-wise compare each ranked member of P, seeing if our proposed utility
404
+ # function increases monotonically as rank increases
405
+ for p in range(P_count - 1):
406
+
407
+ current_P_val = vf(P[[p],:], x[0:-1])
408
+ next_P_val = vf(P[[p+1],:], x[0:-1])
409
+
410
+ current_rank = ranks[p]
411
+ next_rank = ranks[p+1]
412
+
413
+ if current_rank == next_rank:
414
+ # Handle ties
415
+ G[:,[p + S_constr_len]] = np.abs(current_P_val - next_P_val) - delta*ep
416
+ else:
417
+ G[:,[p + S_constr_len]] = -(current_P_val - next_P_val) + ep
418
+
419
+
420
+ return G
421
+
422
+ ## ---------------- Linear VF creation functions ------------------
423
+
424
+ def _build_ineq_constr_linear(P, vf, ranks, delta):
425
+
426
+ ineq_func = lambda x : _ineq_constr_linear(x, P, vf, ranks, delta)
427
+
428
+ return ineq_func
429
+
430
+ def _build_constr_linear(P, vf, ranks, delta):
431
+
432
+ ineq_constr_func = _build_ineq_constr_linear(P, vf, ranks, delta);
433
+
434
+ return lambda x : np.append(ineq_constr_func(x), _eq_constr_linear(x))
435
+
436
+
437
+ def _ineq_constr_linear(x, P, vf, ranks, delta):
438
+ if len(x.shape) == 1:
439
+ return _ineq_constr_1D_linear(x, P, vf, ranks, delta)
440
+ else:
441
+ return _ineq_constr_2D_linear(x, P, vf, ranks, delta)
442
+
443
+
444
+ def _ineq_constr_2D_linear(x, P, vf, ranks, delta):
445
+
446
+ ep = np.column_stack([x[:,-1]])
447
+ pop_size = np.size(x,0)
448
+
449
+ G = np.ones((pop_size, np.size(P,0)-1))*-99
450
+
451
+ # Pair-wise compare each ranked member of P, seeing if our proposed utility
452
+ # function increases monotonically as rank increases
453
+ for p in range(np.size(P,0) - 1):
454
+
455
+
456
+ current_P_val = vf(P[[p],:], x[:, 0:-1])
457
+ next_P = vf(P[[p+1],:], x[:, 0:-1])
458
+
459
+ current_rank = ranks[p]
460
+ next_rank = ranks[p+1]
461
+
462
+
463
+ if current_rank == next_rank:
464
+ # Handle ties
465
+ G[:,[p]] = np.abs(current_P_val.T - next_P.T) - delta*ep
466
+ else:
467
+ # As vf returns, each column is an value of P for a given x in the population
468
+ # We transpose to make each ROW the value of P
469
+ G[:,[p]] = -(current_P_val.T - next_P.T) + ep
470
+
471
+
472
+ return G
473
+
474
+
475
+ def _ineq_constr_1D_linear(x, P, vf, ranks, delta):
476
+
477
+ ep = x[-1]
478
+
479
+ G = np.ones((1, np.size(P,0)-1))*-99
480
+
481
+ # Pair-wise compare each ranked member of P, seeing if our proposed utility
482
+ # function increases monotonically as rank increases
483
+ for p in range(np.size(P,0) - 1):
484
+
485
+ current_P_val = vf(P[[p],:], x[0:-1])
486
+ next_P = vf(P[[p+1],:], x[0:-1])
487
+
488
+ current_rank = ranks[p]
489
+ next_rank = ranks[p+1]
490
+
491
+ if current_rank == next_rank:
492
+ # Handle ties
493
+ G[:,[p]] = np.abs(current_P_val - next_P) - delta*ep
494
+ else:
495
+ G[:,[p]] = -(current_P_val - next_P) + ep
496
+
497
+
498
+
499
+ return G
500
+
501
+ def _obj_func(x):
502
+
503
+ # check if x is a 1D array or a 2D array
504
+ if len(x.shape) == 1:
505
+ ep = x[-1]
506
+ else:
507
+ ep = np.column_stack([x[:,-1]])
508
+
509
+ return -ep
510
+
511
+ def _sort_P(P, ranks):
512
+ P_with_rank = np.hstack((P, np.array([ranks]).T))
513
+
514
+ P_sorted = P[P_with_rank[:, -1].argsort()]
515
+
516
+ return P_sorted
517
+
518
+ # Can have several P instances, but assumes one x instance
519
+ def _calc_S(P, x):
520
+
521
+ M = P.shape[-1]
522
+
523
+ # reshape x into a matrix called k
524
+ k = np.array(x[0:M*M].reshape(M,M), copy=True)
525
+ k = k.T
526
+
527
+ # roll each column down to work with equation 5
528
+ for col in range(1, k.shape[1]):
529
+ k[:,[col]] = np.roll(k[:,[col]], col)
530
+
531
+
532
+ l = x[M*M:(M*M)+M].reshape(M,1)
533
+ l = l.T
534
+
535
+ # Calc S for an arbitrary dimensional space of P
536
+ S = np.matmul(P, k) + (l * 2)
537
+
538
+ return np.squeeze(S)
539
+
540
+
541
+ # Constraint that states that the x values must add up to 1
542
+ def _eq_constr_linear(x):
543
+
544
+ if len(x.shape) == 1:
545
+ eq_cons = sum(x[0:-1]) - 1
546
+ else:
547
+ eq_cons = np.sum(x[:,0:-1],1, keepdims=True) - 1
548
+
549
+ return eq_cons
550
+
551
+
552
+ # Makes a comparator for a given value function and the P that is ranked second in the
553
+ def make_vf_comparator(vf, P_rank_2):
554
+
555
+ return lambda P : vf_comparator(vf, P_rank_2, P)
556
+
557
+ def vf_comparator(vf, P_rank_2, P):
558
+
559
+ reference_value = vf(P_rank_2)
560
+
561
+ if reference_value > vf(P):
562
+ return -1
563
+ elif reference_value < vf(P):
564
+ return 1
565
+ else:
566
+ return 0
567
+
568
+
569
+ class OptimizeLinearVF(Problem):
570
+
571
+ def __init__(self, P, ranks, delta, eps_max, vf):
572
+
573
+ # One var for each dimension of the object space, plus epsilon
574
+ n_var_vf = np.size(P, 1) + 1
575
+
576
+ # it has one inequality constraints for every pair of solutions in P
577
+ n_ieq_c_vf = np.size(P,0) - 1
578
+
579
+ xl_vf = [0.0] * n_var_vf
580
+ xu_vf = [1.0] * n_var_vf
581
+
582
+ # upper/lower bound on the epsilon variable is -1000/1000
583
+ xl_vf[-1] = -1000
584
+ xu_vf[-1] = eps_max
585
+
586
+ # TODO start everything at 0.5
587
+
588
+ self.P = _sort_P(P, ranks)
589
+
590
+ self.ranks = ranks
591
+ self.ranks.sort()
592
+
593
+ self.vf = vf
594
+
595
+ self.ranks = ranks
596
+ self.delta = delta
597
+
598
+ super().__init__(n_var_vf, n_obj=1, n_ieq_constr=n_ieq_c_vf, n_eq_constr=1, xl=xl_vf, xu=xu_vf)
599
+
600
+ def _evaluate(self, x, out, *args, **kwargs):
601
+
602
+ ## Objective function:
603
+ obj = _obj_func(x)
604
+
605
+ # The objective function above returns a negated version of epsilon
606
+ ep = -obj
607
+
608
+ # maximize epsilon, or the minimum distance between each contour
609
+ out["F"] = obj
610
+
611
+ ## Inequality
612
+
613
+ ineq_func = _build_ineq_constr_linear(self.P, self.vf, self.ranks, self.delta)
614
+
615
+ out["G"] = ineq_func(x)
616
+
617
+ ## Equality constraint that keeps sum of x under 1
618
+ out["H"] = _eq_constr_linear(x)
619
+
620
+ def _validate_vf(res, verbose):
621
+
622
+ message = ""
623
+
624
+ if isinstance(res, pymoo.core.result.Result):
625
+ success = np.all(res.G <= 0)
626
+ epsilon = res.X[-1]
627
+ if not success:
628
+ message = "Constraints not met\n"
629
+ if epsilon < 0:
630
+ message = message + "Epsilon negative\n"
631
+
632
+
633
+ elif isinstance(res, OptimizeResult):
634
+ success = res.success and res.constr_violation <= 0
635
+ epsilon = res.x[-1]
636
+
637
+ if not (res.constr_violation <= 0):
638
+ message = "Constraints not met."
639
+ else:
640
+ message = res.message
641
+ else:
642
+ ValueError("Internal error: bad result objective given for validation")
643
+
644
+ if epsilon < 0 or not success:
645
+
646
+ if verbose:
647
+ sys.stderr.write("WARNING: Unable to fit value function\n")
648
+ sys.stderr.write(message + "\n")
649
+
650
+ return False
651
+ else:
652
+ return True
653
+
654
+
655
+ class OptimizePolyVF(Problem):
656
+
657
+ def __init__(self, P, ranks, delta, eps_max, vf):
658
+
659
+ M = P.shape[1]
660
+
661
+ P_count = P.shape[0]
662
+
663
+
664
+ # One var for each dimension of the object space, plus epsilon
665
+ n_var_vf = (M**2 + M + 1)
666
+
667
+ # it has one inequality constraints for every pair of solutions in P
668
+ n_ieq_c_vf = (P_count*M) + (P_count - 1)
669
+
670
+ xl_vf = [0.0] * n_var_vf
671
+ xu_vf = [1.0] * n_var_vf
672
+
673
+ # upper/lower bound on the epsilon variable is -1000/1000
674
+ xl_vf[-1] = -1000
675
+ xu_vf[-1] = eps_max
676
+
677
+ # TODO start everything at 0.5
678
+
679
+ self.P = _sort_P(P, ranks)
680
+
681
+ self.ranks = ranks
682
+ self.ranks.sort()
683
+
684
+ self.vf = vf
685
+
686
+ self.delta = delta
687
+
688
+ super().__init__(n_var_vf, n_obj=1, n_ieq_constr=n_ieq_c_vf, n_eq_constr=M, xl=xl_vf, xu=xu_vf)
689
+
690
+ def _evaluate(self, x, out, *args, **kwargs):
691
+
692
+ ## Objective function:
693
+ obj = _obj_func(x)
694
+
695
+ # The objective function above returns a negated version of epsilon
696
+ ep = -obj
697
+
698
+ # maximize epsilon, or the minimum distance between each contour
699
+ out["F"] = obj
700
+
701
+ ## Inequality
702
+ ineq_func = _build_ineq_constr_poly(self.P, self.vf, self.ranks, self.delta)
703
+
704
+ out["G"] = ineq_func(x)
705
+
706
+ ## Equality constraint that keeps sum of x under 1
707
+ out["H"] = _eq_constr_poly(x)
708
+
709
+
710
+ class vfResults():
711
+
712
+ def __init__(self, vf, params, epsilon, fit):
713
+
714
+ self.vf = vf
715
+ self.params = params
716
+ self.epsilon = epsilon
717
+ self.fit = fit
718
+
719
+
720
+