Boost logo

Boost :

From: Larry Evans (jcampbell3_at_[hidden])
Date: 2001-03-22 23:33:54


Jeremy Siek wrote:

...skipping

> I've been working with Ron Garcia on the interface for multi-dim arrays
> the last couple days... still have more work to do there. One of the
> trickier parts is deciding on an interface for subarrays and slicing.
> Blitz++ uses the following notation for specifying subarrays and slices:
>
> A(0, Range(1,2), Range(2, 5)) // ranges are specified has closed intervals
>
> However, this interface results in an interface explosion and has a fixed
> limit on the number of dimensions that can be handled.
>
> Blitz++ has an alternate way to specify subarrays using RectDomain, and
> valarray has the gslice interface, however these approaches are not as
> easy to use.
>
> One possibility I'm looking at starts with the std::slice from valarray,
> but allows them to be combined to specify slices for N dimensions.
>
> A[slice(0)(1,2)(2,3)] // slices here are (start,size=1,stride=1)
> // another sensible option would be to
> // specify slices with half-open intervals
> // (start,finish,stride)
>
> If anyone has any good ideas on a nice interface for specifying subarrays,
> feel free to chime in :)
>

I used to be an apl fan, and tried emulating some of apl's interface's with some c++
classes using expansion vectors described in _An APL Compiler_ by
Timothy Budd(1988). Operations on the expansion vector (size = rank) can be used
to take a slice, rotate the axes.

Attached are a test driver _conslivar.c and a header file, varslirnk.h, declaring a
class used to manipulate the expansion vector. You may find the test driver cryptic,
so I'll give some explanation.

    ; sout<<"===>ConSliOwn CTOR() via SliceOp: From(1)<<UpTo(2)"<<endl
    ; ConSliOwn<double> ownSl(testArr<<From(1)<<UpTo(2)<<EndSli())
    ; sout<<ownSl<<endl

I think this takes a slice out of testArr which drops the 1st element in axis 1, and then
takes the 1st 2 elements of axis 2. This is equivlent to the apl:

    ownS1 <- 2take[2]1drop[1]testArr

For example if:

    testArr =
       {{ 11 , 12, 13}
        , { 21, 22, 23}
        , { 31, 32, 33}
        }

then:

     ownS1 =
        {{ 21, 22}
        , { 31, 32}
        }

The actual data in the array is stored in a T* for the template arg (e.g. double).
Indexing uses the expansion vector and successive operator[](int) to index into this T*.

I found apl's interface very useful; so, I'm suggesting something similar for boost.


//Modification History:
// 96-09-04.1051 evansl
// WHAT:
// Renamed all to nextAx.
// Appended nextAx() call to all sliceops.
// WHY:
// Required by changes to ConSliOps.h file..
// 96-09-03.1343 evansl
// WHAT:
// Renamed next to all.
// WHY:
// all is more meaningful.
// 96-08-22.1840 evansl
// WHAT:
// Copied from _VarSlRnk.
// WHY:
// -
#include "ConSliVar.h"
#include "OwnArrCon.h"
#include "assign.VarArrCon.h"
#define SLICEOP
#ifdef SLICEOP
#include "ConSliOps.h"
#endif

  int
