1
#region License Information
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
5 * This file is part of HeuristicLab.
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.
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.
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/>.
23 using System
.Collections
.Generic
;
25 using HeuristicLab
.Analysis
;
26 using HeuristicLab
.Common
;
27 using HeuristicLab
.Core
;
28 using HeuristicLab
.Data
;
29 using HeuristicLab
.Operators
;
30 using HeuristicLab
.Optimization
;
31 using HeuristicLab
.Optimization
.Operators
;
32 using HeuristicLab
.Parameters
;
33 using HeuristicLab
.Persistence
.Default
.CompositeSerializers
.Storable
;
34 using HeuristicLab
.Random
;
36 namespace HeuristicLab
.Algorithms
.LocalSearch
{
37 [Item("Local Search", "A local search algorithm.")]
38 [Creatable("Algorithms")]
40 public sealed class LocalSearch
: HeuristicOptimizationEngineAlgorithm
, IStorableContent
{
41 public string Filename { get; set; }
43 #region Problem Properties
44 public override Type ProblemType
{
45 get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); }
47 public new ISingleObjectiveHeuristicOptimizationProblem Problem
{
48 get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
49 set { base.Problem = value; }
53 #region Parameter Properties
54 private ValueParameter
<IntValue
> SeedParameter
{
55 get { return (ValueParameter<IntValue>)Parameters["Seed"]; }
57 private ValueParameter
<BoolValue
> SetSeedRandomlyParameter
{
58 get { return (ValueParameter<BoolValue>)Parameters["SetSeedRandomly"]; }
60 public ConstrainedValueParameter
<IMoveGenerator
> MoveGeneratorParameter
{
61 get { return (ConstrainedValueParameter<IMoveGenerator>)Parameters["MoveGenerator"]; }
63 public ConstrainedValueParameter
<IMoveMaker
> MoveMakerParameter
{
64 get { return (ConstrainedValueParameter<IMoveMaker>)Parameters["MoveMaker"]; }
66 public ConstrainedValueParameter
<ISingleObjectiveMoveEvaluator
> MoveEvaluatorParameter
{
67 get { return (ConstrainedValueParameter<ISingleObjectiveMoveEvaluator>)Parameters["MoveEvaluator"]; }
69 private ValueParameter
<IntValue
> MaximumIterationsParameter
{
70 get { return (ValueParameter<IntValue>)Parameters["MaximumIterations"]; }
72 private ValueParameter
<IntValue
> SampleSizeParameter
{
73 get { return (ValueParameter<IntValue>)Parameters["SampleSize"]; }
75 private ValueParameter
<MultiAnalyzer
> AnalyzerParameter
{
76 get { return (ValueParameter<MultiAnalyzer>)Parameters["Analyzer"]; }
81 public IntValue Seed
{
82 get { return SeedParameter.Value; }
83 set { SeedParameter.Value = value; }
85 public BoolValue SetSeedRandomly
{
86 get { return SetSeedRandomlyParameter.Value; }
87 set { SetSeedRandomlyParameter.Value = value; }
89 public IMoveGenerator MoveGenerator
{
90 get { return MoveGeneratorParameter.Value; }
91 set { MoveGeneratorParameter.Value = value; }
93 public IMoveMaker MoveMaker
{
94 get { return MoveMakerParameter.Value; }
95 set { MoveMakerParameter.Value = value; }
97 public ISingleObjectiveMoveEvaluator MoveEvaluator
{
98 get { return MoveEvaluatorParameter.Value; }
99 set { MoveEvaluatorParameter.Value = value; }
101 public IntValue MaximumIterations
{
102 get { return MaximumIterationsParameter.Value; }
103 set { MaximumIterationsParameter.Value = value; }
105 public IntValue SampleSize
{
106 get { return SampleSizeParameter.Value; }
107 set { SampleSizeParameter.Value = value; }
109 public MultiAnalyzer Analyzer
{
110 get { return AnalyzerParameter.Value; }
111 set { AnalyzerParameter.Value = value; }
113 private RandomCreator RandomCreator
{
114 get { return (RandomCreator)OperatorGraph.InitialOperator; }
116 private SolutionsCreator SolutionsCreator
{
117 get { return (SolutionsCreator)RandomCreator.Successor; }
119 private LocalSearchMainLoop MainLoop
{
120 get { return FindMainLoop(SolutionsCreator.Successor); }
123 private BestAverageWorstQualityAnalyzer moveQualityAnalyzer
;
126 [StorableConstructor
]
127 private LocalSearch(bool deserializing
) : base(deserializing
) { }
128 [StorableHook(HookType
.AfterDeserialization
)]
129 private void AfterDeserialization() {
132 private LocalSearch(LocalSearch original
, Cloner cloner
)
133 : base(original
, cloner
) {
134 moveQualityAnalyzer
= cloner
.Clone(original
.moveQualityAnalyzer
);
137 public override IDeepCloneable
Clone(Cloner cloner
) {
138 return new LocalSearch(this, cloner
);
142 Parameters
.Add(new ValueParameter
<IntValue
>("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
143 Parameters
.Add(new ValueParameter
<BoolValue
>("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
144 Parameters
.Add(new ConstrainedValueParameter
<IMoveGenerator
>("MoveGenerator", "The operator used to generate moves to the neighborhood of the current solution."));
145 Parameters
.Add(new ConstrainedValueParameter
<IMoveMaker
>("MoveMaker", "The operator used to perform a move."));
146 Parameters
.Add(new ConstrainedValueParameter
<ISingleObjectiveMoveEvaluator
>("MoveEvaluator", "The operator used to evaluate a move."));
147 Parameters
.Add(new ValueParameter
<IntValue
>("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(1000)));
148 Parameters
.Add(new ValueParameter
<IntValue
>("SampleSize", "Number of moves that MultiMoveGenerators should create. This is ignored for Exhaustive- and SingleMoveGenerators.", new IntValue(100)));
149 Parameters
.Add(new ValueParameter
<MultiAnalyzer
>("Analyzer", "The operator used to analyze the solution and moves.", new MultiAnalyzer()));
151 RandomCreator randomCreator
= new RandomCreator();
152 SolutionsCreator solutionsCreator
= new SolutionsCreator();
153 VariableCreator variableCreator
= new VariableCreator();
154 ResultsCollector resultsCollector
= new ResultsCollector();
155 LocalSearchMainLoop mainLoop
= new LocalSearchMainLoop();
156 OperatorGraph
.InitialOperator
= randomCreator
;
158 randomCreator
.RandomParameter
.ActualName
= "Random";
159 randomCreator
.SeedParameter
.ActualName
= SeedParameter
.Name
;
160 randomCreator
.SeedParameter
.Value
= null;
161 randomCreator
.SetSeedRandomlyParameter
.ActualName
= SetSeedRandomlyParameter
.Name
;
162 randomCreator
.SetSeedRandomlyParameter
.Value
= null;
163 randomCreator
.Successor
= solutionsCreator
;
165 solutionsCreator
.NumberOfSolutions
= new IntValue(1);
166 solutionsCreator
.Successor
= variableCreator
;
168 variableCreator
.Name
= "Initialize EvaluatedMoves";
169 variableCreator
.CollectedValues
.Add(new ValueParameter
<IntValue
>("EvaluatedMoves", new IntValue()));
170 variableCreator
.CollectedValues
.Add(new ValueParameter
<IntValue
>("Iterations", new IntValue(0)));
171 variableCreator
.CollectedValues
.Add(new ValueParameter
<DoubleValue
>("BestQuality", new DoubleValue(0)));
172 variableCreator
.Successor
= resultsCollector
;
174 resultsCollector
.CollectedValues
.Add(new LookupParameter
<IntValue
>("Evaluated Moves", null, "EvaluatedMoves"));
175 resultsCollector
.ResultsParameter
.ActualName
= "Results";
176 resultsCollector
.Successor
= mainLoop
;
178 mainLoop
.MoveGeneratorParameter
.ActualName
= MoveGeneratorParameter
.Name
;
179 mainLoop
.MoveMakerParameter
.ActualName
= MoveMakerParameter
.Name
;
180 mainLoop
.MoveEvaluatorParameter
.ActualName
= MoveEvaluatorParameter
.Name
;
181 mainLoop
.MaximumIterationsParameter
.ActualName
= MaximumIterationsParameter
.Name
;
182 mainLoop
.RandomParameter
.ActualName
= RandomCreator
.RandomParameter
.ActualName
;
183 mainLoop
.ResultsParameter
.ActualName
= "Results";
184 mainLoop
.AnalyzerParameter
.ActualName
= AnalyzerParameter
.Name
;
185 mainLoop
.EvaluatedMovesParameter
.ActualName
= "EvaluatedMoves";
186 mainLoop
.IterationsParameter
.ActualName
= "Iterations";
187 mainLoop
.BestLocalQualityParameter
.ActualName
= "BestQuality";
189 moveQualityAnalyzer
= new BestAverageWorstQualityAnalyzer();
190 ParameterizeAnalyzers();
196 public override void Prepare() {
197 if (Problem
!= null && MoveGenerator
!= null && MoveMaker
!= null && MoveEvaluator
!= null)
202 protected override void OnProblemChanged() {
203 ParameterizeStochasticOperator(Problem
.SolutionCreator
);
204 ParameterizeStochasticOperator(Problem
.Evaluator
);
205 foreach (IOperator op
in Problem
.Operators
) ParameterizeStochasticOperator(op
);
206 foreach (ISingleObjectiveMoveEvaluator op
in Problem
.Operators
.OfType
<ISingleObjectiveMoveEvaluator
>()) {
207 op
.MoveQualityParameter
.ActualNameChanged
+= new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged
);
209 ParameterizeSolutionsCreator();
210 ParameterizeMainLoop();
211 UpdateMoveGenerator();
212 UpdateMoveParameters();
214 ParameterizeMoveGenerators();
215 ParameterizeMoveEvaluators();
216 ParameterizeMoveMakers();
217 ParameterizeAnalyzers();
218 ParameterizeIterationBasedOperators();
219 Problem
.Evaluator
.QualityParameter
.ActualNameChanged
+= new EventHandler(Evaluator_QualityParameter_ActualNameChanged
);
220 base.OnProblemChanged();
222 protected override void Problem_SolutionCreatorChanged(object sender
, EventArgs e
) {
223 ParameterizeStochasticOperator(Problem
.SolutionCreator
);
224 ParameterizeSolutionsCreator();
225 base.Problem_SolutionCreatorChanged(sender
, e
);
227 protected override void Problem_EvaluatorChanged(object sender
, EventArgs e
) {
228 ParameterizeStochasticOperator(Problem
.Evaluator
);
229 ParameterizeSolutionsCreator();
230 ParameterizeMainLoop();
231 ParameterizeMoveEvaluators();
232 ParameterizeMoveMakers();
233 ParameterizeAnalyzers();
234 Problem
.Evaluator
.QualityParameter
.ActualNameChanged
+= new EventHandler(Evaluator_QualityParameter_ActualNameChanged
);
235 base.Problem_EvaluatorChanged(sender
, e
);
237 protected override void Problem_OperatorsChanged(object sender
, EventArgs e
) {
238 foreach (IOperator op
in Problem
.Operators
) ParameterizeStochasticOperator(op
);
239 // This may seem pointless, but some operators already have the eventhandler registered, others don't
240 // FIXME: Is there another way to solve this problem?
241 foreach (ISingleObjectiveMoveEvaluator op
in Problem
.Operators
.OfType
<ISingleObjectiveMoveEvaluator
>()) {
242 op
.MoveQualityParameter
.ActualNameChanged
-= new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged
);
243 op
.MoveQualityParameter
.ActualNameChanged
+= new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged
);
245 UpdateMoveGenerator();
246 UpdateMoveParameters();
248 ParameterizeMainLoop();
249 ParameterizeMoveGenerators();
250 ParameterizeMoveEvaluators();
251 ParameterizeMoveMakers();
252 ParameterizeAnalyzers();
253 ParameterizeIterationBasedOperators();
254 base.Problem_OperatorsChanged(sender
, e
);
256 private void Evaluator_QualityParameter_ActualNameChanged(object sender
, EventArgs e
) {
257 ParameterizeMainLoop();
258 ParameterizeMoveEvaluators();
259 ParameterizeMoveMakers();
261 private void MoveGeneratorParameter_ValueChanged(object sender
, EventArgs e
) {
262 UpdateMoveParameters();
264 private void MoveEvaluatorParameter_ValueChanged(object sender
, EventArgs e
) {
265 ParameterizeMainLoop();
266 ParameterizeMoveEvaluators();
267 ParameterizeMoveMakers();
268 ParameterizeAnalyzers();
270 private void MoveEvaluator_MoveQualityParameter_ActualNameChanged(object sender
, EventArgs e
) {
271 ParameterizeMainLoop();
272 ParameterizeMoveEvaluators();
273 ParameterizeMoveMakers();
274 ParameterizeAnalyzers();
279 private void Initialize() {
280 if (Problem
!= null) {
281 Problem
.Evaluator
.QualityParameter
.ActualNameChanged
+= new EventHandler(Evaluator_QualityParameter_ActualNameChanged
);
282 foreach (ISingleObjectiveMoveEvaluator op
in Problem
.Operators
.OfType
<ISingleObjectiveMoveEvaluator
>()) {
283 op
.MoveQualityParameter
.ActualNameChanged
+= new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged
);
286 MoveGeneratorParameter
.ValueChanged
+= new EventHandler(MoveGeneratorParameter_ValueChanged
);
287 MoveEvaluatorParameter
.ValueChanged
+= new EventHandler(MoveEvaluatorParameter_ValueChanged
);
289 private void UpdateMoveGenerator() {
290 IMoveGenerator oldMoveGenerator
= MoveGenerator
;
291 MoveGeneratorParameter
.ValidValues
.Clear();
292 if (Problem
!= null) {
293 foreach (IMoveGenerator generator
in Problem
.Operators
.OfType
<IMoveGenerator
>().OrderBy(x
=> x
.Name
))
294 MoveGeneratorParameter
.ValidValues
.Add(generator
);
296 if (oldMoveGenerator
!= null) {
297 IMoveGenerator newMoveGenerator
= MoveGeneratorParameter
.ValidValues
.FirstOrDefault(x
=> x
.GetType() == oldMoveGenerator
.GetType());
298 if (newMoveGenerator
!= null) MoveGenerator
= newMoveGenerator
;
300 if (MoveGenerator
== null) {
301 ClearMoveParameters();
304 private void UpdateMoveParameters() {
305 IMoveMaker oldMoveMaker
= MoveMaker
;
306 ISingleObjectiveMoveEvaluator oldMoveEvaluator
= MoveEvaluator
;
307 ClearMoveParameters();
308 if (MoveGenerator
!= null) {
309 List
<Type
> moveTypes
= MoveGenerator
.GetType().GetInterfaces().Where(x
=> typeof(IMoveOperator
).IsAssignableFrom(x
)).ToList();
310 foreach (Type type
in moveTypes
.ToList()) {
311 if (moveTypes
.Any(t
=> t
!= type
&& type
.IsAssignableFrom(t
)))
312 moveTypes
.Remove(type
);
314 foreach (Type type
in moveTypes
) {
315 var operators
= Problem
.Operators
.Where(x
=> type
.IsAssignableFrom(x
.GetType())).OrderBy(x
=> x
.Name
);
316 foreach (IMoveMaker moveMaker
in operators
.OfType
<IMoveMaker
>())
317 MoveMakerParameter
.ValidValues
.Add(moveMaker
);
318 foreach (ISingleObjectiveMoveEvaluator moveEvaluator
in operators
.OfType
<ISingleObjectiveMoveEvaluator
>())
319 MoveEvaluatorParameter
.ValidValues
.Add(moveEvaluator
);
321 if (oldMoveMaker
!= null) {
322 IMoveMaker mm
= MoveMakerParameter
.ValidValues
.FirstOrDefault(x
=> x
.GetType() == oldMoveMaker
.GetType());
323 if (mm
!= null) MoveMaker
= mm
;
325 if (oldMoveEvaluator
!= null) {
326 ISingleObjectiveMoveEvaluator me
= MoveEvaluatorParameter
.ValidValues
.FirstOrDefault(x
=> x
.GetType() == oldMoveEvaluator
.GetType());
327 if (me
!= null) MoveEvaluator
= me
;
331 private void UpdateAnalyzers() {
332 Analyzer
.Operators
.Clear();
333 if (Problem
!= null) {
334 foreach (IAnalyzer analyzer
in Problem
.Operators
.OfType
<IAnalyzer
>()) {
335 foreach (IScopeTreeLookupParameter param
in analyzer
.Parameters
.OfType
<IScopeTreeLookupParameter
>())
337 Analyzer
.Operators
.Add(analyzer
);
340 Analyzer
.Operators
.Add(moveQualityAnalyzer
);
342 private void ClearMoveParameters() {
343 MoveMakerParameter
.ValidValues
.Clear();
344 MoveEvaluatorParameter
.ValidValues
.Clear();
346 private void ParameterizeSolutionsCreator() {
347 SolutionsCreator
.EvaluatorParameter
.ActualName
= Problem
.EvaluatorParameter
.Name
;
348 SolutionsCreator
.SolutionCreatorParameter
.ActualName
= Problem
.SolutionCreatorParameter
.Name
;
350 private void ParameterizeMainLoop() {
351 if (Problem
!= null) {
352 MainLoop
.BestKnownQualityParameter
.ActualName
= Problem
.BestKnownQualityParameter
.Name
;
353 MainLoop
.MaximizationParameter
.ActualName
= Problem
.MaximizationParameter
.Name
;
354 MainLoop
.QualityParameter
.ActualName
= Problem
.Evaluator
.QualityParameter
.ActualName
;
356 if (MoveEvaluator
!= null)
357 MainLoop
.MoveQualityParameter
.ActualName
= MoveEvaluator
.MoveQualityParameter
.ActualName
;
359 private void ParameterizeStochasticOperator(IOperator op
) {
360 if (op
is IStochasticOperator
) {
361 IStochasticOperator stOp
= (IStochasticOperator
)op
;
362 stOp
.RandomParameter
.ActualName
= RandomCreator
.RandomParameter
.ActualName
;
363 stOp
.RandomParameter
.Hidden
= true;
366 private void ParameterizeMoveGenerators() {
367 if (Problem
!= null) {
368 foreach (IMultiMoveGenerator generator
in Problem
.Operators
.OfType
<IMultiMoveGenerator
>()) {
369 generator
.SampleSizeParameter
.ActualName
= SampleSizeParameter
.Name
;
370 generator
.SampleSizeParameter
.Hidden
= true;
374 private void ParameterizeMoveEvaluators() {
375 foreach (ISingleObjectiveMoveEvaluator op
in Problem
.Operators
.OfType
<ISingleObjectiveMoveEvaluator
>()) {
376 op
.QualityParameter
.ActualName
= Problem
.Evaluator
.QualityParameter
.ActualName
;
377 op
.QualityParameter
.Hidden
= true;
380 private void ParameterizeMoveMakers() {
381 foreach (IMoveMaker op
in Problem
.Operators
.OfType
<IMoveMaker
>()) {
382 op
.QualityParameter
.ActualName
= Problem
.Evaluator
.QualityParameter
.ActualName
;
383 op
.QualityParameter
.Hidden
= true;
384 if (MoveEvaluator
!= null) {
385 op
.MoveQualityParameter
.ActualName
= MoveEvaluator
.MoveQualityParameter
.ActualName
;
386 op
.MoveQualityParameter
.Hidden
= true;
388 op
.MoveQualityParameter
.Hidden
= false;
392 private void ParameterizeAnalyzers() {
393 moveQualityAnalyzer
.ResultsParameter
.ActualName
= "Results";
394 moveQualityAnalyzer
.ResultsParameter
.Hidden
= true;
395 if (Problem
!= null) {
396 moveQualityAnalyzer
.MaximizationParameter
.ActualName
= Problem
.MaximizationParameter
.Name
;
397 moveQualityAnalyzer
.MaximizationParameter
.Hidden
= true;
398 if (MoveEvaluator
!= null) {
399 moveQualityAnalyzer
.QualityParameter
.ActualName
= MoveEvaluator
.MoveQualityParameter
.ActualName
;
400 moveQualityAnalyzer
.QualityParameter
.Hidden
= true;
401 } else moveQualityAnalyzer
.QualityParameter
.Hidden
= false;
402 moveQualityAnalyzer
.BestKnownQualityParameter
.ActualName
= Problem
.BestKnownQualityParameter
.Name
;
403 moveQualityAnalyzer
.BestKnownQualityParameter
.Hidden
= true;
405 moveQualityAnalyzer
.MaximizationParameter
.Hidden
= false;
406 moveQualityAnalyzer
.BestKnownQualityParameter
.Hidden
= false;
409 private void ParameterizeIterationBasedOperators() {
410 if (Problem
!= null) {
411 foreach (IIterationBasedOperator op
in Problem
.Operators
.OfType
<IIterationBasedOperator
>()) {
412 op
.IterationsParameter
.ActualName
= "Iterations";
413 op
.IterationsParameter
.Hidden
= true;
414 op
.MaximumIterationsParameter
.ActualName
= MaximumIterationsParameter
.Name
;
415 op
.MaximumIterationsParameter
.Hidden
= true;
419 private LocalSearchMainLoop
FindMainLoop(IOperator start
) {
420 IOperator mainLoop
= start
;
421 while (mainLoop
!= null && !(mainLoop
is LocalSearchMainLoop
))
422 mainLoop
= ((SingleSuccessorOperator
)mainLoop
).Successor
;
423 if (mainLoop
== null) return null;
424 else return (LocalSearchMainLoop
)mainLoop
;