// -*- C++ -*- #ifndef __multi_array_operation_h__ #define __multi_array_operation_h__ #include #include #include #include #include #include "base_def.h" namespace MultiArrayTools { namespace { using namespace MultiArrayHelper; } /* * OperationBase * MutableOperationBase * * OperationMaster : MutableOperationBase * * OperationTemplate<...> * ConstOperationRoot : OperationBase, OperationTemplate<...> * OperationRoot : MutableOperationBase, * OperationTemplate<...> * */ void seekIndexInst(std::shared_ptr i, std::vector >& ivec); // typedef std::pair BTSS; BTSS getBlockType(std::shared_ptr i, std::shared_ptr j, bool first, size_t higherStepSize = 1); template std::shared_ptr > makeBlock(const std::vector& vec, size_t stepSize, size_t blockSize); template std::shared_ptr > makeBlock(std::vector& vec, size_t stepSize, size_t blockSize); size_t getBTNum(const std::vector& mp, BlockType bt); void minimizeAppearanceOfType(std::map, std::vector >& mp, BlockType bt); template std::shared_ptr seekBlockIndex(std::shared_ptr ownIdx, const OpClass& second); template class OperationTemplate { public: OperationTemplate(OperationClass* oc); template auto operator+(const Second& in) const -> Operation,OperationClass,Second>; template auto operator-(const Second& in) const -> Operation,OperationClass,Second>; template auto operator*(const Second& in) const -> Operation,OperationClass,Second>; template auto operator/(const Second& in) const -> Operation,OperationClass,Second>; template auto c(std::shared_ptr& ind) const -> Contraction; private: OperationClass* mOc; }; template class OperationMaster/* : public MutableOperationBase*/ { public: typedef T value_type; typedef OperationBase OB; typedef ContainerRange CRange; typedef typename MultiRange::IndexType IndexType; OperationMaster(MutableMultiArrayBase& ma, const OpClass& second, std::shared_ptr& index); MBlock& get(); const Block& get() const; std::vector block(const std::shared_ptr blockIndex) const; const OperationMaster& block() const; protected: //void performAssignment(const OperationBase& in); OpClass const& mSecond; MutableMultiArrayBase& mArrayRef; std::shared_ptr mIndex; mutable std::shared_ptr > mBlockPtr; }; template class ConstOperationRoot : /*public OperationBase,*/ public OperationTemplate > { public: typedef T value_type; typedef OperationBase OB; typedef OperationTemplate > OT; typedef ContainerRange CRange; typedef typename CRange::IndexType IndexType; ConstOperationRoot(const MultiArrayBase& ma, const std::shared_ptr&... indices); const Block& get() const; std::vector block(const std::shared_ptr blockIndex) const; const ConstOperationRoot& block() const; protected: MultiArrayBase const& mArrayRef; std::shared_ptr mIndex; mutable std::shared_ptr > mBlockPtr; }; template class OperationRoot : /*public MutableOperationBase,*/ public OperationTemplate > { public: typedef T value_type; typedef OperationBase OB; typedef OperationTemplate > OT; typedef ContainerRange CRange; typedef typename CRange::IndexType IndexType; OperationRoot(MutableMultiArrayBase& ma, const std::shared_ptr&... indices); template OperationMaster operator=(const OpClass& in); const MBlock& get() const; MBlock& get(); std::vector block(const std::shared_ptr blockIndex) const; const OperationRoot& block() const; protected: MutableMultiArrayBase& mArrayRef; std::shared_ptr mIndex; mutable std::shared_ptr > mBlockPtr; }; template class Operation : /*public OperationBase,*/ public OperationTemplate > { public: typedef T value_type; typedef OperationBase OB; typedef OperationTemplate > OT; typedef OpFunction F; Operation(const Ops&... ops); const BlockResult& get() const; std::vector block(const std::shared_ptr blockIndex) const; const Operation& block() const; protected: std::tuple mOps; mutable BlockResult mRes; }; template class Contraction : public OperationTemplate > { public: typedef T value_type; typedef OperationTemplate > OT; Contraction(const Op& op, std::shared_ptr ind); const BlockResult& get() const; std::vector block(const std::shared_ptr blockIndex) const; const Contraction& block() const; protected: Op mOp; std::shared_ptr mInd; mutable BlockResult mRes; }; } /* ========================= * * --- TEMPLATE CODE --- * * ========================= */ namespace MultiArrayTools { namespace { using namespace MultiArrayHelper; } void seekIndexInst(std::shared_ptr i, std::vector >& ivec) { for(size_t inum = 0; inum != i->rangePtr()->dim(); ++inum){ auto ii = i->getPtr(inum); if(ii->type() == IndexType::MULTI or ii->type() == IndexType::CONT){ seekIndexInst(ii, ivec); } ivec.push_back(ii); } } BTSS getBlockType(std::shared_ptr i, std::shared_ptr j, bool first, size_t higherStepSize) { // returning BlockType and step size is redundant (change in the future) // stepSize == 0 => VALUE // stepSize == 1 => BLOCK // stepSize > 1 => SPLIT :) BTSS out(BlockType::VALUE, 0); size_t lastNum = i->rangePtr()->dim(); for(size_t inum = 0; inum != lastNum; ++inum){ auto ii = i->getPtr(inum); if(ii == j){ if(inum == lastNum - 1 and first){ out = BTSS(BlockType::BLOCK, 1); } else { first = false; out = BTSS(BlockType::SPLIT, i->getStepSize(inum) * higherStepSize + out.second); } continue; } if(ii->type() == IndexType::MULTI or ii->type() == IndexType::CONT){ BTSS tmp = getBlockType(ii, j, inum == lastNum - 1, i->getStepSize(inum) * higherStepSize); if(tmp.first != BlockType::VALUE){ out = tmp; } } } return out; } template std::shared_ptr > makeBlock(const std::vector& vec, size_t stepSize, size_t blockSize) { return std::make_shared >(vec, 0, blockSize, stepSize); } template std::shared_ptr > makeBlock(std::vector& vec, size_t stepSize, size_t blockSize) { return std::make_shared >(vec, 0, blockSize, stepSize); } size_t getBTNum(const std::vector& mp, BlockType bt) { size_t out = 0; for(auto& xx: mp){ if(xx.first == bt){ ++out; } } return out; } void minimizeAppearanceOfType(std::map, std::vector >& mp, BlockType bt) { size_t minNum = getBTNum( mp.begin()->second, bt ); for(auto& mm: mp){ size_t tmp = getBTNum( mm.second, bt ); if(tmp < minNum){ minNum = tmp; } } for(auto mit = mp.begin(); mit != mp.end(); ){ size_t tmp = getBTNum( mit->second, bt ); if(tmp > minNum){ mit = mp.erase(mit); } else { ++mit; } } } template std::shared_ptr seekBlockIndex(std::shared_ptr ownIdx, const OpClass& second) { std::vector > ivec; seekIndexInst(ownIdx, ivec); std::map, std::vector > mp; for(auto& xx: ivec){ mp[xx] = second.block(xx); } // seek minimal number of VALUEs => guarantees absence of conflicting blocks minimizeAppearanceOfType(mp, BlockType::VALUE); // seek mininmal number of SPLITs => maximal vectorization possible minimizeAppearanceOfType(mp, BlockType::SPLIT); return mp.begin()->first; } /*************************** * OperationTemplate * ***************************/ template OperationTemplate::OperationTemplate(OperationClass* oc) : mOc(oc) {} template template auto OperationTemplate::operator+(const Second& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(*mOc, in); } template template auto OperationTemplate::operator-(const Second& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(*mOc, in); } template template auto OperationTemplate::operator*(const Second& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(*mOc, in); } template template auto OperationTemplate::operator/(const Second& in) const -> Operation,OperationClass,Second> { return Operation,OperationClass,Second>(*mOc, in); } template template auto OperationTemplate::c(std::shared_ptr& ind) const -> Contraction { return Contraction(*mOc, ind); } /************************* * OperationMaster * *************************/ template OperationMaster:: OperationMaster(MutableMultiArrayBase& ma, const OpClass& second, std::shared_ptr& index) : mSecond(second), mArrayRef(ma), mIndex() { MultiRangeFactory mrf( index->range() ); std::shared_ptr > mr = std::dynamic_pointer_cast >( mrf.create() ); mIndex = std::make_shared( mr->begin() ); (*mIndex) = *index; auto blockIndex = seekBlockIndex( mIndex, second); intptr_t blockIndexNum = blockIndex->getPtrNum(); block(blockIndex); second.block(blockIndex); for(*mIndex = 0; mIndex->pos() != mIndex->max(); mIndex->pp(blockIndexNum) ){ get() = mSecond.get(); } } template MBlock& OperationMaster::get() { block(); return *mBlockPtr; } template const Block& OperationMaster::get() const { block(); return *mBlockPtr; } template std::vector OperationMaster::block(const std::shared_ptr blockIndex) const { std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); mBlockPtr = makeBlock(mArrayRef.datav(), btv[0].second, blockIndex->max()); return btv; } template const OperationMaster& OperationMaster::block() const { mBlockPtr->set( mIndex->pos() ); return *this; } /**************************** * ConstOperationRoot * ****************************/ template ConstOperationRoot:: ConstOperationRoot(const MultiArrayBase& ma, const std::shared_ptr&... indices) : OperationTemplate >(this), mArrayRef(ma), mIndex( std::make_shared( mArrayRef.range() ) ) { (*mIndex)(indices...); } template const Block& ConstOperationRoot::get() const { block(); return *mBlockPtr; } template std::vector ConstOperationRoot::block(const std::shared_ptr blockIndex) const { std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); mBlockPtr = makeBlock(mArrayRef.datav(), btv[0].second, blockIndex->max()); return btv; } template const ConstOperationRoot& ConstOperationRoot::block() const { mBlockPtr->set( (*mIndex)().pos() ); return *this; } /*********************** * OperationRoot * ***********************/ template OperationRoot:: OperationRoot(MutableMultiArrayBase& ma, const std::shared_ptr&... indices) : OperationTemplate >(this), mArrayRef(ma), mIndex( std::make_shared( mArrayRef.range() ) ) { (*mIndex)(indices...); } template template OperationMaster OperationRoot::operator=(const OpClass& in) { return OperationMaster(mArrayRef, in, mIndex); } template const MBlock& OperationRoot::get() const { block(); return *mBlockPtr; } template MBlock& OperationRoot::get() { block(); return *mBlockPtr; } template std::vector OperationRoot::block(const std::shared_ptr blockIndex) const { std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); mBlockPtr = makeBlock(mArrayRef.datav(), btv[0].second, blockIndex->max()); return btv; } template const OperationRoot& OperationRoot::block() const { mBlockPtr->set( (*mIndex)().pos() ); return *this; } /******************* * Operation * *******************/ template Operation::Operation(const Ops&... ops) : OperationTemplate >(this), mOps(ops...) {} template const BlockResult& Operation::get() const { mRes = std::move( PackNum::template unpackArgs(mOps) ); return mRes; } template std::vector Operation::block(const std::shared_ptr blockIndex) const { std::vector btv; PackNum::makeBlockTypeVec(btv, mOps, blockIndex); return btv; } template const Operation& Operation::block() const { //mBlockPtr->set( mIndex->pos() ); return *this; } /********************* * Contraction * *********************/ template Contraction::Contraction(const Op& op, std::shared_ptr ind) : OperationTemplate >(this), mOp(op), mInd(ind) {} template const BlockResult& Contraction::get() const { BlockBinaryOpSelf,decltype(mOp.get())> f(mRes); for(*mInd = 0; mInd->pos() != mInd->max(); ++(*mInd)){ f(mOp.get()); } return mRes; } template std::vector Contraction::block(const std::shared_ptr blockIndex) const { return mOp.block(blockIndex); } template const Contraction& Contraction::block() const { return *this; } } #endif