From ff53571a3be87653877404240d4444bf09487230 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 9 Mar 2017 21:21:44 +0100 Subject: [PATCH] add `CCList.{cartesian_product,map_product_l}` --- src/core/CCList.ml | 42 ++++++++++++++++++++++++++++++++++++++++-- src/core/CCList.mli | 20 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/core/CCList.ml b/src/core/CCList.ml index d5bb6fad..abb44b36 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -277,8 +277,8 @@ let fold_product f acc l1 l2 = (fun acc x1 -> List.fold_left (fun acc x2 -> f acc x1 x2) - acc l2 - ) acc l1 + acc l2) + acc l1 let diagonal l = let rec gen acc l = match l with @@ -329,6 +329,44 @@ let pure = return let (<*>) funs l = product (fun f x -> f x) funs l +let cartesian_product l = + (* [left]: elements picked so far + [right]: sets to pick elements from + [acc]: accumulator for the result, to pass to continuation + [k]: continuation *) + let rec prod_rec left right k acc = match right with + | [] -> k acc (List.rev left) + | l1 :: tail -> + List.fold_left + (fun acc x -> prod_rec (x::left) tail k acc) + acc l1 + in + prod_rec [] l (fun acc l' -> l' :: acc) [] + +(*$inject + let cmp_lii_unord l1 l2 : bool = + List.sort CCOrd.compare l1 = List.sort CCOrd.compare l2 +*) + +(*$= & ~printer:Q.Print.(list (list int)) ~cmp:cmp_lii_unord + [[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]] \ + (cartesian_product [[1;2];[3];[4;5;6]]) + [] (cartesian_product [[1;2];[];[4;5;6]]) + [[]] (cartesian_product []) + [[1;3;4;5;6];[2;3;4;5;6]] \ + (cartesian_product [[1;2];[3];[4];[5];[6]]) +*) + +(* cartesian product of lists of lists *) +let map_product_l f l = + let l = List.map f l in + cartesian_product l + +(*$Q + Q.(list_of_size Gen.(1--4) (list_of_size Gen.(0--4) small_int)) (fun l-> \ + cmp_lii_unord (cartesian_product l) (map_product_l CCFun.id l)) +*) + let sorted_merge ?(cmp=Pervasives.compare) l1 l2 = let rec recurse cmp acc l1 l2 = match l1,l2 with | [], _ -> List.rev_append acc l2 diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 3d5a316b..360a0687 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -83,6 +83,26 @@ val product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t val fold_product : ('c -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c (** Fold on the cartesian product *) +val cartesian_product : 'a t t -> 'a t t +(** + For example: + {[ + # cartesian_product [[1;2];[3];[4;5;6]] = + [[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]];; + # cartesian_product [[1;2];[];[4;5;6]] = [];; + # cartesian_product [[1;2];[3];[4];[5];[6]] = + [[1;3;4;5;6];[2;3;4;5;6]];; + ]} + invariant: [cartesian_product l = map_product id l]. + @since NEXT_RELEASE *) + +val map_product_l : ('a -> 'b list) -> 'a list -> 'b list list +(** [map_product_l f l] maps each element of [l] to a list of + objects of type ['b] using [f]. + We obtain [[l1;l2;…;ln]] where [length l=n] and [li : 'b list]. + Then, it returns all the ways of picking exactly one element per [li]. + @since NEXT_RELEASE *) + val diagonal : 'a t -> ('a * 'a) t (** All pairs of distinct positions of the list. [list_diagonal l] will return the list of [List.nth i l, List.nth j l] if [i < j]. *)