From: Helmut Eller <heller@co...>  20100723 08:53:29

Hello, I'd like to create a macro/function that when given two series as input produces the "cross product" as output. E.g. (cross (scan '(a b c)) (scan '(1 2 3))) => #Z(a a a b b b c c c) and #Z(1 2 3 1 2 3 1 2 3) Or as picture:    (scan '(a b c)) > > #z(a b c a b c a b c)     cross      (scan '(1 2 3)) > > #z(1 1 1 2 2 2 3 3 3)   I tried this: (defmacro cross (sx sy) `(producing (ox oy) ((genx ,sx) x geny y) (loop (tagbody (setq x (nextin genx (terminateproducing))) (setq geny (generator ,sy)) loop (setq y (progn (nextin geny (go end)))) (nextout ox x) (nextout oy y) (go loop) end)))) (defun foo () (collect (mapping (((x y) (cross (scan '(1 2 3)) (scan '(a b c))))) (cons x y)))) It works but apparently this can't be optimized. Is there a better way to write such "nested loops" where the outputs are "faster" than the inputs? If not, would it be possible to add a new "primitive" for such cases? Helmut 
From: Helmut Eller <heller@co...>  20100723 16:26:11

* Raymond Toy [20100723 15:00+0200] writes: > On 7/23/10 4:15 AM, Helmut Eller wrote: >> Hello, >> >> I'd like to create a macro/function that when given two series >> as input produces the "cross product" as output. E.g. >> >> (cross (scan '(a b c)) (scan '(1 2 3))) >> => #Z(a a a b b b c c c) and #Z(1 2 3 1 2 3 1 2 3) >> > Do the two series have the same length? Yes, the output series have the same length (possibly infinite). > It seems you just replicate > each element 3 times. Why 3? Because there are 3 elements in the > original series? Perhaps a bad example, but yes: 3 because the inputs have length 3. > I'm a bit confused on exactly what cross should do. Another way to write CROSS would be: (defmacro cross (sx sy) `(let ((xs '()) (ys '())) (iterate ((x ,sx)) (iterate ((y ,sy)) (push x xs) (push y ys))) (values (scan (reverse xs)) (scan (reverse ys))))) Obviously inefficient, but hopefully clearer. One series expression drives the outer loop and the other series expression drives the inner loop. The outer loop produces a series; lets call that #z(x_0 x_1 ... x_n). The inner loop consumes that series. For each element x_i the inner loop produces (part of) a series #z(y_i_0 y_i_1 ... y_i_m) and additionally copies x_i m times to a second series (so that clients of CROSS can access the corresponding x and y values). The final two outputs look like: #z(x_0 x_0 ... x_0 x_1 x_1 ... x_1 x_2 x_2 ...) #z(y_0_0 y_0_1 ... y_0_m y_1_0 y_1_1 ... y_1_k y_2_0 y_2_1 ...) y_0_0 and y_1_0 can be different; also m and k can be different. The inner loop doesn't necessarily produce the same values for each iteration of the outer loop; i.e. the y values aren't just replicated. [The series expression of the inner loop should also have access to the current x value. In the example that's possible by accessing the variable x but that's sloppy; the name should better be an argument to CROSS or the second expression should be a lambda taking the value of x as argument.] Helmut 
From: Raymond Toy <toy.raymond@gm...>  20100726 00:13:58

On 7/23/10 12:25 PM, Helmut Eller wrote: > * Raymond Toy [20100723 15:00+0200] writes: > >> On 7/23/10 4:15 AM, Helmut Eller wrote: >>> Hello, >>> >>> I'd like to create a macro/function that when given two series >>> as input produces the "cross product" as output. E.g. >>> >>> (cross (scan '(a b c)) (scan '(1 2 3))) >>> => #Z(a a a b b b c c c) and #Z(1 2 3 1 2 3 1 2 3) >>> >> Do the two series have the same length? > Yes, the output series have the same length (possibly infinite). Sorry, I'm still confused. If the series have infinite length, then the first series from cross will repeat the first element forever? Or something else? > >> I'm a bit confused on exactly what cross should do. > Another way to write CROSS would be: > > (defmacro cross (sx sy) > `(let ((xs '()) (ys '())) > (iterate ((x ,sx)) > (iterate ((y ,sy)) > (push x xs) > (push y ys))) > (values (scan (reverse xs)) > (scan (reverse ys))))) > > Obviously inefficient, but hopefully clearer. This produces something different from the original cross. I get (cross (scan '(a b c)) (scan '(1 2 3))) > #Z(a a a b b b c c c) #z(1 2 3 1 2 3 1 2 3) > One series expression drives the outer loop and the other series > expression drives the inner loop. The outer loop produces a series; > lets call that #z(x_0 x_1 ... x_n). The inner loop consumes that > series. For each element x_i the inner loop produces (part of) a series > #z(y_i_0 y_i_1 ... y_i_m) and additionally copies x_i m times to a What is the value of m? How is it derived from the inputs? I think it's ok if the output of a series function is "faster" than the inputs. The function SPREAD produces more output data than the input data series. Ray 
From: Helmut Eller <heller@co...>  20100726 06:19:22

* Raymond Toy [20100726 02:13+0200] writes: > On 7/23/10 12:25 PM, Helmut Eller wrote: >> * Raymond Toy [20100723 15:00+0200] writes: >> >>> On 7/23/10 4:15 AM, Helmut Eller wrote: >>>> Hello, >>>> >>>> I'd like to create a macro/function that when given two series >>>> as input produces the "cross product" as output. E.g. >>>> >>>> (cross (scan '(a b c)) (scan '(1 2 3))) >>>> => #Z(a a a b b b c c c) and #Z(1 2 3 1 2 3 1 2 3) >>>> >>> Do the two series have the same length? >> Yes, the output series have the same length (possibly infinite). > Sorry, I'm still confused. If the series have infinite length, then the > first series from cross will repeat the first element forever? Or > something else? Yes, it's repeated. [But in a lazy fashion, so that the version with ITERATE wouldn't work if the client only consumes the first 10 elements.] >> >>> I'm a bit confused on exactly what cross should do. >> Another way to write CROSS would be: >> >> (defmacro cross (sx sy) >> `(let ((xs '()) (ys '())) >> (iterate ((x ,sx)) >> (iterate ((y ,sy)) >> (push x xs) >> (push y ys))) >> (values (scan (reverse xs)) >> (scan (reverse ys))))) >> >> Obviously inefficient, but hopefully clearer. > This produces something different from the original cross. I get > > (cross (scan '(a b c)) (scan '(1 2 3))) > > #Z(a a a b b b c c c) > #z(1 2 3 1 2 3 1 2 3) That's the same as what I quoted above, no? >> One series expression drives the outer loop and the other series >> expression drives the inner loop. The outer loop produces a series; >> lets call that #z(x_0 x_1 ... x_n). The inner loop consumes that >> series. For each element x_i the inner loop produces (part of) a series >> #z(y_i_0 y_i_1 ... y_i_m) and additionally copies x_i m times to a > What is the value of m? In the example it's 3; #z(y_i_0 y_i_1 ... y_i_m) corresponds to one of the #z(1 2 3) segments. > How is it derived from the inputs? I realize now that the second argument of cross can't be a just a series it must be a function that produces a series (the current element of the first series is passed in as argument). It's that function that decides how long the segments get. > I think it's ok if the output of a series function is "faster" than the > inputs. The function SPREAD produces more output data than the input > data series. Yes, that looks promising. I'm trying to write some examples here http://projectfortress.sun.com/Projects/Community/wiki/ComprehendingComprehensions with series. They enumerate Pythagorean Triples with generator expressions. It feels like that should be possible with series too, but actually doing it is quite hard. Helmut 
From: Raymond Toy <toy.raymond@gm...>  20100726 13:07:13

On 7/26/10 2:19 AM, Helmut Eller wrote: > >> This produces something different from the original cross. I get >> >> (cross (scan '(a b c)) (scan '(1 2 3))) > >> #Z(a a a b b b c c c) >> #z(1 2 3 1 2 3 1 2 3) > That's the same as what I quoted above, no? Yes. I don't know what I was looking at. For some reason, I thought the original was #z(1 1 1 2 2 2 3 3 3). > > I'm trying to write some examples here > http://projectfortress.sun.com/Projects/Community/wiki/ComprehendingComprehensions > > with series. They enumerate Pythagorean Triples with generator > expressions. It feels like that should be possible with series too, > but actually doing it is quite hard. Ah, now I understand. We have 3 sets of numbers, a, b, c, and we want to take all possible combinations of those 3 numbers so that we can apply the coprime property, the ordering a < b < c, and the most important property of a^2+b^2 = c^2. So to do this with series, we need to generate series as you propose so that we eventually get all possible combinations of a, b, and c. Ray 