From: R. Matthew Emerson
Subject: declaring functional types
Date: 
Message-ID: <874shyhrcs.fsf@nightfly.apk.net>
I have the following functions, and I want the arithmetic in #'rk-step
to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
out that the result of the (funcall f ...) form will be a single-float.

Am I doing this wrong (or expecting too much)?

(defun rk-step (f h x y)
  (declare (optimize speed)
	   (ftype (function (single-float single-float) single-float) f)
	   (type single-float h x y))
  (let* ((k1 (* h (funcall f x y)))
         (k2 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k1)))))
         (k3 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k2)))))
         (k4 (* h (funcall f (+ x h) (+ y k3)))))
    (+ y (/ (+ k1 (* 2.0 k2) (* 2.0 k3) k4) 6.0))))

(defun f (x y)
  (declare (type single-float x y))
  (* 2 x y))

-matt

From: Vassil Nikolov
Subject: Re: declaring functional types
Date: 
Message-ID: <l03130303b3e023a6c3f2@195.138.129.118>
R. Matthew Emerson wrote:                [1999-08-18 00:17 +0000]

  > I have the following functions, and I want the arithmetic in #'rk-step
  > to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
  > out that the result of the (funcall f ...) form will be a single-float.

(I can't give you advice regarding a specific compiler (can't you get them
to report what optimisation they did do?), but in general in such cases
one could find THE useful, as in (THE SINGLE-FLOAT (FUNCALL F ...)).)

  > Am I doing this wrong (or expecting too much)?
  > 
  > (defun rk-step (f h x y)
  >   (declare (optimize speed)
  > 	   (ftype (function (single-float single-float) single-float) f)

This declaration would concern calls that look like (F ...), i.e. it
concerns the functional binding of F; for the variable binding of F,
you want (TYPE (FUNCTION ...) F).

(In theory, one could expect that the compiler would warn about
declarations that were unused, like it warns about variables
that don't get actually used unless declared IGNORE or IGNORABLE,
but in practice compiler writers have more important things to do,
I suppose.)

  > 	   (type single-float h x y))
  >   (let* ((k1 (* h (funcall f x y)))
  >          (k2 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k1)))))
  >          (k3 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k2)))))
  >          (k4 (* h (funcall f (+ x h) (+ y k3)))))

You might add declarations for K1 to K4 here.

  >     (+ y (/ (+ k1 (* 2.0 k2) (* 2.0 k3) k4) 6.0))))
  > 

You could perhaps say here

  (declaim (ftype (function ...) f))

  > (defun f (x y)
  >   (declare (type single-float x y))
  >   (* 2 x y))

I have not tested any of the above; beware of typos!

Good luck,
Vassil.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Barry Margolin
Subject: Re: declaring functional types
Date: 
Message-ID: <rjAu3.205$m84.3007@burlma1-snr2>
In article <··············@nightfly.apk.net>,
R. Matthew Emerson <···@nightfly.apk.net> wrote:
>I have the following functions, and I want the arithmetic in #'rk-step
>to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
>out that the result of the (funcall f ...) form will be a single-float.
>
>Am I doing this wrong (or expecting too much)?
>
>(defun rk-step (f h x y)
>  (declare (optimize speed)
>	   (ftype (function (single-float single-float) single-float) f)

You should use a TYPE declaration, not an FTYPE declaration.  FTYPE
declarations apply to the value of #'F, but you're declaring the type of
the value of F.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Johan Kullstam
Subject: Re: declaring functional types
Date: 
Message-ID: <m2vha6el6s.fsf@sophia.axel.nom>
Barry Margolin <······@bbnplanet.com> writes:

> In article <··············@nightfly.apk.net>,
> R. Matthew Emerson <···@nightfly.apk.net> wrote:
> >I have the following functions, and I want the arithmetic in #'rk-step
> >to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
> >out that the result of the (funcall f ...) form will be a single-float.
> >
> >Am I doing this wrong (or expecting too much)?
> >
> >(defun rk-step (f h x y)
> >  (declare (optimize speed)
> >	   (ftype (function (single-float single-float) single-float) f)
> 
> You should use a TYPE declaration, not an FTYPE declaration.  FTYPE
> declarations apply to the value of #'F, but you're declaring the type of
> the value of F.

i thought he wants to declare #'F?  this seems to be exactly as desired
since F is being FUNCALL'd.  the value of F is never used.

-- 
J o h a n  K u l l s t a m
[········@ne.mediaone.net]
Don't Fear the Penguin!
From: Barry Margolin
Subject: Re: declaring functional types
Date: 
Message-ID: <C1ew3.349$m84.6235@burlma1-snr2>
In article <··············@sophia.axel.nom>,
Johan Kullstam  <········@ne.mediaone.net> wrote:
>i thought he wants to declare #'F?  this seems to be exactly as desired
>since F is being FUNCALL'd.  the value of F is never used.

When you do (funcall f ...) you're calling the function that's the value of
the variable F.  When you do (f ...) you're calling the function that's the
value of the expression #'F.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Steve Gonedes
Subject: Re: declaring functional types
Date: 
Message-ID: <m2g11h6pk8.fsf@KludgeUnix.com>
···@nightfly.apk.net (R. Matthew Emerson) writes:

< I have the following functions, and I want the arithmetic in #'rk-step
< to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
< out that the result of the (funcall f ...) form will be a single-float.
< 
< Am I doing this wrong (or expecting too much)?
< 
< (defun rk-step (f h x y)
<   (declare (optimize speed)
< 	   (ftype (function (single-float single-float) single-float) f)
< 	   (type single-float h x y))
<   (let* ((k1 (* h (funcall f x y)))
<          (k2 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k1)))))
<          (k3 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k2)))))
<          (k4 (* h (funcall f (+ x h) (+ y k3)))))
<     (+ y (/ (+ k1 (* 2.0 k2) (* 2.0 k3) k4) 6.0))))
< 
< (defun f (x y)
<   (declare (type single-float x y))
<   (* 2 x y))
< 
< -matt


