#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using HeuristicLab.Core;
using HeuristicLab.Problems.Instances;
using HeuristicLab.Random;
namespace HeuristicLab.Problems.BinPacking3D {
// make sure that for each class we have a separate entry in the problem instance providers
public class RandomInstanceClass1Provider : RandomInstanceProvider {
public RandomInstanceClass1Provider() : base() { @class = 1; binWidth = binHeight = binDepth = 100; }
}
public class RandomInstanceClass2Provider : RandomInstanceProvider {
public RandomInstanceClass2Provider() : base() { @class = 2; binWidth = binHeight = binDepth = 100; }
}
public class RandomInstanceClass3Provider : RandomInstanceProvider {
public RandomInstanceClass3Provider() : base() { @class = 3; binWidth = binHeight = binDepth = 100; }
}
public class RandomInstanceClass4Provider : RandomInstanceProvider {
public RandomInstanceClass4Provider() : base() { @class = 4; binWidth = binHeight = binDepth = 100; }
}
public class RandomInstanceClass5Provider : RandomInstanceProvider {
public RandomInstanceClass5Provider() : base() { @class = 5; binWidth = binHeight = binDepth = 100; }
}
public class RandomInstanceClass6Provider : RandomInstanceProvider {
public RandomInstanceClass6Provider() : base() {
@class = 6;
binWidth = binHeight = binDepth = 10;
}
protected override void SampleItemParameters(IRandom rand, out int w, out int h, out int d) {
w = rand.Next(1, 11);
h = rand.Next(1, 11);
d = rand.Next(1, 11);
}
}
public class RandomInstanceClass7Provider : RandomInstanceProvider {
public RandomInstanceClass7Provider() : base() {
@class = 7;
binWidth = binHeight = binDepth = 40;
}
protected override void SampleItemParameters(IRandom rand, out int w, out int h, out int d) {
w = rand.Next(1, 36);
h = rand.Next(1, 36);
d = rand.Next(1, 36);
}
}
public class RandomInstanceClass8Provider : RandomInstanceProvider {
public RandomInstanceClass8Provider() : base() {
@class = 8;
binWidth = binHeight = binDepth = 100;
}
protected override void SampleItemParameters(IRandom rand, out int w, out int h, out int d) {
w = rand.Next(1, 101);
h = rand.Next(1, 101);
d = rand.Next(1, 101);
}
}
// class 9 from the paper (all-fill) is not implemented
public abstract class RandomInstanceProvider : ProblemInstanceProvider, IProblemInstanceProvider {
protected int @class;
protected int binWidth, binHeight, binDepth;
public override string Name {
get { return string.Format("Martello, Pisinger, Vigo (class={0})", @class); }
}
public override string Description {
get { return "Randomly generated 3d bin packing problems as described in Martello, Pisinger, Vigo: 'The Three-Dimensional Bin Packing Problem', Operations Research Vol 48, Issue 2, 2000, pp. 256-267."; }
}
public override Uri WebLink {
get { return null; }
}
public override string ReferencePublication {
get { return "Martello, Pisinger, Vigo: 'The Three-Dimensional Bin Packing Problem', Operations Research Vol 48, Issue 2, 2000, pp. 256-267."; }
}
public RandomInstanceProvider() : base() { }
public override IEnumerable GetDataDescriptors() {
// 10 classes
var rand = new MersenneTwister(1234); // fixed seed to makes sure that instances are always the same
foreach (int numItems in new int[] { 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90 }) {
// get class parameters
// generate 30 different instances for each class
foreach (int instance in Enumerable.Range(1, 30)) {
string name = string.Format("n={0}-id={1:00} (class={2})", numItems, instance, @class);
var dd = new RandomDataDescriptor(name, name, numItems, @class, seed: rand.Next());
yield return dd;
}
}
}
public override BPPData LoadData(IDataDescriptor dd) {
var randDd = dd as RandomDataDescriptor;
if (randDd == null) throw new NotSupportedException("Cannot load data descriptor " + dd);
var data = new BPPData() {
BinShape = new PackingShape(binWidth, binHeight, binDepth),
Items = new PackingItem[randDd.NumItems]
};
var instanceRand = new MersenneTwister((uint)randDd.Seed);
for (int i = 0; i < randDd.NumItems; i++) {
int w, h, d;
SampleItemParameters(instanceRand, out w, out h, out d);
data.Items[i] = new PackingItem(w, h, d, data.BinShape);
}
return data;
}
// default implementation for class 1 .. 5
protected virtual void SampleItemParameters(IRandom rand, out int w, out int h, out int d) {
// for classes 1 - 5
Contract.Assert(@class >= 1 && @class <= 5);
var weights = new double[] { 0.1, 0.1, 0.1, 0.1, 0.1 };
weights[@class - 1] = 0.6;
var type = Enumerable.Range(1, 5).SampleProportional(rand, 1, weights).First();
int minW, maxW;
int minH, maxH;
int minD, maxD;
GetItemParameters(type, rand, binWidth, binHeight, binDepth,
out minW, out maxW, out minH, out maxH, out minD, out maxD);
w = rand.Next(minW, maxW + 1);
h = rand.Next(minH, maxH + 1);
d = rand.Next(minD, maxD + 1);
}
private void GetItemParameters(int type, IRandom rand,
int w, int h, int d,
out int minW, out int maxW, out int minH, out int maxH, out int minD, out int maxD) {
switch (type) {
case 1: {
minW = 1; maxW = w / 2; // integer division on purpose (see paper)
minH = h * 2 / 3; maxH = h;
minD = d * 2 / 3; maxD = d;
break;
}
case 2: {
minW = w * 2 / 3; maxW = w;
minH = 1; maxH = h / 2;
minD = d * 2 / 3; maxD = d;
break;
}
case 3: {
minW = w * 2 / 3; maxW = w;
minH = h * 2 / 3; maxH = h;
minD = 1; maxD = d / 2;
break;
}
case 4: {
minW = w / 2; maxW = w;
minH = h / 2; maxH = h;
minD = d / 2; maxD = d;
break;
}
case 5: {
minW = 1; maxW = w / 2;
minH = 1; maxH = h / 2;
minD = 1; maxD = d / 2;
break;
}
default: {
throw new InvalidProgramException();
}
}
}
public override bool CanImportData {
get { return false; }
}
public override BPPData ImportData(string path) {
throw new NotSupportedException();
}
public override bool CanExportData {
get { return true; }
}
public override void ExportData(BPPData instance, string file) {
using (Stream stream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write)) {
Export(instance, stream);
}
}
public static void Export(BPPData instance, Stream stream) {
using (var writer = new StreamWriter(stream)) {
writer.WriteLine(String.Format("{0,-5} {1,-5} {2,-5} WBIN,HBIN,DBIN", instance.BinShape.Width, instance.BinShape.Height, instance.BinShape.Depth));
for (int i = 0; i < instance.NumItems; i++) {
if (i == 0)
writer.WriteLine("{0,-5} {1,-5} {2,-5} W(I),H(I),D(I),I=1,...,N", instance.Items[i].Width, instance.Items[i].Height, instance.Items[i].Depth);
else
writer.WriteLine("{0,-5} {1,-5} {2,-5}", instance.Items[i].Width, instance.Items[i].Height, instance.Items[i].Depth);
}
writer.Flush();
}
}
}
}