Free cookie consent management tool by TermsFeed Policy Generator

source: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPBinarySolver.cs @ 15866

Last change on this file since 15866 was 15713, checked in by abeham, 7 years ago

#1614:

  • added additional constraint to benchmark data generator and updated one instance that was affected by this
  • added fitness landscape characteristics for the GQAP
  • fixed RLD analysis view to compensate for empty convergence graphs
  • fixed CPLEX solvers not using the obj value when the solver terminates (callback is not called if proven optimal solution is found)
  • added code for local solver to also check on final quality
File size: 8.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Threading;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Data;
27using HeuristicLab.Encodings.IntegerVectorEncoding;
28using HeuristicLab.Optimization;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using localsolver;
31
32namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSolverNet {
33  [Item("LocalSolver Binary (GQAP)", "LocalSolver algorithm solving the GQAP using 0-1 decision variables")]
34  [StorableClass]
35  [Creatable(CreatableAttribute.Categories.Algorithms)]
36  public sealed class GQAPBinarySolver : ContextAlgorithm<LocalSolverContext, IntegerVectorEncoding> {
37    public override bool SupportsPause {
38      get { return false; }
39    }
40
41    public override Type ProblemType {
42      get { return typeof(GQAP); }
43    }
44
45    public new GQAP Problem {
46      get { return (GQAP)base.Problem; }
47      set { base.Problem = value; }
48    }
49
50    // LS Program variables
51    private LSExpression[][] x;
52    private LSExpression[] equipmentsOnLocations;
53    private LSExpression obj;
54    private LocalSolver localSolver;
55
56
57    [StorableConstructor]
58    private GQAPBinarySolver(bool deserializing) : base(deserializing) { }
59    private GQAPBinarySolver(GQAPBinarySolver original, Cloner cloner)
60    : base(original, cloner) {
61    }
62    public GQAPBinarySolver() {
63      Problem = new GQAP();
64      MaximumEvaluationsParameter.Hidden = true;
65      MaximumIterationsParameter.Hidden = true;
66    }
67
68    public override IDeepCloneable Clone(Cloner cloner) {
69      return new GQAPBinarySolver(this, cloner);
70    }
71
72    private double prevObj;
73    private DateTime lastUpdate;
74    private CancellationToken token;
75
76    private void LocalSolverOnIterationTicked(LocalSolver ls, LSCallbackType type) {
77      IResult result;
78      Context.Iterations++;
79      if ((DateTime.UtcNow - lastUpdate) > TimeSpan.FromSeconds(1)) {
80        if (Results.TryGetValue("Iterations", out result))
81          ((IntValue)result.Value).Value = Context.Iterations;
82        else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
83        lastUpdate = DateTime.UtcNow;
84      }
85
86      if (token.IsCancellationRequested) localSolver.Stop();
87
88      var curObj = obj.GetDoubleValue();
89
90      if (curObj >= prevObj) return;
91      UpdateSolution(curObj);
92
93      Context.RunOperator(Analyzer, CancellationToken.None);
94
95      if (StoppingCriterion()) localSolver.Stop();
96    }
97
98    private void UpdateSolution(double obj) {
99      IResult result;
100      prevObj = obj;
101      Context.BestQuality = obj;
102
103      if (Results.TryGetValue("BestQuality", out result))
104        ((DoubleValue)result.Value).Value = Context.BestQuality;
105      else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
106
107      var locations = Problem.ProblemInstance.Capacities.Length;
108      var best = new int[Problem.ProblemInstance.Demands.Length];
109      for (var i = 0; i < best.Length; i++) {
110        for (var j = 0; j < locations; j++) {
111          if (x[i][j].GetIntValue() == 1) {
112            best[i] = j;
113            break;
114          }
115        }
116      }
117      var bestVec = new IntegerVector(best);
118      var eval = Problem.ProblemInstance.Evaluate(bestVec);
119      Context.BestSolution = new GQAPSolution(bestVec, eval);
120
121      var scope = Context.ToScope(new GQAPSolution(new IntegerVector(best), (Evaluation)eval.Clone()), Problem.ProblemInstance.ToSingleObjective(eval));
122      Context.ReplaceIncumbent(scope);
123
124      if (Results.TryGetValue("BestSolution", out result))
125        result.Value = Context.BestSolution;
126      else Results.Add(new Result("BestSolution", Context.BestSolution));
127    }
128
129    protected override void Initialize(CancellationToken cancellationToken) {
130      base.Initialize(cancellationToken);
131
132      prevObj = double.MaxValue;
133    }
134
135    protected override void Run(CancellationToken cancellationToken) {
136      base.Run(cancellationToken);
137      token = cancellationToken;
138      lastUpdate = DateTime.UtcNow.AddSeconds(-1);
139      localSolver = new LocalSolver();
140
141      // Declares the optimization model
142      LSModel model = localSolver.GetModel();
143
144      var data = Problem.ProblemInstance;
145
146      // x[f,l] = 1 if equipments f is on location l, 0 otherwise
147      x = new LSExpression[data.Demands.Length][];
148      for (int f = 0; f < data.Demands.Length; f++) {
149        x[f] = new LSExpression[data.Capacities.Length];
150        for (int l = 0; l < data.Capacities.Length; l++) {
151          x[f][l] = model.Bool();
152        }
153      }
154
155      // All equipments are installed in exactly 1 location
156      for (int f = 0; f < data.Demands.Length; f++) {
157        LSExpression nbLocationsAssigned = model.Sum();
158        for (int l = 0; l < data.Capacities.Length; l++) {
159          nbLocationsAssigned.AddOperand(x[f][l]);
160        }
161        model.Constraint(nbLocationsAssigned == 1);
162      }
163
164      // All locations contain not more equipments than there is capacity for
165      for (int l = 0; l < data.Capacities.Length; l++) {
166        LSExpression assignedDemand = model.Sum();
167        for (int f = 0; f < data.Demands.Length; f++) {
168          assignedDemand.AddOperand(x[f][l] * data.Demands[f]);
169        }
170        model.Constraint(assignedDemand <= data.Capacities[l]);
171      }
172
173      // Index of the assigned location of equipment f
174      equipmentsOnLocations = new LSExpression[data.Demands.Length];
175      for (int f = 0; f < data.Demands.Length; f++) {
176        equipmentsOnLocations[f] = model.Sum();
177        for (int l = 0; l < data.Capacities.Length; l++) {
178          equipmentsOnLocations[f].AddOperand(l * x[f][l]);
179        }
180      }
181
182      // Create distances as an array to be accessed by an at operator
183      var distancesJagged = new double[data.Capacities.Length][];
184      for (var i = 0; i < data.Capacities.Length; i++) {
185        distancesJagged[i] = new double[data.Capacities.Length];
186        for (var j = 0; j < data.Capacities.Length; j++)
187          distancesJagged[i][j] = data.Distances[i, j];
188      }
189      var installJagged = new double[data.Demands.Length][];
190      for (var i = 0; i < data.Demands.Length; i++) {
191        installJagged[i] = new double[data.Capacities.Length];
192        for (var j = 0; j < data.Capacities.Length; j++)
193          installJagged[i][j] = data.InstallationCosts[i, j];
194      }
195      LSExpression distancesArray = model.Array(distancesJagged);
196      LSExpression installCostsArray = model.Array(installJagged);
197
198      // Minimize the sum of product distance*flow
199      obj = model.Sum();
200      for (int f1 = 0; f1 < data.Demands.Length; f1++) {
201        for (int f2 = 0; f2 < data.Demands.Length; f2++) {
202          obj.AddOperand(data.TransportationCosts * data.Weights[f1, f2] * distancesArray[equipmentsOnLocations[f1], equipmentsOnLocations[f2]]);
203        }
204        obj.AddOperand(installCostsArray[f1, equipmentsOnLocations[f1]]);
205      }
206
207      model.Minimize(obj);
208
209      try {
210        model.Close();
211
212        // Parameterizes the solver.
213        LSPhase phase = localSolver.CreatePhase();
214        phase.SetTimeLimit((int)Math.Ceiling(MaximumRuntime.TotalSeconds));
215
216        localSolver.AddCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked);
217
218        localSolver.Solve();
219
220        var curObj = obj.GetDoubleValue();
221        if (curObj < prevObj)
222          UpdateSolution(curObj);
223
224        localSolver.RemoveCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked);
225      } finally {
226        localSolver.Dispose();
227      }
228
229      Context.RunOperator(Analyzer, CancellationToken.None);
230    }
231  }
232}
Note: See TracBrowser for help on using the repository browser.