Small matrix/vector library (ET, swizzling, SSE)

I've just uploaded my matrix/vector library to the vault (math2-matrix-vector, under Math - Geometry). It's a library I was working on for a very long time a few years back, trying to find the computationally most efficient one possible. The reason I haven't shared it earlier is that I've come to believe that keeping it simple is better, but now I see that vector swizzling is being discussed, so... The library uses expression templates for all componentwise operations (so v1 = 2*v2 + v3 can be evaluated with no temporaries greater than a float), has support for SSE2 vector intrinsics, and supports some element reordering operations, including lvalue vector swizzling (v[zw] = vector<2>(1,2) works). Not all swizzlings are named, but if the one you happen to want is not provided then it is easy to create: const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx; vector<4> v1, v2(1,2,3,4); v1 = v2[xxzx]; // v1 = (1,1,3,1) v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1) Overall, I've found swizzling somewhat convenient, but far from necessary. Nearly every time I used it it was to isolate xyz in a 4-component vector. -- Daniel Wesslén

Daniel Wesslén wrote:
Not all swizzlings are named, but if the one you happen to want is not provided then it is easy to create: <snip example>
Apologies - the required header isn't exactly obvious (matrix.h includes definitions of matrix and vector, but matrix.tpp is required for the operations.) This should do it: #include <math/matrix.tpp> using namespace math; int main() { const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx; vector<4> v1, v2(1,2,3,4); v1 = v2[xxzx]; // v1 = (1,1,3,1) // v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1) } -- Daniel Wesslén

Am Sonntag, den 03.12.2006, 13:15 +0100 schrieb Daniel Wesslén:
This should do it:
#include <math/matrix.tpp> using namespace math;
int main() {
const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx;
vector<4> v1, v2(1,2,3,4);
v1 = v2[xxzx]; // v1 = (1,1,3,1) // v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1)
}
I'm sorry if it was mentioned before, but g++ 3.4.6/ 4.1.1/ 4.2.0-alpha20061031 don't compile this <at math2-matrix-vector/src> g++-4.1.1 test.cc -I../include </at math2-matrix-vector/src> <error message> ../include/math/bits/basic_matrix.h: In member function 'Type math::bits::basic_matrix<Rows, Cols, Type>::element() const': ../include/math/bits/basic_matrix.h:27: error: there are no arguments to 'data' that depend on a template parameter, so a declaration of 'data' must be available ../include/math/bits/basic_matrix.h:27: error: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated) ../include/math/bits/basic_matrix.h: In member function 'Type& math::bits::basic_matrix<Rows, Cols, Type>::element()': ../include/math/bits/basic_matrix.h:31: error: there are no arguments to 'data' that depend on a template parameter, so a declaration of 'data' must be available ../include/math/bits/tmatrix.h: In constructor 'math::tmatrix_dim<Rows, Cols, Base, Type>::tmatrix_dim(typename math::bits::if_bool_type<((Rows == 1) && (Cols == 1)), const Type&, math::tmatrix_dim<Rows, Cols, Base, Type>::dummy>::type)': ../include/math/bits/tmatrix.h:38: error: 'element' was not declared in this scope ../include/math/bits/tmatrix.h:38: error: expected primary-expression before ')' token ../include/math/bits/tmatrix.h: In member function 'math::tmatrix_dim<Rows, Cols, Base, Type>::operator typename math::bits::if_bool_type<((Rows == 1) && (Cols == 1)), Type&, math::tmatrix_dim<Rows, Cols, Base, Type>::dummy>::type()': ../include/math/bits/tmatrix.h:74: error: 'element' was not declared in this scope ../include/math/bits/tmatrix.h:74: error: expected primary-expression before ')' token ../include/math/constants.h: At global scope: ../include/math/constants.h:13: error: uninitialized const 'math::identity' ../include/math/constants.h:16: error: uninitialized const 'math::zero' </error message> Regards, Maik

