Generated on Mon Jul 6 18:09:01 2009 for Gecode by doxygen 1.5.9

steel-mill.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Mikael Lagerkvist, 2008
00008  *
00009  *  Last modified:
00010  *     $Date: 2009-05-14 19:35:46 +0200 (Thu, 14 May 2009) $ by $Author: tack $
00011  *     $Revision: 9118 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/driver.hh>
00039 #include <gecode/int.hh>
00040 #include <gecode/minimodel.hh>
00041 
00042 #include <fstream>
00043 
00044 using namespace Gecode;
00045 
00052 typedef int (*order_t)[2];     
00053 extern const int order_weight; 
00054 extern const int order_color;  
00055 
00056 
00062 extern int csplib_capacities[];         
00063 extern unsigned int csplib_ncapacities; 
00064 extern unsigned int csplib_maxcapacity; 
00065 extern int csplib_loss[];               
00066 extern int csplib_orders[][2];          
00067 extern unsigned int csplib_ncolors;     
00068 extern unsigned int csplib_norders;     
00069 
00070 
00071 
00077 class SteelMillOptions : public Options {
00078 private:
00079   unsigned int _size;    
00080   int* _capacities;      
00081   int  _ncapacities;     
00082   int  _maxcapacity;     
00083   int* _loss;            
00084   order_t _orders;       
00085   int  _ncolors;         
00086   unsigned int _norders; 
00087 public:
00089   SteelMillOptions(const char* n)
00090     : Options(n), _size(csplib_norders),
00091       _capacities(csplib_capacities), _ncapacities(csplib_ncapacities),
00092       _maxcapacity(csplib_maxcapacity),
00093       _loss(csplib_loss), _orders(&(csplib_orders[0])), _ncolors(csplib_ncolors),
00094       _norders(csplib_norders) {}
00096   virtual void help(void);
00098   bool parse(int& argc, char* argv[]);
00099 
00101   unsigned int size(void) const { return _size;        }
00103   int* capacities(void) const   { return _capacities;  }
00105   int ncapacities(void) const   { return _ncapacities; }
00107   int maxcapacity(void) const   { return _maxcapacity; }
00109   int* loss(void) const         { return _loss;        }
00111   order_t orders(void) const    { return _orders;      }
00113   int ncolors(void) const       { return _ncolors;     }
00115   int norders(void) const       { return _norders;     }
00116 };
00117 
00118 
00147 class SteelMill : public MinimizeScript {
00148 protected:
00152   int* capacities;      
00153   int  ncapacities;     
00154   int  maxcapacity;     
00155   int* loss;            
00156   int  ncolors;         
00157   order_t orders;       
00158   unsigned int norders; 
00159   unsigned int nslabs;  
00160 
00161 
00165   IntVarArray slab, 
00166     slabload, 
00167     slabcost; 
00168   IntVar total_cost; 
00169 
00170 
00171 public:
00173   enum {
00174     BRANCHING_NAIVE,   
00175     BRANCHING_SYMMETRY 
00176   };
00177 
00179   SteelMill(const SteelMillOptions& opt)
00180     : // Initialize instance data
00181       capacities(opt.capacities()), ncapacities(opt.ncapacities()),
00182       maxcapacity(opt.maxcapacity()), loss(opt.loss()),
00183       ncolors(opt.ncolors()), orders(opt.orders()),
00184       norders(opt.size()), nslabs(opt.size()),
00185       // Initialize problem variables
00186       slab(*this, norders, 0,nslabs-1),
00187       slabload(*this, nslabs, 0,45),
00188       slabcost(*this, nslabs, 0, Int::Limits::max),
00189       total_cost(*this, 0, Int::Limits::max)
00190   {
00191     // Boolean variables for slab[o]==s
00192     BoolVarArgs boolslab(norders*nslabs);
00193     for (unsigned int i = 0; i < norders; ++i) {
00194       BoolVarArgs tmp(nslabs);
00195       for (int j = nslabs; j--; ) {
00196         boolslab[j + i*nslabs] = tmp[j] = BoolVar(*this, 0, 1);
00197       }
00198       channel(*this, tmp, slab[i]);
00199     }
00200 
00201     // Packing constraints
00202     for (unsigned int s = 0; s < nslabs; ++s) {
00203       IntArgs c(norders);
00204       BoolVarArgs x(norders);
00205       for (int i = norders; i--; ) {
00206         c[i] = orders[i][order_weight];
00207         x[i] = boolslab[s + i*nslabs];
00208       }
00209       linear(*this, c, x, IRT_EQ, slabload[s]);
00210     }
00211     // Redundant packing constraint
00212     int totalweight = 0;
00213     for (unsigned int i = norders; i-- ; ) 
00214        totalweight += orders[i][order_weight] ;
00215     linear(*this, slabload, IRT_EQ, totalweight);
00216 
00217 
00218     // Color constraints
00219     IntArgs nofcolor(ncolors);
00220     for (int c = ncolors; c--; ) {
00221       nofcolor[c] = 0;
00222       for (int o = norders; o--; ) {
00223         if (orders[o][order_color] == c) nofcolor[c] += 1;
00224       }
00225     }
00226     BoolVar f(*this, 0, 0);
00227     for (unsigned int s = 0; s < nslabs; ++s) {
00228       BoolVarArgs hascolor(ncolors);
00229       for (int c = ncolors; c--; ) {
00230         if (nofcolor[c]) {
00231           BoolVarArgs hasc(nofcolor[c]);
00232           int pos = 0;
00233           for (int o = norders; o--; ) {
00234             if (orders[o][order_color] == c)
00235               hasc[pos++] = boolslab[s + o*nslabs];
00236           }
00237           assert(pos == nofcolor[c]);
00238           hascolor[c] = BoolVar(*this, 0, 1);
00239           rel(*this, BOT_OR, hasc, hascolor[c]);
00240         } else {
00241           hascolor[c] = f;
00242         }
00243       }
00244       linear(*this, hascolor, IRT_LQ, 2);
00245     }
00246 
00247     // Compute slabcost
00248     IntArgs l(maxcapacity, loss);
00249     for (int s = nslabs; s--; ) {
00250       element(*this, l, slabload[s], slabcost[s]);
00251     }
00252     linear(*this, slabcost, IRT_EQ, total_cost);
00253 
00254     // Add branching
00255     if (opt.branching() == BRANCHING_SYMMETRY) {
00256       // Install custom branching
00257       SteelMillBranch::post(*this);
00258     } else { // opt.branching() == BRANCHING_NAIVE
00259       branch(*this, slab, INT_VAR_MAX_MIN, INT_VAL_MIN);
00260     }
00261   }
00262 
00264   virtual void
00265   print(std::ostream& os) const {
00266     os << "What slab="  << slab << std::endl;
00267     os << "Slab load="  << slabload << std::endl;
00268     os << "Slab cost="  << slabcost << std::endl;
00269     os << "Total cost=" << total_cost << std::endl;
00270     int nslabsused = 0;
00271     int nslabscost = 0;
00272     bool unassigned = false;
00273     for (int i = nslabs; i--; ) {
00274       if (!slabload[i].assigned() || !slabcost[i].assigned()) {
00275         unassigned = true;
00276         break;
00277       }
00278       if (slabload[i].min()>0) ++nslabsused;
00279       if (slabcost[i].min()>0) ++nslabscost;
00280     }
00281     if (!unassigned)
00282       os << "Number of slabs used=" << nslabsused
00283          << ", slabs with cost="    << nslabscost
00284          << std::endl;
00285     os << std::endl;
00286   }
00287 
00289   SteelMill(bool share, SteelMill& s)
00290     : MinimizeScript(share,s),
00291       capacities(s.capacities), ncapacities(s.ncapacities),
00292       maxcapacity(s.maxcapacity), loss(s.loss),
00293       ncolors(s.ncolors), orders(s.orders),
00294       norders(s.norders), nslabs(s.nslabs) {
00295     slab.update(*this, share, s.slab);
00296     slabload.update(*this, share, s.slabload);
00297     slabcost.update(*this, share, s.slabcost);
00298     total_cost.update(*this, share, s.total_cost);
00299   }
00301   virtual Space*
00302   copy(bool share) {
00303     return new SteelMill(share,*this);
00304   }
00306   virtual IntVar cost(void) const {
00307     return total_cost;
00308   }
00309 
00310 
00319   class SteelMillBranch : Branching {
00321     mutable int start;
00323     class Description : public BranchingDesc {
00324     public:
00326       int pos;
00328       int val;
00332       Description(const Branching& b, unsigned int a, int pos0, int val0)
00333         : BranchingDesc(b,a), pos(pos0), val(val0) {}
00335       virtual size_t size(void) const {
00336         return sizeof(Description);
00337       }
00338     };
00339 
00341     SteelMillBranch(Space& home)
00342       : Branching(home), start(0) {}
00344     SteelMillBranch(Space& home, bool share, SteelMillBranch& b)
00345       : Branching(home, share, b), start(b.start) {
00346     }
00347 
00348   public:
00350     virtual bool status(const Space& home) const {
00351       const SteelMill& sm = static_cast<const SteelMill&>(home);
00352       for (unsigned int i = start; i < sm.norders; ++i)
00353         if (!sm.slab[i].assigned()) {
00354           start = i;
00355           return true;
00356         }
00357       // No non-assigned orders left
00358       return false;
00359     }
00361     virtual BranchingDesc* description(Space& home) {
00362       SteelMill& sm = static_cast<SteelMill&>(home);
00363       assert(!sm.slab[start].assigned());
00364       // Find order with a) minimum size, b) largest weight
00365       unsigned int size = sm.norders;
00366       int weight = 0;
00367       unsigned int pos = start;
00368       for (unsigned int i = start; i<sm.norders; ++i) {
00369         if (!sm.slab[i].assigned()) {
00370           if (sm.slab[i].size() == size && 
00371               sm.orders[i][order_weight] > weight) {
00372             weight = sm.orders[i][order_weight];
00373             pos = i;
00374           } else if (sm.slab[i].size() < size) {
00375             size = sm.slab[i].size();
00376             weight = sm.orders[i][order_weight];
00377             pos = i;
00378           }
00379         }
00380       }
00381       unsigned int val = sm.slab[pos].min();
00382       // Find first still empty slab (all such slabs are symmetric)
00383       unsigned int firstzero = 0;
00384       while (firstzero < sm.nslabs && sm.slabload[firstzero].min() > 0)
00385         ++firstzero;
00386       assert(pos < sm.nslabs &&
00387              val < sm.norders);
00388       return new Description(*this, val<firstzero ? 2 : 1, pos, val);
00389     }
00391     virtual ExecStatus commit(Space& home, const BranchingDesc& d,
00392                               unsigned int a) {
00393       SteelMill& sm = static_cast<SteelMill&>(home);
00394       const Description& desc =
00395         static_cast<const Description&>(d);
00396       if (a)
00397         return me_failed(Int::IntView(sm.slab[desc.pos]).nq(home, desc.val))
00398           ? ES_FAILED : ES_OK;
00399       else
00400         return me_failed(Int::IntView(sm.slab[desc.pos]).eq(home, desc.val))
00401           ? ES_FAILED : ES_OK;
00402     }
00404     virtual Actor* copy(Space& home, bool share) {
00405       return new (home) SteelMillBranch(home, share, *this);
00406     }
00408     static void post(Space& home) {
00409       (void) new (home) SteelMillBranch(home);
00410     }
00411   };
00412 };
00413 
00417 int
00418 main(int argc, char* argv[]) {
00419   SteelMillOptions opt("Steel Mill Slab design");
00420   opt.branching(SteelMill::BRANCHING_SYMMETRY);
00421   opt.branching(SteelMill::BRANCHING_NAIVE,"naive");
00422   opt.branching(SteelMill::BRANCHING_SYMMETRY,"symmetry");
00423   opt.solutions(0);
00424   if (!opt.parse(argc,argv))
00425     return 1;
00426   Script::run<SteelMill,BAB,SteelMillOptions>(opt);
00427   return 0;
00428 }
00429 
00430 
00431 void
00432 SteelMillOptions::help(void) {
00433   Options::help();
00434   std::cerr << "\t(string), optional" << std::endl
00435             << "\t\tBenchmark to load." << std::endl
00436             << "\t\tIf none is given, the standard CSPLib instance is used."
00437             << std::endl;
00438   std::cerr << "\t(unsigned int), optional" << std::endl
00439             << "\t\tNumber of orders to use, in the interval [0..norders]."
00440             << std::endl
00441             << "\t\tIf none is given, all orders are used." << std::endl;
00442 }
00443 
00444 bool
00445 SteelMillOptions::parse(int& argc, char* argv[]) {
00446   Options::parse(argc,argv);
00447   // Check number of arguments
00448   if (argc >= 4) {
00449     std::cerr << "Too many arguments given, max two allowed (given={";
00450     for (int i = 1; i < argc; ++i) {
00451       std::cerr << "\"" << argv[i] << "\"";
00452       if (i < argc-1) std::cerr << ",";
00453     }
00454     std::cerr << "})." << std::endl;
00455     return false;
00456   }
00457   // Parse options
00458   while (argc >= 2) {
00459     bool issize = true;
00460     for (int i = strlen(argv[argc-1]); i-- && issize; )
00461       issize &= (isdigit(argv[argc-1][i]) != 0);
00462     if (issize) {
00463       _size = atoi(argv[argc-1]);
00464     } else {
00465       std::ifstream instance(argv[argc-1]);
00466       if (instance.fail()) {
00467         std::cerr << "Argument \"" << argv[argc-1]
00468                   << "\" is neither an integer nor a readable file"
00469                   << std::endl;
00470         return false;
00471       }
00472       // Read file instance
00473       instance >> _ncapacities;
00474       _capacities = new int[_ncapacities];
00475       _maxcapacity = -1;
00476       for (int i = 0; i < _ncapacities; ++i) {
00477         instance >> _capacities[i];
00478         _maxcapacity = std::max(_maxcapacity, _capacities[i]);
00479       }
00480       instance >> _ncolors >> _norders;
00481       _orders = new int[_norders][2];
00482       for (unsigned int i = 0; i < _norders; ++i) {
00483         instance >> _orders[i][order_weight] >> _orders[i][order_color];
00484       }
00485     }
00486 
00487     --argc;
00488   }
00489   // Compute loss
00490   {
00491     _loss = new int[_maxcapacity+1];
00492     _loss[0] = 0;
00493     int currcap = 0;
00494     for (int c = 1; c < _maxcapacity; ++c) {
00495       if (c > _capacities[currcap]) ++currcap;
00496       _loss[c] = _capacities[currcap] - c;
00497     }
00498   }
00499   // Set size, if none given
00500   if (_size == 0) {
00501     _size = _norders;
00502   }
00503   // Check size reasonability
00504   if (_size == 0 || _size > _norders) {
00505     std::cerr << "Size must be between 1 and " << _norders << std::endl;
00506     return false;
00507   }
00508   return true;
00509 }
00510 
00511 // Positions in order array
00512 const int order_weight = 0;
00513 const int order_color = 1;
00514 
00515 // CSPLib instance
00516 int csplib_capacities[] =
00517   {12, 14, 17, 18, 19,
00518    20, 23, 24, 25, 26,
00519    27, 28, 29, 30, 32,
00520    35, 39, 42, 43, 44};
00521 unsigned int csplib_ncapacities = 20;
00522 unsigned int csplib_maxcapacity = 44;
00523 int csplib_loss[45];
00524 unsigned int csplib_ncolors = 89;
00525 unsigned int csplib_norders = 111;
00526 int csplib_orders[][2] = {
00527   {4, 1},
00528   {22, 2},
00529   {9, 3},
00530   {5, 4},
00531   {8, 5},
00532   {3, 6},
00533   {3, 4},
00534   {4, 7},
00535   {7, 4},
00536   {7, 8},
00537   {3, 6},
00538   {2, 6},
00539   {2, 4},
00540   {8, 9},
00541   {5, 10},
00542   {7, 11},
00543   {4, 7},
00544   {7, 11},
00545   {5, 10},
00546   {7, 11},
00547   {8, 9},
00548   {3, 1},
00549   {25, 12},
00550   {14, 13},
00551   {3, 6},
00552   {22, 14},
00553   {19, 15},
00554   {19, 15},
00555   {22, 16},
00556   {22, 17},
00557   {22, 18},
00558   {20, 19},
00559   {22, 20},
00560   {5, 21},
00561   {4, 22},
00562   {10, 23},
00563   {26, 24},
00564   {17, 25},
00565   {20, 26},
00566   {16, 27},
00567   {10, 28},
00568   {19, 29},
00569   {10, 30},
00570   {10, 31},
00571   {23, 32},
00572   {22, 33},
00573   {26, 34},
00574   {27, 35},
00575   {22, 36},
00576   {27, 37},
00577   {22, 38},
00578   {22, 39},
00579   {13, 40},
00580   {14, 41},
00581   {16, 27},
00582   {26, 34},
00583   {26, 42},
00584   {27, 35},
00585   {22, 36},
00586   {20, 43},
00587   {26, 24},
00588   {22, 44},
00589   {13, 45},
00590   {19, 46},
00591   {20, 47},
00592   {16, 48},
00593   {15, 49},
00594   {17, 50},
00595   {10, 28},
00596   {20, 51},
00597   {5, 52},
00598   {26, 24},
00599   {19, 53},
00600   {15, 54},
00601   {10, 55},
00602   {10, 56},
00603   {13, 57},
00604   {13, 58},
00605   {13, 59},
00606   {12, 60},
00607   {12, 61},
00608   {18, 62},
00609   {10, 63},
00610   {18, 64},
00611   {16, 65},
00612   {20, 66},
00613   {12, 67},
00614   {6, 68},
00615   {6, 68},
00616   {15, 69},
00617   {15, 70},
00618   {15, 70},
00619   {21, 71},
00620   {30, 72},
00621   {30, 73},
00622   {30, 74},
00623   {30, 75},
00624   {23, 76},
00625   {15, 77},
00626   {15, 78},
00627   {27, 79},
00628   {27, 80},
00629   {27, 81},
00630   {27, 82},
00631   {27, 83},
00632   {27, 84},
00633   {27, 79},
00634   {27, 85},
00635   {27, 86},
00636   {10, 87},
00637   {3, 88}
00638 };
00639 
00640 // STATISTICS: example-any