change operator* for indices -> creates index packs instead of m/yindices

This commit is contained in:
Christian Zimmermann 2023-01-11 17:32:52 +01:00
parent 603d03971d
commit 55922490b2
12 changed files with 357 additions and 143 deletions

View file

@ -20,7 +20,7 @@ namespace CNORXZ
template <typename I, typename M>
const T& CArrayBase<T>::operator[](const IndexInterface<I,M>& i) const
{
auto ai = this->begin() + i.lex();
auto ai = itLex(i);
return *ai;
}
@ -28,11 +28,37 @@ namespace CNORXZ
template <typename I, typename M>
const T& CArrayBase<T>::at(const IndexInterface<I,M>& i) const
{
CXZ_ASSERT(i.lex() < this->size(), "index out of range");
auto beg = this->begin();
//CXZ_ASSERT(false, "IMPLEMENT CHECKS!!");
// check further compatibility of index/range format!!!
auto ai = beg + i.lex();
auto ai = itLexSave(i);
return *ai;
}
template <typename T>
template <class... Indices>
const T& CArrayBase<T>::operator[](const SPack<Indices...>& pack) const
{
auto ai = itLex(pack);
return *ai;
}
template <typename T>
template <class... Indices>
const T& CArrayBase<T>::at(const SPack<Indices...>& pack) const
{
auto ai = itLexSave(pack);
return *ai;
}
template <typename T>
const T& CArrayBase<T>::operator[](const DPack& pack) const
{
auto ai = itLex(pack);
return *ai;
}
template <typename T>
const T& CArrayBase<T>::at(const DPack& pack) const
{
auto ai = itLexSave(pack);
return *ai;
}
@ -78,6 +104,27 @@ namespace CNORXZ
return coproot(*this, i);
}
/******************************
* CArrayBase (protected) *
******************************/
template <typename T>
template <class Acc>
typename CArrayBase<T>::const_iterator CArrayBase<T>::itLex(const Acc& acc) const
{
return begin() + acc.lex();
}
template <typename T>
template <class Acc>
typename CArrayBase<T>::const_iterator CArrayBase<T>::itLexSave(const Acc& acc) const
{
CXZ_ASSERT(acc.lex() < this->size(), "index out of range");
//CXZ_ASSERT(false, "IMPLEMENT CHECKS!!");
// check further compatibility of index/range format!!!
return begin() + acc.lex();
}
/*****************
* ArrayBase *
*****************/
@ -91,17 +138,45 @@ namespace CNORXZ
template <typename I, typename M>
T& ArrayBase<T>::operator[](const IndexInterface<I,M>& i)
{
auto ai = this->begin() + i.lex();
auto ai = itLex(i);
return *ai;
}
template <typename T>
template <typename I, typename M>
T& ArrayBase<T>::at(const IndexInterface<I,M>& i)
{
CXZ_ASSERT(i.lex() < this->size(), "index out of range");
// check further compatibility of index/range format!!!
auto ai = this->begin() + i.lex();
auto ai = itLexSave(i);
return *ai;
}
template <typename T>
template <class... Indices>
T& ArrayBase<T>::operator[](const SPack<Indices...>& pack)
{
auto ai = itLex(pack);
return *ai;
}
template <typename T>
template <class... Indices>
T& ArrayBase<T>::at(const SPack<Indices...>& pack)
{
auto ai = itLexSave(pack);
return *ai;
}
template <typename T>
T& ArrayBase<T>::operator[](const DPack& pack)
{
auto ai = itLex(pack);
return *ai;
}
template <typename T>
T& ArrayBase<T>::at(const DPack& pack)
{
auto ai = itLexSave(pack);
return *ai;
}
@ -135,6 +210,27 @@ namespace CNORXZ
return oproot(*this, i);
}
/*****************************
* ArrayBase (protected) *
*****************************/
template <typename T>
template <class Acc>
typename ArrayBase<T>::iterator ArrayBase<T>::itLex(const Acc& acc)
{
return begin() + acc.lex();
}
template <typename T>
template <class Acc>
typename ArrayBase<T>::iterator ArrayBase<T>::itLexSave(const Acc& acc)
{
CXZ_ASSERT(acc.lex() < this->size(), "index out of range");
//CXZ_ASSERT(false, "IMPLEMENT CHECKS!!");
// check further compatibility of index/range format!!!
return begin() + acc.lex();
}
}
#endif

