base.hpp /usr/include/gecode/int/circuit.hh Gecode::Int::Circuit::SsccInfo Gecode::Int::Circuit::TellInfo Gecode Gecode::Int Gecode::Int::Circuit /*-*-mode:C++;c-basic-offset:2;indent-tabs-mode:nil-*-*/ /* *Mainauthors: *ChristianSchulte<schulte@gecode.org> * *Copyright: *ChristianSchulte,2007 * *Lastmodified: *$Date:2012-09-0717:31:22+0200(Fri,07Sep2012)$by$Author:schulte$ *$Revision:13068$ * *ThisfileispartofGecode,thegenericconstraint *developmentenvironment: *http://www.gecode.org * *Permissionisherebygranted,freeofcharge,toanypersonobtaining *acopyofthissoftwareandassociateddocumentationfiles(the *"Software"),todealintheSoftwarewithoutrestriction,including *withoutlimitationtherightstouse,copy,modify,merge,publish, *distribute,sublicense,and/orsellcopiesoftheSoftware,andto *permitpersonstowhomtheSoftwareisfurnishedtodoso,subjectto *thefollowingconditions: * *Theabovecopyrightnoticeandthispermissionnoticeshallbe *includedinallcopiesorsubstantialportionsoftheSoftware. * *THESOFTWAREISPROVIDED"ASIS",WITHOUTWARRANTYOFANYKIND, *EXPRESSORIMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOF *MERCHANTABILITY,FITNESSFORAPARTICULARPURPOSEAND *NONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSORCOPYRIGHTHOLDERSBE *LIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,WHETHERINANACTION *OFCONTRACT,TORTOROTHERWISE,ARISINGFROM,OUTOFORINCONNECTION *WITHTHESOFTWAREORTHEUSEOROTHERDEALINGSINTHESOFTWARE. * */ namespaceGecode{namespaceInt{namespaceCircuit{ template<classView,classOffset> forceinline Base<View,Offset>::Base(Homehome,ViewArray<View>&x,Offset&o0) :NaryPropagator<View,Int::PC_INT_DOM>(home,x),y(home,x),o(o0){ home.notice(*this,AP_WEAKLY); } template<classView,classOffset> forceinline Base<View,Offset>::Base(Space&home,boolshare,Base<View,Offset>&p) :NaryPropagator<View,Int::PC_INT_DOM>(home,share,p){ o.update(p.o); y.update(home,share,p.y); } template<classView> classSsccInfo{ public: intmin,low,pre; Int::ViewValues<View>v; }; template<classView> classTellInfo{ public: Viewx;intn; }; template<classView,classOffset> ExecStatus Base<View,Offset>::connected(Space&home){ intn=x.size(); intstart=0; while(x[start].assigned()){ start=o(x[start]).val(); if(start==0)break; } Regionr(home); typedeftypenameOffset::ViewTypeOView; SsccInfo<OView>*si=r.alloc<SsccInfo<OView>>(n); unsignedintn_edges=0; for(inti=n;i--;){ n_edges+=x[i].size(); si[i].pre=-1; } //Stacktorememberwhichnodeshavenotbeenprocessedcompletely Support::StaticStack<int,Region>next(r,n); //Arraytorememberwhichmandatorytellsneedtobedone TellInfo<OView>*eq=r.alloc<TellInfo<OView>>(n); intn_eq=0; //Arraytorememberwhichedgesneedtobepruned TellInfo<OView>*nq=r.alloc<TellInfo<OView>>(n_edges); intn_nq=0; /* *Checkwhetherthereisasinglestronglyconnectedcomponent. *ThisisadownstrippedversionofTarjan'salgorithmas *thecomputationofsccsproperisnotneeded.Inaddition,it *checksamandatoryconditionforagraphtobeHamiltonian *(duetoMatsCarlsson). * *ToquoteMats:Supposeyoudoadepth-firstsearchofthegraph. *Inthatsearch,therootnodewillhaveanumberofchildsubtrees *T1,...,Tn.Byconstruction,ifi<jthenthereisnoedgefrom *TitoTj.ThenecessaryconditionforHamiltonianicityisthat *therebeanedgefromTi+1toTi,for0<i<n. * *Inaddition,wedothefollowing:ifthereisonlyasingleedge *fromTi+1toTi,thenitmustbemandatoryandthevariablemust *beassignedtothatvalue. * *ThesameholdstrueforabackedgefromT0totherootnode. * *Then,alledgesthatreachfromTi+k+1toTicanbepruned. * */ { //Startalwaysatnodestart inti=start; //Counterforscc intcnt=0; //Smallestpreordernumberoflastsubtree(initially,therootnode) intsubtree_min=0; //Largestpreordernumberoflastsubtree(initially,therootnode) intsubtree_max=0; //Numberofbackedgesintolastsubtreeorroot intback=0; start: si[i].min=si[i].pre=si[i].low=cnt++; si[i].v.init(o(x[i])); do{ if(si[si[i].v.val()].pre<0){ next.push(i); i=si[i].v.val(); gotostart; }elseif((subtree_min<=si[si[i].v.val()].pre)&& (si[si[i].v.val()].pre<=subtree_max)){ back++; eq[n_eq].x=o(x[i]); eq[n_eq].n=si[i].v.val(); }elseif(si[si[i].v.val()].pre<subtree_min){ nq[n_nq].x=o(x[i]); nq[n_nq].n=si[i].v.val(); n_nq++; } cont: if(si[si[i].v.val()].low<si[i].min) si[i].min=si[si[i].v.val()].low; ++si[i].v; }while(si[i].v()); if(si[i].min<si[i].low){ si[i].low=si[i].min; }elseif(i!=start){ //Ifitisnotthefirstnodevisited,thereismorethanoneSCC returnES_FAILED; } if(!next.empty()){ i=next.pop(); if(i==start){ //Nobackedge if(back==0) returnES_FAILED; //Exactlyonebackedge,makeitmandatory(keeptopmostentry) if(back==1) n_eq++; back=0; subtree_min=subtree_max+1; subtree_max=cnt-1; } gotocont; } //Whetherallnodeshavebeenvisited if(cnt!=n) returnES_FAILED; ExecStatuses=ES_FIX; //Assignallmandatoryedges while(n_eq-->0){ ModEventme=eq[n_eq].x.eq(home,eq[n_eq].n); if(me_failed(me)) returnES_FAILED; if(me_modified(me)) es=ES_NOFIX; } //Removealledgesthatwouldrequireanon-simplecycle while(n_nq-->0){ ModEventme=nq[n_nq].x.nq(home,nq[n_nq].n); if(me_failed(me)) returnES_FAILED; if(me_modified(me)) es=ES_NOFIX; } returnes; } } template<classView,classOffset> ExecStatus Base<View,Offset>::path(Space&home){ //Prunesthatpartialassignedpathsarenotcompletedtocycles intn=x.size(); Regionr(home); //Thepathstartingatassignedx[i]endsatx[end[j]]whichis //notassigned. int*end=r.alloc<int>(n); for(inti=n;i--;) end[i]=-1; //Astackthatrecordsallindicesisuchthatend[i]!=-1 Support::StaticStack<int,Region>tell(r,n); typedeftypenameOffset::ViewTypeOView; for(inti=y.size();i--;){ assert(!y[i].assigned()); //Non-assignedviewsserveasstartingpointsforassignedpaths Int::ViewValues<OView>v(o(y[i])); //Tryallconnectedvalues do{ intj0=v.val(); //Startingpointfornotyetfollowedassignedpathfound if(x[j0].assigned()&&(end[j0]<0)){ //Followassignedpathuntilnon-assignedview: //allassignedviewonthepathscanbeskipped,as //ifx[i]isassignedtoj,thenx[j]willonlyhave //x[i]aspredecessorduetopropagatingdistinct. intj=j0; do{ j=o(x[j]).val(); }while(x[j].assigned()); //Nowtherecannotbeacyclefromx[j]tox[v.val()]! //However,thetellcannotbedonehereasjmightbe //equaltoiandmighthencekilltheiteratorv! end[j0]=j;tell.push(j0); } ++v; }while(v()); } //Nowdothetellsbasedontheendinformation while(!tell.empty()){ inti=tell.pop(); assert(end[i]>=0); GECODE_ME_CHECK(o(x[end[i]]).nq(home,i)); } returnES_NOFIX; } template<classView,classOffset> forceinlinesize_t Base<View,Offset>::dispose(Space&home){ home.ignore(*this,AP_WEAKLY); (void)NaryPropagator<View,Int::PC_INT_DOM>::dispose(home); returnsizeof(*this); } }}} //STATISTICS:int-prop