Maik Beckmann wrote:
#include <math/matrix.tpp> using namespace math;
int main() {
const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx;
vector<4> v1, v2(1,2,3,4);
v1 = v2[xxzx]; // v1 = (1,1,3,1) // v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1)
}
I'm sorry if it was mentioned before, but g++ 3.4.6/ 4.1.1/ 4.2.0-alpha20061031 don't compile this
<at math2-matrix-vector/src> g++-4.1.1 test.cc -I../include </at math2-matrix-vector/src>
<error message> ../include/math/bits/basic_matrix.h: In member function 'Type math::bits::basic_matrix<Rows, Cols, Type>::element() const': ../include/math/bits/basic_matrix.h:27: error: there are no arguments to 'data' that depend on a template parameter, so a declaration of 'data' must be available
[snip more error messages] Has it been that long since I tested this on gcc? Changing "data()" on the offending lines to "this->data()" should do it, though I'm afraid I can't guarantee there won't be other errors like it at the moment. Use -fpermissive as suggested if you want to try it out for now. Thanks. -- Daniel Wesslén

Am Dienstag, den 05.12.2006, 11:41 +0100 schrieb Daniel Wesslén:
Has it been that long since I tested this on gcc? Changing "data()" on the offending lines to "this->data()" should do it, though I'm afraid I can't guarantee there won't be other errors like it at the moment. Use -fpermissive as suggested if you want to try it out for now.
Thanks.
-- Daniel Wesslén
(1)Note that I'm not an experienced developer! chaning data() to this->data() causes also no need for -fpermissive anymore. I made additionally changes to get it compiled: tmatrix.h: element ==> Base::template element constants.h: commented typeless constants zero and identity since this triggers.. <error> ../include/math/constants.h:14: error: uninitialized const 'math::identity' ../include/math/constants.h:17: error: uninitialized const 'math::zero' </error> I'm not sure if the syntax classname::template template_member is the correct answer to the problem, since I didn't see this very often (but consider (1) ;o) ). Thanks for posting this Library. It would be wonderful if the gcc support gets updated. Best Regards, Maik Beckmann

Am Dienstag, den 05.12.2006, 12:36 +0100 schrieb Maik Beckmann:
(1)Note that I'm not an experienced developer!
chaning data() to this->data() causes also no need for -fpermissive anymore.
I made additionally changes to get it compiled:
tmatrix.h: element ==> Base::template element
constants.h: commented typeless constants zero and identity since this triggers.. <error> ../include/math/constants.h:14: error: uninitialized const 'math::identity' ../include/math/constants.h:17: error: uninitialized const 'math::zero' </error>
I'm not sure if the syntax classname::template template_member is the correct answer to the problem, since I didn't see this very often (but consider (1) ;o) ).
Thanks for posting this Library. It would be wonderful if the gcc support gets updated.
Best Regards, Maik Beckmann
If the constants zero and identity are not commented but initialized like suggested by gcc constants.h: const identity_t identity = identity_t(); const zero_t zero = zero_t(); matrix2.cpp matrix3.cpp, matrix.cpp compile as well. Regards, Maik

Maik Beckmann wrote:
I'm not sure if the syntax classname::template template_member is the correct answer to the problem, since I didn't see this very often (but consider (1) ;o) ).
Thanks for posting this Library. It would be wonderful if the gcc support gets updated.
That is indeed the correct answer. I found some more instances of the same problem and fixed them as well, and compiled successfully on Apple's GCC 4.0.1. I've updated the file in the vault. (While at it, I removed matrix.tpp - matrix.h brings in the operations as well now.) -- Daniel Wesslén

