add WRange (same as URange but with arbitrary meta data ordering)

This commit is contained in:
Christian Zimmermann 2024-04-18 18:01:19 +02:00
parent 9ea47a20a3
commit e8b6dd9f4d
7 changed files with 786 additions and 5 deletions

View file

@ -171,12 +171,20 @@ namespace CNORXZ
// definition: ranges/urange.h
template <typename Meta>
class URange; // generic simple range (uni-dimensional)
class URange; // generic simple range (uni-dimensional, ordered)
// definition: ranges/urange.h
template <typename Meta>
class UIndex;
// definition: ranges/wrange.h
template <typename Meta>
class WRange; // generic simple range (uni-dimensional)
// definition: ranges/wrange.h
template <typename Meta>
class WIndex;
// definition: ranges/prange.h
template <class Range>
class PRange;

View file

@ -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"

View file

@ -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"

View file

@ -395,9 +395,6 @@ namespace CNORXZ
}
};
template <typename T> struct is_vector : std::false_type {};
template <typename T, typename A> struct is_vector<std::vector<T,A>> : std::true_type {};
template <typename U>
struct URangeCast<Vector<U>>
{

View file

@ -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 <typename MetaT>
@ -244,6 +244,11 @@ namespace CNORXZ
{
static constexpr bool value = true;
};
// TODO: move to utils file!!!
template <typename T> struct is_vector : std::false_type {};
template <typename T, typename A> struct is_vector<std::vector<T,A>> : std::true_type {};
}
#endif

View file