View file

@ -19,11 +19,6 @@ namespace CNORXZ
public:
typedef AIndex<T> const_iterator;
protected:
RangePtr mRange;
public:
CArrayBase(const RangePtr& range);
DEFAULT_MEMBERS(CArrayBase);
@ -35,6 +30,15 @@ namespace CNORXZ
template <typename I, typename M>
const T& at(const IndexInterface<I,M>& i) const;
template <class... Indices>
const T& operator[](const SPack<Indices...>& pack) const;
template <class... Indices>
const T& at(const SPack<Indices...>& pack) const;
const T& operator[](const DPack& pack) const;
const T& at(const DPack& pack) const;
template <typename I, typename M>
Sptr<CArrayBase<T>> sl(const IndexInterface<I,M>& i) const;
@ -52,6 +56,14 @@ namespace CNORXZ
template <class Index>
COpRoot<T,Index> operator()(const Sptr<Index>& i) const;
protected:
RangePtr mRange;
template <class Acc>
const_iterator itLex(const Acc& acc) const;
template <class Acc>
const_iterator itLexSave(const Acc& acc) const;
};
template <typename T>
@ -80,6 +92,15 @@ namespace CNORXZ
template <typename I, typename M>
T& at(const IndexInterface<I,M>& i);
template <class... Indices>
T& operator[](const SPack<Indices...>& pack);
template <class... Indices>
T& at(const SPack<Indices...>& pack);
T& operator[](const DPack& pack);
T& at(const DPack& pack);
template <typename I, typename M>
Sptr<ArrayBase<T>> sl(const IndexInterface<I,M>& i);
@ -91,6 +112,13 @@ namespace CNORXZ
template <class Index>
OpRoot<T,Index> operator()(const Sptr<Index>& i);
protected:
template <class Acc>
iterator itLex(const Acc& acc);
template <class Acc>
iterator itLexSave(const Acc& acc);
};
}

View file

