Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reject reason for optimizer #1247

Merged
merged 7 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/user_manual/generated/optimizer.tex
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ \subsection{GradientDescent}
\item \texttt{trajID}: integer identifier for different optimization starting locations and paths
\item \texttt{iteration}: integer identifying which iteration (or step, or generation) a trajectory is on
\item \texttt{accepted}: string acceptance status of the potential optimal point (algorithm dependent)
\item \texttt{rejectReason}: discription of reject reason, 'noImprovement' means rejected the new optimization point for no improvement from last point, 'implicitConstraintsViolation' means rejected by implicit constraints violation, return None if the point is accepted
\item \texttt{\{VAR\}}: any variable from the \xmlNode{TargetEvaluation} input or output; gives the value of that variable at the optimal candidate for this iteration.
\item \texttt{stepSize}: the size of step taken in the normalized input space to arrive at each optimal point
\item \texttt{conv\_\{CONV\}}: status of each given convergence criteria
Expand Down Expand Up @@ -472,6 +473,7 @@ \subsection{SimulatedAnnealing}
\item \texttt{trajID}: integer identifier for different optimization starting locations and paths
\item \texttt{iteration}: integer identifying which iteration (or step, or generation) a trajectory is on
\item \texttt{accepted}: string acceptance status of the potential optimal point (algorithm dependent)
\item \texttt{rejectReason}: discription of reject reason, 'noImprovement' means rejected the new optimization point for no improvement from last point, 'implicitConstraintsViolation' means rejected by implicit constraints violation, return None if the point is accepted
\item \texttt{\{VAR\}}: any variable from the \xmlNode{TargetEvaluation} input or output; gives the value of that variable at the optimal candidate for this iteration.
\item \texttt{conv\_\{CONV\}}: status of each given convergence criteria
\item \texttt{amp\_\{VAR\}}: amplitued associated to each variable used to compute step size based on cooling method and the corresponding next neighbour
Expand Down
23 changes: 15 additions & 8 deletions framework/Optimizers/GradientDescent.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ def getSolutionExportVariableNames(cls):
new.update(gradReturnClass(grad, cls).getSolutionExportVariableNames())
for step in stepKnownTypes():
new.update(stepReturnClass(step, cls).getSolutionExportVariableNames())

ok.update(new)
return ok

