123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124(*****************************************************************************)(* *)(* MIT License *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)letfind_and_remove_optflist=letrecauxacc=function|[]->None|x::xs->iffxthenSome(x,List.revacc@xs)elseaux(x::acc)xsinaux[]listletfind_and_removeflist=matchfind_and_remove_optflistwithNone->raiseNot_found|Somex->xletfind2_and_removef1f2list=matchfind_and_remove_optf1listwith|None->find_and_removef2list|Somex->xletrecsplit_last=function|[]->assertfalse|[x]->([],x)|x::xs->letxs,last=split_lastxsin(x::xs,last)letsplit_first=function[]->assertfalse|x::xs->(x,xs)(* TODO: implement this function in O(n) complexity *)letlist_intersection~equall1l2=List.fold_left(funaccx->ifList.exists(equalx)l1thenx::accelseacc)[]l2(* [complete ~n acc l] moves elements from [l] to [acc] until
[acc] contains exactly [n] elements, it returns two lists
corresponding to the updated [acc] and [l] respectively. *)letreccomplete~nacc=function|[]->(acc,[])|h::t->letr=List.compare_length_withaccninifr>0thenassertfalseelseifr=0then(acc,h::t)elsecomplete~n(acc@[h])tletrev_first_n~nl=letrecaux(acc,k)=function|[]->acc|h::t->ifk=nthenaccelseaux(h::acc,succk)tinaux([],0)lletpermute_listpermutationl=letl=Array.of_listlinList.map(funj->l.(j))permutationletrecis_identity_perm?(cnt=0)permutation=matchpermutationwith|[]->true|x::xs->x=cnt&&is_identity_perm~cnt:(cnt+1)xs(* Given two lists [l1] and [l2], it returns a permutation [p] of [l1] such that
for all i: l2.(i) = l1.(p i) OR l2.(i) < 0 OR l1.(p i) < 0.
(Where a permutation is modeled as a list of integers). *)letadaptl1l2=(* return the identity if they are already compatible *)ifList.for_all2(funx1x2->x1=x2||x1<0||x2<0)l1l2thenSome(List.init(List.lengthl1)Fun.id)elseletcommon=list_intersection~equal:(=)l1l2intryletperm,_=List.fold_left(fun(perm,pending)y->letequals_y(_,x)=x=yinletis_free(_,x)=x<0inletis_unrelated(_,x)=x>=0&&(not@@List.memxcommon)inletx,pending=ify>=0thenifList.memy(List.mapsndpending)thenfind_and_removeequals_ypendingelsefind_and_removeis_freependingelsefind2_and_removeis_unrelatedis_freependingin(perm@[fstx],pending))([],List.mapi(funix->(i,x))l1)l2inSomepermwithNot_found->Noneletlist_subnl=letrecauxkaccl=ifk=nthenList.revaccelseaux(k+1)(List.hdl::acc)(List.tll)inaux0[]lletshuffle_list?seedl=(matchseedwithNone->()|Somei->Random.initi);List.rev_map(funx->(Random.bits(),x))l|>List.sort(fun(i,_)(j,_)->Int.compareij)|>List.rev_mapsnd