Allow Tagging Blaze Expressions
Hi Klaus,
I hope things are well with you!
I was wondering if it would be possible to add an extra type template parameter to all expressions that acts as a "name" for them. What I mean is that instead of blaze::Vector<VT, TF>
there would be a blaze::Vector<VT, TF, Tag>
. The reason for this is we have several different vectors that we use Blaze as the ET implementation for. However, they different vectors should not be mixed in expressions since they represent fundamentally different data. For example, we have a vector for the solution in physical space and a different vector for the solution in spectral space. We want to have the expressions carry this information as a template parameter so that they cannot accidentally be mixed together. This would be a huge win for us, but I'm not sure how easy/difficult it would be to implement. I realize it would be a fairly extensive change but is this something you would consider useful? We could help with the change, but would rather not do it if it's not something that would be welcome upstream. Let me know what your thoughts are on the matter :)
Cheers,
Nils
Comments (19)
-
-
Hello!
What about some kind of strong typedef? Is it possible to resolve this issue outside of Blaze by using strong typedefs for vectors/matrixes or even for their contents? Probably something like
template<VT, TF>struct DomainStructure: public blaze::Vector<VT, TF>;
could be a solution? Strong typedef implementation may also be useful.Best regards,
Innokentiy
-
Hi Innokentiy!
Thanks a lot for the suggestion. From our point of view, this would indeed be a reasonable alternate approach that we did not think about, but of course we cannot cannot speak for Nils' application. Thanks for joining the discussion,
Best regards,
Klaus!
-
reporter Hi,
It's not clear to me how easy this solution is, though it looks like it could work. Looking at CustomVector it has a ResultType of DynamicVector. If this could be controlled I think that's all that is necessary. What I'm trying right now is:
class DataVector : public blaze::DenseVector<DataVector, blaze::defaultTransposeFlag> { public: using This = DataVector; using BaseType = blaze::DenseVector<DataVector, blaze::defaultTransposeFlag>; using ResultType = DataVector; using ReturnType = const double&; using CompositeType = const DataVector&; ... };
However, I don't know what I need to add to get this to work. The error I get is:
/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/traits/AddTrait.h:151:66: error: function 'operator+<DataVector, DataVector, false>' with deduced return type cannot be used before it is defined struct AddType { using Type = decltype( std::declval<Type1>() + std::declval<Type2>() ); }; ^ /home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/traits/AddTrait.h:158:26: note: in instantiation of member class 'blaze::AddTrait<DataVector, DataVector, void>::AddType' requested here using Type = typename If_< Or< IsConst<T1>, IsVolatile<T1>, IsReference<T1> ^ /home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/traits/AddTrait.h:250:1: note: in instantiation of template class 'blaze::AddTrait<DataVector, DataVector, void>' requested here using AddTrait_ = typename AddTrait<T1,T2>::Type; ^ /home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/expressions/DVecDVecAddExpr.h:164:26: note: in instantiation of template type alias 'AddTrait_' requested here using ResultType = AddTrait_<RE1,RE2>; //!< Result type for expression template evaluations. ^ /home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/expressions/DVecDVecAddExpr.h:1067:11: note: in instantiation of template class 'blaze::DVecDVecAddExpr<DataVector, DataVector, false>' requested here return ReturnType( ~lhs, ~rhs ); ^ ../tests/Unit/DataStructures/Test_DataVector.cpp:201:12: note: in instantiation of function template specialization 'blaze::operator+<DataVector, DataVector, false>' requested here b = m0 + m1; ^ /home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include/blaze/math/expressions/DVecDVecAddExpr.h:1058:4: note: 'operator+<DataVector, DataVector, false>' declared here operator+( const DenseVector<VT1,TF>& lhs, const DenseVector<VT2,TF>& rhs )
Any ideas? I'm not defining an operator+(DataVector, DataVector) since I'd like to use the one for DenseVector.
Thanks!
Cheers,
Nils
-
Hi Nils!
Deriving directly from
blaze::DenseVector
would require you to implement a completely new vector type. This would indeed be a lot of work (also since we have admittedly not yet provided a tutorial about how to do this properly).A possible solution that works would be the following one. I have implemented the two dense vectors
DataVector
andSolutionVector
that are both based onCustomVector
and that should not be combined viaoperator+
. I have added the capability to automatically clean up the allocated storage as this might be of interest for you.class DataVector : public CustomVector< double, unaligned, unpadded, defaultTransposeFlag > { public: using Base = CustomVector< double, unaligned, unpadded, defaultTransposeFlag >; explicit inline DataVector( size_t n ) : CustomVector<double,unaligned,unpadded,defaultTransposeFlag>() , array_( new double[n] ) { this->reset( array_.get(), n ); } using Base::operator=; private: std::unique_ptr<double[]> array_; }; class SolutionVector : public CustomVector< double, unaligned, unpadded, defaultTransposeFlag > { public: using Base = CustomVector< double, unaligned, unpadded, defaultTransposeFlag >; explicit inline SolutionVector( size_t n ) : CustomVector<double,unaligned,unpadded,defaultTransposeFlag>() , array_( new double[n] ) { this->reset( array_.get(), n ); } using Base::operator=; private: std::unique_ptr<double[]> array_; }; decltype(auto) operator+( DataVector const& a, DataVector const& b ) { using Base = DataVector::Base; return static_cast<Base const&>( a ) + static_cast<Base const&>( b ); } decltype(auto) operator+( SolutionVector const& a, SolutionVector const& b ) { using Base = SolutionVector::Base; return static_cast<Base const&>( a ) + static_cast<Base const&>( b ); } void operator+( DataVector const& a, SolutionVector const& b ); void operator+( SolutionVector const& a, DataVector const& b );
As you can see it is necessary to define some addition operators. Else the built-in
operator+
would be used, which just works withblaze::DenseVector
and that could not distinguish betweenDataVector
andSolutionVector
. However, the implementation of these customoperator+
is based on the Blaze implementation (i.e. only a little overhead) and clearly spells out which combinations are incorrect. Therefore it might be an acceptable solution.I don't know if this meets your requirements, but I hope it helps.
Best regards,
Klaus!
-
reporter Hi Klaus,
Thanks for showing the implementation. Unfortunately this has the exact problem I'm trying to prevent:
blaze::DataVector ten_dv(5); blaze::DataVector two_dv(5); const auto result_dv = ten_dv + two_dv; blaze::SolutionVector ten_sv(5); blaze::SolutionVector two_sv(5); const auto result_combined = (ten_dv + two_dv) + (ten_sv + two_sv);
The last line compiles when I don't want it to. Any ideas on how to deal with that? I still think being able to control
ResultType
would be sufficient for my needs. If I doTD<typename decltype(result_combined)::ResultType> aoeu{};
to get the resulting type it tells meblaze::DynamicVector
. I think if the ResultType of SolutionVector was a SolutionVector not a DynamicVector then everything would be check the way I want. This probably requires no changes in Blaze (other than documenting this secret feature if it works :) ). It's a bit more work on my part, but I'm okay with that if it means I get the type tracking.Thank you for the help! :)
Cheers,
Nils
-
Hi Nils!
Your are correct, for more complex expressions this simple solution will fail. Thus I have a second proposal, the
TaggedVector
adaptor (which might be similar to what you have in mind):template< typename VT, typename Tag > class TaggedVector : public DenseVector< TaggedVector<VT,Tag>, TransposeFlag_v<VT> > { public: using This = TaggedVector<VT,Tag>; using BaseType = DenseVector<This,TransposeFlag_v<VT>>; using ResultType = TaggedVector<ResultType_t<VT>,Tag>; using TransposeType = TaggedVector<TransposeType_t<VT>,Tag>; using ElementType = ElementType_t<VT>; using SIMDType = SIMDTrait_t<ElementType>; using ReturnType = const ElementType&; using CompositeType = const TaggedVector&; using Reference = ElementType&; using ConstReference = const ElementType&; using Pointer = ElementType*; using ConstPointer = const ElementType*; using Iterator = Iterator_t<VT>; using ConstIterator = ConstIterator_t<VT>; static constexpr bool simdEnabled = VT::simdEnabled; static constexpr bool smpAssignable = VT::smpAssignable; explicit TaggedVector() : vec_() {} template< typename... Args, typename = EnableIf_t< And_v< Not< IsVector<Args> >... > > > explicit TaggedVector( Args&&... args ) : vec_( std::forward<Args>( args )... ) {} template< typename VT2, bool TF > explicit TaggedVector( const Vector<VT2,TF>& vec ) : vec_( vec ) { static_assert( IsSame_v<ResultType_t<VT2>,This>, "Invalid result type detected" ); } Reference operator[]( size_t index ) { return vec_[index]; } ConstReference operator[]( size_t index ) const { return vec_[index]; } size_t size() const { return vec_.size(); } size_t capacity() const { return vec_.capacity(); } Iterator begin() { return vec_.begin(); } ConstIterator begin() const { return vec_.begin(); } Iterator end() { return vec_.begin(); } ConstIterator end() const { return vec_.end(); } TaggedVector& operator=( const TaggedVector& vec ) { vec_ = vec.vec_; return *this; } template< typename VT2, bool TF > TaggedVector& operator=( const Vector<VT2,TF>& vec ) { static_assert( IsSame_v<ResultType_t<VT2>,This>, "Invalid result type detected" ); vec_ = vec; return *this; } template< typename Other > inline bool canAlias ( const Other* alias ) const noexcept { return vec_.canAlias( alias ); } template< typename Other > inline bool isAliased( const Other* alias ) const noexcept { return vec_.isAliased( alias ); } private: VT vec_; }; template< typename VT1, typename Tag, typename VT2 > struct AddTrait< TaggedVector<VT1,Tag>, TaggedVector<VT2,Tag> > { using Type = TaggedVector< AddTrait_t<VT1,VT2>, Tag >; }; template< typename VT1, typename Tag1, typename VT2, typename Tag2 > struct AddTrait< TaggedVector<VT1,Tag1>, TaggedVector<VT2,Tag2> > {}; template< typename VT1, typename Tag, typename VT2, bool TF > struct AddTrait< TaggedVector<VT1,Tag>, DynamicVector<VT2,TF> > {}; template< typename VT1, bool TF, typename VT2, typename Tag > struct AddTrait< DynamicVector<VT1,TF>, TaggedVector<VT2,Tag> > {};
The class is incomplete, but demonstrates the intent:
TaggedVector
wraps another vector type (DynamicVector
,CustomVector
, ...) and adds a tag type. The result type is always aTaggedVector
, which can be exploited in the operation traits (I have only added a fewAddTrait
specializations in this short demo). Whenever aTaggedVector
is used in combination with another vector type, there will be a compilation error (AddTrait
cannot determine the resulting type). Also, whenTaggedVector
is used in combination with anotherTaggedVector
with different tag type, there will be a compilation error. An operation is only allowed if aTaggedVector
is combined with aTaggedVector
with the same tag type.Once again, the class is incomplete and a lot of details need to be properly implemented, but it hopefully serves the purpose to demonstrate the idea.
Best regards,
Klaus!
-
reporter Hi Klaus,
I'm currently exploring what you've suggested. We have our own implementation of CustomVector so I'm adding the tagging ability to that. I'll give an update once I have things understood/working. Thank you for the help!
Cheers,
Nils
-
reporter Hi Klaus,
Sorry this took so long to figure out, but I have it working now. All that's necessary (with some oversimplification) is adding a template parameter
typename ExprResultType = blaze::DynamicVector<blaze::RemoveConst_<Type>, TF>
to CustomVector, and a similar one for CustomMatrix. See this commit for how I do it with ourPointerVector
class, which at this point might be exactly the same as CustomVector (now with the new ExprResultType). I think this would be super easy to integrate into Blaze and would be exactly what I'm looking for :) I'm happy to do this in a PR, unless you want to implement it yourself.Cheers,
Nils
-
Hi Nils!
I'm sorry for the late reply, but I was thinking about this idea for the past two days. I'm still struggling to decide whether this as a special solution for your case (since "tagging" only works when you use
CustomVector
orCustomMatrix
) or a general solution for all Blaze users (since you can manually define the resulting vector or matrix type). I'm also not thrilled by the idea to introduce a second defaulted template parameter (there should be only one at maximum), but so far I couldn't think of a better approach. I will continue to consider the idea and your requirements.Best regards,
Klaus!
-
reporter Hi Klaus,
Thanks for the update on what you're thinking! I'm just curious what your reasons are against a second defaulted template parameter? In this particular case it would be rarely used since normally there would be a class deriving off
CustomVector
that would also be theResultType
. Thanks for the consideration!Best,
Nils
-
Hi Nils!
I'm starting to believe that your solution can be of general interest for a greater audience. Providing the option to specify the result type explicitly allows for other kinds of optimization that have not been possible so far (e.g. you could specify
StaticVector
instead ofDynamicVector
in case you know that yourCustomVector
has a specific size; tagging would just be a special use for this). However, users should be unaware of the implementation details ofCustomVector
. In your commit it is necessary to useRemoveConst_t
in the interface:template <typename Type, bool AF = blaze::unaligned, bool PF = blaze::unpadded, bool TF = blaze::defaultTransposeFlag, typename ExprResultType = blaze::DynamicVector<blaze::RemoveConst_<Type>, TF>> struct PointerVector { /*...*/ };
If you agree to this compromise then I believe the approach is viable:
template< typename Type // Data type of the vector , bool AF // Alignment flag , bool PF // Padding flag , bool TF = defaultTransposeFlag // Transpose flag , typename ExprResultType = DynamicVector<Type,TF> > // <- Can be any general vector type class CustomVector : public DenseVector< CustomVector<Type,AF,PF,TF,ExprResultType>, TF > { // ... //! Result type for expression template evaluations. using ResultType = typename ExprResultType::BLAZE_TEMPLATE Rebind< RemoveConst_t<Type> >::Other; //! Transpose type for expression template evaluations. using TransposeType = TransposeType_t<ResultType>; // ... };
Best regards,
Klaus!
-
reporter Hi Klaus!
That looks great and it would be awesome to have in Blaze! :) Thank you so much, we all really appreciate it :)
Best,
Nils
-
Commit 508e966 updates the
CustomVector
class requested. The modification is slightly different from the proposed change, but guarantees that even the nestedRebind
andResize
class templates work correctly. Commit d41a167 updates theCustomMatrix
class accordingly.Since the updates of
CustomVector
andCustomMatrix
do not generally solve the tagging problem, we leave the issue open until a general solution has been found and implemented. -
reporter Hi Klaus,
Thanks for adding this! Super useful :)
Best,
Nils
-
-
assigned issue to
-
assigned issue to
-
- changed status to open
-
Intermediate Summary
The last push introduced the ability to tag vectors and matrices and by that associate both with predefined or custom groups. Since the implementation details (e.g. the final order of template parameters) depend on the modifications done in issue 307, these two issues will be resolved together.
The following gives an overview of the current (potentially not final) implementation.
Tagging and Groups
Sometimes it may be desirable to separate two or more distinct groups of vectors and matrices, for instance in order to allow operations only within a group and to prevent operations across groups. This goal can be achieved by means of tags. All vector and matrix classes provide a template parameter to specify a tag (for instance, the third template parameter for
blaze::DynamicVector
and the sixth template parameter forblaze::StaticVector
):template< typename Type, bool TF, typename Tag > class DynamicVector; template< typename Type, size_t N, bool TF, AlignmentFlag AF, PaddingFlag PF, typename Tag > class StaticVector;
By default, all vectors and matrices are associated with
blaze::Group0
(i.e. the tag is set toblaze::Group0
). However, it is possible to explicitly associate vectors and matrices with different groups:using blaze::DynamicVector; using blaze::Group0; using blaze::Group1; using blaze::columnVector; DynamicVector<int,columnVector,Group0> a0, b0; DynamicVector<int,columnVector,Group1> a1, b1; a0 + b0; // Compiles, a0 and b0 are in the same group (Group0) a1 + b1; // Compiles, a1 and b1 are in the same group (Group1) a0 + b1; // Compilation error: a0 and b1 are not in the same group
All vectors or matrices that are associated with the same group can be freely combined with any other vector or matrix from the same group. The attempt to combine vectors and matrices from different groups results in a compilation error.
Creating New Groups
Blaze provides the tags for the ten predefined groups
blaze::Group0
throughblaze::Group9
. In order to create further groups, all that needs to be done is to create new instances of theblaze::GroupTag
class template:using Group10 = blaze::GroupTag<10>; using Group11 = blaze::GroupTag<11>; // ... further groups
All groups based on the
blaze::GroupTag
class template will be treated as separate groups just as the ten predefined groups.
Custom Tags
Sometimes it is not enough to separate vectors and matrices into different groups, but it is required to define the interaction between different groups. This situation for instance occurs if a vector or matrix is associated with a physical quantity. This problem can be solved by using custom tags. The following example gives an impression on how to define the physics on meters (represented by the
Meter
tag) and seconds (represented by theSecond
tag):struct Meter {}; // Definition of the 'Meter' tag struct Second {}; // Definition of the 'Second' tag struct SquareMeter {}; // Definition of the 'SquareMeter' tag struct MeterPerSecond {}; // Definition of the 'MeterPerSecond' tag
The
Meter
andSecond
tags are not associated with theblaze::GroupTag
class template. For that reason, by default, it is not possible to perform any operation on an accordingly tagged vector or matrix. All required operations need to be declared explicitly in order to specify the resulting tag of an operation. In the following code example, this happens by declaring both the addition for theMeter
tag and theSecond
tag, the multiplication between twoMeter
tags and the division betweenMeter
andSecond
. Note that it is enough to declare the operations, it is not necessary to define them!Meter operator+( Meter , Meter ); // Enabling addition between 'Meter' Second operator+( Second, Second ); // Enabling addition between 'Second' SquareMeter operator*( Meter , Meter ); // Enabling multiplication between 'Meter' MeterPerSecond operator/( Meter , Second ); // Enabling division between 'Meter' and 'Second'
With these declarations it is now possible to add meters and seconds, but not to subtract them (no subtraction operator was declared). Also, it is possible to multiply meters and to divide meters and seconds:
const DynamicVector<int,rowVector,Meter> m1{ 1, 2, 3 }; const DynamicVector<int,rowVector,Meter> m2{ 4, 5, 6 }; const DynamicVector<int,rowVector,Second> s1{ 1, 2, 3 }; const DynamicVector<int,rowVector,Second> s2{ 4, 5, 6 }; m1 + m2; // Compiles and results in vector tagged with 'Meter' s1 + s2; // Compiles and results in vector tagged with 'Second' m1 - m2; // Compilation error: No subtraction defined for 'Meter'! m1 + s2; // Compilation error: No addition between 'Meter' and 'Second' defined! m1 * m2; // Compiles and results in vector tagged with 'SquareMeter' m1 / s1; // Compiles and results in vector tagged with 'MeterPerSecond'
At this point it is possible to use the {{{pow2()}}} function for vectors and matrices tagged with {{{Meter}}} since {{{pow2()}}} is based on multiplication, which has already been declared. However, it is not possible to use the {{{abs()}}} function:
pow2( m1 ); // Compiles and results in vector tagged with 'SquareMeter' abs ( m1 ); // Compilation error: No 'abs()' declared for the 'Meter' tag
In order to enable the
abs()
function it also needs to be explicitly declared for theMeter
tag:Meter abs( Meter ); // Enabling the 'abs()' function on 'Meter' abs( m1 ); // Compiles and results in vector tagged with 'Meter'
-
- changed status to resolved
Summary
With the recent additions to Blaze it is now possible to group/tag vectors and matrices. The feature is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.8.
Tagging and Groups
Sometimes it may be desirable to separate two or more distinct groups of vectors and matrices, for instance in order to allow operations only within a group and to prevent operations across groups. This goal can be achieved by means of tags. All vector and matrix classes provide a template parameter to specify a tag (for instance, the fourth template parameter for
blaze::DynamicVector
and the sixth template parameter forblaze::StaticVector
):template< typename Type, bool TF, typename Alloc, typename Tag > class DynamicVector; template< typename Type, size_t N, bool TF, AlignmentFlag AF, PaddingFlag PF, typename Tag > class StaticVector;
By default, all vectors and matrices are associated with
blaze::Group0
(i.e. the tag is set toblaze::Group0
). However, it is possible to explicitly associate vectors and matrices with different groups:using blaze::DynamicVector; using blaze::AlignedAllocator; using blaze::Group0; using blaze::Group1; using blaze::columnVector; DynamicVector<int,columnVector,AlignedAllocator<int>,Group0> a0, b0; DynamicVector<int,columnVector,AlignedAllocator<int>,Group1> a1, b1; a0 + b0; // Compiles, a0 and b0 are in the same group (Group0) a1 + b1; // Compiles, a1 and b1 are in the same group (Group1) a0 + b1; // Compilation error: a0 and b1 are not in the same group
All vectors or matrices that are associated with the same group can be freely combined with any other vector or matrix from the same group. The attempt to combine vectors and matrices from different groups results in a compilation error.
Creating New Groups
Blaze provides the tags for the ten predefined groups
blaze::Group0
throughblaze::Group9
. In order to create further groups, all that needs to be done is to create new instances of theblaze::GroupTag
class template:using Group10 = blaze::GroupTag<10>; using Group11 = blaze::GroupTag<11>; // ... further groups
All groups based on the
blaze::GroupTag
class template will be treated as separate groups just as the ten predefined groups.
Custom Tags
Sometimes it is not enough to separate vectors and matrices into different groups, but it is required to define the interaction between different groups. This situation for instance occurs if a vector or matrix is associated with a physical quantity. This problem can be solved by using custom tags. The following example gives an impression on how to define the physics on meters (represented by the
Meter
tag) and seconds (represented by theSecond
tag):struct Meter {}; // Definition of the 'Meter' tag struct Second {}; // Definition of the 'Second' tag struct SquareMeter {}; // Definition of the 'SquareMeter' tag struct MeterPerSecond {}; // Definition of the 'MeterPerSecond' tag
The
Meter
andSecond
tags are not associated with theblaze::GroupTag
class template. For that reason, by default, it is not possible to perform any operation on an accordingly tagged vector or matrix. All required operations need to be declared explicitly in order to specify the resulting tag of an operation. In the following code example, this happens by declaring both the addition for theMeter
tag and theSecond
tag, the multiplication between twoMeter
tags and the division betweenMeter
andSecond
. Note that it is enough to declare the operations, it is not necessary to define them!Meter operator+( Meter , Meter ); // Enabling addition between 'Meter' Second operator+( Second, Second ); // Enabling addition between 'Second' SquareMeter operator*( Meter , Meter ); // Enabling multiplication between 'Meter' MeterPerSecond operator/( Meter , Second ); // Enabling division between 'Meter' and 'Second'
With these declarations it is now possible to add meters and seconds, but not to subtract them (no subtraction operator was declared). Also, it is possible to multiply meters and to divide meters and seconds:
const DynamicVector<int,rowVector,AlignedAllocator<int>,Meter> m1{ 1, 2, 3 }; const DynamicVector<int,rowVector,AlignedAllocator<int>,Meter> m2{ 4, 5, 6 }; const DynamicVector<int,rowVector,AlignedAllocator<int>,Second> s1{ 1, 2, 3 }; const DynamicVector<int,rowVector,AlignedAllocator<int>,Second> s2{ 4, 5, 6 }; m1 + m2; // Compiles and results in vector tagged with 'Meter' s1 + s2; // Compiles and results in vector tagged with 'Second' m1 - m2; // Compilation error: No subtraction defined for 'Meter'! m1 + s2; // Compilation error: No addition between 'Meter' and 'Second' defined! m1 * m2; // Compiles and results in vector tagged with 'SquareMeter' m1 / s1; // Compiles and results in vector tagged with 'MeterPerSecond'
At this point it is possible to use the
pow2()
function for vectors and matrices tagged withMeter
sincepow2()
is based on multiplication, which has already been declared. However, it is not possible to use theabs()
function:pow2( m1 ); // Compiles and results in vector tagged with 'SquareMeter' abs ( m1 ); // Compilation error: No 'abs()' declared for the 'Meter' tag
In order to enable the
abs()
function it also needs to be explicitly declared for theMeter
tag:Meter abs( Meter ); // Enabling the 'abs()' function on 'Meter' abs ( m1 ); // Compiles and results in vector tagged with 'Meter'
- Log in to comment
Hi Nils!
Thanks a lot for creating this proposal. We perfectly understand your intention and agree that this could indeed be a huge win for your application. At this point we also cannot think of a better way to provide the same feature, i.e. adding a tag to all vectors and matrices would probably be the best course of action (although we still think about alternatives).
However, we can ascertain that this change would be indeed a huge effort. All vector and matrix classes (base classes as well as concrete classes) would have to be adapted since the tag would have to be passed via the concrete classes down to the base classes:
The change would also affect a large portion of the member functions of these classes and a huge portion of the operations on vectors and matrices. In summary, we estimate that this change would affect approx. 75% of the Blaze functionality. Additionally, we currently have no idea if this would harmonize with the changes we have planned for the next two releases that will move Blaze towards N-dimensional arithmetic (see issue #53). Therefore at this point in time we don't know if we could immediately act on this because we see some risk involved.
In summary, we feel that this could indeed be a reasonable future change to Blaze. We will keep this issue on our radar and continue to evaluate the required effort and the risk involved. By all means, thanks for pointing out this potential improvement, this idea will definitely be considered in our next steps.
Best regards,
Klaus!