On 12/3/06, Daniel Wesslén <daniel@wesslen.org> wrote:
Not all swizzlings are named, but if the one you happen to want is not provided then it is easy to create:
const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx; vector<4> v1, v2(1,2,3,4); v1 = v2[xxzx]; // v1 = (1,1,3,1) v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1)
I really dislike that syntax. Feel free to make use of the swizzle code generation macros I posted in the Vault. They generate all possible combinations so users don't have to make instances of your index_swizzle classes. You would want to replace the SWIZZLE_BODY macro with your own. It simply takes in the next permutation as a sequence, e.g. (z)(w)(y). The only downside is that there will be no compile-time error in situations like your //error line from above. v1.xxzx() = v2; // compiles, but doesn't make too much sense You could try to determine how the function was being used (read vs write) and only allow write masks for combinations where each vector component was only specified once: v1.xxzx() = v2; // fails to compile v1.wxzy() = v2; // compiles or you could throw an exception from the assignment operator if any of the invoking class's references were aliased. I much prefer the compile-time solution (if one exists?). --Michael Fawcett

Michael Fawcett wrote:
On 12/3/06, Daniel Wesslén <daniel@wesslen.org> wrote:
Not all swizzlings are named, but if the one you happen to want is not provided then it is easy to create:
const indexer<bits::index_swizzle<0,0,2,0> > xxzx; const indexer<bits::index_swizzle<3,2,1,0> > wzyx; vector<4> v1, v2(1,2,3,4); v1 = v2[xxzx]; // v1 = (1,1,3,1) v1[xxzx] = v2; // error - v1[xxzx] is not a lvalue due to aliasing v1[wzyx] = v2; // v1 = (4,3,2,1)
I really dislike that syntax. Feel free to make use of the swizzle code generation macros I posted in the Vault. They generate all possible combinations so users don't have to make instances of your index_swizzle classes. You would want to replace the SWIZZLE_BODY macro with your own. It simply takes in the next permutation as a sequence, e.g. (z)(w)(y).
The only downside is that there will be no compile-time error in situations like your //error line from above.
v1.xxzx() = v2; // compiles, but doesn't make too much sense
Fair enough. I much prefer my syntax to yours, but the main reason for posting was simply to present another way to do it - both syntax and implementation. Obviously I could also generate all indexing objects, but in my experience (~3 years of using this library in computer graphics), xy and xyz are the only swizzlings (if you can even call them that) that's seen any significant use. -- Daniel Wesslén

On 12/5/06, Daniel Wesslén <daniel@wesslen.org> wrote:
Michael Fawcett wrote:
I really dislike that syntax.
Fair enough. I much prefer my syntax to yours, but the main reason for posting was simply to present another way to do it - both syntax and implementation.
Fair enough :) I guess my last question is (not to you directly, just Boost developers in general) - I wonder if either of our swizzle implementations would be considered useful to ublas or MTL ( http://osl.iu.edu/research/mtl/ )? I use swizzling all the time (and more than just xyz) but it's in actual shaders using Cg, not C++ code. I'm not sure if that's because I have never had them exposed to me in C++, or if I have just not needed them. I think swizzling tends to be used mostly in graphics programming, and neither ublas nor MTL describe that as their problem domain. Perhaps it's too specific to be included with those libraries. I notice that that Vault - Graphics folder is empty...maybe some OpenGL work needs to be done. --Michael Fawcett

Michael Fawcett wrote:
I guess my last question is (not to you directly, just Boost developers in general) - I wonder if either of our swizzle implementations would be considered useful to ublas or MTL ( http://osl.iu.edu/research/mtl/ )?
I use swizzling all the time (and more than just xyz) but it's in actual shaders using Cg, not C++ code. I'm not sure if that's because I have never had them exposed to me in C++, or if I have just not needed them.
I think swizzling tends to be used mostly in graphics programming, and neither ublas nor MTL describe that as their problem domain. Perhaps it's too specific to be included with those libraries. I notice that that Vault - Graphics folder is empty...maybe some OpenGL work needs to be done.
I use swizzling all the time in shaders as well, but not in C++. I used to - back when I started writing the library - but that was before capable programmable GPUs were mainstream and we actually used C++ for vertex transformations and such. As far as I know, "we" are the only ones who use swizzling, but that may well just be my ignorance talking... -- Daniel Wesslén
participants (3)
-
Daniel Wesslén
-
Maik Beckmann
-
Michael Fawcett