Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2817-BinPackingSpeedup/HeuristicLab.Problems.BinPacking/3.3/Algorithms/3D/ExtremePointAlgorithm.cs @ 15454

Last change on this file since 15454 was 15454, checked in by rhanghof, 7 years ago

#2817

  • Extreme point bin packing does not need the occupation layer anymore
  • Changes at the fitting algorithm. Now they are packing the items as in the paper of S. Martello, D. Pisinger, D. Vigo described
File size: 14.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Joseph Helm and 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.Collections.Generic;
24using System.Linq;
25using System.Threading;
26
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Encodings.PermutationEncoding;
31using HeuristicLab.Optimization;
32using HeuristicLab.Parameters;
33using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
34using HeuristicLab.Problems.BinPacking3D.Packer;
35
36namespace HeuristicLab.Problems.BinPacking3D {
37
38  public enum SortingMethod { All, Given, VolumeHeight, HeightVolume, AreaHeight, HeightArea, ClusteredAreaHeight, ClusteredHeightArea }
39  public enum FittingMethod { All, FirstFit, ResidualSpaceBestFit, FreeVolumeBestFit }
40
41  [Item("Extreme-point-based Bin Packing (3d)", "An implementation of the extreme-point based packing described in Crainic, T. G., Perboli, G., & Tadei, R. (2008). Extreme point-based heuristics for three-dimensional bin packing. Informs Journal on computing, 20(3), 368-384.")]
42  [StorableClass]
43  [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms, Priority = 180)]
44  public sealed class ExtremePointAlgorithm : BasicAlgorithm {
45
46    public override Type ProblemType {
47      get { return typeof(PermutationProblem); }
48    }
49
50    public new PermutationProblem Problem {
51      get { return (PermutationProblem)base.Problem; }
52      set { base.Problem = value; }
53    }
54
55    public override bool SupportsPause {
56      get { return false; }
57    }
58
59    [Storable]
60    private readonly IValueParameter<EnumValue<SortingMethod>> sortingMethodParameter;
61    public IValueParameter<EnumValue<SortingMethod>> SortingMethodParameter {
62      get { return sortingMethodParameter; }
63    }
64
65    [Storable]
66    private readonly IValueParameter<EnumValue<FittingMethod>> fittingMethodParameter;
67    public IValueParameter<EnumValue<FittingMethod>> FittingMethodParameter {
68      get { return fittingMethodParameter; }
69    }
70
71    [Storable]
72    private readonly IValueParameter<PercentValue> deltaParameter;
73    public IValueParameter<PercentValue> DeltaParameter {
74      get { return deltaParameter; }
75    }
76
77    [StorableConstructor]
78    private ExtremePointAlgorithm(bool deserializing) : base(deserializing) { }
79    private ExtremePointAlgorithm(ExtremePointAlgorithm original, Cloner cloner)
80      : base(original, cloner) {
81      sortingMethodParameter = cloner.Clone(original.sortingMethodParameter);
82      fittingMethodParameter = cloner.Clone(original.fittingMethodParameter);
83      deltaParameter = cloner.Clone(original.deltaParameter);
84    }
85    public ExtremePointAlgorithm() {
86      Parameters.Add(sortingMethodParameter = new ValueParameter<EnumValue<SortingMethod>>("SortingMethod", "In which order the items should be packed.", new EnumValue<SortingMethod>(SortingMethod.All)));
87      Parameters.Add(fittingMethodParameter = new ValueParameter<EnumValue<FittingMethod>>("FittingMethod", "Which method to fit should be used.", new EnumValue<FittingMethod>(FittingMethod.All)));
88      Parameters.Add(deltaParameter = new ValueParameter<PercentValue>("Delta", "[1;100]% Clustered sorting methods use a delta parameter to determine the clusters.", new PercentValue(.1)));
89
90      Problem = new PermutationProblem();
91    }
92
93    public override IDeepCloneable Clone(Cloner cloner) {
94      return new ExtremePointAlgorithm(this, cloner);
95    }
96
97    [StorableHook(HookType.AfterDeserialization)]
98    private void AfterDeserialization() {
99    }
100
101    /// <summary>
102    /// Runs the extreme point algorithm and adds the results to the property <see cref="Result"/>
103    /// </summary>
104    /// <param name="token"></param>
105    protected override void Run(CancellationToken token) {
106      var items = Problem.Items;
107      var bin = Problem.BinShape;
108      var sorting = new[] { SortingMethodParameter.Value.Value };
109      if (sorting[0] == SortingMethod.All) {
110        sorting = Enum.GetValues(typeof(SortingMethod)).Cast<SortingMethod>().Where(x => x != SortingMethod.All).ToArray();
111      }
112      var fitting = new[] { fittingMethodParameter.Value.Value };
113      if (fitting[0] == FittingMethod.All) {
114        fitting = Enum.GetValues(typeof(FittingMethod)).Cast<FittingMethod>().Where(x => x != FittingMethod.All).ToArray();
115      }
116
117      //
118      var result = GetBest(bin, items, sorting, fitting, token);
119      if (result == null) {
120        throw new InvalidOperationException("No result obtained!");
121      }
122
123      Results.Add(new Result("Best Solution", "The best found solution", result.Item1));
124      Results.Add(new Result("Best Solution Quality", "The quality of the best found solution according to the evaluator", new DoubleValue(result.Item2)));
125
126      var binUtil = new BinUtilizationEvaluator();
127      var packRatio = new PackingRatioEvaluator();
128      Results.Add(new Result("Best Solution Bin Count",
129        "The number of bins in the best found solution",
130        new IntValue(result.Item1.NrOfBins)));
131      Results.Add(new Result("Best Solution Bin Utilization",
132        "The utilization given in percentage as calculated by the BinUtilizationEvaluator (total used space / total available space)",
133        new PercentValue(Math.Round(binUtil.Evaluate(result.Item1), 3))));
134
135      if (result.Item3.HasValue && sorting.Length > 1) {
136        Results.Add(new Result("Best Sorting Method",
137          "The sorting method that found the best solution",
138          new EnumValue<SortingMethod>(result.Item3.Value)));
139      }
140
141      if (result.Item4.HasValue && fitting.Length > 1) {
142        Results.Add(new Result("Best Fitting Method",
143          "The fitting method that found the best solution",
144          new EnumValue<FittingMethod>(result.Item4.Value)));
145      }
146    }
147
148    private Tuple<Solution, double, SortingMethod?, FittingMethod?> GetBest(PackingShape bin, IList<PackingItem> items, SortingMethod[] sortings, FittingMethod[] fittings, CancellationToken token) {
149      SortingMethod? bestSorting = null;
150      FittingMethod? bestFitting = null;
151      var best = double.NaN;
152      Solution bestSolution = null;
153      foreach (var fit in fittings) {
154        foreach (var sort in sortings) {
155          var result = Optimize(bin, items, sort, fit, DeltaParameter.Value.Value, Problem.UseStackingConstraints, Problem.SolutionEvaluator, token);
156          if (double.IsNaN(result.Item2) || double.IsInfinity(result.Item2)) {
157            continue;
158          }
159
160          if (double.IsNaN(best) || Problem.Maximization && result.Item2 > best || !Problem.Maximization && result.Item2 < best) {
161            bestSolution = result.Item1;
162            best = result.Item2;
163            bestSorting = sort;
164            bestFitting = fit;
165          }
166          if (token.IsCancellationRequested) {
167            return Tuple.Create(bestSolution, best, bestSorting, bestFitting);
168          }
169        }
170      }
171      if (double.IsNaN(best)) {
172        return null;
173      }
174      return Tuple.Create(bestSolution, best, bestSorting, bestFitting);
175    }
176
177    private static Tuple<Solution, double> Optimize(PackingShape bin, IList<PackingItem> items, SortingMethod sorting, FittingMethod fitting, double delta, bool stackingConstraints, IEvaluator evaluator, CancellationToken token) {
178      Permutation sortedItems = SortItemsBySortingMethod(bin, items, sorting, delta);
179
180      if (false) {// alt
181        ExtremePointPermutationDecoderBase decoder = GetDecoderByFittingMethod(fitting);
182        var sol = decoder.Decode(sortedItems, bin, items, stackingConstraints);
183        var fit = evaluator.Evaluate(sol);
184
185        return Tuple.Create(sol, fit);
186      } else {
187        Decoder.ExtremePointPermutationDecoder decoder = new Decoder.ExtremePointPermutationDecoder(GetBinPackerByFittingMethod(fitting, sortedItems, bin, items, stackingConstraints));
188
189        var sol = decoder.Decode(sortedItems, bin, items, stackingConstraints);
190        var fit = evaluator.Evaluate(sol);
191
192        return Tuple.Create(sol, fit);
193      }
194     
195
196     
197    }
198
199
200
201    private static BinPacker GetBinPackerByFittingMethod(FittingMethod fittingMethod, Permutation sortedItems, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
202      BinPacker binPacker = null;
203      switch (fittingMethod) {
204        case FittingMethod.FirstFit:
205          binPacker = new BinPackerFirstFit(sortedItems, binShape, items, useStackingConstraints);
206          break;
207        case FittingMethod.FreeVolumeBestFit:
208          binPacker = new BinPackerFreeVolumeBestFit(sortedItems, binShape, items, useStackingConstraints);
209          break;
210        case FittingMethod.ResidualSpaceBestFit:
211          binPacker = new BinPackerResidualSpaceBestFit(sortedItems, binShape, items, useStackingConstraints);
212          break;
213        default:
214          throw new ArgumentException("Unknown fitting method: " + fittingMethod);
215      }
216      return binPacker;
217    }
218
219    /// <summary>
220    /// Returns a new permutation of the given items depending on the sorting method
221    /// </summary>
222    /// <param name="bin"></param>
223    /// <param name="items"></param>
224    /// <param name="sortingMethod"></param>
225    /// <param name="delta"></param>
226    /// <returns></returns>
227    private static Permutation SortItemsBySortingMethod(PackingShape bin, IList<PackingItem> items, SortingMethod sortingMethod, double delta) {
228      Permutation sorted = null;
229      switch (sortingMethod) {
230        case SortingMethod.Given:
231          sorted = new Permutation(PermutationTypes.Absolute, Enumerable.Range(0, items.Count).ToArray());
232          break;
233        case SortingMethod.VolumeHeight:
234          sorted = new Permutation(PermutationTypes.Absolute,
235                    items.Select((v, i) => new { Index = i, Item = v })
236                         .OrderByDescending(x => x.Item.Depth * x.Item.Width * x.Item.Height)
237                         .ThenByDescending(x => x.Item.Height)
238                         .Select(x => x.Index).ToArray());
239          break;
240        case SortingMethod.HeightVolume:
241          sorted = new Permutation(PermutationTypes.Absolute,
242                    items.Select((v, i) => new { Index = i, Item = v })
243                         .OrderByDescending(x => x.Item.Height)
244                         .ThenByDescending(x => x.Item.Depth * x.Item.Width * x.Item.Height)
245                         .Select(x => x.Index).ToArray());
246          break;
247        case SortingMethod.AreaHeight:
248          sorted = new Permutation(PermutationTypes.Absolute,
249                    items.Select((v, i) => new { Index = i, Item = v })
250                         .OrderByDescending(x => x.Item.Depth * x.Item.Width)
251                         .ThenByDescending(x => x.Item.Height)
252                         .Select(x => x.Index).ToArray());
253          break;
254        case SortingMethod.HeightArea:
255          sorted = new Permutation(PermutationTypes.Absolute,
256                    items.Select((v, i) => new { Index = i, Item = v })
257                         .OrderByDescending(x => x.Item.Height)
258                         .ThenByDescending(x => x.Item.Depth * x.Item.Width)
259                         .Select(x => x.Index).ToArray());
260          break;
261        case SortingMethod.ClusteredAreaHeight:
262          double clusterRange = bin.Width * bin.Depth * delta;
263          sorted = new Permutation(PermutationTypes.Absolute,
264                    items.Select((v, i) => new { Index = i, Item = v, ClusterId = (int)(Math.Ceiling(v.Width * v.Depth / clusterRange)) })
265                        .GroupBy(x => x.ClusterId)
266                        .Select(x => new { Cluster = x.Key, Items = x.OrderByDescending(y => y.Item.Height).ToList() })
267                        .OrderByDescending(x => x.Cluster)
268                        .SelectMany(x => x.Items)
269                        .Select(x => x.Index).ToArray());
270          break;
271        case SortingMethod.ClusteredHeightArea:
272          double clusterRange2 = bin.Height * delta;
273          sorted = new Permutation(PermutationTypes.Absolute,
274                    items.Select((v, i) => new { Index = i, Item = v, ClusterId = (int)(Math.Ceiling(v.Height / clusterRange2)) })
275                        .GroupBy(x => x.ClusterId)
276                        .Select(x => new { Cluster = x.Key, Items = x.OrderByDescending(y => y.Item.Depth * y.Item.Width).ToList() })
277                        .OrderByDescending(x => x.Cluster)
278                        .SelectMany(x => x.Items)
279                        .Select(x => x.Index).ToArray());
280          break;
281        default:
282          throw new ArgumentException("Unknown sorting method: " + sortingMethod);
283      }
284      return sorted;
285    }
286
287    /// <summary>
288    /// Returns a decoder depending on the given fitting method
289    /// </summary>
290    /// <param name="fittingMethod"></param>
291    /// <returns></returns>
292    private static ExtremePointPermutationDecoderBase GetDecoderByFittingMethod(FittingMethod fittingMethod) {
293      ExtremePointPermutationDecoderBase decoder = null;
294      switch (fittingMethod) {
295        case FittingMethod.FirstFit:
296          decoder = new ExtremePointPermutationDecoder();
297          break;
298        case FittingMethod.FreeVolumeBestFit:
299          decoder = new FreeVolumeBestFitExtremePointPermutationDecoder();
300          break;
301        case FittingMethod.ResidualSpaceBestFit:
302          decoder = new ResidualSpaceBestFitExtremePointPermutationDecoder();
303          break;
304        default:
305          throw new ArgumentException("Unknown fitting method: " + fittingMethod);
306      }
307      return decoder;
308    }
309  }
310}
Note: See TracBrowser for help on using the repository browser.