Changeset 15555


Ignore:
Timestamp:
12/20/17 23:35:23 (2 years ago)
Author:
abeham
Message:

#1614: finished checking the implementation against the paper

Location:
branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs

    r15553 r15555  
    3232
    3333namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
     34  /// <summary>
     35  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
     36  /// </summary>
    3437  [Item("GQAPPathRelinking", "Operator that performs path relinking between two solutions. It is described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
    3538  [StorableClass]
     
    7174      var cmp = new IntegerVectorEqualityComparer();
    7275
     76      var greedy = true; // greedy performed better according to the paper
    7377      var sFit = problemInstance.ToSingleObjective(sourceEval);
    7478      var tFit = problemInstance.ToSingleObjective(targetEval);
     
    114118        }
    115119        if (B.Count > 0) { // line 21 of Algorithm 4
    116           var pi = B.SampleProportional(random, 1, B_fit.Select(x => 1.0 / x), false).First(); // line 22 of Algorithm 4
     120          GQAPSolution pi;
     121          // line 22 of Algorithm 4
     122          if (greedy) {
     123            pi = B.Select((val, idx) => new { Index = idx, Value = val }).MinItems(x => B_fit[x.Index]).Shuffle(random).First().Value;
     124          } else {
     125            pi = B.SampleProportional(random, 1, B_fit.Select(x => 1.0 / x), false).First();
     126          }
    117127          var diff = IntegerVectorEqualityComparer.GetDifferingIndices(pi.Assignment, target); // line 23 of Algorithm 4
    118128          var I = phi.Except(diff); // line 24 of Algorithm 4
     
    126136            pi_star = pi; // line 30 of Algorithm 4
    127137          }
    128         } else return pi_star ?? new GQAPSolution((IntegerVector)source.Clone(), (Evaluation)sourceEval.Clone());
     138        } else return pi_star;
    129139        phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
    130140      }
    131141
    132       return pi_star ?? new GQAPSolution((IntegerVector)source.Clone(), (Evaluation)sourceEval.Clone());
     142      return pi_star;
    133143    }
    134144
  • branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs

    r15553 r15555  
    3131using HeuristicLab.Parameters;
    3232using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     33using HeuristicLab.Random;
    3334
    3435namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
     36  /// <summary>
     37  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
     38  /// </summary>
    3539  [Item("ApproximateLocalSearch", "The approximate local search is described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
    3640  [StorableClass]
     
    105109
    106110      /// <summary>
    107       /// The implementation differs slightly from Mateus et al. in that the maximumIterations parameter defines a cap
    108       /// on the number of steps that the local search can perform. While the maxSampleSize parameter corresponds to
    109       /// the maxItr parameter defined by Mateus et al.
    110111      /// </summary>
    111112      /// <param name="random">The random number generator to use.</param>
     
    127128      var evaluations = 0.0;
    128129      var deltaEvaluationFactor = 1.0 / assignment.Length;
    129       while (true) {
    130         int count = 0;
    131         var CLS = new List<Tuple<NMove, double, Evaluation>>();
    132         double sum = 0.0;
     130      var greedy = true; // greedy selection performed better in 5 of 8 instances according to the paper
     131      while (true) { // line 1 of Algorithm 3
     132        var count = 0; // line 2 of Algorithm 3
     133        var CLS = new List<Tuple<NMove, double, Evaluation>>(); // line 3 of Algorithm 3
    133134        do {
    134           NMove move;
    135           if (random.NextDouble() < oneMoveProbability)
    136             move = StochasticNMoveSingleMoveGenerator.GenerateOneMove(random, assignment, capacities);
    137           else move = StochasticNMoveSingleMoveGenerator.GenerateTwoMove(random, assignment, capacities);
    138          
     135          var move = Move(random, assignment, oneMoveProbability, capacities); // line 4 of Algorithm 3
     136
    139137          var moveEval = GQAPNMoveEvaluator.Evaluate(move, assignment, evaluation, problemInstance);
    140138          evaluations += move.Indices.Count * deltaEvaluationFactor;
    141139          double moveQuality = problemInstance.ToSingleObjective(moveEval);
    142140
    143           if (moveEval.ExcessDemand <= 0.0 && moveQuality < quality) {
    144             CLS.Add(Tuple.Create(move, moveQuality, moveEval));
    145             sum += 1.0 / moveQuality;
     141          if (moveEval.ExcessDemand <= 0.0 && moveQuality < quality) { // line 5 of Algorithm 3
     142            CLS.Add(Tuple.Create(move, moveQuality, moveEval)); // line 6 of Algorithm 3
    146143          }
    147           count++;
    148         } while (CLS.Count < maxCLS && count < maximumIterations);
     144          count++; // line 8 of Algorithm 3
     145        } while (CLS.Count < maxCLS && count < maximumIterations); // line 9 of Algorithm 3
    149146
    150         if (CLS.Count == 0) {
     147        if (CLS.Count == 0) { // line 10 of Algorithm 3
    151148          evaluatedSolutions += (int)Math.Ceiling(evaluations);
    152149          return; // END
    153150        } else {
    154           var ball = random.NextDouble() * sum;
    155           var selected = CLS.Last();
    156           foreach (var candidate in CLS) {
    157             ball -= 1.0 / candidate.Item2;
    158             if (ball <= 0.0) {
    159               selected = candidate;
    160               break;
    161             }
     151          // line 11 of Algorithm 3
     152          Tuple<NMove, double, Evaluation> selected;
     153          if (greedy) {
     154            selected = CLS.MinItems(x => x.Item2).Shuffle(random).First();
     155          } else {
     156            selected = CLS.SampleProportional(random, 1, CLS.Select(x => 1.0 / x.Item2), false, false).Single();
    162157          }
    163158          NMoveMaker.Apply(assignment, selected.Item1);
     
    166161        }
    167162      }
     163    }
     164
     165    private static NMove Move(IRandom random, IntegerVector assignment, double oneMoveProbability, DoubleArray capacities) {
     166      if (random.NextDouble() < oneMoveProbability)
     167        return StochasticNMoveSingleMoveGenerator.GenerateOneMove(random, assignment, capacities);
     168      return StochasticNMoveSingleMoveGenerator.GenerateTwoMove(random, assignment, capacities);
    168169    }
    169170
  • branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs

    r15553 r15555  
    3333
    3434namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
     35  /// <summary>
     36  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
     37  /// </summary>
    3538  [Item("GreedyRandomizedSolutionCreator", "Creates a solution according to the procedure described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
    3639  [StorableClass]
     
    6063    public static IntegerVector CreateSolution(IRandom random, GQAPInstance problemInstance,
    6164      int maximumTries, bool createMostFeasibleSolution, CancellationToken cancelToken) {
     65      var weights = problemInstance.Weights;
     66      var distances = problemInstance.Distances;
    6267      var demands = problemInstance.Demands;
    6368      var capacities = problemInstance.Capacities.ToArray();
     69      var transportCosts = problemInstance.TransportationCosts;
    6470      var equipments = demands.Length;
    6571      var locations = capacities.Length;
     
    6975      double minViolation = double.MaxValue;
    7076      int[] bestAssignment = null;
    71       var CF = new bool[equipments]; // set of chosen facilities / equipments
    72       var T = new List<int>(equipments); // set of facilities / equpiments that can be assigned to the set of chosen locations (CL)
     77      var F = new List<int>(equipments); // set of (initially) all facilities / equipments
     78      var CF = new List<int>(equipments); // set of chosen facilities / equipments
     79      var L = new List<int>(locations); // set of (initially) all locations
    7380      var CL_list = new List<int>(locations); // list of chosen locations
    7481      var CL_selected = new bool[locations]; // bool decision if location is chosen
    75       var F = new List<int>(equipments); // set of (initially) all facilities / equipments
    76       var L = new List<int>(locations); // set of (initially) all locations
    77      
     82      var T = new List<int>(equipments); // set of facilities / equpiments that can be assigned to the set of chosen locations (CL)
     83      var H = new double[locations]; // proportions for choosing locations in stage 1
     84      var W = new double[equipments]; // proportions for choosing facilities in stage 2
     85      var Z = new double[locations]; // proportions for choosing locations in stage 2
     86
    7887      while (maximumTries <= 0 || tries < maximumTries) {
    7988        cancelToken.ThrowIfCancellationRequested();
    8089
    81         Array.Copy(capacities, slack, locations);
    82         Array.Clear(CF, 0, equipments);
    83         Array.Clear(CL_selected, 0, locations);
    84         CL_list.Clear();
    85         T.Clear();
    86 
    87         F.Clear(); F.AddRange(Enumerable.Range(0, equipments));
    88         L.Clear(); L.AddRange(Enumerable.Range(0, locations));
    89 
    90         double threshold = 1.0;
    91         do {
    92           if (L.Count > 0 && random.NextDouble() < threshold) {
    93             int l = L.SampleRandom(random);
    94             L.Remove(l);
    95             CL_list.Add(l);
    96             CL_selected[l] = true;
    97             T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands));
    98           }
    99           if (T.Count > 0) {
    100             var fidx = Enumerable.Range(0, T.Count).SampleRandom(random);
    101             var f = T[fidx];
    102             T.RemoveAt(fidx);
    103             F.Remove(f); // TODO: slow
    104             CF[f] = true;
    105             int l = WhereSlackGreaterOrEqual(CL_list, demands[f], slack).SampleRandom(random);
    106             assignment[f] = l + 1;
     90        Array.Copy(capacities, slack, locations); // line 2 of Algorihm 2
     91        CF.Clear(); // line 2 of Algorihm 2
     92        Array.Clear(CL_selected, 0, locations); // line 2 of Algorihm 2
     93        CL_list.Clear(); // line 2 of Algorihm 2
     94        T.Clear(); // line 2 of Algorihm 2
     95
     96        F.Clear(); F.AddRange(Enumerable.Range(0, equipments)); // line 2 of Algorihm 2
     97        L.Clear(); L.AddRange(Enumerable.Range(0, locations)); // line 2 of Algorihm 2
     98
     99        double threshold = 1.0; // line 3 of Algorithm 2
     100        do { // line 4 of Algorithm 2
     101          if (L.Count > 0 && random.NextDouble() < threshold) { // line 5 of Algorithm 2
     102            // H is the proportion that a location is chosen
     103            // The paper doesn't mention what happens if the candidate list CL
     104            // does not contain an element in which case according to the formula
     105            // all H_k elements would be 0 which would be equal to random selection
     106            var HH = H.Select((v, i) => new { Index = i, Value = v })
     107              .Where(x => !CL_selected[x.Index])
     108              .Select(x => x.Value);
     109            int l = L.SampleProportional(random, 1, HH, false, false).Single(); // line 6 of Algorithm 2
     110            L.Remove(l); // line 7 of Algorithm 2
     111            CL_list.Add(l); // line 7 of Algorithm 2
     112            CL_selected[l] = true; // line 7 of Algorithm 2
     113            for (var k = 0; k < locations; k++)
     114              if (!CL_selected[k])
     115                H[k] += capacities[k] * capacities[l] / distances[k, l];
     116            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands)); // line 8 of Algorithm 2
     117          }
     118          if (T.Count > 0) { // line 10 of Algorithm 2
     119            // W is the proportion that an equipment is chosen
     120            Array.Clear(W, 0, W.Length);
     121            var wk = 0;
     122            foreach (var k in T) {
     123              for (var h = 0; h < equipments; h++) {
     124                if (k == h) continue;
     125                W[wk] += weights[k, h];
     126              }
     127              W[wk] *= demands[k];
     128              wk++;
     129            }
     130            var f = T.SampleProportional(random, 1, W.Take(T.Count), false, false) // line 11 of Algorithm 2
     131              .Single();
     132            T.Remove(f); // line 12 of Algorithm 2
     133            F.Remove(f); // line 12 of Algorithm 2
     134            CF.Add(f); // line 12 of Algorithm 2
     135            var R = WhereSlackGreaterOrEqual(CL_list, demands[f], slack).ToList(); // line 13 of Algorithm 2
     136            // Z is the proportion that a location is chosen in stage 2
     137            Array.Clear(Z, 0, Z.Length);
     138            var zk = 0;
     139            foreach (var k in R) {
     140              // d is an increase in fitness if f would be assigned to location k
     141              var d = problemInstance.InstallationCosts[f, k];
     142              foreach (var i in CF) {
     143                if (assignment[i] == 0) continue; // i is unassigned
     144                var j = assignment[i] - 1;
     145                d += transportCosts * weights[f, i] * distances[k, j];
     146              }
     147              foreach (var h in CL_list) {
     148                if (k == h) continue;
     149                Z[zk] += slack[k] * capacities[h] / (d * distances[k, h]);
     150              }
     151              zk++;
     152            }
     153            int l = R.SampleProportional(random, 1, Z.Take(R.Count), false, false).Single(); // line 14 of Algorithm 2
     154            assignment[f] = l + 1; // line 15 of Algorithm 2
    107155            slack[l] -= demands[f];
    108             T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands));
    109             threshold = 1.0 - (double)T.Count / Math.Max(F.Count, 1.0);
    110           }
    111         } while (T.Count > 0 || L.Count > 0);
     156            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands)); // line 16 of Algorithm 2
     157            threshold = 1.0 - (double)T.Count / Math.Max(F.Count, 1.0); // line 17 of Algorithm 2
     158          }
     159        } while (T.Count > 0 || L.Count > 0); // line 19 of Algorithm 2
     160
    112161        if (maximumTries > 0) tries++;
     162
    113163        if (F.Count == 0) {
    114           bestAssignment = assignment;
     164          bestAssignment = assignment.Select(x => x - 1).ToArray();
    115165          break;
    116166        } else if (createMostFeasibleSolution) {
     
    130180          double violation = slack.Select(x => x < 0 ? -x : 0).Sum();
    131181          if (violation < minViolation) {
    132             bestAssignment = assignment;
    133             assignment = new int[equipments];
     182            bestAssignment = assignment.Select(x => x - 1).ToArray();
    134183            minViolation = violation;
    135184          }
     185          assignment = new int[equipments];
    136186        }
    137187      }
    138188
    139       if (bestAssignment == null || bestAssignment.Any(x => x == 0))
     189      if (bestAssignment == null)
    140190        throw new InvalidOperationException(String.Format("No solution could be found in {0} tries.", maximumTries));
    141191
    142       return new IntegerVector(bestAssignment.Select(x => x - 1).ToArray());
     192      return new IntegerVector(bestAssignment);
    143193    }
    144194
  • branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/RandomButFeasibleSolutionCreator.cs

    r15504 r15555  
    6565      int counter = 0;
    6666      double minViolation = double.MaxValue;
    67       var slack = new DoubleArray(capacities.Length);
    68       var assignment = new IntegerVector(demands.Length);
     67      var slack = new double[capacities.Length];
     68      var assignment = new int[demands.Length];
    6969
    7070      while (!isFeasible) {
     
    8686        isFeasible = violation == 0;
    8787        if (isFeasible || violation < minViolation) {
    88           result = (IntegerVector)assignment.Clone();
     88          result = new IntegerVector(assignment);
    8989          minViolation = violation;
    9090        }
     
    100100    }
    101101
    102     private static IEnumerable<int> GetFreeLocations(int equipment, DoubleArray demands, DoubleArray freeCapacities) {
     102    private static IEnumerable<int> GetFreeLocations(int equipment, DoubleArray demands, double[] freeCapacities) {
    103103      var freeLocations = freeCapacities
    104104        .Select((v, idx) => new KeyValuePair<int, double>(idx, v))
  • branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/SlackMinimizationSolutionCreator.cs

    r15504 r15555  
    7474      int counter = 0;
    7575      double minViolation = double.MaxValue;
    76       var slack = new DoubleArray(capacities.Length);
     76      var slack = new double[capacities.Length];
    7777      var assignment = new Dictionary<int, int>(demands.Length);
    7878
     
    150150    }
    151151
    152     private static void RandomFeasibleWalk(IRandom random, Dictionary<int, int> assignment, DoubleArray demands, DoubleArray slack, int walkLength) {
     152    private static void RandomFeasibleWalk(IRandom random, Dictionary<int, int> assignment, DoubleArray demands, double[] slack, int walkLength) {
    153153      for (int i = 0; i < walkLength; i++) {
    154154        var equipments = Enumerable.Range(0, demands.Length).Shuffle(random);
Note: See TracChangeset for help on using the changeset viewer.