Topic: I need a trinary operator in C++


Author: Jens Kilian <Jens_Kilian@bbn.hp.com>
Date: 1999/04/26
Raw View
F.Baldeweg@t-online.de (Falk Brettschneider) writes:
> I have a C++ class for mathematical matrices and it's called Matrix.
>
> Well, now I want to write:
>     C =3D A * B;
> to perform a matrix multiplication.
[...]
> I want to have both of them: highly efficiency and nice syntax. Is it
> possible?

Have a look at the Blitz++ library:

 http://monet.uwaterloo.ca/blitz/

If your compiler cannot handle the Blitz++ code, try the approach described
in section 22.4.7 of Stroustrup's "The C++ Programming Language", 3rd ed.

HTH,

 Jens.
--
mailto:jjk@acm.org                 phone:+49-7031-14-7698 (HP TELNET 778-7698)
  http://www.bawue.de/~jjk/          fax:+49-7031-14-7351
PGP:       06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: krigan@my-dejanews.com
Date: 1999/04/23
Raw View
Hi,
>
> I have a C++ class for mathematical matrices and it's called Matrix.
>
> Well, now I want to write:
>     C =3D A * B;
> to perform a matrix multiplication.
You can use such method:

void TrinaryXXX(matrix &c, const matrix &a, const matrix &b);

struct MatrixMul
{ const matrix     &_a, &_b;
    MatrixMul(const matrix &a, const matrix &b) : _a(a), _b(b)  {}
};

MatrixMul operator *(const matrix &a, const matrix &b)
{    return  MatrixMul(a,b);
}

matrix &operator =(matrix &c, MatrixMul &mm)
{   TrinaryXXX(c, mm._a, mm._b);
    return c;
}




-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: F.Baldeweg@t-online.de (Falk Brettschneider)
Date: 1999/04/19
Raw View
Hi,

I have a C++ class for mathematical matrices and it's called Matrix.

Well, now I want to write:
    C =3D A * B;
to perform a matrix multiplication.

Unfortunatelly this means to have an operator * and an operator =3D  and
because of the temporary matrix object in the operator* method I have to
do some extra operations:
1. one constructor of the temporary object in operator*
2. one copy constructor call when I return the temporary object in
operator*
3. one destructor of the temporary object in operator*
4. the whole operator=3D call

One could say: "Don't use this syntax for multiplication. Use this:
    C.mult( A, B);
".
Okay this works fine and is more efficient but but this looks not so
nice as the syntax from above.

I want to have both of them: highly efficiency and nice syntax. Is it
possible?

I think I could define a trinary operator =3D*
Matrix& operator=3D*( Matrix& A, Matrix& B)
to make this call possible:
C =3D A * B;

Is this right? Can this be?
I saw trinary operators in JAVA but no equivalent in C++.
--


Tsch=FCs,
--Falk

-----------------
Falk Brettschneider
mailto:gigafalk@geocities.com
http://www.geocities.com/SiliconValley/Station/4004
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/04/19
Raw View
In article <371B0C34.D5E74F88@geocities.com>,
  F.Baldeweg@t-online.de (Falk Brettschneider) wrote:
> Hi,
>
> I have a C++ class for mathematical matrices and it's called Matrix.
>
> Well, now I want to write:
>     C =3D A * B;
> to perform a matrix multiplication.
>
> Unfortunatelly this means to have an operator * and an operator =3D  and
> because of the temporary matrix object in the operator* method I have to
> do some extra operations:
> 1. one constructor of the temporary object in operator*
> 2. one copy constructor call when I return the temporary object in
> operator*
> 3. one destructor of the temporary object in operator*
> 4. the whole operator=3D call
OK, how about this then:

C=A;  // Or Matrix C(A); if it's an initialization
C*=B;

The only members that will get invoked will be op= and op*.  No temporaries,
no copy constructors.

--
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post here.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jonathan Biggar <jon@floorboard.com>
Date: 1999/04/19
Raw View
Falk Brettschneider wrote:
> Well, now I want to write:
>     C = A * B;
> to perform a matrix multiplication.
>
> Unfortunatelly this means to have an operator * and an operator =  and
> because of the temporary matrix object in the operator* method I have to
> do some extra operations:
> 1. one constructor of the temporary object in operator*
> 2. one copy constructor call when I return the temporary object in
> operator*
> 3. one destructor of the temporary object in operator*
> 4. the whole operator= call
>
> One could say: "Don't use this syntax for multiplication. Use this:
>     C.mult( A, B);
> ".
> Okay this works fine and is more efficient but but this looks not so
> nice as the syntax from above.
>
> I want to have both of them: highly efficiency and nice syntax. Is it
> possible?
>
> I think I could define a trinary operator =*
> Matrix& operator=*( Matrix& A, Matrix& B)
> to make this call possible:
> C = A * B;
>
> Is this right? Can this be?
> I saw trinary operators in JAVA but no equivalent in C++.

