
Emil, I have a few quick and random questions concerning (proposed) Boost.QVM, which I notice is still in the review queue without a review manager (I may be able to help in that regard if things go well with Lorenzo's (proposed) Boost.Local review). I might be able to utilize this in some of my future work, so I'm interested. First, a very general question. Can you explain where QVM fit within the large collection of linear algebra libraries? What additional value is QVM providing that you feel other solutions are lacking? Now, I've barely scratched the documentation and I already have some questions :/ First, it doesn't look like you support read-only or write-only structures, or structures for which writing is effected through a proxy reference. E.g., v_traits<V>::r<I>(v) and v_traits<V>::w<I>(v) must always be supported, and v_traits<V>::w<I>(v) must return a reference-to-non-const. It seems like, in particular, read-only structures could be useful (e.g., a stateless standard basis vector or identity matrix), as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c). Comment? Why do you require the dimension of vectors (and, likely, matrices; I haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code. I noticed that among the vector operations is a cross product for 3-vectors, but no cross product for vectors of other dimensions. Such a construct is useful for computing normals to hyperplanes in D-dimensional space. I can help you add it if you think it fits. What algorithm do you use for computing determinants? I think a signed volume function would fit in well with the matrix operations. I can help you add this, too. Hmmm...how do you compute the magnitude of a vector given the scalar requirements defined at http://www.revergestudios.com/boost-qvm/scalar_requirements.html ? Seems like you would need a square root function, and possibly even a conjugation function if you want to support complex scalar types... Okay that's it for now, - Jeff

On Sun, Jul 17, 2011 at 9:16 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Emil, I have a few quick and random questions concerning (proposed) Boost.QVM, which I notice is still in the review queue without a review manager (I may be able to help in that regard if things go well with Lorenzo's (proposed) Boost.Local review). I might be able to utilize this in some of my future work, so I'm interested.
Thanks for your interest and feedback. And yes, the library needs a review manager.
First, a very general question. Can you explain where QVM fit within the large collection of linear algebra libraries? What additional value is QVM providing that you feel other solutions are lacking?
I called the library QVM which stands for Quaternions, Vectors and Matrices. This scope is practical for 3D graphics. While the library does support dimensions greater than 4, that is outside of my focus, and perhaps even my competence.
Now, I've barely scratched the documentation and I already have some questions :/
First, it doesn't look like you support read-only or write-only structures,
The library doesn't require that ::w is defined. The library itself does define some types that are read-only.
or structures for which writing is effected through a proxy reference. E.g., v_traits<V>::r<I>(v) and v_traits<V>::w<I>(v) must always be supported, and v_traits<V>::w<I>(v) must return a reference-to-non-const.
Yes, ::w must return a mutable reference. However, it is not required that ::w is defined for each and every element. For example, diag_m maps a vector as a square matrix that has the vector as its diagonal, and zeroes in all other elements. In this case, ::r is defined for all elements, but ::w is defined only for the diagonal elements, returning mutable references to the vector elements.
as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c).
This requirement means that none of the boost::qvm functions can return temporary objects for proxies. The mutable proxies Boost QVM avoid temporary objects by clever type casting. This helps control the abstraction penalty of the library. I guess it's possible to define ::w more abstractly. I decided to play it safe for now, but that's not set in stone.
Why do you require the dimension of vectors (and, likely, matrices; I haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code.
I wasn't aware of that. What can you do with a zero dimensional vector?
I noticed that among the vector operations is a cross product for 3-vectors, but no cross product for vectors of other dimensions. Such a construct is useful for computing normals to hyperplanes in D-dimensional space. I can help you add it if you think it fits.
Sure.
What algorithm do you use for computing determinants?
The general case is pretty straight forward recursion, defined in boost/qvm/detail/determinant_impl.hpp. However, the library comes with a code generator (libs/qvm/gen.cpp) capable of defining overloads for any specific size, unrolling the recursion. The code generator is used instead of template metaprogramming, again to control the abstraction penalty of the library.
I think a signed volume function would fit in well with the matrix operations. I can help you add this, too.
OK.
Hmmm...how do you compute the magnitude of a vector given the scalar requirements defined at
http://www.revergestudios.com/boost-qvm/scalar_requirements.html
? Seems like you would need a square root function, and possibly even a conjugation function if you want to support complex scalar types...
I guess that the documentation isn't clear but boost/qvm/math.hpp defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Jul 18, 2011 at 12:24 AM, Emil Dotchevski <emildotchevski@gmail.com>wrote:
On Sun, Jul 17, 2011 at 9:16 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
[...]
First, it doesn't look like you support read-only or write-only structures,
The library doesn't require that ::w is defined. The library itself does define some types that are read-only.
Ah, okay; that wasn't clear in the docs on v_traits, IIRC :/
or structures for which writing is effected through a proxy reference.
E.g., v_traits<V>::r<I>(v) and v_traits<V>::w<I>(v) must always be supported, and v_traits<V>::w<I>(v) must return a reference-to-non-const.
Yes, ::w must return a mutable reference. However, it is not required that ::w is defined for each and every element. For example, diag_m maps a vector as a square matrix that has the vector as its diagonal, and zeroes in all other elements. In this case, ::r is defined for all elements, but ::w is defined only for the diagonal elements, returning mutable references to the vector elements.
Make sense.
as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c).
This requirement means that none of the boost::qvm functions can return temporary objects for proxies. The mutable proxies Boost QVM avoid temporary objects by clever type casting. This helps control the abstraction penalty of the library.
I don't understand. Can you elaborate?
Why do you require the dimension of vectors (and, likely, matrices; I haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code.
I wasn't aware of that. What can you do with a zero dimensional vector?
Not much, to be sure (all zero-dim vectors of a given scalar type, at least, would be equal). I can't give a concrete example at the moment, but I seem to remember some recursion on dimension I've done where the base case was simpler to express at 0 than at 1.
I noticed that among the vector operations is a cross product for 3-vectors, but no cross product for vectors of other dimensions. Such a construct is useful for computing normals to hyperplanes in D-dimensional space. I can help you add it if you think it fits.
Sure.
I'll browse the code.
What algorithm do you use for computing determinants?
The general case is pretty straight forward recursion, defined in boost/qvm/detail/determinant_impl.hpp. However, the library comes with a code generator (libs/qvm/gen.cpp) capable of defining overloads for any specific size, unrolling the recursion.
The code generator is used instead of template metaprogramming, again to control the abstraction penalty of the library.
I'll take a look. I ask because I believe for 4x4 and larger matrices, a dynamic programming solution ends up significantly reducing the number of operations over the O(n!) recursive solution. But, I believe, for matrices larger than 5x5, still other techniques take fewer operations. Still, dynamic programming might improve the 4x4 and 5x5 cases. But maybe you've already looked into this...?
I think a signed volume function would fit in well with the matrix
operations. I can help you add this, too.
OK.
Hmmm...how do you compute the magnitude of a vector given the scalar requirements defined at
http://www.revergestudios.com/boost-qvm/scalar_requirements.html
? Seems like you would need a square root function, and possibly even a conjugation function if you want to support complex scalar types...
I guess that the documentation isn't clear but boost/qvm/math.hpp defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing.
Are complex scalar types within the scope of the library? - Jeff

On Mon, Jul 18, 2011 at 11:14 AM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Mon, Jul 18, 2011 at 12:24 AM, Emil Dotchevski
as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c).
This requirement means that none of the boost::qvm functions can return temporary objects for proxies. The mutable proxies Boost QVM avoid temporary objects by clever type casting. This helps control the abstraction penalty of the library.
I don't understand. Can you elaborate?
For example, here is the col_m function which maps a vector type A as a matrix-column: template <class A> typename boost::enable_if_c< is_v<A>::value, qvm_detail::col_m_<A> &>::type BOOST_QVM_INLINE_TRIVIAL col_m( A & a ) { return reinterpret_cast<typename qvm_detail::col_m_<A> &>(a); } The v_traits<col_m_>::r and v_traits<col_m_>::w functions cast back to A (which is stored as v_traits<col_m_>::OriginalVector) before accessing its elements: template <int Row,int Col> static BOOST_QVM_INLINE_CRITICAL scalar_type & w( this_matrix & x ) { BOOST_QVM_STATIC_ASSERT(Col==0); BOOST_QVM_STATIC_ASSERT(Row>=0); BOOST_QVM_STATIC_ASSERT(Row<rows); return v_traits<OriginalVector>::template w<Row>(reinterpret_cast<OriginalVector &>(x)); } This technique avoids the creation of temporaries which are often the source of abstraction penalties.
Why do you require the dimension of vectors (and, likely, matrices; I haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code.
I wasn't aware of that. What can you do with a zero dimensional vector?
Not much, to be sure (all zero-dim vectors of a given scalar type, at least, would be equal). I can't give a concrete example at the moment, but I seem to remember some recursion on dimension I've done where the base case was simpler to express at 0 than at 1.
In principle I'm not against lifting this requirement, but I want to make sure it's needed first. Doesn't this only affect the specialization of v_traits? I mean, you can still write recursive template meta programs that use zero as the base case as long as they don't define zero size in a v_traits specialization.
What algorithm do you use for computing determinants?
The general case is pretty straight forward recursion, defined in boost/qvm/detail/determinant_impl.hpp. However, the library comes with a code generator (libs/qvm/gen.cpp) capable of defining overloads for any specific size, unrolling the recursion.
The code generator is used instead of template metaprogramming, again to control the abstraction penalty of the library.
I'll take a look. I ask because I believe for 4x4 and larger matrices, a dynamic programming solution ends up significantly reducing the number of operations over the O(n!) recursive solution. But, I believe, for matrices larger than 5x5, still other techniques take fewer operations. Still, dynamic programming might improve the 4x4 and 5x5 cases. But maybe you've already looked into this...?
No I have not. The determinant computations are currently pretty straight-forward, save the use of an off-line code generator.
I guess that the documentation isn't clear but boost/qvm/math.hpp defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing.
Are complex scalar types within the scope of the library?
I think so. I've certainly been very careful to design a type system that permits non-trivial scalar types. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Jul 18, 2011 at 12:21 PM, Emil Dotchevski <emildotchevski@gmail.com>wrote:
On Mon, Jul 18, 2011 at 11:14 AM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Mon, Jul 18, 2011 at 12:24 AM, Emil Dotchevski
as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c).
This requirement means that none of the boost::qvm functions can return temporary objects for proxies. The mutable proxies Boost QVM avoid temporary objects by clever type casting. This helps control the abstraction penalty of the library.
I don't understand. Can you elaborate?
For example, here is the col_m function which maps a vector type A as a matrix-column:
template <class A> typename boost::enable_if_c< is_v<A>::value, qvm_detail::col_m_<A> &>::type BOOST_QVM_INLINE_TRIVIAL col_m( A & a ) { return reinterpret_cast<typename qvm_detail::col_m_<A> &>(a); }
The v_traits<col_m_>::r and v_traits<col_m_>::w functions cast back to A (which is stored as v_traits<col_m_>::OriginalVector) before accessing its elements:
template <int Row,int Col> static BOOST_QVM_INLINE_CRITICAL scalar_type & w( this_matrix & x ) { BOOST_QVM_STATIC_ASSERT(Col==0); BOOST_QVM_STATIC_ASSERT(Row>=0); BOOST_QVM_STATIC_ASSERT(Row<rows); return v_traits<OriginalVector>::template w<Row>(reinterpret_cast<OriginalVector &>(x)); }
This technique avoids the creation of temporaries which are often the source of abstraction penalties.
Wow, I guess I'm surprised the temporaries wouldn't be optimized away, at least in this case... I understand your desire to play it safe for now and require lvalue references for w. However, I don't see how the above example precludes the use of proxy references :/ Sorry for being dense. I would think col_m_<A> would simply use whatever reference type (lvalue or proxy) that A uses... In any case, I can't really think of a compelling use case for proxy references yet (can you?), so it's not a huge deal.
Why do you require the dimension of vectors (and, likely, matrices; I
haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code.
I wasn't aware of that. What can you do with a zero dimensional vector?
Not much, to be sure (all zero-dim vectors of a given scalar type, at least, would be equal). I can't give a concrete example at the moment, but I seem to remember some recursion on dimension I've done where the base case was simpler to express at 0 than at 1.
In principle I'm not against lifting this requirement, but I want to make sure it's needed first. Doesn't this only affect the specialization of v_traits? I mean, you can still write recursive template meta programs that use zero as the base case as long as they don't define zero size in a v_traits specialization.
Again, this is still kind of pure speculation. I could imagine an algorithm written using the QVM abstraction which, say, recurses in dimension by (lazily) removing the first or last element of vectors (does QVM support such operations?), and at some point you'd remove the first or last element of a 1-vector. But it's fair to avoid lifting the requirement until needed. I was just wondering if there was some other rationale for requiring a positive dimension other than "I hadn't seen a need for it".
What algorithm do you use for computing determinants?
The general case is pretty straight forward recursion, defined in boost/qvm/detail/determinant_impl.hpp. However, the library comes with a code generator (libs/qvm/gen.cpp) capable of defining overloads for any specific size, unrolling the recursion.
The code generator is used instead of template metaprogramming, again to control the abstraction penalty of the library.
I'll take a look. I ask because I believe for 4x4 and larger matrices, a dynamic programming solution ends up significantly reducing the number of operations over the O(n!) recursive solution. But, I believe, for matrices larger than 5x5, still other techniques take fewer operations. Still, dynamic programming might improve the 4x4 and 5x5 cases. But maybe you've already looked into this...?
No I have not. The determinant computations are currently pretty straight-forward, save the use of an off-line code generator.
I just ran through a quick count of the number of multiplies, and for 4x4 matrices, dynamic programming will reduce the number of multiplications from 40 to 28 over straightforward recursion, while for 5x5 matrices, the reduction from 205 to 75 (or so).
I guess that the documentation isn't clear but boost/qvm/math.hpp defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing.
Are complex scalar types within the scope of the library?
I think so. I've certainly been very careful to design a type system that permits non-trivial scalar types.
I figured complex scalars might be tacitly supported, as you don't require ordering comparisons on scalar types, but I'm not sure the scalar type requirements you give are sufficient (e.g., you probably need conjugation somehow). In any case, this was more of a curiosity than an actual need. I'll continue to browse through the library and let you know if I have additional comments or questions. - Jeff

On Mon, Jul 18, 2011 at 12:49 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Mon, Jul 18, 2011 at 12:21 PM, Emil Dotchevski <emildotchevski@gmail.com>wrote:
On Mon, Jul 18, 2011 at 11:14 AM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Mon, Jul 18, 2011 at 12:24 AM, Emil Dotchevski
as could proxy structures (c*v could be a proxy vector where w<0>(c*v) = 1 is equivalent to w<0>(v) = 1/c).
This requirement means that none of the boost::qvm functions can return temporary objects for proxies. The mutable proxies Boost QVM avoid temporary objects by clever type casting. This helps control the abstraction penalty of the library.
I don't understand. Can you elaborate?
For example, here is the col_m function which maps a vector type A as a matrix-column: <snip> This technique avoids the creation of temporaries which are often the source of abstraction penalties.
Wow, I guess I'm surprised the temporaries wouldn't be optimized away, at least in this case...
It is likely that they'll be optimized away, but in my experience temporaries are more likely to confuse optimizers than inline functions. Not that I have hard data to back this claim. :)
I understand your desire to play it safe for now and require lvalue references for w. However, I don't see how the above example precludes the use of proxy references :/ Sorry for being dense. I would think col_m_<A> would simply use whatever reference type (lvalue or proxy) that A uses...
In any case, I can't really think of a compelling use case for proxy references yet (can you?), so it's not a huge deal.
No you're right, allowing for more generic ::w would not preclude this, I was just pointing out that I've tried to keep things straight-forward. This doesn't mean that I'm against it in principle, but ideally I'd like to examine several use cases that require this complication in order to come up with the correct more generic formal specification.
Why do you require the dimension of vectors (and, likely, matrices; I
haven't checked) to be strictly greater than 0? Sometimes a 0-dimensional vector is convenient to have when writing dimension-independent code.
I wasn't aware of that. What can you do with a zero dimensional vector?
Not much, to be sure (all zero-dim vectors of a given scalar type, at least, would be equal). I can't give a concrete example at the moment, but I seem to remember some recursion on dimension I've done where the base case was simpler to express at 0 than at 1.
In principle I'm not against lifting this requirement, but I want to make sure it's needed first. Doesn't this only affect the specialization of v_traits? I mean, you can still write recursive template meta programs that use zero as the base case as long as they don't define zero size in a v_traits specialization.
Again, this is still kind of pure speculation. I could imagine an algorithm written using the QVM abstraction which, say, recurses in dimension by (lazily) removing the first or last element of vectors (does QVM support such operations?), and at some point you'd remove the first or last element of a 1-vector. But it's fair to avoid lifting the requirement until needed. I was just wondering if there was some other rationale for requiring a positive dimension other than "I hadn't seen a need for it".
Right, I try to avoid speculations like this. It is important to understand the use cases before designing an interface to support them. To answer your question, there aren't currently functions to remove an element of a vector except as part of the swizzling support which can only output dimensions up to 4. For example v%YZ maps the Y and Z elements of a vector with size at least 3, as a 2D vector. There are functions for removing rows and columns of matrices, so perhaps a similar functionality makes sense for vectors in general.
No I have not. The determinant computations are currently pretty straight-forward, save the use of an off-line code generator.
I just ran through a quick count of the number of multiplies, and for 4x4 matrices, dynamic programming will reduce the number of multiplications from 40 to 28 over straightforward recursion, while for 5x5 matrices, the reduction from 205 to 75 (or so).
I welcome any optimization like this. Is it possible to write a generic code generator for this algorithm, similarly to the other code generators in libs/qvm/gen/gen.cpp?
I guess that the documentation isn't clear but boost/qvm/math.hpp defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing.
Are complex scalar types within the scope of the library?
I think so. I've certainly been very careful to design a type system that permits non-trivial scalar types.
I figured complex scalars might be tacitly supported, as you don't require ordering comparisons on scalar types, but I'm not sure the scalar type requirements you give are sufficient (e.g., you probably need conjugation somehow). In any case, this was more of a curiosity than an actual need.
Like I said, my motivation was to write a generic library that's useful for 3D graphics, but I'm not against extending the scope beyond that as long as things don't get too crazy. Complex and fixed point scalars seem appropriate, but I know I don't want to support vectors and matrices of dynamic size or general sparsity.
I'll continue to browse through the library and let you know if I have additional comments or questions.
I appreciate your feedback! Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Jul 18, 2011 at 2:55 PM, Emil Dotchevski <emildotchevski@gmail.com>wrote:
On Mon, Jul 18, 2011 at 12:49 PM, Jeffrey Lee Hellrung, Jr.
[...]
To answer your question, there aren't currently functions to remove an element of a vector except as part of the swizzling support which can only output dimensions up to 4. For example v%YZ maps the Y and Z elements of a vector with size at least 3, as a 2D vector. There are functions for removing rows and columns of matrices, so perhaps a similar functionality makes sense for vectors in general.
Agreed; also the symmetric operations of (lazily) adding rows and columns to matrices and (lazily) adding elements to vectors would be useful, too.
No I have not. The determinant computations are currently pretty straight-forward, save the use of an off-line code generator.
I just ran through a quick count of the number of multiplies, and for 4x4 matrices, dynamic programming will reduce the number of multiplications from 40 to 28 over straightforward recursion, while for 5x5 matrices, the reduction from 205 to 75 (or so).
I welcome any optimization like this. Is it possible to write a generic code generator for this algorithm, similarly to the other code generators in libs/qvm/gen/gen.cpp?
I think it is, but it's certainly more challenging than the straightforward algorithm. Lemme look at this gen.cpp to see what you do. I'm curious, what are you reasons for not using the preprocessor for code generation? Is it not possible in this case? Too much of a maintenance problem? Compile-time speed? Haven't tried?
I guess that the documentation isn't clear but boost/qvm/math.hpp
defines function templates that correspond to the functions from <math.h>. The templates are specialized for float and double, but can be specialized for any other scalar. That said, I don't have tests using any other scalar type. Perhaps a fixed point scalar should be implemented to make sure there isn't something missing.
Are complex scalar types within the scope of the library?
I think so. I've certainly been very careful to design a type system that permits non-trivial scalar types.
I figured complex scalars might be tacitly supported, as you don't require ordering comparisons on scalar types, but I'm not sure the scalar type requirements you give are sufficient (e.g., you probably need conjugation somehow). In any case, this was more of a curiosity than an actual need.
Like I said, my motivation was to write a generic library that's useful for 3D graphics, but I'm not against extending the scope beyond that as long as things don't get too crazy. Complex and fixed point scalars seem appropriate,
Well, when you get that far, it seems you'll need to revisit your (documented) scalar requirements. It's possible that could be a precondition for review. but I know I don't want to support vectors
and matrices of dynamic size or general sparsity.
Of course.
I'll continue to browse through the library and let you know if I have additional comments or questions.
I appreciate your feedback!
No problem. - Jeff

On Mon, Jul 18, 2011 at 11:54 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
I just ran through a quick count of the number of multiplies, and for 4x4 matrices, dynamic programming will reduce the number of multiplications from 40 to 28 over straightforward recursion, while for 5x5 matrices, the reduction from 205 to 75 (or so).
I welcome any optimization like this. Is it possible to write a generic code generator for this algorithm, similarly to the other code generators in libs/qvm/gen/gen.cpp?
I think it is, but it's certainly more challenging than the straightforward algorithm. Lemme look at this gen.cpp to see what you do.
I'm curious, what are you reasons for not using the preprocessor for code generation? Is it not possible in this case? Too much of a maintenance problem? Compile-time speed? Haven't tried?
Compile-time speed and readability of the generated code. I often step through this kind of code trying to figure out what's wrong with my matrices; the last thing I want is to have to look at preprocessor or template meta programs. What's the downside anyway?
Well, when you get that far, it seems you'll need to revisit your (documented) scalar requirements. It's possible that could be a precondition for review.
That's fine. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (2)
-
Emil Dotchevski
-
Jeffrey Lee Hellrung, Jr.