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

int.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  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00006  *
00007  *  Copyright:
00008  *     Christian Schulte, 2005
00009  *     Mikael Lagerkvist, 2005
00010  *
00011  *  Last modified:
00012  *     $Date: 2008-02-27 17:57:55 +0100 (Wed, 27 Feb 2008) $ by $Author: tack $
00013  *     $Revision: 6328 $
00014  *
00015  *  This file is part of Gecode, the generic constraint
00016  *  development environment:
00017  *     http://www.gecode.org
00018  *
00019  *  Permission is hereby granted, free of charge, to any person obtaining
00020  *  a copy of this software and associated documentation files (the
00021  *  "Software"), to deal in the Software without restriction, including
00022  *  without limitation the rights to use, copy, modify, merge, publish,
00023  *  distribute, sublicense, and/or sell copies of the Software, and to
00024  *  permit persons to whom the Software is furnished to do so, subject to
00025  *  the following conditions:
00026  *
00027  *  The above copyright notice and this permission notice shall be
00028  *  included in all copies or substantial portions of the Software.
00029  *
00030  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00031  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00032  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00033  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00034  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00035  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00036  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00037  *
00038  */
00039 
00040 #include "test/int.hh"
00041 
00042 #include <algorithm>
00043 
00044 namespace Test { namespace Int {
00045 
00046 
00047   /*
00048    * Complete assignments
00049    *
00050    */
00051   void
00052   CpltAssignment::operator++(void) {
00053     int i = n-1;
00054     while (true) {
00055       ++dsv[i];
00056       if (dsv[i]() || (i == 0))
00057         return;
00058       dsv[i--].init(d);
00059     }
00060   }
00061 
00062   /*
00063    * Random assignments
00064    *
00065    */
00066   void
00067   RandomAssignment::operator++(void) {
00068     for (int i = n; i--; )
00069       vals[i]=randval();
00070     a--;
00071   }
00072 
00073 }}
00074 
00075 std::ostream&
00076 operator<<(std::ostream& os, const Test::Int::Assignment& a) {
00077   int n = a.size();
00078   os << "{";
00079   for (int i=0; i<n; i++)
00080     os << a[i] << ((i!=n-1) ? "," : "}");
00081   return os;
00082 }
00083 
00084 namespace Test { namespace Int {
00085 
00087   class TestSpace : public Gecode::Space {
00088   public:
00090     Gecode::IntSet d;
00092     Gecode::IntVarArray x;
00094     Gecode::BoolVar b;
00096     bool reified;
00098     Test* test;
00099 
00100   public:
00109     TestSpace(int n, Gecode::IntSet& d0, bool r, Test* t, bool log=true)
00110       : d(d0), x(this,n,d), b(this,0,1), reified(r), test(t) {
00111       if (opt.log && log) {
00112         olog << ind(2) << "Initial: x[]=" << x;
00113         if (reified)
00114           olog << " b=" << b;
00115         olog << std::endl;
00116       }
00117     }
00119     TestSpace(bool share, TestSpace& s) 
00120       : Gecode::Space(share,s), d(s.d), reified(s.reified), test(s.test) {
00121       x.update(this, share, s.x);
00122       b.update(this, share, s.b);
00123     }
00125     virtual Gecode::Space* copy(bool share) {
00126       return new TestSpace(share,*this);
00127     }
00128 
00130     TestSpace* cloneWithReflection(void) {
00131       TestSpace* c = new TestSpace(x.size(), d, reified, test);
00132       Gecode::Reflection::VarMap vm;
00133       vm.putArray(this, x, "x");
00134       vm.put(this, b, "b");
00135       Gecode::Reflection::VarMap cvm;
00136       cvm.putArray(c, c->x, "x", true);
00137       cvm.put(c, c->b, "b", true);
00138       Gecode::Reflection::Unreflector d(c, cvm);
00139       Gecode::Reflection::VarMapIter vmi(vm);
00140       try {
00141         for (Gecode::Reflection::ActorSpecIter si(this, vm); si(); ++si) {
00142           Gecode::Reflection::ActorSpec s = si.actor();
00143           for (; vmi(); ++vmi) {
00144             try {
00145               d.var(vmi.spec());
00146             } catch (Gecode::Reflection::ReflectionException e) {
00147               delete c;
00148               return NULL;
00149             }
00150           }
00151           try {
00152             d.post(s);
00153           } catch (Gecode::Reflection::ReflectionException e) {
00154             delete c;
00155             return NULL;
00156           }
00157         }
00158         for (; vmi(); ++vmi) {
00159           try {
00160             d.var(vmi.spec());
00161           } catch (Gecode::Reflection::ReflectionException e) {
00162             delete c;
00163             return NULL;
00164           }
00165         }
00166         assert(c != NULL);
00167         if (failed()) {
00168           c->fail();
00169         }
00170         return c;
00171       } catch (Gecode::Reflection::ReflectionException e) {
00172         delete c;
00173         if (status() == Gecode::SS_FAILED)
00174           return this;
00175         return static_cast<TestSpace*>(clone());
00176       }
00177     }
00178 
00180     bool assigned(void) const {
00181       for (int i=x.size(); i--; )
00182         if (!x[i].assigned())
00183           return false;
00184       return true;
00185     }
00186 
00188     void post(void) {
00189       if (reified){
00190         test->post(this,x,b);
00191         if (opt.log)
00192           olog << ind(3) << "Posting reified propagator" << std::endl;
00193       } else {
00194         test->post(this,x);
00195         if (opt.log)
00196           olog << ind(3) << "Posting propagator" << std::endl;
00197         }
00198     }
00200     bool failed(void) {
00201       if (opt.log) {
00202         olog << ind(3) << "Fixpoint: " << x;
00203         bool f=(status() == Gecode::SS_FAILED);
00204         olog << std::endl << ind(3) << "     -->  " << x << std::endl;
00205         return f;
00206       } else {
00207         return status() == Gecode::SS_FAILED;
00208       }
00209     }
00211     void rel(int i, Gecode::IntRelType irt, int n) {
00212       if (opt.log) {
00213         olog << ind(4) << "x[" << i << "] ";
00214         switch (irt) {
00215         case Gecode::IRT_EQ: olog << "="; break;
00216         case Gecode::IRT_NQ: olog << "!="; break;
00217         case Gecode::IRT_LQ: olog << "<="; break;
00218         case Gecode::IRT_LE: olog << "<"; break;
00219         case Gecode::IRT_GQ: olog << ">="; break;
00220         case Gecode::IRT_GR: olog << ">"; break;
00221         }
00222         olog << " " << n << std::endl;
00223       }
00224       Gecode::rel(this, x[i], irt, n);
00225     }
00227     void rel(bool sol) {
00228       int n = sol ? 1 : 0;
00229       assert(reified);
00230       if (opt.log) 
00231         olog << ind(4) << "b = " << n << std::endl;
00232       Gecode::rel(this, b, Gecode::IRT_EQ, n);
00233     }
00235     void assign(const Assignment& a, bool skip=false) {
00236       using namespace Gecode;
00237       int i = skip ? static_cast<int>(Base::rand(a.size())) : -1;
00238       for (int j=a.size(); j--; ) 
00239         if (i != j) {
00240           rel(j, IRT_EQ, a[j]);
00241           if (Base::fixpoint() && failed())
00242             return;
00243         }
00244     }
00246     void prune(void) {
00247       using namespace Gecode;
00248       // Select variable to be pruned
00249       int i = Base::rand(x.size());
00250       while (x[i].assigned()) {
00251         i = (i+1) % x.size();
00252       }
00253       // Prune values
00254       for (int vals = Base::rand(x[i].size()-1)+1; vals--; ) {
00255         int v;
00256         Gecode::Int::ViewRanges<Gecode::Int::IntView> it(x[i]);
00257         unsigned int skip = Base::rand(x[i].size()-1);
00258         while (true) {
00259           if (it.width() > skip) {
00260             v = it.min() + skip; break;
00261           }
00262           skip -= it.width(); ++it;
00263         }
00264         rel(i, IRT_NQ, v);
00265       }
00266     }
00268     bool prune(const Assignment& a) {
00269       // Select variable to be pruned
00270       int i = Base::rand(x.size());
00271       while (x[i].assigned())
00272         i = (i+1) % x.size();
00273       // Select mode for pruning
00274       switch (Base::rand(3)) {
00275       case 0:
00276         if (a[i] < x[i].max()) {
00277           int v=a[i]+1+Base::rand(static_cast
00278                                   <unsigned int>(x[i].max()-a[i]));
00279           assert((v > a[i]) && (v <= x[i].max()));
00280           rel(i, Gecode::IRT_LE, v);
00281         }
00282         break;
00283       case 1:
00284         if (a[i] > x[i].min()) {
00285           int v=x[i].min()+Base::rand(static_cast
00286                                       <unsigned int>(a[i]-x[i].min()));
00287           assert((v < a[i]) && (v >= x[i].min()));
00288           rel(i, Gecode::IRT_GR, v);
00289         }
00290         break;
00291       default:
00292         {
00293           int v;
00294           Gecode::Int::ViewRanges<Gecode::Int::IntView> it(x[i]);
00295           unsigned int skip = Base::rand(x[i].size()-1);
00296           while (true) {
00297             if (it.width() > skip) {
00298               v = it.min() + skip;
00299               if (v == a[i]) {
00300                 if (it.width() == 1) {
00301                   ++it; v = it.min();
00302                 } else if (v < it.max()) {
00303                   ++v;
00304                 } else {
00305                   --v;
00306                 }
00307               }
00308               break;
00309             }
00310             skip -= it.width(); ++it;
00311           }
00312           rel(i, Gecode::IRT_NQ, v);
00313           break;
00314         }
00315       }
00316       if (Base::fixpoint()) {
00317         if (failed())
00318           return true;
00319         TestSpace* c = static_cast<TestSpace*>(clone());
00320         if (opt.log)
00321           olog << ind(3) << "Testing fixpoint on copy" << std::endl;
00322         c->post();
00323         if (c->failed()) {
00324           delete c; return false;
00325         }
00326         for (int i=x.size(); i--; )
00327           if (x[i].size() != c->x[i].size()) {
00328             delete c; return false;
00329           }
00330         if (reified && (b.size() != c->b.size())) {
00331           delete c; return false;
00332         }
00333         if (opt.log)
00334           olog << ind(3) << "Finished testing fixpoint on copy" << std::endl;
00335         delete c;
00336       }                                                
00337       return true;
00338     }
00339 
00340   };
00341 
00342   const Gecode::IntConLevel IntConLevels::icls[] =
00343     {Gecode::ICL_DOM,Gecode::ICL_BND,Gecode::ICL_VAL};
00344 
00345   const Gecode::IntRelType IntRelTypes::irts[] = 
00346     {Gecode::IRT_EQ,Gecode::IRT_NQ,Gecode::IRT_LQ,
00347      Gecode::IRT_LE,Gecode::IRT_GQ,Gecode::IRT_GR};
00348 
00349   const Gecode::BoolOpType BoolOpTypes::bots[] = 
00350     {Gecode::BOT_AND,Gecode::BOT_OR,Gecode::BOT_IMP,
00351      Gecode::BOT_EQV,Gecode::BOT_XOR};
00352 
00353   Assignment*
00354   Test::assignment(void) const {
00355     return new CpltAssignment(arity,dom);
00356   }
00357 
00358 
00360 #define CHECK_TEST(T,M)                                         \
00361 if (opt.log)                                                    \
00362   olog << ind(3) << "Check: " << (M) << std::endl;              \
00363 if (!(T)) {                                                     \
00364   problem = (M); delete s; goto failed;                         \
00365 }
00366 
00368 #define START_TEST(T)                                           \
00369   if (opt.log) {                                                \
00370      olog.str("");                                              \
00371      olog << ind(2) << "Testing: " << (T) << std::endl;         \
00372   }                                                             \
00373   test = (T);
00374 
00375   bool
00376   Test::ignore(const Assignment&) const {
00377     return false;
00378   }
00379 
00380   void 
00381   Test::post(Gecode::Space*, Gecode::IntVarArray&, 
00382              Gecode::BoolVar) {}
00383 
00384   bool
00385   Test::run(void) {
00386     using namespace Gecode;
00387     const char* test    = "NONE";
00388     const char* problem = "NONE";
00389 
00390     // Set up assignments
00391     Assignment* ap = assignment();
00392     Assignment& a = *ap;
00393 
00394     // Set up space for all solution search
00395     TestSpace* search_s = new TestSpace(arity,dom,false,this,false);
00396     post(search_s,search_s->x);
00397     branch(search_s,search_s->x,INT_VAR_NONE,INT_VAL_MIN);
00398     DFS<TestSpace> e_s(search_s);
00399     delete search_s;
00400 
00401     while (a()) {
00402       bool sol = solution(a);
00403       if (opt.log) {
00404         olog << ind(1) << "Assignment: " << a 
00405              << (sol ? " (solution)" : " (no solution)")
00406              << std::endl;
00407       }
00408       
00409       START_TEST("Assignment (after posting)");
00410       {
00411         TestSpace* s = new TestSpace(arity,dom,false,this);
00412         TestSpace* sc = NULL;
00413         s->post();
00414         switch (Base::rand(3)) {
00415           case 0:
00416             if (opt.log)
00417               olog << ind(3) << "No copy" << std::endl;
00418             sc = s;
00419             s = NULL;
00420             break;
00421           case 1:
00422             if (opt.log)
00423               olog << ind(3) << "Unshared copy" << std::endl;
00424             if (s->status() != SS_FAILED) {
00425               sc = static_cast<TestSpace*>(s->clone(false));
00426             } else {
00427               sc = s; s = NULL;
00428             }
00429             break;
00430           case 2:
00431             if (opt.log)
00432               olog << ind(3) << "Shared copy" << std::endl;
00433             if (s->status() != SS_FAILED) {
00434               sc = static_cast<TestSpace*>(s->clone(true));
00435             } else {
00436               sc = s; s = NULL;
00437             }
00438             break;
00439           default: assert(false);
00440         }
00441         sc->assign(a);
00442         if (sol) {
00443           CHECK_TEST(!sc->failed(), "Failed on solution");
00444           CHECK_TEST(sc->propagators()==0, "No subsumption");
00445         } else {
00446           CHECK_TEST(sc->failed(), "Solved on non-solution");
00447         }
00448         delete s; delete sc;
00449       }
00450       if (opt.reflection) {
00451         START_TEST("Assignment (after posting + reflection)");
00452         {
00453           TestSpace* s = new TestSpace(arity,dom,false,this);
00454           TestSpace* sc = NULL;
00455           s->post();
00456           if (opt.log)
00457             olog << ind(3) << "Reflection copy" << std::endl;
00458           sc = s->cloneWithReflection();
00459           if (sc == s)
00460             s = NULL;
00461           CHECK_TEST(sc != NULL, "Reflection error");
00462           sc->assign(a);
00463           if (sol) {
00464             CHECK_TEST(!sc->failed(), "Failed on solution");
00465             CHECK_TEST(sc->propagators()==0, "No subsumption");
00466           } else {
00467             CHECK_TEST(sc->failed(), "Solved on non-solution");
00468           }
00469           delete s; delete sc;
00470         }
00471       }
00472       START_TEST("Partial assignment (after posting)");
00473       {
00474         TestSpace* s = new TestSpace(arity,dom,false,this);
00475         s->post();
00476         s->assign(a,true);
00477         (void) s->failed();
00478         s->assign(a);
00479         if (sol) {
00480           CHECK_TEST(!s->failed(), "Failed on solution");
00481           CHECK_TEST(s->propagators()==0, "No subsumption");
00482         } else {
00483           CHECK_TEST(s->failed(), "Solved on non-solution");
00484         }
00485         delete s;
00486       }
00487       START_TEST("Assignment (before posting)");
00488       {      
00489         TestSpace* s = new TestSpace(arity,dom,false,this);
00490         s->assign(a); 
00491         s->post();
00492         if (sol) {
00493           CHECK_TEST(!s->failed(), "Failed on solution");
00494           CHECK_TEST(s->propagators()==0, "No subsumption");
00495         } else {
00496           CHECK_TEST(s->failed(), "Solved on non-solution");
00497         }
00498         delete s;
00499       }
00500       START_TEST("Partial assignment (before posting)");
00501       {      
00502         TestSpace* s = new TestSpace(arity,dom,false,this);
00503         s->assign(a,true); 
00504         s->post();
00505         (void) s->failed();
00506         s->assign(a);
00507         if (sol) {
00508           CHECK_TEST(!s->failed(), "Failed on solution");
00509           CHECK_TEST(s->propagators()==0, "No subsumption");
00510         } else {
00511           CHECK_TEST(s->failed(), "Solved on non-solution");
00512         }
00513         delete s;
00514       }
00515       START_TEST("Prune");
00516       {      
00517         TestSpace* s = new TestSpace(arity,dom,false,this);
00518         s->post();
00519         while (!s->failed() && !s->assigned())
00520           if (!s->prune(a)) {
00521             problem = "No fixpoint";
00522             delete s;
00523             goto failed;
00524           }
00525         s->assign(a);
00526         if (sol) {
00527           CHECK_TEST(!s->failed(), "Failed on solution");
00528           CHECK_TEST(s->propagators()==0, "No subsumption");
00529         } else {
00530           CHECK_TEST(s->failed(), "Solved on non-solution");
00531         }
00532         delete s;
00533       }
00534 
00535       if (reified && !ignore(a)) {
00536         START_TEST("Assignment reified (rewrite after post)");
00537         {      
00538           TestSpace* s = new TestSpace(arity,dom,true,this);
00539           s->post();
00540           s->rel(sol);
00541           s->assign(a);
00542           CHECK_TEST(!s->failed(), "Failed");
00543           CHECK_TEST(s->propagators()==0, "No subsumption");
00544           delete s;
00545         }
00546         START_TEST("Assignment reified (immediate rewrite)");
00547         {        
00548           TestSpace* s = new TestSpace(arity,dom,true,this);
00549           s->rel(sol);
00550           s->post();
00551           s->assign(a);
00552           CHECK_TEST(!s->failed(), "Failed");
00553           CHECK_TEST(s->propagators()==0, "No subsumption");
00554           delete s;
00555         }
00556         START_TEST("Assignment reified (before posting)");
00557         {        
00558           TestSpace* s = new TestSpace(arity,dom,true,this);
00559           s->assign(a); 
00560           s->post();
00561           CHECK_TEST(!s->failed(), "Failed");
00562           CHECK_TEST(s->propagators()==0, "No subsumption");
00563           CHECK_TEST(s->b.assigned(), "Control variable unassigned");
00564           if (sol) {
00565             CHECK_TEST(s->b.val()==1, "Zero on solution");
00566           } else {
00567             CHECK_TEST(s->b.val()==0, "One on non-solution");
00568           }
00569           delete s;
00570         }
00571         START_TEST("Assignment reified (after posting)");
00572         {        
00573           TestSpace* s = new TestSpace(arity,dom,true,this);
00574           s->post();
00575           s->assign(a);
00576           CHECK_TEST(!s->failed(), "Failed");
00577           CHECK_TEST(s->propagators()==0, "No subsumption");
00578           CHECK_TEST(s->b.assigned(), "Control variable unassigned");
00579           if (sol) {
00580             CHECK_TEST(s->b.val()==1, "Zero on solution");
00581           } else {
00582             CHECK_TEST(s->b.val()==0, "One on non-solution");
00583           }
00584           delete s;
00585         }
00586         if (opt.reflection) {
00587           START_TEST("Assignment reified (after posting + reflection)");
00588           {
00589             TestSpace* s = new TestSpace(arity,dom,true,this);
00590             TestSpace* sc = NULL;
00591             s->post();
00592             if (opt.log)
00593               olog << ind(3) << "Reflection copy" << std::endl;
00594             sc = s->cloneWithReflection();
00595             if (sc == s)
00596               s = NULL;
00597             CHECK_TEST(sc != NULL, "Reflection error");
00598             sc->assign(a);
00599             CHECK_TEST(!sc->failed(), "Failed");
00600             CHECK_TEST(sc->propagators()==0, "No subsumption");
00601             CHECK_TEST(sc->b.assigned(), "Control variable unassigned");
00602             if (sol) {
00603               CHECK_TEST(sc->b.val()==1, "Zero on solution");
00604             } else {
00605               CHECK_TEST(sc->b.val()==0, "One on non-solution");
00606             }
00607             delete s; delete sc;
00608           }
00609         }
00610         START_TEST("Prune reified");
00611         {        
00612           TestSpace* s = new TestSpace(arity,dom,true,this);
00613           s->post();
00614           while (!s->failed() && (!s->assigned() || !s->b.assigned()))
00615             if (!s->prune(a)) {
00616               problem = "No fixpoint";
00617               delete s;
00618               goto failed;
00619             }
00620           CHECK_TEST(!s->failed(), "Failed");
00621           CHECK_TEST(s->propagators()==0, "No subsumption");
00622           CHECK_TEST(s->b.assigned(), "Control variable unassigned");
00623           if (sol) {
00624             CHECK_TEST(s->b.val()==1, "Zero on solution");
00625           } else {
00626             CHECK_TEST(s->b.val()==0, "One on non-solution");
00627           }
00628           delete s;
00629         }
00630       }
00631 
00632       if (testsearch) {
00633         if (sol) {
00634           START_TEST("Search");
00635           TestSpace* s = e_s.next();
00636           CHECK_TEST(s != NULL, "Solutions exhausted");
00637           CHECK_TEST(s->propagators()==0, "No subsumption");
00638           for (int i=a.size(); i--; ) {
00639             CHECK_TEST(s->x[i].assigned(), "Unassigned variable");
00640             CHECK_TEST(a[i] == s->x[i].val(), "Wrong value in solution");
00641           }
00642           delete s;
00643         }
00644       }
00645 
00646       ++a;
00647     }
00648 
00649     if (testsearch) {
00650       test = "Search";
00651       if (e_s.next() != NULL) {
00652         problem = "Excess solutions";
00653         goto failed;
00654       }
00655     }
00656 
00657     if ((icl == ICL_DOM) && testdomcon) {
00658       START_TEST("Full domain consistency");
00659       TestSpace* s = new TestSpace(arity,dom,false,this);
00660       s->post();
00661       while (!s->failed() && !s->assigned())
00662         s->prune();
00663       CHECK_TEST(!s->failed(), "Failed");
00664       CHECK_TEST(s->propagators()==0, "No subsumption");
00665       delete s;
00666     }
00667 
00668     delete ap;
00669     return true;
00670 
00671   failed:
00672     if (opt.log)
00673       olog << "FAILURE" << std::endl
00674            << ind(1) << "Test:       " << test << std::endl
00675            << ind(1) << "Problem:    " << problem << std::endl;
00676     if (a() && opt.log)
00677       olog << ind(1) << "Assignment: " << a << std::endl;
00678     delete ap;
00679 
00680     return false;
00681   }
00682 
00683 }}
00684 
00685 #undef START_TEST
00686 #undef CHECK_TEST
00687 
00688 // STATISTICS: test-int