| 1 | package de.uka.ipd.sdq.tcfmoop.tcmanager; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.LinkedList; |
| 5 | import java.util.List; |
| 6 | |
| 7 | import org.opt4j.core.Archive; |
| 8 | import org.opt4j.core.Population; |
| 9 | import org.opt4j.core.optimizer.Control; |
| 10 | import org.opt4j.core.optimizer.Optimizer; |
| 11 | |
| 12 | import de.uka.ipd.sdq.tcfmoop.config.IConfiguration; |
| 13 | import de.uka.ipd.sdq.tcfmoop.config.TerminationCriteriaNames; |
| 14 | import de.uka.ipd.sdq.tcfmoop.outputtree.Node; |
| 15 | import de.uka.ipd.sdq.tcfmoop.outputtree.Tree; |
| 16 | import de.uka.ipd.sdq.tcfmoop.outputtree.Node.NodeType; |
| 17 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.ElapsedTimeCriterion; |
| 18 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.GivenParetoFrontIsReachedCriterion; |
| 19 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.ITerminationCriterion; |
| 20 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.InsignificantParetoFrontChangeCriterion; |
| 21 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.InsignificantSetQualityImprovementCriterion; |
| 22 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.MaxGenerationNumber; |
| 23 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.MinimalQualityCriteriaValueCriterion; |
| 24 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.NoNewParetoOptimalCandidatesFoundCriterion; |
| 25 | import de.uka.ipd.sdq.tcfmoop.terminationcriteria.ParetoOptimalSetStabilityCriterion; |
| 26 | |
| 27 | import com.google.inject.Inject; |
| 28 | import com.google.inject.Singleton; |
| 29 | |
| 30 | import bsh.EvalError; |
| 31 | import bsh.Interpreter; |
| 32 | |
| 33 | /** |
| 34 | * The main goal of the Termination Criteria Manager is to create termination |
| 35 | * criteria, call them so that they can evaluate the current optimization state |
| 36 | * and then evaluate their decisions, on which it must base its own decision |
| 37 | * whether to stop the optimization or not. |
| 38 | * |
| 39 | * @author Atanas Dimitrov |
| 40 | */ |
| 41 | @Singleton |
| 42 | public class TerminationCriteriaManager implements ITerminationCriteriaManager { |
| 43 | |
| 44 | /** |
| 45 | * List of all currently configured Termination Criteria |
| 46 | */ |
| 47 | private List<ITerminationCriterion> terminationCriteria = new LinkedList<ITerminationCriterion>(); |
| 48 | |
| 49 | /** |
| 50 | * Defines the Termination Criteria manager has been initialized |
| 51 | */ |
| 52 | private boolean isInitialized = false; |
| 53 | |
| 54 | /** |
| 55 | * So that all termination criteria can work with the same time. |
| 56 | */ |
| 57 | private long currentTime; |
| 58 | |
| 59 | // Required resources |
| 60 | private Control control; |
| 61 | private Optimizer optimizer; |
| 62 | private Population population; |
| 63 | private Archive archive; |
| 64 | private int iteration; |
| 65 | |
| 66 | /** |
| 67 | * if true - the manager will evaluate the termination criteria and report |
| 68 | * their output but this will not influence the evaluation in any way |
| 69 | */ |
| 70 | private boolean isInComparisionMode = false; |
| 71 | |
| 72 | /** |
| 73 | * if true - Composed Criterion are on. If false a standard || Criterion is |
| 74 | * used |
| 75 | */ |
| 76 | private boolean isComposedCriterionActive = false; |
| 77 | |
| 78 | /** |
| 79 | * if true, the optimization will be stopped the next time the manager runs. |
| 80 | */ |
| 81 | private boolean performManualStop = false; |
| 82 | |
| 83 | /** |
| 84 | * Composed Criterion Expression |
| 85 | */ |
| 86 | private String composedCriterionExpression = ""; |
| 87 | |
| 88 | // Event Listeners |
| 89 | private List<IOutputChangedListener> outputChangedListeners; |
| 90 | private static List<ITerminationCriteriaManagerInitializedListener> terminationCriteriaManagerInitializedListeners = new ArrayList<ITerminationCriteriaManagerInitializedListener>(); |
| 91 | private List<IOptimizationTerminatedListener> optimizationTerminatedListener; |
| 92 | |
| 93 | // Output |
| 94 | private Tree outputTree = new Tree("Termination Criteria Manager", |
| 95 | NodeType.MANAGER); |
| 96 | private Tree managerTree = new Tree("Manager", NodeType.MANAGER); |
| 97 | private Tree tCriteriaTree = new Tree("Termination Criteria", |
| 98 | NodeType.PARAMETER_GROUP); |
| 99 | private Tree warningsTree = new Tree("Warnings", NodeType.WARNING); |
| 100 | |
| 101 | // Output Nodes: |
| 102 | private Node iterationNummberNode; |
| 103 | private Node candidatesInPopulationNode; |
| 104 | private Node candidatesInArchiveNode; |
| 105 | private Node useComposedCriterionNode; |
| 106 | private Node ComposedCriterionExpressionNode; |
| 107 | private Node isRunningInComparisionModeNode; |
| 108 | private Node manualTerminationRequestedNode; |
| 109 | private Node optimizationStoppedNode; |
| 110 | |
| 111 | /** |
| 112 | * Warning flags to prevent more warning than are required |
| 113 | */ |
| 114 | private boolean substituteWarningShown = false; |
| 115 | |
| 116 | @Inject |
| 117 | public TerminationCriteriaManager(Control control, Population population, |
| 118 | Archive archive) { |
| 119 | this.control = control; |
| 120 | this.population = population; |
| 121 | this.archive = archive; |
| 122 | |
| 123 | this.outputChangedListeners = new ArrayList<IOutputChangedListener>(); |
| 124 | this.optimizationTerminatedListener = new ArrayList<IOptimizationTerminatedListener>(); |
| 125 | |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * {@inheritDoc} |
| 130 | */ |
| 131 | @Override |
| 132 | public void initialize(List<IConfiguration> tcConfigurations) { |
| 133 | for (IConfiguration conf : tcConfigurations) { |
| 134 | if (!conf.validateConfiguration()) { |
| 135 | this.warningsTree.addChild("The configuration for : " |
| 136 | + conf.getTerminationCriterionName() |
| 137 | + " cannot be veryfied successfully. " |
| 138 | + "The criterion will not be created.", |
| 139 | NodeType.WARNING); |
| 140 | continue; |
| 141 | } |
| 142 | |
| 143 | ITerminationCriterion tc = null; |
| 144 | |
| 145 | switch (conf.getTerminationCriterionName()) { |
| 146 | case MAXIMUM_NUMBER_OF_GENERATIONS: |
| 147 | tc = new MaxGenerationNumber(conf, population, archive); |
| 148 | break; |
| 149 | case ELAPSED_TIME: |
| 150 | tc = new ElapsedTimeCriterion(conf, population, archive); |
| 151 | break; |
| 152 | case PARETO_OPTIMAL_SET_STABILITY: |
| 153 | tc = new ParetoOptimalSetStabilityCriterion(conf, population, archive); |
| 154 | break; |
| 155 | case NO_NEW_PARETO_OPTIMAL_CANDIDATES_FOUND: |
| 156 | tc = new NoNewParetoOptimalCandidatesFoundCriterion(conf, population, archive); |
| 157 | break; |
| 158 | case MINIMAL_QUALITY_CIRTERIA_VALUE: |
| 159 | tc = new MinimalQualityCriteriaValueCriterion(conf, population, archive); |
| 160 | break; |
| 161 | case INSIGNIFICANT_SET_QUALITY_IMPROVEMENT: |
| 162 | tc = new InsignificantSetQualityImprovementCriterion(conf, population, archive); |
| 163 | break; |
| 164 | case GIVEN_PARETO_FRONT_IS_REACHED: |
| 165 | tc = new GivenParetoFrontIsReachedCriterion(conf, population, archive); |
| 166 | break; |
| 167 | case INSIGNIFICANT_PARETO_FRONT_CHANGE: |
| 168 | tc = new InsignificantParetoFrontChangeCriterion(conf, population, archive); |
| 169 | break; |
| 170 | default: |
| 171 | this.warningsTree.addChild("Unknown Termination Criterion: " |
| 172 | + conf.getTerminationCriterionName(), NodeType.WARNING); |
| 173 | } |
| 174 | if (tc != null) { |
| 175 | terminationCriteria.add(tc); |
| 176 | } |
| 177 | |
| 178 | } |
| 179 | this.initializeOutputTree(); |
| 180 | this.isInitialized = true; |
| 181 | |
| 182 | this.fireTerminationCriteriaManagerInitializedEvent(); |
| 183 | this.fireOutputInformationChangedEvent(); |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Initializes the output tree |
| 188 | */ |
| 189 | private void initializeOutputTree() { |
| 190 | this.outputTree.attachSubtree(managerTree); |
| 191 | this.outputTree.attachSubtree(tCriteriaTree); |
| 192 | this.outputTree.attachSubtree(warningsTree); |
| 193 | |
| 194 | this.iterationNummberNode = managerTree.addChild("Iteration Number: " |
| 195 | + this.iteration, NodeType.PARAMETER); |
| 196 | this.candidatesInPopulationNode = managerTree.addChild( |
| 197 | "Candidates in Population: " + this.population.size(), |
| 198 | NodeType.PARAMETER); |
| 199 | this.candidatesInArchiveNode = managerTree.addChild( |
| 200 | "All Pareto Optimal Candidates: " + this.archive.size(), |
| 201 | NodeType.PARAMETER); |
| 202 | this.useComposedCriterionNode = managerTree.addChild( |
| 203 | "Use Composed Criterion: " + this.isComposedCriterionActive, |
| 204 | NodeType.PARAMETER); |
| 205 | this.ComposedCriterionExpressionNode = managerTree |
| 206 | .addChild("Composed Criterion Expression: " |
| 207 | + this.composedCriterionExpression, NodeType.EXPRESSION); |
| 208 | this.isRunningInComparisionModeNode = managerTree.addChild( |
| 209 | "Running in Comparision Mode: " + this.isInComparisionMode, |
| 210 | NodeType.PARAMETER); |
| 211 | this.manualTerminationRequestedNode = managerTree.addChild( |
| 212 | "Manual Termination requested: " + this.performManualStop, |
| 213 | NodeType.PARAMETER); |
| 214 | this.optimizationStoppedNode = managerTree.addChild( |
| 215 | "Optimization Stopped: " + control.isStopped(), |
| 216 | NodeType.PARAMETER); |
| 217 | |
| 218 | } |
| 219 | |
| 220 | /** |
| 221 | * {@inheritDoc} |
| 222 | */ |
| 223 | @Override |
| 224 | public void activateTCComparisionMode() { |
| 225 | this.isInComparisionMode = true; |
| 226 | this.fireOutputInformationChangedEvent(); |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * {@inheritDoc} |
| 231 | */ |
| 232 | @Override |
| 233 | public void deactivateTCComparisionMode() { |
| 234 | this.isInComparisionMode = false; |
| 235 | this.fireOutputInformationChangedEvent(); |
| 236 | } |
| 237 | |
| 238 | /** |
| 239 | * {@inheritDoc} |
| 240 | */ |
| 241 | @Override |
| 242 | public void activateComposedCriterion() { |
| 243 | this.isComposedCriterionActive = true; |
| 244 | this.fireOutputInformationChangedEvent(); |
| 245 | |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * {@inheritDoc} |
| 250 | */ |
| 251 | @Override |
| 252 | public void deactivateComposedCriterion() { |
| 253 | this.isComposedCriterionActive = false; |
| 254 | this.fireOutputInformationChangedEvent(); |
| 255 | } |
| 256 | |
| 257 | /** |
| 258 | * {@inheritDoc} |
| 259 | */ |
| 260 | @Override |
| 261 | public void setComposedCriterionExpression( |
| 262 | String composedCriterionExpression) { |
| 263 | if (isComposedCriterionActive && !composedCriterionExpression.isEmpty()) { |
| 264 | |
| 265 | /* |
| 266 | * Checks the supplied boolean expression for consistency before |
| 267 | * using it It will be checked whether the expression can be |
| 268 | * evaluated and whether it contains illegal symbol in order to |
| 269 | * prevent execution of unwanted Java code |
| 270 | */ |
| 271 | |
| 272 | String exprTemp = composedCriterionExpression + ""; |
| 273 | exprTemp = exprTemp.replace(TerminationCriteriaNames.ELAPSED_TIME.name(), ""); |
| 274 | exprTemp = exprTemp.replace(TerminationCriteriaNames.GIVEN_PARETO_FRONT_IS_REACHED.name(), ""); |
| 275 | exprTemp = exprTemp.replace(TerminationCriteriaNames.INSIGNIFICANT_PARETO_FRONT_CHANGE.name(), ""); |
| 276 | exprTemp = exprTemp.replace(TerminationCriteriaNames.INSIGNIFICANT_SET_QUALITY_IMPROVEMENT.name(), ""); |
| 277 | exprTemp = exprTemp.replace(TerminationCriteriaNames.MAXIMUM_NUMBER_OF_GENERATIONS.name(), ""); |
| 278 | exprTemp = exprTemp.replace(TerminationCriteriaNames.MINIMAL_QUALITY_CIRTERIA_VALUE.name(), ""); |
| 279 | exprTemp = exprTemp.replace(TerminationCriteriaNames.NO_NEW_PARETO_OPTIMAL_CANDIDATES_FOUND.name(), ""); |
| 280 | exprTemp = exprTemp.replace(TerminationCriteriaNames.PARETO_OPTIMAL_SET_STABILITY.name(), ""); |
| 281 | |
| 282 | exprTemp = exprTemp.replace("true", ""); |
| 283 | exprTemp = exprTemp.replace("false", ""); |
| 284 | |
| 285 | exprTemp = exprTemp.replace("&&", ""); |
| 286 | exprTemp = exprTemp.replace("||", ""); |
| 287 | exprTemp = exprTemp.replace("!", ""); |
| 288 | |
| 289 | exprTemp = exprTemp.replace("(", ""); |
| 290 | exprTemp = exprTemp.replace(")", ""); |
| 291 | |
| 292 | exprTemp = exprTemp.replaceAll(" ", ""); |
| 293 | |
| 294 | if (!exprTemp.isEmpty()) { |
| 295 | isComposedCriterionActive = false; |
| 296 | this.warningsTree |
| 297 | .addChild( |
| 298 | "Composed Criterion Expression cannot be set because of the following reason: " |
| 299 | + "1. The expression contains symbols that are not allowed. " |
| 300 | + "A Standard 'OR' Expression will be used instead.", |
| 301 | NodeType.WARNING); |
| 302 | |
| 303 | return; |
| 304 | } |
| 305 | |
| 306 | Interpreter i = new Interpreter(); // Construct an interpreter |
| 307 | |
| 308 | try { |
| 309 | |
| 310 | i.set(TerminationCriteriaNames.ELAPSED_TIME.name(), true); |
| 311 | i.set(TerminationCriteriaNames.GIVEN_PARETO_FRONT_IS_REACHED.name(), true); |
| 312 | i.set(TerminationCriteriaNames.INSIGNIFICANT_PARETO_FRONT_CHANGE.name(), true); |
| 313 | i.set(TerminationCriteriaNames.INSIGNIFICANT_SET_QUALITY_IMPROVEMENT.name(), true); |
| 314 | i.set(TerminationCriteriaNames.MAXIMUM_NUMBER_OF_GENERATIONS.name(), true); |
| 315 | i.set(TerminationCriteriaNames.MINIMAL_QUALITY_CIRTERIA_VALUE.name(), true); |
| 316 | i.set(TerminationCriteriaNames.NO_NEW_PARETO_OPTIMAL_CANDIDATES_FOUND.name(), true); |
| 317 | i.set(TerminationCriteriaNames.PARETO_OPTIMAL_SET_STABILITY.name(), true); |
| 318 | |
| 319 | /* |
| 320 | * If eval() and get() can be successfully executed at this |
| 321 | * point with this form of the composed criteria expression, |
| 322 | * then the expression is correct. If an exception is thrown |
| 323 | * now, then the expression is malformed and cannot be used. |
| 324 | */ |
| 325 | i.eval("boolean evalResult = " + composedCriterionExpression + ";"); |
| 326 | i.get("evalResult"); |
| 327 | |
| 328 | this.composedCriterionExpression = composedCriterionExpression; |
| 329 | |
| 330 | } catch (EvalError e) { |
| 331 | isComposedCriterionActive = false; |
| 332 | this.warningsTree |
| 333 | .addChild( |
| 334 | "Composed Criterion Expression cannot be set because of the following reason: " |
| 335 | + "1. The Expression cannot be evaluated because it is malformed. " |
| 336 | + "A Standard 'OR' Expression will be used instead.", |
| 337 | NodeType.WARNING); |
| 338 | } |
| 339 | } else { |
| 340 | this.warningsTree |
| 341 | .addChild( |
| 342 | "Composed Criterion Expression cannot be set because of one of the following reasons: " |
| 343 | + "1. The Composed Criterion is deactivated. " |
| 344 | + "2. The Expression is empty. " |
| 345 | + "A Standard 'OR' Expression will be used instead.", |
| 346 | NodeType.WARNING); |
| 347 | } |
| 348 | |
| 349 | this.fireOutputInformationChangedEvent(); |
| 350 | |
| 351 | } |
| 352 | |
| 353 | /** |
| 354 | * {@inheritDoc} |
| 355 | */ |
| 356 | @Override |
| 357 | public void evaluateTerminationCriteria() { |
| 358 | if (this.isInitialized) { |
| 359 | this.iteration = this.optimizer.getIteration(); |
| 360 | |
| 361 | this.currentTime = System.currentTimeMillis(); |
| 362 | |
| 363 | boolean doStop = false; |
| 364 | |
| 365 | if (!this.performManualStop) { |
| 366 | for (ITerminationCriterion tc : this.terminationCriteria) { |
| 367 | tc.evaluate(this.optimizer.getIteration(),this.currentTime); |
| 368 | } |
| 369 | |
| 370 | if (this.isComposedCriterionActive) { |
| 371 | |
| 372 | doStop = this.evaluateExpression(); |
| 373 | |
| 374 | } else { |
| 375 | for (ITerminationCriterion tc : this.terminationCriteria) { |
| 376 | if (tc.getEvaluationResult() && !doStop) { |
| 377 | doStop = true; |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | if (this.performManualStop || (doStop && !this.isInComparisionMode)) { |
| 384 | control.doStop(); |
| 385 | this.fireOutputInformationChangedEvent(); |
| 386 | this.fireOptimizationTerminatedEvent(); |
| 387 | } else { |
| 388 | this.fireOutputInformationChangedEvent(); |
| 389 | } |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | /** |
| 394 | * Perform final Expression consistency check and evaluate it using |
| 395 | * BeanShell. If the check or the evaluation fail, then a simple OR |
| 396 | * Expression is used. |
| 397 | * |
| 398 | * @return the result of the evaluation. True - the optimization must be |
| 399 | * stopped. False - must not be stopped. |
| 400 | */ |
| 401 | private boolean evaluateExpression() { |
| 402 | |
| 403 | String expressionCopy = this.composedCriterionExpression.trim(); |
| 404 | |
| 405 | for (ITerminationCriterion tc : this.terminationCriteria) { |
| 406 | if (expressionCopy.contains(tc.getName().name())) { |
| 407 | expressionCopy = expressionCopy.replace(tc.getName().name(), |
| 408 | Boolean.toString(tc.getEvaluationResult())); |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | if (expressionCopy.contains("_")) { |
| 413 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.ELAPSED_TIME.name(), Boolean.toString(false)); |
| 414 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.GIVEN_PARETO_FRONT_IS_REACHED.name(), Boolean.toString(false)); |
| 415 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.INSIGNIFICANT_PARETO_FRONT_CHANGE.name(), Boolean.toString(false)); |
| 416 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.INSIGNIFICANT_SET_QUALITY_IMPROVEMENT.name(), Boolean.toString(false)); |
| 417 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.MAXIMUM_NUMBER_OF_GENERATIONS.name(), Boolean.toString(false)); |
| 418 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.MINIMAL_QUALITY_CIRTERIA_VALUE.name(), Boolean.toString(false)); |
| 419 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.NO_NEW_PARETO_OPTIMAL_CANDIDATES_FOUND.name(), Boolean.toString(false)); |
| 420 | expressionCopy = expressionCopy.replace(TerminationCriteriaNames.PARETO_OPTIMAL_SET_STABILITY.name(), Boolean.toString(false)); |
| 421 | if (!this.substituteWarningShown) { |
| 422 | this.substituteWarningShown = true; |
| 423 | this.warningsTree.addChild("There is an inactive Termination Criterion referensed in the Composed Criterion Expression. " |
| 424 | + "Its value has been substituted with false.", NodeType.WARNING); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | Interpreter i = new Interpreter(); // Construct an interpreter |
| 429 | boolean evaluationResult = false; |
| 430 | |
| 431 | try { |
| 432 | |
| 433 | i.eval("boolean evalResult = " + expressionCopy + ";"); |
| 434 | evaluationResult = (Boolean) (i.get("evalResult")); |
| 435 | |
| 436 | } catch (EvalError e) { |
| 437 | isComposedCriterionActive = false; |
| 438 | |
| 439 | for (ITerminationCriterion tc : this.terminationCriteria) { |
| 440 | if (tc.getEvaluationResult() && !evaluationResult) { |
| 441 | evaluationResult = true; |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | this.warningsTree.addChild("Composed Criterion Expression cannot be set because of the following reason: " |
| 446 | + "1. The Expression cannot be evaluated because it is malformed. " |
| 447 | + "A Standard 'OR' Expression will be used instead.", NodeType.WARNING); |
| 448 | } |
| 449 | |
| 450 | return evaluationResult; |
| 451 | } |
| 452 | |
| 453 | /** |
| 454 | * {@inheritDoc} |
| 455 | */ |
| 456 | private void fireOutputInformationChangedEvent() { |
| 457 | if (this.isInitialized) { |
| 458 | this.iterationNummberNode.updateValue("Iteration Number: " + this.iteration); |
| 459 | this.candidatesInPopulationNode.updateValue("Candidates in Population: " + this.population.size()); |
| 460 | this.candidatesInArchiveNode.updateValue("All Pareto Optimal Candidates: " + this.archive.size()); |
| 461 | this.useComposedCriterionNode.updateValue("Use Composed Criterion: " + this.isComposedCriterionActive); |
| 462 | this.ComposedCriterionExpressionNode.updateValue("Composed Criterion Expression: " + this.composedCriterionExpression); |
| 463 | this.isRunningInComparisionModeNode.updateValue("Running in Comparision Mode: " + this.isInComparisionMode); |
| 464 | this.manualTerminationRequestedNode.updateValue("Manual Termination requested: " + this.performManualStop); |
| 465 | this.optimizationStoppedNode.updateValue("Optimization Stopped: " + control.isStopped()); |
| 466 | |
| 467 | this.tCriteriaTree.clearChildren(); |
| 468 | for (ITerminationCriterion tc : terminationCriteria) { |
| 469 | tCriteriaTree.attachSubtree(tc.getOutputInformation()); |
| 470 | } |
| 471 | |
| 472 | } |
| 473 | |
| 474 | for (IOutputChangedListener listener : outputChangedListeners) { |
| 475 | listener.handleOutputChangedEvent(outputTree); |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | /** |
| 480 | * Fires a Termination Criteria Manager Initialized event when the TCM is |
| 481 | * initialized. |
| 482 | */ |
| 483 | private void fireTerminationCriteriaManagerInitializedEvent() { |
| 484 | for (ITerminationCriteriaManagerInitializedListener listener : terminationCriteriaManagerInitializedListeners) { |
| 485 | listener.handleTerminationCriteriaManagerInitializedEvent(this); |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | /** |
| 490 | * Fires a Optimization Terminated Event when the Termination Criteria |
| 491 | * Manager decides to stop the optimization. |
| 492 | */ |
| 493 | private void fireOptimizationTerminatedEvent() { |
| 494 | List<IOptimizationTerminatedListener> tempList = new ArrayList<IOptimizationTerminatedListener>( |
| 495 | this.optimizationTerminatedListener); |
| 496 | for (IOptimizationTerminatedListener listener : tempList) { |
| 497 | listener.handleOptimizationTerminatedListener(this); |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | /** |
| 502 | * {@inheritDoc} |
| 503 | * |
| 504 | * If the listener is also a IRequestManualTerminationProvider. the TCM will |
| 505 | * add itself as a listener to that event. |
| 506 | */ |
| 507 | @Override |
| 508 | public void addOutputChangedListener(IOutputChangedListener listener) { |
| 509 | this.outputChangedListeners.add(listener); |
| 510 | if (listener instanceof IRequestManualTerminationProvider) { |
| 511 | ((IRequestManualTerminationProvider) (listener)) |
| 512 | .addRequestManualTerminationListener(this); |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | /** |
| 517 | * {@inheritDoc} |
| 518 | * |
| 519 | * If the listener is also a IRequestManualTerminationProvider. the TCM will |
| 520 | * remove itself as a listener from that event. |
| 521 | */ |
| 522 | @Override |
| 523 | public void removeOutputChangedListener(IOutputChangedListener listener) { |
| 524 | this.outputChangedListeners.remove(listener); |
| 525 | if (listener instanceof IRequestManualTerminationProvider) { |
| 526 | ((IRequestManualTerminationProvider) (listener)) |
| 527 | .removeRequestManualTerminationListener(this); |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | /** |
| 532 | * Adds a new listener for the static TerminationCriteriaManagerInitialized |
| 533 | * event. |
| 534 | * |
| 535 | * @param listener |
| 536 | * ITerminationCriteriaManagerInitializedListener listener |
| 537 | */ |
| 538 | public static void addTerminationCriteriaManagerInitializedListener( |
| 539 | ITerminationCriteriaManagerInitializedListener listener) { |
| 540 | terminationCriteriaManagerInitializedListeners.add(listener); |
| 541 | } |
| 542 | |
| 543 | /** |
| 544 | * Removes a listener from the static TerminationCriteriaManagerInitialized |
| 545 | * event. |
| 546 | * |
| 547 | * @param listener |
| 548 | * ITerminationCriteriaManagerInitializedListener listener |
| 549 | */ |
| 550 | public static void removeTerminationCriteriaManagerInitializedListener( |
| 551 | ITerminationCriteriaManagerInitializedListener listener) { |
| 552 | terminationCriteriaManagerInitializedListeners.remove(listener); |
| 553 | } |
| 554 | |
| 555 | /** |
| 556 | * {@inheritDoc} |
| 557 | */ |
| 558 | @Override |
| 559 | public void iterationComplete(Optimizer optimizer, int iteration) { |
| 560 | if (this.isInitialized) { |
| 561 | this.optimizer = optimizer; |
| 562 | this.evaluateTerminationCriteria(); |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | /** |
| 567 | * {@inheritDoc} |
| 568 | */ |
| 569 | @Override |
| 570 | public void addOptimizationTerminatedListener( |
| 571 | IOptimizationTerminatedListener listener) { |
| 572 | this.optimizationTerminatedListener.add(listener); |
| 573 | } |
| 574 | |
| 575 | /** |
| 576 | * {@inheritDoc} |
| 577 | */ |
| 578 | @Override |
| 579 | public void removeOptimizationTerminatedListener( |
| 580 | IOptimizationTerminatedListener listener) { |
| 581 | this.optimizationTerminatedListener.remove(listener); |
| 582 | } |
| 583 | |
| 584 | /** |
| 585 | * {@inheritDoc} |
| 586 | */ |
| 587 | @Override |
| 588 | public void handleManualTerminationRequest() { |
| 589 | this.performManualStop = true; |
| 590 | this.fireOutputInformationChangedEvent(); |
| 591 | } |
| 592 | |
| 593 | } |