unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
* generic * and 0
@ 2006-11-29 17:58 SZAVAI Gyula
  2006-12-01 19:56 ` Kevin Ryde
  0 siblings, 1 reply; 13+ messages in thread
From: SZAVAI Gyula @ 2006-11-29 17:58 UTC (permalink / raw)



guile-1.8-20061126

(use-modules (oop goops))
(define-class <c> ())
(define-method (* a (b <c>)) #t)
(* 0 (make <c>))
==> 0



--- orig/libguile/numbers.c     2006-11-29 18:09:22.393764800 +0100
+++ mod/libguile/numbers.c      2006-11-29 18:10:22.319934400 +0100
@@ -4416,12 +4416,6 @@
     intbig:
       xx = SCM_I_INUM (x);

-      switch (xx)
-       {
-        case 0: return x; break;
-        case 1: return y; break;
-       }
-
       if (SCM_I_INUMP (y))
        {
          long yy = SCM_I_INUM (y);



_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-11-29 17:58 generic * and 0 SZAVAI Gyula
@ 2006-12-01 19:56 ` Kevin Ryde
  2006-12-01 20:22   ` Mikael Djurfeldt
  0 siblings, 1 reply; 13+ messages in thread
From: Kevin Ryde @ 2006-12-01 19:56 UTC (permalink / raw)
  Cc: bug-guile

SZAVAI Gyula <szgyg@ludens.elte.hu> writes:
>
> (use-modules (oop goops))
> (define-class <c> ())
> (define-method (* a (b <c>)) #t)
> (* 0 (make <c>))
> ==> 0

Thanks, that's a bug.

> -      switch (xx)
> -       {
> -        case 0: return x; break;
> -        case 1: return y; break;
> -       }
> -

Though that's not the fix (it breaks 0 * bignum, and changes 0 * real
and complex).


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-01 19:56 ` Kevin Ryde
@ 2006-12-01 20:22   ` Mikael Djurfeldt
  2006-12-01 21:52     ` Kevin Ryde
  0 siblings, 1 reply; 13+ messages in thread
From: Mikael Djurfeldt @ 2006-12-01 20:22 UTC (permalink / raw)
  Cc: bug-guile

2006/12/1, Kevin Ryde <user42@zip.com.au>:
> SZAVAI Gyula <szgyg@ludens.elte.hu> writes:
> >
> > (use-modules (oop goops))
> > (define-class <c> ())
> > (define-method (* a (b <c>)) #t)
> > (* 0 (make <c>))
> > ==> 0
>
> Thanks, that's a bug.

Are you sure?

If you want to use an operator which is common for numbers and <c>:s,
why don't you want to use a common zero?  If you don't, the behavior
of the operator will be inconsistent.

If one still don't want 0 as zero (in the abstract sense), maybe one
should use another name for the operator, or, tie a different generic
to the name "*".

M


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-01 20:22   ` Mikael Djurfeldt
@ 2006-12-01 21:52     ` Kevin Ryde
  2006-12-04  0:26       ` Kevin Ryde
  0 siblings, 1 reply; 13+ messages in thread
From: Kevin Ryde @ 2006-12-01 21:52 UTC (permalink / raw)
  Cc: bug-guile

"Mikael Djurfeldt" <mikael@djurfeldt.com> writes:
>
> If you want to use an operator which is common for numbers and <c>:s,
> why don't you want to use a common zero?  If you don't, the behavior
> of the operator will be inconsistent.

For multiply by 0, I can sort of think of cases when the return type
shouldn't be a fixnum.  If you're doing 0 times a certain size matrix,
then you probably want a matrix full of zeros to come back.  Does that
sound right?

For multiply by 1, I can't actually think of any time you wouldn't
want to get back the object unchanged.  But perhaps if a class has a
notion of multiply, but not "multiply by scalar" then you'd like it to
be overridable so it can be banned.


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-01 21:52     ` Kevin Ryde
@ 2006-12-04  0:26       ` Kevin Ryde
  2006-12-04 18:26         ` Mikael Djurfeldt
  0 siblings, 1 reply; 13+ messages in thread
From: Kevin Ryde @ 2006-12-04  0:26 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 348 bytes --]

While nosing around nearby stuff I noticed

	(* 0 1.0)  => 0
	(* 0 1+1i) => 0
but
	(* 1.0  0) => 0.0
	(* 1+1i 0) => 0.0

which seems a bit inconsistent.  R5RS "Exactness" reads like either
exact or inexact is permitted, but I imagine it ought to be the same
whichever way around you write the args.  I think I'll change the
latter two to exact 0.


[-- Attachment #2: numbers.c.mul-exact0-16.diff --]
[-- Type: text/plain, Size: 854 bytes --]

--- numbers.c.~1.135.2.22.~	2006-03-20 08:48:19.000000000 +1100
+++ numbers.c	2006-12-03 15:59:32.000000000 +1100
@@ -3632,6 +3632,9 @@
     }
   } else if (SCM_REALP (x)) {
     if (SCM_INUMP (y)) {
+      /* inexact*exact0 is exact 0, per R5RS "Exactness" section */
+      if (SCM_EQ_P (y, SCM_INUM0))
+        return y;
       return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
     } else if (SCM_BIGP (y)) {
       return scm_make_real (scm_i_big2dbl (y) * SCM_REAL_VALUE (x));
@@ -3645,6 +3648,9 @@
     }
   } else if (SCM_COMPLEXP (x)) {
     if (SCM_INUMP (y)) {
+      /* inexact*exact0 is exact 0, per R5RS "Exactness" section */
+      if (SCM_EQ_P (y, SCM_INUM0))
+        return y;
       return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
 			       SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
     } else if (SCM_BIGP (y)) {

[-- Attachment #3: numbers.c.mul-exact0-18.diff --]
[-- Type: text/plain, Size: 1208 bytes --]

--- numbers.c.~1.281.2.7.~	2006-09-27 11:34:11.000000000 +1000
+++ numbers.c	2006-12-03 16:08:52.000000000 +1100
@@ -4492,7 +4492,12 @@
   else if (SCM_REALP (x))
     {
       if (SCM_I_INUMP (y))
-	return scm_from_double (SCM_I_INUM (y) * SCM_REAL_VALUE (x));
+        {
+          /* inexact*exact0 is exact 0, per R5RS "Exactness" section */
+          if (scm_is_eq (y, SCM_INUM0))
+            return y;
+          return scm_from_double (SCM_I_INUM (y) * SCM_REAL_VALUE (x));
+        }
       else if (SCM_BIGP (y))
 	{
 	  double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
@@ -4512,8 +4517,13 @@
   else if (SCM_COMPLEXP (x))
     {
       if (SCM_I_INUMP (y))
-	return scm_c_make_rectangular (SCM_I_INUM (y) * SCM_COMPLEX_REAL (x),
-				 SCM_I_INUM (y) * SCM_COMPLEX_IMAG (x));
+        {
+          /* inexact*exact0 is exact 0, per R5RS "Exactness" section */
+          if (scm_is_eq (y, SCM_INUM0))
+            return y;
+          return scm_c_make_rectangular (SCM_I_INUM (y) * SCM_COMPLEX_REAL (x),
+                                         SCM_I_INUM (y) * SCM_COMPLEX_IMAG (x));
+        }
       else if (SCM_BIGP (y))
 	{
 	  double z = mpz_get_d (SCM_I_BIG_MPZ (y));

[-- Attachment #4: Type: text/plain, Size: 137 bytes --]

_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-04  0:26       ` Kevin Ryde
@ 2006-12-04 18:26         ` Mikael Djurfeldt
  2006-12-05  0:00           ` Kevin Ryde
  0 siblings, 1 reply; 13+ messages in thread
From: Mikael Djurfeldt @ 2006-12-04 18:26 UTC (permalink / raw)
  Cc: bug-guile

2006/12/4, Kevin Ryde <user42@zip.com.au>:
> While nosing around nearby stuff I noticed
>
>         (* 0 1.0)  => 0
>         (* 0 1+1i) => 0
> but
>         (* 1.0  0) => 0.0
>         (* 1+1i 0) => 0.0
>
> which seems a bit inconsistent.

Indeed.

>  R5RS "Exactness" reads like either
> exact or inexact is permitted, but I imagine it ought to be the same
> whichever way around you write the args.  I think I'll change the
> latter two to exact 0.

Good idea.  Because of paragraph 6.2.2, a program cannot expect to get
the result 0.0, and it seems like a strength of the implementation to
provide the additional piece of information that the result is indeed
*exactly* 0.

An added bonus is that it doesn't break the idea to have a common
abstract zero for the * operator.  (Not entirely sure that the common
zero is a good idea, but I tend to think so.)


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-04 18:26         ` Mikael Djurfeldt
@ 2006-12-05  0:00           ` Kevin Ryde
  2006-12-05 14:07             ` SZAVAI Gyula
  2006-12-06 15:52             ` Marius Vollmer
  0 siblings, 2 replies; 13+ messages in thread
From: Kevin Ryde @ 2006-12-05  0:00 UTC (permalink / raw)


"Mikael Djurfeldt" <mikael@djurfeldt.com> writes:
>
> Good idea.

I made the change.

> Because of paragraph 6.2.2, a program cannot expect to get
> the result 0.0, and it seems like a strength of the implementation to
> provide the additional piece of information that the result is indeed
> *exactly* 0.

If you wanted an argument the other way, returning a flonum zero could
give negative zero for say "(* 0 -1.0)".  But I'd favour exactness,
since the result is certainly exactly zero.

> (Not entirely sure that the common zero is a good idea, but I tend
> to think so.)

I suppose it's a question of whether "*" should do that, or leave it
up to the application.

The only case I can think of where a common zero may not be good is
with matrices, where "(* 0 matrix) => matrix" could preserve the
dimensions of the input matrix in the output matrix.  Those dimensions
could be used later "(* matrix matrix)", to signal an error if the
dimensions were incompatible.


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-05  0:00           ` Kevin Ryde
@ 2006-12-05 14:07             ` SZAVAI Gyula
  2006-12-05 15:33               ` Mikael Djurfeldt
  2006-12-06 15:52             ` Marius Vollmer
  1 sibling, 1 reply; 13+ messages in thread
From: SZAVAI Gyula @ 2006-12-05 14:07 UTC (permalink / raw)


Kevin Ryde wrote:
> "Mikael Djurfeldt" <mikael@djurfeldt.com> writes:
>   
>> (Not entirely sure that the common zero is a good idea, but I tend
>> to think so.)
>>     
>
> I suppose it's a question of whether "*" should do that, or leave it
> up to the application.
>   

I think there are 3 solution:
1, make * really generic (non-associative, no 0, no 1)
2, make * non-generic
3, document this strange behaviour

But present undocumented half-genericity is annoying.

Thanks
      s



_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-05 14:07             ` SZAVAI Gyula
@ 2006-12-05 15:33               ` Mikael Djurfeldt
  2006-12-05 15:51                 ` Ludovic Courtès
  0 siblings, 1 reply; 13+ messages in thread
From: Mikael Djurfeldt @ 2006-12-05 15:33 UTC (permalink / raw)
  Cc: bug-guile

2006/12/5, SZAVAI Gyula <szgyg@ludens.elte.hu>:
> Kevin Ryde wrote:
> > "Mikael Djurfeldt" <mikael@djurfeldt.com> writes:
> >
> >> (Not entirely sure that the common zero is a good idea, but I tend
> >> to think so.)
> >>
> >
> > I suppose it's a question of whether "*" should do that, or leave it
> > up to the application.
> >
>
> I think there are 3 solution:
> 1, make * really generic (non-associative, no 0, no 1)

In Guile, this might be tricky to do without large damage to performance.

> 2, make * non-generic

This would make it impossible to extend the arithmetic system with matrices etc.

> 3, document this strange behaviour

Absolutely.


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-05 15:33               ` Mikael Djurfeldt
@ 2006-12-05 15:51                 ` Ludovic Courtès
  2006-12-05 19:42                   ` Mikael Djurfeldt
  0 siblings, 1 reply; 13+ messages in thread
From: Ludovic Courtès @ 2006-12-05 15:51 UTC (permalink / raw)
  Cc: bug-guile

Hi,

"Mikael Djurfeldt" <mikael@djurfeldt.com> writes:

> 2006/12/5, SZAVAI Gyula <szgyg@ludens.elte.hu>:
>> Kevin Ryde wrote:
>> > "Mikael Djurfeldt" <mikael@djurfeldt.com> writes:
>> >
>> >> (Not entirely sure that the common zero is a good idea, but I tend
>> >> to think so.)
>> >>
>> >
>> > I suppose it's a question of whether "*" should do that, or leave it
>> > up to the application.
>> >
>>
>> I think there are 3 solution:
>> 1, make * really generic (non-associative, no 0, no 1)
>
> In Guile, this might be tricky to do without large damage to performance.

It would be soooo nice if some day we could have a framework to
specialize invocations, especially for arithmetic operators (e.g., like
what CMUCL and others have)...  :-)

Thanks,
Ludovic.


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-05 15:51                 ` Ludovic Courtès
@ 2006-12-05 19:42                   ` Mikael Djurfeldt
  0 siblings, 0 replies; 13+ messages in thread
From: Mikael Djurfeldt @ 2006-12-05 19:42 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 899 bytes --]

2006/12/5, Ludovic Courtès <ludovic.courtes@laas.fr>:
> It would be soooo nice if some day we could have a framework to
> specialize invocations, especially for arithmetic operators (e.g., like
> what CMUCL and others have)...  :-)

Well, we do have the things call "primitive generics"---i.e. most
procedures can behave as generic functions.  What is nice about the
system is that hanging methods for new classes on, for example, the
Guile arithmetic operators doesn't slow them down.

I attach a matrix library to this email as an example.  (See README.)
It seems to compile also under CVS HEAD.

However, of course things could be made much better if we could
redesign procedure invocation from bottom up, so that all primitive
procedures are true generic functions.  If so, most argument checking
logic which the C code for all Guile primitives start with could be
eliminated.

[-- Attachment #2: guile-matrix-1.3.0.tar.gz --]
[-- Type: application/x-gzip, Size: 432979 bytes --]

[-- Attachment #3: Type: text/plain, Size: 137 bytes --]

_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-05  0:00           ` Kevin Ryde
  2006-12-05 14:07             ` SZAVAI Gyula
@ 2006-12-06 15:52             ` Marius Vollmer
  2006-12-07 15:28               ` Mikael Djurfeldt
  1 sibling, 1 reply; 13+ messages in thread
From: Marius Vollmer @ 2006-12-06 15:52 UTC (permalink / raw)
  Cc: bug-guile

Kevin Ryde <user42@zip.com.au> writes:

> The only case I can think of where a common zero may not be good is
> with matrices, where "(* 0 matrix) => matrix" could preserve the
> dimensions of the input matrix in the output matrix.

I would have to dig for the specifics (having forgotton most of my
math by now), but 'scaling' matrices and 'multiplying' them are
actually two different operations.  They are unfortunately notated the
same. (* scalar matrix) is scaling, and (* matrix matrix) is
multiplying.  A special case of this is the more familiar vector
scaling versus the vector dot product, I think.

Thus, it makes sense to me to let the 'unknown' object in a call to an
arithmetic operation decide how to interpret it, and not doing any
shortcuts.

In general, it is not guaranteed that (* 0 something) is even
well-defined, it might be an error.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: generic * and 0
  2006-12-06 15:52             ` Marius Vollmer
@ 2006-12-07 15:28               ` Mikael Djurfeldt
  0 siblings, 0 replies; 13+ messages in thread
From: Mikael Djurfeldt @ 2006-12-07 15:28 UTC (permalink / raw)
  Cc: bug-guile, Kevin Ryde

2006/12/6, Marius Vollmer <mvo@zagadka.de>:
> Kevin Ryde <user42@zip.com.au> writes:
>
> > The only case I can think of where a common zero may not be good is
> > with matrices, where "(* 0 matrix) => matrix" could preserve the
> > dimensions of the input matrix in the output matrix.
>
> I would have to dig for the specifics (having forgotton most of my
> math by now), but 'scaling' matrices and 'multiplying' them are
> actually two different operations.

They certainly are different operations:
(C complex space, M space of matrices)

1. Scaling: C x M --> M
2. Matrix multiplikation: M x M --> M

> They are unfortunately notated the same.

That they are notated similarly on paper does not necessarily imply
that they should be notated the same way in computer code.

> (* scalar matrix) is scaling, and (* matrix matrix) is
> multiplying.  A special case of this is the more familiar vector
> scaling versus the vector dot product, I think.

It's actually a third operation:

3. Dot product: V x V --> C
(V space of vectors)

> Thus, it makes sense to me to let the 'unknown' object in a call to an
> arithmetic operation decide how to interpret it, and not doing any
> shortcuts.
>
> In general, it is not guaranteed that (* 0 something) is even
> well-defined, it might be an error.

Yes.

And I think you raise another important point: that one might want to
use the same generic function to represent different operators.

It is probably Right to make it possible for the primitive generic to
dispatch on all arguments (that is skipping the 0 and 1 trick which we
have inherited from the original SCM code).

However, doing this kind of "improvements" in an incremental manner,
given the current structure of the Guile evaluator, makes the thing
dog slow.  Also, if hanging methods on * implies performance penalty
for ordinary arithmetic, it leads to strange practise in structuring
code.

So I would vote "no" for just "fixing" this, and "yes" for a total
restructuring of invocation of primitive procedures so that they would
be true generic functions.


_______________________________________________
Bug-guile mailing list
Bug-guile@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-guile


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2006-12-07 15:28 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-29 17:58 generic * and 0 SZAVAI Gyula
2006-12-01 19:56 ` Kevin Ryde
2006-12-01 20:22   ` Mikael Djurfeldt
2006-12-01 21:52     ` Kevin Ryde
2006-12-04  0:26       ` Kevin Ryde
2006-12-04 18:26         ` Mikael Djurfeldt
2006-12-05  0:00           ` Kevin Ryde
2006-12-05 14:07             ` SZAVAI Gyula
2006-12-05 15:33               ` Mikael Djurfeldt
2006-12-05 15:51                 ` Ludovic Courtès
2006-12-05 19:42                   ` Mikael Djurfeldt
2006-12-06 15:52             ` Marius Vollmer
2006-12-07 15:28               ` Mikael Djurfeldt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).