Expand Down Expand Up @@ -565,6 +564,7 @@ def _checkAcceptability(self, traj, opt, optVal, info):
@ In, info, dict, identifying information about the opt point
@ Out, acceptable, str, acceptability condition for point
@ Out, old, dict, old opt point
@ Out, rejectReason, str, reject reason of opt point, or return None if accepted
"""
# Check acceptability
if self._optPointHistory[traj]:
Expand All @@ -580,10 +580,11 @@ def _checkAcceptability(self, traj, opt, optVal, info):
self.raiseADebug('Cancelling Trajectory {} because it is following Trajectory {}'.format(traj, following))
self._trajectoryFollowers[following].append(traj) # "traj" is killed by "following"
self._closeTrajectory(traj, 'cancel', 'following {}'.format(following), optVal)
return 'accepted', old
return 'accepted', old, 'None'

self.raiseADebug(' ... change: {d: 1.3e} new: {n: 1.6e} old: {o: 1.6e}'
.format(d=optVal-oldVal, o=oldVal, n=optVal))
rejectReason = 'None'
## some stepManipulators may need to override the acceptance criteria, e.g. conjugate gradient
if self._stepInstance.needsAccessToAcceptance:
acceptable = self._stepInstance.modifyAcceptance(old, oldVal, opt, optVal)
Expand All @@ -598,35 +599,42 @@ def _checkAcceptability(self, traj, opt, optVal, info):
acceptable = 'accepted'
else:
if self._impConstraintFunctions:
accept = self._handleImplicitConstraints(old)
accept = self._handleImplicitConstraints(opt)
if accept:
acceptable = self._checkForImprovement(optVal, oldVal)
acceptable, rejectReason = self._checkForImprovement(optVal, oldVal)
else:
acceptable = 'rejected'
rejectReason = 'implicitConstraintsViolation'
else:
acceptable = self._checkForImprovement(optVal, oldVal)
acceptable, rejectReason = self._checkForImprovement(optVal, oldVal)
else: # no history
# if first sample, simply assume it's better!
rejectReason = 'None'
if self._impConstraintFunctions:
accept = self._handleImplicitConstraints(opt)
if not accept:
self.raiseAWarning('First point violate Implicit constraint, please change another point to start!')
rejectReason = 'implicitConstraintsViolation'
acceptable = 'first'
old = None
self._acceptHistory[traj].append(acceptable)
self.raiseADebug(' ... {a}!'.format(a=acceptable))
return acceptable, old
return acceptable, old, rejectReason

def _checkForImprovement(self, new, old):
"""
Determine if the new value is sufficient improved over the old.
@ In, new, float, new optimization value
@ In, old, float, previous optimization value
@ Out, improved, bool, True if "sufficiently" improved or False if not.
@ Out, rejectReason, str, reject reason of opt point, or return None if accepted
"""
# TODO could this be a base RavenSampled class?
improved = self._acceptInstance.checkImprovement(new, old)
return 'accepted' if improved else 'rejected'
if improved:
return 'accepted', 'None'
else:
return 'rejected', 'noImprovement'

def _updateConvergence(self, traj, new, old, acceptable):
"""
Expand Down Expand Up @@ -815,7 +823,6 @@ def _formatSolutionExportVariableNames(self, acceptable):
# remaking the list is easier than using the existing one
acceptable = RavenSampled._formatSolutionExportVariableNames(self, acceptable)
new = []
print('DEBUGG acceptable:', acceptable)
while acceptable:
template = acceptable.pop()
if '{CONV}' in template:
Expand Down
3 changes: 2 additions & 1 deletion framework/Optimizers/Optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,13 @@ def checkConvergence(self, traj):
"""

@abc.abstractmethod
def _updateSolutionExport(self, traj, rlz, acceptable):
def _updateSolutionExport(self, traj, rlz, acceptable, rejectReason):
"""
Stores information to the solution export.
@ In, traj, int, trajectory which should be written
@ In, rlz, dict, collected point
@ In, acceptable, bool, acceptability of opt point
@ In, rejectReason, str, reject reason of opt point, or return None if accepted
@ Out, None
"""

Expand Down
12 changes: 8 additions & 4 deletions framework/Optimizers/RavenSampled.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def getSolutionExportVariableNames(cls):
ok.update({'trajID': 'integer identifier for different optimization starting locations and paths',
'iteration': 'integer identifying which iteration (or step, or generation) a trajectory is on',
'accepted': 'string acceptance status of the potential optimal point (algorithm dependent)',
'rejectReason':'discription of reject reason, \'noImprovement\' means rejected the new optimization point for no improvement from last point, \'implicitConstraintsViolation\' means rejected by implicit constraints violation, return None if the point is accepted',
'{VAR}': r'any variable from the \xmlNode{TargetEvaluation} input or output; gives the value of that variable at the optimal candidate for this iteration.',
})
return ok
Expand Down Expand Up @@ -314,7 +315,7 @@ def finalizeSampler(self, failedRuns):
self.raiseAMessage(finalTemplate.format(name=var, value=val))
self.raiseAMessage('*'*80)
# write final best solution to soln export
self._updateSolutionExport(bestTraj, self.normalizeData(bestOpt), 'final')
self._updateSolutionExport(bestTraj, self.normalizeData(bestOpt), 'final', 'None')

###################
# Utility Methods #
Expand Down Expand Up @@ -460,7 +461,7 @@ def _resolveNewOptPoint(self, traj, rlz, optVal, info):
# note the collection of the opt point
self._stepTracker[traj]['opt'] = (rlz, info)
# FIXME check implicit constraints? Function call, - Jia
acceptable, old = self._checkAcceptability(traj, rlz, optVal, info)
acceptable, old, rejectReason = self._checkAcceptability(traj, rlz, optVal, info)
converged = self._updateConvergence(traj, rlz, old, acceptable)
# we only want to update persistance if we've accepted a new point.
# We don't want rejected points to count against our convergence.
Expand All @@ -469,7 +470,7 @@ def _resolveNewOptPoint(self, traj, rlz, optVal, info):
# NOTE: the solution export needs to be updated BEFORE we run rejectOptPoint or extend the opt
# point history.
if self._writeSteps == 'every':
self._updateSolutionExport(traj, rlz, acceptable)
self._updateSolutionExport(traj, rlz, acceptable, rejectReason)
self.raiseADebug('*'*80)
# decide what to do next
if acceptable in ['accepted', 'first']:
Expand All @@ -492,6 +493,7 @@ def _checkAcceptability(self, traj, opt, optVal):
@ In, optVal, float, new optimization value
@ Out, acceptable, str, acceptability condition for point
@ Out, old, dict, old opt point
@ Out, rejectReason, str, reject reason of opt point, or return None if accepted
"""

@abc.abstractmethod
Expand Down Expand Up @@ -522,12 +524,13 @@ def _rejectOptPoint(self, traj, info, old):
@ In, old, dict, previous optimal point (to resubmit)
"""

def _updateSolutionExport(self, traj, rlz, acceptable):
def _updateSolutionExport(self, traj, rlz, acceptable, rejectReason):
"""
Stores information to the solution export.
@ In, traj, int, trajectory which should be written
@ In, rlz, dict, collected point
@ In, acceptable, bool, acceptability of opt point
@ In, rejectReason, str, reject reason of opt point, or return None if accepted
@ Out, None
"""
# make a holder for the realization that will go to the solutionExport
Expand All @@ -536,6 +539,7 @@ def _updateSolutionExport(self, traj, rlz, acceptable):
toExport.update({'iteration': self.getIteration(traj),
'trajID': traj,
'accepted': acceptable,
'rejectReason': rejectReason
})
# optimal point input and output spaces
objValue = rlz[self._objectiveVar]
Expand Down
3 changes: 2 additions & 1 deletion framework/Optimizers/SimulatedAnnealing.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ def _checkAcceptability(self, traj, opt, optVal, info):
@ In, info, dict, meta information about the opt point
@ Out, acceptable, str, acceptability condition for point
@ Out, old, dict, old opt point
@ Out, rejectReason, str, reject reason of opt point, or return None if accepted
"""
# Check acceptability
# NOTE: if self._optPointHistory[traj]: -> faster to use "try" for all but the first time
Expand Down Expand Up @@ -446,7 +447,7 @@ def _checkAcceptability(self, traj, opt, optVal, info):
old = None
self._acceptHistory[traj].append(acceptable)
self.raiseADebug(' ... {a}!'.format(a=acceptable))
return acceptable, old
return acceptable, old, 'None'

def _acceptabilityCriterion(self,currentObjective,newObjective):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</description>
<revisions>
<revision author="zhouj" date="2020-05-15">Add implicit constriant node in optimizer and function node with objective as variable.</revision>
<revision author="zhouj" date="2020-06-04">Add reject opt point reason.</revision>
</revisions>
<requirements>R-RM-2</requirements>
</TestInfo>
Expand Down Expand Up @@ -103,7 +104,7 @@
</PointSet>
<PointSet name="opt_export">
<Input>trajID</Input>
<Output>x,y,ans,stepSize,iteration,accepted,conv_gradient</Output>
<Output>x,y,ans,stepSize,iteration,accepted,conv_gradient,rejectReason</Output>
</PointSet>
</DataObjects>

Expand Down
Loading