April 21, 2004
Ben Hinkle wrote:
> Eventually array arithmetic will act element-wise, so I would design Matrix so that * mean element-wise multiply. That would work fine with commutativity. I suspect another operator will eventually be added to D to mean "non-commutative multiply" something like ** so that Matrix multiply is the regular sense would use **.

There is no point in elementwise multiplying two matrices. Of course, a Matrix implementation would use some elementwise operation internally on the array that it encapsulates. Anyhow, that is an implementation issue. To the outside, Matrix should only have one multiplication, and that is the Matrix multiplication.

> For example, the language R uses %*% for matrix mult, %o% for inner product, %x% for outer product.

You can save all these if you work with column- and rowvectors. r*c means inner product, c*r is an outer product, resulting in a matrix. r*r or c*c don't exist. To convert between the two, you just transpose them (or even better adjungate them, then you are safe even for complex stuff)

Of course, this all works only for plain 2-d matrices, but for higher dimensional object, you need to use indices anyway.

Distinguishing between row- and columnvectors seems awkward at first, but once you are used to it, you realize that things get a lot easier.

I would really hate it to see n different multiplication operators, when actually, the types of the operands tell you everything you need.
April 21, 2004
The point is that the D compiler is allowed make B*A out of A*B. which is not equivalent in the case of matrix multiplication.

-- 
Jan-Eric Duden
"J Anderson" <REMOVEanderson@badmama.com.au> wrote in message
news:c65p09$i3u$1@digitaldaemon.com...
> Jan-Eric Duden wrote:
>
> >Uhm. That depends how you interpret the matrices - as row vectors or as column vectors.
> >
> >
> You just make a choice and stick with it (row/col is pretty standard ie
> x/y).  It all depends on how you see the array.  You'll have that
> *problem* in any language.
> a * vec3
> vec3 * a
>
> >In any case, your program proofs as well that b*a != a*b !
> >
> >
> And so it should.  Sorry I'm not quite sure if you understand that D works for matrices yet or not?
>
> Really, download undig from my website and look at the math.d file. It's really quite complete.
>
> -- 
> -Anderson: http://badmama.com.au/~anderson/


April 21, 2004
Norbert Nemec wrote:

>OK, now, this actually boils down the problem even further. It only leaves
>cases where one of the two operand types is not accessible to add the
>multiplication. I can think of three possible reasons for that:
>
>* one of the types is a primitive. (I don't know of any mathematical object
>that does not commute with scalars, but who knows?)
>  
>
I don't know of any mathematical object that does not commute with scalars, but who knows?
Exactly.  If you really needed you can box.

>* you cannot or do not want to touch the sourcecode of one of the types -
>here I have not enough insight whether delegates might solve this and if
>this solution is elegant and efficient enough to justify the inhibition of
>opMult_r
>
>Allowing opMult_r would not cost anything than a minor change in the
>language definition and the implementation. It would break no existing code
>at all and finish this kind of discussion.
>
>  
>
It would cost something.  We would have C++ where operators are used for anything.  Anyhow I've shown how this can be overcome.

It's not impossible, just hard to do because most of the time you don't need it (and if you do there is probably something wrong in your design).




-- 
-Anderson: http://badmama.com.au/~anderson/
April 21, 2004
Actually, no. I thought so myself (that's why I started the thread) but
        http://www.digitalmars.com/d/operatoroverloading.html
explicitely states the rules after which the compiler determines which code
to use. Writing
        A*B
then first A.opMul(B) is checked. Only if this does not exist, B.opMul(A) is
called. This solves the problem, if the library author takes care not to
forget any definitions. Only in that case the compiler might swap factors
without a warning.

The only thing that may still be discussed, and will probably pop up over and over again until Walter gives in, is the question of opMul_r and opAdd_r. I believe it would make sense to allow those and check them before commuting factors, but I can live without them.

Jan-Eric Duden wrote:

> The point is that the D compiler is allowed make B*A out of A*B. which is not equivalent in the case of matrix multiplication.


April 21, 2004
Jan-Eric Duden wrote:

>The point is that the D compiler is allowed make B*A out of A*B.
>  
>
That is not true!  Because mat3 is multiplied by itself you automaticly get the non-commutative.  If for example you had mat3 (A) and mat4 (B) then you'd need to write 2 overloads to make them non-commutative between the two (of course you can't multiply m3xm4 unless you use in the 16th pos in mat3 with 1).  In C++ you would also have to write at least 2 overloads (probably more) to do the same thing.  So all D is doing is putting in a *default* commutative method for all types which you can take out by specifying the other side.

