|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: mdvect.h
//
//--------------------------------------------------------------------------
//
// mdvect.h: multi-dimensional array handling
//
#ifndef _MDVECT_H_
#define _MDVECT_H_
/*
Multidimensional array classes and templates.
Each array carries the dimensionality of each dimension as a short integer; the signed value is reinterpreted for projections and redimensioning.
Note that giving a subscript array (VIMD) whose length is less than the dimensionality of the target array produces a subscript with lower dimensions assumed to be equal to zero. This is useful for indexing to lowest-dimensioned rows for probability tables.
Types used (see basics.h):
REAL is a double VLREAL is valarray<REAL> IMD is an unsigned index into a multi-dimensional array VIMD is a vector of IMD SIMD is a signed index into a multi-dimensional array; it's used for projecting dimensions out VSIMD is a vector of SIMD
An MDVSLICE is dimensionality and iteration information for an m-d vector or maxtrix.
The template TMDVDENSE defines a generic multi-dimensional array which a pair of elements: 'first' is a flat (1-d) valarray of an unspecified type (e.g., REAL) 'second' is an MDVSLICE describing its dimensionality
The nested class TMDVDENSE::Iterator (note the capital 'I') is the smart iterator for classes derived from TMDVDENSE<>. */
#include <stdarg.h>
#include "algos.h"
typedef valarray<REAL> VLREAL;
// 'valarray' comparison templates
template<class _V> struct lessv : binary_function<_V, _V, bool> { bool operator()(const _V & vra, const _V & vrb) const { int cmin = _cpp_min( vra.size(), vrb.size() ); for ( int i = 0 ; i < cmin ; i++ ) { if ( vra[i] < vrb[i] ) return true; if ( vra[i] > vrb[i] ) return false; } return vra.size() < vrb.size(); } };
/////////////////////////////////////////////////////////////////////////////////
// Class MDVSLICE:
// Similar to 'gslice'. Has gslice converter (see 'valarray' header).
// Contains integer array of lengths, array of strides
// and starting point.
/////////////////////////////////////////////////////////////////////////////////
class MDVSLICE { public: // Construct a slice from complete data (like gslice)
MDVSLICE ( size_t _S, const VIMD & _L, const VIMD & _D) : _Start(_S), _Len(_L), _Stride(_D) {}
// Construct a slice given only the dimensions
MDVSLICE ( const VIMD & _L, size_t _S = 0 ) { Init( _L, _S ); } MDVSLICE ( int cdim, int ibound, ... ) : _Start(0) { va_list vl; va_start( vl, cdim ); Init( cdim, vl ); }
MDVSLICE ( const VSIMD & vsimd, size_t _S = 0 ) { Init( vsimd, _S ); }
bool operator == ( const MDVSLICE & sl ) const { return _Start == sl._Start && vequal(_Len,sl._Len) && vequal(_Stride,sl._Stride); } bool operator != ( const MDVSLICE & sl ) const { return !(*this == sl); }
// Provided for compatibility with gslice
MDVSLICE() : _Start(0) {}
// Return an equivalent gslice for use with other 'valarray' operations
gslice Gslice () const;
void Init ( const VIMD & _L, size_t _S = 0 ) { _Start = _S; _Len = _L; StrideFromLength(); }
void Init ( const VSIMD & vsimd, size_t _S = 0 ) { int cd = vsimd.size(); vbool vboolMissing(cd); _Len.resize(cd); _Start = _S; for ( int i = 0; i < cd; i++ ) { SIMD simd = vsimd[i]; if ( vboolMissing[i] = simd < 0 ) _Len[i] = - simd; else _Len[i] = simd; } StrideFromLength( & vboolMissing ); }
void Init ( int cdim, ... ) { va_list vl; va_start( vl, cdim ); Init( cdim, vl ); }
void Init ( int cdim, va_list & vl ) { _Len.resize(cdim); for ( int idim = 0; idim < cdim; idim++ ) { _Len[idim] = va_arg(vl,int); } StrideFromLength(); }
/********************************************************
* Accessors to internal data *********************************************************/ size_t start() const {return _Start; } const VIMD & size() const {return _Len; } const VIMD & stride() const {return _Stride; } // Return the number of dimensions
size_t _Nslice() const { return _Len.size(); }
// Return the total number of elements according to this slice
size_t _Totlen() const { size_t _L = _Len.size() > 0; if ( _L ) { for (size_t _I = 0; _I < _Len.size(); ++_I ) { if ( _Len[_I] ) _L *= _Len[_I]; } } return _L; }
/********************************************************
* Subscript handling. There are two levels, one leaves * the subscript array unchanged, the other updates it. * There is a set of overloads for these which allow * reordering of dimensions. *********************************************************/
// Return the index offset based upon the subscript array given
size_t _IOff ( const VIMD& _Idx ) const { size_t _K = _Start; for (size_t _I = 0; _I < _Idx.size(); ++_I) _K += _Idx[_I] * _Stride[_I]; return _K; } // Return the index offset based upon the varargs array given
size_t _IOff ( int i, ... ) const { va_list vl; va_start( vl, i ); return _IOff( i, vl ); } size_t _IOff ( int i, va_list & vl ) const { size_t ioff = _Start; int j; for ( j = 0; j < _Len.size() && i >= 0 ; ++j ) { ioff += i * _Stride[j]; i = va_arg(vl,int); } return j == _Len.size() ? ioff : -1; } // Bump the subscript array to its next valid index
void _Upd (VIMD & _Idx) const { for (size_t _I = _Len.size(); 0 < _I--;) { if (++_Idx[_I] < _Len[_I]) break; _Idx[_I] = 0; } }
// Iterate to the next subscript by computing its offset and updating
// THIS IS THE FUNCTION USED FOR NORMAL ITERATION
size_t _Off (VIMD& _Idx) const { size_t _K = _IOff(_Idx); _Upd(_Idx); return _K; }
// Dimension reordering overloads; each behaves identically to its
// base function, but accepts a dimension reordering array
size_t _IOff(const VIMD& _Idx, const VIMD& _Idim) const { size_t _K = _Start; for (size_t _I = 0; _I < _Idx.size(); ++_I) { size_t _II = _Idim[_I]; _K += _Idx[_II] * _Stride[_II]; } return _K; } void _Upd (VIMD & _Idx, const VIMD& _Idim) const { for (size_t _I = _Len.size(); 0 < _I--;) { size_t _II = _Idim[_I]; if (++_Idx[_II] < _Len[_II]) break; _Idx[_II] = 0; } }
size_t _Off (VIMD& _Idx, const VIMD& _Idim) const { size_t _K = _IOff(_Idx,_Idim); _Upd(_Idx,_Idim); return _K; }
// Return an array like (0,1,2,3,...) for use with
// the dimension-reordering members above
void InitDimReorder ( VIMD & vimdDim ) const { vimdDim.resize( _Nslice() ); for ( size_t i = 0 ; i < vimdDim.size() ; ++i ) { vimdDim[i] = i; } } protected: size_t _Start; // Absolute starting offset into array
VIMD _Len; // Signed integer array of dimension lengths
VIMD _Stride; // Signed integer array of strides
// Given the dimension lengths, compute the array of strides.
inline void StrideFromLength ( const vbool * pvboolMissing = NULL ); };
/////////////////////////////////////////////////////////////////////////////////
//
// Template TMDVDENSE: Generalized multidimensional array handling.
// Base class is 'valarray', so member elements must be available
// (directly or through conversion) for mathematical operations.
// For example, there's a "sum()" member for valarrays.
//
/////////////////////////////////////////////////////////////////////////////////
template<class T> class TMDVDENSE : public pair<valarray<T>,MDVSLICE> { typedef valarray<T> vr_base; typedef pair<valarray<T>,MDVSLICE> pair_base;
public: TMDVDENSE ( const VIMD & vimd ) : pair_base( vr_base(), vimd ) { SyncSize(); } TMDVDENSE () {} ~ TMDVDENSE () {} void Init ( const VIMD & vimd, size_t start = 0 ) { second.Init( vimd, start ); SyncSize(); }
void Init ( const MDVSLICE & mdvs ) { second = mdvs; SyncSize(); } void Init ( int cdim, ... ) { va_list vl; va_start( vl, cdim ); Init( cdim, vl ); }
void Init ( int cdim, va_list & vl ) { second.Init( cdim, vl ); SyncSize(); }
void SyncSize () { size_t cElem = second._Totlen(); if ( first.size() != cElem ) first.resize( cElem ); }
// Subscripting as flat array
T & operator [] ( int i ) { return first.operator[](i); } T operator [] ( int i ) const { return first.operator[](i); }
// Subscripting as m-d array
T & operator [] ( const VIMD & vimd ) { return (*this)[ second._IOff(vimd) ]; } T operator [] ( const VIMD & vimd ) const { return (*this)[ second._IOff(vimd) ]; }
size_t size () const { return first.size(); }
const MDVSLICE & Slice () const { return second ; }
const VIMD & VimdDim () const { return second.size(); }
bool operator == ( const TMDVDENSE & mdv ) const { return vequal(first,mdv.first) && second == mdv.second; } bool operator != ( const TMDVDENSE & mdv ) const { return !(*this == mdv); }
class Iterator { public: Iterator ( TMDVDENSE & mdv ) : _mdv(mdv), _mdvSlice( mdv.Slice() ), _itcurr(0), _itend( mdv.size() ), _bDimReorder(false) { assert( _mdvSlice._Totlen() == _itend ); _vimd.resize(_mdvSlice._Nslice()); }
Iterator ( TMDVDENSE & mdv, const MDVSLICE & mdvslice ) : _mdv(mdv), _mdvSlice( mdvslice ), _itcurr(0), _itend( mdvslice._Totlen() ), _bDimReorder(false) { _vimd.resize(_mdvSlice._Nslice()); }
void Reset() { vclear( _vimd, 0 ); _itcurr = 0; }
// Return flat index given const subscript array
size_t Indx ( const VIMD & vimd ) const { return _bDimReorder ? _mdvSlice._IOff( vimd, _vimdDim ) : _mdvSlice._IOff( vimd ); } // Return flat index given subscript array; update sub array
size_t IndxUpd ( VIMD & vimd ) { return _bDimReorder ? _mdvSlice._Off( vimd, _vimdDim ) : _mdvSlice._Off( vimd ); } // Return current flat index, no update
size_t Indx () const { return Indx( _vimd ); } // Return current flat index, with update
size_t IndxUpd () { if ( _itcurr < _itend ) _itcurr++; return IndxUpd( _vimd ); } // Return current datum, no update
T & operator[] ( VIMD & vimd ) { return _mdv[Indx()]; } // Return current datum, update sub array
T & Next () { return _mdv[IndxUpd()]; }
size_t ICurr () const { return _itcurr; } size_t IEnd () const { return _itend; } bool BNext () const { return _itcurr < _itend; } const VIMD & Vitmd () const { return _vimd; } const MDVSLICE & Slice() const { return _mdvSlice; } void SetDimReorder ( const VIMD & vimdDim ) { _vimdDim = vimdDim; _bDimReorder = true; // MSRDEVBUG: assert that the contents mention all dimensions correctly
} TMDVDENSE & Mdv () { return _mdv; } bool BReorder () const { return _bDimReorder; } const VIMD & VimdReorder () const { return _vimdDim; } protected: TMDVDENSE & _mdv; // Flat valarray
const MDVSLICE & _mdvSlice; // Multidimensional slice
VIMD _vimd; // Iteration control
VIMD _vimdDim; // Dimension reordering (optional)
size_t _itcurr; // Current iteration point
size_t _itend; // Iteration terminus
bool _bDimReorder; // Dimension reordering?
};
friend class Iterator;
};
/////////////////////////////////////////////////////////////////////////////////
// MDVSLICE member functions
/////////////////////////////////////////////////////////////////////////////////
inline void MDVSLICE :: StrideFromLength ( const vbool * pvboolMissing ) { size_t cd = _Len.size(); _Stride.resize(cd); size_t c = 1; size_t cmiss = pvboolMissing ? pvboolMissing->size() : 0;
for ( int i = cd; --i >= 0 ; ) { int l = _Len[i]; if ( l == 0 ) continue; if ( i < cmiss && (*pvboolMissing)[i] ) { _Stride[i] = 0; } else { _Stride[i] = c; c *= l; } } }
// Construct a gslice from an MDVSLICE
inline gslice MDVSLICE :: Gslice () const { _Sizarray vszLength; _Sizarray vszStride; return gslice( _Start, vdup( vszLength, _Len ), vdup( vszStride, _Stride ) ); }
// End of mdvect.h
#endif
|