#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
}
}