UBLAS: copy on write for matrix & vector?
A question on use of the matrix and vector classes: Should I: matrix<double> foo(const matrix<double> a) { matrix >double> r; ... return r; } or void foo(matrix<double>& r, const matrix<double> a) { ... } In other words: is it expensive to construct the temporary in case one? As I understand, the class would need an underlying 'copy on write' to be cheap, similar as strings do. I tried, to answer this question from the documentation, but sorry I did not get through. Thank you for help. Roland
----- Original Message ----- From: Ivan Vecerina To: boost-users@yahoogroups.com Sent: Thursday, February 13, 2003 3:41 PM Subject: [Boost-Users] Re: UBLAS: copy on write for matrix & vector?
wrote in message news:b2g7nj+6gee@eGroups.com... | A question on use of the matrix and vector classes: | | Should I: ... | matrix<double> foo(const matrix<double> a) ... | void foo(matrix<double>& r, const matrix<double> a) ... | In other words: is it expensive to construct the temporary in case | one? As I understand, the class would need an underlying 'copy on | write' to be cheap, similar as strings do. By default, the copy constructor of boost::numeric::ublas::matrix appears to copy its representation in a newly allocated block. As far as I can tell, this behavior could be customized by using a custom storage type (the third template parameter).
Yup. One could play ugly games with class array_adaptor<> for example, but I'd tend to advise against it.
However, many optimizing compilers are able to eliminate unnecessary copying of the return value of a function. (This is called RVO or NRVO for Return Value Optimization and Named..., depending on how the function is written). For example, MSVC suppresses the unnecessary copy, even in Debug mode with no optimizations enabled.
So I think you should prefer the interface which is more natural to use: matrix<double> foo(const matrix<double> a)
Generally agreed, although ublas' bench1 shows, what can happen (especially for small dimensions) if temporaries are involved. Thanks, Joerg
First thank you for help, but I still find it very hard to use the ublas (yes I am somewhat between an oldie and newbie). I tried to find out what is happening in the case: matrix<double> foo() { matrix<double> r(3); return r; } ... r1 = foo(); The matrix (that was constructed on the stack) is copied twice when used in this manner. One copy for the returned temporary, a second copy for the assignment. (I am using MSVC debug mode) And this definitely is not a cheap operation. Both in terms of memory _and_ execution time. Also a second question comes to me now: Can I define a LHS that can be the target of an arbitrary size matrix? I.e.: matrix<double> lhs; matrix<doubel> rhs(3,3); lhs = rhs; will give a runtime exeception because of different size. Can I do anything about this? I have the feeling, that I still do not well understand the overall semantics of the matrix and vector classes. Are there any books/examples which I can study to get a better understanding? Thank you again, Roland
Hi Ivan, you've been faster again ;-). You wrote:
wrote in message news:b2nq2e+jht8@eGroups.com... | I tried to find out what is happening in the case: | | matrix<double> foo() | { | matrix<double> r(3); | return r; | } ... | r1 = foo(); | | The matrix (that was constructed on the stack) is copied twice when | used in this manner. One copy for the returned temporary, a second | copy for the assignment. (I am using MSVC debug mode) And this | definitely is not a cheap operation. Both in terms of memory _and_ | execution time. The first copy indicates that MSVC (6?) could not apply the NRVO optimization. It may support the RVO optimization though: you could try using direct returns when possible: return matrix<double>(3);
The second copy will be avoided by the compiler if you use construction of a new variable instead of assignment: matrix<double> r1 = foo(); // shall avoid 2nd copy or: matrix<double> const& r2 = foo(); // always optimized // but can trigger a VC7 bug
I agree these alternatives are not fully equivalent, but they are coding style tricks that can be useful to improve performance.
Besides the question, when which compiler uses RVO: if Roland needs uttermost performance using similar interfaces, we'll either have to add the mojo protocol or he should try to extend the expression template machinery.
| Also a second question comes to me now: | Can I define a LHS that can be the target of an arbitrary size matrix? | I.e.: | matrix<double> lhs; | matrix<doubel> rhs(3,3); | | lhs = rhs; | | will give a runtime exeception because of different size. Can I do | anything about this?
Yes. Four ways: 1. matrix<double> lhs(3,3); matrix<double> rhs(3,3); lhs = rhs; 2. matrix<double> rhs(3,3); matrix<double> lhs(rhs); 3. matrix<double> lhs; matrix<double> rhs(3,3); lhs.resize(3,3); lhs = rhs; 4. matrix<double> lhs; matrix<double> rhs(3,3); lhs.reset(rhs);
I'm not a UBLAS expert. But here also, declaring variables where they are initialized would solve the problem, and provide best performance: matrix<double> const lhs = rhs; // drop the 'const' if required
This is the usually recommended C++ style. And to go back to your original question, it requires that toutines *return* their result instead of taking output parameters. ( but I cannot certify that boost's UBLAS was developed with this in mind )
| I have the feeling, that I still do not well understand the overall | semantics of the matrix and vector classes.
uBLAS assumes that vectors and matrices in an assignment have conforming dimensions. Copy semantics are deep.
|Are there any | books/examples which I can study to get a better understanding?
There probably are no books about this. For examples one could look into Michael Stevens' Bayesian Filters at www.sf.net/projects/bayesclasses or Paul C. Leopardi's Clifford Algebras at www.sf.net/projects/glucat
I won't be of much help here. I admit I don't use UBLAS personally. ( I use small fixed-size matrices in my current applications ). But, I home some of the suggestions above may still help...
Thanks, Joerg [Non-text portions of this message have been removed]
On Monday 17 February 2003 19:21, Ivan Vecerina wrote:
The second copy will be avoided by the compiler if you use construction of a new variable instead of assignment: matrix<double> r1 = foo(); // shall avoid 2nd copy or: matrix<double> const& r2 = foo(); // always optimized // but can trigger a VC7 bug
Here you're taking a const-reference to a temporary.
From the moment you're using r2 you have 'undefined behaviour' IMHO.
t
"Toon Knapen"
On Thursday 13 February 2003 14:48, "speedsnaii wrote:
A question on use of the matrix and vector classes: In other words: is it expensive to construct the temporary in case one? As I understand, the class would need an underlying 'copy on write' to be cheap, similar as strings do.
matrices and vectors (the containers themselves) have deep copy semantics. Views (like matrix_range, matrix_stride, matrix_row etc) have shallow copy semantics. So if you want to pass a matrix by value (syntacticly) but want shallow copy semantics, just define a matrix_range on your matrix that covers the whole matrix and use this in the argument list. toon
participants (4)
-
Ivan Vecerina
-
jhr.walter@t-online.de
-
speedsnaii <speedsnaii@yahoo.de>
-
Toon Knapen