Source code for statease.optimizer

from enum import Enum
import json

[docs]class Goal(Enum): """An enumeration representing the different types of goals a Criteria can have.""" NONE = 0 MAXIMIZE = 1 MINIMIZE = 2 TARGET = 3 IN_RANGE = 4 EQUAL_TO = 5 CPK = 6 def __str__(self): return self.name
[docs]class Optimizer: """The Optimizer class is used to set criteria on one or more Analyses, then use those criteria to find the optimal parameters. """ def __init__(self, client): self._client = client result = self._client.send_payload({ "method": "GET", "uri": "optimizer", }) self._criteria = [] self._solutions = tuple() def __str__(self): out = '' for c in self._criteria: if c.goal != Goal.NONE: out += '{}\n'.format(c) out += "Found {} solutions:".format(len(self._solutions)) for s in self._solutions: out += '{}\n'.format(s) return out def have_criteria(self): for c in self._criteria: if c._factor and c.goal == Goal.NONE: return False return True def add_criteria(self, criteria): if criteria._factor and criteria.goal==Goal.NONE: raise ValueError("Can't add criteria - no goal specified for '{}'.".format(criteria.name)) if criteria.restrict_discrete==True: if not criteria._factor: raise ValueError("Can't add criteria - It is not a discrete factor. For response/analysis '{}', restrict_discrete must be False.".format(criteria.name)) if (criteria._factor.type!="Numeric") or (criteria._factor.type=="Numeric" and criteria._factor.subtype!="Discrete"): raise ValueError("Can't add criteria - It is not a discrete factor. For factor '{}', restrict_discrete must be False.".format(criteria.name)) self._criteria.append(criteria) @property def solutions(self): return self._solutions
[docs] def optimize(self): """ Runs the optimization routine. Must have one or more Criteria specified. """ if not self.have_criteria(): raise ValueError("Can't run optimization - no criteria specified!") result = self._client.send_payload({ "method": "POST", "uri": "optimizer", "criteria": [ c.to_json() for c in self._criteria ], }) solutions = [] for solution in result['payload']['solutions']: solutions.append(json.loads(solution)) self._solutions = tuple(solutions)
[docs]class Criteria: """The Criteria class is used by the optimizer to calculate a desirability score for a given point in the design space, which is then used to search for an optimal point. Each Analysis and Factor can have a Criteria (e.g. you might maximize the output of an Analysis, and target a certain value of a Factor). """ def __init__(self, factor=None, analysis=None): """ Create a Criteria for a Factor or Analysis. """ if (not analysis and not factor) or (analysis and factor): raise ValueError("You must pass in either an analysis or factor.") self._analysis = analysis self._factor = factor self._name = '' self._goal = Goal.NONE self._target = 0 self._lower_limit = 0 self._upper_limit = 0 self._lower_weight = 1 self._upper_weight = 1 self._importance = 0 self._restrict_discrete = False def __str__(self): name = '' if self._analysis: name += self._analysis.name if self._factor: name += self._factor.name return "Criteria for {} -> Goal: {} Target: {} Lower Limit: {} Upper Limit: {} Lower Weight: {} Upper Weight: {} Importance: {} Restrict discrete: {}".format( name, self._goal, self._target, self._lower_limit, self. _upper_limit, self._lower_weight, self._upper_weight, self._importance, self._restrict_discrete, ) if self._factor: result += " " + "Restrict discrete: "+ str(self._restrict_discrete) return result @property def name(self): """ The name of this Criteria (analysis/response or factor name). """ if self._analysis: self._name = self._analysis.name elif self._factor: self._name = self._factor.name else: raise ValueError("You must pass in either an analysis or factor.") return self._name @property def goal(self): """ The goal of this Criteria (e.g. Goal.MAXIMIZE). """ return self._goal @goal.setter def goal(self, goal): self._goal = goal @property def target(self): """ The target for this Criteria, if using Goal.EQUAL_TO or Goal.TARGET """ return self._target @target.setter def target(self, target): self._target = target @property def lower_limit(self): """ The lower limit for this Criteria. """ return self._lower_limit @lower_limit.setter def lower_limit(self, lower_limit): self._lower_limit = lower_limit @property def upper_limit(self): """ The upper limit for this Criteria. """ return self._upper_limit @upper_limit.setter def upper_limit(self, upper_limit): self._upper_limit = upper_limit @property def lower_weight(self): """ The lower weight for this Criteria. """ return self._lower_weight @lower_weight.setter def lower_weight(self, lower_weight): self._lower_weight = lower_weight @property def upper_weight(self): """ The upper weight for this Criteria. """ return self._upper_weight @upper_weight.setter def upper_weight(self, upper_weight): self._upper_weight = upper_weight @property def importance(self): """ The importance of this Criteria, relative to other Criteria. """ return self._importance @importance.setter def importance(self, importance): self._importance = importance @property def restrict_discrete(self): """ The restrict discrete for this Criteria. """ return self._restrict_discrete @restrict_discrete.setter def restrict_discrete(self, restrict_discrete): self._restrict_discrete = restrict_discrete def to_json(self): out_dict = { 'analysis': self._analysis.name if self._analysis else None, 'factor': self._factor.name if self._factor else None, 'goal': str(self._goal), } # the rest of the members are primitives for k, v in self.__dict__.items(): key = k[1:] # strip off leading underscore if key in out_dict.keys(): continue out_dict[key] = v return out_dict