<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<META content="MSHTML 6.00.2900.2963" name=GENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=#ffffff>
<DIV><FONT face="Courier New" size=2>If you use the appropriate tools,
cartesian-product can be written in one single line of 93 characters,
unnecessary spaces included.</FONT></DIV>
<DIV><FONT face="Courier New" size=2></FONT> </DIV>
<DIV>((((lambda(x)((((((x x)x)x)x)x)x))<BR> (lambda(x)(lambda(y)(x(x
y)))))<BR> (lambda(x)(write x)x))<BR> "greetings, Jos") </DIV>
<BLOCKQUOTE
style="PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
<DIV style="FONT: 10pt arial">----- Original Message ----- </DIV>
<DIV
style="BACKGROUND: #e4e4e4; FONT: 10pt arial; font-color: black"><B>From:</B>
<A title=albert.neu@gmail.com href="mailto:albert.neu@gmail.com">Albert
Neumüller</A> </DIV>
<DIV style="FONT: 10pt arial"><B>To:</B> <A title=plt-scheme@list.cs.brown.edu
href="mailto:plt-scheme@list.cs.brown.edu">plt-scheme@list.cs.brown.edu</A>
</DIV>
<DIV style="FONT: 10pt arial"><B>Sent:</B> Tuesday, September 19, 2006 1:49
PM</DIV>
<DIV style="FONT: 10pt arial"><B>Subject:</B> [plt-scheme] Scheme efficiency
guidelines (or: the fastest way tocalc a cartesian product)</DIV>
<DIV><BR></DIV>Hello!<BR><BR>An invitation:<BR>How would you write the fastest
possible scheme program that computes the cartesian product of a
set?<BR><BR>Example:<BR>=================<BR><BR>set1 = {0,
1}<BR><BR>then<BR><BR>cartesian_product = {(0, 0), (0, 1), (1, 0), (1, 1)}
<BR><BR><BR>Note:<BR>If set1 has n elements (cardinality 2), then
cartesian_product will have 2^n pairs (cardinality 2^n)<BR><BR><BR><BR>In
Scheme<BR>~~~~~~~~~~<BR><BR>(define-struct onepair (left
right))<BR><BR><BR>(define set1 (build-list 2 identity)) = (list 0 1)
<BR><BR>(cartesian-product set1)<BR>=<BR>(list (make-onepair 0
0)<BR> (make-onepair 0
1)<BR> (make-onepair 1
0)<BR> (make-onepair 1
1))<BR><BR><BR><BR><BR><BR>There are incredibly many ways of writing a
definition which does the cartesian product! <BR>And these definitions can be
reordered and rearranged and changed (local etc.) in MANY ways.<BR><BR>Below
are a few examples.<BR><BR>Are there some efficiency guidelines for coding in
Scheme? (Especially when considering the scheme code below:) <BR><BR>Some
questions in my mind are:<BR>Is it better to use an unchanging parameter in a
recursive function (just passing it through the whole time), or is it better
to use a local?)<BR>Is it better to build up a list in normal order or reverse
order? <BR>Isn't the use of append, to be avoided when
possible?<BR><BR>(weblink??)<BR><BR><BR>Any comments or suggestions will be
appreciated!<BR><BR>Kind regards,<BR>Albert Neumüller<BR>(The present author
has been writing scheme code for 2.5 months and is still learning
[HTDP])<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>;;
Data Definition:<BR><BR>;; A SV is a Scheme value<BR><BR><BR>(define-struct
onepair (left right))<BR>;; A onepair is a structure : (make-onepair l r),
where l and r are SV (scheme-values)
<BR><BR><BR><BR>;;===================================================<BR>;;cartesian-product1
: (listof SV) -> (listof onepair)<BR>(define (cartesian-product1
alist)<BR> (do-cartesian1 alist alist alist))<BR><BR>;;do-cartesian1 :
(listof SV) (listof SV) (listof SV) -> (listof onepair) <BR>(define
(do-cartesian1 x y alist)<BR> (cond<BR> [(empty? x)
empty]<BR> [(empty? y) (do-cartesian1 (rest x) alist
alist)]<BR> [else (cons (make-onepair (first x) (first
y))<BR>
(do-cartesian1 x (rest y) alist))]))
<BR>;;===================================================<BR><BR>;; In
do-cartesian1 the 3rd parameter ( alist) does not change. Hence we can put it
into a local:<BR><BR>;;===================================================
<BR>;;cartesian-product1b : (listof SV) -> (listof onepair)<BR>(define
(cartesian-product1b alist)<BR> (local ((define (do-cartesian1b x
y)<BR>
(cond<BR>
[(empty? x)
empty]<BR>
[(empty? y) (do-cartesian1b (rest x) alist)]
<BR>
[else (cons (make-onepair (first x) (first
y))<BR>
(do-cartesian1b x (rest y)))])))<BR> (do-cartesian1b alist
alist)))<BR>;;=================================================== <BR><BR>;;
In do-cartesian1b, the same value (first x) is used in repeated recursions
(over y). Hence we can pass it as a parameter
x-single:<BR><BR>;;===================================================<BR>;;cartesian-product1c
: (listof SV) -> (listof onepair) <BR>(define (cartesian-product1c
alist)<BR> (local ((define (do-cartesian1c x-single x-rest
y)<BR>
(cond<BR>
[(empty? y)
(cond<BR>
[(empty? x-rest)
empty]<BR>
[else (do-cartesian1c (first x-rest) (rest x-rest) alist)])]
<BR>
[else (cons (make-onepair x-single (first
y))<BR>
(do-cartesian1c x-single x-rest (rest y)))])))<BR>
(cond<BR> [(empty? alist)
empty]<BR> [else (do-cartesian1c (first alist)
(rest alist) alist)])))
<BR>;;===================================================<BR><BR>;; If order
does not matter then we can use, where we end up with a reversed
result:<BR><BR>;;===================================================<BR>;;cartesian-product2
: (listof SV) -> (listof onepair) <BR>(define (cartesian-product2
alist)<BR> (local ((define (do-cartesian2 x y
growing-result)<BR>
(cond<BR>
[(empty? x)
growing-result]<BR>
[else (do-cartesian2 (rest x)
<BR>
y
<BR>
(cartesian-with-fixed-x2 (first x) y
growing-result))]))<BR>
(define (cartesian-with-fixed-x2 single-x y
growing-result)<BR>
(cond<BR>
[(empty? y) growing-result]
<BR>
[else (cons (make-onepair single-x (first
y))<BR>
(cartesian-with-fixed-x2 single-x (rest y)
growing-result))])))<BR> (do-cartesian2 alist alist
empty)))<BR>;;=================================================== <BR><BR>;;
In do-cartesian2 the 2nd parameter (y) is always equal to the outer paremeter
alist, hence we can remove it:<BR>;; (unfortunately cartesian-product2b
actually seems to perform worse than cartesian-product2!! why?)
<BR><BR>;;===================================================<BR>;;cartesian-product2b
: (listof SV) -> (listof onepair)<BR>(define (cartesian-product2b
alist)<BR> (local ((define (do-cartesian2b x
growing-result)<BR>
(cond<BR>
[(empty? x)
growing-result]<BR>
[else (do-cartesian2b (rest x)
<BR>
(cartesian-with-fixed-x2b (first x) alist
growing-result))]))<BR>
(define (cartesian-with-fixed-x2b single-x y growing-result)
<BR>
(cond<BR>
[(empty? y)
growing-result]<BR>
[else (cons (make-onepair single-x (first
y))<BR>
(cartesian-with-fixed-x2b single-x (rest y) growing-result))])))
<BR> (do-cartesian2b alist
empty)))<BR>;;===================================================<BR><BR>;; In
cartesian-with-fixed-x2b, the 3rd parameter is fixed. Hence we can use a
local:<BR><BR>;;===================================================
<BR>;;cartesian-product3 : (listof SV) -> (listof onepair)<BR>(define
(cartesian-product3 alist)<BR> (local ((define (do-cartesian3 x
growing-result)<BR>
(cond<BR>
[(empty? x)
growing-result]<BR>
[else (do-cartesian3 (rest x)
<BR>
(local ((define (cartesian-with-fixed-x3 single-x
y)<BR>
(cond<BR>
[(empty? y) growing-result]
<BR>
[else (cons (make-onepair single-x (first
y))<BR>
(cartesian-with-fixed-x3 single-x (rest
y)))])))<BR>
(cartesian-with-fixed-x3 (first x) alist)))]))) <BR>
(do-cartesian3 alist
empty)))<BR>;;===================================================<BR><BR>;; In
cartesian-with-fixed-x3, the 1st parameter ( single-x) doesn not change. Hence
we can add it to a local expression:
<BR><BR>;;===================================================<BR>;;cartesian-product3b
: (listof SV) -> (listof onepair)<BR>(define (cartesian-product3b
alist)<BR> (local ((define (do-cartesian3b x
growing-result)<BR>
(cond<BR>
[(empty? x)
growing-result]<BR>
[else (do-cartesian3b (rest x)
<BR>
(local ((define single-x (first
x))<BR>
(define (cartesian-with-fixed-x3b y)
<BR>
(cond<BR>
[(empty? y)
growing-result]<BR>
[else (cons (make-onepair single-x (first y))
<BR>
(cartesian-with-fixed-x3b (rest
y)))])))<BR>
(cartesian-with-fixed-x3b alist)))])))<BR> (do-cartesian3b
alist
empty)))<BR>;;===================================================<BR><BR><BR>;;
Using
append<BR><BR>;;===================================================<BR>;;cartesian-product4
: (listof SV) -> (listof onepair)<BR>(define (cartesian-product4 alist)
<BR> (local ((define (do-cartesian4
x)<BR>
(cond<BR>
[(empty? x)
empty]<BR>
[else (append (do-cartesian4 (rest
x))<BR>
(cartesian-with-fixed-x4 (first x) alist))]))
<BR> (define
(cartesian-with-fixed-x4 single-x
y)<BR> (cond
<BR>
[(empty? y)
empty]<BR>
[else (cons (make-onepair single-x (first
y))<BR>
(cartesian-with-fixed-x4 single-x (rest y)))]))) <BR>
(do-cartesian4
alist)))<BR>;;===================================================<BR><BR>;;
Swapping arguments of append
(faster):<BR><BR>;;===================================================<BR>;;cartesian-product4b
: (listof SV) -> (listof onepair) <BR>(define (cartesian-product4b
alist)<BR> (local ((define (do-cartesian4b
x)<BR>
(cond<BR>
[(empty? x)
empty]<BR>
[else (append (cartesian-with-fixed-x4b (first x)
alist)<BR>
(do-cartesian4b (rest x)))]))
<BR> (define
(cartesian-with-fixed-x4b single-x
y)<BR> (cond
<BR>
[(empty? y)
empty]<BR>
[else (cons (make-onepair single-x (first
y))<BR>
(cartesian-with-fixed-x4b single-x (rest y)))]))) <BR>
(do-cartesian4b
alist)))<BR>;;===================================================<BR><BR>;; In
cartesian-with-fixed-x4b, the 1st parameter (single-x) does not change. Hence
we pull it into a
local:<BR><BR>;;===================================================
<BR>;;cartesian-product4c : (listof SV) -> (listof onepair)<BR>(define
(cartesian-product4c alist)<BR> (local ((define (do-cartesian4c
x)<BR>
(cond<BR>
[(empty? x)
empty]<BR>
[else (append (local ((define single-x (first x))
<BR>
(define (cartesian-with-fixed-x4c
y)<BR>
(cond
<BR>
[(empty? y)
empty]<BR>
[else (cons (make-onepair single-x (first y))
<BR>
(cartesian-with-fixed-x4c (rest
y)))])))<BR>
(cartesian-with-fixed-x4c
alist))<BR>
(do-cartesian4c (rest x)))]))
<BR>
)<BR> (do-cartesian4c
alist)))<BR>;;===================================================<BR><BR>(define
mylist (build-list 2 identity))<BR><BR>(cartesian-product1
mylist)<BR>(cartesian-product1b mylist)<BR>(cartesian-product1c
mylist)<BR>(cartesian-product2 mylist)<BR>(cartesian-product2b
mylist)<BR>(cartesian-product3 mylist)<BR>(cartesian-product3b
mylist)<BR>(cartesian-product4 mylist)<BR>(cartesian-product4b
mylist)<BR>(cartesian-product4c mylist)<BR><BR><BR>;(time (cartesian-product1
mylist))<BR>;(time (cartesian-product1b mylist))<BR>;(time
(cartesian-product1c mylist))<BR>;(time (cartesian-product2 mylist))<BR>;(time
(cartesian-product2b mylist)) <BR>;(time (cartesian-product3
mylist))<BR>;(time (cartesian-product3b mylist))<BR>;(time (cartesian-product4
mylist))<BR>;(time (cartesian-product4b mylist))<BR>;(time
(cartesian-product4c mylist))<BR><BR><BR>
<P>
<HR>
<P></P>_________________________________________________<BR> For
list-related administrative tasks:<BR>
http://list.cs.brown.edu/mailman/listinfo/plt-scheme<BR></BLOCKQUOTE></BODY></HTML>