// -*- C++ -*- #ifndef __multi_array_operation_h__ #define __multi_array_operation_h__ #include #include #include #include #include #include "base_def.h" #include "mbase_def.h" #include "ranges/rheader.h" #include "pack_num.h" #include "arith.h" namespace MultiArrayTools { namespace { using namespace MultiArrayHelper; } template class OperationBase { public: OperationClass& THIS() { return static_cast(*this); } const OperationClass& THIS() const { return static_cast(*this); } template auto operator+(const OperationBase& in) const -> Operation,OperationClass,Second>; template auto operator-(const OperationBase& in) const -> Operation,OperationClass,Second>; template auto operator*(const OperationBase& in) const -> Operation,OperationClass,Second>; template auto operator/(const OperationBase& in) const -> Operation,OperationClass,Second>; template auto c(const std::shared_ptr& ind) const -> Contraction; template auto sl(const std::shared_ptr&... inds) const -> ConstSlice; template auto slc(const std::shared_ptr&... inds) const -> SliceContraction; private: friend OperationClass; friend OperationTemplate; OperationBase() = default; }; template class OperationTemplate : public OperationBase { /* empty per default; specialize if needed */ private: OperationTemplate() = default; friend OperationClass; }; template class OperationMaster { public: class AssignmentExpr { private: AssignmentExpr() = default; OperationMaster& mM; const OpClass& mSec; public: static constexpr size_t LAYER = 0; static constexpr size_t SIZE = OpClass::SIZE; typedef decltype(mSec.rootSteps()) ExtType; AssignmentExpr(OperationMaster& m, const OpClass& sec); AssignmentExpr(const AssignmentExpr& in) = default; AssignmentExpr(AssignmentExpr&& in) = default; inline void operator()(size_t start = 0) const; inline void operator()(size_t start, ExtType last) const; auto rootSteps(std::intptr_t iPtrNum = 0) const -> ExtType; }; typedef T value_type; //typedef OperationBase OB; typedef ContainerRange CRange; typedef ContainerIndex IndexType; //typedef typename MultiRange::IndexType IndexType; OperationMaster(MutableMultiArrayBase& ma, const OpClass& second, IndexType& index); OperationMaster(T* data, const OpClass& second, IndexType& index); inline void set(size_t pos, T val) { mDataPtr[pos] = val; } inline void add(size_t pos, T val) { mDataPtr[pos] += val; } inline T get(size_t pos) const; private: void performAssignment(std::intptr_t blockIndexNum); OpClass const& mSecond; //MutableMultiArrayBase& mArrayRef; T* mDataPtr; IndexType mIndex; }; template class ConstOperationRoot : public OperationTemplate > { public: typedef T value_type; typedef OperationBase > OT; typedef ContainerRange CRange; typedef ContainerIndex IndexType; static constexpr size_t SIZE = 1; ConstOperationRoot(const MultiArrayBase& ma, const std::shared_ptr&... indices); ConstOperationRoot(std::shared_ptr > maptr, const std::shared_ptr&... indices); ConstOperationRoot(const T* data, const IndexType& ind); template inline T get(ET pos) const; template inline const ConstOperationRoot& set(ET pos) const; MExt rootSteps(std::intptr_t iPtrNum = 0) const; // nullptr for simple usage with decltype template Expr loop(Expr exp) const; const T* data() const; private: //MultiArrayBase const& mArrayRef; const T* mDataPtr; mutable IndexType mIndex; mutable size_t mOff = 0; std::shared_ptr > mMaPtr; // never remove this ptr, otherwise we lose temporary container instances! }; template class StaticCast : public OperationTemplate > { private: const Op& mOp; public: typedef T value_type; typedef OperationBase > OT; typedef typename Op::CRange CRange; typedef typename Op::IndexType IndexType; static constexpr size_t SIZE = Op::SIZE; StaticCast(const Op& op); template inline T get(ET pos) const; template inline const StaticCast& set(ET pos) const; auto rootSteps(std::intptr_t iPtrNum = 0) const -> decltype(mOp.rootSteps(iPtrNum)); template Expr loop(Expr exp) const; }; template StaticCast staticcast(const Op& op) { return StaticCast(op); } template class MetaOperationRoot : public OperationTemplate, MetaOperationRoot > { public: typedef ContainerIndex, typename Ranges::IndexType...> IndexType; typedef typename IndexType::MetaType value_type; typedef OperationBase > OT; typedef ContainerRange CRange; static constexpr size_t SIZE = 1; MetaOperationRoot(const IndexType& ind); template inline value_type get(ET pos) const; template inline const MetaOperationRoot& set(ET pos) const; MExt rootSteps(std::intptr_t iPtrNum = 0) const; // nullptr for simple usage with decltype template Expr loop(Expr exp) const; private: //MultiArrayBase const& mArrayRef; //const T* mDataPtr; IndexType mIndex; }; template class OperationRoot : public OperationTemplate > { public: typedef T value_type; typedef OperationBase > OT; typedef ContainerRange CRange; typedef ContainerIndex IndexType; static constexpr size_t SIZE = 1; OperationRoot(MutableMultiArrayBase& ma, const std::shared_ptr&... indices); OperationRoot(T* data, const IndexType& ind); template OperationMaster operator=(const OpClass& in); template inline T get(ET pos) const; template inline const OperationRoot& set(ET pos) const; MExt rootSteps(std::intptr_t iPtrNum = 0) const; // nullptr for simple usage with decltype template Expr loop(Expr exp) const; T* data() const; template auto sl(const std::shared_ptr&... inds) -> Slice; private: //MutableMultiArrayBase& mArrayRef; T* mDataPtr; mutable IndexType mIndex; mutable size_t mOff = 0; }; template class OperationValue : public OperationTemplate > { public: typedef T value_type; typedef OperationBase > OT; typedef ContainerRange CRange; typedef ContainerIndex IndexType; static constexpr size_t SIZE = 1; OperationValue(const T& val); template inline T get(ET pos) const; template inline const OperationValue& set(ET pos) const; MExt rootSteps(std::intptr_t iPtrNum = 0) const; // nullptr for simple usage with decltype template Expr loop(Expr exp) const; private: T mVal; }; template size_t sumRootNum() { return typename Op::rootNum(); } template size_t sumRootNum() { return typename Op1::rootNum() + sumRootNum(); } template struct RootSumN { template struct rs { static constexpr size_t SIZE = Op1::SIZE + RootSumN::template rs::SIZE; }; }; template <> struct RootSumN<0> { template struct rs { static constexpr size_t SIZE = Op1::SIZE; }; }; template struct RootSum { static constexpr size_t SIZE = RootSumN::template rs::SIZE; }; template class Operation : public OperationTemplate > { public: typedef T value_type; typedef OperationBase > OT; typedef OpFunction F; static constexpr size_t SIZE = RootSum::SIZE; static constexpr bool FISSTATIC = OpFunction::FISSTATIC; private: std::tuple mOps; std::shared_ptr mF; // only if non-static public: typedef decltype(PackNum::template mkSteps(0, mOps)) ETuple; Operation(const Ops&... ops); Operation(std::shared_ptr ff, const Ops&... ops); template inline T get(ET pos) const; template inline const Operation& set(ET pos) const; auto rootSteps(std::intptr_t iPtrNum = 0) const // nullptr for simple usage with decltype -> decltype(PackNum::mkSteps(iPtrNum, mOps)); template auto loop(Expr exp) const -> decltype(PackNum::mkLoop( mOps, exp)); }; namespace { template struct OpMaker { template static inline auto mkOperation(const std::shared_ptr& f, const Ops&... ops) -> Operation { return Operation(f,ops...); } }; template <> struct OpMaker { template static inline auto mkOperation(const std::shared_ptr& f, const Ops&... ops) -> Operation { return Operation(ops...); } }; } template auto mkOperation(const std::shared_ptr& f, const Ops&... ops) -> Operation { return OpMaker::mkOperation(f, ops...); } template class Contraction : public OperationTemplate > { public: typedef T value_type; typedef OperationBase > OT; static constexpr size_t SIZE = Op::SIZE; private: const Op& mOp; std::shared_ptr mInd; public: typedef decltype(mOp.rootSteps(0)) ETuple; Contraction(const Op& op, std::shared_ptr ind); template inline T get(ET pos) const; template inline const Contraction& set(ET pos) const; auto rootSteps(std::intptr_t iPtrNum = 0) const // nullptr for simple usage with decltype -> decltype(mOp.rootSteps(iPtrNum)); template auto loop(Expr exp) const -> decltype(mInd->iforh(1,exp)); }; template // class SliceContraction : public OperationTemplate //, //SliceContraction,Op,Indices...> > class SliceContraction : public OperationTemplate > { public: typedef MultiArray value_type; typedef OperationTemplate > OT; static constexpr size_t SIZE = Op::SIZE; private: const Op& mOp; mutable MultiArray mCont; mutable OperationRoot mTarOp; public: typedef decltype(mOp.rootSteps(0)) ETuple; SliceContraction(const Op& op, std::shared_ptr... ind); template inline const value_type& get(ET pos) const; template inline const SliceContraction& set(ET pos) const; auto rootSteps(std::intptr_t iPtrNum = 0) const // nullptr for simple usage with decltype -> decltype(mOp.rootSteps(iPtrNum)); template auto loop(Expr exp) const -> decltype(mOp.loop(exp)); // no loop }; } /* ========================= * * --- TEMPLATE CODE --- * * ========================= */ namespace MultiArrayTools { namespace { using namespace MultiArrayHelper; } /*************************** * OperationTemplate * ***************************/ template template auto OperationBase::operator+(const OperationBase& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(THIS(), in.THIS()); } template template auto OperationBase::operator-(const OperationBase& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(THIS(), in.THIS()); } template template auto OperationBase::operator*(const OperationBase& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(THIS(), in.THIS()); } template template auto OperationBase::operator/(const OperationBase& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(THIS(), in.THIS()); } template template auto OperationBase::c(const std::shared_ptr& ind) const -> Contraction { return Contraction(THIS(), ind); } template template auto OperationBase::sl(const std::shared_ptr&... inds) const -> ConstSlice { ConstSlice out(inds->range()...); out.define(inds...) = THIS(); return out; } template template auto OperationBase::slc(const std::shared_ptr&... inds) const -> SliceContraction { return SliceContraction (THIS(), inds...); } /***************************************** * OperationMaster::AssignmentExpr * *****************************************/ template OperationMaster::AssignmentExpr:: AssignmentExpr(OperationMaster& m, const OpClass& sec) : mM(m), mSec(sec) {} template inline void OperationMaster::AssignmentExpr:: operator()(size_t start, ExtType last) const { //VCHECK(mSec.template get(last)); mM.add(start, mSec.template get(last) ); } template typename OperationMaster::AssignmentExpr::ExtType OperationMaster::AssignmentExpr:: rootSteps(std::intptr_t iPtrNum) const { return mSec.rootSteps(iPtrNum); } /************************* * OperationMaster * *************************/ template OperationMaster:: OperationMaster(MutableMultiArrayBase& ma, const OpClass& second, IndexType& index) : mSecond(second), mDataPtr(ma.data()), mIndex(index) { performAssignment(0); } template OperationMaster:: OperationMaster(T* data, const OpClass& second, IndexType& index) : mSecond(second), mDataPtr(data), mIndex(index) { performAssignment(0); } template void OperationMaster::performAssignment(std::intptr_t blockIndexNum) { AssignmentExpr ae(*this, mSecond); // Expression to be executed within loop const auto loop = mSecond.template loop( mIndex.ifor(1,ae) ); // hidden Loops outside ! -> auto vectorizable loop(); // execute overall loop(s) and so internal hidden loops and so the inherited expressions } template inline T OperationMaster::get(size_t pos) const { return mDataPtr[pos]; } /**************************** * ConstOperationRoot * ****************************/ template ConstOperationRoot:: ConstOperationRoot(const MultiArrayBase& ma, const std::shared_ptr&... indices) : mDataPtr(ma.data()), mIndex( ma.begin() ) { //VCHECK(ma.data()); mIndex(indices...); } template ConstOperationRoot:: ConstOperationRoot(std::shared_ptr > maptr, const std::shared_ptr&... indices) : mDataPtr(maptr->data()), mIndex(maptr->begin()), mMaPtr(maptr) { mIndex(indices...); } template ConstOperationRoot:: ConstOperationRoot(const T* data, const IndexType& ind) : mDataPtr(data), mIndex( ind ) { } template template inline T ConstOperationRoot::get(ET pos) const { return mDataPtr[pos.val()+mOff]; } template template inline const ConstOperationRoot& ConstOperationRoot::set(ET pos) const { mIndex = pos.val(); mOff = mIndex.pos(); return *this; } template const T* ConstOperationRoot::data() const { return mDataPtr + mIndex().pos(); } template MExt ConstOperationRoot::rootSteps(std::intptr_t iPtrNum) const { return MExt(getStepSize( mIndex, iPtrNum )); //return MExt(getStepSize( getRootIndices( mIndex->info() ), iPtrNum )); } template template Expr ConstOperationRoot::loop(Expr exp) const { return exp; } /******************** * StaticCast * ********************/ template StaticCast::StaticCast(const Op& op) : mOp(op) {} template template inline T StaticCast::get(ET pos) const { return static_cast( mOp.get(pos) ); } template template inline const StaticCast& StaticCast::set(ET pos) const { mOp.set(pos); return *this; } template auto StaticCast::rootSteps(std::intptr_t iPtrNum) const -> decltype(mOp.rootSteps(iPtrNum)) { return mOp.rootSteps(iPtrNum); } template template Expr StaticCast::loop(Expr exp) const { return mOp.loop(exp); } /**************************** * MetaOperationRoot * ****************************/ template MetaOperationRoot:: MetaOperationRoot(const IndexType& ind) : mIndex( ind ) { } template template inline typename MetaOperationRoot::value_type MetaOperationRoot::get(ET pos) const { //VCHECK(pos.val()); //VCHECK(mDataPtr); //VCHECK(mDataPtr[pos.val()]) return mIndex.meta(pos.val()); } template template inline const MetaOperationRoot& MetaOperationRoot::set(ET pos) const { mIndex = pos.val(); return *this; } template MExt MetaOperationRoot::rootSteps(std::intptr_t iPtrNum) const { return MExt(getStepSize( mIndex, iPtrNum )); //return MExt(getStepSize( getRootIndices( mIndex->info() ), iPtrNum )); } template template Expr MetaOperationRoot::loop(Expr exp) const { return exp; } /*********************** * OperationRoot * ***********************/ template OperationRoot:: OperationRoot(MutableMultiArrayBase& ma, const std::shared_ptr&... indices) : mDataPtr(ma.data()), mIndex( ma.begin() ) { mIndex(indices...); } template OperationRoot:: OperationRoot(T* data, const IndexType& ind) : mDataPtr(data), mIndex( ind ) { } template template OperationMaster OperationRoot::operator=(const OpClass& in) { return OperationMaster(mDataPtr, in, mIndex); } template template inline T OperationRoot::get(ET pos) const { return mDataPtr[pos.val()+mOff]; } template template inline const OperationRoot& OperationRoot::set(ET pos) const { mIndex = pos.val(); mOff = mIndex.pos(); return *this; } template MExt OperationRoot::rootSteps(std::intptr_t iPtrNum) const { return MExt(getStepSize( mIndex, iPtrNum )); //return MExt(getStepSize( mIndex.info(), iPtrNum )); } template template Expr OperationRoot::loop(Expr exp) const { return exp; } template T* OperationRoot::data() const { return mDataPtr + mIndex().pos(); } template template auto OperationRoot::sl(const std::shared_ptr&... inds) -> Slice { Slice out(inds->range()...); out.define(inds...) = *this; return out; } /************************ * OperationValue * ************************/ template OperationValue::OperationValue(const T& val) : mVal(val) {} template template inline T OperationValue::get(ET pos) const { return mVal; } template template inline const OperationValue& OperationValue::set(ET pos) const { return *this; } template MExt OperationValue::rootSteps(std::intptr_t iPtrNum) const { return MExt(0); } template template Expr OperationValue::loop(Expr exp) const { return exp; } /******************* * Operation * *******************/ template Operation::Operation(const Ops&... ops) : mOps(ops...) { static_assert( FISSTATIC, "need function instance for non-static function" ); } template Operation::Operation(std::shared_ptr ff, const Ops&... ops) : mOps(ops...), mF(ff) { static_assert( not FISSTATIC, "using instance of function supposed to be static" ); } template template inline T Operation::get(ET pos) const { typedef std::tuple OpTuple; return PackNum:: template mkOpExpr(mF, pos, mOps); } template template inline const Operation& Operation::set(ET pos) const { PackNum::setOpPos(mOps,pos); return *this; } template auto Operation::rootSteps(std::intptr_t iPtrNum) const -> decltype(PackNum::mkSteps(iPtrNum, mOps)) { return PackNum::mkSteps(iPtrNum, mOps); } template template auto Operation::loop(Expr exp) const -> decltype(PackNum::mkLoop( mOps, exp )) { return PackNum::mkLoop( mOps, exp ); } /********************* * Contraction * *********************/ template Contraction::Contraction(const Op& op, std::shared_ptr ind) : mOp(op), mInd(ind) {} // forward loop !!!! template template inline T Contraction::get(ET pos) const { return mOp.template get(pos); } template template inline const Contraction& Contraction::set(ET pos) const { mOp.set(pos); return *this; } template auto Contraction::rootSteps(std::intptr_t iPtrNum) const -> decltype(mOp.rootSteps(iPtrNum)) { return mOp.rootSteps(iPtrNum); } template template auto Contraction::loop(Expr exp) const -> decltype(mInd->iforh(1,exp)) { return mInd->iforh(1,exp); } /************************** * SliceContraction * **************************/ template SliceContraction::SliceContraction(const Op& op, std::shared_ptr... ind) : mOp(op), mCont(ind->range()...), mTarOp(mCont,ind...) {} // forward loop !!!! template template inline const MultiArray& SliceContraction::get(ET pos) const { mCont *= 0; // grrr mTarOp = mOp.set(pos); // SET FUNCTION!! return mCont; } template template inline const SliceContraction& SliceContraction::set(ET pos) const { mOp.set(pos); return *this; } template auto SliceContraction::rootSteps(std::intptr_t iPtrNum) const -> decltype(mOp.rootSteps(iPtrNum)) { return mOp.rootSteps(iPtrNum); } template template auto SliceContraction::loop(Expr exp) const -> decltype(mOp.loop(exp)) { return mOp.loop(exp); } } #include "type_operations.h" #endif