There is a way to make this work.  Define all of your arithmetic
operators (*, +, -, etc) to return a new class called MatrixOperation.
This class just stores a representation of the operation to perform,
rather than actually doing the operation.  Then you define
operator=(const MatrixOperation &) to parse the information in
MatrixOperation and perform the actual arithmetic.  The definition of
operator=() can recognize special patterns like C = A * B and perform
the approporiate optimizations.

--
Jon Biggar
Floorboard Software
jon@floorboard.com
jon@biggar.org
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Chris Hines" <chrishines@email.msn.com>
Date: 1999/04/19
Raw View
One approach to solving your problem is a technique known as Expression
Templates.  Todd Veldhuizen wrote an article about the technique in C++
Report.  His article was republished in the book "C++ Gems" published by
SIGS.  If you don't already have the book it should still be available in
bookstores.  IMHO it is worth having.

I just did a search on AltaVista, you can look at:

http://www.cup.org/sgs/0135705819.html

for more info about the book.

You can also look at:

http://monet.uwaterloo.ca/~tveldhui/papers/Rapid-Linear-Algebra/rapid-linear
-algebra.html

for a full article by Todd on the same topic that was published in Dr.
Dobbs.

And finally, another version of Todd's material can be found at:

http://www.roguewave.com/products/resources/exchange/extempl.html

--
    Chris Hines
    The sooner you start coding, the longer it will take you to finish.

Falk Brettschneider <F.Baldeweg@t-online.de> wrote in message
news:371B0C34.D5E74F88@geocities.com...
Hi,

I have a C++ class for mathematical matrices and it's called Matrix.

Well, now I want to write:
    C = A * B;
to perform a matrix multiplication.

Unfortunatelly this means to have an operator * and an operator =  and
because of the temporary matrix object in the operator* method I have to
do some extra operations:
1. one constructor of the temporary object in operator*
2. one copy constructor call when I return the temporary object in
operator*
3. one destructor of the temporary object in operator*
4. the whole operator= call

One could say: "Don't use this syntax for multiplication. Use this:
    C.mult( A, B);
".
Okay this works fine and is more efficient but but this looks not so
nice as the syntax from above.

I want to have both of them: highly efficiency and nice syntax. Is it
possible?

I think I could define a trinary operator =*
Matrix& operator=*( Matrix& A, Matrix& B)
to make this call possible:
C = A * B;

Is this right? Can this be?
I saw trinary operators in JAVA but no equivalent in C++.
--


Tsch   s,
--Falk

-----------------
Falk Brettschneider
mailto:gigafalk@geocities.com
http://www.geocities.com/SiliconValley/Station/4004
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "AllanW {formerly AllanW@my-dejanews.com}" <allan_w@my-dejanews.com>
Date: 1999/04/19
Raw View
In article <7ff8um$5h1$1@nnrp1.dejanews.com>,
  Jim Hyslop <jim.hyslop@leitch.com> wrote:
> In article <371B0C34.D5E74F88@geocities.com>,
>   F.Baldeweg@t-online.de (Falk Brettschneider) wrote:
> > Hi,
> >
> > I have a C++ class for mathematical matrices and it's called Matrix.
> >
> > Well, now I want to write:
> >     C = A * B;
> > to perform a matrix multiplication.
> >
> > Unfortunatelly this means to have an operator * and an operator = and
> > because of the temporary matrix object in the operator* method I have to
> > do some extra operations:
> > 1. one constructor of the temporary object in operator*
> > 2. one copy constructor call when I return the temporary object in
> > operator*
> > 3. one destructor of the temporary object in operator*
> > 4. the whole operator= call

> OK, how about this then:
>
> C=A;  // Or Matrix C(A); if it's an initialization
> C*=B;
>
> The only members that will get invoked will be op= and op*.  No temporaries,
> no copy constructors.

Well, there's still either assignment or copy of A into C, before the
multiplication is done. Also, can Matrix multiplication be done in-place?
Finally, since we don't know any details about Matrix, let's assume that
once it's initialized to a certain size it can't be re-initialized to
some other size. If I remember correctly, multiplying a 4x9 matrix by a
9x20 matrix results in a 4x20 matrix. And yet your version would initialize
C to 4x9 instead of 4x20.

Falk Brettschneider seems to want to know about proxy return types.
Since this is a matter of technique rather than standards, I have
set the followups for this message to comp.lang.c++ only.

The idea in proxy return types is that instead of returning the real
result, you return an instanciation of a class that "knows" how to
get the result. It also saves any information needed to accomplish
this. Then, for each possible way to use the result, you define a
member function in the proxy class to perform the computation.

In your example, Matrix, we would have operator* return a proxy class
called Product. Product would contain references to the actual data
to be manipulated, but it wouldn't actually calculate the result until
that result was ready to be used. For the moment I'll assume that the
only way we ever use the result is to store it in a Matrix.

