* Cartesian product @ 2009-07-30 17:56 Ligia Nistor 2009-07-30 18:46 ` [Caml-list] " Peng Zang ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Ligia Nistor @ 2009-07-30 17:56 UTC (permalink / raw) To: caml-list [-- Attachment #1: Type: text/plain, Size: 185 bytes --] Hi, Is there an already implemented way of doing the Cartesian product of 2 sets in OCaml? My sets are of type Set.Make(Types), where Types is a module I have defined. Thanks, Ligia [-- Attachment #2: Type: text/html, Size: 207 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 17:56 Cartesian product Ligia Nistor @ 2009-07-30 18:46 ` Peng Zang 2009-07-30 18:53 ` Peng Zang 2009-07-30 20:22 ` Brian Hurt 2009-07-30 21:26 ` [Caml-list] " Damien Guichard 2 siblings, 1 reply; 8+ messages in thread From: Peng Zang @ 2009-07-30 18:46 UTC (permalink / raw) To: caml-list; +Cc: Ligia Nistor -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Not that I know of. But you can use this general implementation. It assumes you have Enum (from Batteries, and ExtLib before). The (~~) prefix operator is "Obj.magic". Peng (* makes the cross product of the given array of enumerations *) let crossproductM enums initcount = let numenums = Array.length enums in let clean = Array.map clone enums in let initstate = enums in let rec cpmk cur curcount = let reseti i = cur.(i) <- clone clean.(i) in let tick () = let rec tick_aux place = if place >= numenums then () else let ple = cur.(place) in ignore (get ple); if is_empty ple then ( reseti place; tick_aux (place + 1) ) in tick_aux 0; decr curcount in let get () = Array.init numenums (fun i -> Option.get (peek cur.(i))) in let nx () = match !curcount with | 0 -> raise No_more_elements | 1 -> decr curcount; get () | x -> assert (x >= 0); let ans = get () in tick (); ans in let ct () = !curcount in let cl () = cpmk (Array.init numenums (fun i -> clone cur.(i))) (ref !curcount) in make nx ct cl in ( if initcount == 0 then empty () else cpmk initstate (ref initcount) ) let crossproduct enums = let copy = Array.copy enums in let initcount = Array.fold_left (fun acc e -> count e * acc) 1 copy in crossproductM copy initcount let cross2 (t1:'a t) (t2:'b t) : ('a * 'b) t = ~~(crossproduct [|~~t1; ~~t2|]) let cross3 (t1:'a t) (t2:'b t) (t3:'c t) : ('a * 'b * 'c) t = ~~(crossproduct [|~~t1; ~~t2; ~~t3|]) On Thursday 30 July 2009 01:56:50 pm Ligia Nistor wrote: > Hi, > > Is there an already implemented way of doing the Cartesian product of 2 > sets in OCaml? My sets are of type Set.Make(Types), where Types is a module > I have defined. > > Thanks, > > Ligia -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.7 (GNU/Linux) iD8DBQFKceqXfIRcEFL/JewRAnM5AKC3dnxh9uWl7kdRBKW68koS1f3dhACgxau4 ubBf3OXzaxkMeU3Cb848lJY= =XZ4Q -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 18:46 ` [Caml-list] " Peng Zang @ 2009-07-30 18:53 ` Peng Zang 2009-07-30 20:08 ` Erick Matsen 0 siblings, 1 reply; 8+ messages in thread From: Peng Zang @ 2009-07-30 18:53 UTC (permalink / raw) To: caml-list; +Cc: Ligia Nistor -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I really should provide a bit more context. It's a general implementation for crossing [Enum.t]s. Eg. let a = List.enum [1;2;3;4] let b = List.enum ['a'; 'b'; 'c'] let c = cross2 a b yields [(1,'a'); (2,'a'); (3,'a'); (4,'a'); (1,'b'); ..] There are implementations for converting Set to Enum in the same library(s) that provide Enum. Peng On Thursday 30 July 2009 02:46:41 pm Peng Zang wrote: > Not that I know of. But you can use this general implementation. It > assumes you have Enum (from Batteries, and ExtLib before). The (~~) prefix > operator is "Obj.magic". > > > Peng > > > (* makes the cross product of the given array of enumerations *) > let crossproductM enums initcount = > let numenums = Array.length enums in > let clean = Array.map clone enums in > let initstate = enums in > > let rec cpmk cur curcount = > let reseti i = cur.(i) <- clone clean.(i) in > > let tick () = > let rec tick_aux place = > if place >= numenums then () > else > let ple = cur.(place) in > ignore (get ple); > if is_empty ple then ( > reseti place; > tick_aux (place + 1) > ) > in tick_aux 0; decr curcount in > > let get () = Array.init numenums (fun i -> Option.get (peek cur.(i))) > in > > let nx () = match !curcount with > > | 0 -> raise No_more_elements > | 1 -> decr curcount; get () > | x -> assert (x >= 0); let ans = get () in tick (); ans in > > let ct () = !curcount in > > let cl () = cpmk (Array.init numenums (fun i -> clone cur.(i))) > (ref !curcount) in > make nx ct cl > in > ( if initcount == 0 then empty () > else cpmk initstate (ref initcount) ) > > > let crossproduct enums = > let copy = Array.copy enums in > let initcount = Array.fold_left (fun acc e -> count e * acc) 1 copy in > crossproductM copy initcount > > > let cross2 (t1:'a t) (t2:'b t) : ('a * 'b) t = > ~~(crossproduct [|~~t1; ~~t2|]) > > let cross3 (t1:'a t) (t2:'b t) (t3:'c t) : ('a * 'b * 'c) t = > ~~(crossproduct [|~~t1; ~~t2; ~~t3|]) > > On Thursday 30 July 2009 01:56:50 pm Ligia Nistor wrote: > > Hi, > > > > Is there an already implemented way of doing the Cartesian product of 2 > > sets in OCaml? My sets are of type Set.Make(Types), where Types is a > > module I have defined. > > > > Thanks, > > > > Ligia -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.7 (GNU/Linux) iD8DBQFKcew1fIRcEFL/JewRArLiAKCYGbfEHY5igi0IlM6f71tNAL2OqACeMUPR qR8nC+F5QNRgaX19gSVtMsA= =8JeB -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 18:53 ` Peng Zang @ 2009-07-30 20:08 ` Erick Matsen 0 siblings, 0 replies; 8+ messages in thread From: Erick Matsen @ 2009-07-30 20:08 UTC (permalink / raw) To: caml-list Hello Ligia--- The following code takes cartesian products of lists: let listListPrepend x ll = List.map (fun l -> x :: l) ll let rec cartesianProduct = function | aList :: listList -> let prev = cartesianProduct listList in List.flatten ( List.map (fun x -> listListPrepend x prev) aList) | [] -> [[]] and could be easily adapted to the case of sets. Erick On Thu, Jul 30, 2009 at 11:53 AM, Peng Zang<peng.zang@gmail.com> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > I really should provide a bit more context. It's a general implementation for > crossing [Enum.t]s. Eg. > > let a = List.enum [1;2;3;4] > let b = List.enum ['a'; 'b'; 'c'] > > let c = cross2 a b > > yields [(1,'a'); (2,'a'); (3,'a'); (4,'a'); (1,'b'); ..] > > > There are implementations for converting Set to Enum in the same library(s) > that provide Enum. > > Peng > > On Thursday 30 July 2009 02:46:41 pm Peng Zang wrote: >> Not that I know of. But you can use this general implementation. It >> assumes you have Enum (from Batteries, and ExtLib before). The (~~) prefix >> operator is "Obj.magic". >> >> >> Peng >> >> >> (* makes the cross product of the given array of enumerations *) >> let crossproductM enums initcount = >> let numenums = Array.length enums in >> let clean = Array.map clone enums in >> let initstate = enums in >> >> let rec cpmk cur curcount = >> let reseti i = cur.(i) <- clone clean.(i) in >> >> let tick () = >> let rec tick_aux place = >> if place >= numenums then () >> else >> let ple = cur.(place) in >> ignore (get ple); >> if is_empty ple then ( >> reseti place; >> tick_aux (place + 1) >> ) >> in tick_aux 0; decr curcount in >> >> let get () = Array.init numenums (fun i -> Option.get (peek cur.(i))) >> in >> >> let nx () = match !curcount with >> >> | 0 -> raise No_more_elements >> | 1 -> decr curcount; get () >> | x -> assert (x >= 0); let ans = get () in tick (); ans in >> >> let ct () = !curcount in >> >> let cl () = cpmk (Array.init numenums (fun i -> clone cur.(i))) >> (ref !curcount) in >> make nx ct cl >> in >> ( if initcount == 0 then empty () >> else cpmk initstate (ref initcount) ) >> >> >> let crossproduct enums = >> let copy = Array.copy enums in >> let initcount = Array.fold_left (fun acc e -> count e * acc) 1 copy in >> crossproductM copy initcount >> >> >> let cross2 (t1:'a t) (t2:'b t) : ('a * 'b) t = >> ~~(crossproduct [|~~t1; ~~t2|]) >> >> let cross3 (t1:'a t) (t2:'b t) (t3:'c t) : ('a * 'b * 'c) t = >> ~~(crossproduct [|~~t1; ~~t2; ~~t3|]) >> >> On Thursday 30 July 2009 01:56:50 pm Ligia Nistor wrote: >> > Hi, >> > >> > Is there an already implemented way of doing the Cartesian product of 2 >> > sets in OCaml? My sets are of type Set.Make(Types), where Types is a >> > module I have defined. >> > >> > Thanks, >> > >> > Ligia > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v2.0.7 (GNU/Linux) > > iD8DBQFKcew1fIRcEFL/JewRArLiAKCYGbfEHY5igi0IlM6f71tNAL2OqACeMUPR > qR8nC+F5QNRgaX19gSVtMsA= > =8JeB > -----END PGP SIGNATURE----- > > _______________________________________________ > Caml-list mailing list. Subscription management: > http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list > Archives: http://caml.inria.fr > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 17:56 Cartesian product Ligia Nistor 2009-07-30 18:46 ` [Caml-list] " Peng Zang @ 2009-07-30 20:22 ` Brian Hurt 2009-07-30 21:54 ` Ligia Nistor 2009-07-30 21:26 ` [Caml-list] " Damien Guichard 2 siblings, 1 reply; 8+ messages in thread From: Brian Hurt @ 2009-07-30 20:22 UTC (permalink / raw) To: Ligia Nistor; +Cc: caml-list On Thu, 30 Jul 2009, Ligia Nistor wrote: > Hi, > > Is there an already implemented way of doing the Cartesian product of 2 sets > in OCaml? My sets are of type Set.Make(Types), where Types is a module I > have defined. The biggest problem with implementing the cartesian product is that the type t*t is not the same as the type t. But it's still not that hard. Say you have: module Type : sig type t;; val compare : t -> t -> int;; end = struct ... end;; module TypeSet = Set.Make(Type);; Then you could do: module TypeType = struct type t = Type.t * Type.t;; let compare (x1, x2) (y1, y2) = let r = Type.compare x1 y1 in if r == 0 then Type.compare x2 y2 else r ;; end;; module TypeTypeSet = Set.Make(TypeType);; As a side note, you could simply use Pervasives.compare there instead of the code I wrote, but that wouldn't necessarily preserve the ordering given by Type.compare. Once you have the set module for the cartesian products, you can use nested folds to create one: let cartesian_product s1 s2 = let f x y t = TypeTypeSet.add (x, y) t in let g x t = TypeSet.fold (f x) s2 t in TypeSet.fold g s1 TypeTypeSet.empty ;; Hope this helps. Brian ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 20:22 ` Brian Hurt @ 2009-07-30 21:54 ` Ligia Nistor 2009-07-31 16:23 ` Michael Ekstrand 0 siblings, 1 reply; 8+ messages in thread From: Ligia Nistor @ 2009-07-30 21:54 UTC (permalink / raw) To: Brian Hurt; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 1763 bytes --] Thanks for the reply. This is how I thought of doing it, but in the module TypeType, type t should be a list of types( the list has to be ref, so that it can change its length). This way, you can do the cartesian product of an arbitrary number of sets, not only of 2. Ligia On Thu, Jul 30, 2009 at 9:22 PM, Brian Hurt <bhurt@spnz.org> wrote: > > > On Thu, 30 Jul 2009, Ligia Nistor wrote: > > Hi, >> >> Is there an already implemented way of doing the Cartesian product of 2 >> sets >> in OCaml? My sets are of type Set.Make(Types), where Types is a module I >> have defined. >> > > The biggest problem with implementing the cartesian product is that the > type t*t is not the same as the type t. But it's still not that hard. Say > you have: > > module Type : sig > type t;; > val compare : t -> t -> int;; > end = struct > ... > end;; > > module TypeSet = Set.Make(Type);; > > Then you could do: > > module TypeType = struct > type t = Type.t * Type.t;; > let compare (x1, x2) (y1, y2) = > let r = Type.compare x1 y1 in > if r == 0 then > Type.compare x2 y2 > else > r > ;; > end;; > > module TypeTypeSet = Set.Make(TypeType);; > > As a side note, you could simply use Pervasives.compare there instead of > the code I wrote, but that wouldn't necessarily preserve the ordering given > by Type.compare. > > Once you have the set module for the cartesian products, you can use nested > folds to create one: > > let cartesian_product s1 s2 = > let f x y t = TypeTypeSet.add (x, y) t in > let g x t = TypeSet.fold (f x) s2 t in > TypeSet.fold g s1 TypeTypeSet.empty > ;; > > Hope this helps. > > Brian > > [-- Attachment #2: Type: text/html, Size: 2415 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Cartesian product 2009-07-30 21:54 ` Ligia Nistor @ 2009-07-31 16:23 ` Michael Ekstrand 0 siblings, 0 replies; 8+ messages in thread From: Michael Ekstrand @ 2009-07-31 16:23 UTC (permalink / raw) To: caml-list Ligia Nistor wrote: > Thanks for the reply. This is how I thought of doing it, but in the module > TypeType, type t should be a list of types( the list has to be ref, so that > it can change its length). This way, you can do the cartesian product of an > arbitrary number of sets, not only of 2. That would be possible (use a type of Type.t list), but the resulting set types would have a static typing hole: you would not be guaranteed that all elements would have the same length. Another way to do it would be to have a Product functor, like so: module Product = functor (T1: Set.ORDERED_TYPE) -> functor (T2: Set.ORDERED_TYPE) -> struct type t = T1.t * T2.t let compare (a1,b1) (a2,b2) = let r = T1.compare a1 a2 in if r = 0 then T2.compare b1 b2 else r end Then you can create a 2-ary product set type: module Set2 = Set.Make(Product(Type)(Type)) and build further sets by constructing products of products: module Set3 = Set.Make(Product(Product(Type))(Type))) That would allow you to construct arbitrarily high-dimensional product set types that still remain type-safe. - Michael ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Caml-list] Cartesian product 2009-07-30 17:56 Cartesian product Ligia Nistor 2009-07-30 18:46 ` [Caml-list] " Peng Zang 2009-07-30 20:22 ` Brian Hurt @ 2009-07-30 21:26 ` Damien Guichard 2 siblings, 0 replies; 8+ messages in thread From: Damien Guichard @ 2009-07-30 21:26 UTC (permalink / raw) To: caml-list [-- Attachment #1: Type: text/plain, Size: 1501 bytes --] Hi Ligia Nistor, Supposing you want to implement the Cartesian product of 2 sets, and supposing you implement sets as (balanced) sorted binary trees, here is how i would do that : implement a functor that, given x:A and a set B, maps B to a new set of pairs (x,y), y:B this functor transforms each item of A into a new balanced tree if you map this functor to A the result is a tree of trees supposing you can merge all these trees you then get the cartesian product howewer you don't actually need the tree of trees, all you need is the merged result thus, instead of doing (3) you apply the (1) functor as f argument of the following flatten_map function : type 'a set = tree option and tree = {left: 'a set; item: 'a; right: 'a set} let rec flatten_map f p = function | None -> p | Some n -> union (flatten_map f p n.left) (flatten_map f (f n.item) n.right) let flatten_map f = flatten_map f None It seems to me that my solution gives you the cartesian product as an ordered (balanced) binary tree set in optimal time. - damien Damien Guichard 2009-07-30 En réponse au message de : Ligia Nistor du : 2009-07-30 19:56:57 À : caml-list@yquem.inria.fr CC : Sujet : [Caml-list] Cartesian product Hi, Is there an already implemented way of doing the Cartesian product of 2 sets in OCaml? My sets are of type Set.Make(Types), where Types is a module I have defined. Thanks, Ligia [-- Attachment #2: Type: text/html, Size: 5253 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2009-07-31 16:23 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-07-30 17:56 Cartesian product Ligia Nistor 2009-07-30 18:46 ` [Caml-list] " Peng Zang 2009-07-30 18:53 ` Peng Zang 2009-07-30 20:08 ` Erick Matsen 2009-07-30 20:22 ` Brian Hurt 2009-07-30 21:54 ` Ligia Nistor 2009-07-31 16:23 ` Michael Ekstrand 2009-07-30 21:26 ` [Caml-list] " Damien Guichard
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox