Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
07/21/16 10:19:55 (8 years ago)
Author:
gkronber
Message:

#1966: new implementation for 2d bin packing problem with permutation encoding

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.BinPacking/HeuristicLab.Problems.BinPacking.2D/3.3/PackingSequenceProblem.cs

    r14128 r14146  
    2323
    2424using System;
    25 using System.CodeDom;
     25using System.Collections.Generic;
    2626using System.Linq;
    27 using System.Text;
    2827using HeuristicLab.Common;
    2928using HeuristicLab.Core;
     
    3130using HeuristicLab.Encodings.PermutationEncoding;
    3231using HeuristicLab.Optimization;
     32using HeuristicLab.Parameters;
    3333using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    3434using HeuristicLab.Problems.BinPacking;
    3535using HeuristicLab.Problems.BinPacking2D;
     36using HeuristicLab.Problems.Instances;
     37using HeuristicLab.Random;
    3638
    3739namespace HeuristicLab.Problems.BinPacking2d {
     40  [Item("Bin Packing Problem (2D, permutation encoding) (BPP)", "Represents a two-dimensional bin-packing problem using only bins with identical measures and bins/items with rectangular shapes.")]
    3841  [StorableClass]
    3942  [Creatable(Category = CreatableAttribute.Categories.CombinatorialProblems, Priority = 300)]
    40   public class PackingSequenceProblem : PackingSequenceProblem<Permutation, PermutationEncoding> {
     43  public sealed class PackingSequenceProblem : SingleObjectiveBasicProblem<PermutationEncoding>, IProblemInstanceConsumer<BPPData>, IProblemInstanceExporter<BPPData> {
     44    private readonly string SolutionEvaluatorParameterName = "SolutionEvaluator";
     45    #region Default Instance
     46    private static readonly BPPData DefaultInstance = new BPPData() {
     47      Name = "2D BPP Default Instance",
     48      Description = "The default instance for 2D Bin Packing.",
     49      BinShape = new PackingShape(20, 16),
     50      Items = new PackingItem[] {
     51        new PackingItem(3,  8, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     52        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     53        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     54        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     55        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     56        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     57        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     58        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     59        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     60        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     61        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     62        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     63        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     64        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     65        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     66        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     67        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     68        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     69        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     70        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     71        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     72        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     73        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     74        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     75        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     76        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     77        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     78        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     79        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     80        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     81        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     82        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     83        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     84        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     85        new PackingItem(5,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     86        new PackingItem(9,  3, new PackingShape(20, 16)) { Material = 1, Weight = 1.0},
     87        new PackingItem(2,  7, new PackingShape(20, 16)) { Material = 1, Weight = 1.0}
     88      },
     89    };
     90    #endregion
     91
     92    #region parameter properties
     93    public IValueParameter<IPermutationDecoder> DecoderParameter {
     94      get { return (IValueParameter<IPermutationDecoder>)Parameters["Decoder"]; }
     95    }
     96    public IValueParameter<BinPacking2D.IEvaluator> SolutionEvaluatorParameter {
     97      get { return (IValueParameter<BinPacking2D.IEvaluator>)Parameters[SolutionEvaluatorParameterName]; }
     98    }
     99    public IValueParameter<ReadOnlyItemList<PackingItem>> ItemsParameter {
     100      get { return (IValueParameter<ReadOnlyItemList<PackingItem>>)Parameters["Items"]; }
     101    }
     102    public IValueParameter<PackingShape> BinShapeParameter {
     103      get { return (IValueParameter<PackingShape>)Parameters["BinShape"]; }
     104    }
     105    public IValueParameter<Solution> BestKnownSolutionParameter {
     106      get { return (IValueParameter<Solution>)Parameters["BestKnownSolution"]; }
     107    }
     108    public IFixedValueParameter<IntValue> LowerBoundParameter {
     109      get { return (IFixedValueParameter<IntValue>)Parameters["LowerBound"]; }
     110    }
     111    #endregion
     112
     113    #region properties
     114    public IPermutationDecoder Decoder {
     115      get { return DecoderParameter.Value; }
     116      set { DecoderParameter.Value = value; }
     117    }
     118    public new BinPacking2D.IEvaluator SolutionEvaluator {
     119      get { return SolutionEvaluatorParameter.Value; }
     120      set { SolutionEvaluatorParameter.Value = value; }
     121    }
     122    public ReadOnlyItemList<PackingItem> Items {
     123      get { return ItemsParameter.Value; }
     124      set { ItemsParameter.Value = value; }
     125    }
     126    public PackingShape BinShape {
     127      get { return BinShapeParameter.Value; }
     128      set { BinShapeParameter.Value = value; }
     129    }
     130    public Solution BestKnownSolution {
     131      get { return BestKnownSolutionParameter.Value; }
     132      set { BestKnownSolutionParameter.Value = value; }
     133    }
     134    public int LowerBound {
     135      get { return LowerBoundParameter.Value.Value; }
     136    }
     137    public int NumberOfItems {
     138      get { return Items == null ? 0 : Items.Count; }
     139    }
     140    #endregion
    41141
    42142    // persistence
    43143    [StorableConstructor]
    44     protected PackingSequenceProblem(bool deserializing) : base(deserializing) { }
    45     [StorableHook(HookType.AfterDeserialization)]
    46     private void AfterDeserialization() { }
    47 
    48     public override bool Maximization {
    49       get { return true; }
    50     }
    51 
     144    private PackingSequenceProblem(bool deserializing) : base(deserializing) { }
    52145
    53146    // cloning
    54     protected PackingSequenceProblem(PackingSequenceProblem original, Cloner cloner)
     147    private PackingSequenceProblem(PackingSequenceProblem original, Cloner cloner)
    55148      : base(original, cloner) {
    56     }
    57 
    58     protected PackingSequenceProblem() : base() { }
    59 
    60 
     149      RegisterEventHandlers();
     150    }
     151
     152    public PackingSequenceProblem()
     153      : base() {
     154      var defaultEvaluator = new PackingRatioEvaluator();
     155      var defaultDecoder = new ExtremePointPermutationDecoder();
     156      Parameters.Add(new ValueParameter<IPermutationDecoder>("Decoder", "The decoder translates a permutation to a packing solution candidiates", defaultDecoder));
     157      Parameters.Add(new ValueParameter<BinPacking2D.IEvaluator>(SolutionEvaluatorParameterName, "The evaluator calculates qualities of solution candidates", defaultEvaluator));
     158      Parameters.Add(new ValueParameter<ReadOnlyItemList<PackingItem>>("Items", "The items which must be packed into bins"));
     159      Parameters.Add(new ValueParameter<PackingShape>("BinShape", "The size of bins into which items must be packed"));
     160      Parameters.Add(new OptionalValueParameter<Solution>("BestKnownSolution", "The best solution found so far"));
     161      Parameters.Add(new FixedValueParameter<IntValue>("LowerBound", "A lower bound for the number of bins that is necessary to pack all items"));
     162
     163      Load(DefaultInstance);
     164
     165      Encoding = new PermutationEncoding("PackingSequence", Items.Count, PermutationTypes.Absolute);
     166      AddOperators();
     167      RegisterEventHandlers();
     168    }
    61169    public override IDeepCloneable Clone(Cloner cloner) {
    62170      return new PackingSequenceProblem(this, cloner);
    63171    }
    64172
     173    [StorableHook(HookType.AfterDeserialization)]
     174    private void AfterDeserialization() {
     175      RegisterEventHandlers();
     176    }
     177
     178
     179    private void AddOperators() {
     180      Operators.Add(new StochasticInsertionMultiMoveGenerator());
     181      Operators.Add(new ExhaustiveInsertionMoveGenerator());
     182      Operators.Add(new TranslocationMoveMaker());
     183      Operators.Add(new TranslocationMoveEvaluator());
     184      Operators.Add(new TranslocationMoveTabuMaker());
     185
     186      Operators.RemoveAll(x => x is SingleObjectiveMoveGenerator);
     187      Operators.RemoveAll(x => x is SingleObjectiveMoveMaker);
     188      Operators.RemoveAll(x => x is SingleObjectiveMoveEvaluator);
     189
     190      Encoding.ConfigureOperators(Operators.OfType<IOperator>());
     191    }
     192
     193    private void RegisterEventHandlers() {
     194      // update encoding length when number of items is changed
     195      ItemsParameter.ValueChanged += (sender, args) => Encoding.Length = Items.Count;
     196    }
     197
     198    public override bool Maximization { get { return true; } }
     199
    65200
    66201    public override double Evaluate(Individual individual, IRandom random) {
    67       var permutation = individual.Permutation();
    68       var decoder = new ExtremePointPackingSequenceDecoder2D();
    69       var packingPlan = decoder.CreatePackingPlanFromEncoding(permutation, Bin, Items);
    70       var ratio = PackingRatioEvaluator.CalculatePackingRatio(packingPlan);
    71       return ratio.Value;
     202      var permutation = individual.Permutation("PackingSequence");
     203      var decoder = Decoder;
     204      var solution = decoder.Decode(permutation, BinShape, Items);
     205      return SolutionEvaluator.Evaluate(solution);
    72206    }
    73207
    74208    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
    75209      base.Analyze(individuals, qualities, results, random);
    76       Analyze(individuals.Select(i => i.Permutation()).ToArray(), qualities, results, random);
    77     }
     210      Analyze(individuals.Select(i => i.Permutation("PackingSequence")).ToArray(), qualities, results, random);
     211    }
     212
     213    public void Analyze(Permutation[] individuals, double[] qualities, ResultCollection results, IRandom random) {
     214      var bestSolutionResultName = "Best Packing Solution";
     215      var numContainersResultName = "Nr of Containers";
     216      var binUtilResultName = "Overall Bin Utilization";
     217
     218      if (!results.ContainsKey(bestSolutionResultName)) results.Add(new Result(bestSolutionResultName, typeof(Solution)));
     219      if (!results.ContainsKey(numContainersResultName)) results.Add(new Result(numContainersResultName, typeof(IntValue)));
     220      if (!results.ContainsKey(binUtilResultName)) results.Add(new Result(binUtilResultName, typeof(DoubleValue)));
     221
     222
     223      // find index of item with max quality
     224      int bestIdx = 0;
     225      for (int j = 1; j < qualities.Length; j++)
     226        if (qualities[j] > qualities[bestIdx]) bestIdx = j;
     227
     228
     229      // update best solution so far
     230      var bestSolution = results[bestSolutionResultName].Value as Solution;
     231      if (bestSolution == null ||
     232        bestSolution.Quality.Value < qualities[bestIdx]) {
     233
     234        var newBestSolution = Decoder.Decode(individuals[bestIdx], BinShape, Items);
     235        newBestSolution.Quality = new DoubleValue(qualities[bestIdx]);
     236        results[bestSolutionResultName].Value = newBestSolution;
     237        results[numContainersResultName].Value = new IntValue(newBestSolution.NrOfBins);
     238        results[binUtilResultName].Value = new DoubleValue(BinUtilizationEvaluator.CalculateBinUtilization(newBestSolution));
     239
     240        // update best known solution
     241        var bestKnownQuality = BestKnownQualityParameter.Value;
     242        if (bestKnownQuality == null ||
     243            bestKnownQuality.Value < qualities[bestIdx]) {
     244          BestKnownQualityParameter.ActualValue = new DoubleValue(qualities[bestIdx]);
     245          BestKnownSolutionParameter.ActualValue = newBestSolution;
     246        }
     247      }
     248    }
     249
     250
     251    #region Problem instance handling
     252    public void Load(BPPData data) {
     253      BestKnownSolutionParameter.Value = null;
     254      BestKnownQualityParameter.Value = null;
     255
     256      if (data.BestKnownQuality.HasValue)
     257        BestKnownQuality = data.BestKnownQuality.Value;
     258
     259      BinShape = data.BinShape;
     260      var items = new ItemList<PackingItem>(data.Items);
     261      items.Sort((x, y) => y.CompareTo(x));
     262      Items = items.AsReadOnly();
     263
     264      ApplyHorizontalOrientation();
     265      LowerBoundParameter.Value.Value = CalculateLowerBound();
     266    }
     267
     268
     269    public BPPData Export() {
     270      return new BPPData {
     271        Name = Name,
     272        Description = Description,
     273        BinShape = BinShape,
     274        Items = Items.ToArray()
     275      };
     276    }
     277    #endregion
     278
     279
     280    #region helpers
     281    private void ApplyHorizontalOrientation() {
     282      BinShape.ApplyHorizontalOrientation();
     283      foreach (var shape in Items) {
     284        shape.ApplyHorizontalOrientation();
     285      }
     286    }
     287
     288    private int CalculateLowerBound() {
     289      //This is the obvious continuous lower bound calculation; Martello and Vigo proposed a better way but it has not been implemented yet;
     290      int itemsVol = Items.Select(x => x.Volume).Sum();
     291      int binVol = BinShape.Volume;
     292      return (itemsVol + binVol - 1) / (binVol);
     293    }
     294
     295    #endregion
    78296  }
    79297}
Note: See TracChangeset for help on using the changeset viewer.