main(void)
  {
  ; IndOstream sout(cout)
  ; sout<<"===>Normal CTOR"<<endl
  ; const int rank=3
  ; const int shapes[rank]={4,4,4}
  ; OwnArrCon<double> testArr(rank,shapes)
  ; assign(testArr)
  ; sout<<"--->begin testArr="<<endl
  ; sout()<<"---config="<<endl<<testArr.config()<<endl
  ; sout<<"---contents="<<endl<<testArr<<endl
  ; {
    ; sout<<"===>ConSliVar CTOR"<<endl
    ; ConSliVar<double> varSl(testArr)
    ; sout<<"--->varSl="<<endl
    ; sout<<varSl<<endl
    ; sout<<"--->varSl.from(1)="<<endl
    ; varSl.from(1).nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->varSl.upto(2)="<<endl
    ; varSl.upto(2).nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->toConSliOwn="<<endl
    ; ConSliOwn<double> ownSl(varSl.toConSliOwn())
    ; sout<<ownSl<<endl
    ;}
  ; {
    ; sout<<"===>ConSliVar CTOR"<<endl
    ; ConSliVar<double> varSl(testArr)
    ; sout<<"--->varSl.frto(2,4)="<<endl
    ; varSl.frto(2,4).nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->varSl.nextAx()="<<endl
    ; varSl.nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->toConSliOwn="<<endl
    ; ConSliOwn<double> ownSl(varSl.toConSliOwn())
    ; sout<<ownSl<<endl
    ;}
  ; {
    ; sout<<"===>ConSliVar CTOR"<<endl
    ; ConSliVar<double> varSl(testArr)
    ; sout<<"--->varSl.from(1).upto(1).frto(2,4)="<<endl
    ; varSl.from(1).nextAx().upto(1).nextAx().frto(2,4).nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->toConSliOwn="<<endl
    ; ConSliOwn<double> ownSl(varSl.toConSliOwn())
    ; sout<<ownSl<<endl
    ;}
  ; {
    ; sout<<"===>ConSliVar CTOR"<<endl
    ; ConSliVar<double> varSl(testArr)
    ; sout<<"--->varSl.from(1)="<<endl
    ; varSl.from(1).nextAx()
    ; sout<<varSl<<endl
    ; sout<<"--->toConSliOwn="<<endl
    ; ConSliOwn<double> ownSl(varSl.toConSliOwn())
    ; sout<<ownSl<<endl
    ; sout<<"===>ConSliVar CTOR2"<<endl
    ; ConSliVar<double> varS2(ownSl)
    ; sout<<"--->varS2.from(1)="<<endl
    ; varS2.from(1).nextAx()
    ; sout<<varS2<<endl
    ; sout<<"--->toConSliOwn="<<endl
    ; ConSliOwn<double> ownS2(varS2.toConSliOwn())
    ; sout<<ownS2<<endl
    ;}
  #ifdef SLICEOP
  ; {
    ; sout<<"===>ConSliOwn CTOR() via SliceOp: From(1)<<UpTo(2)"<<endl
    ; ConSliOwn<double> ownSl(testArr<<From(1)<<UpTo(2)<<EndSli())
    ; sout<<ownSl<<endl
    ;}
  ; {
    ; sout<<"===>ConSliOwn CTOR= via SliceOp: From(1)<<UpTo(2)"<<endl
    ; ConSliOwn<double> ownSl=testArr<<From(1)<<UpTo(2)<<EndSli()
    ; sout<<ownSl<<endl
    ;}
  #endif
  ; sout<<"--->end testArr="<<endl
  ; sout<<testArr<<endl
  ; return 0
  ;}


#ifndef __VarSliRnk_h__
#define __VarSliRnk_h__
//Purpose:
// Provide an intermediate class used to specify the changes to
// a ConEvcRnk or ConSliRnk to produce another ConSliRnk.
// These changes include:
// Taking slices of any axis
// Reversing any axis
// Transposing the axes.
//Modification History:
// 96-10-08.2218 evansl
// WHAT:
// 1.Renamed to VarSliRnk from VarAxsRnk.
// WHY:
// 1.Name more closely reflects purpose.
// 96-09-15.1312 evansl
// WHAT:
// 1.Combined code from VarStpRnk and ConStpPtr.
// WHY:
// 1.Initial version of class def.
#include "ConSliRnk.h"
#include "Permut.h"