So we have, for example:

    class Matrix {
        // ... Usual stuff here: Ctor, Dtor, copy ctor, op=, and so on.
    public:
        // This function sets the matrix to the result of multiplying
        // two other matrices. Unfortunately, it's syntax isn't ideal.
        // To solve the mathematical equation A = B * C (with A unknown)
        // we use:
        //     A.CalcProduct(B,C);
        // Note that the function allows aliasing; that is,
        //     A.CalcProduct(A,A);
        // is perfectly legal for a square matrix, and will give the
        // usual mathematical results.
        CalcProduct(const Matrix &lhs, const Matrix &rhs); // Not shown
        // The rest of the stuff below is an attempt to allow "Normal"
        // syntax to end up calling CalcProduct when appropriate.

    private:
        // This is the proxy class. It's a private class becase we
        // don't want client code using it directly (see discussion
        // below). While an instance of this class exists, we know
        // that a multiplication needs to be done, but we have
        // delayed doing it until we know where the result goes.
        // The constructor saves all the information needed to do
        // the multiplication later, which is our only need for
        // data members.
        // We use struct (instead of class) to make all members
        // public (to Matrix class). Since the class itself is
        // private to Matrix, no code outside of the class can see
        // it. This is as it should be; the proxy class is an
        // implementation detail, not intended to be used by clients.
        struct Product {
            const Matrix &lhs;
            const Matrix &rhs;
            Product(const Matrix&l, const Matrix &r) : lhs(l), rhs(r) {};
        };

    public:
        // Operator* creates a Product proxy so that the multiplication
        // will be done later. This *MUST* be returned by value, but
        // since it contains nothing except two references, this will
        // not be a performance bottleneck.
        Product operator*(const Matrix&lhs, const Matrix&rhs)
            { return Product(lhs, rhs); }

        // This function resolves the expression
        //     A=B*C;
        // where A,B,C are all Matrixes. The sub-expression (B*C)
        // created a Product proxy without actually doing the
        // multiplication. Now that we know where the result will
        // be stored, we can perform the multiplication in-place.
        Matrix &operator=(Proxy &p) {
            CalcProduct(p.lhs, p.rhs);
            return *this;
        }

        // This function resolves expressions such as
        //     Matrix A=B*C;
        // or
        //     Matrix *A = new Matrix(B*C);
        // where we construct a new matrix A (or *A) from the product
        // of two other Matrixes B and C. The sub-expression (B*C)
        // created a Product proxy without actually doing the
        // multiplication. Now that we know where the result will
        // be stored, we can perform the multiplication in-place.
        Matrix(Proxy &p) {
            CalcProduct(p.lhs, p.rhs);
        }
    };

The good news is that every function except for CalcProduct is in-line,
so the compiler should be able to optimize it away. The result is very
nearly as good as if you had used the more awkward syntax.

The bad news is, every single thing that you can do with a product
must be handled. For instance, as written above the statement
    A = B + C*D;
will generate an error. (Couldn't find a suitable overload for
operator+(Matrix,Matrix::Product). If you want that expression to
be processed properly, you must define
    Matrix::operator+(Matrix&, Matrix::Product&)
This too can return proxy classes, such as SumProduct, if you have the
time and patience. But certainly you can see that there are an infinite
number of possible expressions, while you can only write a finite number
of proxy classes and functions that accept them. Still, the only limit
to how far to take this is your own patience and the laws of
diminishing returns.

Meanwhile, every case you didn't think of won't compile at all. You can
solve that problem by defining Product::operator Matrix(), which will
allow any product to convert to a matrix for normal (non-optimized) use.
    operator Matrix(Matrix::Product&p) {
        Matrix m=p.lhs;
        m.CalcProduct(m,p.rhs);
        return m;
    }
Now the expression A = B + C*D will work. First it calls Matrix::operator*
to create the proxy object. Then, since there's no such thing as
operator+(Matrix,Matrix::Product), it will convert the second argument
from a Product to a Matrix and then perform the normal operator+
analysis. This us not optimized, but at least it will work correctly.

----
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: brahms@mindspring.com (Stan Brown)
Date: 1999/04/19
Raw View
Dixitque F.Baldeweg@t-online.de (Falk Brettschneider) in comp.std.c++:
>Well, now I want to write:
>    C =3D A * B;
>to perform a matrix multiplication.

Please consider turning off "quoted-printable" in your news software. Q-P
is responsible for turning an equal sign that you type into the three
characters equal, 3, D -- does not help comprehension! (Q-P has other bad
effects too.)

--
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA
                                    http://www.mindspring.com/~brahms/
My reply address is correct as is. The courtesy of providing a correct
reply address is more important to me than time spent deleting spam.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/04/20
Raw View
In article <371B0C34.D5E74F88@geocities.com>,
  F.Baldeweg@t-online.de (Falk Brettschneider) wrote:

> I saw trinary operators in JAVA but no equivalent in C++.

The only trinary operator in Java is ?:, just as in C++.  And you can't
overload it in either language.

--
James Kanze                         mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86 27

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]