#region License Information /* HeuristicLab * Copyright (C) 2002-2017 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 System.Runtime.CompilerServices; using System.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP { [Item("GRASP+PR (GQAP) Context", "Context for GRASP+PR (GQAP).")] [StorableClass] public sealed class GRASPContext : ParameterizedNamedItem, IExecutionContext { private IExecutionContext parent; public IExecutionContext Parent { get { return parent; } set { parent = value; } } [Storable] private IScope scope; public IScope Scope { get { return scope; } private set { scope = value; } } IKeyedItemCollection IExecutionContext.Parameters { get { return Parameters; } } [Storable] private IValueParameter problem; public GQAP Problem { get { return problem.Value; } set { problem.Value = value; } } public bool Maximization { get { return Problem.Maximization; } } [Storable] private IValueParameter initialized; public bool Initialized { get { return initialized.Value.Value; } set { initialized.Value.Value = value; } } [Storable] private IValueParameter iterations; public int Iterations { get { return iterations.Value.Value; } set { iterations.Value.Value = value; } } [Storable] private IValueParameter evaluatedSolutions; public int EvaluatedSolutions { get { return evaluatedSolutions.Value.Value; } set { evaluatedSolutions.Value.Value = value; } } [Storable] private IValueParameter bestQuality; public double BestQuality { get { return bestQuality.Value.Value; } set { bestQuality.Value.Value = value; } } [Storable] private IValueParameter bestSolution; public GQAPSolution BestSolution { get { return bestSolution.Value; } set { bestSolution.Value = value; } } [Storable] private IValueParameter localSearchEvaluations; public int LocalSearchEvaluations { get { return localSearchEvaluations.Value.Value; } set { localSearchEvaluations.Value.Value = value; } } [Storable] private IValueParameter random; public IRandom Random { get { return random.Value; } set { random.Value = value; } } public IEnumerable> Population { get { return scope.SubScopes.OfType>(); } } public void AddToPopulation(ISingleObjectiveSolutionScope solScope) { scope.SubScopes.Add(solScope); } public void ReplaceAtPopulation(int index, ISingleObjectiveSolutionScope solScope) { scope.SubScopes[index] = solScope; } public ISingleObjectiveSolutionScope AtPopulation(int index) { return scope.SubScopes[index] as ISingleObjectiveSolutionScope; } public void SortPopulation() { scope.SubScopes.Replace(scope.SubScopes.OfType>().OrderBy(x => Maximization ? -x.Fitness : x.Fitness).ToList()); } public int PopulationCount { get { return scope.SubScopes.Count; } } [StorableConstructor] private GRASPContext(bool deserializing) : base(deserializing) { } private GRASPContext(GRASPContext original, Cloner cloner) : base(original, cloner) { scope = cloner.Clone(original.scope); problem = cloner.Clone(original.problem); initialized = cloner.Clone(original.initialized); iterations = cloner.Clone(original.iterations); evaluatedSolutions = cloner.Clone(original.evaluatedSolutions); bestQuality = cloner.Clone(original.bestQuality); bestSolution = cloner.Clone(original.bestSolution); localSearchEvaluations = cloner.Clone(original.localSearchEvaluations); random = cloner.Clone(original.random); } public GRASPContext() : this("GRASP+PR (GQAP) Context") { } public GRASPContext(string name) : base(name) { scope = new Scope("Global"); Parameters.Add(problem = new ValueParameter("Problem")); Parameters.Add(initialized = new ValueParameter("Initialized", new BoolValue(false))); Parameters.Add(iterations = new ValueParameter("Iterations", new IntValue(0))); Parameters.Add(evaluatedSolutions = new ValueParameter("EvaluatedSolutions", new IntValue(0))); Parameters.Add(bestQuality = new ValueParameter("BestQuality", new DoubleValue(double.NaN))); Parameters.Add(bestSolution = new ValueParameter("BestFoundSolution")); Parameters.Add(localSearchEvaluations = new ValueParameter("LocalSearchEvaluations", new IntValue(0))); Parameters.Add(random = new ValueParameter("Random", new MersenneTwister())); } public override IDeepCloneable Clone(Cloner cloner) { return new GRASPContext(this, cloner); } public ISingleObjectiveSolutionScope ToScope(GQAPSolution code, double fitness = double.NaN) { var name = Problem.Encoding.Name; var scope = new SingleObjectiveSolutionScope(code, name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) { Parent = Scope }; scope.Variables.Add(new Variable(name, code.Assignment)); scope.Variables.Add(new Variable("Evaluation", code.Evaluation)); return scope; } public void IncrementEvaluatedSolutions(int byEvaluations) { if (byEvaluations < 0) throw new ArgumentException("Can only increment and not decrement evaluated solutions."); EvaluatedSolutions += byEvaluations; } private static void ExecuteAlgorithm(IAlgorithm algorithm) { using (var evt = new AutoResetEvent(false)) { EventHandler exeStateChanged = (o, args) => { if (algorithm.ExecutionState != ExecutionState.Started) evt.Set(); }; algorithm.ExecutionStateChanged += exeStateChanged; if (algorithm.ExecutionState != ExecutionState.Prepared) { algorithm.Prepare(true); evt.WaitOne(); } algorithm.Start(); evt.WaitOne(); algorithm.ExecutionStateChanged -= exeStateChanged; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsBetter(ISingleObjectiveSolutionScope a, ISingleObjectiveSolutionScope b) { return IsBetter(a.Fitness, b.Fitness); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsBetter(double a, double b) { return double.IsNaN(b) && !double.IsNaN(a) || Maximization && a > b || !Maximization && a < b; } #region IExecutionContext members public IAtomicOperation CreateOperation(IOperator op) { return new Core.ExecutionContext(this, op, Scope); } public IAtomicOperation CreateOperation(IOperator op, IScope s) { return new Core.ExecutionContext(this, op, s); } public IAtomicOperation CreateChildOperation(IOperator op) { return new Core.ExecutionContext(this, op, Scope); } public IAtomicOperation CreateChildOperation(IOperator op, IScope s) { return new Core.ExecutionContext(this, op, s); } #endregion #region Engine Helper public void RunOperator(IOperator op, IScope scope, CancellationToken cancellationToken) { var stack = new Stack(); stack.Push(CreateChildOperation(op, scope)); while (stack.Count > 0) { cancellationToken.ThrowIfCancellationRequested(); var next = stack.Pop(); if (next is OperationCollection) { var coll = (OperationCollection)next; for (int i = coll.Count - 1; i >= 0; i--) if (coll[i] != null) stack.Push(coll[i]); } else if (next is IAtomicOperation) { var operation = (IAtomicOperation)next; try { next = operation.Operator.Execute((IExecutionContext)operation, cancellationToken); } catch (Exception ex) { stack.Push(operation); if (ex is OperationCanceledException) throw ex; else throw new OperatorExecutionException(operation.Operator, ex); } if (next != null) stack.Push(next); } } } #endregion } }