From: DanL
Subject: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <8befef93-acab-405d-b247-db240eccec89@m4g2000vbp.googlegroups.com>
Hello!

If I wanted to implement this simple transducer:

(defun foo (s)
  (declare (optimizable-series-function))
  (#midentity s))

using producing, how would I do that? The documentation (s-doc.txt)
says:

It [producing] can be used as the basis for defining all the other
series functions, including the off-line transducers.

But in:

(defun foo (s)
  (declare (optimizable-series-function))
  (producing (out) ((in s) e)
    (loop
      (tagbody
        (setq e (next-in in (terminate-producing)))
        (next-out out e)))))

s is "unexpectedly off-line". Now, there are four limitations
concerning producing mentioned:

1. the body must have the form (loop (tagbody ... OK
2. terminate-producing must be used to terminate the body ... OK
3. next-out must be at top-level, final position etc. ... OK
4. next-in must be at top-level or in setq, at initial position
etc. ... OK

If I understand correctly, the function should process in lock step,
so that won't be the problem, right? Maybe the implicit binding of in
to a generator of s is the problem, but I'm just guessing. So, why
exactly is the input port off-line in this example? Maybe I get
something totally wrong, but if the doc says "defining all the other
series functions" is possible with producing, so I wonder why I can't
even get such an easy transducer (which basically does nothing) to
work. Defining some functions with producing works like a charm (e.g.
I wrote foldl/foldr and a clojure-like distinctively using it), but up
to now I don't seem to have grokked the on-line/of-line and
optimization issues.

Maybe someone with more insight can shed some light.

Regards,

dhl

From: Kojak
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <20090305021339.4b03675c@thor.janville.org>
Le Wed, 4 Mar 2009 16:08:59 -0800 (PST),
DanL a écrit :

> [...]
> But in:
> 
> (defun foo (s)
>   (declare (optimizable-series-function))
>   (producing (out) ((in s) e)
>     (loop
>       (tagbody
>         (setq e (next-in in (terminate-producing)))
>         (next-out out e)))))
> 
> s is "unexpectedly off-line". Now, there are four limitations
> concerning producing mentioned:
> [...]

Don't really understand what you are looking for, but...
Does that help you?

(defun foo (s)
  (let ((arg s))
    (declare (optimizable-series-function))
    (producing (out) ((in arg) e)
	       (loop
		  (tagbody
		     (setq e (next-in in (terminate-producing)))
		     (next-out out e))))))

That said, don't ask me more. :-)

-- 
Jacques.
From: DanL
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <102e1446-2e38-4a01-b1d4-332cf1136739@r29g2000vbp.googlegroups.com>
On Mar 5, 2:13 am, Kojak <·······@janville.Borg.invalid> wrote:

> Don't really understand what you are looking for, but...

I want to know if it's possible to have a series function using
producing without making the input port off-line. Maybe I just misread
it, but I thought because

(defun foo (s)
  (declare (optimizable-series-function))
  (#midentity s))

is a series function and it's input port is on-line that, given that
the docs say "for defining ALL the other sequence functions" it should
be possible to implement this function using producing without the
unexpected off-line issue.

Maybe I just misread "including the off-line transducers", which could
also mean ONLY the off-line transducers, but that would contradict the
"... defining ALL ...", IMHO.

So I am wondering, if it is at all possible to define a series
function using producing which keeps input ports on-line, since I
comply with the mentioned limitations and I think that the computation
is in lock step*.

But, as mentioned, I haven't really grokked those optimization
issues ...

> Does that help you?
>
> (defun foo (s)
>   (let ((arg s))
>     (declare (optimizable-series-function))
> ...

Well, it doesn't emit the warning about s being unexpectedly off-line,
but I think that's just because the declaration of optimizable-series-
function must be "immediately inside a DEFUN", so in your example, the
function isn't even analyzed for optimization.


Thanks anyway,

dhl


* "The initial element of each on-line input is read, then the initial
element of each on-line output is written, then the second element of
each on-line input is read, then the second element of each on-line
output is written, and so on."
From: Kojak
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <20090305033232.3babb0a2@thor.janville.org>
Le Wed, 4 Mar 2009 17:44:16 -0800 (PST),
DanL a écrit :

> On Mar 5, 2:13 am, Kojak <·······@janville.Borg.invalid> wrote:
> > Does that help you?
> >
> > (defun foo (s)
> >   (let ((arg s))
> >     (declare (optimizable-series-function))
> > ...
> 
> Well, it doesn't emit the warning about s being unexpectedly off-line,
> but I think that's just because the declaration of optimizable-series-
> function must be "immediately inside a DEFUN", so in your example, the
> function isn't even analyzed for optimization.

Ok, I've take a quick look at the package. I can miss again,
but I think this way should be better:

(defun foo (s)
  (producing (out) ((in s) e)
	     (declare (optimizable-series-function))
	     (loop
		(tagbody
		   (setq e (next-in in (terminate-producing)))
		   (next-out out e)))))

-- 
Jacques.
From: DanL
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <30977ac2-e451-40ff-a581-dd42aa5a7192@q11g2000vbn.googlegroups.com>
On Mar 5, 3:32 am, Kojak <·······@janville.Borg.invalid> wrote:

> Ok, I've take a quick look at the package. I can miss again,
> but I think this way should be better:
>
> (defun foo (s)
>   (producing (out) ((in s) e)
>              (declare (optimizable-series-function))
>              (loop
>                 (tagbody
>                    (setq e (next-in in (terminate-producing)))
>                    (next-out out e)))))

Hm ... I think, the declaration must really be on the toplevel of
defun:

TEST> (defun foo (s)
        (declare (optimizable-series-function))
        (producing (out) ((in s) e)
          (loop
             (tagbody
                (setq e (next-in in (terminate-producing)))
                (next-out out e)))))

Warning 40 in series expression:
...
The input S unexpectedly off-line.
FOO
TEST> (defun bar (s)
        (declare (optimizable-series-function))
        (foo s))
Warning 40 in series expression:
(DEFUN BAR (S
  (DECLARE (OPTIMIZABLE-SERIES-FUNCTION))
  (FOO S))
The input S unexpectedly off-line.
BAR
TEST> (bar #z(1 2 3))
#z(1 2 3)

S is offline, but it works. (The warning could be avoided by declaring
(off-line-port s), too).

TEST> (defun foo (s)
        (producing (out) ((in s) e)
           (declare (optimizable-series-function))
           (loop
              (tagbody
                 (setq e (next-in in (terminate-producing)))
                 (next-out out e)))))
FOO
TEST> (defun bar (s)
        (declare (optimizable-series-function))
        (foo s))
Warning 44 in series expression:
(DEFUN BAR (S)
  (DECLARE (OPTIMIZABLE-SERIES-FUNCTION))
  (FOO S))
OPTIMIZABLE-SERIES-FUNCTION neither uses nor returns a series.
BAR
TEST> (bar #z (1 2 3))
Restriction violation 13 in series expression:
(BAR (SERIES::LITERAL-SERIES '(1 2 3)))
Series to non-series data flow from:
(SERIES::LITERAL-SERIES '(1 2 3))
to:
(BAR (SERIES::LITERAL-SERIES '(1 2 3)))
...

Doesn't work at all. Also:

TEST> (defun foo (s)
        (declare (optimizable-series-function))
        (producing (out) ((in s) e)
           (declare (optimizable-series-function))
           (loop
              (tagbody
                 (setq e (next-in in (terminate-producing)))
                 (next-out out e)))))

Restriction violation 1 in series expression:
...
The declaration (OPTIMIZABLE-SERIES-FUNCTION) blocks optimization.
FOO
TEST>

Regards,

dhl
From: Kojak
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <20090305061957.6767371f@thor.janville.org>
Le Wed, 4 Mar 2009 20:04:17 -0800 (PST),
DanL a écrit :

> On Mar 5, 3:32 am, Kojak <·······@janville.Borg.invalid> wrote:
> > (defun foo (s)
> >   (producing (out) ((in s) e)
> >              (declare (optimizable-series-function))
> >              (loop
> >                 (tagbody
> >                    (setq e (next-in in (terminate-producing)))
> >                    (next-out out e)))))
> 
> Hm ... I think, the declaration must really be on the toplevel of
> defun:

I've just followed the doc, who shows 'PRODUCING' syntax:

  PRODUCING OUTPUT-LIST INPUT-LIST {DECLARATION}* {FORM}*

Testing this version with the following version of bar:

(defun bar (s)
  (let ()
    (declare (optimizable-series-function))
    (foo s)))

Or another version:

(defun bar (s)
  (let ()
    (declare (optimizable-series-function))
    (producing (out) ((in s) e)
	       (declare (optimizable-series-function))
	       (loop
		  (tagbody
		     (setq e (next-in in (terminate-producing)))
		     (next-out out e)
		     (foo s))))))

Seem to run correctly with optimization. For 'LET' I refer to
the doc too.

Sorry, but I don't see anything else. Perhaps someone else here,
wait and see...

-- 
Jacques.
From: DanL
Subject: Re: SERIES:PRODUCING off-line ports question
Date: 
Message-ID: <0caa330f-a3fe-4e6f-b058-38855c7a2574@s31g2000vbp.googlegroups.com>
On Mar 5, 6:19 am, Kojak <·······@janville.Borg.invalid> wrote:

> Le Wed, 4 Mar 2009 20:04:17 -0800 (PST),
> DanL a écrit :
> > Hm ... I think, the declaration must really be on the toplevel of
> > defun:
>
> I've just followed the doc, who shows 'PRODUCING' syntax:
>
>   PRODUCING OUTPUT-LIST INPUT-LIST {DECLARATION}* {FORM}*
>

[...]

> Seem to run correctly with optimization. For 'LET' I refer to
> the doc too.

I see, but the doc says:

"The declaration specifier (OPTIMIZABLE-SERIES-FUNCTION INTEGER)
indicates that the function being defined is a series function that
needs to be analyzed so that it can be optimized when it appears in
series expressions."

Notice that it says "the function being defined"; neither let (or
series::let), nor producing defines a function, defun does.
(Otherwise, o-s-f would be pretty bad naming, too)

Well, let's just test it:

TEST> (defun scan-distinct-randoms (n)
        (declare (optimizable-series-function))
        (producing (nums) (produced num)
           (loop
              (tagbody
               start
                 (setq num (random n))
                 (when (member num produced)
                   (go start))
                 (push num produced)
                 (next-out nums num)))))
SCAN-DISTINCT-RANDOMS
TEST> (time (collect (take 10000 (scan-distinct-randoms 1.0))))
Evaluation took:
  0.747 seconds of real time
  0.726620 seconds of total run time (0.723286 user, 0.003334 system)
  97.32% CPU
  1,868,776,835 processor cycles
  621,152 bytes consed

(0.61155033 0.37570083 ...)
TEST> (defun scan-distinct-randoms (n)
        (producing (nums) (produced num)
        (declare (optimizable-series-function))
           (loop
              (tagbody
               start
                 (setq num (random n))
                 (when (member num produced)
                   (go start))
                 (push num produced)
                 (next-out nums num)))))
SCAN-DISTINCT-RANDOMS
TEST> (time (collect (take 10000 (scan-distinct-randoms 1.0))))
Warning 28 in series expression:
(COLLECT (TAKE 10000 (SCAN-DISTINCT-RANDOMS 1.0)))
Non-series to series data flow from:
(SCAN-DISTINCT-RANDOMS 1.0)
to:
(TAKE 10000 (SCAN-DISTINCT-RANDOMS 1.0))
Evaluation took:
  1.822 seconds of real time
  1.829881 seconds of total run time (1.829881 user, 0.000000 system)
  100.44% CPU
  4,574,681,716 processor cycles
  1,397,456 bytes consed

(0.72591805 0.1701343 ...)
TEST>

The timing difference is a result of the latter definition of scan-
distinct-randoms not being opimized.

scan-distinct-randoms is just an example which I can code without any
port being off-line, what I am really doing is more along with this:

(defun distinct (series)
  (declare (optimizable-series-function)
           (off-line-port series))
  (producing (out) ((in series) element seen)
             (loop
                (tagbody
                 start
                   (setq element
                         (next-in in (terminate-producing)))
                   (when (member element seen)
                     (go start))
                   (push element seen)
                   (next-out out element)))))

which wold allow me to write (pretty clojure-like):

TEST> (take 10 (distinct (mapping () (random 20))))
#Z(1 8 13 12 15 17 4 16 11 0)

By the way, the input port being off-line does not have a performance
impact in this case:

TEST> (time (collect (take 10000
                           (distinct (mapping () (random 1.0))))))
Evaluation took:
  0.734 seconds of real time
  0.733286 seconds of total run time (0.733286 user, 0.000000 system)
  99.86% CPU
  1,842,565,172 processor cycles
  518,144 bytes consed

(0.54450524 0.8860377 ...)

But anyway, I'd like to know if it can be avoided.

Both distinct and scan-distinct-randoms are buggy btw, if you
evaluate:

TEST> (take 1 (distinct (mapping () (random 1))

It just sits there and computes forever, but I'm just getting used to
write such kind of code. Maybe someone sees the bug and can help a
little.

> Sorry, but I don't see anything else. Perhaps someone else here,
> wait and see...

Thanks,

dhl

(defun take (n series)
  (declare (optimizable-series-function)
           (off-line-port series))
  (subseries series 0 n))