#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.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Operators; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment { [Item("N-Move Evaluator", "Evaluates an N-Move.")] [StorableClass] public class GQAPNMoveEvaluator : SingleSuccessorOperator, IGQAPNMoveEvaluator, IQualityAwareGQAPOperator, IProblemInstanceAwareGQAPOperator { #region Parameter Descriptions public static readonly string MoveQualityDescription = "The quality of the move if it would be applied."; public static readonly string MoveEvaluationDescription = "The results of evaluating the move."; #endregion #region Parameter Properties public ILookupParameter MoveQualityParameter { get { return (ILookupParameter)Parameters["MoveQuality"]; } } public ILookupParameter MoveEvaluationParameter { get { return (ILookupParameter)Parameters["MoveEvaluation"]; } } public ILookupParameter MoveParameter { get { return (ILookupParameter)Parameters["Move"]; } } public ILookupParameter AssignmentParameter { get { return (ILookupParameter)Parameters["Assignment"]; } } public ILookupParameter QualityParameter { get { return (ILookupParameter)Parameters["Quality"]; } } public ILookupParameter EvaluationParameter { get { return (ILookupParameter)Parameters["Evaluation"]; } } public ILookupParameter ProblemInstanceParameter { get { return (ILookupParameter)Parameters["ProblemInstance"]; } } #endregion [StorableConstructor] protected GQAPNMoveEvaluator(bool deserializing) : base(deserializing) { } protected GQAPNMoveEvaluator(GQAPNMoveEvaluator original, Cloner cloner) : base(original, cloner) { } public GQAPNMoveEvaluator() : base() { Parameters.Add(new LookupParameter("Assignment", GQAPSolutionCreator.AssignmentDescription)); Parameters.Add(new LookupParameter("Move", GQAPNMoveGenerator.MoveDescription)); Parameters.Add(new LookupParameter("Quality", "")); Parameters.Add(new LookupParameter("Evaluation", GQAP.EvaluationDescription)); Parameters.Add(new LookupParameter("MoveQuality", MoveQualityDescription)); Parameters.Add(new LookupParameter("MoveEvaluation", MoveEvaluationDescription)); Parameters.Add(new LookupParameter("ProblemInstance", GQAP.ProblemInstanceDescription)); } public override IDeepCloneable Clone(Cloner cloner) { return new GQAPNMoveEvaluator(this, cloner); } public static Evaluation Evaluate(NMove move, IntegerVector assignment, Evaluation evaluation, GQAPInstance problemInstance) { int moves = move.N; var newEvaluation = new Evaluation() { ExcessDemand = evaluation.ExcessDemand, FlowCosts = evaluation.FlowCosts, InstallationCosts = evaluation.InstallationCosts, Slack = evaluation.Slack.ToArray() }; foreach (var kvp in move.NewAssignments) { int equip = kvp.Key; int newLoc = kvp.Value; int oldLoc = assignment[equip]; var equipDemand = problemInstance.Demands[equip]; newEvaluation.InstallationCosts -= problemInstance.InstallationCosts[equip, oldLoc]; newEvaluation.InstallationCosts += problemInstance.InstallationCosts[equip, newLoc]; for (int j = 0; j < assignment.Length; j++) { if (!move.NewAssignments.ContainsKey(j)) { newEvaluation.FlowCosts += problemInstance.Weights[equip, j] * problemInstance.Distances[newLoc, assignment[j]]; newEvaluation.FlowCosts -= problemInstance.Weights[equip, j] * problemInstance.Distances[oldLoc, assignment[j]]; newEvaluation.FlowCosts += problemInstance.Weights[j, equip] * problemInstance.Distances[assignment[j], newLoc]; newEvaluation.FlowCosts -= problemInstance.Weights[j, equip] * problemInstance.Distances[assignment[j], oldLoc]; } else { newEvaluation.FlowCosts += problemInstance.Weights[equip, j] * problemInstance.Distances[newLoc, move.NewAssignments[j]]; newEvaluation.FlowCosts -= problemInstance.Weights[equip, j] * problemInstance.Distances[oldLoc, assignment[j]]; } } newEvaluation.Slack[oldLoc] += equipDemand; if (newEvaluation.Slack[oldLoc] < equipDemand) newEvaluation.ExcessDemand -= Math.Min(equipDemand, equipDemand - newEvaluation.Slack[oldLoc]); newEvaluation.Slack[newLoc] -= equipDemand; if (newEvaluation.Slack[newLoc] < 0) newEvaluation.ExcessDemand += Math.Min(equipDemand, -newEvaluation.Slack[newLoc]); } return newEvaluation; } public override IOperation Apply() { var problemInstance = ProblemInstanceParameter.ActualValue; var evaluation = EvaluationParameter.ActualValue; var moveEvaluation = Evaluate(MoveParameter.ActualValue, AssignmentParameter.ActualValue, evaluation, problemInstance); MoveEvaluationParameter.ActualValue = moveEvaluation; return base.Apply(); } } }