#region License Information /* HeuristicLab * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Optimization.Operators; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Algorithms.LocalSearch { /// /// A local search improvement operator. /// [Item("LocalSearchImprovementOperator", "A local search improvement operator.")] [StorableClass] public class LocalSearchImprovementOperator : SingleSuccessorOperator, ILocalImprovementOperator { [Storable] private LocalSearchMainLoop loop; [Storable] private BestAverageWorstQualityAnalyzer qualityAnalyzer; private ConstrainedValueParameter MoveGeneratorParameter { get { return (ConstrainedValueParameter)Parameters["MoveGenerator"]; } } private ConstrainedValueParameter MoveMakerParameter { get { return (ConstrainedValueParameter)Parameters["MoveMaker"]; } } private ConstrainedValueParameter MoveEvaluatorParameter { get { return (ConstrainedValueParameter)Parameters["MoveEvaluator"]; } } private ValueParameter MaximumIterationsParameter { get { return (ValueParameter)Parameters["MaximumIterations"]; } } private ValueParameter SampleSizeParameter { get { return (ValueParameter)Parameters["SampleSize"]; } } public LookupParameter EvaluatedSolutionsParameter { get { return (LookupParameter)Parameters["EvaluatedSolutions"]; } } public ValueParameter AnalyzerParameter { get { return (ValueParameter)Parameters["Analyzer"]; } } public IMoveGenerator MoveGenerator { get { return MoveGeneratorParameter.Value; } set { MoveGeneratorParameter.Value = value; } } public IMoveMaker MoveMaker { get { return MoveMakerParameter.Value; } set { MoveMakerParameter.Value = value; } } public ISingleObjectiveMoveEvaluator MoveEvaluator { get { return MoveEvaluatorParameter.Value; } set { MoveEvaluatorParameter.Value = value; } } public MultiAnalyzer Analyzer { get { return AnalyzerParameter.Value; } set { AnalyzerParameter.Value = value; } } [StorableConstructor] protected LocalSearchImprovementOperator(bool deserializing) : base(deserializing) { } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { Initialize(); } protected LocalSearchImprovementOperator(LocalSearchImprovementOperator original, Cloner cloner) : base(original, cloner) { this.loop = cloner.Clone(original.loop); this.qualityAnalyzer = cloner.Clone(original.qualityAnalyzer); Initialize(); } public override IDeepCloneable Clone(Cloner cloner) { return new LocalSearchImprovementOperator(this, cloner); } public LocalSearchImprovementOperator() : base() { loop = new LocalSearchMainLoop(); ResultsCollector rc = (loop.OperatorGraph.InitialOperator as SingleSuccessorOperator).Successor as ResultsCollector; rc.CollectedValues.Remove("BestLocalQuality"); qualityAnalyzer = new BestAverageWorstQualityAnalyzer(); Parameters.Add(new ConstrainedValueParameter("MoveGenerator", "The operator used to generate moves to the neighborhood of the current solution.")); Parameters.Add(new ConstrainedValueParameter("MoveMaker", "The operator used to perform a move.")); Parameters.Add(new ConstrainedValueParameter("MoveEvaluator", "The operator used to evaluate a move.")); Parameters.Add(new ValueParameter("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(150))); Parameters.Add(new ValueParameter("SampleSize", "Number of moves that MultiMoveGenerators should create. This is ignored for Exhaustive- and SingleMoveGenerators.", new IntValue(1500))); Parameters.Add(new LookupParameter("EvaluatedSolutions", "The number of evaluated moves.")); Parameters.Add(new ValueParameter("Analyzer", "The operator used to analyze the solution.", new MultiAnalyzer())); Initialize(); } private void Initialize() { MoveGeneratorParameter.ValueChanged += new EventHandler(MoveGeneratorParameter_ValueChanged); } public void OnProblemChanged(IProblem problem) { UpdateMoveOperators(problem); ChooseMoveOperators(); ParameterizeMoveGenerators(problem as ISingleObjectiveHeuristicOptimizationProblem); ParameterizeMoveEvaluators(problem as ISingleObjectiveHeuristicOptimizationProblem); ParameterizeMoveMakers(problem as ISingleObjectiveHeuristicOptimizationProblem); ParameterizeAnalyzers(problem as ISingleObjectiveHeuristicOptimizationProblem); UpdateAnalyzers(problem as ISingleObjectiveHeuristicOptimizationProblem); } void ParameterizeAnalyzers(ISingleObjectiveHeuristicOptimizationProblem problem) { qualityAnalyzer.ResultsParameter.ActualName = "Results"; if (problem != null) { qualityAnalyzer.MaximizationParameter.ActualName = problem.MaximizationParameter.Name; if (MoveEvaluator != null) qualityAnalyzer.QualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName; qualityAnalyzer.BestKnownQualityParameter.ActualName = problem.BestKnownQualityParameter.Name; } } void UpdateAnalyzers(ISingleObjectiveHeuristicOptimizationProblem problem) { Analyzer.Operators.Clear(); if (problem != null) { foreach (IAnalyzer analyzer in problem.Operators.OfType()) { IAnalyzer clone = analyzer.Clone() as IAnalyzer; foreach (IScopeTreeLookupParameter param in clone.Parameters.OfType()) param.Depth = 0; Analyzer.Operators.Add(clone); } } Analyzer.Operators.Add(qualityAnalyzer); } void MoveGeneratorParameter_ValueChanged(object sender, EventArgs e) { ChooseMoveOperators(); } private void UpdateMoveOperators(IProblem problem) { IMoveGenerator oldMoveGenerator = MoveGenerator; IMoveMaker oldMoveMaker = MoveMaker; ISingleObjectiveMoveEvaluator oldMoveEvaluator = MoveEvaluator; ClearMoveParameters(); if (problem != null) { foreach (IMoveGenerator generator in problem.Operators.OfType().OrderBy(x => x.Name)) MoveGeneratorParameter.ValidValues.Add(generator); foreach (IMoveMaker maker in problem.Operators.OfType().OrderBy(x => x.Name)) MoveMakerParameter.ValidValues.Add(maker); foreach (ISingleObjectiveMoveEvaluator evaluator in problem.Operators.OfType().OrderBy(x => x.Name)) MoveEvaluatorParameter.ValidValues.Add(evaluator); } if (oldMoveGenerator != null) { IMoveGenerator newMoveGenerator = MoveGeneratorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveGenerator.GetType()); if (newMoveGenerator != null) MoveGenerator = newMoveGenerator; } if (MoveGenerator == null) { ClearMoveParameters(); } if (oldMoveMaker != null) { IMoveMaker mm = MoveMakerParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveMaker.GetType()); if (mm != null) MoveMaker = mm; } if (oldMoveEvaluator != null) { ISingleObjectiveMoveEvaluator me = MoveEvaluatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveEvaluator.GetType()); if (me != null) MoveEvaluator = me; } } private void ChooseMoveOperators() { IMoveMaker oldMoveMaker = MoveMaker; ISingleObjectiveMoveEvaluator oldMoveEvaluator = MoveEvaluator; if (MoveGenerator != null) { List moveTypes = MoveGenerator.GetType().GetInterfaces().Where(x => typeof(IMoveOperator).IsAssignableFrom(x)).ToList(); foreach (Type type in moveTypes.ToList()) { if (moveTypes.Any(t => t != type && type.IsAssignableFrom(t))) moveTypes.Remove(type); } List validMoveMakers = new List(); List validMoveEvaluators = new List(); foreach (Type type in moveTypes) { var moveMakers = MoveMakerParameter.ValidValues.Where(x => type.IsAssignableFrom(x.GetType())).OrderBy(x => x.Name); foreach (IMoveMaker moveMaker in moveMakers) validMoveMakers.Add(moveMaker); var moveEvaluators = MoveEvaluatorParameter.ValidValues.Where(x => type.IsAssignableFrom(x.GetType())).OrderBy(x => x.Name); foreach (ISingleObjectiveMoveEvaluator moveEvaluator in moveEvaluators) validMoveEvaluators.Add(moveEvaluator); } if (oldMoveMaker != null) { IMoveMaker mm = validMoveMakers.FirstOrDefault(x => x.GetType() == oldMoveMaker.GetType()); if (mm != null) MoveMaker = mm; else MoveMaker = validMoveMakers.FirstOrDefault(); } if (oldMoveEvaluator != null) { ISingleObjectiveMoveEvaluator me = validMoveEvaluators.FirstOrDefault(x => x.GetType() == oldMoveEvaluator.GetType()); if (me != null) MoveEvaluator = me; else MoveEvaluator = validMoveEvaluators.FirstOrDefault(); } } } private void ClearMoveParameters() { MoveGeneratorParameter.ValidValues.Clear(); MoveMakerParameter.ValidValues.Clear(); MoveEvaluatorParameter.ValidValues.Clear(); } private void ParameterizeMoveGenerators(ISingleObjectiveHeuristicOptimizationProblem problem) { if (problem != null) { foreach (IMultiMoveGenerator generator in problem.Operators.OfType()) generator.SampleSizeParameter.ActualName = SampleSizeParameter.Name; } } private void ParameterizeMoveEvaluators(ISingleObjectiveHeuristicOptimizationProblem problem) { foreach (ISingleObjectiveMoveEvaluator op in problem.Operators.OfType()) { op.QualityParameter.ActualName = problem.Evaluator.QualityParameter.ActualName; } } private void ParameterizeMoveMakers(ISingleObjectiveHeuristicOptimizationProblem problem) { foreach (IMoveMaker op in problem.Operators.OfType()) { op.QualityParameter.ActualName = problem.Evaluator.QualityParameter.ActualName; if (MoveEvaluator != null) op.MoveQualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName; } } public override IOperation Apply() { Scope subScope = new Scope(); Scope individual = new Scope(); foreach (Variable var in ExecutionContext.Scope.Variables) { individual.Variables.Add(var); } subScope.SubScopes.Add(individual); ExecutionContext.Scope.SubScopes.Add(subScope); int index = subScope.Parent.SubScopes.IndexOf(subScope); SubScopesProcessor processor = new SubScopesProcessor(); SubScopesRemover remover = new SubScopesRemover(); remover.RemoveAllSubScopes = false; remover.SubScopeIndexParameter.Value = new IntValue(index); for (int i = 0; i < index; i++) { processor.Operators.Add(new EmptyOperator()); } VariableCreator variableCreator = new VariableCreator(); variableCreator.CollectedValues.Add(new ValueParameter("LocalIterations", new IntValue(0))); variableCreator.CollectedValues.Add(new ValueParameter("BestLocalQuality", new DoubleValue(0))); variableCreator.Successor = loop; loop.EvaluatedMovesParameter.ActualName = EvaluatedSolutionsParameter.ActualName; processor.Operators.Add(variableCreator); processor.Successor = remover; IOperation next = base.Apply(); if (next as ExecutionContext != null) { remover.Successor = (next as ExecutionContext).Operator; } return ExecutionContext.CreateChildOperation(processor); } } }