Skip to content

Commit

Permalink
removing nParents from inputs, and regolding (#1673)
Browse files Browse the repository at this point in the history
* removing nParents from inputs, and regolding

* pushing KnapsackModel

* pushing gold for knapsack Tournament

* making the population size exactly equal the user input

* removing commented lines

* fixing typo in manual

* regolding

* Adding a conversion script
  • Loading branch information
Jimmy-INL authored Oct 14, 2021
1 parent a31f89a commit 0b14ebd
Show file tree
Hide file tree
Showing 65 changed files with 3,461 additions and 15,068 deletions.
64 changes: 27 additions & 37 deletions developer_tools/XSDSchemas/Optimizers.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@
</xsd:all>
</xsd:complexType>

<!-- <xsd:complexType name="linearCoolingType">
<xsd:element name="beta" type="xsd:float"/>
</xsd:complexType> -->

<xsd:complexType name="exponentialCoolingType">
<xsd:all>
<xsd:element name="alpha" type="xsd:float"/>
Expand All @@ -113,10 +109,6 @@
</xsd:all>
</xsd:complexType>

<!-- <xsd:complexType name="fastCoolingType">
<xsd:element name="c" type="xsd:float"/>
</xsd:complexType> -->

<xsd:complexType name="veryFastCoolingType">
<xsd:all>
<xsd:element name="c" type="xsd:float"/>
Expand Down Expand Up @@ -188,14 +180,40 @@
<xsd:attribute name="verbosity" type="verbosityAttr"/>
</xsd:complexType>

<xsd:complexType name="GeneticAlgorithmOptimizer">
<xsd:sequence>
<xsd:element name="samplerInit" type="optInitType" minOccurs="0"/>
<xsd:element name="GAparams" type="GAoptInitType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="convergence" type="SAConvergenceType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="coolingSchedule" type="OptCoolingScheduleType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="variable" type="optVarType" minOccurs="1" maxOccurs='unbounded'/>
<xsd:element name="objective" type="xsd:string" minOccurs="1" maxOccurs="1"/>
<xsd:element name="TargetEvaluation" type="AssemblerObjectType" minOccurs="1" maxOccurs="1"/>
<xsd:element name="constant" type="constantVarType" minOccurs="0" maxOccurs='unbounded'/>
<xsd:element name="ConstantSource" minOccurs="0" maxOccurs='unbounded'>
<xsd:complexType mixed="true">
<xsd:attribute name="class" type="xsd:string" use="required"/>
<xsd:attribute name="type" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="Sampler" type="AssemblerObjectType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="Constraint" type="AssemblerObjectType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ImplicitConstraint" type="AssemblerObjectType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Restart" type="AssemblerObjectType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="restartTolerance" type="xsd:float" minOccurs="0" maxOccurs="1"/>
<xsd:element name="variableTransformation" type="variablesTransformationType" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="verbosity" type="verbosityAttr"/>
</xsd:complexType>
<xsd:complexType name="crossoverType">
<xsd:all>
<xsd:element name="crossoverProb" type="xsd:float" />
</xsd:all>
<xsd:attribute name="type" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="mutationType">
<xsd:complexType name="mutationType">
<xsd:all>
<xsd:element name="mutationProb" type="xsd:float" />
<xsd:element name="locs" type="xsd:string" minOccurs="0" maxOccurs="1"/>
Expand All @@ -208,7 +226,6 @@
<xsd:element name="crossover" type="crossoverType" />
<xsd:element name="mutation" type="mutationType" />
</xsd:all>
<xsd:attribute name="nParents" type="xsd:integer" />
</xsd:complexType>

<xsd:complexType name="fitnessType">
Expand All @@ -228,31 +245,4 @@
<xsd:element name="survivorSelection" type="xsd:string" />
</xsd:all>
</xsd:complexType>

<xsd:complexType name="GeneticAlgorithmOptimizer">
<xsd:sequence>
<xsd:element name="samplerInit" type="optInitType" minOccurs="0"/>
<xsd:element name="GAparams" type="GAoptInitType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="convergence" type="SAConvergenceType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="coolingSchedule" type="OptCoolingScheduleType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="variable" type="optVarType" minOccurs="1" maxOccurs='unbounded'/>
<xsd:element name="objective" type="xsd:string" minOccurs="1" maxOccurs="1"/>
<xsd:element name="TargetEvaluation" type="AssemblerObjectType" minOccurs="1" maxOccurs="1"/>
<xsd:element name="constant" type="constantVarType" minOccurs="0" maxOccurs='unbounded'/>
<xsd:element name="ConstantSource" minOccurs="0" maxOccurs='unbounded'>
<xsd:complexType mixed="true">
<xsd:attribute name="class" type="xsd:string" use="required"/>
<xsd:attribute name="type" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="Sampler" type="AssemblerObjectType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="Constraint" type="AssemblerObjectType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ImplicitConstraint" type="AssemblerObjectType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Restart" type="AssemblerObjectType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="restartTolerance" type="xsd:float" minOccurs="0" maxOccurs="1"/>
<xsd:element name="variableTransformation" type="variablesTransformationType" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="verbosity" type="verbosityAttr"/>
</xsd:complexType>
</xsd:schema>
61 changes: 40 additions & 21 deletions doc/user_manual/generated/optimizer.tex
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ \subsection{GradientDescent}
SPSA, a small value for the shrink factor is recommended. If an
optimization path appears to be converging early, increasing the shrink
factor might improve the search. \default{1.15}

\item \xmlNode{window}: \xmlDesc{integer},
the number of previous gradient evaluations to include when determining a new step
direction. Modifying this allows past gradient evaluations to influence future steps,
with a decaying influence. Setting this to 1 means only the local gradient evaluation
will be used. \default{1}.

\item \xmlNode{decay}: \xmlDesc{float},
if including more than one gradient history terms when determining a new step
direction, specifies the rate of decay for previous terms to influence
the current direction. The decay factor has the form $e^(-\lambda t)$,
where $t$ counts the gradient terms starting with the most recent as 0
and moving towards the past, and $\lambda$ is this decay factor. This
should generally be a small decimal number. \default{0.2}
\end{itemize}

\item \xmlNode{ConjugateGradient}:
Expand Down Expand Up @@ -392,7 +406,8 @@ \subsection{GradientDescent}
the name of a function defined in the \xmlNode{Functions} block (see
Section~\ref{sec:functions}). This external function must contain a method
called ``constrain'', which returns True for inputs satisfying the explicit
constraints and False otherwise.
constraints and False otherwise. \nb Currently this accepts any number of constraints from the
user.
The \xmlNode{Constraint} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{class}: \xmlDesc{string, required},
Expand Down Expand Up @@ -784,7 +799,8 @@ \subsection{SimulatedAnnealing}
the name of a function defined in the \xmlNode{Functions} block (see
Section~\ref{sec:functions}). This external function must contain a method
called ``constrain'', which returns True for inputs satisfying the explicit
constraints and False otherwise.
constraints and False otherwise. \nb Currently this accepts any number of constraints from the
user.
The \xmlNode{Constraint} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{class}: \xmlDesc{string, required},
Expand Down Expand Up @@ -1094,27 +1110,24 @@ \subsection{GeneticAlgorithm}
A node containing the criterion based on which the parents are selected. This can be a
fitness proportional selection such as: a.
\textbf{\textit{rouletteWheel}}, b.
\textbf{\textit{stochasticUniversalSampling}}, c.
\textbf{\textit{Tournament}}, d. \textbf{\textit{Rank}}, or
e. \textbf{\textit{randomSelection}}
\textbf{\textit{tournamentSelection}}, c.
\textbf{\textit{rankSelection}} for all methods nParents is computed
such that the population size is kept constant. \[ nChildren = 2 \times
{nParents \choose 2} = nParents \times (nParents-1) = popSize \], solving for nParents we
get: $nParents = ceil(\frac{1 + \sqrt{1+4*popSize}}{2})$ This will
result in a popSize a little lareger than the initial one, these excessive children will
be later thrawn away and only the first popSize child will be kept

\item \xmlNode{reproduction}:
a node containing the reproduction methods. This accepts subnodes that
specifies the types of crossover and mutation.
The \xmlNode{reproduction} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{nParents}: \xmlDesc{integer, required},
number of parents to be considered in the reproduction phase
\end{itemize}

The \xmlNode{reproduction} node recognizes the following subnodes:
\begin{itemize}
\item \xmlNode{crossover}: \xmlDesc{string},
a subnode containing the implemented crossover mechanisms. This
includes: a. One Point Crossover, b. MultiPoint
Crossover, c. Uniform Crossover,
d. Whole Arithmetic Recombination, or e. Davis’
Order Crossover.
includes: a. onePointCrossover, b.
twoPointsCrossover, c. uniformCrossover.
The \xmlNode{crossover} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{type}: \xmlDesc{string, required},
Expand All @@ -1133,9 +1146,8 @@ \subsection{GeneticAlgorithm}

\item \xmlNode{mutation}: \xmlDesc{string},
a subnode containing the implemented mutation mechanisms. This
includes: a. Bit Flip, b. Random Resetting,
c. Swap, d. Scramble, or
e. Inversion.
includes: a. bitFlipMutation, b. swapMutation,
c. scrambleMutation, or d. inversionMutation.
The \xmlNode{mutation} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{type}: \xmlDesc{string, required},
Expand All @@ -1159,12 +1171,18 @@ \subsection{GeneticAlgorithm}

\item \xmlNode{fitness}: \xmlDesc{string},
a subnode containing the implemented fitness functions. This includes:
a. invLinear: $fitness = \frac{1}{a \times obj + b \times penalty}$.
b. logistic: $fitness = \frac{1}{1+e^{a \times (obj-b)}}$

a. invLinear: \[fitness = -a \times obj - b \times \sum_{j=1}^{nConstraints}
max(0,-penalty_j)\] b. logistic: \[fitness =
\frac{1}{1+e^{a \times (obj-b)}}\] c. feasibleFirst:
\[fitness = \begin{cases}
-obj & g_j(x) \geq 0 \forall j \\
-obj_{worst} - \sum_{j=1}^{nConstraints} <g_j(x)> & o.w. \\
\end{cases}\]
The \xmlNode{fitness} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{type}: \xmlDesc{string, required},
[invLin, logistic]
[invLin, logistic, feasibleFirst]
\end{itemize}

The \xmlNode{fitness} node recognizes the following subnodes:
Expand Down Expand Up @@ -1247,7 +1265,8 @@ \subsection{GeneticAlgorithm}
the name of a function defined in the \xmlNode{Functions} block (see
Section~\ref{sec:functions}). This external function must contain a method
called ``constrain'', which returns True for inputs satisfying the explicit
constraints and False otherwise.
constraints and False otherwise. \nb Currently this accepts any number of constraints from the
user.
The \xmlNode{Constraint} node recognizes the following parameters:
\begin{itemize}
\item \xmlAttr{class}: \xmlDesc{string, required},
Expand Down
31 changes: 19 additions & 12 deletions framework/Optimizers/GeneticAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,19 @@ def getInputSpecification(cls):
fitness proportional selection such as:
a. \textbf{\textit{rouletteWheel}},
b. \textbf{\textit{tournamentSelection}},
c. \textbf{\textit{rankSelection}}, or""")
c. \textbf{\textit{rankSelection}}
for all methods nParents is computed such that the population size is kept constant.
\[ nChildren = 2 \times {nParents \choose 2} = nParents \times (nParents-1) = popSize \]
solving for nParents we get:
\[nParents = ceil(\frac{1 + \sqrt{1+4*popSize}}{2})\]
This will result in a popSize a little lareger than the initial one, these excessive children will be later thrawn away and only the first popSize child will be kept""")
GAparams.addSub(parentSelection)