class VarSliRnk
  : protected ConSliRnk
  {
  public:

    ConSliRnk::rank
      ;

      VarSliRnk&
    nextAx
      ( void
      )
      {
      ; assert(_axis<rank())
      ; _nextAx()
      ; return *this
      ;}

      VarSliRnk&
    setAx
      ( int axi
      )
      {
      ; assert(-1<axi)
      ; assert(axi<rank())
      ; _axis=axi
      ; return *this
      ;}

      VarSliRnk&
    from
      ( int fri
      )
      {
      ; assert(_axis<rank())
      ; _from(fri)
      ; return *this
      ;}

      VarSliRnk&
    upto
      ( int toi
      )
      {
      ; assert(_axis<rank())
      ; _upto(toi)
      ; return *this
      ;}

      VarSliRnk&
    frto
      ( int fri
      , int toi
      )
      {
      ; assert(_axis<rank())
      ; _frto(fri,toi)
      ; return *this
      ;}

      VarSliRnk&
    trans( void )
      {
      ; _trans()
      ; return *this
      ;}

      VarSliRnk&
    trans( const ExpPerm& p )
      {
      ; assert(p.range() == rank())
      ; assert(p.OK()==ExpPerm::ALL_OK)
      ; _trans(p)
      ; return *this
      ;}

      VarSliRnk&
    reverse( void )
      { assert(_axis<rank())
      ; _reverse()
      ; return *this
      ;}

      VarSliRnk&
    reverse( int ax )
      {
      ; int curAx=slAxis()
      ; setAx(ax)
      ; _reverse()
      ; setAx(curAx)
      ; return *this
      ;}

      int
    slAxis(void)const
      { return _axis
      ;}

      int
    slDisp(void)const
      { return _disp
      ;}

      void
    print(ostream& sout)const
      { ConSliRnk::print(sout)
      ; sout<<"axis="<<slAxis()<<endl
      ; sout<<"disp="<<slDisp()<<endl
      ;}
      
    VarSliRnk(const ConEvcRnk& evec)
      : ConSliRnk(evec, OwnFlag())
      , _axVec(_CTORaxes(evec.rank()))
      , _axis(0)
      , _disp(0)
      {
      ;}

    VarSliRnk(const ConSliRnk& evec)
      : ConSliRnk(evec, OwnFlag())
      , _axVec(_CTORaxes(evec.rank()))
      , _axis(0)
      , _disp(0)
      {
      ;}

      ConSliRnk
    toConSliRnk(void)const
      {
      ; return ConSliRnk(rank(),construct_Evec(*this))
      ;}

    ~VarSliRnk(void)
      { destruct_ArrCfig()
      ; delete[] _axVec
      ;}

      int
    axis(int i)const
      { return _axVec[i]
      ;}

  private:

        static
      EvecElement*
    construct_Evec(const VarSliRnk& evec)
      { const EvecElement* fr=evec.con_Cptr()
      ; const r=evec.rank()
      ; EvecElement* to=construct_ArrCfig(r)
      ; for(int i=-1; i<r; i++)
        {
        ; to[i]=fr[evec.axis(i)]
        ;}
      ; return to
      ;}

      int&
    var_axis(int i)
      { return _axVec[i]
      ;}

      void
    _upto
      ( int toi
      )
      {
      ; int iax=axis(_axis)
      ; int ish=shape(_axis)
      ; assert(toi<=ish)
      ; EvecElement* eVec=var_Cptr()
      ; eVec[iax].var_shape()=toi
      ;}

      void
    _from
      ( int fri
      )
      {
      ; int iax=axis(_axis)
      ; int ish=shape(_axis)
      ; assert(fri<ish)
      ; EvecElement* eVec=var_Cptr()
      ; eVec[iax].var_shape()-=fri
      ; _disp+=fri*stride(iax)
      ;}

      int*
    _TRaxes(void)const
      {
      ; int r=rank()
      ; int* axes = new int[r]
      ; for(int iax=0; iax<r; ++iax)
        { axes[iax]=axis(iax)
        ;}
      ; return axes
      ;}

      void
    _trans
      ( void
      )
      {
      ; int* axes=_TRaxes()
      ; int r=rank()
      ; int r1=r-1
      ; for(int iax=0; iax<r; ++iax)
        {
        ; var_axis(iax)=axes[r1-iax]
        ;}
      ; delete [] axes
      ;}

      void
    _trans
      ( const ExpPerm& axes
      )
      {
      ; int r=rank()
      ; for(int iax=0; iax<r; ++iax)
        {
        ; var_axis(iax)=axes[iax]
        ;}
      ;}

      void
    _reverse
      ( void
      )
      {
      ; EvecElement* eVec=var_Cptr()
      ; int iax=axis(_axis)
      ; int istr=stride(_axis)
      ; int isha=shape(_axis)
      ; eVec[iax].var_stride()=-istr
      ; _disp+=istr*(isha-1)
      ;}

      void
    _frto(int fri, int toi)
      {
      ; _from(fri)
      ; _upto(toi-fri)
      ;}

      void
    _nextAx
      ( void
      )
      {
      ; _axis++
      ;}

        static
      int *
    _CTORaxes(int rank)
      { int* p=new int[rank]
      ; for(int i=0; i<rank; i++)
        {
        ; p[i]=i
        ;}
      ; return p
      ;}

      int*
    _axVec
      ;

      int
    _axis
      ;

      int
    _disp
      ;

  };//end VarSliRnk class

    inline
  ostream&
operator<<(ostream& sout, const VarSliRnk& x)
  { x.print(sout)
  ; return sout
  ;}

#endif


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk