source: branches/2817-BinPackingSpeedup/HeuristicLab.Problems.BinPacking/3.3/3D/Packer/BinPackerMinRSLeft.cs @ 15646

Last change on this file since 15646 was 15646, checked in by rhanghof, 3 years ago

#2817:

  • Dealing with stackable items
  • Enhanced the Evaluator
  • Added parameters some paramters to the packing items
File size: 12.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 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.Text;
26using System.Threading.Tasks;
27using HeuristicLab.Common;
28using HeuristicLab.Encodings.PermutationEncoding;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using HeuristicLab.Problems.BinPacking3D.ExtremePointCreation;
31using HeuristicLab.Problems.BinPacking3D.ExtremePointPruning;
32
33namespace HeuristicLab.Problems.BinPacking3D.Packer {
34  internal class BinPackerMinRSLeft : BinPacker {
35    #region Constructors for HEAL
36    [StorableConstructor]
37    protected BinPackerMinRSLeft(bool deserializing) : base(deserializing) { }
38
39    public BinPackerMinRSLeft(BinPackerMinRSLeft original, Cloner cloner) : base(original, cloner) {
40    }
41
42    public override IDeepCloneable Clone(Cloner cloner) {
43      return new BinPackerMinRSLeft(this, cloner);
44    }
45    #endregion
46
47
48
49    public BinPackerMinRSLeft() : base() { }
50
51    /// <summary>
52    /// This proportion of the residual space left to the item height is used for deciding if a not stackable item should be placed.
53    /// </summary>
54    private const double NOT_STACKABLE_RS_LEFT_TO_ITEM_HEIGHT_PROPORTION = 1.1;
55
56    public override IList<BinPacking3D> PackItems(Permutation sortedItems, PackingShape binShape, IList<PackingItem> items, ExtremePointCreationMethod epCreationMethod, ExtremePointPruningMethod epPruningMethod, bool useStackingConstraints) {
57      var workingItems = CloneItems(items);
58      IList<BinPacking3D> packingList = new List<BinPacking3D>();
59      IList<int> remainingIds = new List<int>(sortedItems);
60
61      try {
62        while (remainingIds.Count > 0) {
63          BinPacking3D packingBin = new BinPacking3D(binShape);
64          PackRemainingItems(ref remainingIds, ref packingBin, workingItems, epCreationMethod, useStackingConstraints);
65          packingList.Add(packingBin);         
66        }
67      } catch (BinPacking3DException e) {
68      }
69
70      ExtremePointPruningFactory.CreatePruning().PruneExtremePoints(epPruningMethod, packingList);
71
72      return packingList;
73    }
74
75    /// <summary>
76    /// Tries to pack the remainig items into a given BinPacking3D object. Each item could be packed into the BinPacking3D object will be removed from the list of remaining ids
77    /// </summary>
78    /// <param name="remainingIds">List of remaining ids. After the method has been executed the list has to have less items</param>
79    /// <param name="packingBin">This object will be filled with some of the given items</param>
80    /// <param name="items">List of packing items. Some of the items will be assigned to the BinPacking3D object</param>
81    /// <param name="epCreationMethod"></param>
82    /// <param name="useStackingConstraints"></param>
83    protected void PackRemainingItems(ref IList<int> remainingIds, ref BinPacking3D packingBin, IList<PackingItem> items, ExtremePointCreationMethod epCreationMethod, bool useStackingConstraints) {
84      IExtremePointCreator extremePointCreator = ExtremePointCreatorFactory.CreateExtremePointCreator(epCreationMethod, useStackingConstraints);
85      var remainingNotStackableItems = new List<int>();
86      foreach (var itemId in new List<int>(remainingIds)) {
87        var item = items[itemId];
88
89        // If an item is not stackable it should have a minimum waste of the residual space.
90        // As long as there are stackable items left, put the non stackable items into a collection
91        // and try to find positions where they don't waste too much space.
92        // If there are no stackable items left the non stackable have to be treated as a stackable one.
93        if (!item.IsStackabel && useStackingConstraints && remainingIds.Where(x => items[x].IsStackabel).Any()) {
94          remainingNotStackableItems.Add(itemId);         
95        } else {
96          PackingPosition position = FindPackingPositionForItem(packingBin, item, useStackingConstraints);
97          // if a valid packing position could be found, the current item can be added to the given bin
98          if (position != null) {           
99            PackItem(packingBin, itemId, item, position, extremePointCreator, useStackingConstraints);
100            remainingIds.Remove(itemId);
101          }
102        }
103
104        // try to find a valid position for a non stackable item
105        var stackableLeft = remainingIds.Where(x => items[x].IsStackabel).Any();
106        foreach (var saId in new List<int>(remainingNotStackableItems)) {
107          item = items[saId];
108          PackingPosition position = null;
109          if (stackableLeft) {
110            position  = FindPackingPositionForNotStackableItem(packingBin, item, useStackingConstraints);
111          } else {
112            position = FindPackingPositionForItem(packingBin, item, useStackingConstraints);
113          }
114         
115          if (position != null) {           
116            PackItem(packingBin, saId, item, position, extremePointCreator, useStackingConstraints);
117            remainingIds.Remove(saId);
118            remainingNotStackableItems.Remove(saId);
119          }
120        }
121       
122      }
123    }
124
125    /// <summary>
126    /// Tries to find a valid position for a non stackable item.
127    /// Positions will only be valid if the height difference of its residual space is smaller then the hight of the item.
128    /// </summary>
129    /// <param name="packingBin"></param>
130    /// <param name="packingItem"></param>
131    /// <param name="useStackingConstraints"></param>
132    /// <returns></returns>
133    private PackingPosition FindPackingPositionForNotStackableItem(BinPacking3D packingBin, PackingItem packingItem, bool useStackingConstraints) {
134      if (!CheckItemDimensions(packingBin, packingItem)) {
135        throw new BinPacking3DException($"The dimensions of the given item exceeds the bin dimensions. " +
136          $"Bin: ({packingBin.BinShape.Width} {packingBin.BinShape.Depth} {packingBin.BinShape.Height})" +
137          $"Item: ({packingItem.Width} {packingItem.Depth} {packingItem.Height})");
138      }
139      var rsds = CalculateResidalSpaceDifferences(packingBin, packingItem, useStackingConstraints).ToList();
140      var rsd = rsds.Where(x => x != null && (x.Y / (double)x.Item.Height) < NOT_STACKABLE_RS_LEFT_TO_ITEM_HEIGHT_PROPORTION).OrderByDescending(x => x.Y % x.Item.Height).FirstOrDefault();
141
142      if (rsd == null) {
143        return null;
144      }
145
146      packingItem.Rotated = rsd.Item.Rotated;
147      packingItem.Tilted = rsd.Item.Tilted;
148      return rsd.Position;
149    }
150
151    protected override PackingPosition FindPackingPositionForItem(BinPacking3D packingBin, PackingItem packingItem, bool useStackingConstraints) {
152      if (!CheckItemDimensions(packingBin, packingItem)) {
153        throw new BinPacking3DException($"The dimensions of the given item exceeds the bin dimensions. " +
154          $"Bin: ({packingBin.BinShape.Width} {packingBin.BinShape.Depth} {packingBin.BinShape.Height})" +
155          $"Item: ({packingItem.Width} {packingItem.Depth} {packingItem.Height})");
156      }
157
158      var rsd = CalculateResidalSpaceDifferences(packingBin, packingItem, useStackingConstraints).Where(x => x != null).FirstOrDefault();
159
160      if (rsd == null) {
161        return null;
162      }
163
164      packingItem.Rotated = rsd.Item.Rotated;
165      packingItem.Tilted = rsd.Item.Tilted;
166      return rsd.Position;
167    }
168
169    /// <summary>
170    ///
171    /// </summary>
172    /// <param name="packingBin"></param>
173    /// <param name="packingItem"></param>
174    /// <param name="useStackingConstraints"></param>
175    /// <returns></returns>
176    private SortedSet<ResidualSpaceDifference> CalculateResidalSpaceDifferences(BinPacking3D packingBin, PackingItem packingItem, bool useStackingConstraints) {
177      var rsds = new SortedSet<ResidualSpaceDifference>();
178
179      rsds.Add(FindResidualSpaceDifferenceForItem(packingBin, packingItem, useStackingConstraints, rotated: false, tilted: false));
180
181      if (packingItem.TiltEnabled) {
182        rsds.Add(FindResidualSpaceDifferenceForItem(packingBin, packingItem, useStackingConstraints, rotated: false, tilted: true));
183      }
184      if (packingItem.RotateEnabled) {
185        rsds.Add(FindResidualSpaceDifferenceForItem(packingBin, packingItem, useStackingConstraints, rotated: true, tilted: false));
186      }
187      if (packingItem.RotateEnabled && packingItem.TiltEnabled) {
188        rsds.Add(FindResidualSpaceDifferenceForItem(packingBin, packingItem, useStackingConstraints, rotated: true, tilted: true));
189      }
190      return rsds;
191    }
192
193    /// <summary>
194    ///
195    /// </summary>
196    /// <param name="packingBin"></param>
197    /// <param name="packingItem"></param>
198    /// <param name="useStackingConstraints"></param>
199    /// <param name="rotated"></param>
200    /// <param name="tilted"></param>
201    /// <returns></returns>
202    protected ResidualSpaceDifference FindResidualSpaceDifferenceForItem(BinPacking3D packingBin, PackingItem packingItem, bool useStackingConstraints, bool rotated, bool tilted) {
203      PackingItem newItem = new PackingItem(packingItem) {
204        Rotated = rotated,
205        Tilted = tilted
206      };
207     
208      var rsds = new SortedSet<ResidualSpaceDifference>();
209      foreach (var ep in packingBin.ExtremePoints) {
210        var position = ep.Key;
211        foreach (var rs in ep.Value) {
212          var rsd = ResidualSpaceDifference.Create(position, newItem, rs);
213          if (rsd != null) {
214            rsds.Add(rsd);
215          }
216        }
217      }
218      return rsds.Where(rsd => packingBin.IsPositionFeasible(rsd.Item, rsd.Position, useStackingConstraints)).FirstOrDefault();
219    }
220       
221    protected override bool CheckItemDimensions(BinPacking3D packingBin, PackingItem item) {
222      bool ok = false;
223      int width = item.OriginalWidth;
224      int height = item.OriginalHeight;
225      int depth = item.OriginalDepth;
226
227      ok |= CheckItemDimensions(packingBin, width, height, depth);
228
229      if (item.RotateEnabled && item.TiltEnabled) {
230        ok |= CheckItemDimensions(packingBin, depth, height, width);//rotated
231        ok |= CheckItemDimensions(packingBin, height, width, depth);//tilted
232        ok |= CheckItemDimensions(packingBin, depth, width, height);//rotated & tilted
233      } else if (item.RotateEnabled) {
234        ok |= CheckItemDimensions(packingBin, depth, height, width);
235      } else if (item.TiltEnabled) {
236        ok |= CheckItemDimensions(packingBin, height, width, depth);
237      }
238
239      return ok;
240    }
241
242    private bool CheckItemDimensions(BinPacking3D packingBin, int width, int height, int depth) {
243      return base.CheckItemDimensions(packingBin, new PackingItem() {
244        OriginalWidth = width,
245        OriginalHeight = height,
246        OriginalDepth = depth
247      });
248    }
249
250    protected class ResidualSpaceDifference : IComparable {
251      public static ResidualSpaceDifference Create(PackingPosition position, PackingItem item, ResidualSpace rs) {
252        var x = rs.Width - item.Width;
253        var y = rs.Height - item.Height;
254        var z = rs.Depth - item.Depth;
255        // the item can't be places in the residual space
256        if (rs.IsZero() || x < 0 || y < 0 || z < 0) {
257          return null;
258        }
259
260        return new ResidualSpaceDifference() {
261          Position = position,
262          Item = item,
263          X = x,
264          Y = y,
265          Z = z
266        };
267      }
268
269      public ResidualSpaceDifference() { }
270
271      public PackingItem Item { get; set; }
272
273      public PackingPosition Position { get; set; }
274      public int X { get; set; }
275      public int Y { get; set; }
276      public int Z { get; set; }
277
278
279      public int CompareTo(object obj) {
280        if (!(obj is ResidualSpaceDifference)) {
281          return 0;
282        }
283        var rsd = obj as ResidualSpaceDifference;
284
285        var x = this.X - rsd.X;
286        var y = rsd.Y - this.Y;
287        var z = this.Z - rsd.Z;
288
289        if (x != 0) {
290          return x;
291        } else if (y != 0) {
292          return y;
293        } else if (z != 0) {
294          return z;
295        }
296
297        return 0;
298      }
299    }
300
301  }
302}
Note: See TracBrowser for help on using the repository browser.