# Reproduction
reproduction = InputData.parameterInputFactory('reproduction', strictMode=True,
printPriority=108,
descr=r"""a node containing the reproduction methods.
This accepts subnodes that specifies the types of crossover and mutation.""")
reproduction.addParam("nParents", InputTypes.IntegerType, True,
descr="number of parents to be considered in the reproduction phase")
# 1. Crossover
crossover = InputData.parameterInputFactory('crossover', strictMode=True,
contentType=InputTypes.StringType,
Expand Down Expand Up @@ -289,7 +292,7 @@ def handleInput(self, paramInput):
self._parentSelectionInstance = parentSelectionReturnInstance(self,name = parentSelectionNode.value)
# reproduction node
reproductionNode = gaParamsNode.findFirst('reproduction')
self._nParents = reproductionNode.parameterValues['nParents']
self._nParents = int(np.ceil(1/2 + np.sqrt(1+4*self._populationSize)/2))
self._nChildren = int(2*comb(self._nParents,2))
# crossover node
crossoverNode = reproductionNode.findFirst('crossover')
Expand Down Expand Up @@ -319,7 +322,7 @@ def handleInput(self, paramInput):

# Check if the fitness requested is among the constrained optimization fitnesses
# Currently, only InvLin and feasibleFirst Fitnesses deal with constrained optimization
## TODO: @mandd, please explore the possibility to conver the logistic fitness into a constrained optimization fitness.
## TODO: @mandd, please explore the possibility to convert the logistic fitness into a constrained optimization fitness.
if 'Constraint' in self.assemblerObjects.keys() and self._fitnessType not in ['invLinear','feasibleFirst']:
self.raiseAnError(IOError, 'Currently constrained Genetic Algorithms only support invLinear and feasibleFirst fitnesses, whereas provided fitness is {}'.format(self._fitnessType))
self._objCoeff = fitnessNode.findFirst('a').value if fitnessNode.findFirst('a') is not None else None
Expand Down Expand Up @@ -354,7 +357,7 @@ def initialize(self, externalSeeding=None, solutionExport=None):

meta = ['batchId']
self.addMetaKeys(meta)
self.batch = self._populationSize*(self.counter==0)+self._nChildren*(self.counter>0)
self.batch = self._populationSize
if self._populationSize != len(self._initialValues):
self.raiseAnError(IOError, 'Number of initial values provided for each variable is {}, while the population size is {}'.format(len(self._initialValues),self._populationSize,self._populationSize))
for _, init in enumerate(self._initialValues):
Expand Down Expand Up @@ -431,7 +434,7 @@ def _useRealization(self, info, rlz):
coords={'chromosome':np.arange(np.shape(offSprings)[0]),
'Constraint':[y.name for y in (self._constraintFunctions + self._impConstraintFunctions)]})
## FIXME The constraint handling is following the structure of the RavenSampled.py,
# there are many utility functions that can be simplified and/or merged with
# there are many utility functions that can be simplified and/or merged together
# _check, _handle, and _apply, for explicit and implicit constraints.
# This can be simplified in the near future in GradientDescent, SimulatedAnnealing, and here in GA
for index,individual in enumerate(offSprings):
Expand Down Expand Up @@ -525,20 +528,24 @@ def _useRealization(self, info, rlz):
repeated.append(j)
repeated = list(set(repeated))
if repeated:
newChildren = self._mutationInstance(offSprings=children[repeated,:], distDict = self.distDict, locs = self._mutationLocs, mutationProb=self._mutationProb,variables=list(self.toBeSampled))
children.data[repeated,:] = newChildren.data
if len(repeated)> children.shape[0] - self._populationSize:
newChildren = self._mutationInstance(offSprings=children[repeated,:], distDict = self.distDict, locs = self._mutationLocs, mutationProb=self._mutationProb,variables=list(self.toBeSampled))
children.data[repeated,:] = newChildren.data
else:
children = children.drop_sel(chromosome=repeated)
else:
flag = False

self.batch = np.shape(children)[0]
# keeping the population size constant by ignoring the excessive children
children = children[:self._populationSize,:]

daChildren = xr.DataArray(children,
dims=['chromosome','Gene'],
coords={'chromosome': np.arange(np.shape(children)[0]),
'Gene':list(self.toBeSampled)})

# 5 @ n: Submit children batch
# submit children coordinates (x1,...,xm), i.e., self.childrenCoordinates
for i in range(np.shape(daChildren)[0]):
for i in range(self.batch):
newRlz={}
for _,var in enumerate(self.toBeSampled.keys()):
newRlz[var] = float(daChildren.loc[i,var].values)
Expand Down
Loading

0 comments on commit 0b14ebd

Please sign in to comment.