@ -6,41 +6,6 @@
namespace CNORXZ
{
/*****************
* MIndexMul *
*****************/
template <class BlockT, class... Indices, class I, typename Meta, SizeT... Is>
constexpr decltype(auto) MIndexMul::evalMX(const GMIndex<BlockT,Indices...>& a,
const IndexInterface<I,Meta>& b,
Isq<Is...> is)
{
static_assert(sizeof...(Is) == sizeof...(Indices), "inconsistent index sequence");
return MIndex<Indices...,I>( a.pack()[CSizeT<Is>{}]...,
std::make_shared<I>(b.THIS()) );
}
template <class BlockT, class... Indices, class I, typename Meta, SizeT... Js>
constexpr decltype(auto) MIndexMul::evalXM(const IndexInterface<I,Meta>& a,
const GMIndex<BlockT,Indices...>& b,
Isq<Js...> js)
{
static_assert(sizeof...(Js) == sizeof...(Indices), "inconsistent index sequence");
return MIndex<Indices...,I>( std::make_shared<I>(a.THIS()),
b.pack()[CSizeT<Js>{}]... );
}
template <class BlockT1, class... Indices1, class BlockT2, class... Indices2,
SizeT... Is, SizeT... Js>
constexpr decltype(auto) MIndexMul::evalMM(const GMIndex<BlockT1,Indices1...>& a,
const GMIndex<BlockT2,Indices2...>& b,
Isq<Is...> is, Isq<Js...> js)
{
static_assert(sizeof...(Is) == sizeof...(Indices1), "inconsistent index sequence");
static_assert(sizeof...(Js) == sizeof...(Indices2), "inconsistent index sequence");
return MIndex<Indices1...,Indices2...>( a.pack()[CSizeT<Is>{}]...,
b.pack()[CSizeT<Js>{}]... );
}
/*********************
* MIndexSptrMul *
@ -79,58 +44,57 @@ namespace CNORXZ
/*****************
* operator* *
*****************/
template <class I1, typename Meta1, class I2, typename Meta2>
constexpr decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const IndexInterface<I2,Meta2>& b)
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const IndexInterface<I2,Meta2>& b)
{
if constexpr(std::is_same<I1,DIndex>::value){
if constexpr(std::is_same<I2,DIndex>::value){
return YIndex({ a.THIS().xptr(), b.THIS().xptr() });
}
else if constexpr(std::is_same<I2,YIndex>::value){
auto p = b.THIS().pack();
auto n = p.lmul( a.THIS().xptr() );
return YIndex(n.all());
}
}
else if constexpr(std::is_same<I1,YIndex>::value){
if constexpr(std::is_same<I2,DIndex>::value){
auto p = a.THIS().pack();
auto n = p.rmul( b.THIS().xptr() );
return YIndex(n.all());
}
else if constexpr(std::is_same<I2,YIndex>::value){
auto ap = a.THIS().pack().all();
const auto& bp = b.THIS().pack();
ap.insert(ap.end(), bp.all().begin(), bp.all().end());
return YIndex(ap);
}
if constexpr(std::is_same<I1,YIndex>::value or std::is_same<I2,YIndex>::value or
std::is_same<I1,DIndex>::value or std::is_same<I2,DIndex>::value) {
return dpack(a.THIS(), b.THIS());
}
else {
constexpr SizeT I1D = index_dim<I1>::value;
constexpr SizeT I2D = index_dim<I2>::value;
if constexpr(I1D == 1){
if constexpr(I2D == 1){
return MIndex<I1,I2>(a.THIS(),b.THIS());
}
else {
return MIndexMul::evalXM(a, b.THIS(), std::make_index_sequence<I2D>{});
}
}
else {
if constexpr(I2D == 1){
return MIndexMul::evalMX(a.THIS(), b, std::make_index_sequence<I1D>{});
}
else {
return MIndexMul::evalMM(a.THIS(), b.THIS(),
std::make_index_sequence<I1D>{},
std::make_index_sequence<I2D>{});
}
}
return spack(a.THIS(), b.THIS());
}
}
template <class I1, typename Meta1, class... Indices>
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const SPack<Indices...>& b)
{
return b.lmul(std::make_shared<I1>(a.THIS()));
}
template <class I2, typename Meta2, class... Indices>
inline decltype(auto) operator*(const SPack<Indices...>& a,
const IndexInterface<I2,Meta2>& b)
{
return a.rmul(std::make_shared<I2>(b.THIS()));
}
template <class... Indices1, class... Indices2>
inline decltype(auto) operator*(const SPack<Indices1...>& a, const SPack<Indices2...>& b)
{
return a.mul(b);
}
template <class I1, typename Meta1>
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a, const DPack& b)
{
return b.lmul(std::make_shared<I1>(a.THIS()));
}
template <class I2, typename Meta2>
inline decltype(auto) operator*(const DPack& a, const IndexInterface<I2,Meta2>& b)
{
return a.rmul(std::make_shared<I2>(b.THIS()));
}
inline decltype(auto) operator*(const DPack& a, const DPack& b)
{
return a.mul(b);
}
/***************
* iptrMul *
***************/

View file

@ -7,25 +7,6 @@
namespace CNORXZ
{
struct MIndexMul
{
template <class BlockT, class... Indices, class I, typename Meta, SizeT... Is>
static constexpr decltype(auto) evalMX(const GMIndex<BlockT,Indices...>& a,
const IndexInterface<I,Meta>& b,
Isq<Is...> is);
template <class BlockT, class... Indices, class I, typename Meta, SizeT... Js>
static constexpr decltype(auto) evalXM(const IndexInterface<I,Meta>& a,
const GMIndex<BlockT,Indices...>& b,
Isq<Js...> js);
template <class BlockT1, class... Indices1, class BlockT2, class... Indices2,
SizeT... Is, SizeT... Js>
static constexpr decltype(auto) evalMM(const GMIndex<BlockT1,Indices1...>& a,
const GMIndex<BlockT2,Indices2...>& b,
Isq<Is...> is, Isq<Js...> js);
};
struct MIndexSptrMul
{
template <class BlockT, class... Indices, class I, SizeT... Is>
@ -44,9 +25,29 @@ namespace CNORXZ
};
template <class I1, typename Meta1, class I2, typename Meta2>
constexpr decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const IndexInterface<I2,Meta2>& b);
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const IndexInterface<I2,Meta2>& b);
template <class I1, typename Meta1, class... Indices>
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a,
const SPack<Indices...>& b);
template <class I2, typename Meta2, class... Indices>
inline decltype(auto) operator*(const SPack<Indices...>& a,
const IndexInterface<I2,Meta2>& b);
template <class... Indices1, class... Indices2>
inline decltype(auto) operator*(const SPack<Indices1...>& a, const SPack<Indices2...>& b);
template <class I1, typename Meta1>
inline decltype(auto) operator*(const IndexInterface<I1,Meta1>& a, const DPack& b);
template <class I2, typename Meta2>
inline decltype(auto) operator*(const DPack& a, const IndexInterface<I2,Meta2>& b);
inline decltype(auto) operator*(const DPack& a, const DPack& b);
template <class I1, class I2>
decltype(auto) iptrMul(const Sptr<I1>& a, const Sptr<I2>& b);
}

