Generated on Mon Aug 25 11:35:45 2008 for Gecode by doxygen 1.5.6

search.cc

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Christian Schulte, 2008
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-02-22 02:44:55 +0100 (Fri, 22 Feb 2008) $ by $Author: schulte $
00011  *     $Revision: 6273 $
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/int.hh"
00039 #include "gecode/minimodel.hh"
00040 #include "gecode/search.hh"
00041 
00042 #include "test/test.hh"
00043 
00044 namespace Test { 
00045 
00047   namespace Search {
00048 
00049     using namespace Gecode;
00050     using namespace Gecode::Int;
00051 
00053     enum HowToBranch {
00054       HTB_NONE,   
00055       HTB_UNARY,  
00056       HTB_BINARY, 
00057       HTB_NARY    
00058     };
00059 
00061     enum HowToConstrain {
00062       HTC_NONE,   
00063       HTC_LEX_LE, 
00064       HTC_LEX_GR, 
00065       HTC_BAL_LE, 
00066       HTC_BAL_GR  
00067     };
00068 
00070     enum WhichModel {
00071       WM_FAIL_IMMEDIATE, 
00072       WM_FAIL_SEARCH,    
00073       WM_SOLUTIONS       
00074     };
00075 
00077     class PosValuesDesc : public BranchingDesc {
00078     protected:
00080       int _pos;
00082       int* _values;
00083     public:
00085       PosValuesDesc(const Branching* b, int p, IntView x)
00086         : BranchingDesc(b,x.size()), 
00087           _pos(p), 
00088           _values(static_cast<int*>(Memory::malloc(sizeof(int)*x.size()))) {
00089         ViewValues<IntView> v(x);
00090         int i=0;
00091         while (v()) {
00092           _values[i]=v.val(); ++i; ++v;
00093         }
00094       }
00096       int pos(void) const {
00097         return _pos;
00098       }
00100       int val(unsigned int a) const {
00101         return _values[a];
00102       }
00104       virtual size_t size(void) const {
00105         return 0;
00106       }
00108       virtual ~PosValuesDesc(void) {
00109         Memory::free(_values);
00110       }
00111     };
00112 
00113 
00115     class NaryBranching : public Branching {
00116     protected:
00118       ViewArray<IntView> x; 
00120       NaryBranching(Space* home, bool share, NaryBranching& b) 
00121         : Branching(home,share,b) {
00122         x.update(home,share,b.x);
00123       }
00124     public:
00126       NaryBranching(Space* home, ViewArray<IntView>& x0) 
00127         : Branching(home), x(x0) {}
00129       virtual Actor* copy(Space* home, bool share) {
00130         return new (home) NaryBranching(home,share,*this);
00131       }
00133       virtual bool status(const Space*) const {
00134         for (int i=0; i<x.size(); i++)
00135           if (!x[i].assigned())
00136             return true;
00137         return false;
00138       }
00140       virtual const BranchingDesc* description(const Space*) const {
00141         int i=0; 
00142         while (x[i].assigned()) 
00143           i++;
00144         return new PosValuesDesc(this,i,x[i]);
00145       }
00147       virtual ExecStatus commit(Space* home, const BranchingDesc* d,
00148                                 unsigned int a) {
00149         const PosValuesDesc* pvd = static_cast<const PosValuesDesc*>(d);
00150         return me_failed(x[pvd->pos()].eq(home,pvd->val(a)))
00151           ? ES_FAILED : ES_OK;
00152       }
00154       static Support::Symbol ati(void) {
00155         return "Test::Search::NaryBranching";
00156       }
00158       virtual Reflection::ActorSpec spec(Space* home, Reflection::VarMap& m) {
00159         Reflection::ActorSpec s(ati());
00160         return s << x.spec(home, m);
00161       }
00162 
00164       virtual Reflection::BranchingSpec branchingSpec(Space*, 
00165                                                       Reflection::VarMap&,
00166                                                       const BranchingDesc* d) {
00167         Reflection::BranchingSpec bs(d);
00168         return bs;
00169       }
00171       static void post(Space*, Reflection::VarMap&,
00172                        const Reflection::ActorSpec&) {
00173       }
00174     };
00175 
00177     class TestSpace : public Space {
00178     public:
00180       TestSpace(void) {}
00182       TestSpace(bool share, TestSpace& s) : Space(share,s) {}
00184       virtual int solutions(void) const = 0;
00186       virtual bool best(void) const = 0;
00187     };
00188 
00190     class FailImmediate : public TestSpace {
00191     public:
00193       IntVarArray x;
00195       FailImmediate(HowToBranch, HowToBranch, HowToBranch, 
00196                     HowToConstrain=HTC_NONE) 
00197         : x(this,1,0,0) {
00198         rel(this, x[0], IRT_EQ, 1);
00199       }
00201       FailImmediate(bool share, FailImmediate& s) : TestSpace(share,s) {
00202         x.update(this, share, s.x);
00203       }
00205       virtual Space* copy(bool share) {
00206         return new FailImmediate(share,*this);
00207       }
00209       void constrain(Space*) {
00210       }
00212       virtual int solutions(void) const {
00213         return 0;
00214       }
00216       virtual bool best(void) const {
00217         return false;
00218       }
00220       static std::string name(void) {
00221         return "Fail";
00222       }
00223     };
00224 
00226     class HasSolutions : public TestSpace {
00227     public:
00229       IntVarArray x;
00231       HowToBranch htb1, htb2, htb3;
00233       HowToConstrain htc;
00235       void branch(const IntVarArgs& x, HowToBranch htb) {
00236         switch (htb) {
00237         case HTB_NONE:
00238           break;
00239         case HTB_UNARY:
00240           assign(this, x, INT_ASSIGN_MIN);
00241           break;
00242         case HTB_BINARY:
00243           Gecode::branch(this, x, INT_VAR_NONE, INT_VAL_MIN);
00244           break;
00245         case HTB_NARY:
00246           {
00247             ViewArray<IntView> xv(this,x);
00248             new (this) NaryBranching(this, xv);
00249             break;
00250           }
00251         }
00252       }
00254       HasSolutions(HowToBranch _htb1, HowToBranch _htb2, HowToBranch _htb3,
00255                    HowToConstrain _htc=HTC_NONE) 
00256         : x(this,6,0,5), htb1(_htb1), htb2(_htb2), htb3(_htb3), htc(_htc) {
00257         distinct(this, x);
00258         rel(this, x[2], IRT_LQ, 3); rel(this, x[3], IRT_LQ, 3);
00259         rel(this, x[4], IRT_LQ, 1); rel(this, x[5], IRT_LQ, 1);
00260         IntVarArgs x1(2); x1[0]=x[0]; x1[1]=x[1]; branch(x1, htb1);
00261         IntVarArgs x2(2); x2[0]=x[2]; x2[1]=x[3]; branch(x2, htb2);
00262         IntVarArgs x3(2); x3[0]=x[4]; x3[1]=x[5]; branch(x3, htb3);
00263       }
00265       HasSolutions(bool share, HasSolutions& s) 
00266         : TestSpace(share,s), 
00267           htb1(s.htb1), htb2(s.htb2), htb3(s.htb3), htc(s.htc) {
00268         x.update(this, share, s.x);
00269       }
00271       virtual Space* copy(bool share) {
00272         return new HasSolutions(share,*this);
00273       }
00275       void constrain(Space* _s) {
00276         HasSolutions* s = static_cast<HasSolutions*>(_s);
00277         switch (htc) {
00278         case HTC_NONE:
00279           break;
00280         case HTC_LEX_LE:
00281         case HTC_LEX_GR:
00282           {
00283             IntVarArgs y(6);
00284             for (int i=0; i<6; i++)
00285               y[i].init(this, s->x[i].val(), s->x[i].val());
00286             lex(this, x, (htc == HTC_LEX_LE) ? IRT_LE : IRT_GR, y);
00287             break;
00288           }
00289         case HTC_BAL_LE:
00290         case HTC_BAL_GR:
00291           {
00292             IntVarArgs y(6);
00293             for (int i=0; i<6; i++)
00294               y[i].init(this, s->x[i].val(), s->x[i].val());
00295             IntVar xs(this, -18, 18);
00296             IntVar ys(this, -18, 18);
00297             post(this, x[0]+x[1]+x[2]-x[3]-x[4]-x[5] == xs);
00298             post(this, y[0]+y[1]+y[2]-y[3]-y[4]-y[5] == ys);
00299             rel(this, 
00300                 abs(this,xs), 
00301                 (htc == HTC_BAL_LE) ? IRT_LE : IRT_GR,
00302                 abs(this,ys));
00303             break;
00304           }
00305         }
00306       }
00308       virtual int solutions(void) const {
00309         if (htb1 == HTB_NONE) {
00310           assert((htb2 == HTB_NONE) && (htb3 == HTB_NONE));
00311           return 1;
00312         }
00313         if ((htb1 == HTB_UNARY) || (htb2 == HTB_UNARY))
00314           return 0;
00315         if (htb3 == HTB_UNARY)
00316           return 4;
00317         return 8;
00318       }
00320       virtual bool best(void) const {
00321         if ((htb1 == HTB_NONE) || (htb2 == HTB_NONE) || (htb3 == HTB_NONE) ||
00322             (htb1 == HTB_UNARY) || (htb2 == HTB_UNARY) || (htb3 == HTB_UNARY))
00323           return true;
00324         switch (htc) {
00325         case HTC_NONE: 
00326           return true;
00327         case HTC_LEX_LE:
00328           return ((x[0].val()==4) && (x[1].val()==5) &&
00329                   (x[2].val()==2) && (x[3].val()==3) && 
00330                   (x[4].val()==0) && (x[5].val()==1));
00331         case HTC_LEX_GR:
00332           return ((x[0].val()==5) && (x[1].val()==4) &&
00333                   (x[2].val()==3) && (x[3].val()==2) &&
00334                   (x[4].val()==1) && (x[5].val()==0));
00335         case HTC_BAL_LE:
00336           return ((x[0].val()==4) && (x[1].val()==5) &&
00337                   (x[2].val()==2) && (x[3].val()==3) && 
00338                   (x[4].val()==0) && (x[5].val()==1));
00339         case HTC_BAL_GR:
00340           return ((x[0].val()==4) && (x[1].val()==5) &&
00341                   (x[2].val()==3) && (x[3].val()==2) &&
00342                   (x[4].val()==0) && (x[5].val()==1));
00343         default: GECODE_NEVER;
00344         }
00345         return false;
00346       }
00348       static std::string name(void) {
00349         return "Sol";
00350       }
00351     };
00352 
00354     class Test : public Base {
00355     public:
00357       HowToBranch htb1, htb2, htb3;
00359       HowToConstrain htc;
00361       static std::string str(unsigned int i) {
00362         std::stringstream s;
00363         s << i;
00364         return s.str();
00365       }
00367       static std::string str(HowToBranch htb) {
00368         switch (htb) {
00369         case HTB_NONE:   return "None";
00370         case HTB_UNARY:  return "Unary";
00371         case HTB_BINARY: return "Binary";
00372         case HTB_NARY:   return "Nary";
00373         default: GECODE_NEVER;
00374         }
00375         GECODE_NEVER;
00376         return "";
00377       }
00379       static std::string str(HowToConstrain htc) {
00380         switch (htc) {
00381         case HTC_NONE:   return "None";
00382         case HTC_LEX_LE: return "LexLe";
00383         case HTC_LEX_GR: return "LexGr";
00384         case HTC_BAL_LE: return "BalLe";
00385         case HTC_BAL_GR: return "BalGr";
00386         default: GECODE_NEVER;
00387         }
00388         GECODE_NEVER;
00389         return "";
00390       }
00392       Test(const std::string& s,
00393            HowToBranch _htb1, HowToBranch _htb2, HowToBranch _htb3,
00394            HowToConstrain _htc=HTC_NONE) 
00395         : Base("Search::"+s), 
00396           htb1(_htb1), htb2(_htb2), htb3(_htb3), htc(_htc) {}
00397     };
00398 
00400     template <class Model>
00401     class DFS : public Test {
00402     private:
00404       unsigned int c_d;
00406       unsigned int a_d;
00407     public:
00409       DFS(HowToBranch htb1, HowToBranch htb2, HowToBranch htb3,
00410           unsigned int c_d0, unsigned int a_d0) 
00411         : Test("DFS::"+Model::name()+"::"+
00412                str(htb1)+"::"+str(htb2)+"::"+str(htb3)+"::"+
00413                str(c_d0)+"::"+str(a_d0),
00414                htb1,htb2,htb3), c_d(c_d0), a_d(a_d0) {}
00416       virtual bool run(void) {
00417         Model* m = new Model(htb1,htb2,htb3);
00418         Gecode::Search::FailStop f(2);
00419         Gecode::Search::Options o;
00420         o.c_d  = c_d;
00421         o.a_d  = a_d;
00422         o.stop = &f;
00423         Gecode::DFS<Model> dfs(m,o);
00424         int n = m->solutions();
00425         delete m;
00426         while (true) {
00427           Model* s = dfs.next();
00428           if (s != NULL) {
00429             n--; delete s;
00430           }
00431           if ((s == NULL) && !dfs.stopped())
00432             break;
00433           f.limit(f.limit()+2);
00434         }
00435         return n == 0;
00436       }
00437     };
00438 
00440     template <class Model>
00441     class LDS : public Test {
00442     public:
00444       LDS(HowToBranch htb1, HowToBranch htb2, HowToBranch htb3)
00445         : Test("LDS::"+Model::name()+"::"+
00446                str(htb1)+"::"+str(htb2)+"::"+str(htb3),
00447                htb1,htb2,htb3) {}
00449       virtual bool run(void) {
00450         Model* m = new Model(htb1,htb2,htb3);
00451         Gecode::Search::FailStop f(2);
00452         Gecode::Search::Options o;
00453         o.stop = &f;
00454         Gecode::LDS<Model> lds(m,50,o);
00455         int n = m->solutions();
00456         delete m;
00457         while (true) {
00458           Model* s = lds.next();
00459           if (s != NULL) {
00460             n--; delete s;
00461           }
00462           if ((s == NULL) && !lds.stopped())
00463             break;
00464           f.limit(f.limit()+2);
00465         }
00466         return n == 0;
00467       }
00468     };
00469 
00471     template <class Model, template<class> class Engine>
00472     class Best : public Test {
00473     private:
00475       unsigned int c_d;
00477       unsigned int a_d;
00478     public:
00480       Best(const std::string& b, HowToConstrain htc,
00481            HowToBranch htb1, HowToBranch htb2, HowToBranch htb3,
00482            unsigned int c_d0, unsigned int a_d0) 
00483         : Test(b+"::"+Model::name()+"::"+str(htc)+"::"+
00484                str(htb1)+"::"+str(htb2)+"::"+str(htb3)+"::"+
00485                str(c_d0)+"::"+str(a_d0),
00486                htb1,htb2,htb3,htc), c_d(c_d0), a_d(a_d0) {}
00488       virtual bool run(void) {
00489         Model* m = new Model(htb1,htb2,htb3,htc);
00490         Gecode::Search::FailStop f(2);
00491         Gecode::Search::Options o;
00492         o.c_d  = c_d;
00493         o.a_d  = a_d;
00494         o.stop = &f;
00495         Engine<Model> best(m,o);
00496         delete m;
00497         Model* b = NULL;
00498         while (true) {
00499           Model* s = best.next();
00500           if (s != NULL) {
00501             delete b; b=s;
00502           }
00503           if ((s == NULL) && !best.stopped())
00504             break;
00505           f.limit(f.limit()+2);
00506         }
00507         bool ok = (b == NULL) || b->best();
00508         delete b;
00509         return ok;
00510       }
00511     };
00512 
00514     class BranchTypes {
00515     private:
00517       static const HowToBranch htbs[3];
00519       int i; 
00520     public:
00522       BranchTypes(void) : i(0) {}
00524       bool operator()(void) const {
00525         return i<3;
00526       } 
00528       void operator++(void) {
00529         i++;
00530       }
00532       HowToBranch htb(void) const {
00533         return htbs[i];
00534       }
00535     };
00536 
00537     const HowToBranch BranchTypes::htbs[3] = {HTB_UNARY, HTB_BINARY, HTB_NARY};
00538     
00540     class ConstrainTypes {
00541     private:
00543       static const HowToConstrain htcs[4];
00545       int i; 
00546     public:
00548       ConstrainTypes(void) : i(0) {}
00550       bool operator()(void) const {
00551         return i<4;
00552       } 
00554       void operator++(void) {
00555         i++;
00556       }
00558       HowToConstrain htc(void) const {
00559         return htcs[i];
00560       }
00561     };
00562 
00563     const HowToConstrain ConstrainTypes::htcs[4] = 
00564       {HTC_LEX_LE, HTC_LEX_GR, HTC_BAL_LE, HTC_BAL_GR};
00565     
00566 
00568     class Create {
00569     public:
00571       Create(void) {
00572         // Depth-first search
00573         for (unsigned int c_d = 1; c_d<10; c_d++)
00574           for (unsigned int a_d = 1; a_d<=c_d; a_d++) {
00575             for (BranchTypes htb1; htb1(); ++htb1)
00576               for (BranchTypes htb2; htb2(); ++htb2)
00577                 for (BranchTypes htb3; htb3(); ++htb3)
00578                   (void) new DFS<HasSolutions>(htb1.htb(),htb2.htb(),htb3.htb(),
00579                                                c_d, a_d);
00580             new DFS<FailImmediate>(HTB_NONE, HTB_NONE, HTB_NONE, c_d, a_d);
00581             new DFS<HasSolutions>(HTB_NONE, HTB_NONE, HTB_NONE, c_d, a_d);
00582           }
00583 
00584         // Limited discrepancy search
00585         for (BranchTypes htb1; htb1(); ++htb1)
00586           for (BranchTypes htb2; htb2(); ++htb2)
00587             for (BranchTypes htb3; htb3(); ++htb3)
00588               (void) new LDS<HasSolutions>(htb1.htb(),htb2.htb(),htb3.htb());
00589         new LDS<FailImmediate>(HTB_NONE, HTB_NONE, HTB_NONE);
00590         new LDS<HasSolutions>(HTB_NONE, HTB_NONE, HTB_NONE);
00591 
00592         // Best solution search
00593         for (unsigned int c_d = 1; c_d<10; c_d++)
00594           for (unsigned int a_d = 1; a_d<=c_d; a_d++) {
00595             for (ConstrainTypes htc; htc(); ++htc)
00596               for (BranchTypes htb1; htb1(); ++htb1)
00597                 for (BranchTypes htb2; htb2(); ++htb2)
00598                   for (BranchTypes htb3; htb3(); ++htb3) {
00599                     (void) new Best<HasSolutions,BAB>
00600                       ("BAB",htc.htc(),htb1.htb(),htb2.htb(),htb3.htb(),c_d,a_d);
00601                     (void) new Best<HasSolutions,Restart>
00602                       ("Restart",htc.htc(),htb1.htb(),htb2.htb(),htb3.htb(),c_d,a_d);
00603                   }
00604             (void) new Best<FailImmediate,BAB>
00605               ("BAB",HTC_NONE,HTB_NONE,HTB_NONE,HTB_NONE,c_d,a_d);
00606             (void) new Best<HasSolutions,BAB>
00607               ("BAB",HTC_NONE,HTB_NONE,HTB_NONE,HTB_NONE,c_d,a_d);
00608           }
00609 
00610       }
00611     };
00612 
00613     Create c;
00614   }
00615 
00616 }
00617 
00618 // STATISTICS: test-search