#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.Threading; using HEAL.Attic; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Optimization; using localsolver; namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSolverNet { [Item("LocalSolver Integer (GQAP)", "LocalSolver algorithm solving the GQAP using integer decision variables")] [StorableType("6D0D77CE-A8DE-41EA-9674-A1D59782D03B")] [Creatable(CreatableAttribute.Categories.Algorithms)] public sealed class GQAPIntegerSolver : ContextAlgorithm { public override bool SupportsPause { get { return false; } } public override Type ProblemType { get { return typeof(GQAP); } } public new GQAP Problem { get { return (GQAP)base.Problem; } set { base.Problem = value; } } // LS Program variables private LSExpression[] x; private LSExpression obj; private LocalSolver localSolver; [StorableConstructor] private GQAPIntegerSolver(StorableConstructorFlag _) : base(_) { } private GQAPIntegerSolver(GQAPIntegerSolver original, Cloner cloner) : base(original, cloner) { } public GQAPIntegerSolver() { Problem = new GQAP(); MaximumEvaluationsParameter.Hidden = true; MaximumIterationsParameter.Hidden = true; } public override IDeepCloneable Clone(Cloner cloner) { return new GQAPIntegerSolver(this, cloner); } private double prevObj; private DateTime lastUpdate; private CancellationToken token; private void LocalSolverOnIterationTicked(LocalSolver ls, LSCallbackType type) { IResult result; Context.Iterations++; if ((DateTime.UtcNow - lastUpdate) > TimeSpan.FromSeconds(1)) { if (Results.TryGetValue("Iterations", out result)) ((IntValue)result.Value).Value = Context.Iterations; else Results.Add(new Result("Iterations", new IntValue(Context.Iterations))); lastUpdate = DateTime.UtcNow; } if (token.IsCancellationRequested) localSolver.Stop(); var curObj = obj.GetDoubleValue(); if (curObj >= prevObj) return; UpdateSolution(curObj); Context.RunOperator(Analyzer, CancellationToken.None); if (StoppingCriterion()) localSolver.Stop(); } private void UpdateSolution(double obj) { IResult result; prevObj = obj; Context.BestQuality = obj; if (Results.TryGetValue("BestQuality", out result)) ((DoubleValue)result.Value).Value = Context.BestQuality; else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality))); var locations = Problem.ProblemInstance.Capacities.Length; var best = new int[Problem.ProblemInstance.Demands.Length]; for (var i = 0; i < best.Length; i++) { best[i] = (int)x[i].GetIntValue(); } var bestVec = new IntegerVector(best); var eval = Problem.ProblemInstance.Evaluate(bestVec); Context.BestSolution = new GQAPSolution(bestVec, eval); var scope = Context.ToScope(new GQAPSolution(new IntegerVector(best), (Evaluation)eval.Clone()), Problem.ProblemInstance.ToSingleObjective(eval)); Context.ReplaceIncumbent(scope); if (Results.TryGetValue("BestSolution", out result)) result.Value = Context.BestSolution; else Results.Add(new Result("BestSolution", Context.BestSolution)); } protected override void Initialize(CancellationToken cancellationToken) { base.Initialize(cancellationToken); prevObj = double.MaxValue; } protected override void Run(CancellationToken cancellationToken) { base.Run(cancellationToken); token = cancellationToken; lastUpdate = DateTime.UtcNow.AddSeconds(-1); localSolver = new LocalSolver(); // Declares the optimization model LSModel model = localSolver.GetModel(); var data = Problem.ProblemInstance; // x[f] = location l, f ... facility/equipment x = new LSExpression[data.Demands.Length]; for (int f = 0; f < data.Demands.Length; f++) { x[f] = model.Int(0, data.Capacities.Length - 1); } // All locations contain not more equipments than there is capacity for for (int l = 0; l < data.Capacities.Length; l++) { var util = model.Sum(); for (var f = 0; f < data.Demands.Length; f++) util.AddOperand((x[f] == l) * data.Demands[f]); model.Constraint(util <= data.Capacities[l]); } // Create distances as an array to be accessed by an at operator var distancesJagged = new double[data.Capacities.Length][]; for (var i = 0; i < data.Capacities.Length; i++) { distancesJagged[i] = new double[data.Capacities.Length]; for (var j = 0; j < data.Capacities.Length; j++) distancesJagged[i][j] = data.Distances[i, j]; } var installJagged = new double[data.Demands.Length][]; for (var i = 0; i < data.Demands.Length; i++) { installJagged[i] = new double[data.Capacities.Length]; for (var j = 0; j < data.Capacities.Length; j++) installJagged[i][j] = data.InstallationCosts[i, j]; } LSExpression distancesArray = model.Array(distancesJagged); LSExpression installCostsArray = model.Array(installJagged); // Minimize the sum of product distance*flow obj = model.Sum(); for (int f1 = 0; f1 < data.Demands.Length; f1++) { for (int f2 = 0; f2 < data.Demands.Length; f2++) { obj.AddOperand(data.TransportationCosts * data.Weights[f1, f2] * distancesArray[x[f1], x[f2]]); } obj.AddOperand(installCostsArray[f1, x[f1]]); } model.Minimize(obj); try { model.Close(); // Parameterizes the solver. LSPhase phase = localSolver.CreatePhase(); phase.SetTimeLimit((int)Math.Ceiling(MaximumRuntime.TotalSeconds)); localSolver.AddCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked); localSolver.Solve(); var curObj = obj.GetDoubleValue(); if (curObj < prevObj) UpdateSolution(curObj); localSolver.RemoveCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked); } finally { localSolver.Dispose(); } Context.RunOperator(Analyzer, CancellationToken.None); } } }