View file

@ -6,6 +6,10 @@
namespace CNORXZ
{
/*************
* SPack *
*************/
template <class... Indices>
constexpr SPack<Indices...>::SPack(const Sptr<Indices>&... is) :
mIs(is...)
@ -40,14 +44,14 @@ namespace CNORXZ
template <class Index>
constexpr decltype(auto) SPack<Indices...>::rmul(const Sptr<Index>& i) const
{
return SPack<Indices...,Index>( std::tuple_cat(mIs,i) );
return SPack<Indices...,Index>( std::tuple_cat(mIs,std::make_tuple(i)) );
}
template <class... Indices>
template <class Index>
constexpr decltype(auto) SPack<Indices...>::lmul(const Sptr<Index>& i) const
{
return SPack<Index,Indices...>( std::tuple_cat(i, mIs) );
return SPack<Index,Indices...>( std::tuple_cat(std::make_tuple(i), mIs) );
}
template <class... Indices>
@ -56,6 +60,72 @@ namespace CNORXZ
{
return SPack<Indices...,Indices2...>( std::tuple_cat(mIs, all()) );
}
template <class... Indices>
decltype(auto) SPack<Indices...>::mkRange() const
{
return iter<0,sizeof...(Indices)>( [&](auto i) { return get(i)->range(); },
[](const auto&... e) { return mrange(e...); } );
}
template <class... Indices>
SizeT SPack<Indices...>::lex() const
{
return iter<0,sizeof...(Indices)-1>
( [&](auto i) { return get(i)->lex() * iter<i+1,sizeof...(Indices)>
( [&](auto j) { return get(j)->lmax().val(); },
[](const auto&... m) { return ( m * ... ); } ); },
[](const auto&... e) { return ( e + ... ); } ) +
get(CSizeT<sizeof...(Indices)-1>{})->lex() ;
}
/**************************
* SPack (non-member) *
**************************/
template <class... Indices>
constexpr decltype(auto) spack(const Indices&... inds)
{
static_assert((is_index<Indices>::value and ...), "got non-index type");
return SPack<Indices...>( std::make_shared<Indices>(inds)... );
}
template <class... Indices>
constexpr decltype(auto) spackp(const Sptr<Indices>&... inds)
{
static_assert((is_index<Indices>::value and ...), "got non-index type");
return SPack<Indices...>( inds... );
}
/*************
* DPack *
*************/
template <class... Indices>
DPack::DPack(const SPack<Indices...>& p) :
mIs( iter<0,sizeof...(Indices)>
( [&](auto i) { return xindexPtr(p[i]); },
[](const auto&... e) { return { e... }; } )
)
{}
/**************************
* DPack (non-member) *
**************************/
template <class... Indices>
DPack dpack(const Indices&... inds)
{
return DPack( Vector<XIndexPtr>( { xindexPtr( std::make_shared<Indices>( inds ) )... } ) );
}
template <class... Indices>
DPack dpackp(const Sptr<Indices>&... inds)
{
return DPack( Vector<XIndexPtr>( { xindexPtr( inds )... } ) );
}
}
#endif

View file

