Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file batArray.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203(*
* BatArray - additional and modified functions for arrays.
* Copyright (C) 2005 Richard W.M. Jones (rich @ annexia.org)
* 2009 David Rajchenbach-Teller, LIFO, Universite d'Orleans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)includeArray##V>=5##modulePervasives=Stdlib(*$inject
##V>=5##module Pervasives = Stdlib
*)type'at='aarraytype'aenumerable='attype'amappable='at##V<4.2##letcreate_floatn=maken0.##V<4.2##letmake_float=create_float##V=4.2##externalmake_float:int->floatarray="caml_make_float_vect"##V=4.2##externalcreate_float:int->floatarray="caml_make_float_vect"##V>=4.3##externalcreate_float:int->floatarray="caml_make_float_vect"##V>=4.3##letmake_float=create_floatletsingletonx=[|x|](*$Qsingleton
Q.int (fun x -> let s = singleton x in s.(0) = x && length s = 1)
*)letmodifyfa=fori=0tolengtha-1dounsafe_setai(f(unsafe_getai))doneletmodifyifa=fori=0tolengtha-1dounsafe_setai(fi(unsafe_getai))done(*$T modify
let a = [|3;2;1|] in modify (fun x -> x +1) a;a = [|4;3;2|]
*)(*$T modifyi
let a = [|3;2;1|] in modifyi (fun i x -> i * x) a;a = [|0;2;2|]
*)letfold=fold_leftletfold_left_mapfinit a=letn=lengthainif n=0then(init,[||])elseletacc=refinitinletf'x=letacc',y=f!accxinacc:=acc';yinletres=mapf'ain(!acc,res)(*$T fold_left_map
fold_left_map(fun acc x-> (acc+ x, x)) 0 [|0;1;2;3|] = (6,[|0;1;2;3|])fold_left_map (fun acc x -> (acc+ x, x)) 0 [||] = (0, [||])
*)letfold_leftifxa=letr=refxinfori=0tolengtha-1dor:=f!ri(unsafe_getai)done;!r(*$Tfold_lefti
fold_lefti (fun a i x -> a +i* x) 1 [|2;4;5|] = 1+ 0+ 4 + 10
fold_lefti (fun a i x-> a + i * x) 1 [||] = 1
*)letfold_rightifax=letr=refxinfori=lengtha-1downto0dor:=fi(unsafe_getai)!rdone;!r(*$T fold_righti
fold_righti (fun i x a -> a + i* x) [|2;4;5|] 1 = 1 +0+ 4 + 10
fold_righti (fun i x a -> a +i * x) [||] 1 = 1
*)letrev_in_placexs=letn=lengthxsinletj=ref(n-1)infori=0ton/2-1do(* let c = xs.(i)in *)letc=unsafe_getxsiin(* xs.(i) <- xs.(!j); *)unsafe_setxsi(unsafe_getxs!j);(* xs.(!j) <- c; *)unsafe_setxs!jc;decrjdone(*$T rev_in_place
let a = [|1;2;3;4|] in rev_in_place a; a = [|4;3;2;1|] let a = [|1;2;3|] in rev_in_place a; a = [|3;2;1|]
let a = [||] in rev_in_place a; a=[||]
*)letrevxs=let ys=copyxsinrev_in_placeys;ys(*$Q rev
(Q.array Q.int) ~count:5 (fun l -> revl |> rev = l)
*)letfor_allpxs=letn=lengthxsinletrecloopi=ifi=nthentrueelseifp(unsafe_getxsi)thenloop(succi)elsefalseinloop0(*$T for_all
for_all (fun x -> x mod 2 = 0) [|2;4;6|]
for_all (fun x -> x mod 2 = 0) [|2;3;6|] = false for_all (fun _ -> false) [||]*)letexistspxs=letn=lengthxsinletrecloopi=ifi=nthenfalseelseifp(unsafe_getxsi)thentrueelseloop(succi)inloop0(*$T exists
exists(fun x -> x mod 2 = 0) [|1;4;5|]
exists(fun x -> x mod 2 = 0) [|1;3;5|] = false
exists (fun _ -> false) [||] = false
*)letmemaxs=letn=lengthxsinletrecloopi=ifi=nthenfalseelseifa=unsafe_getxsithentrueelseloop(succi)inloop0(*$T memmem 2 [|1;2;3|]
mem 2[||] = false
mem (ref 3) [|ref 1; ref 2; ref 3|]
*)letmemqaxs=letn=lengthxsinletrecloopi=ifi=nthenfalseelseifa==unsafe_getxsithentrueelseloop(succi)inloop0(*$T memq memq 2 [|1;2;3|]
memq 2 [||] = false
memq (ref 3) [|ref 1; ref 2;ref 3|] = false
*)letfindipxs=letn=lengthxsinletrecloopi=ifi=nthenraiseNot_foundelseifp(unsafe_getxsi)thenielseloop(succi)inloop0(*$Q findi
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int Q.bool)) (fun (a, Q.Fun(_,f)) -> \
try let index = findi f a in \
let i = ref (-1) in \
for_all (fun elt -> incr i; \
if !i < index thennot (f elt) \
else if !i = index then f elt else true)\
a \
with Not_found -> for_all (fun elt -> not (f elt)) a)
*)letfindpxs=xs.(findipxs)(*$Q find
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int Q.bool)) (fun (a, Q.Fun(_,f)) -> \
let a = map (fun x -> `a x) a in \
let f (`a x) = f x in\
try let elt = find f a in \
let past = ref false in \
for_all (fun x -> if x == elt then (past := true;f x) \
else !past || not(fx)) \
a \
with Not_found -> for_all(fun elt -> not(f elt)) a)
*)letfind_optpa=letn=lengthainletrecloopi=ifi=nthenNoneelseletx=unsafe_getaiinifpxthenSomexelseloop(succi)inloop0(*$T find_opt
find_opt (fun x -> x < 0) [||] = None
find_opt (fun x ->x< 0) [|0;1;2;3|] = None
find_opt (fun x -> x>= 3) [|0;1;2;3|] = Some 3
*)letfind_mapfa=letn=lengthainletrecloopi=ifi=nthenNoneelsematchf(unsafe_getai)with|None->loop(succi)|Some_asr->rinloop0(*$T find_map
find_map (fun x -> if x < 0 then Some x else None) [||] = None
find_map (fun x -> if x < 0 then Some x else None) [|0;-1;2|] = (Some (-1))
find_map (fun x -> if x < 0 then Some x else None) [|0;1;-2|] = (Some (-2))
*)(* Use of BitSet suggested by BrianHurt. *)letfilterpxs=letn=lengthxsin(* Use a bitset to store which elements will be in the final array. *)letbs=BatBitSet.createninfori=0ton-1doifp(unsafe_getxsi)thenBatBitSet.setbsidone;(* Allocatethefinal array and copyelementsinto it. *)letn'=BatBitSet.countbsinletj=ref0ininitn'(fun_->matchBatBitSet.next_set_bitbs!jwith|Somei->j:=i+1;unsafe_getxsi|None->(* not enough 1 bits - incorrect count? *)assertfalse)(*$Q filter
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int Q.bool)) (fun (a, Q.Fun(_,f)) -> \
let b = to_list (filter f a) in\ let b' = List.filter f (to_list a) in \
List.for_all (fun (x,y) -> x = y) (List.combine b b') \ )
*)exceptionEndofintletfold_whilepfinitxs=letacc=refinitintryletn=lengthxsinfori=0ton-1doletx=unsafe_getxsiinifp!accxthenacc:=f!accxelseraise(Endi)done;(!acc,n)withEndi->(!acc,i)(*$T fold_while
fold_while (fun _ x -> x mod 2 = 0) (+) 0 [|1;2|] = (0, 0)
fold_while (fun _ x -> x mod 2 = 1) (+) 0 [|1;2|] = (1, 1)
fold_while (fun _ x -> x < 4) (+) 0 [|1;2;3;4|] = (6, 3)
fold_while (fun _ x -> x < 4) (+) 0 [|1;2;3|] =(6, 3)
fold_while (fun _ x -> x < 4) (+) 0 [||] = (0, 0)
*)letcount_matchingpxs=letn=lengthxsinletcount=ref0infori=0ton-1doifp(unsafe_getxsi)thenincrcountdone;!count(*$T count_matching
count_matching (fun _ -> true) [||] = 0
count_matching (fun x -> x = -1) [|-1|] = 1
count_matching (fun x -> x = -1) [|-1;0;-1|]= 2
*)letfilteripxs=letn=lengthxsin(* Use a bitset to store which elements will be in the final array. *)letbs=BatBitSet.createninfori=0ton-1doifpi(unsafe_getxsi)thenBatBitSet.setbsidone;(* Allocatethefinal array and copyelementsinto it. *)letn'=BatBitSet.countbsinletj=ref0ininitn'(fun_->matchBatBitSet.next_set_bitbs!jwith|Somei->j:=i+1;unsafe_getxsi|None->(* not enough 1 bits - incorrect count? *)assertfalse)(*$Tfilteri
filteri (fun i x ->(i+x) mod 2 = 0) [|1;2;3;4;0;1;2;3|] = [|0;1;2;3|]
*)letfind_all=filter(* <=>List.partition *)letpartitionpa=letn=lengthainifn=0then([||],[||])elseletok_count=ref0inletmask=initn(funi->letpi=p(unsafe_getai)inifpithen incrok_count;pi)inletko_count=n-!ok_count inletinit=unsafe_geta0inletok=make!ok_countinitinletko=make ko_countinitinletj=ref0inletk=ref0infori=0ton-1doletx=unsafe_getaiinletpx=unsafe_getmaskiinifpxthen(unsafe_setok!jx;incrj)else(unsafe_setko!kx;incrk)done;(ok,ko)(*$Q partition
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int Q.bool)) (fun (a, Q.Fun(_,f)) -> \
let b1, b2 = partition f a in \
let b1, b2 = to_list b1, to_list b2 in \
let b1', b2' = List.partition f (to_list a) in \
List.for_all (fun (x,y) -> x= y) (List.combine b1 b1') && \
List.for_all (fun (x,y) -> x = y) (List.combine b2 b2') \
)
*)letenumxs=letrecmakestartxs=letn=lengthxsin(* inside the loop, as [make]may later be called with another array *)BatEnum.make~next:(fun()->if!start<nthenunsafe_getxs(BatRef.post_incrstart)elseraise BatEnum.No_more_elements)~count:(fun()->n-!start)~clone:(fun()->make(BatRef.copystart)xs)inmake(ref0)xs(*$Q enum
(Q.array Q.small_int) (fun a -> \
let e = enum a in \
for i = 0 to length a / 2 - 1 do\
assert (a.(i) = BatEnum.get_exn e)\
done; \
let e' = BatEnum.clone e in \
assert (BatEnum.count e = BatEnum.count e'); \
for i = length a / 2 to length a - 1 do \
assert (a.(i) = BatEnum.get_exn e && a.(i) = BatEnum.get_exn e') \
done; \
BatEnum.is_empty e && BatEnum.is_empty e' \
)
*)letbackwardsxs=letrecmakestartxs=BatEnum.make~next:(fun()->if!start>0thenunsafe_getxs(BatRef.pre_decrstart)elseraiseBatEnum.No_more_elements)~count:(fun()->!start)~clone:(fun()->make(BatRef.copystart)xs)inmake(ref(lengthxs))xs(*$Q backwards
(Q.array Q.small_int) (fun a -> \
let e = backwards a in \
let n = length a in \
for i = 0 to length a / 2 - 1 do\
assert (a.(n - 1 - i) = BatEnum.get_exn e)\
done; \
let e' = BatEnum.clone e in \
assert (BatEnum.count e = BatEnum.count e'); \
for i = length a / 2 to length a - 1 do \
assert (a.(n - 1 - i) = BatEnum.get_exn e && \
a.(n - 1 - i) = BatEnum.get_exn e') \
done; \
BatEnum.is_empty e && BatEnum.is_empty e' \
)
*)letof_enume=letn=BatEnum.countein(* This assumes, reasonably, that init traverses the array in order. *)initn(fun_i->matchBatEnum.getewith|Somex->x|None->assertfalse)letof_backwardse=of_list(BatList.of_backwardse)letrangexs=BatEnum.(--^)0(lengthxs)(*$Q range
(Q.array Q.small_int) (fun a -> \
BatEnum.equal (=) (range a) \
(enum (init (length a) (fun i -> i))))
*)letfilter_mappxs=of_enum(BatEnum.filter_mapp(enumxs))(*$Q filter_map
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int (Q.option Q.int))) \
(fun (a, Q.Fun (_,f)) -> \
let a' =filter (fun elt -> f elt <> None) a in \
let a' = map (f %> BatOption.get) a' in \
let a= filter_map f a in \
a = a' \
)
*)letiter2fa1a2=iflengtha1<>lengtha2theninvalid_arg"Array.iter2";fori=0tolengtha1-1do(* f a1.(i) a2.(i) *)f(unsafe_geta1i)(unsafe_geta2i)done(*$Q iter2
(Q.array Q.small_int) (fun a -> \
let a' = map (fun a -> a + 1) a in \
let i = ref (-1) in \
let b = make (length a) (max_int, max_int) in \
let f x1 x2 = incr i; b.(!i) <- (x1, x2) in \
let b' = map (fun a -> (a, a + 1)) a in \
iter2 f a a'; \
b = b' \
)
*)(*$T iter2
try iter2 (fun _ _ -> ()) [|1|] [|1;2;3|]; false \
withInvalid_argument _ -> true
try iter2 (fun _ _ -> ()) [|1|] [||]; false\
with Invalid_argument _ -> true
*)letiter2ifa1a2=iflengtha1<>lengtha2theninvalid_arg"Array.iter2i";fori=0tolengtha1-1do(* f i a1.(i) a2.(i) *)fi(unsafe_geta1i)(unsafe_geta2i)done(*$Q iter2i
(Q.array Q.small_int) (fun a -> \
let a' = map (fun a -> a + 1) a in \
let i = ref (-1) in \
let b = make (length a) (max_int, max_int) in \
let f idx x1 x2 = incr i; assert (!i = idx); b.(!i) <- (x1, x2) in \
let b' = map (fun a -> (a, a + 1)) a in \
iter2i f a a'; \
b = b' \
)
*)(*$T iter2i
try iter2i (fun _ _ _ -> ()) [|1|] [|1;2;3|]; false \
with Invalid_argument _ -> true
try iter2i (fun _ _ _ -> ()) [|1|] [||]; false \
with Invalid_argument _ -> true
*)##V>=4.11##letfor_all2=Array.for_all2##V<4.11##letfor_all2pxsys=##V<4.11##letn=lengthxsin##V<4.11##iflengthys<>ntheninvalid_arg"Array.for_all2";##V<4.11##letrecloopi=##V<4.11##ifi=nthentrue##V<4.11##elseifp(unsafe_getxsi)(unsafe_getysi)thenloop(succi)##V<4.11##elsefalse##V<4.11##in##V<4.11##loop0(*$T for_all2
for_all2 (=) [|1;2;3|] [|3;2;1|] = false
for_all2 (=) [|1;2;3|] [|1;2;3|]
for_all2 (<>) [|1;2;3|] [|3;2;1|] = false
try ignore (for_all2 (=) [|1;2;3|] [|1;2;3;4|]); false \
with Invalid_argument _ -> true
try ignore (for_all2 (=) [|1;2|] [||]); false \
with Invalid_argument _ -> true
*)##V>=4.11##letexists2=Array.exists2##V<4.11##letexists2pxsys=##V<4.11##letn=lengthxsin##V<4.11##iflengthys<>ntheninvalid_arg"Array.exists2";##V<4.11##letrecloopi=##V<4.11##ifi=nthenfalse##V<4.11##elseifp(unsafe_getxsi)(unsafe_getysi)thentrue##V<4.11##elseloop(succi)##V<4.11##in##V<4.11##loop0(*$T exists2
exists2 (=) [|1;2;3|] [|3;2;1|]
exists2 (<>) [|1;2;3|] [|1;2;3|] = false
try ignore (exists2 (=) [|1;2|] [|3|]); false \
with Invalid_argument _ -> true
*)letmap2fxsys=letn=lengthxsiniflengthys<>ntheninvalid_arg"Array.map2";initn(funi->f(unsafe_getxsi)(unsafe_getysi))(*$Tmap2
map2 (-) [|1;2;3|][|6;3;1|] = [|-5;-1;2|]map2 (-) [|2;4;6|] [|1;2;3|] = [|1;2;3|]
try ignore (map2 (-) [|2;4|] [|1;2;3|]); false \
with Invalid_argument _ -> true
try ignore (map2 (-) [|2;4|] [|3|]); false \
with Invalid_argument _ -> true
*)letcartesian_productab=letna=lengthainletnb=lengthbininit(na*nb)(funj->leti=j/nbin(unsafe_getai,unsafe_getb(j-i*nb)))(*$T cartesian_product
let a = cartesian_product [|1;2|] [|"a";"b"|] in \
sort Legacy.compare a; \
a = [|1,"a";1,"b"; 2,"a";2, "b" |]
*)(*$Q cartesian_product
(Q.pair (Q.list Q.small_int)(Q.list Q.small_int))(fun(la,lb) ->\
let a = of_list (List.take 5 la) and b = of_list (List.take 4 lb) in \
length (cartesian_product a b) = length a * length b)
*)letcomparecmpab=letlength_a=lengthainletlength_b=lengthbinletlength=BatInt.minlength_alength_binletrecauxi=ifi<lengththenletresult=cmp(unsafe_getai)(unsafe_getbi)inifresult=0thenaux(i+1)elseresultelseiflength_a=length_bthen0elseiflength_a<length_bthen-1else1inaux0(*$T compare
compare Legacy.compare [|1;2;3|] [|1;2|] =1
compare Legacy.compare [|1;2|] [|1;2;4|] = -1
compare Legacy.compare [|1|] [||] = 1
compareLegacy.compare [||] [||] = 0
compare Legacy.compare[|1;2|] [|1;2|] = 0
compare (fun x y -> -(Legacy.compare x y)) [|2;1|] [|1;2|] = -1
*)letprint?(first="[|")?(last="|]")?(sep="; ")print_aoutt=matchlengthtwith|0->BatInnerIO.nwriteoutfirst;BatInnerIO.nwriteoutlast|n->BatInnerIO.nwriteoutfirst;print_aout(unsafe_gett0);fori=1ton-1doBatInnerIO.nwriteoutsep;print_aout (unsafe_getti);done;BatInnerIO.nwrite out last(*$T
BatIO.to_string (print ~sep:","~first:"[" ~last:"]"BatInt.print) \
[|2;4;66|] = "[2,4,66]"
BatIO.to_string (print ~sep:"," ~first:"[" ~last:"]" BatInt.print) \
[|2|] = "[2]"
BatIO.to_string (print ~sep:"," ~first:"[" ~last:"]" BatInt.print) \
[||] = "[]"*)letreducefa=iflengtha=0theninvalid_arg"Array.reduce: empty array"elseletacc=ref(unsafe_geta0)infori=1tolengtha-1doacc:=f!acc(unsafe_getai)done;!acc(*$T reduce
reduce (+) [|1;2;3|] = 6
reduce (fun _ -> assert false) [|1|] = 1
try reduce (fun _ _ -> ()) [||]; false \ with Invalid_argument_ -> true
*)letmina=reducePervasives.minaletmaxa=reducePervasives.maxa(*$T min
min [|1;2;3|] = 1 min [|2;3;1|] = 1
*)(*$T max
max [|1;2;3|] = 3
max [|2;3;1|] = 3
*)letmin_maxa=letn=lengthainifn=0theninvalid_arg"Array.min_max: empty array"elseletmini=ref(unsafe_geta0)inlet maxi=ref(unsafe_get a0)infori=1ton-1doif(unsafe_getai)>!maxithenmaxi:=(unsafe_getai);if(unsafe_getai)<!minithenmini:=(unsafe_getai)done;(!mini,!maxi)(*$T min_max
min_max [|1|]= (1, 1)
min_max [|1;-2;10;3|] = (-2,10)
try ignore (min_max [||]); false withInvalid_argument _ -> true
*)letsum=fold_left (+)0letfsum=fold_left(+.)0.(*$T sum
sum [|1;2;3|] = 6
sum [|0|] = 0
sum [||] = 0
*)(*$T fsum
fsum [|1.0;2.0;3.0|] = 6.0
fsum [|0.0|] = 0.0
*)letkahan_sumarr=letsum=ref0.inleterr=ref0.infori=0tolengtharr-1doletx=(unsafe_getarri)-.!errinletnew_sum=!sum+.xinerr:=(new_sum-.!sum)-.x;sum:=new_sum+.0.;(* this suspicious +. 0. is addedto help the hand of the somewhat flaky unboxing optimizer; it hopefully won't be necessary anymore
in a few OCaml versions *)done;!sum+.0.(*$T kahan_sum
kahan_sum [| |] = 0.
kahan_sum [| 1.; 2. |] = 3.
let n, x = 1_000, 1.1 in \
Float.approx_equal (float n *. x) \
(kahan_sum (make n x))
*)letflengtha=float_of_int(lengtha)letavg a=(float_of_int(suma))/.(flengtha)letfavga=(fsuma)/.(flengtha);;(*$T avg
avg [|1; 2; 3|] = 2.
avg [|0|] = 0.
*)(*$T favg
favg [|1.0; 2.0; 3.0|] = 2.0
favg [|0.0|] =0.0
*)(* meant for tests, don't care about side effects being repeated
or not failing early *)letis_sorted_byfxs=letok=reftrueinfori=0tolengthxs-2dook:=!ok&&(f(unsafe_getxsi))<=(f(unsafe_getxs(i+1)))done;!ok(* TODO: Investigate whether a second array is better than pairs *)letdecorate_stable_sortfxs=letdecorated=map(funx->(fx,x))xsinlet()=stable_sort(fun(i,_)(j,_)->Pervasives.compareij)decoratedinmap(fun(_,x)->x)decorated(*$T decorate_stable_sort
decorate_stable_sort fst [|(1,2);(1,3);(0,2);(1,4)|] \
= [|(0,2);(1,2);(1,3);(1,4)|]
*)(*$Q decorate_stable_sort
(Q.pair (Q.array Q.small_int) (Q.fun1 Q.Observable.int (Q.option Q.int))) \
(fun (a, Q.Fun(_,f)) -> is_sorted_by f (decorate_stable_sort f a))
*)letdecorate_fast_sortfxs=letdecorated=map(funx->(fx,x))xsinlet()=fast_sort(fun(i,_)(j,_)->Pervasives.compareij)decoratedinmap(fun(_,x)->x)decorated(*$Q decorate_fast_sort
(Q.pair (Q.array Q.small_int)(Q.fun1 Q.Observable.int (Q.option Q.int)))\(fun (a, Q.Fun(_,f)) -> is_sorted_by f (decorate_fast_sort f a))
*)let bsearchcmparrx=letrecbsearchij=ifi>jthen`Just_afterjelseletmiddle=i+(j-i)/2in(* avoid overflow *)matchcmpx(unsafe_getarrmiddle)with|BatOrd.Eq->`Atmiddle|BatOrd.Lt->bsearchi(middle-1)|BatOrd.Gt->bsearch(middle+1)jiniflengtharr=0then`Emptyelsematch(cmp(unsafe_getarr0)x,cmp(unsafe_getarr(lengtharr-1))x)with|BatOrd.Gt,_->`All_bigger|_,BatOrd.Lt->`All_lower|_->bsearch0(lengtharr-1)(*$T bsearch bsearch BatInt.ord [|1; 2; 2; 3; 4; 10|] 3 = `At 3
bsearch BatInt.ord [|1; 2; 2; 3; 4; 10|] 5 = `Just_after 4bsearch BatInt.ord [|1; 2;5; 5; 11; 12|] 1 = `At 0
bsearchBatInt.ord [|1; 2; 5; 5; 11; 12|] 12 = `At 5
bsearch BatInt.ord [|1; 2; 2; 3; 4; 9|] 10= `All_lower
bsearch BatInt.ord [|1; 2; 2; 3; 4; 9|] 0 = `All_bigger
bsearch BatInt.ord [| |] 3 = `Empty
*)letpivot_splitcmparrx=letopenBatOrdinletn=lengtharrin(* find left edge between iand j *)letrecsearch_leftij=ifi>jthenielseletmiddle=i+(j-i)/2inmatchcmp(unsafe_getarrmiddle)xwith|Lt->search_left(middle+1)j|Gt->search_lefti(middle-1)|Eq->(* check whether [middle] istheedge, ie the leftmost index
where arr.(_) = x *)letneighbor=middle-1inifneighbor<0||cmp(unsafe_getarrneighbor)x=Ltthenmiddle(* found!*)elsesearch_leftineighbor(* go further on left*)(* find right edge, between i and j *)andsearch_right ij=ifi>jthenielseletmiddle=i+(j-i)/2inmatchcmp(unsafe_getarrmiddle)xwith|Lt->search_right(middle+1)j|Gt->search_righti(middle-1)|Eq->letneighbor=middle+1inifneighbor=n||cmp(unsafe_getarrneighbor)x=Gtthenmiddle+1(* found! *)elsesearch_rightneighborj(* go further on right *)in(search_left0(n-1),search_right 0(n-1))(*$T pivot_split
pivot_splitBatInt.ord [| |] 1 = (0, 0)
pivot_split BatInt.ord [|1;2;2;3;3;4;5|] 3 = (3,5)
pivot_split BatInt.ord [|1;1;1;2;3;3;4;5|] 1= (0,3)
pivot_split BatInt.ord [|1;2;2;3;3;4;5|] 10 = (7,7)
pivot_split BatInt.ord [|1;2;2;3;3;4;5|] 0 = (0,0)
pivot_split BatInt.ord [|2;2;2|] 2 = (0,3)
pivot_split BatInt.ord [|1;2;2;4;5|] 3 = (3,3)
*)letinsertxsxi=letlen=lengthxsinifi<0||i>lentheninvalid_arg"Array.insert: offset out of range";init(len+1)(funj->ifj<ithenunsafe_getxsjelseifj>ithenunsafe_getxs(j-1)elsex)(*$T insert
insert [|1;2;3|] 4 0 = [|4;1;2;3|]
insert [|1;2;3|]4 3 = [|1;2;3;4|] insert [|1;2;3|] 4 2 = [|1;2;4;3|]
try ignore (insert [|1;2;3|] 4 100); false \
with Invalid_argument _ -> true
try ignore (insert [|1;2;3|] 4 (-40)); false \
with Invalid_argument _ -> true
*)letremove_atisrc=letx=src.(i)in(* keep the bound check in there *)letn=lengthsrcinletdst=make(n-1)xinblitsrc0dst0i;blit src(i+1)dsti(n-i-1);dst(*$T remove_at
try remove_at 0 [||] = [|1|]\
with Invalid_argument _ -> true
remove_at 0 [|1;2;3|] = [|2;3|]
remove_at 1 [|1;2;3|]= [|1;3|]
remove_at 2 [|1;2;3|] = [|1;2|]
try remove_at 3 [|1;2;3|] = [|1|]\ with Invalid_argument _ ->true
*)(* helper function; only works for arrays of equal length *)leteq_elementseq_elta1a2=for_all2eq_elta1a2(* helperfunction to compare arrays *)letrecord_auxeq_eltia1a2=letopenBatOrdinifi>=lengtha1thenEqelsematcheq_elt(unsafe_geta1i)(unsafe_geta2i)with|(Lt|Gt)asres->res|Eq->ord_auxeq_elt(i+1)a1a2letord_elementseq_elta1a2=ord_aux eq_elt0a1a2letequaleqa1a2=BatOrd.bin_eqBatInt.equal(lengtha1)(lengtha2)(eq_elementseq)a1a2(*$T equal
equal (=) [|1;2;3|] [|1;2;3|]
not (equal (=) [|1;2;3|] [|1;2;3;4|])
not (equal (=) [|1;2;3;4|] [|1;2;3|])
equal (=) [||] [||]
equal (<>) [|1;2;3|] [|2;3;4|]
not (equal (<>) [|1;2;3|] [|3;2;1|])
*)letordord_elta1a2=BatOrd.bin_ordBatInt.ord(lengtha1)(lengtha2)(ord_elementsord_elt)a1a2(*$T ord
ord BatInt.ord [|2|] [|1;2|] = BatOrd.Lt
ord BatInt.ord [|1;1|] [|2|] = BatOrd.Gt
ord BatInt.ord [|1;1;1|] [|1;1;2|] = BatOrd.Lt
ord BatInt.ord [|1;1;1|] [|1;1;1|] = BatOrd.Eq
*)letshuffle?statea=BatInnerShuffle.array_shuffle?statea(*$T shuffle
let s = Random.State.make [|11|] in \
let a =[|1;2;3;4;5;6;7;8;9|] in \
shuffle ~state:sa; \
let ocaml_version =int_of_string (String.make 1 Sys.ocaml_version.[0]) in \
a= if ocaml_version < 5 then \
[|7; 2; 9; 5; 3; 6; 4; 1; 8|] else \
[|1; 7; 4; 9; 5; 2; 8; 6; 3|]
let b = [||] in \
shuffle b; \
b = [||]
*)(* equivalent of List.split *)letsplita=letn=lengthainifn=0then([||],[||])elseletl,r=unsafe_get a0inletleft=makenlinletright=makenrinfori=1ton-1doletl,r=unsafe_getaiinunsafe_setleftil;unsafe_setrightirdone;(left,right)(*$T split
split [||] = ([||], [||])
split [|(1,2);(3,4);(5,6)|] = ([|1;3;5|], [|2;4;6|])
*)letcombineab=letm=lengthainletn=lengthbinifm<>ntheninvalid_arg "Array.combine";map2(funxy->(x,y))ab(*$T combine
combine [||] [||] = [||] try combine [|1;2;3|] [||] = [||] with Invalid_argument _ -> true
combine [|1;2;3|] [|4;5;6|] = [|(1,4);(2,5);(3,6)|]
*)module Incubator =structmoduleEq(T:BatOrd.Eq)=structtypet=T.tarrayleteq=equalT.eqendmoduleOrd(T:BatOrd.Ord)=structtypet=T.tarrayletord=ordT.ordendendletleftalen=iflen>=lengthathenaelsesuba0lenletrightalen=letalen=lengthainiflen>=alenthenaelsesuba(alen-len)lenletheadapos=leftaposlettailapos=letalen=lengthainifpos>=alenthen[||]elsesubapos(alen-pos)(*$= left & ~printer:(IO.to_string (print Int.print))
(left [|1;2;3|] 1) [|1|]
(left [|1;2|] 3) [|1;2|]
(left [|1;2;3|] 3) [|1;2;3|]
(left [|1;2;3|] 10)[|1;2;3|]
(left [|1;2;3|] 0) [||]
*)(*$= right & ~printer:(IO.to_string (print Int.print))
(right [|1;2;3|] 1) [|3|]
(right [|1;2|] 3) [|1;2|]
(right [|1;2;3|] 3) [|1;2;3|]
(right [|1;2;3|] 10) [|1;2;3|]
(right [|1;2;3|] 0) [||]
*)(*$= tail & ~printer:(IO.to_string (print Int.print))
(tail [|1;2;3|] 1) [|2;3|]
[||] (tail [|1;2;3|] 10)
(tail [|1;2;3|] 0) [|1;2;3|]
*)(*$= head & ~printer:(IO.to_string (print Int.print))
(head [|1;2;3|] 1) [|1|]
(head [|1;2;3|] 10) [|1;2;3|]
(head [|1;2;3|] 0) [||]
*)moduleCap=struct(** Implementation note: in [('a, 'b) t], ['b] serves only as
a phantom type, to mark which operations are only legitimate on
readable arrays or writeable arrays.*)type('a,'b)t='aarrayconstraint'b=[<`Read|`Write]externalof_array:'aarray->('a,_)t="%identity"externalto_array:('a,[`Read|`Write])t->'aarray="%identity"external read_only:('a,[>`Read])t->('a,[`Read])t="%identity"external write_only:('a,[>`Write])t->('a,[`Write])t="%identity"externallength:('a,[>])t->int="%array_length"externalget:('a,[>`Read])t->int->'a="%array_safe_get"externalset:('a,[>`Write])t->int ->'a->unit="%array_safe_set"externalmake:int->'a->('a,_)t="caml_make_vect"externalcreate:int->'a->('a,_)t="caml_make_vect"##V>=4.2##externalmake_float:int->(float,_)t="caml_make_float_vect"##V<4.2##letmake_floatn=maken0.letinit=initletmake_matrix=make_matrixletcreate_matrix=make_matrixletiter=iterletmap =mapletfilter=filterletfilter_map=filter_mapletcount_matching=count_matchingletiteri=iteriletmapi=mapiletmodify=modifyletmodifyi=modifyiletfold_left=fold_leftletfold=fold_leftletfold_left_map=fold_left_mapletfold_right=fold_rightletfold_while=fold_whileletiter2=iter2letiter2i =iter2iletfor_all=for_alllet exists=existsletfind=findletfind_opt=find_optletfind_map=find_mapletmem=memletmemq=memqletfindi=findiletfind_all=find_allletpartition =partitionletrev=revletrev_in_place=rev_in_placeletappend=appendletconcat=concatletsub=subletcopy=copyletfill=fillletblit=blitletenum=enumletof_enum=of_enumletbackwards=backwardsletof_backwards=of_backwardsletto_list=to_listletsplit =splitletcombine=combineletpivot_split=pivot_splitletof_list=of_listletsort=sortletstable_sort=stable_sortletfast_sort=fast_sortletcompare=compareletprint=printletord=ordlet equal=equalexternalunsafe_get :('a,[>`Read])t->int->'a="%array_unsafe_get"externalunsafe_set:('a,[>`Write])t-> int->'a-> unit="%array_unsafe_set"moduleLabels=structletiniti~f=initifletcreatelen~init=createleninitletmake=createletmake_matrix~dimx~dimyx=make_matrixdimxdimyxletcreate_matrix=make_matrixletsuba~pos~len=subaposlenlet filla~pos~lenx=fillaposlenxletblit~src~src_pos~dst~dst_pos~len=blitsrcsrc_posdstdst_poslenletiter~fa=iterfaletmap~fa=mapfaletiteri~fa=iterifaletmapi ~fa=mapifaletmodify~fa=modifyfaletmodifyi~fa=modifyifaletfold_left~f~inita=fold_leftfinitalet fold_left_map~f~inita=fold_left_mapfinitaletfold=fold_leftletfold_right~fa~init=fold_rightfainitletfold_while~p~f~inita=fold_whilepfinitaletsort~cmpa=sortcmpaletstable_sort~cmpa=stable_sort cmpaletfast_sort~cmpa=fast_sortcmpaletiter2~fab=iter2fabletexists~fa=existsfaletfor_all~fa=for_allfaletiter2i~fab=iter2ifabletfind~fa=findfaletfind_opt~fa=find_optfaletfind_map~fa=find_mapfaletfilter~fa=filterfaletfilter_map~fa=filter_mapfaletcount_matching~fa=count_matching faendmodule Exceptionless =structletfindfe=trySome(find fe)withNot_found->Noneletfindife=trySome(findife)withNot_found->NoneendendmoduleExceptionless=structletfindfe=trySome(findfe)withNot_found->Noneletfindife=trySome(findife)withNot_found->NoneendmoduleLabels=structletiniti~f=initifletcreatelen~init=makeleninitletmake=createletmake_matrix~dimx~dimyx=make_matrixdimxdimyxletcreate_matrix =make_matrixletsuba~pos~len=subaposlenletfilla~pos~lenx=fillaposlenxlet blit~src~src_pos ~dst~dst_pos~len=blitsrcsrc_posdstdst_poslenletiter~fa=iterfaletmap~fa=mapfaletiteri~fa=iterifaletmapi~fa=mapifaletmodify~fa=modifyfaletmodifyi~fa=modifyifaletfold_left~f~inita=fold_leftfinitaletfold_left_map~f~inita=fold_left_mapfinitaletfold=fold_leftletfold_right~fa~init=fold_rightfainitletfold_while~p~f~inita=fold_whilepfinitaletsort~cmpa=sortcmpaletstable_sort~cmpa=stable_sortcmpaletfast_sort~cmpa=fast_sortcmpaletiter2~fab=iter2fabletexists~fa=existsfaletfor_all ~fa=for_allfaletiter2i~fab=iter2ifabletfind~fa=findfaletfind_opt~fa=find_optfaletfind_map~fa=find_mapfaletfindi~fe=findifeletfilter~fa=filterfaletfilter_map~fa=filter_mapfaletcount_matching~fa=count_matchingfamoduleLExceptionless=structincludeExceptionlessletfind~fe=findfeletfindi~fe=findifeendend