123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187openUtilsLibmoduleLog=Xlog.Make(structletname="Resumptions"end)moduletypeResumptions_sig=sigtype'aresumptionstype'acomputationtypewvalempty:alt_max:int->'aresumptionsvalregular_sorting:'aresumptions->boolvalis_empty:'aresumptions->boolvalextend_resumptions:computation:'acomputation->weight:w->'aresumptions->'aresumptionsvalpp:Format.formatter->'aresumptions->unitvalswap:?current_computation:'acomputation*w->'aresumptions->'acomputation*w*'aresumptionsendmoduleMake(W:Weight.Weight_sig)(C:sigtype'acomputationend)=structexceptionEmptytype'acomputation='aC.computationtypew=W.wtype'aresumptions={resumptions:'aC.computationW.WMap.t;(* a map from weights to states for resuming *)alt_max:int;(* the threshold beyong which sorting stop
being regular *)alt_number:int;(* the number of alternatives still to be processed *)regular_sorting:bool;(* This field is used to indicate whether
regular sorting is used or if switching
to higher stages was necessary. *)unordered_resumptions:('aC.computation*w)list;(* when [regular_sorting] is false, populate
this list instead of the map. Should be
faster.
*)unordered_number:int;}(* [pow a n] returns [a^n] *)letrecpowa=function|0->1|1->a|n->letb=powa(n/2)inb*b*(ifnmod2=0then1elsea)letempty~alt_max=letalt_max=max0alt_maxin{resumptions=W.WMap.empty;alt_max=pow10alt_max;alt_number=0;regular_sorting=true;unordered_resumptions=[];unordered_number=0;}letregular_sortingres=res.regular_sortingletis_emptyres=matchW.WMap.optimumres.resumptions,res.unordered_resumptionswith|None,[]->let()=assert(res.alt_number=0)inlet()=assert(res.unordered_number=0)intrue|Some_,_->false|None,_::_->falseletextend_resumptions~computation~weightresumptions=ifresumptions.alt_number<=resumptions.alt_max&&resumptions.regular_sortingthen{resumptionswithresumptions=W.WMap.addweightcomputationresumptions.resumptions;alt_number=resumptions.alt_number+1}elselet()=ifresumptions.regular_sortingthenLogs.warn(funm->m"The@ grammar@ is@ too@ ambiguous.@ \
Breaking@ regular@ sorting@ is@ needed@ in@ \
order@ to@ avoid@ stack@ overflow")in{resumptionswithalt_number=resumptions.alt_number+1;regular_sorting=false;unordered_resumptions=(computation,weight)::resumptions.unordered_resumptions;unordered_number=resumptions.unordered_number+1}letppfmt{resumptions;alt_number;alt_max;regular_sorting=_;unordered_resumptions=_;unordered_number=_;}=Format.fprintffmt"Current resumption is as follow:@ @[%d alternatives (max is %d).@ @[%a@]@]"alt_numberalt_maxW.WMap.ppresumptions[@@warning"-32"](** [swap ~current_computation resumptions] returns [(alternative_states,
new_resumption)] where [alternative_states] correspond to the
optimal binding of the resumption, and [new_resumption] the new
resumption when the optimal one has been removed. If
[current_computation] is provided, it is taken into account to check
the optimal binding, except if sorting is not regular in which
case it is directly returned (in order to stop swapping).
*)letrecswap?current_computation(* When present, the [current_computation] parameter specifies the
current computation and its weight when asking for swapping. The
aim is to keep the current computation within the working stage
without adding it with [extend_resumptions] that could put it
in a secondary stage.*)({resumptions=resumption_map;alt_number;alt_max=_;regular_sorting;unordered_resumptions;unordered_number;}asresumptions)=matchregular_sorting,current_computation,W.WMap.optimumresumption_map,unordered_resumptionswith|true,_,_,_::_->failwith"Bug: the unorderd_resumptions should be empty when \
regular sorting is true"|true,Some(computation,w),None,[]->computation,w,resumptions|true,Some(computation,w),Someopt,_when(W.is_betterwopt||W.is_equalwopt)->computation,w,resumptions|true,Some(computation,w),Some_,_->letnew_resumptions=extend_resumptions~computation:computation~weight:wresumptionsinswapnew_resumptions|true,None,None,[]->raiseEmpty|false,Some(computation,w),_,_::_->computation,w,resumptions|false,Some(computation,w),_,[]->let()=Logs.warn(funm->m"Back@ to@ normal@ sorting")incomputation,w,{resumptionswithregular_sorting=true}|false,None,None,[]->raiseEmpty|false,None,_,(computation,w)::tl->computation,w,{resumptionswithunordered_resumptions=tl;unordered_number=unordered_number-1;}|_,None,Some_,[]->letopt_computation,opt_w,new_map=matchW.WMap.pop_optimumresumption_mapwith|None->failwith"Bug: the optimume should not be set to None"|Someres->resinopt_computation,opt_w,{resumptionswithresumptions=new_map;alt_number=alt_number-1;regular_sorting=true;}end