@ -33,29 +33,50 @@ namespace CNORXZ
template <class... Indices2>
constexpr decltype(auto) mul(const SPack<Indices2...>& p) const;
decltype(auto) mkRange() const;
SizeT lex() const;
private:
Tuple<Sptr<Indices>...> mIs;
};
template <class... Indices>
constexpr decltype(auto) spack(const Indices&... inds);
template <class... Indices>
constexpr decltype(auto) spackp(const Sptr<Indices>&... inds);
class DPack
{
public:
DEFAULT_MEMBERS(DPack);
DPack(const Vector<XIndexPtr>& is);
DPack(Vector<XIndexPtr>&& is);
explicit DPack(const Vector<XIndexPtr>& is);
explicit DPack(Vector<XIndexPtr>&& is);
template <class... Indices>
explicit DPack(const SPack<Indices...>& p);
const Vector<XIndexPtr>& all() const;
SizeT size() const;
const XIndexPtr& get(SizeT i) const;
const XIndexPtr& operator[](SizeT i) const;
DPack rmul(const XIndexPtr& i) const;
DPack lmul(const XIndexPtr& i) const;
DPack rmul(const Sptr<DIndex>& i) const;
DPack lmul(const Sptr<DIndex>& i) const;
DPack mul(const DPack& p) const;
RangePtr mkRange() const;
SizeT lex() const;
private:
Vector<XIndexPtr> mIs;
};
template <class... Indices>
DPack dpack(const Indices&... inds);
template <class... Indices>
DPack dpackp(const Sptr<Indices>&... inds);
}
#endif

View file

@ -163,10 +163,10 @@ namespace CNORXZ
}
template <class FormatT, class... Indices>
constexpr GMIndex<FormatT,Indices...>::GMIndex(const Indices&... is) :
constexpr GMIndex<FormatT,Indices...>::GMIndex(const SPack<Indices...>& pack) :
IndexInterface<GMIndex<FormatT,Indices...>,Tuple<typename Indices::MetaType...>>(0),
mRange(std::dynamic_pointer_cast<RangeType>(mrange(is.range()...))),
mIPack(std::make_shared<Indices>(is)...),
mRange(std::dynamic_pointer_cast<RangeType>(pack.mkRange())),
mIPack(pack),
mLexFormat(mkLexFormat(mIPack,Isqr<1,NI>{})),
mFormat(),
mLMax(mkLMax(mIPack)),
@ -176,10 +176,10 @@ namespace CNORXZ
}
template <class FormatT, class... Indices>
constexpr GMIndex<FormatT,Indices...>::GMIndex(const FormatT& bs, const Indices&... is) :
constexpr GMIndex<FormatT,Indices...>::GMIndex(const FormatT& bs, const SPack<Indices...>& pack) :
IndexInterface<GMIndex<FormatT,Indices...>,Tuple<typename Indices::MetaType...>>(0),
mRange(std::dynamic_pointer_cast<RangeType>(mrange(is.range()...))),
mIPack(std::make_shared<Indices>(is)...),
mRange(std::dynamic_pointer_cast<RangeType>(pack.mkRange())),
mIPack(pack),
mLexFormat(mkLexFormat(mIPack,Isqr<1,NI>{})),
mFormat(bs),
mLMax(mkLMax(mIPack)),
@ -482,7 +482,13 @@ namespace CNORXZ
constexpr decltype(auto) mindex(const Sptr<Indices>&... is)
{
return MIndex<Indices...>(is...);
}
}
template <class... Indices>
constexpr decltype(auto) mindex(const SPack<Indices...>& pack)
{
return MIndex<Indices...>(pack);
}
template <class FormatT, class... Indices>
constexpr decltype(auto) gmindexPtr(const FormatT& bs, const Sptr<Indices>&... is)

View file

@ -34,10 +34,8 @@ namespace CNORXZ
constexpr GMIndex(const GMIndex& i);
constexpr GMIndex& operator=(const GMIndex& i);
//constexpr GMIndex(const SPack<Indices...>& is);
//constexpr GMIndex(const FormatT& format, const SPack<Indices...>& is);
constexpr GMIndex(const Indices&... is);
constexpr GMIndex(const FormatT& format, const Indices&... is);
constexpr GMIndex(const SPack<Indices...>& pack);
constexpr GMIndex(const FormatT& format, const SPack<Indices...>& pack);
constexpr GMIndex(const Sptr<Indices>&... is);
constexpr GMIndex(const FormatT& format, const Sptr<Indices>&... is);
constexpr GMIndex(const RangePtr& range, SizeT lexpos = 0);
@ -146,6 +144,9 @@ namespace CNORXZ
template <class... Indices>
constexpr decltype(auto) mindex(const Sptr<Indices>&... is);
template <class... Indices>
constexpr decltype(auto) mindex(const SPack<Indices...>& pack);
template <class FormatT, class... Indices>
constexpr decltype(auto) gmindexPtr(const FormatT& bs, const Sptr<Indices>&... is);

