Generated on Wed Nov 1 15:04:38 2006 for Gecode by doxygen 1.4.5

reg.cc

Go to the documentation of this file.
00001 /*
00002  *  Main authors:
00003  *     Christian Schulte <schulte@gecode.org>
00004  *
00005  *  Copyright:
00006  *     Christian Schulte, 2004
00007  *
00008  *  Last modified:
00009  *     $Date: 2006-08-04 16:03:26 +0200 (Fri, 04 Aug 2006) $ by $Author: schulte $
00010  *     $Revision: 3512 $
00011  *
00012  *  This file is part of Gecode, the generic constraint
00013  *  development environment:
00014  *     http://www.gecode.org
00015  *
00016  *  See the file "LICENSE" for information on usage and
00017  *  redistribution of this file, and for a
00018  *     DISCLAIMER OF ALL WARRANTIES.
00019  *
00020  */
00021 
00022 #include "gecode/int.hh"
00023 
00024 #include "gecode/support/sort.hh"
00025 #include "gecode/support/block-allocator.hh"
00026 #include "gecode/support/dynamic-stack.hh"
00027 #include "gecode/support/dynamic-array.hh"
00028 
00029 namespace Gecode {
00030 
00031   namespace Int { namespace Regular {
00032 
00033     class PosSet;
00037     typedef Support::BlockAllocator<PosSet> PosSetAllocator;
00038 
00039     class NodeInfo;
00040     class PosInfo;
00041 
00042   }}
00043 
00045   class REG::Exp {
00046   public:
00047     unsigned int use_cnt;
00048     unsigned int _n_pos;
00052     enum ExpType {
00053       ET_SYMBOL,
00054       ET_CONC,
00055       ET_OR,
00056       ET_STAR
00057     };
00058     ExpType type;
00059     union {
00060       int  symbol;
00061       Exp* kids[2];
00062     } data;
00063 
00064     void followpos(Int::Regular::PosSetAllocator&,
00065                    Int::Regular::NodeInfo&,
00066                    Int::Regular::PosInfo*,
00067                    int&);
00068     void inc(void);
00069     void dec(void);
00070     unsigned int n_pos(void) const;
00071     std::ostream& print(std::ostream&) const;
00072 
00073     static void* operator new(size_t);
00074     static void  operator delete(void*);
00075   private:
00076     void dispose(void);
00077   };
00078 
00079 
00080   /*
00081    * Operations on expression nodes
00082    *
00083    */
00084 
00085 
00086   forceinline void*
00087   REG::Exp::operator new(size_t s) {
00088     return Memory::malloc(s);
00089   }
00090   forceinline void
00091   REG::Exp::operator delete(void*) {
00092     // Deallocation happens in dispose
00093   }
00094 
00095   void
00096   REG::Exp::dispose(void) {
00097     Support::DynamicStack<Exp*> todo;
00098     todo.push(this);
00099     while (!todo.empty()) {
00100       Exp* e = todo.pop();
00101       switch (e->type) {
00102       case ET_OR:
00103       case ET_CONC:
00104         if ((e->data.kids[1] != NULL) && (--e->data.kids[1]->use_cnt == 0))
00105           todo.push(e->data.kids[1]);
00106       case ET_STAR:
00107         if ((e->data.kids[0] != NULL) && (--e->data.kids[0]->use_cnt == 0))
00108           todo.push(e->data.kids[0]);
00109       default: ;
00110       }
00111       Memory::free(e);
00112     }
00113   }
00114 
00115   forceinline void
00116   REG::Exp::inc(void) {
00117     if (this != NULL)
00118       use_cnt++;
00119   }
00120   forceinline void
00121   REG::Exp::dec(void) {
00122     if ((this != NULL) && (--use_cnt == 0))
00123       dispose();
00124   }
00125 
00126 
00127   forceinline unsigned int
00128   REG::Exp::n_pos(void) const {
00129     return (this != NULL) ? _n_pos : 0;
00130   }
00131 
00132   std::ostream&
00133   REG::Exp::print(std::ostream& os) const {
00134     if (this == NULL)
00135       return os << "[]";
00136     switch (type) {
00137     case ET_SYMBOL:
00138       return os << "[" << data.symbol << "]";
00139     case ET_STAR:
00140       {
00141         bool par = ((data.kids[0] != NULL) &&
00142                     ((data.kids[0]->type == ET_CONC) ||
00143                      (data.kids[0]->type == ET_OR)));
00144         return data.kids[0]->print(os << (par ? "*(" : "*"))
00145                                       << (par ? ")" : "");
00146       }
00147     case ET_CONC:
00148       {
00149         bool par0 = ((data.kids[0] != NULL) &&
00150                      (data.kids[0]->type == ET_OR));
00151         std::ostream& os1 = data.kids[0]->print(os << (par0 ? "(" : ""))
00152                                                    << (par0 ? ")+" : "+");
00153         bool par1 = ((data.kids[1] != NULL) &&
00154                      (data.kids[1]->type == ET_OR));
00155         return data.kids[1]->print(os1 << (par1 ? "(" : "") )
00156                                        << (par1 ? ")" : "");
00157       }
00158     case ET_OR:
00159       return data.kids[1]->print(data.kids[0]->print(os) << "|");
00160     default: GECODE_NEVER;
00161     }
00162     GECODE_NEVER;
00163     return os;
00164   }
00165 
00166 
00167   /*
00168    * Regular expressions
00169    *
00170    */
00171 
00172   forceinline
00173   REG::REG(Exp* f) : e(f) {}
00174 
00175   REG::REG(void) : e(NULL) {}
00176 
00177   REG::REG(const REG& r) : e(r.e) {
00178     e->inc();
00179   }
00180 
00181   std::ostream&
00182   REG::print(std::ostream& os) const {
00183     return e->print(os);
00184   }
00185 
00186   const REG&
00187   REG::operator=(const REG& r) {
00188     if (&r != this) {
00189       r.e->inc();
00190       e->dec();
00191       e = r.e;
00192     }
00193     return *this;
00194   }
00195 
00196   REG::~REG(void) {
00197     e->dec();
00198   }
00199 
00200   REG::REG(int s) : e(new Exp) {
00201     e->use_cnt     = 1;
00202     e->_n_pos      = 1;
00203     e->type        = REG::Exp::ET_SYMBOL;
00204     e->data.symbol = s;
00205   }
00206 
00207   REG
00208   REG::operator|(const REG& r2) {
00209     if (e == r2.e)
00210       return *this;
00211     Exp* f = new Exp();
00212     f->use_cnt      = 1;
00213     f->_n_pos       = e->n_pos() + r2.e->n_pos();
00214     f->type         = REG::Exp::ET_OR;
00215     f->data.kids[0] = e;    e->inc();
00216     f->data.kids[1] = r2.e; r2.e->inc();
00217     REG r(f);
00218     return r;
00219   }
00220 
00221   REG
00222   REG::operator+(const REG& r2) {
00223     if (e == NULL)    return r2;
00224     if (r2.e == NULL) return *this;
00225     Exp* f = new Exp();
00226     f->use_cnt      = 1;
00227     f->_n_pos       = e->n_pos() + r2.e->n_pos();
00228     f->type         = REG::Exp::ET_CONC;
00229     f->data.kids[0] = e;    e->inc();
00230     f->data.kids[1] = r2.e; r2.e->inc();
00231     REG r(f);
00232     return r;
00233   }
00234 
00235   REG
00236   REG::operator*(void) {
00237     if ((e == NULL) || (e->type == REG::Exp::ET_STAR))
00238       return *this;
00239     Exp* f = new Exp();
00240     f->use_cnt      = 1;
00241     f->_n_pos       = e->n_pos();
00242     f->type         = REG::Exp::ET_STAR;
00243     f->data.kids[0] = e; e->inc();
00244     REG r(f);
00245     return r;
00246   }
00247 
00248   REG
00249   REG::operator()(unsigned int n, unsigned int m) {
00250     REG r;
00251     if ((n>m) || (m == 0))
00252       return r;
00253     if (n>0) {
00254       int i = n;
00255       REG r0 = *this;
00256       while (i>0)
00257         if (i & 1) {
00258           r = r0+r; i--;
00259         } else {
00260           r0 = r0+r0; i >>= 1;
00261         }
00262     }
00263     if (m > n) {
00264       int i = m-n;
00265       REG s0;
00266       s0 = s0 | *this;
00267       REG s;
00268       while (i>0)
00269         if (i & 1) {
00270           s = s0+s; i--;
00271         } else {
00272           s0 = s0+s0; i >>= 1;
00273         }
00274       r = r + s;
00275     }
00276     return r;
00277   }
00278 
00279   REG
00280   REG::operator()(unsigned int n) {
00281     REG r;
00282     if (n > 0) {
00283       REG r0 = *this;
00284       int i = n;
00285       while (i>0)
00286         if (i & 1) {
00287           r = r0+r; i--;
00288         } else {
00289           r0 = r0+r0; i >>= 1;
00290         }
00291     }
00292     return r+**this;
00293   }
00294 
00295   REG
00296   REG::operator+(void) {
00297     return this->operator()(1);
00298   }
00299 
00300 
00301   namespace Int { namespace Regular {
00302 
00303     /*
00304      * Sets of positions
00305      *
00306      */
00307 
00311     enum PosSetCmp {
00312       PSC_LE,
00313       PSC_EQ,
00314       PSC_GR
00315     };
00316 
00320     class PosSet : public Support::BlockClient<PosSet> {
00321       // Maintain sets of positions in inverse order
00322       // This makes the check whether the last position is included
00323       // more efficient.
00324     public:
00325       int pos; PosSet* next;
00326 
00327       PosSet(void);
00328       PosSet(int);
00329 
00330       bool in(int) const;
00331       static PosSetCmp cmp(PosSet*,PosSet*);
00332       static PosSet*   cup(PosSetAllocator&,PosSet*,PosSet*);
00333     };
00334 
00335 
00336     forceinline
00337     PosSet::PosSet(void) {}
00338     forceinline
00339     PosSet::PosSet(int p) : pos(p), next(NULL) {}
00340 
00341 
00342     forceinline bool
00343     PosSet::in(int p) const {
00344       for (const PosSet* ps = this; ps != NULL; ps = ps->next)
00345         if (ps->pos == p) {
00346           return true;
00347         } else if (ps->pos < p) {
00348           return false;
00349         }
00350       return false;
00351     }
00352 
00353     forceinline PosSetCmp
00354     PosSet::cmp(PosSet* ps1, PosSet* ps2) {
00355       while ((ps1 != NULL) && (ps2 != NULL)) {
00356         if (ps1 == ps2)
00357           return PSC_EQ;
00358         if (ps1->pos < ps2->pos)
00359           return PSC_LE;
00360         if (ps1->pos > ps2->pos)
00361           return PSC_GR;
00362         ps1 = ps1->next; ps2 = ps2->next;
00363       }
00364       if (ps1 == ps2)
00365         return PSC_EQ;
00366       return ps1 == NULL ? PSC_LE : PSC_GR;
00367     }
00368 
00369     PosSet*
00370     PosSet::cup(PosSetAllocator& psm, PosSet* ps1, PosSet* ps2) {
00371       PosSet*  ps;
00372       PosSet** p = &ps;
00373       while ((ps1 != NULL) && (ps2 != NULL)) {
00374         if (ps1 == ps2) {
00375           *p = ps1; return ps;
00376         }
00377         PosSet* n = new (psm) PosSet;
00378         *p = n; p = &n->next;
00379         if (ps1->pos == ps2->pos) {
00380           n->pos = ps1->pos;
00381           ps1 = ps1->next; ps2 = ps2->next;
00382         } else if (ps1->pos > ps2->pos) {
00383           n->pos = ps1->pos; ps1 = ps1->next;
00384         } else {
00385           n->pos = ps2->pos; ps2 = ps2->next;
00386         }
00387       }
00388       *p = (ps1 != NULL) ? ps1 : ps2;
00389       return ps;
00390     }
00391 
00392 
00397     class NodeInfo {
00398     public:
00399       bool    nullable;
00400       PosSet* firstpos;
00401       PosSet* lastpos;
00402     };
00403 
00404 
00409     class PosInfo {
00410     public:
00411       int     symbol;
00412       PosSet* followpos;
00413     };
00414 
00415   }}
00416 
00417   void
00418   REG::Exp::followpos(Int::Regular::PosSetAllocator& psm,
00419                       Int::Regular::NodeInfo& ni,
00420                       Int::Regular::PosInfo* pi, int& p) {
00421     using Int::Regular::PosSet;
00422     using Int::Regular::NodeInfo;
00423     if (this == NULL) {
00424       ni.nullable = true;
00425       ni.firstpos = NULL;
00426       ni.lastpos  = NULL;
00427       return;
00428     }
00429     switch (type) {
00430     case ET_SYMBOL:
00431       {
00432         pi[p].symbol = data.symbol;
00433         PosSet* ps = new (psm) PosSet(p);
00434         p++;
00435         ni.nullable = false;
00436         ni.firstpos = ps;
00437         ni.lastpos  = ps;
00438       }
00439       break;
00440     case ET_STAR:
00441       {
00442         data.kids[0]->followpos(psm, ni, pi, p);
00443         ni.nullable = true;
00444         for (PosSet* ps = ni.lastpos; ps != NULL; ps = ps->next)
00445           pi[ps->pos].followpos =
00446             PosSet::cup(psm,pi[ps->pos].followpos, ni.firstpos);
00447       }
00448       break;
00449     case ET_CONC:
00450       {
00451         NodeInfo ni0; data.kids[0]->followpos(psm, ni0, pi, p);
00452         data.kids[1]->followpos(psm, ni, pi, p);
00453         for (PosSet* ps = ni0.lastpos; ps != NULL; ps = ps->next)
00454           pi[ps->pos].followpos =
00455             PosSet::cup(psm,pi[ps->pos].followpos,ni.firstpos);
00456         ni.firstpos =
00457           ni0.nullable ? PosSet::cup(psm,ni0.firstpos,ni.firstpos)
00458           : ni0.firstpos;
00459         ni.lastpos =
00460           ni.nullable ? PosSet::cup(psm,ni0.lastpos,ni.lastpos)
00461           : ni.lastpos;
00462         ni.nullable &= ni0.nullable;
00463       }
00464       break;
00465     case ET_OR:
00466       {
00467         NodeInfo ni0; data.kids[0]->followpos(psm, ni0, pi, p);
00468         data.kids[1]->followpos(psm, ni, pi, p);
00469         ni.nullable |= ni0.nullable;
00470         ni.firstpos = PosSet::cup(psm,ni0.firstpos,ni.firstpos);
00471         ni.lastpos  = PosSet::cup(psm,ni0.lastpos,ni.lastpos);
00472       }
00473       break;
00474     default: GECODE_NEVER;
00475     }
00476   }
00477 
00478 
00479   namespace Int { namespace Regular {
00480 
00481     class StateNode;
00482 
00486     typedef Support::BlockAllocator<StateNode> StatePoolAllocator;
00487 
00491     class StateNode : public Support::BlockClient<StateNode> {
00492     public:
00493       PosSet*    pos;
00494       int        state;
00495       StateNode* next;
00496       StateNode* left;
00497       StateNode* right;
00498     };
00499 
00503     class StatePool {
00504     public:
00505       int   n_states;
00506       StateNode  root;
00507       StateNode* next;
00508       StateNode* all;
00509 
00510       StatePool(PosSet*);
00511 
00512       StateNode* pop(void);
00513       bool empty(void) const;
00514 
00515       int state(StatePoolAllocator&, PosSet*);
00516     };
00517 
00518     forceinline
00519     StatePool::StatePool(PosSet* ps) {
00520       next     = &root;
00521       all      = NULL;
00522       n_states = 1;
00523       root.pos   = ps;
00524       root.state = 0;
00525       root.next  = NULL;
00526       root.left  = NULL;
00527       root.right = NULL;
00528     }
00529 
00530     forceinline StateNode*
00531     StatePool::pop(void) {
00532       StateNode* n = next;
00533       next = n->next;
00534       n->next = all;
00535       all = n;
00536       return n;
00537     }
00538 
00539     forceinline bool
00540     StatePool::empty(void) const {
00541       return next == NULL;
00542     }
00543 
00544     forceinline int
00545     StatePool::state(StatePoolAllocator& spm, PosSet* ps) {
00546       int d = 0;
00547       StateNode** p = NULL;
00548       StateNode*  n = &root;
00549       do {
00550         switch (PosSet::cmp(ps,n->pos)) {
00551         case PSC_EQ: return n->state;
00552         case PSC_LE: p = &n->left;  n = *p; break;
00553         case PSC_GR: p = &n->right; n = *p; break;
00554         default: GECODE_NEVER;
00555         }
00556         d++;
00557       } while (n != NULL);
00558       n = new (spm) StateNode; *p = n;
00559       n->pos   = ps;
00560       n->state = n_states++;
00561       n->next  = next;
00562       n->left  = NULL;
00563       n->right = NULL;
00564       next = n;
00565       return n->state;
00566     }
00567 
00571     class SymbolsInc {
00572     public:
00573       forceinline bool
00574       operator()(int x, int y) {
00575         return x < y;
00576       }
00577       forceinline static void
00578       sort(int s[], int n) {
00579         SymbolsInc o;
00580         Support::quicksort<int,SymbolsInc>(s,n,o);
00581       }
00582     };
00583 
00584 
00589     class TransitionBag {
00590     private:
00591       Support::DynamicArray<DFA::Transition> t;
00592       int n;
00593     public:
00594       TransitionBag(void);
00595       void add(int,int,int);
00596       void finish(void);
00597       DFA::Transition* transitions(void);
00598     };
00599 
00600     forceinline
00601     TransitionBag::TransitionBag(void) : n(0) {}
00602 
00603     forceinline void
00604     TransitionBag::add(int i_state, int symbol, int o_state) {
00605       t[n].i_state = i_state;
00606       t[n].symbol  = symbol;
00607       t[n].o_state = o_state;
00608       n++;
00609     }
00610 
00611     forceinline void
00612     TransitionBag::finish(void) {
00613       t[n].i_state = -1;
00614     }
00615 
00616     forceinline DFA::Transition*
00617     TransitionBag::transitions(void) {
00618       return &t[0];
00619     }
00620 
00621 
00626     class FinalBag {
00627     private:
00628       Support::DynamicArray<int> f;
00629       int n;
00630     public:
00631       FinalBag(void);
00632       void add(int);
00633       void finish(void);
00634       int* finals(void);
00635     };
00636 
00637     forceinline
00638     FinalBag::FinalBag(void) : n(0) {}
00639 
00640     forceinline void
00641     FinalBag::add(int state) {
00642       f[n++] = state;
00643     }
00644 
00645     forceinline void
00646     FinalBag::finish(void) {
00647       f[n] = -1;
00648     }
00649 
00650     forceinline int*
00651     FinalBag::finals(void) {
00652       return &f[0];
00653     }
00654 
00655   }}
00656 
00657   DFA::DFA(REG& r0) {
00658     using Int::Regular::PosSetAllocator;
00659     using Int::Regular::StatePoolAllocator;
00660     using Int::Regular::PosInfo;
00661     using Int::Regular::PosSet;
00662     using Int::Regular::NodeInfo;
00663 
00664     using Int::Regular::StatePool;
00665     using Int::Regular::StateNode;
00666 
00667     using Int::Regular::TransitionBag;
00668     using Int::Regular::FinalBag;
00669 
00670     using Int::Regular::SymbolsInc;
00671 
00672     PosSetAllocator    psm;
00673     StatePoolAllocator spm;
00674     REG r = r0 + REG(Limits::Int::int_max+1);
00675     int n_pos = r.e->n_pos();
00676 
00677     GECODE_AUTOARRAY(PosInfo, pi, n_pos);
00678     for (int i=n_pos; i--; )
00679       pi[i].followpos = NULL;
00680 
00681     NodeInfo ni_root;
00682     int n_p = 0;
00683     r.e->followpos(psm,ni_root,&pi[0],n_p);
00684     assert(n_p == n_pos);
00685 
00686     // Compute symbols
00687     GECODE_AUTOARRAY(int, symbols, n_pos);
00688     for (int i=n_pos; i--; )
00689       symbols[i] = pi[i].symbol;
00690 
00691     SymbolsInc::sort(&symbols[0],n_pos-1);
00692     int n_symbols = 1;
00693     for (int i = 1; i<n_pos-1; i++)
00694       if (symbols[i-1] != symbols[i])
00695         symbols[n_symbols++] = symbols[i];
00696 
00697     // Compute states and transitions
00698     TransitionBag tb;
00699     StatePool sp(ni_root.firstpos);
00700     while (!sp.empty()) {
00701       StateNode* sn = sp.pop();
00702       for (int i = n_symbols; i--; ) {
00703         PosSet* u = NULL;
00704         for (PosSet* ps = sn->pos; ps != NULL; ps = ps->next)
00705           if (pi[ps->pos].symbol == symbols[i])
00706             u = PosSet::cup(psm,u,pi[ps->pos].followpos);
00707         if (u != NULL)
00708           tb.add(sn->state,symbols[i],sp.state(spm,u));
00709       }
00710     }
00711     tb.finish();
00712 
00713     // Compute final states
00714     FinalBag fb;
00715     for (StateNode* n = sp.all; n != NULL; n = n->next)
00716       if (n->pos->in(n_pos-1))
00717         fb.add(n->state);
00718     fb.finish();
00719 
00720     init(0,tb.transitions(),fb.finals(),true);
00721   }
00722 
00723 }
00724 
00725 /*
00726  * Computing with expressions
00727  *
00728  */
00729 
00730 
00731 std::ostream&
00732 operator<<(std::ostream& os, const Gecode::REG& r) {
00733   return r.print(os);
00734 }
00735 
00736 
00737 // STATISTICS: int-prop
00738