import numpy as np
import matplotlib.pyplot as plt
[docs]
class SingleObjOptResults:
"""
Container for optimization results for single objective
problems.
Attributes
----------
success: bool
Optimization success
vars_int: np.array
Optimal variables, shape: (n_vars_int,)
vars_float: np.array
Optimal variables, shape: (n_vars_float,)
objs: float
Optimal objective function value
cons: np.array
Constraint values, shape: (n_constraints,)
problem_results: Object
The results of the variable application to the problem
pname: str
The problem's name
vnames_int: list of str
The int variable names
vnames_float: list of str
The float variable names
onames: list of str
The names of objectives
cnames: list of str
The names of constraints
:group: core
"""
[docs]
def __init__(
self,
problem,
success,
vars_int,
vars_float,
objs,
cons,
problem_results,
):
"""
Constructor
Parameters
----------
problem: iwopy.core.Problem
The problem
success: bool
Optimization success
vars_int: np.array
Optimal variables, shape: (n_vars_int,)
vars_float: np.array
Optimal variables, shape: (n_vars_float,)
objs: float
Optimal objective function value
cons: np.array
Constraint values, shape: (n_constraints,)
problem_results: Object
The results of the variable application to the problem
"""
self.success = success
self.vars_int = vars_int
self.vars_float = vars_float
self.objs = objs
self.cons = cons
self.problem_results = problem_results
self.pname = problem.name
self.vnames_int = problem.var_names_int()
self.vnames_float = problem.var_names_float()
self.onames = problem.objs.component_names
self.cnames = problem.cons.component_names
if problem.n_objectives > 1:
raise ValueError(
f"Wrong opt results class '{type(self).__name__}' for multi objective problem. Use 'MultiObjOptResults' instead."
)
[docs]
def __str__(self):
s = f"Results problem '{self.pname}':\n"
hline = "-" * len(s) + "\n"
if len(self.vnames_int):
s += hline
L = len(max(self.vnames_int, key=len))
s += " Integer variables:\n"
for i, vname in enumerate(self.vnames_int):
s += f" {i}: {vname:<{L}} = {self.vars_int[i]}\n"
if self.vars_float is not None and len(self.vnames_float):
s += hline
L = len(max(self.vnames_float, key=len))
s += " Float variables:\n"
for i, vname in enumerate(self.vnames_float):
s += f" {i}: {vname:<{L}} = {self.vars_float[i]:.6e}\n"
if self.objs is not None and len(self.onames):
s += hline
L = len(max(self.onames, key=len))
s += " Objectives:\n"
for i, vname in enumerate(self.onames):
s += f" {i}: {vname:<{L}} = {self.objs[i]:.6e}\n"
if self.cons is not None and len(self.cnames):
s += hline
L = len(max(self.cnames, key=len))
s += " Constraints:\n"
for i, vname in enumerate(self.cnames):
s += f" {i}: {vname:<{L}} = {self.cons[i]:.6e}\n"
s += hline
s += f" Success: {self.success}\n"
s += hline
return s
[docs]
class MultiObjOptResults:
"""
Container for optimization results for multi objective
problems.
Attributes
----------
success: bool
Optimization success
vars_int: np.array
Pareto-optimal variables, shape: (n_pop, n_vars_int)
vars_float: np.array
Pareto-optimal variables, shape: (n_pop, n_vars_float)
objs: np.array
Pareto front objective function values, shape: (n_pop, n_objectives)
cons: np.array
Parteo front Constraint values, shape: (n_pop, n_constraints)
problem_results: Object
The results of the variable application to the problem
pname: str
The problem's name
vnames_int: list of str
The int variable names
vnames_float: list of str
The float variable names
onames: list of str
The names of objectives
cnames: list of str
The names of constraints
:group: core
"""
[docs]
def __init__(
self,
problem,
success,
vars_int,
vars_float,
objs,
cons,
problem_results,
):
"""
Constructor
Parameters
----------
problem: iwopy.core.Problem
The problem
success: bool
Optimization success
vars_int: np.array
Pareto-optimal variables, shape: (n_pop, n_vars_int)
vars_float: np.array
Pareto-optimal variables, shape: (n_pop, n_vars_float)
objs: np.array
Pareto front objective function values, shape: (n_pop, n_objectives)
cons: np.array
Parteo front Constraint values, shape: (n_pop, n_constraints)
problem_results: Object
The results of the variable application to the problem
"""
self.success = success
self.vars_int = vars_int
self.vars_float = vars_float
self.objs = objs
self.cons = cons
self.problem_results = problem_results
self.pname = problem.name
self.vnames_int = problem.var_names_int()
self.vnames_float = problem.var_names_float()
self.onames = problem.objs.component_names
self.cnames = problem.cons.component_names
if problem.n_objectives <= 1:
raise ValueError(
f"Wrong opt results class '{type(self).__name__}' for single objective problem. Use 'SingleObjOptResults' instead."
)
[docs]
def __str__(self):
s = f"Results problem '{self.pname}':\n"
hline = "-" * 2 * len(s) + "\n"
if len(self.vnames_int):
s += hline
L = len(max(self.vnames_int, key=len))
s += " Integer variables:\n"
for i, vname in enumerate(self.vnames_int):
v = self.vars_int[:, i]
s += f" {i}: {vname:<{L}}: {vname:<{L}} = {np.min(v)} --> {np.max(v)}\n"
if self.vars_float is not None and len(self.vnames_float):
s += hline
L = len(max(self.vnames_float, key=len))
s += " Float variables:\n"
for i, vname in enumerate(self.vnames_float):
v = self.vars_float[:, i]
s += f" {i}: {vname:<{L}}: {vname:<{L}} = {np.min(v):.6e} --> {np.max(v):.6e}\n"
if self.objs is not None and len(self.onames):
s += hline
L = len(max(self.onames, key=len))
s += " Objectives:\n"
for i, vname in enumerate(self.onames):
v = self.objs[:, i]
s += f" {i}: {vname:<{L}} = {np.min(v):.6e} --> {np.max(v):.6e}\n"
if self.cons is not None and len(self.cnames):
s += hline
L = len(max(self.cnames, key=len))
s += " Constraints:\n"
for i, vname in enumerate(self.cnames):
v = self.cons[:, i]
s += f" {i}: {vname:<{L}} = {np.min(v):.6e} --> {np.max(v):.6e}\n"
s += hline
v = np.sum(self.success) / len(self.success.flat)
s += f" Success: {100*v:.2f} %\n"
s += hline
return s
[docs]
def plot_pareto(
self,
obj_0=0,
obj_1=1,
ax=None,
figsize=(5, 5),
s=50,
color_val="orange",
color_ival="red",
title=None,
):
"""
Get figure that shows the pareto front
Parameters
----------
obj_0: int
The objective on the x axis
obj_1: int
The objective on the y axis
ax: pyplot.Axis, optional
The axis to plot on
figsize: tuple
The figure size, if ax is not given
s: float
Scatter point size
color_val: str
Color choice for valid points
color_ival: str
Color choice for invalid points
title: str, optional
The plot title
Returns
-------
ax: pyplot.axis
The plot axis
"""
if ax is None:
__, ax = plt.subplots(figsize=figsize)
sel = self.success
ax.scatter(
self.objs[sel, obj_0],
self.objs[sel, obj_1],
s=s,
c=color_val,
label="valid",
)
sel = ~self.success
ax.scatter(
self.objs[sel, obj_0],
self.objs[sel, obj_1],
s=s,
c=color_ival,
label="invalid",
)
if np.any(sel):
ax.legend(loc="best")
ax.set_xlabel(self.onames[obj_0])
ax.set_ylabel(self.onames[obj_1])
ax.set_title(self.pname if title is None else title)
ax.grid()
return ax
[docs]
def find_pareto_objmix(self, obj_weights, max=False):
"""
Find the point on the pareto front that
approximates best the given weights of objectives
Paramters
---------
obj_weights: list of float
The weights of the objectives
max: bool
Find the maximal value of the weighted result
(otherwise find the minimal value)
Returns
-------
index: int
The index in the pareto front results
"""
w = np.array(obj_weights, dtype=np.float64)
res = np.einsum("po,o->p", self.objs, w)
return np.argmax(res) if max else np.argmin(res)