[11492] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
| 3 | * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
| 4 | *
|
---|
| 5 | * This file is part of HeuristicLab.
|
---|
| 6 | *
|
---|
| 7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 8 | * it under the terms of the GNU General Public License as published by
|
---|
| 9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 10 | * (at your option) any later version.
|
---|
| 11 | *
|
---|
| 12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 15 | * GNU General Public License for more details.
|
---|
| 16 | *
|
---|
| 17 | * You should have received a copy of the GNU General Public License
|
---|
| 18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #endregion
|
---|
| 21 |
|
---|
| 22 | using System;
|
---|
| 23 | using System.Linq;
|
---|
| 24 | using HeuristicLab.Analysis;
|
---|
| 25 | using HeuristicLab.Common;
|
---|
| 26 | using HeuristicLab.Core;
|
---|
| 27 | using HeuristicLab.Data;
|
---|
| 28 | using HeuristicLab.Operators;
|
---|
| 29 | using HeuristicLab.Optimization;
|
---|
| 30 | using HeuristicLab.Optimization.Operators;
|
---|
| 31 | using HeuristicLab.Parameters;
|
---|
| 32 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
| 33 | using HeuristicLab.PluginInfrastructure;
|
---|
| 34 | using HeuristicLab.Random;
|
---|
| 35 |
|
---|
| 36 | namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
|
---|
| 37 | /// <summary>
|
---|
| 38 | /// An offspring selection genetic algorithm.
|
---|
| 39 | /// </summary>
|
---|
[11510] | 40 | [Item("VOSGA", "An OSGA with selectable OS criteria and automtic crossover/mutation selection.")]
|
---|
[11492] | 41 | [Creatable("Algorithms")]
|
---|
| 42 | [StorableClass]
|
---|
[11510] | 43 | public sealed class VOffspringSelectionGeneticAlgorithm : HeuristicOptimizationEngineAlgorithm, IStorableContent {
|
---|
[11492] | 44 | public string Filename { get; set; }
|
---|
| 45 |
|
---|
| 46 | #region Problem Properties
|
---|
| 47 | public override Type ProblemType {
|
---|
| 48 | get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); }
|
---|
| 49 | }
|
---|
| 50 | public new ISingleObjectiveHeuristicOptimizationProblem Problem {
|
---|
| 51 | get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
|
---|
| 52 | set { base.Problem = value; }
|
---|
| 53 | }
|
---|
| 54 | #endregion
|
---|
| 55 |
|
---|
| 56 | #region Parameter Properties
|
---|
| 57 | private ValueParameter<IntValue> SeedParameter {
|
---|
| 58 | get { return (ValueParameter<IntValue>)Parameters["Seed"]; }
|
---|
| 59 | }
|
---|
| 60 | private ValueParameter<BoolValue> SetSeedRandomlyParameter {
|
---|
| 61 | get { return (ValueParameter<BoolValue>)Parameters["SetSeedRandomly"]; }
|
---|
| 62 | }
|
---|
| 63 | private ValueParameter<IntValue> PopulationSizeParameter {
|
---|
| 64 | get { return (ValueParameter<IntValue>)Parameters["PopulationSize"]; }
|
---|
| 65 | }
|
---|
| 66 | public IConstrainedValueParameter<ISelector> SelectorParameter {
|
---|
| 67 | get { return (IConstrainedValueParameter<ISelector>)Parameters["Selector"]; }
|
---|
| 68 | }
|
---|
| 69 | public IConstrainedValueParameter<ICrossover> CrossoverParameter {
|
---|
| 70 | get { return (IConstrainedValueParameter<ICrossover>)Parameters["Crossover"]; }
|
---|
| 71 | }
|
---|
| 72 | private ValueParameter<PercentValue> MutationProbabilityParameter {
|
---|
| 73 | get { return (ValueParameter<PercentValue>)Parameters["MutationProbability"]; }
|
---|
| 74 | }
|
---|
| 75 | public IConstrainedValueParameter<IManipulator> MutatorParameter {
|
---|
| 76 | get { return (IConstrainedValueParameter<IManipulator>)Parameters["Mutator"]; }
|
---|
| 77 | }
|
---|
| 78 | private ValueParameter<IntValue> ElitesParameter {
|
---|
| 79 | get { return (ValueParameter<IntValue>)Parameters["Elites"]; }
|
---|
| 80 | }
|
---|
| 81 | private IFixedValueParameter<BoolValue> ReevaluateElitesParameter {
|
---|
| 82 | get { return (IFixedValueParameter<BoolValue>)Parameters["ReevaluateElites"]; }
|
---|
| 83 | }
|
---|
| 84 | private ValueParameter<IntValue> MaximumGenerationsParameter {
|
---|
| 85 | get { return (ValueParameter<IntValue>)Parameters["MaximumGenerations"]; }
|
---|
| 86 | }
|
---|
| 87 | private ValueLookupParameter<DoubleValue> SuccessRatioParameter {
|
---|
| 88 | get { return (ValueLookupParameter<DoubleValue>)Parameters["SuccessRatio"]; }
|
---|
| 89 | }
|
---|
| 90 | private ValueLookupParameter<DoubleValue> ComparisonFactorLowerBoundParameter {
|
---|
| 91 | get { return (ValueLookupParameter<DoubleValue>)Parameters["ComparisonFactorLowerBound"]; }
|
---|
| 92 | }
|
---|
| 93 | private ValueLookupParameter<DoubleValue> ComparisonFactorUpperBoundParameter {
|
---|
| 94 | get { return (ValueLookupParameter<DoubleValue>)Parameters["ComparisonFactorUpperBound"]; }
|
---|
| 95 | }
|
---|
| 96 | public IConstrainedValueParameter<IDiscreteDoubleValueModifier> ComparisonFactorModifierParameter {
|
---|
| 97 | get { return (IConstrainedValueParameter<IDiscreteDoubleValueModifier>)Parameters["ComparisonFactorModifier"]; }
|
---|
| 98 | }
|
---|
| 99 | private ValueLookupParameter<DoubleValue> MaximumSelectionPressureParameter {
|
---|
| 100 | get { return (ValueLookupParameter<DoubleValue>)Parameters["MaximumSelectionPressure"]; }
|
---|
| 101 | }
|
---|
| 102 | private ValueLookupParameter<BoolValue> OffspringSelectionBeforeMutationParameter {
|
---|
| 103 | get { return (ValueLookupParameter<BoolValue>)Parameters["OffspringSelectionBeforeMutation"]; }
|
---|
| 104 | }
|
---|
| 105 | private ValueLookupParameter<IntValue> SelectedParentsParameter {
|
---|
| 106 | get { return (ValueLookupParameter<IntValue>)Parameters["SelectedParents"]; }
|
---|
| 107 | }
|
---|
| 108 | private ValueParameter<MultiAnalyzer> AnalyzerParameter {
|
---|
| 109 | get { return (ValueParameter<MultiAnalyzer>)Parameters["Analyzer"]; }
|
---|
| 110 | }
|
---|
| 111 | private ValueParameter<IntValue> MaximumEvaluatedSolutionsParameter {
|
---|
| 112 | get { return (ValueParameter<IntValue>)Parameters["MaximumEvaluatedSolutions"]; }
|
---|
| 113 | }
|
---|
| 114 | private IFixedValueParameter<BoolValue> FillPopulationWithParentsParameter {
|
---|
| 115 | get { return (IFixedValueParameter<BoolValue>)Parameters["FillPopulationWithParents"]; }
|
---|
| 116 | }
|
---|
[11510] | 117 | public IConstrainedValueParameter<IOffspringSelector> OffspringSelectorParameter {
|
---|
| 118 | get { return (IConstrainedValueParameter<IOffspringSelector>)Parameters["OffspringSelector"]; }
|
---|
| 119 | }
|
---|
[11513] | 120 | public ConstrainedValueParameter<ISubScopesQualityComparatorOperator> SubScopesQualityComparatorParameter {
|
---|
| 121 | get { return (ConstrainedValueParameter<ISubScopesQualityComparatorOperator>)Parameters["SubScopesQualityComparator"]; }
|
---|
| 122 | }
|
---|
[11516] | 123 | public IConstrainedValueParameter<ISingleObjectiveSolutionSimilarityCalculator> SimilarityCalculatorParameter {
|
---|
| 124 | get { return (IConstrainedValueParameter<ISingleObjectiveSolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
|
---|
| 125 | }
|
---|
[11492] | 126 | #endregion
|
---|
| 127 |
|
---|
| 128 | #region Properties
|
---|
| 129 | public IntValue Seed {
|
---|
| 130 | get { return SeedParameter.Value; }
|
---|
| 131 | set { SeedParameter.Value = value; }
|
---|
| 132 | }
|
---|
| 133 | public BoolValue SetSeedRandomly {
|
---|
| 134 | get { return SetSeedRandomlyParameter.Value; }
|
---|
| 135 | set { SetSeedRandomlyParameter.Value = value; }
|
---|
| 136 | }
|
---|
| 137 | public IntValue PopulationSize {
|
---|
| 138 | get { return PopulationSizeParameter.Value; }
|
---|
| 139 | set { PopulationSizeParameter.Value = value; }
|
---|
| 140 | }
|
---|
| 141 | public ISelector Selector {
|
---|
| 142 | get { return SelectorParameter.Value; }
|
---|
| 143 | set { SelectorParameter.Value = value; }
|
---|
| 144 | }
|
---|
[11510] | 145 | public IOffspringSelector OffspringSelector {
|
---|
| 146 | get { return OffspringSelectorParameter.Value; }
|
---|
| 147 | set { OffspringSelectorParameter.Value = value; }
|
---|
| 148 | }
|
---|
[11492] | 149 | public ICrossover Crossover {
|
---|
| 150 | get { return CrossoverParameter.Value; }
|
---|
| 151 | set { CrossoverParameter.Value = value; }
|
---|
| 152 | }
|
---|
| 153 | public PercentValue MutationProbability {
|
---|
| 154 | get { return MutationProbabilityParameter.Value; }
|
---|
| 155 | set { MutationProbabilityParameter.Value = value; }
|
---|
| 156 | }
|
---|
| 157 | public IManipulator Mutator {
|
---|
| 158 | get { return MutatorParameter.Value; }
|
---|
| 159 | set { MutatorParameter.Value = value; }
|
---|
| 160 | }
|
---|
| 161 | public IntValue Elites {
|
---|
| 162 | get { return ElitesParameter.Value; }
|
---|
| 163 | set { ElitesParameter.Value = value; }
|
---|
| 164 | }
|
---|
| 165 | public bool ReevaluteElites {
|
---|
| 166 | get { return ReevaluateElitesParameter.Value.Value; }
|
---|
| 167 | set { ReevaluateElitesParameter.Value.Value = value; }
|
---|
| 168 | }
|
---|
| 169 | public IntValue MaximumGenerations {
|
---|
| 170 | get { return MaximumGenerationsParameter.Value; }
|
---|
| 171 | set { MaximumGenerationsParameter.Value = value; }
|
---|
| 172 | }
|
---|
| 173 | public DoubleValue SuccessRatio {
|
---|
| 174 | get { return SuccessRatioParameter.Value; }
|
---|
| 175 | set { SuccessRatioParameter.Value = value; }
|
---|
| 176 | }
|
---|
| 177 | public DoubleValue ComparisonFactorLowerBound {
|
---|
| 178 | get { return ComparisonFactorLowerBoundParameter.Value; }
|
---|
| 179 | set { ComparisonFactorLowerBoundParameter.Value = value; }
|
---|
| 180 | }
|
---|
| 181 | public DoubleValue ComparisonFactorUpperBound {
|
---|
| 182 | get { return ComparisonFactorUpperBoundParameter.Value; }
|
---|
| 183 | set { ComparisonFactorUpperBoundParameter.Value = value; }
|
---|
| 184 | }
|
---|
| 185 | public IDiscreteDoubleValueModifier ComparisonFactorModifier {
|
---|
| 186 | get { return ComparisonFactorModifierParameter.Value; }
|
---|
| 187 | set { ComparisonFactorModifierParameter.Value = value; }
|
---|
| 188 | }
|
---|
| 189 | public DoubleValue MaximumSelectionPressure {
|
---|
| 190 | get { return MaximumSelectionPressureParameter.Value; }
|
---|
| 191 | set { MaximumSelectionPressureParameter.Value = value; }
|
---|
| 192 | }
|
---|
| 193 | public BoolValue OffspringSelectionBeforeMutation {
|
---|
| 194 | get { return OffspringSelectionBeforeMutationParameter.Value; }
|
---|
| 195 | set { OffspringSelectionBeforeMutationParameter.Value = value; }
|
---|
| 196 | }
|
---|
| 197 | public IntValue SelectedParents {
|
---|
| 198 | get { return SelectedParentsParameter.Value; }
|
---|
| 199 | set { SelectedParentsParameter.Value = value; }
|
---|
| 200 | }
|
---|
| 201 | public MultiAnalyzer Analyzer {
|
---|
| 202 | get { return AnalyzerParameter.Value; }
|
---|
| 203 | set { AnalyzerParameter.Value = value; }
|
---|
| 204 | }
|
---|
| 205 | public IntValue MaximumEvaluatedSolutions {
|
---|
| 206 | get { return MaximumEvaluatedSolutionsParameter.Value; }
|
---|
| 207 | set { MaximumEvaluatedSolutionsParameter.Value = value; }
|
---|
| 208 | }
|
---|
| 209 | public bool FillPopulationWithParents {
|
---|
| 210 | get { return FillPopulationWithParentsParameter.Value.Value; }
|
---|
| 211 | set { FillPopulationWithParentsParameter.Value.Value = value; }
|
---|
| 212 | }
|
---|
[11513] | 213 | public ISubScopesQualityComparatorOperator SubScopesQualityComparator {
|
---|
| 214 | get { return SubScopesQualityComparatorParameter.Value; }
|
---|
| 215 | set { SubScopesQualityComparatorParameter.Value = value; }
|
---|
| 216 | }
|
---|
| 217 |
|
---|
[11492] | 218 | private RandomCreator RandomCreator {
|
---|
| 219 | get { return (RandomCreator)OperatorGraph.InitialOperator; }
|
---|
| 220 | }
|
---|
| 221 | private SolutionsCreator SolutionsCreator {
|
---|
| 222 | get { return (SolutionsCreator)RandomCreator.Successor; }
|
---|
| 223 | }
|
---|
[11516] | 224 | public ISingleObjectiveSolutionSimilarityCalculator SimilarityCalculator {
|
---|
| 225 | get { return SimilarityCalculatorParameter.Value; }
|
---|
| 226 | set { SimilarityCalculatorParameter.Value = value; }
|
---|
| 227 | }
|
---|
[11510] | 228 | private VOffspringSelectionGeneticAlgorithmMainLoop MainLoop {
|
---|
[11492] | 229 | get { return FindMainLoop(SolutionsCreator.Successor); }
|
---|
| 230 | }
|
---|
| 231 | [Storable]
|
---|
| 232 | private BestAverageWorstQualityAnalyzer qualityAnalyzer;
|
---|
| 233 | [Storable]
|
---|
| 234 | private ValueAnalyzer selectionPressureAnalyzer;
|
---|
| 235 | [Storable]
|
---|
| 236 | private SuccessfulOffspringAnalyzer successfulOffspringAnalyzer;
|
---|
| 237 | #endregion
|
---|
| 238 |
|
---|
| 239 | [StorableConstructor]
|
---|
[11510] | 240 | private VOffspringSelectionGeneticAlgorithm(bool deserializing) : base(deserializing) { }
|
---|
[11492] | 241 | [StorableHook(HookType.AfterDeserialization)]
|
---|
| 242 | private void AfterDeserialization() {
|
---|
| 243 | // BackwardsCompatibility3.3
|
---|
| 244 | #region Backwards compatible code, remove with 3.4
|
---|
| 245 | if (successfulOffspringAnalyzer == null)
|
---|
| 246 | successfulOffspringAnalyzer = new SuccessfulOffspringAnalyzer();
|
---|
| 247 | if (!Parameters.ContainsKey("ReevaluateElites")) {
|
---|
| 248 | Parameters.Add(new FixedValueParameter<BoolValue>("ReevaluateElites", "Flag to determine if elite individuals should be reevaluated (i.e., if stochastic fitness functions are used.)", (BoolValue)new BoolValue(false).AsReadOnly()) { Hidden = true });
|
---|
| 249 | }
|
---|
| 250 | if (!Parameters.ContainsKey("FillPopulationWithParents"))
|
---|
| 251 | Parameters.Add(new FixedValueParameter<BoolValue>("FillPopulationWithParents", "True if the population should be filled with parent individual or false if worse children should be used when the maximum selection pressure is exceeded.", new BoolValue(false)) { Hidden = true });
|
---|
| 252 | #endregion
|
---|
| 253 |
|
---|
| 254 | Initialize();
|
---|
| 255 | }
|
---|
[11510] | 256 | private VOffspringSelectionGeneticAlgorithm(VOffspringSelectionGeneticAlgorithm original, Cloner cloner)
|
---|
[11492] | 257 | : base(original, cloner) {
|
---|
| 258 | qualityAnalyzer = cloner.Clone(original.qualityAnalyzer);
|
---|
| 259 | selectionPressureAnalyzer = cloner.Clone(original.selectionPressureAnalyzer);
|
---|
| 260 | successfulOffspringAnalyzer = cloner.Clone(original.successfulOffspringAnalyzer);
|
---|
| 261 | Initialize();
|
---|
| 262 | }
|
---|
| 263 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
[11510] | 264 | return new VOffspringSelectionGeneticAlgorithm(this, cloner);
|
---|
[11492] | 265 | }
|
---|
[11510] | 266 | public VOffspringSelectionGeneticAlgorithm()
|
---|
[11492] | 267 | : base() {
|
---|
| 268 | Parameters.Add(new ValueParameter<IntValue>("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
|
---|
| 269 | Parameters.Add(new ValueParameter<BoolValue>("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
|
---|
| 270 | Parameters.Add(new ValueParameter<IntValue>("PopulationSize", "The size of the population of solutions.", new IntValue(100)));
|
---|
| 271 | Parameters.Add(new ConstrainedValueParameter<ISelector>("Selector", "The operator used to select solutions for reproduction."));
|
---|
| 272 | Parameters.Add(new ConstrainedValueParameter<ICrossover>("Crossover", "The operator used to cross solutions."));
|
---|
| 273 | Parameters.Add(new ValueParameter<PercentValue>("MutationProbability", "The probability that the mutation operator is applied on a solution.", new PercentValue(0.05)));
|
---|
| 274 | Parameters.Add(new OptionalConstrainedValueParameter<IManipulator>("Mutator", "The operator used to mutate solutions."));
|
---|
| 275 | Parameters.Add(new ValueParameter<IntValue>("Elites", "The numer of elite solutions which are kept in each generation.", new IntValue(1)));
|
---|
| 276 | Parameters.Add(new FixedValueParameter<BoolValue>("ReevaluateElites", "Flag to determine if elite individuals should be reevaluated (i.e., if stochastic fitness functions are used.)", new BoolValue(false)) { Hidden = true });
|
---|
| 277 | Parameters.Add(new ValueParameter<IntValue>("MaximumGenerations", "The maximum number of generations which should be processed.", new IntValue(1000)));
|
---|
| 278 | Parameters.Add(new ValueLookupParameter<DoubleValue>("SuccessRatio", "The ratio of successful to total children that should be achieved.", new DoubleValue(1)));
|
---|
| 279 | Parameters.Add(new ValueLookupParameter<DoubleValue>("ComparisonFactorLowerBound", "The lower bound of the comparison factor (start).", new DoubleValue(0)));
|
---|
| 280 | Parameters.Add(new ValueLookupParameter<DoubleValue>("ComparisonFactorUpperBound", "The upper bound of the comparison factor (end).", new DoubleValue(1)));
|
---|
| 281 | Parameters.Add(new OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>("ComparisonFactorModifier", "The operator used to modify the comparison factor.", new ItemSet<IDiscreteDoubleValueModifier>(new IDiscreteDoubleValueModifier[] { new LinearDiscreteDoubleValueModifier() }), new LinearDiscreteDoubleValueModifier()));
|
---|
| 282 | Parameters.Add(new ValueLookupParameter<DoubleValue>("MaximumSelectionPressure", "The maximum selection pressure that terminates the algorithm.", new DoubleValue(100)));
|
---|
| 283 | Parameters.Add(new ValueLookupParameter<BoolValue>("OffspringSelectionBeforeMutation", "True if the offspring selection step should be applied before mutation, false if it should be applied after mutation.", new BoolValue(false)));
|
---|
| 284 | Parameters.Add(new ValueLookupParameter<IntValue>("SelectedParents", "How much parents should be selected each time the offspring selection step is performed until the population is filled. This parameter should be about the same or twice the size of PopulationSize for smaller problems, and less for large problems.", new IntValue(200)));
|
---|
| 285 | Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze each generation.", new MultiAnalyzer()));
|
---|
| 286 | Parameters.Add(new ValueParameter<IntValue>("MaximumEvaluatedSolutions", "The maximum number of evaluated solutions (approximately).", new IntValue(int.MaxValue)));
|
---|
| 287 | Parameters.Add(new FixedValueParameter<BoolValue>("FillPopulationWithParents", "True if the population should be filled with parent individual or false if worse children should be used when the maximum selection pressure is exceeded.", new BoolValue(false)) { Hidden = true });
|
---|
[11510] | 288 | Parameters.Add(new ConstrainedValueParameter<IOffspringSelector>("OffspringSelector", "The operator used as selection criterea for deciding which individuals are successful and which should be disgarded."));
|
---|
[11513] | 289 | Parameters.Add(new ConstrainedValueParameter<ISubScopesQualityComparatorOperator>("SubScopesQualityComparator", "The operator used to compare solution candidates with."));
|
---|
[11516] | 290 | Parameters.Add(new ConstrainedValueParameter<ISingleObjectiveSolutionSimilarityCalculator>("SimilarityCalculator", "The operator used to calculate the similarity between two solutions."));
|
---|
[11492] | 291 |
|
---|
| 292 | RandomCreator randomCreator = new RandomCreator();
|
---|
| 293 | SolutionsCreator solutionsCreator = new SolutionsCreator();
|
---|
| 294 | SubScopesCounter subScopesCounter = new SubScopesCounter();
|
---|
| 295 | ResultsCollector resultsCollector = new ResultsCollector();
|
---|
[11510] | 296 | VOffspringSelectionGeneticAlgorithmMainLoop mainLoop = new VOffspringSelectionGeneticAlgorithmMainLoop();
|
---|
[11492] | 297 | OperatorGraph.InitialOperator = randomCreator;
|
---|
| 298 |
|
---|
| 299 | randomCreator.RandomParameter.ActualName = "Random";
|
---|
| 300 | randomCreator.SeedParameter.ActualName = SeedParameter.Name;
|
---|
| 301 | randomCreator.SeedParameter.Value = null;
|
---|
| 302 | randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameter.Name;
|
---|
| 303 | randomCreator.SetSeedRandomlyParameter.Value = null;
|
---|
| 304 | randomCreator.Successor = solutionsCreator;
|
---|
| 305 |
|
---|
| 306 | solutionsCreator.NumberOfSolutionsParameter.ActualName = PopulationSizeParameter.Name;
|
---|
| 307 | solutionsCreator.Successor = subScopesCounter;
|
---|
| 308 |
|
---|
| 309 | subScopesCounter.Name = "Initialize EvaluatedSolutions";
|
---|
| 310 | subScopesCounter.ValueParameter.ActualName = "EvaluatedSolutions";
|
---|
| 311 | subScopesCounter.Successor = resultsCollector;
|
---|
| 312 |
|
---|
| 313 | resultsCollector.CollectedValues.Add(new LookupParameter<IntValue>("Evaluated Solutions", "", "EvaluatedSolutions"));
|
---|
| 314 | resultsCollector.ResultsParameter.ActualName = "Results";
|
---|
| 315 | resultsCollector.Successor = mainLoop;
|
---|
| 316 |
|
---|
| 317 | mainLoop.AnalyzerParameter.ActualName = AnalyzerParameter.Name;
|
---|
| 318 | mainLoop.ComparisonFactorModifierParameter.ActualName = ComparisonFactorModifierParameter.Name;
|
---|
| 319 | mainLoop.ComparisonFactorParameter.ActualName = "ComparisonFactor";
|
---|
| 320 | mainLoop.ComparisonFactorStartParameter.ActualName = ComparisonFactorLowerBoundParameter.Name;
|
---|
| 321 | mainLoop.CrossoverParameter.ActualName = CrossoverParameter.Name;
|
---|
| 322 | mainLoop.ElitesParameter.ActualName = ElitesParameter.Name;
|
---|
| 323 | mainLoop.ReevaluateElitesParameter.ActualName = ReevaluateElitesParameter.Name;
|
---|
| 324 | mainLoop.EvaluatedSolutionsParameter.ActualName = "EvaluatedSolutions";
|
---|
| 325 | mainLoop.MaximumGenerationsParameter.ActualName = MaximumGenerationsParameter.Name;
|
---|
| 326 | mainLoop.MaximumSelectionPressureParameter.ActualName = MaximumSelectionPressureParameter.Name;
|
---|
| 327 | mainLoop.MutationProbabilityParameter.ActualName = MutationProbabilityParameter.Name;
|
---|
| 328 | mainLoop.MutatorParameter.ActualName = MutatorParameter.Name;
|
---|
| 329 | mainLoop.OffspringSelectionBeforeMutationParameter.ActualName = OffspringSelectionBeforeMutationParameter.Name;
|
---|
| 330 | mainLoop.RandomParameter.ActualName = RandomCreator.RandomParameter.ActualName;
|
---|
| 331 | mainLoop.ResultsParameter.ActualName = "Results";
|
---|
| 332 | mainLoop.SelectorParameter.ActualName = SelectorParameter.Name;
|
---|
| 333 | mainLoop.SuccessRatioParameter.ActualName = SuccessRatioParameter.Name;
|
---|
| 334 | mainLoop.FillPopulationWithParentsParameter.ActualName = FillPopulationWithParentsParameter.Name;
|
---|
| 335 |
|
---|
| 336 | foreach (ISelector selector in ApplicationManager.Manager.GetInstances<ISelector>().Where(x => !(x is IMultiObjectiveSelector)).OrderBy(x => x.Name))
|
---|
| 337 | SelectorParameter.ValidValues.Add(selector);
|
---|
| 338 | ISelector proportionalSelector = SelectorParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("ProportionalSelector"));
|
---|
| 339 | if (proportionalSelector != null) SelectorParameter.Value = proportionalSelector;
|
---|
| 340 | ParameterizeSelectors();
|
---|
| 341 |
|
---|
| 342 | foreach (IDiscreteDoubleValueModifier modifier in ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>().OrderBy(x => x.Name))
|
---|
| 343 | ComparisonFactorModifierParameter.ValidValues.Add(modifier);
|
---|
| 344 | IDiscreteDoubleValueModifier linearModifier = ComparisonFactorModifierParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("LinearDiscreteDoubleValueModifier"));
|
---|
| 345 | if (linearModifier != null) ComparisonFactorModifierParameter.Value = linearModifier;
|
---|
| 346 | ParameterizeComparisonFactorModifiers();
|
---|
| 347 |
|
---|
[11510] | 348 | foreach (IOffspringSelector selector in ApplicationManager.Manager.GetInstances<IOffspringSelector>().OrderBy(x => x.Name))
|
---|
| 349 | OffspringSelectorParameter.ValidValues.Add(selector);
|
---|
| 350 | IOffspringSelector standardOffspringSelector = OffspringSelectorParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("StandardOffspringSelector"));
|
---|
| 351 | if (standardOffspringSelector != null) OffspringSelectorParameter.Value = standardOffspringSelector;
|
---|
| 352 | ParameterizeOffspringSelectors();
|
---|
| 353 |
|
---|
[11513] | 354 | foreach (ISubScopesQualityComparatorOperator comparator in ApplicationManager.Manager.GetInstances<ISubScopesQualityComparatorOperator>().OrderBy(x => x.Name))
|
---|
| 355 | SubScopesQualityComparatorParameter.ValidValues.Add(comparator);
|
---|
| 356 | ISubScopesQualityComparatorOperator standardComparator = SubScopesQualityComparatorParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("WeightedParentsQualityComparator"));
|
---|
| 357 | if (standardComparator != null) SubScopesQualityComparatorParameter.Value = standardComparator;
|
---|
| 358 | ParameterizeSubScopesQualityComparators();
|
---|
| 359 |
|
---|
[11492] | 360 | qualityAnalyzer = new BestAverageWorstQualityAnalyzer();
|
---|
| 361 | selectionPressureAnalyzer = new ValueAnalyzer();
|
---|
| 362 | successfulOffspringAnalyzer = new SuccessfulOffspringAnalyzer();
|
---|
| 363 | ParameterizeAnalyzers();
|
---|
| 364 | UpdateAnalyzers();
|
---|
| 365 |
|
---|
| 366 | Initialize();
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | public override void Prepare() {
|
---|
| 370 | if (Problem != null) base.Prepare();
|
---|
| 371 | }
|
---|
| 372 |
|
---|
| 373 | #region Events
|
---|
| 374 | protected override void OnProblemChanged() {
|
---|
| 375 | ParameterizeStochasticOperator(Problem.SolutionCreator);
|
---|
| 376 | ParameterizeStochasticOperator(Problem.Evaluator);
|
---|
| 377 | foreach (IOperator op in Problem.Operators.OfType<IOperator>()) ParameterizeStochasticOperator(op);
|
---|
| 378 | ParameterizeSolutionsCreator();
|
---|
| 379 | ParameterizMainLoop();
|
---|
| 380 | ParameterizeSelectors();
|
---|
| 381 | ParameterizeAnalyzers();
|
---|
| 382 | ParameterizeIterationBasedOperators();
|
---|
| 383 | UpdateCrossovers();
|
---|
| 384 | UpdateMutators();
|
---|
| 385 | UpdateAnalyzers();
|
---|
[11513] | 386 | ParameterizeSubScopesQualityComparators();
|
---|
| 387 | ParameterizeOffspringSelectors();
|
---|
[11516] | 388 | UpdateSimilarityCalculators();
|
---|
[11492] | 389 | Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
|
---|
| 390 | base.OnProblemChanged();
|
---|
| 391 | }
|
---|
| 392 |
|
---|
| 393 | protected override void Problem_SolutionCreatorChanged(object sender, EventArgs e) {
|
---|
| 394 | ParameterizeStochasticOperator(Problem.SolutionCreator);
|
---|
| 395 | ParameterizeSolutionsCreator();
|
---|
| 396 | base.Problem_SolutionCreatorChanged(sender, e);
|
---|
| 397 | }
|
---|
| 398 | protected override void Problem_EvaluatorChanged(object sender, EventArgs e) {
|
---|
| 399 | ParameterizeStochasticOperator(Problem.Evaluator);
|
---|
| 400 | ParameterizeSolutionsCreator();
|
---|
| 401 | ParameterizMainLoop();
|
---|
| 402 | ParameterizeSelectors();
|
---|
| 403 | ParameterizeAnalyzers();
|
---|
| 404 | Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
|
---|
| 405 | base.Problem_EvaluatorChanged(sender, e);
|
---|
| 406 | }
|
---|
| 407 | protected override void Problem_OperatorsChanged(object sender, EventArgs e) {
|
---|
| 408 | foreach (IOperator op in Problem.Operators.OfType<IOperator>()) ParameterizeStochasticOperator(op);
|
---|
| 409 | ParameterizeIterationBasedOperators();
|
---|
| 410 | UpdateCrossovers();
|
---|
| 411 | UpdateMutators();
|
---|
| 412 | UpdateAnalyzers();
|
---|
| 413 | base.Problem_OperatorsChanged(sender, e);
|
---|
| 414 | }
|
---|
| 415 | private void ElitesParameter_ValueChanged(object sender, EventArgs e) {
|
---|
| 416 | Elites.ValueChanged += new EventHandler(Elites_ValueChanged);
|
---|
| 417 | ParameterizeSelectors();
|
---|
| 418 | }
|
---|
| 419 | private void Elites_ValueChanged(object sender, EventArgs e) {
|
---|
| 420 | ParameterizeSelectors();
|
---|
| 421 | }
|
---|
| 422 | private void PopulationSizeParameter_ValueChanged(object sender, EventArgs e) {
|
---|
| 423 | PopulationSize.ValueChanged += new EventHandler(PopulationSize_ValueChanged);
|
---|
| 424 | ParameterizeSelectors();
|
---|
| 425 | }
|
---|
| 426 | private void PopulationSize_ValueChanged(object sender, EventArgs e) {
|
---|
| 427 | ParameterizeSelectors();
|
---|
| 428 | }
|
---|
| 429 | private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
|
---|
| 430 | ParameterizMainLoop();
|
---|
| 431 | ParameterizeSelectors();
|
---|
| 432 | ParameterizeAnalyzers();
|
---|
[11516] | 433 | ParameterizeSimilarityCalculators();
|
---|
[11492] | 434 | }
|
---|
| 435 | #endregion
|
---|
| 436 |
|
---|
| 437 | #region Helpers
|
---|
| 438 | private void Initialize() {
|
---|
| 439 | PopulationSizeParameter.ValueChanged += new EventHandler(PopulationSizeParameter_ValueChanged);
|
---|
| 440 | PopulationSize.ValueChanged += new EventHandler(PopulationSize_ValueChanged);
|
---|
| 441 | ElitesParameter.ValueChanged += new EventHandler(ElitesParameter_ValueChanged);
|
---|
| 442 | Elites.ValueChanged += new EventHandler(Elites_ValueChanged);
|
---|
| 443 | if (Problem != null) {
|
---|
| 444 | Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
|
---|
| 445 | }
|
---|
| 446 | }
|
---|
| 447 | private void ParameterizeSolutionsCreator() {
|
---|
| 448 | SolutionsCreator.EvaluatorParameter.ActualName = Problem.EvaluatorParameter.Name;
|
---|
| 449 | SolutionsCreator.SolutionCreatorParameter.ActualName = Problem.SolutionCreatorParameter.Name;
|
---|
| 450 | }
|
---|
| 451 | private void ParameterizMainLoop() {
|
---|
| 452 | MainLoop.EvaluatorParameter.ActualName = Problem.EvaluatorParameter.Name;
|
---|
| 453 | MainLoop.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
|
---|
| 454 | MainLoop.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
|
---|
| 455 | }
|
---|
| 456 | private void ParameterizeStochasticOperator(IOperator op) {
|
---|
| 457 | if (op is IStochasticOperator)
|
---|
| 458 | ((IStochasticOperator)op).RandomParameter.ActualName = RandomCreator.RandomParameter.ActualName;
|
---|
| 459 | }
|
---|
| 460 | private void ParameterizeSelectors() {
|
---|
| 461 | foreach (ISelector selector in SelectorParameter.ValidValues) {
|
---|
| 462 | selector.CopySelected = new BoolValue(true);
|
---|
| 463 | selector.NumberOfSelectedSubScopesParameter.Value = null;
|
---|
| 464 | selector.NumberOfSelectedSubScopesParameter.ActualName = SelectedParentsParameter.Name;
|
---|
| 465 | ParameterizeStochasticOperator(selector);
|
---|
| 466 | }
|
---|
| 467 | if (Problem != null) {
|
---|
| 468 | foreach (ISingleObjectiveSelector selector in SelectorParameter.ValidValues.OfType<ISingleObjectiveSelector>()) {
|
---|
| 469 | selector.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
|
---|
| 470 | selector.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
|
---|
| 471 | }
|
---|
| 472 | }
|
---|
| 473 | }
|
---|
[11510] | 474 | private void ParameterizeOffspringSelectors() {
|
---|
| 475 | foreach (IOffspringSelector selector in OffspringSelectorParameter.ValidValues) {
|
---|
| 476 | //TODO: do we need to set these parameters? if yes, where?
|
---|
| 477 | // selector.CurrentSuccessRatioParameter.ActualName = CurrentSuccessRatioParameter.Name;
|
---|
| 478 | //selector.SelectionPressureParameter.ActualName = SelectionPressureParameter.Name;
|
---|
| 479 | selector.MaximumSelectionPressureParameter.ActualName = MaximumSelectionPressureParameter.Name;
|
---|
| 480 | selector.SuccessRatioParameter.ActualName = SuccessRatioParameter.Name;
|
---|
| 481 | selector.OffspringPopulationParameter.ActualName = "OffspringPopulation";
|
---|
| 482 | selector.OffspringPopulationWinnersParameter.ActualName = "OffspringPopulationWinners";
|
---|
| 483 | selector.SuccessfulOffspringParameter.ActualName = "SuccessfulOffspring";
|
---|
| 484 | selector.FillPopulationWithParentsParameter.ActualName = FillPopulationWithParentsParameter.Name;
|
---|
| 485 | }
|
---|
| 486 | }
|
---|
[11513] | 487 | private void ParameterizeSubScopesQualityComparators() {
|
---|
| 488 | foreach (var comp in SubScopesQualityComparatorParameter.ValidValues) {
|
---|
| 489 | comp.ComparisonFactorParameter.ActualName = "ComparisonFactor";
|
---|
| 490 | if (Problem != null) {
|
---|
| 491 | comp.LeftSideParameter.ActualName = Problem.Evaluator.QualityParameter.Name;
|
---|
| 492 | comp.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
|
---|
| 493 | comp.RightSideParameter.ActualName = Problem.Evaluator.QualityParameter.Name;
|
---|
| 494 | }
|
---|
| 495 | comp.ResultParameter.ActualName = "SuccessfulOffspring";
|
---|
| 496 | }
|
---|
| 497 | }
|
---|
[11492] | 498 | private void ParameterizeAnalyzers() {
|
---|
| 499 | qualityAnalyzer.ResultsParameter.ActualName = "Results";
|
---|
| 500 | selectionPressureAnalyzer.Name = "SelectionPressure Analyzer";
|
---|
| 501 | selectionPressureAnalyzer.ResultsParameter.ActualName = "Results";
|
---|
| 502 | selectionPressureAnalyzer.ValueParameter.ActualName = "SelectionPressure";
|
---|
| 503 | selectionPressureAnalyzer.ValueParameter.Depth = 0;
|
---|
| 504 | selectionPressureAnalyzer.ValuesParameter.ActualName = "Selection Pressure History";
|
---|
| 505 | successfulOffspringAnalyzer.ResultsParameter.ActualName = "Results";
|
---|
| 506 | successfulOffspringAnalyzer.GenerationsParameter.ActualName = "Generations";
|
---|
| 507 | successfulOffspringAnalyzer.SuccessfulOffspringFlagParameter.Value.Value = "SuccessfulOffspring";
|
---|
| 508 | successfulOffspringAnalyzer.DepthParameter.Value = new IntValue(1);
|
---|
| 509 | if (Problem != null) {
|
---|
| 510 | qualityAnalyzer.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
|
---|
| 511 | qualityAnalyzer.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
|
---|
| 512 | qualityAnalyzer.BestKnownQualityParameter.ActualName = Problem.BestKnownQualityParameter.Name;
|
---|
| 513 | }
|
---|
| 514 | }
|
---|
| 515 | private void ParameterizeComparisonFactorModifiers() {
|
---|
| 516 | foreach (IDiscreteDoubleValueModifier modifier in ComparisonFactorModifierParameter.ValidValues) {
|
---|
| 517 | modifier.IndexParameter.ActualName = "Generations";
|
---|
| 518 | modifier.EndIndexParameter.ActualName = MaximumGenerationsParameter.Name;
|
---|
| 519 | modifier.EndValueParameter.ActualName = ComparisonFactorUpperBoundParameter.Name;
|
---|
| 520 | modifier.StartIndexParameter.Value = new IntValue(0);
|
---|
| 521 | modifier.StartValueParameter.ActualName = ComparisonFactorLowerBoundParameter.Name;
|
---|
| 522 | modifier.ValueParameter.ActualName = "ComparisonFactor";
|
---|
| 523 | }
|
---|
| 524 | }
|
---|
| 525 | private void ParameterizeIterationBasedOperators() {
|
---|
| 526 | if (Problem != null) {
|
---|
| 527 | foreach (IIterationBasedOperator op in Problem.Operators.OfType<IIterationBasedOperator>()) {
|
---|
| 528 | op.IterationsParameter.ActualName = "Generations";
|
---|
| 529 | op.MaximumIterationsParameter.ActualName = MaximumGenerationsParameter.Name;
|
---|
| 530 | }
|
---|
| 531 | }
|
---|
| 532 | }
|
---|
| 533 | private void UpdateCrossovers() {
|
---|
| 534 | ICrossover oldCrossover = CrossoverParameter.Value;
|
---|
| 535 | CrossoverParameter.ValidValues.Clear();
|
---|
| 536 | ICrossover defaultCrossover = Problem.Operators.OfType<ICrossover>().FirstOrDefault();
|
---|
| 537 |
|
---|
| 538 | foreach (ICrossover crossover in Problem.Operators.OfType<ICrossover>().OrderBy(x => x.Name))
|
---|
| 539 | CrossoverParameter.ValidValues.Add(crossover);
|
---|
| 540 |
|
---|
| 541 | if (oldCrossover != null) {
|
---|
| 542 | ICrossover crossover = CrossoverParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldCrossover.GetType());
|
---|
| 543 | if (crossover != null) CrossoverParameter.Value = crossover;
|
---|
| 544 | else oldCrossover = null;
|
---|
| 545 | }
|
---|
| 546 | if (oldCrossover == null && defaultCrossover != null)
|
---|
| 547 | CrossoverParameter.Value = defaultCrossover;
|
---|
| 548 | }
|
---|
| 549 | private void UpdateMutators() {
|
---|
| 550 | IManipulator oldMutator = MutatorParameter.Value;
|
---|
| 551 | MutatorParameter.ValidValues.Clear();
|
---|
| 552 | foreach (IManipulator mutator in Problem.Operators.OfType<IManipulator>().OrderBy(x => x.Name))
|
---|
| 553 | MutatorParameter.ValidValues.Add(mutator);
|
---|
| 554 | if (oldMutator != null) {
|
---|
| 555 | IManipulator mutator = MutatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMutator.GetType());
|
---|
| 556 | if (mutator != null) MutatorParameter.Value = mutator;
|
---|
| 557 | }
|
---|
| 558 | }
|
---|
| 559 | private void UpdateAnalyzers() {
|
---|
| 560 | Analyzer.Operators.Clear();
|
---|
| 561 | if (Problem != null) {
|
---|
| 562 | foreach (IAnalyzer analyzer in Problem.Operators.OfType<IAnalyzer>()) {
|
---|
| 563 | foreach (IScopeTreeLookupParameter param in analyzer.Parameters.OfType<IScopeTreeLookupParameter>())
|
---|
| 564 | param.Depth = 1;
|
---|
| 565 | Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
|
---|
| 566 | }
|
---|
| 567 | }
|
---|
| 568 | Analyzer.Operators.Add(qualityAnalyzer, qualityAnalyzer.EnabledByDefault);
|
---|
| 569 | Analyzer.Operators.Add(selectionPressureAnalyzer, selectionPressureAnalyzer.EnabledByDefault);
|
---|
| 570 | Analyzer.Operators.Add(successfulOffspringAnalyzer, successfulOffspringAnalyzer.EnabledByDefault);
|
---|
| 571 | }
|
---|
[11516] | 572 | private void UpdateSimilarityCalculators() {
|
---|
| 573 | ISingleObjectiveSolutionSimilarityCalculator oldSimilarityCalculator = SimilarityCalculatorParameter.Value;
|
---|
| 574 | SimilarityCalculatorParameter.ValidValues.Clear();
|
---|
| 575 | ISingleObjectiveSolutionSimilarityCalculator defaultSimilarityCalculator = Problem.Operators.OfType<ISingleObjectiveSolutionSimilarityCalculator>().FirstOrDefault();
|
---|
| 576 |
|
---|
| 577 | SimilarityCalculatorParameter.ValidValues.Add(new QualitySimilarityCalculator { QualityVariableName = Problem.Evaluator.QualityParameter.ActualName });
|
---|
| 578 | SimilarityCalculatorParameter.ValidValues.Add(new NoSimilarityCalculator());
|
---|
| 579 |
|
---|
| 580 | foreach (ISingleObjectiveSolutionSimilarityCalculator similarityCalculator in Problem.Operators.OfType<ISingleObjectiveSolutionSimilarityCalculator>())
|
---|
| 581 | SimilarityCalculatorParameter.ValidValues.Add(similarityCalculator);
|
---|
| 582 |
|
---|
| 583 | if (oldSimilarityCalculator != null) {
|
---|
| 584 | ISingleObjectiveSolutionSimilarityCalculator similarityCalculator = SimilarityCalculatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldSimilarityCalculator.GetType());
|
---|
| 585 | if (similarityCalculator != null) SimilarityCalculatorParameter.Value = similarityCalculator;
|
---|
| 586 | else oldSimilarityCalculator = null;
|
---|
| 587 | }
|
---|
| 588 | if (oldSimilarityCalculator == null && defaultSimilarityCalculator != null)
|
---|
| 589 | SimilarityCalculatorParameter.Value = defaultSimilarityCalculator;
|
---|
| 590 | }
|
---|
| 591 | private void ParameterizeSimilarityCalculators() {
|
---|
| 592 | foreach (ISingleObjectiveSolutionSimilarityCalculator calc in SimilarityCalculatorParameter.ValidValues) {
|
---|
| 593 | calc.QualityVariableName = Problem.Evaluator.QualityParameter.ActualName;
|
---|
| 594 | }
|
---|
| 595 | }
|
---|
[11510] | 596 | private VOffspringSelectionGeneticAlgorithmMainLoop FindMainLoop(IOperator start) {
|
---|
[11492] | 597 | IOperator mainLoop = start;
|
---|
[11510] | 598 | while (mainLoop != null && !(mainLoop is VOffspringSelectionGeneticAlgorithmMainLoop))
|
---|
[11492] | 599 | mainLoop = ((SingleSuccessorOperator)mainLoop).Successor;
|
---|
| 600 | if (mainLoop == null) return null;
|
---|
[11510] | 601 | else return (VOffspringSelectionGeneticAlgorithmMainLoop)mainLoop;
|
---|
[11492] | 602 | }
|
---|
| 603 | #endregion
|
---|
| 604 | }
|
---|
| 605 | }
|
---|