@ -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 <functional>
#include <algorithm>
#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 <typename MetaT>
WIndex<MetaT>::WIndex(const RangePtr& range, SizeT pos) :
IndexInterface<WIndex<MetaT>,MetaT>(pos),
mRangePtr(rangeCast<RangeType>(range)),
mMetaPtr(mRangePtr->get()),
mSpaceToPos(mRangePtr->spaceToPos()),
mPosToSpace(mRangePtr->posToSpace())
{}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::operator=(size_t lexpos)
{
IB::mPos = lexpos;
return *this;
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::operator++()
{
++IB::mPos;
return *this;
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::operator--()
{
--IB::mPos;
return *this;
}
template <typename MetaT>
WIndex<MetaT> WIndex<MetaT>::operator+(Int n) const
{
return WIndex(mRangePtr, IB::mPos + n);
}
template <typename MetaT>
WIndex<MetaT> WIndex<MetaT>::operator-(Int n) const
{
return WIndex(mRangePtr, IB::mPos - n);
}
template <typename MetaT>
SizeT WIndex<MetaT>::operator-(const WIndex& i) const
{
return lex() - i.lex();
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::operator+=(Int n)
{
IB::mPos += n;
return *this;
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::operator-=(Int n)
{
IB::mPos -= n;
return *this;
}
template <typename MetaT>
SizeT WIndex<MetaT>::lex() const
{
return IB::mPos;
}
template <typename MetaT>
UPos WIndex<MetaT>::pmax() const
{
return UPos(mRangePtr->size());
}
template <typename MetaT>
UPos WIndex<MetaT>::lmax() const
{
return UPos(mRangePtr->size());
}
template <typename MetaT>
IndexId<0> WIndex<MetaT>::id() const
{
return IndexId<0>(this->ptrId());
}
template <typename MetaT>
const MetaT& WIndex<MetaT>::operator*() const
{
return meta();
}
template <typename MetaT>
String WIndex<MetaT>::stringMeta() const
{
return toString(this->meta());
}
template <typename MetaT>
const MetaT& WIndex<MetaT>::meta() const
{
return mMetaPtr[mPosToSpace[IB::mPos]];
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::at(const MetaT& metaPos)
{
(*this) = mRangePtr->getMeta(metaPos);
return *this;
}
template <typename MetaT>
decltype(auto) WIndex<MetaT>::xpr(const Sptr<WIndex<MetaT>>& _this) const
{
CXZ_ERROR("not implemented"); // TODO: Operation root with reordered meta data access!!!
return coproot(mMetaPtr,_this);
}
template <typename MetaT>
RangePtr WIndex<MetaT>::prange(const WIndex<MetaT>& last) const
{
CXZ_ASSERT(last >= *this, "got last index position (" << last.lex()
<< ") smaller than begin index position (" << lex() << ")");
const SizeT beginPos = lex();
Vector<SizeT> 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 <typename MetaT>
SizeT WIndex<MetaT>::deepFormat() const
{
return 1;
}
template <typename MetaT>
SizeT WIndex<MetaT>::deepMax() const
{
return lmax().val();
}
template <typename MetaT>
WIndex<MetaT>& WIndex<MetaT>::reformat(const Vector<SizeT>& f, const Vector<SizeT>& 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 <typename MetaT>
size_t WIndex<MetaT>::dim() const // = 1
{
return 1;
}
template <typename MetaT>
Sptr<WRange<MetaT>> WIndex<MetaT>::range() const
{
return mRangePtr;
}
template <typename MetaT>
template <SizeT I>
decltype(auto) WIndex<MetaT>::stepSize(const IndexId<I>& id) const
{
if constexpr(I != 0){
return SPos<0>();
}
else {
return UPos(id == this->id() ? 1 : 0);
}
}
template <typename MetaT>
template <class Xpr, class F>
decltype(auto) WIndex<MetaT>::ifor(const Xpr& xpr, F&& f) const
{
return For<0,Xpr,F>(this->pmax().val(), this->id(), xpr, std::forward<F>(f));
}
template <typename MetaT>
bool WIndex<MetaT>::formatIsTrivial() const
{
return true;
}
template <typename MetaT, class I1>
decltype(auto) operator*(const Sptr<WIndex<MetaT>>& a, const Sptr<I1>& b)
{
return iptrMul(a, b);
}
/*====================+
| WRangeFactory |
+====================*/
template <typename MetaT>
WRangeFactory<MetaT>::WRangeFactory(const Vector<MetaT>& space) :
mSpace(space) {}
template <typename MetaT>
WRangeFactory<MetaT>::WRangeFactory(Vector<MetaT>&& space) :
mSpace(space) {}
template <typename MetaT>
WRangeFactory<MetaT>::WRangeFactory(const Vector<MetaT>& space, const RangePtr& ref) :
mSpace(space), mRef(ref) {}
template <typename MetaT>
WRangeFactory<MetaT>::WRangeFactory(Vector<MetaT>&& space, const RangePtr& ref) :
mSpace(space), mRef(ref) {}
template <typename MetaT>
void WRangeFactory<MetaT>::make()
{
const auto& info = typeid(WRange<MetaT>);
if(mRef != nullptr) {
mProd = this->fromCreated(info, {mRef->id()});
}
if(mProd == nullptr){
RangePtr key = mProd = std::shared_ptr<WRange<MetaT>>
( new WRange<MetaT>( std::move(mSpace) ) );
if(mRef != nullptr) { key = mRef; }
this->addToCreated(info, { key->id() }, mProd);
}
}
/*=============+
| WRange |
+=============*/
template <typename MetaT>
void WRange<MetaT>::setupSpace(const Vector<MetaT>& space)
{
mSpace = space;
const SizeT s = mSpace.size();
mSpaceToPos.resize(s);
mPosToSpace.resize(s);
std::sort(mSpace.begin(), mSpace.end(), std::less<MetaT>());
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 <typename MetaT>
WRange<MetaT>::WRange(const Vector<MetaT>& space) :
RangeInterface<WRange<MetaT>>()
{
setupSpace(space);
}
template <typename MetaT>
WRange<MetaT>::WRange(Vector<MetaT>&& space) :
RangeInterface<WRange<MetaT>>()
{
setupSpace(space);
}
template <typename MetaT>
const MetaT& WRange<MetaT>::get(SizeT pos) const
{
return mSpace[mPosToSpace[pos]];
}
template <typename MetaT>
const MetaT* WRange<MetaT>::get() const
{
return mSpace.data();
}
template <typename MetaT>
SizeT WRange<MetaT>::getMeta(const MetaT& meta) const
{
auto b = mSpace.begin();
auto e = mSpace.end();
auto i = std::lower_bound(b, e, meta, std::less<MetaT>());
if(i == e){
return size();
}
if(*i != meta){
return size();
}
return mSpaceToPos[i - b];
}
template <typename MetaT>
SizeT WRange<MetaT>::size() const
{
return mSpace.size();
}
template <typename MetaT>
SizeT WRange<MetaT>::dim() const
{
return 1;
}
template <typename MetaT>
String WRange<MetaT>::stringMeta(SizeT pos) const
{
return toString(this->get(pos));
}
template <typename MetaT>
const TypeInfo& WRange<MetaT>::type() const
{
return typeid(WRange<MetaT>);
}
template <typename MetaT>
const TypeInfo& WRange<MetaT>::metaType() const
{
return typeid(MetaT);
}
template <typename MetaT>
RangePtr WRange<MetaT>::extend(const RangePtr& r) const
{
auto rx = rangeCast<WRange<MetaT>>(r);
Vector<MetaT> 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<MetaT>( nspace ).create();
}
template <typename MetaT>
Vector<Uuid> WRange<MetaT>::key() const
{
return Vector<Uuid> { this->id() };
}
/*=================+
| Range Casts |
+=================*/
template <typename MetaT>
struct WRangeCast
{
template <typename T>
static inline Sptr<WRange<MetaT>> transform(const RangePtr& r)
{
if(r->type() == typeid(PRange<WRange<T>>)){
return transform<T>( std::dynamic_pointer_cast<PRange<WRange<T>>>(r)->derive() );
}
else if(r->type() == typeid(WRange<T>)){
auto rr = std::dynamic_pointer_cast<WRange<T>>(r);
Vector<MetaT> v(rr->size());
std::transform(rr->begin(), rr->end(), v.begin(),
[](const T& x) { return static_cast<MetaT>(x); } );
return std::dynamic_pointer_cast<WRange<MetaT>>
( WRangeFactory<MetaT>(std::move(v)).create() );
}
else {
return nullptr;
}
}
static inline Sptr<WRange<MetaT>> cast(const RangePtr& r)
{
static_assert(std::is_fundamental<MetaT>::value, "got non-fundamental type");
CXZ_ASSERT(r->dim() == 1, "range cast into WRange<Int>: source range must have dim = 1, got " << r->dim());
Sptr<WRange<MetaT>> o = nullptr;
// TODO: cast from CRange!!!
o = transform<SizeT>(r); if(o) return o;
o = transform<Int>(r); if(o) return o;
o = transform<LInt>(r); if(o) return o;
o = transform<Double>(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 <typename U>
struct WRangeCast<Vector<U>>
{
template <typename T>
static inline Sptr<WRange<Vector<U>>> transform(const RangePtr& r)
{
if(r->type() == typeid(WRange<T>)){
auto rr = std::dynamic_pointer_cast<WRange<T>>(r);
Vector<Vector<U>> v(rr->size());
std::transform(rr->begin(), rr->end(), v.begin(),
[](const T& x) { return Vector<U> { static_cast<U>(x) }; } );
return std::dynamic_pointer_cast<WRange<Vector<U>>>
( WRangeFactory<Vector<U>>(std::move(v)).create() );
}
else {
return nullptr;
}
}
template <typename T, SizeT N>
static inline Sptr<WRange<Vector<U>>> atransform(const RangePtr& r)
{
if(r->type() == typeid(WRange<Arr<T,N>>)){
auto rr = std::dynamic_pointer_cast<WRange<Arr<T,N>>>(r);
Vector<Vector<U>> v(rr->size());
std::transform(rr->begin(), rr->end(), v.begin(),
[](const Arr<T,N>& x) {
return iter<0,N>( [&](auto i) { return static_cast<U>(x[i]); },
[](const auto&... e) { return Vector<U>{ e... }; });
} );
return std::dynamic_pointer_cast<WRange<Vector<U>>>
( WRangeFactory<Vector<U>>(std::move(v)).create() );
}
else {
return nullptr;
}
}
static inline Sptr<WRange<Vector<U>>> cast(const RangePtr& r)
{
Sptr<WRange<Vector<U>>> o = nullptr;
if constexpr(std::is_fundamental<U>::value){
o = transform<SizeT>(r); if(o) return o;
o = transform<Int>(r); if(o) return o;
o = transform<LInt>(r); if(o) return o;
o = transform<Double>(r); if(o) return o;
o = atransform<SizeT,2>(r); if(o) return o;
o = atransform<Int,2>(r); if(o) return o;
o = atransform<LInt,2>(r); if(o) return o;
o = atransform<Double,2>(r); if(o) return o;
o = atransform<SizeT,3>(r); if(o) return o;
o = atransform<Int,3>(r); if(o) return o;
o = atransform<LInt,3>(r); if(o) return o;
o = atransform<Double,3>(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 <typename MetaT>
Sptr<WRange<MetaT>> RangeCast<WRange<MetaT>>::func(const RangePtr& r)
{
if constexpr(std::is_fundamental<MetaT>::value or is_vector<MetaT>::value){
return WRangeCast<MetaT>::cast(r);
}
else {
CXZ_ERROR("no range cast available for input range '" << r->type().name() << "'");
return nullptr;
}
}
template <typename MetaT>
RangePtr wrange(const Vector<MetaT>& space)
{
return WRangeFactory<MetaT>(space).create();
}
}
#endif

266
src/include/ranges/wrange.h Normal file
View file

@ -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 <iterator>
namespace CNORXZ
{
/** ****
Specific index for WRange.
@tparam MetaT Meta data type.
*/
template <typename MetaT>
class WIndex : public IndexInterface<WIndex<MetaT>,MetaT>
{
public:
typedef IndexInterface<WIndex<MetaT>,MetaT> IB;
typedef WRange<MetaT> 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<RangeType> range() const;
/** @copydoc IndexInterface::stepSize() */
template <SizeT I>
decltype(auto) stepSize(const IndexId<I>& 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<MetaType>& last) const;
/** @copydoc IndexInterface::deepFormat() */
SizeT deepFormat() const;
/** @copydoc IndexInterface::deepMax() */
SizeT deepMax() const;
/** @copydoc IndexInterface::reformat() */
WIndex& reformat(const Vector<SizeT>& f, const Vector<SizeT>& s);
/** @copydoc IndexInterface::ifor() */
template <class Xpr, class F>
decltype(auto) ifor(const Xpr& xpr, F&& f) const;
/** @copydoc IndexInterface::formatIsTrivial() */
bool formatIsTrivial() const;
/** @copydoc IndexInterface::xpr() */
decltype(auto) xpr(const Sptr<WIndex<MetaType>>& _this) const;
private:
Sptr<RangeType> mRangePtr;
const MetaT* mMetaPtr;
const SizeT* mSpaceToPos;
const SizeT* mPosToSpace;
};
template <typename MetaT>
void swap(WIndex<MetaT>& a, WIndex<MetaT>& 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 <typename MetaT, class I1>
decltype(auto) operator*(const Sptr<WIndex<MetaT>>& a, const Sptr<I1>& b);
/** ****
Specific factory for WRange.
@tparam MetaT Meta data type.
*/
template <typename MetaT>
class WRangeFactory : public RangeFactoryBase
{
public:
WRangeFactory(const Vector<MetaT>& space);
WRangeFactory(Vector<MetaT>&& space);
WRangeFactory(const Vector<MetaT>& space, const RangePtr& ref);
WRangeFactory(Vector<MetaT>&& space, const RangePtr& ref);
private:
WRangeFactory() = default;
virtual void make() override final;
Vector<MetaT> 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 <typename MetaT>
class WRange : public RangeInterface<WRange<MetaT>>
{
public:
typedef RangeBase RB;
typedef WIndex<MetaT> IndexType;
typedef MetaT MetaType;
friend WRangeFactory<MetaType>;
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<MetaT>& space);
WRange() = default;
WRange(const WRange& in) = delete;
WRange(const Vector<MetaType>& space);
WRange(Vector<MetaType>&& space);
Vector<MetaType> mSpace;
Vector<SizeT> mSpaceToPos;
Vector<SizeT> mPosToSpace;
virtual Vector<Uuid> key() const override final;
SERIALIZATION_FUNCTIONS_NOPUB;
};
/** ***
Specialize RangeCast for casts to WRange
@see RangeCast
*/
template <typename MetaType>
struct RangeCast<WRange<MetaType>>
{
/** cast the range */
static Sptr<WRange<MetaType>> func(const RangePtr& r);
};
/** Create an WRange, calls WRangeFactory.
@param space Meta data space to create an WRange on.
@return Created range.
*/
template <typename MetaT>
RangePtr wrange(const Vector<MetaT>& space);
/** ***
WIndex can be used as expression
@see index_expression_exists
*/
template <typename MetaT>
struct index_expression_exists<WIndex<MetaT>>
{
static constexpr bool value = true;
};
}
#endif