123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500(* ========================================================================= *)(* - This code originates from John Harrison's HOL LIGHT 2.30 *)(* (see file LICENSE.sos for license, copyright and disclaimer) *)(* This code is the HOL LIGHT library code used by sos.ml *)(* - Laurent Théry (thery@sophia.inria.fr) has isolated the HOL *)(* independent bits *)(* - Frédéric Besson (fbesson@irisa.fr) is using it to feed micromega *)(* ========================================================================= *)(* ------------------------------------------------------------------------- *)(* Comparisons that are reflexive on NaN and also short-circuiting. *)(* ------------------------------------------------------------------------- *)(** FIXME *)letcmp=comparelet(=?)xy=cmpxy=0let(<?)xy=cmpxy<0let(<=?)xy=cmpxy<=0let(>?)xy=cmpxy>0(* ------------------------------------------------------------------------- *)(* Combinators. *)(* ------------------------------------------------------------------------- *)letofgx=f(gx)(* ------------------------------------------------------------------------- *)(* Various versions of list iteration. *)(* ------------------------------------------------------------------------- *)letrecend_itlistfl=matchlwith|[]->failwith"end_itlist"|[x]->x|h::t->fh(end_itlistft)(* ------------------------------------------------------------------------- *)(* All pairs arising from applying a function over two lists. *)(* ------------------------------------------------------------------------- *)letrecallpairsfl1l2=matchl1with|h1::t1->List.fold_right(funxa->fh1x::a)l2(allpairsft1l2)|[]->[](* ------------------------------------------------------------------------- *)(* String operations (surely there is a better way...) *)(* ------------------------------------------------------------------------- *)letimplodel=List.fold_right(^)l""letexplodes=letrecexapnl=ifn<0thenlelseexap(n-1)(String.subsn1::l)inexap(String.lengths-1)[](* ------------------------------------------------------------------------- *)(* Repetition of a function. *)(* ------------------------------------------------------------------------- *)letrecfunpownfx=ifn<1thenxelsefunpow(n-1)f(fx)(* ------------------------------------------------------------------------- *)(* Sequences. *)(* ------------------------------------------------------------------------- *)letrec(--)mn=ifm>nthen[]elsem::(m+1--n)(* ------------------------------------------------------------------------- *)(* Various useful list operations. *)(* ------------------------------------------------------------------------- *)letrectryfindfl=matchlwith|[]->failwith"tryfind"|h::t->(tryfhwithFailure_->tryfindft)(* ------------------------------------------------------------------------- *)(* "Set" operations on lists. *)(* ------------------------------------------------------------------------- *)letrecmemxlis=matchliswith[]->false|h::t->x=?h||memxtletinsertxl=ifmemxlthenlelsex::lletunionl1l2=List.fold_rightinsertl1l2letsubtractl1l2=List.filter(funx->not(memxl2))l1(* ------------------------------------------------------------------------- *)(* Common measure predicates to use with "sort". *)(* ------------------------------------------------------------------------- *)letincreasingfxy=fx<?fy(* ------------------------------------------------------------------------- *)(* Iterating functions over lists. *)(* ------------------------------------------------------------------------- *)letrecdo_listfl=matchlwith[]->()|h::t->fh;do_listft(* ------------------------------------------------------------------------- *)(* Sorting. *)(* ------------------------------------------------------------------------- *)letrecsortcmplis=matchliswith|[]->[]|piv::rest->letr,l=List.partition(cmppiv)restinsortcmpl@(piv::sortcmpr)(* ------------------------------------------------------------------------- *)(* Removing adjacent (NB!) equal elements from list. *)(* ------------------------------------------------------------------------- *)letrecuniql=matchlwith|x::(y::_ast)->lett'=uniqtinifx=?ythent'elseift'==tthenlelsex::t'|_->l(* ------------------------------------------------------------------------- *)(* Convert list into set by eliminating duplicates. *)(* ------------------------------------------------------------------------- *)letsetifys=uniq(sort(<=?)s)(* ------------------------------------------------------------------------- *)(* Polymorphic finite partial functions via Patricia trees. *)(* *)(* The point of this strange representation is that it is canonical (equal *)(* functions have the same encoding) yet reasonably efficient on average. *)(* *)(* Idea due to Diego Olivier Fernandez Pons (OCaml list, 2003/11/10). *)(* ------------------------------------------------------------------------- *)type('a,'b)func=|Empty|Leafofint*('a*'b)list|Branchofint*int*('a,'b)func*('a,'b)func(* ------------------------------------------------------------------------- *)(* Undefined function. *)(* ------------------------------------------------------------------------- *)letundefined=Empty(* ------------------------------------------------------------------------- *)(* In case of equality comparison worries, better use this. *)(* ------------------------------------------------------------------------- *)letis_undefinedf=matchfwithEmpty->true|_->false(* ------------------------------------------------------------------------- *)(* Operation analogous to "map" for lists. *)(* ------------------------------------------------------------------------- *)letmapf=letrecmap_listfl=matchlwith[]->[]|(x,y)::t->(x,fy)::map_listftinletrecmapfft=matchtwith|Empty->Empty|Leaf(h,l)->Leaf(h,map_listfl)|Branch(p,b,l,r)->Branch(p,b,mapffl,mapffr)inmapf(* ------------------------------------------------------------------------- *)(* Operations analogous to "fold" for lists. *)(* ------------------------------------------------------------------------- *)letfoldl=letrecfoldl_listfal=matchlwith[]->a|(x,y)::t->foldl_listf(faxy)tinletrecfoldlfat=matchtwith|Empty->a|Leaf(h,l)->foldl_listfal|Branch(p,b,l,r)->foldlf(foldlfal)rinfoldlletfoldr=letrecfoldr_listfla=matchlwith[]->a|(x,y)::t->fxy(foldr_listfta)inletrecfoldrfta=matchtwith|Empty->a|Leaf(h,l)->foldr_listfla|Branch(p,b,l,r)->foldrfl(foldrfra)infoldr(* ------------------------------------------------------------------------- *)(* Redefinition and combination. *)(* ------------------------------------------------------------------------- *)let(|->),combine=letldbxy=letz=xlxoryinzland-zinletnewbranchp1t1p2t2=letb=ldbp1p2inletp=p1land(b-1)inifp1landb=0thenBranch(p,b,t1,t2)elseBranch(p,b,t2,t1)inletrecdefine_list((x,y)asxy)l=matchlwith|((a,b)asab)::t->ifx=?athenxy::telseifx<?athenxy::lelseab::define_listxyt|[]->[xy]andcombine_listopzl1l2=match(l1,l2)with|[],_->l2|_,[]->l1|((x1,y1)asxy1)::t1,((x2,y2)asxy2)::t2->ifx1<?x2thenxy1::combine_listopzt1l2elseifx2<?x1thenxy2::combine_listopzl1t2elselety=opy1y2andl=combine_listopzt1t2inifzythenlelse(x1,y)::linlet(|->)xy=letk=Hashtbl.hashxinletrecupdt=matchtwith|Empty->Leaf(k,[(x,y)])|Leaf(h,l)->ifh=kthenLeaf(h,define_list(x,y)l)elsenewbranchhtk(Leaf(k,[(x,y)]))|Branch(p,b,l,r)->ifkland(b-1)<>pthennewbranchptk(Leaf(k,[(x,y)]))elseifklandb=0thenBranch(p,b,updl,r)elseBranch(p,b,l,updr)inupdinletreccombineopzt1t2=match(t1,t2)with|Empty,_->t2|_,Empty->t1|Leaf(h1,l1),Leaf(h2,l2)->ifh1=h2thenletl=combine_listopzl1l2inifl=[]thenEmptyelseLeaf(h1,l)elsenewbranchh1t1h2t2|(Leaf(k,lis)aslf),(Branch(p,b,l,r)asbr)|(Branch(p,b,l,r)asbr),(Leaf(k,lis)aslf)->ifkland(b-1)=pthenifklandb=0thenletl'=combineopzlflinifis_undefinedl'thenrelseBranch(p,b,l',r)elseletr'=combineopzlfrinifis_undefinedr'thenlelseBranch(p,b,l,r')elsenewbranchklfpbr|Branch(p1,b1,l1,r1),Branch(p2,b2,l2,r2)->ifb1<b2thenifp2land(b1-1)<>p1thennewbranchp1t1p2t2elseifp2landb1=0thenletl=combineopzl1t2inifis_undefinedlthenr1elseBranch(p1,b1,l,r1)elseletr=combineopzr1t2inifis_undefinedrthenl1elseBranch(p1,b1,l1,r)elseifb2<b1thenifp1land(b2-1)<>p2thennewbranchp1t1p2t2elseifp1landb2=0thenletl=combineopzt1l2inifis_undefinedlthenr2elseBranch(p2,b2,l,r2)elseletr=combineopzt1r2inifis_undefinedrthenl2elseBranch(p2,b2,l2,r)elseifp1=p2thenletl=combineopzl1l2andr=combineopzr1r2inifis_undefinedlthenrelseifis_undefinedrthenlelseBranch(p1,b1,l,r)elsenewbranchp1t1p2t2in((|->),combine)(* ------------------------------------------------------------------------- *)(* Special case of point function. *)(* ------------------------------------------------------------------------- *)let(|=>)xy=(x|->y)undefined(* ------------------------------------------------------------------------- *)(* Grab an arbitrary element. *)(* ------------------------------------------------------------------------- *)letrecchooset=matchtwith|Empty->failwith"choose: completely undefined function"|Leaf(h,l)->List.hdl|Branch(b,p,t1,t2)->chooset1(* ------------------------------------------------------------------------- *)(* Application. *)(* ------------------------------------------------------------------------- *)letapplyd=letrecapply_listdldx=matchlwith|(a,b)::t->ifx=?athenbelseifx>?athenapply_listdtdxelsedx|[]->dxinfunfdx->letk=Hashtbl.hashxinletreclookt=matchtwith|Leaf(h,l)whenh=k->apply_listdldx|Branch(p,b,l,r)->look(ifklandb=0thenlelser)|_->dxinlookfletapplyf=applydf(funx->failwith"apply")lettryapplydfad=applydf(funx->d)a(* ------------------------------------------------------------------------- *)(* Undefinition. *)(* ------------------------------------------------------------------------- *)letundefine=letrecundefine_listxl=matchlwith|((a,b)asab)::t->ifx=?athentelseifx<?athenlelselett'=undefine_listxtinift'==tthenlelseab::t'|[]->[]infunx->letk=Hashtbl.hashxinletrecundt=matchtwith|Leaf(h,l)whenh=k->letl'=undefine_listxlinifl'==lthentelseifl'=[]thenEmptyelseLeaf(h,l')|Branch(p,b,l,r)whenkland(b-1)=p->ifklandb=0thenletl'=undlinifl'==lthentelseifis_undefinedl'thenrelseBranch(p,b,l',r)elseletr'=undrinifr'==rthentelseifis_undefinedr'thenlelseBranch(p,b,l,r')|_->tinund(* ------------------------------------------------------------------------- *)(* Mapping to sorted-list representation of the graph, domain and range. *)(* ------------------------------------------------------------------------- *)letgraphf=setify(foldl(funaxy->(x,y)::a)[]f)letdomf=setify(foldl(funaxy->x::a)[]f)(* ------------------------------------------------------------------------- *)(* More parser basics. *)(* ------------------------------------------------------------------------- *)exceptionNoparseletisspace,isnum=letcharcodes=Char.codes.[0]inletspaces=" \t\n\r"andseparators=",;"andbrackets="()[]{}"andsymbs="\\!@#$%^&*-+|\\<=>/?~.:"andalphas="'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"andnums="0123456789"inletallchars=spaces^separators^brackets^symbs^alphas^numsinletcsetsize=List.fold_right(omaxcharcode)(explodeallchars)256inletctable=Array.makecsetsize0indo_list(func->ctable.(charcodec)<-1)(explodespaces);do_list(func->ctable.(charcodec)<-2)(explodeseparators);do_list(func->ctable.(charcodec)<-4)(explodebrackets);do_list(func->ctable.(charcodec)<-8)(explodesymbs);do_list(func->ctable.(charcodec)<-16)(explodealphas);do_list(func->ctable.(charcodec)<-32)(explodenums);letisspacec=ctable.(charcodec)=1andisnumc=ctable.(charcodec)=32in(isspace,isnum)letparser_orparser1parser2input=tryparser1inputwithNoparse->parser2inputlet(++)parser1parser2input=letresult1,rest1=parser1inputinletresult2,rest2=parser2rest1in((result1,result2),rest2)letrecmanyprsinput=tryletresult,next=prsinputinletresults,rest=manyprsnextin(result::results,rest)withNoparse->([],input)let(>>)prstreatmentinput=letresult,rest=prsinputin(treatmentresult,rest)letfixerrprsinput=tryprsinputwithNoparse->failwith(err^" expected")letlistofprsseperr=prs++many(sep++fixerrprs>>snd)>>fun(h,t)->h::tletpossiblyprsinput=tryletx,rest=prsinputin([x],rest)withNoparse->([],input)letsomep=function|[]->raiseNoparse|h::t->ifphthen(h,t)elseraiseNoparseletatok=some(funitem->item=tok)letrecatleastnprsi=(ifn<=0thenmanyprselseprs++atleast(n-1)prs>>fun(h,t)->h::t)i(* ------------------------------------------------------------------------- *)lettemp_path=Filename.get_temp_dir_name()(* ------------------------------------------------------------------------- *)(* Convenient conversion between files and (lists of) strings. *)(* ------------------------------------------------------------------------- *)letstrings_of_filefilename=letfd=tryopen_infilenamewithSys_error_->failwith("strings_of_file: can't open "^filename)inletrecsuck_linesacc=tryletl=input_linefdinsuck_lines(l::acc)withEnd_of_file->List.revaccinletdata=suck_lines[]inclose_infd;dataletstring_of_filefilename=String.concat"\n"(strings_of_filefilename)letfile_of_stringfilenames=letfd=open_outfilenameinoutput_stringfds;close_outfd(* ------------------------------------------------------------------------- *)(* Iterative deepening. *)(* ------------------------------------------------------------------------- *)letrecdeepenfn=try(*print_string "Searching with depth limit ";
print_int n; print_newline();*)fnwithFailure_->deepenf(n+1)exceptionTooDeepletdeepen_untillimitfn=matchcomparelimit0with|0->raiseTooDeep|-1->deepenfn|_->letrecd_untilfn=try(* if !debugging
then (print_string "Searching with depth limit ";
print_int n; print_newline()) ;*)fnwithFailurex->(*if !debugging then (Printf.printf "solver error : %s\n" x) ; *)ifn=limitthenraiseTooDeepelsed_untilf(n+1)ind_untilfn