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

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