diff --git a/src/include/base/types.h b/src/include/base/types.h index 9ba70d3..53a360b 100644 --- a/src/include/base/types.h +++ b/src/include/base/types.h @@ -171,12 +171,20 @@ namespace CNORXZ // definition: ranges/urange.h template - class URange; // generic simple range (uni-dimensional) + class URange; // generic simple range (uni-dimensional, ordered) // definition: ranges/urange.h template class UIndex; + // definition: ranges/wrange.h + template + class WRange; // generic simple range (uni-dimensional) + + // definition: ranges/wrange.h + template + class WIndex; + // definition: ranges/prange.h template class PRange; diff --git a/src/include/ranges/ranges.cc.h b/src/include/ranges/ranges.cc.h index 5110bca..19be012 100644 --- a/src/include/ranges/ranges.cc.h +++ b/src/include/ranges/ranges.cc.h @@ -14,6 +14,7 @@ #include "mrange.cc.h" #include "xindex.cc.h" #include "urange.cc.h" +#include "wrange.cc.h" #include "srange.cc.h" #include "crange.cc.h" #include "prange.cc.h" diff --git a/src/include/ranges/ranges.h b/src/include/ranges/ranges.h index ac41e2e..909db59 100644 --- a/src/include/ranges/ranges.h +++ b/src/include/ranges/ranges.h @@ -16,6 +16,7 @@ #include "xindex.h" #include "yrange.h" #include "urange.h" +#include "wrange.h" #include "srange.h" #include "crange.h" #include "prange.h" diff --git a/src/include/ranges/urange.cc.h b/src/include/ranges/urange.cc.h index b8878f2..9d5a6a7 100644 --- a/src/include/ranges/urange.cc.h +++ b/src/include/ranges/urange.cc.h @@ -395,9 +395,6 @@ namespace CNORXZ } }; - template struct is_vector : std::false_type {}; - template struct is_vector> : std::true_type {}; - template struct URangeCast> { diff --git a/src/include/ranges/urange.h b/src/include/ranges/urange.h index 7c3605a..8e3b825 100644 --- a/src/include/ranges/urange.h +++ b/src/include/ranges/urange.h @@ -165,7 +165,7 @@ namespace CNORXZ i.e. the parameter space can be arbitrary. However, the parameter space is assumed to be ordered, i.e. the i-1-th element is assumed to be smaller (according to std::less) than the i-th element. - (In the future, there will be another range type, where random ordering is possible.) + If you require arbitrary ordering, use WRange / WIndex instead! @tparam MetaT Meta data type. */ template @@ -244,6 +244,11 @@ namespace CNORXZ { static constexpr bool value = true; }; + + // TODO: move to utils file!!! + template struct is_vector : std::false_type {}; + template struct is_vector> : std::true_type {}; + } #endif diff --git a/src/include/ranges/wrange.cc.h b/src/include/ranges/wrange.cc.h new file mode 100644 index 0000000..db7e84d --- /dev/null +++ b/src/include/ranges/wrange.cc.h @@ -0,0 +1,503 @@ +// -*- C++ -*- +/** + + @file include/ranges/wrange.cc.h + @brief WRange, WRangeFactory and WIndex implementations. + + Copyright (c) 2024 Christian Zimmermann. All rights reserved. + Mail: chizeta@f3l.de + +**/ + +#ifndef __cxz_wrange_cc_h__ +#define __cxz_wrange_cc_h__ + +#include +#include + +#include "wrange.h" +#include "prange.h" +#include "index_mul.h" +#include "xpr/for.h" +#include "operation/op_types.h" +#include "operation/op_types.cc.h" + +namespace CNORXZ +{ + /*===============+ + | WIndex | + +===============*/ + + template + WIndex::WIndex(const RangePtr& range, SizeT pos) : + IndexInterface,MetaT>(pos), + mRangePtr(rangeCast(range)), + mMetaPtr(mRangePtr->get()), + mSpaceToPos(mRangePtr->spaceToPos()), + mPosToSpace(mRangePtr->posToSpace()) + {} + + template + WIndex& WIndex::operator=(size_t lexpos) + { + IB::mPos = lexpos; + return *this; + } + + template + WIndex& WIndex::operator++() + { + ++IB::mPos; + return *this; + } + + template + WIndex& WIndex::operator--() + { + --IB::mPos; + return *this; + } + + template + WIndex WIndex::operator+(Int n) const + { + return WIndex(mRangePtr, IB::mPos + n); + } + + template + WIndex WIndex::operator-(Int n) const + { + return WIndex(mRangePtr, IB::mPos - n); + } + + template + SizeT WIndex::operator-(const WIndex& i) const + { + return lex() - i.lex(); + } + + template + WIndex& WIndex::operator+=(Int n) + { + IB::mPos += n; + return *this; + } + + template + WIndex& WIndex::operator-=(Int n) + { + IB::mPos -= n; + return *this; + } + + template + SizeT WIndex::lex() const + { + return IB::mPos; + } + + template + UPos WIndex::pmax() const + { + return UPos(mRangePtr->size()); + } + + template + UPos WIndex::lmax() const + { + return UPos(mRangePtr->size()); + } + + template + IndexId<0> WIndex::id() const + { + return IndexId<0>(this->ptrId()); + } + + template + const MetaT& WIndex::operator*() const + { + return meta(); + } + + template + String WIndex::stringMeta() const + { + return toString(this->meta()); + } + + template + const MetaT& WIndex::meta() const + { + return mMetaPtr[mPosToSpace[IB::mPos]]; + } + + template + WIndex& WIndex::at(const MetaT& metaPos) + { + (*this) = mRangePtr->getMeta(metaPos); + return *this; + } + + template + decltype(auto) WIndex::xpr(const Sptr>& _this) const + { + CXZ_ERROR("not implemented"); // TODO: Operation root with reordered meta data access!!! + return coproot(mMetaPtr,_this); + } + + template + RangePtr WIndex::prange(const WIndex& last) const + { + CXZ_ASSERT(last >= *this, "got last index position (" << last.lex() + << ") smaller than begin index position (" << lex() << ")"); + const SizeT beginPos = lex(); + Vector parts(last.lex()-beginPos+1); + for(auto i = *this; i != last+1; ++i){ + parts[i.lex()-beginPos] = i.lex(); + } + return CNORXZ::prange(mRangePtr, parts); + } + + template + SizeT WIndex::deepFormat() const + { + return 1; + } + + template + SizeT WIndex::deepMax() const + { + return lmax().val(); + } + + template + WIndex& WIndex::reformat(const Vector& f, const Vector& s) + { + CXZ_ASSERT(f[0]*s[0] == lmax().val(), "got wrong extension: " << f[0]*s[0] + << " vs " << lmax().val()); + CXZ_ASSERT(CNORXZ::formatIsTrivial(f,s), "format is not trivial: f = " << toString(f) + << ", s = " << toString(s)); + return *this; + } + + template + size_t WIndex::dim() const // = 1 + { + return 1; + } + + template + Sptr> WIndex::range() const + { + return mRangePtr; + } + + template + template + decltype(auto) WIndex::stepSize(const IndexId& id) const + { + if constexpr(I != 0){ + return SPos<0>(); + } + else { + return UPos(id == this->id() ? 1 : 0); + } + } + + template + template + decltype(auto) WIndex::ifor(const Xpr& xpr, F&& f) const + { + return For<0,Xpr,F>(this->pmax().val(), this->id(), xpr, std::forward(f)); + } + + template + bool WIndex::formatIsTrivial() const + { + return true; + } + + template + decltype(auto) operator*(const Sptr>& a, const Sptr& b) + { + return iptrMul(a, b); + } + + /*====================+ + | WRangeFactory | + +====================*/ + + template + WRangeFactory::WRangeFactory(const Vector& space) : + mSpace(space) {} + + template + WRangeFactory::WRangeFactory(Vector&& space) : + mSpace(space) {} + + template + WRangeFactory::WRangeFactory(const Vector& space, const RangePtr& ref) : + mSpace(space), mRef(ref) {} + + template + WRangeFactory::WRangeFactory(Vector&& space, const RangePtr& ref) : + mSpace(space), mRef(ref) {} + + template + void WRangeFactory::make() + { + const auto& info = typeid(WRange); + if(mRef != nullptr) { + mProd = this->fromCreated(info, {mRef->id()}); + } + if(mProd == nullptr){ + RangePtr key = mProd = std::shared_ptr> + ( new WRange( std::move(mSpace) ) ); + if(mRef != nullptr) { key = mRef; } + this->addToCreated(info, { key->id() }, mProd); + } + } + + /*=============+ + | WRange | + +=============*/ + + template + void WRange::setupSpace(const Vector& space) + { + mSpace = space; + const SizeT s = mSpace.size(); + mSpaceToPos.resize(s); + mPosToSpace.resize(s); + std::sort(mSpace.begin(), mSpace.end(), std::less()); + auto itdupl = std::adjacent_find(mSpace.begin(), mSpace.end()); + CXZ_ASSERT(itdupl == mSpace.end(), "found duplicate: " << *itdupl); + for(SizeT lx = 0; lx != s; ++lx){ + for(SizeT sp = 0; sp != s; ++sp){ + if(space[lx] == mSpace[sp]){ + mPosToSpace[lx] = sp; + mSpaceToPos[sp] = lx; + break; + } + } + } + } + + template + WRange::WRange(const Vector& space) : + RangeInterface>() + { + setupSpace(space); + } + + template + WRange::WRange(Vector&& space) : + RangeInterface>() + { + setupSpace(space); + } + + + template + const MetaT& WRange::get(SizeT pos) const + { + return mSpace[mPosToSpace[pos]]; + } + + template + const MetaT* WRange::get() const + { + return mSpace.data(); + } + + template + SizeT WRange::getMeta(const MetaT& meta) const + { + auto b = mSpace.begin(); + auto e = mSpace.end(); + auto i = std::lower_bound(b, e, meta, std::less()); + if(i == e){ + return size(); + } + if(*i != meta){ + return size(); + } + return mSpaceToPos[i - b]; + } + + template + SizeT WRange::size() const + { + return mSpace.size(); + } + + template + SizeT WRange::dim() const + { + return 1; + } + + template + String WRange::stringMeta(SizeT pos) const + { + return toString(this->get(pos)); + } + + template + const TypeInfo& WRange::type() const + { + return typeid(WRange); + } + + template + const TypeInfo& WRange::metaType() const + { + return typeid(MetaT); + } + + template + RangePtr WRange::extend(const RangePtr& r) const + { + auto rx = rangeCast>(r); + Vector nspace(mSpace.size()+rx->size()); + SizeT i = 0; + for(; i != mSpace.size(); ++i){ + nspace[i] = mSpace[mPosToSpace[i]]; + } + for(SizeT j = 0; j != rx->mSpace.size(); ++j, ++i){ + nspace[i] = rx->mSpace[rx->mPosToSpace[j]]; + } + return WRangeFactory( nspace ).create(); + } + + template + Vector WRange::key() const + { + return Vector { this->id() }; + } + + /*=================+ + | Range Casts | + +=================*/ + + template + struct WRangeCast + { + template + static inline Sptr> transform(const RangePtr& r) + { + if(r->type() == typeid(PRange>)){ + return transform( std::dynamic_pointer_cast>>(r)->derive() ); + } + else if(r->type() == typeid(WRange)){ + auto rr = std::dynamic_pointer_cast>(r); + Vector v(rr->size()); + std::transform(rr->begin(), rr->end(), v.begin(), + [](const T& x) { return static_cast(x); } ); + return std::dynamic_pointer_cast> + ( WRangeFactory(std::move(v)).create() ); + } + else { + return nullptr; + } + } + + static inline Sptr> cast(const RangePtr& r) + { + static_assert(std::is_fundamental::value, "got non-fundamental type"); + CXZ_ASSERT(r->dim() == 1, "range cast into WRange: source range must have dim = 1, got " << r->dim()); + Sptr> o = nullptr; + // TODO: cast from CRange!!! + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + // else general transform using DType (better than nothing), to be implemented!!! + CXZ_ERROR("no range cast available for input range '" << r->type().name() << "'"); + return nullptr; + } + }; + + template + struct WRangeCast> + { + template + static inline Sptr>> transform(const RangePtr& r) + { + if(r->type() == typeid(WRange)){ + auto rr = std::dynamic_pointer_cast>(r); + Vector> v(rr->size()); + std::transform(rr->begin(), rr->end(), v.begin(), + [](const T& x) { return Vector { static_cast(x) }; } ); + return std::dynamic_pointer_cast>> + ( WRangeFactory>(std::move(v)).create() ); + } + else { + return nullptr; + } + } + + template + static inline Sptr>> atransform(const RangePtr& r) + { + if(r->type() == typeid(WRange>)){ + auto rr = std::dynamic_pointer_cast>>(r); + Vector> v(rr->size()); + std::transform(rr->begin(), rr->end(), v.begin(), + [](const Arr& x) { + return iter<0,N>( [&](auto i) { return static_cast(x[i]); }, + [](const auto&... e) { return Vector{ e... }; }); + } ); + return std::dynamic_pointer_cast>> + ( WRangeFactory>(std::move(v)).create() ); + } + else { + return nullptr; + } + } + + static inline Sptr>> cast(const RangePtr& r) + { + Sptr>> o = nullptr; + if constexpr(std::is_fundamental::value){ + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + o = transform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + o = atransform(r); if(o) return o; + } + // else general transform using DType (better than nothing), to be implemented!!! + CXZ_ERROR("no range cast available for input range '" << r->type().name() << "'"); + } + }; + + + template + Sptr> RangeCast>::func(const RangePtr& r) + { + if constexpr(std::is_fundamental::value or is_vector::value){ + return WRangeCast::cast(r); + } + else { + CXZ_ERROR("no range cast available for input range '" << r->type().name() << "'"); + return nullptr; + } + } + + template + RangePtr wrange(const Vector& space) + { + return WRangeFactory(space).create(); + } + +} + +#endif diff --git a/src/include/ranges/wrange.h b/src/include/ranges/wrange.h new file mode 100644 index 0000000..363bfc5 --- /dev/null +++ b/src/include/ranges/wrange.h @@ -0,0 +1,266 @@ +// -*- C++ -*- +/** + + @file include/ranges/wrange.h + @brief WRange, WRangeFactory and WIndex declaration. + + Copyright (c) 2024 Christian Zimmermann. All rights reserved. + Mail: chizeta@f3l.de + +**/ + +#ifndef __cxz_wrange_h__ +#define __cxz_wrange_h__ + +#include "base/base.h" +#include "ranges/index_base.h" +#include "ranges/range_base.h" +#include "xpr/xpr.h" + +#include + +namespace CNORXZ +{ + + /** **** + Specific index for WRange. + @tparam MetaT Meta data type. + */ + template + class WIndex : public IndexInterface,MetaT> + { + public: + + typedef IndexInterface,MetaT> IB; + typedef WRange RangeType; + typedef MetaT MetaType; + + INDEX_RANDOM_ACCESS_ITERATOR_DEFS(MetaType); + DEFAULT_MEMBERS(WIndex); /**< default constructors and assignments */ + + /** Construct index from range and position. + @param range Range to iterate over. + @param pos lexicographic position. + */ + WIndex(const RangePtr& range, SizeT pos = 0); + + /** @copydoc IndexInterface::operator=(SizeT) */ + WIndex& operator=(SizeT lexpos); + + /** @copydoc IndexInterface::operator++() */ + WIndex& operator++(); + + /** @copydoc IndexInterface::operator--() */ + WIndex& operator--(); + + /** @copydoc IndexInterface::operator+() */ + WIndex operator+(Int n) const; + + /** @copydoc IndexInterface::operator-() */ + WIndex operator-(Int n) const; + + /** @copydoc IndexInterface::operator-(WIndex) */ + SizeT operator-(const WIndex& i) const; + + /** @copydoc IndexInterface::operator+=() */ + WIndex& operator+=(Int n); + + /** @copydoc IndexInterface::operator-=() */ + WIndex& operator-=(Int n); + + /** @copydoc IndexInterface::lex() */ + SizeT lex() const; + + /** @copydoc IndexInterface::pmax() */ + UPos pmax() const; + + /** @copydoc IndexInterface::lmax() */ + UPos lmax() const; + + /** @copydoc IndexInterface::id() */ + IndexId<0> id() const; + + /** @copydoc IndexInterface::operator*() */ + const MetaT& operator*() const; + + /** @copydoc IndexInterface::dim() */ + SizeT dim() const; // = 1 + + /** @copydoc IndexInterface::range() */ + Sptr range() const; + + /** @copydoc IndexInterface::stepSize() */ + template + decltype(auto) stepSize(const IndexId& id) const; + + /** @copydoc IndexInterface::stringMeta() */ + String stringMeta() const; + + /** @copydoc IndexInterface::meta() */ + const MetaT& meta() const; + + /** @copydoc IndexInterface::at() */ + WIndex& at(const MetaT& metaPos); + + /** @copydoc IndexInterface::prange() */ + RangePtr prange(const WIndex& last) const; + + /** @copydoc IndexInterface::deepFormat() */ + SizeT deepFormat() const; + + /** @copydoc IndexInterface::deepMax() */ + SizeT deepMax() const; + + /** @copydoc IndexInterface::reformat() */ + WIndex& reformat(const Vector& f, const Vector& s); + + /** @copydoc IndexInterface::ifor() */ + template + decltype(auto) ifor(const Xpr& xpr, F&& f) const; + + /** @copydoc IndexInterface::formatIsTrivial() */ + bool formatIsTrivial() const; + + /** @copydoc IndexInterface::xpr() */ + decltype(auto) xpr(const Sptr>& _this) const; + + private: + Sptr mRangePtr; + const MetaT* mMetaPtr; + const SizeT* mSpaceToPos; + const SizeT* mPosToSpace; + }; + + template + void swap(WIndex& a, WIndex& b) { a.swap(b); } + + /** Make index pack of a WIndex and another index. + @param a pointer to WIndex. + @param b pointer to another index. + */ + template + decltype(auto) operator*(const Sptr>& a, const Sptr& b); + + /** **** + Specific factory for WRange. + @tparam MetaT Meta data type. + */ + template + class WRangeFactory : public RangeFactoryBase + { + public: + WRangeFactory(const Vector& space); + WRangeFactory(Vector&& space); + WRangeFactory(const Vector& space, const RangePtr& ref); + WRangeFactory(Vector&& space, const RangePtr& ref); + + private: + WRangeFactory() = default; + virtual void make() override final; + + Vector mSpace; + RangePtr mRef; + }; + + /** **** + Uni-(1-)dimensional range with non-trivial meta data space + i.e. the parameter space can be arbitrary. In contrast to URange + the meta data can have arbitrary ordering. + Note: Internally, the meta data is still ordered for the sake of performance during look-up. + The externally visible non-ordering is realized through maps between the internal (meta space) + ordering, and the externally visible lexicographic ordering. + @tparam MetaT Meta data type. + */ + template + class WRange : public RangeInterface> + { + public: + typedef RangeBase RB; + typedef WIndex IndexType; + typedef MetaT MetaType; + + friend WRangeFactory; + + virtual SizeT size() const override final; + virtual SizeT dim() const override final; + virtual String stringMeta(SizeT pos) const override final; + virtual const TypeInfo& type() const override final; + virtual const TypeInfo& metaType() const override final; + virtual RangePtr extend(const RangePtr& r) const override final; + + /** Get meta data at given range position. + @param pos Integer indicating requested position. + @return Meta data at given postion. + */ + const MetaType& get(SizeT pos) const; + + /** Get range position for given meta data. + Returns size() if metaPos is not part of the range. + @param metaPos Meta data. + @return Position of the given meta data if it is contained by the range. + */ + SizeT getMeta(const MetaType& metaPos) const; + + /** Get meta data array. + @return Pointer to first element (memory ordering) of the underlying meta data array. + */ + const MetaType* get() const; + + /** Get map from meta space memory position to lexicographic position. + @return Pointer to first element of the map. + */ + const SizeT* spaceToPos() const; + + /** Get map from lexicographic position to meta space memory position. + @return Pointer to first element of the map. + */ + const SizeT* posToSpace() const; + + private: + + void setupSpace(const Vector& space); + + WRange() = default; + WRange(const WRange& in) = delete; + WRange(const Vector& space); + WRange(Vector&& space); + + Vector mSpace; + Vector mSpaceToPos; + Vector mPosToSpace; + + virtual Vector key() const override final; + + SERIALIZATION_FUNCTIONS_NOPUB; + }; + + /** *** + Specialize RangeCast for casts to WRange + @see RangeCast + */ + template + struct RangeCast> + { + /** cast the range */ + static Sptr> func(const RangePtr& r); + }; + + /** Create an WRange, calls WRangeFactory. + @param space Meta data space to create an WRange on. + @return Created range. + */ + template + RangePtr wrange(const Vector& space); + + /** *** + WIndex can be used as expression + @see index_expression_exists + */ + template + struct index_expression_exists> + { + static constexpr bool value = true; + }; +} + +#endif