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

reg.cpp

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, 2004
00008  *
00009  *  Last modified:
00010  *     $Date: 2009-01-20 23:44:27 +0100 (Tue, 20 Jan 2009) $ by $Author: schulte $
00011  *     $Revision: 8082 $
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/minimodel.hh>
00039 
00040 namespace Gecode {
00041 
00042   namespace MiniModel {
00043 
00044     class PosSet;
00048     typedef Support::BlockAllocator<PosSet> PosSetAllocator;
00049 
00050     class NodeInfo;
00051     class PosInfo;
00052 
00053   }
00054 
00056   class REG::Exp {
00057   public:
00059     unsigned int use_cnt;
00060     unsigned int _n_pos;
00064     enum ExpType {
00065       ET_SYMBOL,
00066       ET_CONC,
00067       ET_OR,
00068       ET_STAR
00069     };
00071     ExpType type;
00073     union {
00075       int  symbol;
00077       Exp* kids[2];
00078     } data;
00079 
00080     void followpos(MiniModel::PosSetAllocator&,
00081                    MiniModel::NodeInfo&,
00082                    MiniModel::PosInfo*,
00083                    int&);
00084     void inc(void);
00085     void dec(void);
00086     unsigned int n_pos(void) const;
00088     template<class Char, class Traits>
00089     std::basic_ostream<Char,Traits>&
00090     print(std::basic_ostream<Char,Traits>& os) const;
00091 
00092     static void* operator new(size_t);
00093     static void  operator delete(void*);
00094   private:
00095     void dispose(void);
00096   };
00097 
00098 
00099   /*
00100    * Operations on expression nodes
00101    *
00102    */
00103 
00104 
00105   forceinline void*
00106   REG::Exp::operator new(size_t s) {
00107     return heap.ralloc(s);
00108   }
00109   forceinline void
00110   REG::Exp::operator delete(void*) {
00111     // Deallocation happens in dispose
00112   }
00113 
00114   void
00115   REG::Exp::dispose(void) {
00116     Support::DynamicStack<Exp*,Heap> todo(heap);
00117     todo.push(this);
00118     while (!todo.empty()) {
00119       Exp* e = todo.pop();
00120       switch (e->type) {
00121       case ET_OR:
00122       case ET_CONC:
00123         if ((e->data.kids[1] != NULL) && (--e->data.kids[1]->use_cnt == 0))
00124           todo.push(e->data.kids[1]);
00125       case ET_STAR:
00126         if ((e->data.kids[0] != NULL) && (--e->data.kids[0]->use_cnt == 0))
00127           todo.push(e->data.kids[0]);
00128       default: ;
00129       }
00130       heap.rfree(e);
00131     }
00132   }
00133 
00134   forceinline void
00135   REG::Exp::inc(void) {
00136     if (this != NULL)
00137       use_cnt++;
00138   }
00139   forceinline void
00140   REG::Exp::dec(void) {
00141     if ((this != NULL) && (--use_cnt == 0))
00142       dispose();
00143   }
00144 
00145 
00146   forceinline unsigned int
00147   REG::Exp::n_pos(void) const {
00148     return (this != NULL) ? _n_pos : 0;
00149   }
00150 
00151 
00152   /*
00153    * Regular expressions
00154    *
00155    */
00156 
00157   forceinline
00158   REG::REG(Exp* f) : e(f) {}
00159 
00160   REG::REG(void) : e(NULL) {}
00161 
00162   REG::REG(const REG& r) : e(r.e) {
00163     e->inc();
00164   }
00165 
00166   const REG&
00167   REG::operator =(const REG& r) {
00168     if (&r != this) {
00169       r.e->inc();
00170       e->dec();
00171       e = r.e;
00172     }
00173     return *this;
00174   }
00175 
00176   REG::~REG(void) {
00177     e->dec();
00178   }
00179 
00180   REG::REG(int s) : e(new Exp) {
00181     e->use_cnt     = 1;
00182     e->_n_pos      = 1;
00183     e->type        = REG::Exp::ET_SYMBOL;
00184     e->data.symbol = s;
00185   }
00186 
00187   REG::REG(const IntArgs& x) {
00188     int n = x.size();
00189     if (n < 1)
00190       throw MiniModel::TooFewArguments("REG");
00191     Exp** a = heap.alloc<Exp*>(n);
00192     // Initialize with symbols
00193     for (int i=n; i--; ) {
00194       a[i] = new Exp();
00195       a[i]->use_cnt     = 1;
00196       a[i]->_n_pos      = 1;
00197       a[i]->type        = REG::Exp::ET_SYMBOL;
00198       a[i]->data.symbol = x[i];
00199     }
00200     // Build a balanced tree of alternative nodes
00201     for (int m=n; m>1; ) {
00202       if (m & 1) {
00203         m -= 1;
00204         Exp* e1 = a[m];
00205         Exp* e2 = a[0];
00206         a[0] = new Exp;
00207         a[0]->use_cnt      = 1;
00208         a[0]->_n_pos       = e1->n_pos() + e2->n_pos();
00209         a[0]->type         = REG::Exp::ET_OR;
00210         a[0]->data.kids[0] = e1;
00211         a[0]->data.kids[1] = e2;
00212       } else {
00213         m >>= 1;
00214         for (int i=0; i<m; i++) {
00215           Exp* e1 = a[2*i];
00216           Exp* e2 = a[2*i+1];
00217           a[i] = new Exp;
00218           a[i]->use_cnt      = 1;
00219           a[i]->_n_pos       = e1->n_pos() + e2->n_pos();
00220           a[i]->type         = REG::Exp::ET_OR;
00221           a[i]->data.kids[0] = e1;
00222           a[i]->data.kids[1] = e2;
00223         }
00224       }
00225     }
00226     e = a[0];
00227     heap.free<Exp*>(a,n);
00228   }
00229 
00230   REG
00231   REG::operator |(const REG& r2) {
00232     if (e == r2.e)
00233       return *this;
00234     Exp* f = new Exp();
00235     f->use_cnt      = 1;
00236     f->_n_pos       = e->n_pos() + r2.e->n_pos();
00237     f->type         = REG::Exp::ET_OR;
00238     f->data.kids[0] = e;    e->inc();
00239     f->data.kids[1] = r2.e; r2.e->inc();
00240     REG r(f);
00241     return r;
00242   }
00243 
00244   REG&
00245   REG::operator |=(const REG& r2) {
00246     if (e == r2.e)
00247       return *this;
00248     Exp* f = new Exp();
00249     f->use_cnt      = 1;
00250     f->_n_pos       = e->n_pos() + r2.e->n_pos();
00251     f->type         = REG::Exp::ET_OR;
00252     f->data.kids[0] = e;
00253     f->data.kids[1] = r2.e; r2.e->inc();
00254     e=f;
00255     return *this;
00256   }
00257 
00258   REG
00259   REG::operator +(const REG& r2) {
00260     if (e == NULL)    return r2;
00261     if (r2.e == NULL) return *this;
00262     Exp* f = new Exp();
00263     f->use_cnt      = 1;
00264     f->_n_pos       = e->n_pos() + r2.e->n_pos();
00265     f->type         = REG::Exp::ET_CONC;
00266     f->data.kids[0] = e;    e->inc();
00267     f->data.kids[1] = r2.e; r2.e->inc();
00268     REG r(f);
00269     return r;
00270   }
00271 
00272   REG&
00273   REG::operator +=(const REG& r2) {
00274     if (r2.e == NULL)
00275       return *this;
00276     if (e == NULL) {
00277       e=r2.e; e->inc();
00278     } else {
00279       Exp* f = new Exp();
00280       f->use_cnt      = 1;
00281       f->_n_pos       = e->n_pos() + r2.e->n_pos();
00282       f->type         = REG::Exp::ET_CONC;
00283       f->data.kids[0] = e;
00284       f->data.kids[1] = r2.e; r2.e->inc();
00285       e=f;
00286     }
00287     return *this;
00288   }
00289 
00290   REG
00291   REG::operator *(void) {
00292     if ((e == NULL) || (e->type == REG::Exp::ET_STAR))
00293       return *this;
00294     Exp* f = new Exp();
00295     f->use_cnt      = 1;
00296     f->_n_pos       = e->n_pos();
00297     f->type         = REG::Exp::ET_STAR;
00298     f->data.kids[0] = e; e->inc();
00299     REG r(f);
00300     return r;
00301   }
00302 
00303   REG
00304   REG::operator ()(unsigned int n, unsigned int m) {
00305     REG r;
00306     if ((n>m) || (m == 0))
00307       return r;
00308     if (n>0) {
00309       int i = n;
00310       REG r0 = *this;
00311       while (i>0)
00312         if (i & 1) {
00313           r = r0+r; i--;
00314         } else {
00315           r0 = r0+r0; i >>= 1;
00316         }
00317     }
00318     if (m > n) {
00319       int i = m-n;
00320       REG s0;
00321       s0 = s0 | *this;
00322       REG s;
00323       while (i>0)
00324         if (i & 1) {
00325           s = s0+s; i--;
00326         } else {
00327           s0 = s0+s0; i >>= 1;
00328         }
00329       r = r + s;
00330     }
00331     return r;
00332   }
00333 
00334   REG
00335   REG::operator ()(unsigned int n) {
00336     REG r;
00337     if (n > 0) {
00338       REG r0 = *this;
00339       int i = n;
00340       while (i>0)
00341         if (i & 1) {
00342           r = r0+r; i--;
00343         } else {
00344           r0 = r0+r0; i >>= 1;
00345         }
00346     }
00347     return r+**this;
00348   }
00349 
00350   REG
00351   REG::operator +(void) {
00352     return this->operator ()(1);
00353   }
00354 
00355 
00356   namespace MiniModel {
00357 
00358     /*
00359      * Sets of positions
00360      *
00361      */
00362 
00366     enum PosSetCmp {
00367       PSC_LE,
00368       PSC_EQ,
00369       PSC_GR
00370     };
00371 
00375     class PosSet : public Support::BlockClient<PosSet> {
00376       // Maintain sets of positions in inverse order
00377       // This makes the check whether the last position is included
00378       // more efficient.
00379     public:
00380       int pos; PosSet* next;
00381 
00382       PosSet(void);
00383       PosSet(int);
00384 
00385       bool in(int) const;
00386       static PosSetCmp cmp(PosSet*,PosSet*);
00387       static PosSet*   cup(PosSetAllocator&,PosSet*,PosSet*);
00388     };
00389 
00390 
00391     forceinline
00392     PosSet::PosSet(void) {}
00393     forceinline
00394     PosSet::PosSet(int p) : pos(p), next(NULL) {}
00395 
00396 
00397     forceinline bool
00398     PosSet::in(int p) const {
00399       for (const PosSet* ps = this; ps != NULL; ps = ps->next)
00400         if (ps->pos == p) {
00401           return true;
00402         } else if (ps->pos < p) {
00403           return false;
00404         }
00405       return false;
00406     }
00407 
00408     forceinline PosSetCmp
00409     PosSet::cmp(PosSet* ps1, PosSet* ps2) {
00410       while ((ps1 != NULL) && (ps2 != NULL)) {
00411         if (ps1 == ps2)
00412           return PSC_EQ;
00413         if (ps1->pos < ps2->pos)
00414           return PSC_LE;
00415         if (ps1->pos > ps2->pos)
00416           return PSC_GR;
00417         ps1 = ps1->next; ps2 = ps2->next;
00418       }
00419       if (ps1 == ps2)
00420         return PSC_EQ;
00421       return ps1 == NULL ? PSC_LE : PSC_GR;
00422     }
00423 
00424     PosSet*
00425     PosSet::cup(PosSetAllocator& psm, PosSet* ps1, PosSet* ps2) {
00426       PosSet*  ps;
00427       PosSet** p = &ps;
00428       while ((ps1 != NULL) && (ps2 != NULL)) {
00429         if (ps1 == ps2) {
00430           *p = ps1; return ps;
00431         }
00432         PosSet* n = new (psm) PosSet;
00433         *p = n; p = &n->next;
00434         if (ps1->pos == ps2->pos) {
00435           n->pos = ps1->pos;
00436           ps1 = ps1->next; ps2 = ps2->next;
00437         } else if (ps1->pos > ps2->pos) {
00438           n->pos = ps1->pos; ps1 = ps1->next;
00439         } else {
00440           n->pos = ps2->pos; ps2 = ps2->next;
00441         }
00442       }
00443       *p = (ps1 != NULL) ? ps1 : ps2;
00444       return ps;
00445     }
00446 
00447 
00452     class NodeInfo {
00453     public:
00454       bool    nullable;
00455       PosSet* firstpos;
00456       PosSet* lastpos;
00457     };
00458 
00459 
00464     class PosInfo {
00465     public:
00466       int     symbol;
00467       PosSet* followpos;
00468     };
00469 
00470   }
00471 
00472   void
00473   REG::Exp::followpos(MiniModel::PosSetAllocator& psm,
00474                       MiniModel::NodeInfo& ni,
00475                       MiniModel::PosInfo* pi, int& p) {
00476     using MiniModel::PosSet;
00477     using MiniModel::NodeInfo;
00478     if (this == NULL) {
00479       ni.nullable = true;
00480       ni.firstpos = NULL;
00481       ni.lastpos  = NULL;
00482       return;
00483     }
00484     switch (type) {
00485     case ET_SYMBOL:
00486       {
00487         pi[p].symbol = data.symbol;
00488         PosSet* ps = new (psm) PosSet(p);
00489         p++;
00490         ni.nullable = false;
00491         ni.firstpos = ps;
00492         ni.lastpos  = ps;
00493       }
00494       break;
00495     case ET_STAR:
00496       {
00497         data.kids[0]->followpos(psm, ni, pi, p);
00498         ni.nullable = true;
00499         for (PosSet* ps = ni.lastpos; ps != NULL; ps = ps->next)
00500           pi[ps->pos].followpos =
00501             PosSet::cup(psm,pi[ps->pos].followpos, ni.firstpos);
00502       }
00503       break;
00504     case ET_CONC:
00505       {
00506         NodeInfo ni0; data.kids[0]->followpos(psm, ni0, pi, p);
00507         data.kids[1]->followpos(psm, ni, pi, p);
00508         for (PosSet* ps = ni0.lastpos; ps != NULL; ps = ps->next)
00509           pi[ps->pos].followpos =
00510             PosSet::cup(psm,pi[ps->pos].followpos,ni.firstpos);
00511         ni.firstpos =
00512           ni0.nullable ? PosSet::cup(psm,ni0.firstpos,ni.firstpos)
00513           : ni0.firstpos;
00514         ni.lastpos =
00515           ni.nullable ? PosSet::cup(psm,ni0.lastpos,ni.lastpos)
00516           : ni.lastpos;
00517         ni.nullable &= ni0.nullable;
00518       }
00519       break;
00520     case ET_OR:
00521       {
00522         NodeInfo ni0; data.kids[0]->followpos(psm, ni0, pi, p);
00523         data.kids[1]->followpos(psm, ni, pi, p);
00524         ni.nullable |= ni0.nullable;
00525         ni.firstpos = PosSet::cup(psm,ni0.firstpos,ni.firstpos);
00526         ni.lastpos  = PosSet::cup(psm,ni0.lastpos,ni.lastpos);
00527       }
00528       break;
00529     default: GECODE_NEVER;
00530     }
00531   }
00532 
00533 
00534   namespace MiniModel {
00535 
00536     class StateNode;
00537 
00541     typedef Support::BlockAllocator<StateNode> StatePoolAllocator;
00542 
00546     class StateNode : public Support::BlockClient<StateNode> {
00547     public:
00548       PosSet*    pos;
00549       int        state;
00550       StateNode* next;
00551       StateNode* left;
00552       StateNode* right;
00553     };
00554 
00558     class StatePool {
00559     public:
00560       int   n_states;
00561       StateNode  root;
00562       StateNode* next;
00563       StateNode* all;
00564 
00565       StatePool(PosSet*);
00566 
00567       StateNode* pop(void);
00568       bool empty(void) const;
00569 
00570       int state(StatePoolAllocator&, PosSet*);
00571     };
00572 
00573     forceinline
00574     StatePool::StatePool(PosSet* ps) {
00575       next     = &root;
00576       all      = NULL;
00577       n_states = 1;
00578       root.pos   = ps;
00579       root.state = 0;
00580       root.next  = NULL;
00581       root.left  = NULL;
00582       root.right = NULL;
00583     }
00584 
00585     forceinline StateNode*
00586     StatePool::pop(void) {
00587       StateNode* n = next;
00588       next = n->next;
00589       n->next = all;
00590       all = n;
00591       return n;
00592     }
00593 
00594     forceinline bool
00595     StatePool::empty(void) const {
00596       return next == NULL;
00597     }
00598 
00599     forceinline int
00600     StatePool::state(StatePoolAllocator& spm, PosSet* ps) {
00601       int d = 0;
00602       StateNode** p = NULL;
00603       StateNode*  n = &root;
00604       do {
00605         switch (PosSet::cmp(ps,n->pos)) {
00606         case PSC_EQ: return n->state;
00607         case PSC_LE: p = &n->left;  n = *p; break;
00608         case PSC_GR: p = &n->right; n = *p; break;
00609         default: GECODE_NEVER;
00610         }
00611         d++;
00612       } while (n != NULL);
00613       n = new (spm) StateNode; *p = n;
00614       n->pos   = ps;
00615       n->state = n_states++;
00616       n->next  = next;
00617       n->left  = NULL;
00618       n->right = NULL;
00619       next = n;
00620       return n->state;
00621     }
00622 
00626     class SymbolsInc {
00627     public:
00628       forceinline bool
00629       operator ()(int x, int y) {
00630         return x < y;
00631       }
00632       forceinline static void
00633       sort(int s[], int n) {
00634         SymbolsInc o;
00635         Support::quicksort<int,SymbolsInc>(s,n,o);
00636       }
00637     };
00638 
00639 
00644     class TransitionBag {
00645     private:
00646       Support::DynamicArray<DFA::Transition,Heap> t;
00647       int n;
00648     public:
00649       TransitionBag(void);
00650       void add(int,int,int);
00651       void finish(void);
00652       DFA::Transition* transitions(void);
00653     };
00654 
00655     forceinline
00656     TransitionBag::TransitionBag(void) : t(heap), n(0) {}
00657 
00658     forceinline void
00659     TransitionBag::add(int i_state, int symbol, int o_state) {
00660       t[n].i_state = i_state;
00661       t[n].symbol  = symbol;
00662       t[n].o_state = o_state;
00663       n++;
00664     }
00665 
00666     forceinline void
00667     TransitionBag::finish(void) {
00668       t[n].i_state = -1;
00669     }
00670 
00671     forceinline DFA::Transition*
00672     TransitionBag::transitions(void) {
00673       return &t[0];
00674     }
00675 
00676 
00681     class FinalBag {
00682     private:
00683       Support::DynamicArray<int,Heap> f;
00684       int n;
00685     public:
00686       FinalBag(void);
00687       void add(int);
00688       void finish(void);
00689       int* finals(void);
00690     };
00691 
00692     forceinline
00693     FinalBag::FinalBag(void) : f(heap), n(0) {}
00694 
00695     forceinline void
00696     FinalBag::add(int state) {
00697       f[n++] = state;
00698     }
00699 
00700     forceinline void
00701     FinalBag::finish(void) {
00702       f[n] = -1;
00703     }
00704 
00705     forceinline int*
00706     FinalBag::finals(void) {
00707       return &f[0];
00708     }
00709 
00710   }
00711 
00712   REG::operator DFA(void) {
00713     using MiniModel::PosSetAllocator;
00714     using MiniModel::StatePoolAllocator;
00715     using MiniModel::PosInfo;
00716     using MiniModel::PosSet;
00717     using MiniModel::NodeInfo;
00718 
00719     using MiniModel::StatePool;
00720     using MiniModel::StateNode;
00721 
00722     using MiniModel::TransitionBag;
00723     using MiniModel::FinalBag;
00724 
00725     using MiniModel::SymbolsInc;
00726 
00727     PosSetAllocator    psm;
00728     StatePoolAllocator spm;
00729     REG r = *this + REG(Int::Limits::max+1);
00730     int n_pos = r.e->n_pos();
00731 
00732     PosInfo* pi = heap.alloc<PosInfo>(n_pos);
00733     for (int i=n_pos; i--; )
00734       pi[i].followpos = NULL;
00735 
00736     NodeInfo ni_root;
00737     int n_p = 0;
00738     r.e->followpos(psm,ni_root,&pi[0],n_p);
00739     assert(n_p == n_pos);
00740 
00741     // Compute symbols
00742     int* symbols = heap.alloc<int>(n_pos);
00743     for (int i=n_pos; i--; )
00744       symbols[i] = pi[i].symbol;
00745 
00746     SymbolsInc::sort(&symbols[0],n_pos-1);
00747     int n_symbols = 1;
00748     for (int i = 1; i<n_pos-1; i++)
00749       if (symbols[i-1] != symbols[i])
00750         symbols[n_symbols++] = symbols[i];
00751 
00752     // Compute states and transitions
00753     TransitionBag tb;
00754     StatePool sp(ni_root.firstpos);
00755     while (!sp.empty()) {
00756       StateNode* sn = sp.pop();
00757       for (int i = n_symbols; i--; ) {
00758         PosSet* u = NULL;
00759         for (PosSet* ps = sn->pos; ps != NULL; ps = ps->next)
00760           if (pi[ps->pos].symbol == symbols[i])
00761             u = PosSet::cup(psm,u,pi[ps->pos].followpos);
00762         if (u != NULL)
00763           tb.add(sn->state,symbols[i],sp.state(spm,u));
00764       }
00765     }
00766     tb.finish();
00767 
00768     // Compute final states
00769     FinalBag fb;
00770     for (StateNode* n = sp.all; n != NULL; n = n->next)
00771       if (n->pos->in(n_pos-1))
00772         fb.add(n->state);
00773     fb.finish();
00774 
00775     heap.free<PosInfo>(pi,n_pos);
00776     heap.free<int>(symbols,n_pos);
00777     return DFA(0,tb.transitions(),fb.finals(),true);
00778   }
00779 
00780 }
00781 
00782 // STATISTICS: minimodel-any
00783