View file

@ -87,6 +87,7 @@ namespace CNORXZ
UPos mLMax = 0;
};
YIndex yindex(const DPack& pack);
YIndex yindex(const Vector<XIndexPtr>& is);
Sptr<YIndex> yindexPtr(const Vector<XIndexPtr>& is);
Sptr<YIndex> yindexPtr(const Vector<SizeT>& bs, const Vector<XIndexPtr>& is);

View file

@ -1,5 +1,5 @@
#include "ranges/index_pack.h"
#include "ranges/ranges.h"
namespace CNORXZ
{
@ -31,18 +31,18 @@ namespace CNORXZ
return get(i);
}
DPack DPack::rmul(const XIndexPtr& i) const
DPack DPack::rmul(const Sptr<DIndex>& i) const
{
auto o = mIs;
o.push_back(i);
o.push_back(i->xptr());
return DPack(std::move(o));
}
DPack DPack::lmul(const XIndexPtr& i) const
DPack DPack::lmul(const Sptr<DIndex>& i) const
{
Vector<XIndexPtr> o;
o.reserve(size()+1);
o.push_back(i);
o.push_back(i->xptr());
o.insert(o.end(), mIs.begin(), mIs.end());
return DPack(std::move(o));
}
@ -56,4 +56,25 @@ namespace CNORXZ
return DPack(std::move(o));
}
RangePtr DPack::mkRange() const
{
Vector<RangePtr> o(mIs.size());
std::transform(mIs.begin(), mIs.end(), o.begin(),
[](const auto& i) { return i->range(); } );
return yrange(o);
}
SizeT DPack::lex() const
{
if(mIs.size() == 0) { return 0; }
const SizeT isizem1 = mIs.size()-1;
SizeT o = mIs[isizem1]->lex();
SizeT m = mIs[isizem1]->lmax().val();
for(SizeT i = isizem1; i != 0; --i){
const SizeT j = i-1;
o += mIs[j]->lex() * m;
m *= mIs[j]->lmax().val();
}
return o;
}
}

View file

@ -382,6 +382,11 @@ namespace CNORXZ
* non-member functions *
****************************/
YIndex yindex(const DPack& pack)
{
return YIndex(pack.all());
}
YIndex yindex(const Vector<XIndexPtr>& is)
{
return YIndex(is);

View file

@ -419,20 +419,20 @@ namespace
for(auto cix = crx->begin(); cix != crx->end(); ++cix){
for(auto uix = urx->begin(); uix != urx->end(); ++uix){
const SizeT p1 = cix.lex()*s1 + uix.lex();
EXPECT_EQ((cix*uix).lex(), p1);
EXPECT_EQ(mindex(cix*uix).lex(), p1);
for(auto ci2x = crx->begin(); ci2x != crx->end(); ++ci2x){
const SizeT p2 = cix.lex()*s1*s2 + uix.lex()*s2 + ci2x.lex();
EXPECT_EQ((cix*uix*ci2x).lex(), p2);
EXPECT_EQ(mindex(cix*uix*ci2x).lex(), p2);
}
}
}
for(auto ci = cr->begin(); ci != cr->end(); ++ci){
for(auto ui = ur->begin(); ui != ur->end(); ++ui){
const SizeT p = ci.lex()*s1 + ui.lex();
EXPECT_EQ((ci*ui).lex(), p);
EXPECT_EQ(yindex(ci*ui).lex(), p);
for(auto ci2 = cr->begin(); ci2 != cr->end(); ++ci2){
const SizeT p2 = ci.lex()*s1*s2 + ui.lex()*s2 + ci2.lex();
EXPECT_EQ((ci*ui*ci2).lex(), p2);
EXPECT_EQ(yindex(ci*ui*ci2).lex(), p2);
}
}
}