You can use the declaration `(:explain :types :calls)' to get type
information in acl. I got most of the calls to be inlined and unboxed
by using a simple macrolet. Your problem was that you didn't declare
the return value.

(defun f (x y)
  (declare (type single-float x y) (:explain :types :calls))
  (the single-float (* 2 x y)))

(defun rk-step (f h x y)
  (declare (optimize speed)
           (ftype (function (single-float single-float) single-float) f)
           (:explain :types :calls)
           (type single-float h x y))
  (macrolet ((%funcall (&rest forms)
               `(the single-float (funcall ,@ forms))))
    (let* ((k1 (* h (%funcall f x y)))
           (k2 (* h (%funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k1)))))
           (k3 (* h (%funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k2)))))
           (k4 (* h (%funcall f (+ x h) (+ y k3)))))
      (+ y (/ (+ k1 (* 2.0 k2) (* 2.0 k3) k4) 6.0)))))

There is a way to define new declarations so that `explain' will run
in cmucl, but I forget how right now.
From: Howard R. Stearns
Subject: Re: declaring functional types
Date: 
Message-ID: <37BC3D59.CA0D0E5E@elwood.com>
I'm a little confused by your use of the variable f to hold a function
object within rk-step, taken with your use of f to name a top-level
function.  It might be clearer if show a smple of how rk-step is called.

For example, if you're doing someting like:
  (rk-step #'f 1.0f0 2.0f0 3.0f0)
then I think the issue is really one of boxing.  Look at it this way:

When CL calls a function that it knows about, it can perform all kinds
of optimizations.  For example, in a call like (f x y), it might, in
principle, in-line the function.  Based on declarations, it might
instead use some special entry point to the function which doesn't box
(heap allocate) the arguments or the returned floats.

However, rk-step gets a random function as argument, which it funcalls. 
This means that somewhere, somehow, someone had to get a Lisp function
object with something like #'f or (fdefinition 'f).  The code that
actually gets this function object doesn't have any idea how it is going
to be used, so the code to do this gets the most general entry point to
the function code and stores it in the function object.  Since funcall
knows that this is the case, funcall always has to box up float
arguments and unbox return arguments - regardless of declarations.  Once
that happens, other operations in the chain might get boxed/unboxed and
you might loose more opencoding.

In principle, at first glance, it looks to me that Lisp function objects
could carry around knowledge of specialized entry points (e.g., special
optimized versions of the function code), and that funcall could make
use of this.  This would involve some runtime checks, which could
themselves be turned off with some declarations.  I've never heard of
any compilers/Lisp-runtimes that actually do this, but it could happen.

Failing that, if you want to make sure that everything EXCEPT the
funcall is open coded, you could use either THE or its equivalent
"expansion" with LET and declarations.

Better, however, is if the set of functions that can be passed in for f
is fairly small. It may be ugly, but you could pass a key (a flag)
instead of f itself, and decode that in a case that has different
branches which directly cll the function (without funcalling a closure).

I think that the best solution, though, is if the compiler can inline
anything, and if it can keep track of known compile time values.  Then,
you might have something like this:

   (cond (... (let ((f #'f)) ... (rk-step f h x y) ...) ...)
         (... (let ((f #'g)) ... (rk-step f h x y) ...) ...))
A sufficiently smart compiler could inline both calls to rk-step, and
replace the resulting (funcall f ...) with inlined versions of (f ..)
and (g ...), respectively.  Then, at the price of a lot of generated
code, you could have your clean Lisp code design and debugging, AND your
optimized production code.  Again, though, I don't know of any Lisp
compilers that are that smart.



R. Matthew Emerson wrote:
> 
> I have the following functions, and I want the arithmetic in #'rk-step
> to open-code.  However, I can't get a compiler (ACL or CMUCL) to figure
> out that the result of the (funcall f ...) form will be a single-float.
> 
> Am I doing this wrong (or expecting too much)?
> 
> (defun rk-step (f h x y)
>   (declare (optimize speed)
>            (ftype (function (single-float single-float) single-float) f)
>            (type single-float h x y))
>   (let* ((k1 (* h (funcall f x y)))
>          (k2 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k1)))))
>          (k3 (* h (funcall f (+ x (* 0.5 h)) (+ y (* 0.5 k2)))))
>          (k4 (* h (funcall f (+ x h) (+ y k3)))))
>     (+ y (/ (+ k1 (* 2.0 k2) (* 2.0 k3) k4) 6.0))))
> 
> (defun f (x y)
>   (declare (type single-float x y))
>   (* 2 x y))
> 
> -matt