>which is not equivalent in the case of matrix multiplication.
>  
>
This is true and is possible in D.

-- 
-Anderson: http://badmama.com.au/~anderson/
April 21, 2004
J Anderson wrote:

> Jan-Eric Duden wrote:
>
>> As far as I understand the docs, this is not correct:
>> opAdd and opMul are supposed to be commutative. There is no opAdd_r or
>> opMul_r.
>> see http://www.digitalmars.com/d/operatoroverloading.html : Overloadable
>> Binary Operators
>>
> It's a miss-understanding.  Sure if the other class doesn't define the opposite overload then D will swap the things around to make it work (this is a feature rather then a con). But that's just a semantic bug on the programmers part.
>
> class A { opMul(B) {} }
>
> class B
> {
>    opMul(A) {} //If this is omitted then D will make things commutative. Otherwise you essentially have non-commutative.
> }
>
> Therefore opMul_r isn't nessary.  This question has been asked a couple of times in the group.  So far I've seen no one show a coded example (or a mathematical type) that defeats this stradagie.  And matrices definatly aren't one.
>
> Now one problem I do see is if the programmer doesn't have access type A and B to add there own types (of course they can overload) but that's a different issue.   I guess it be solved done using delegates though.
>
Actually I didn't mean delegates.  I mean something like:

interface A { B opMyMul(B);  }

class B {
B opMul (A a) { return a.opMyMul(this); }

}

Problem solved.  But most of the time you shouldn't need that.


-- 
-Anderson: http://badmama.com.au/~anderson/
April 21, 2004
But then, In the documentation the word "commutative" should not be used
with opMul and opAdd !
Because they don't need to be commuative!

-- 
Jan-Eric Duden
"Norbert Nemec" <Norbert.Nemec@gmx.de> wrote in message
news:c660ah$uef$1@digitaldaemon.com...
> Actually, no. I thought so myself (that's why I started the thread) but
>         http://www.digitalmars.com/d/operatoroverloading.html
> explicitely states the rules after which the compiler determines which
code
> to use. Writing
>         A*B
> then first A.opMul(B) is checked. Only if this does not exist, B.opMul(A)
is
> called. This solves the problem, if the library author takes care not to forget any definitions. Only in that case the compiler might swap factors without a warning.
>
> The only thing that may still be discussed, and will probably pop up over and over again until Walter gives in, is the question of opMul_r and opAdd_r. I believe it would make sense to allow those and check them
before
> commuting factors, but I can live without them.
>
> Jan-Eric Duden wrote:
>
> > The point is that the D compiler is allowed make B*A out of A*B. which is not equivalent in the case of matrix multiplication.
>
>


April 21, 2004
Jan-Eric Duden wrote:

>But then, In the documentation the word "commutative" should not be used
>with opMul and opAdd !
>Because they don't need to be commuative!
>
They are commutative by default that is, they don't need an _r operator.  I feel like an echo.

-- 
-Anderson: http://badmama.com.au/~anderson/
April 21, 2004
J Anderson wrote:
> It would cost something.  We would have C++ where operators are used for anything.  Anyhow I've shown how this can be overcome.

If you look at "cost" in terms of language and compiler complexity, it would not cost anything. The comfort for the programmer would also stay the same, since current code would just work as now. As long as you don't use opMul_r, you don't have to worry about it. As long as you use only commuting objects, there will never be any reason for opMul_r.

If you - as I understand your remark - consider "cost" the increased danger of abuse of language constructs (Meaning evil programmers defining "*" operators that have nothing to do with multiplication.) then the existance of opMul_r and opAdd_r will change little.

Therefore I really don't understand why you say "Allowing opMul_r would cost something."

So, if opMul_r does not cost anything, I don't see any reason to try to find out whether you can work around it in any case. If anybody ever needs to box a scalar or take the pains of using delegates or whatever means just because someone decided that opMul_r is "unnecessary", then clearly this decision was wrong.
April 21, 2004
J Anderson wrote:

> Jan-Eric Duden wrote:
> 
>>But then, In the documentation the word "commutative" should not be used
>>with opMul and opAdd !
>>Because they don't need to be commuative!
>>
> They are commutative by default that is, they don't need an _r operator.  I feel like an echo.

Sorry, I feel like repeating myself all the time, too, but this last statement just was incorrect.

It should be:

"They are commutative by default, so if your objects do commute, you can drop the opfunc_r (because it would be identical to opfunc). For noncommuting objects, opfunc_r would be different from opfunc, but unfortunately you are still not allowed to define it and therefore have to work around it. This is trivial, if you can just put the definition in the other class as opfunc, but tricky to impossible if you cannot."