cwMtx.h,cpp : Added slice() and derivatives.
This commit is contained in:
parent
077e1bc428
commit
fe5c069adb
48
cwMtx.cpp
48
cwMtx.cpp
@ -3,6 +3,7 @@
|
|||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
#include "cwVectOps.h"
|
||||||
#include "cwMtx.h"
|
#include "cwMtx.h"
|
||||||
|
|
||||||
|
|
||||||
@ -95,8 +96,13 @@ cw::rc_t cw::mtx::test( const object_t* cfg )
|
|||||||
d_t* mtx1 = nullptr;
|
d_t* mtx1 = nullptr;
|
||||||
d_t* mtx2 = nullptr;
|
d_t* mtx2 = nullptr;
|
||||||
d_t* mtx3 = nullptr;
|
d_t* mtx3 = nullptr;
|
||||||
|
d_t* mtx4 = nullptr;
|
||||||
d_t* mtx_y0 = nullptr;
|
d_t* mtx_y0 = nullptr;
|
||||||
d_t* mtx_y1 = nullptr;
|
d_t* mtx_y1 = nullptr;
|
||||||
|
d_t* mtx_y2 = nullptr;
|
||||||
|
d_t* mtx_y3 = nullptr;
|
||||||
|
d_t* mtx_y4 = nullptr;
|
||||||
|
d_t* mtx_y5 = nullptr;
|
||||||
d_t y;
|
d_t y;
|
||||||
|
|
||||||
const object_t* m0 = cfg->find("m0");
|
const object_t* m0 = cfg->find("m0");
|
||||||
@ -115,6 +121,10 @@ cw::rc_t cw::mtx::test( const object_t* cfg )
|
|||||||
if( m3 != nullptr )
|
if( m3 != nullptr )
|
||||||
mtx3 = allocCfg<double>(m3);
|
mtx3 = allocCfg<double>(m3);
|
||||||
|
|
||||||
|
const object_t* m4 = cfg->find("m4");
|
||||||
|
if( m4 != nullptr )
|
||||||
|
mtx4 = allocCfg<double>(m4);
|
||||||
|
|
||||||
const object_t* y0 = cfg->find("y0");
|
const object_t* y0 = cfg->find("y0");
|
||||||
if( y0 != nullptr )
|
if( y0 != nullptr )
|
||||||
mtx_y0 = allocCfg<double>(y0);
|
mtx_y0 = allocCfg<double>(y0);
|
||||||
@ -123,7 +133,7 @@ cw::rc_t cw::mtx::test( const object_t* cfg )
|
|||||||
if( y1 != nullptr )
|
if( y1 != nullptr )
|
||||||
mtx_y1 = allocCfg<double>(y1);
|
mtx_y1 = allocCfg<double>(y1);
|
||||||
|
|
||||||
unsigned n = offset(mtx1,1,1);
|
unsigned n = offset(*mtx1,1,1);
|
||||||
printf("offset: %i\n",n);
|
printf("offset: %i\n",n);
|
||||||
|
|
||||||
|
|
||||||
@ -131,6 +141,7 @@ cw::rc_t cw::mtx::test( const object_t* cfg )
|
|||||||
report(*mtx1,"m1");
|
report(*mtx1,"m1");
|
||||||
report(*mtx2,"m2");
|
report(*mtx2,"m2");
|
||||||
report(*mtx3,"m3");
|
report(*mtx3,"m3");
|
||||||
|
report(*mtx4,"m4");
|
||||||
report(*mtx_y0,"y0");
|
report(*mtx_y0,"y0");
|
||||||
report(*mtx_y1,"y1");
|
report(*mtx_y1,"y1");
|
||||||
|
|
||||||
@ -153,12 +164,47 @@ cw::rc_t cw::mtx::test( const object_t* cfg )
|
|||||||
rc = cwLogError(kTestFailRC,"Test 1 fail.");
|
rc = cwLogError(kTestFailRC,"Test 1 fail.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
transpose(*mtx0);
|
||||||
|
report(*mtx0,"m0");
|
||||||
|
mtx_y2 = join(0,*mtx0,*mtx4);
|
||||||
|
if( mtx_y2 != nullptr )
|
||||||
|
report(*mtx_y2,"y2");
|
||||||
|
|
||||||
|
report(*mtx0,"m0");
|
||||||
|
report(*mtx4,"m4");
|
||||||
|
mtx_y3 = join(1,*mtx0,*mtx4);
|
||||||
|
if( mtx_y3 != nullptr )
|
||||||
|
report(*mtx_y3,"y3");
|
||||||
|
|
||||||
|
|
||||||
|
mtx_y4 = slice_alias(*mtx_y3,0,0,1);
|
||||||
|
if( mtx_y4 != nullptr )
|
||||||
|
{
|
||||||
|
report(*mtx_y4,"y4 - slice");
|
||||||
|
|
||||||
|
ele(*mtx_y4,2) = 1;
|
||||||
|
ele(*mtx_y4,3) = 2;
|
||||||
|
report(*mtx_y4,"y4 - mod");
|
||||||
|
|
||||||
|
|
||||||
|
mtx_y5 = alloc_one_hot(*mtx_y4);
|
||||||
|
if( mtx_y5 != nullptr )
|
||||||
|
report(*mtx_y5,"y5 -(one_hot(y4))");
|
||||||
|
}
|
||||||
|
|
||||||
release(mtx0);
|
release(mtx0);
|
||||||
release(mtx1);
|
release(mtx1);
|
||||||
release(mtx2);
|
release(mtx2);
|
||||||
release(mtx3);
|
release(mtx3);
|
||||||
|
release(mtx4);
|
||||||
release(mtx_y0);
|
release(mtx_y0);
|
||||||
release(mtx_y1);
|
release(mtx_y1);
|
||||||
|
release(mtx_y2);
|
||||||
|
release(mtx_y3);
|
||||||
|
release(mtx_y4);
|
||||||
|
release(mtx_y5);
|
||||||
release(y);
|
release(y);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
524
cwMtx.h
524
cwMtx.h
@ -31,8 +31,9 @@ namespace cw
|
|||||||
{
|
{
|
||||||
kAliasReleaseFl = 0x01, // do not allocate memory, use the passed data pointer, and eventually release it
|
kAliasReleaseFl = 0x01, // do not allocate memory, use the passed data pointer, and eventually release it
|
||||||
kAliasNoReleaseFl = 0x02, // do not allocate memory, use the passed data pointer, and do not ever release it
|
kAliasNoReleaseFl = 0x02, // do not allocate memory, use the passed data pointer, and do not ever release it
|
||||||
kDuplDataFl = 0x04, // allocate data space and copy the data in
|
kDimV_NoReleaseFl = 0x04, // do not release the dimV array when the matrix is released.
|
||||||
kZeroFl = 0x08, // zero the newly allocated data
|
kDuplDataFl = 0x08, // allocate data space and copy the data in
|
||||||
|
kZeroFl = 0x10, // zero the newly allocated data
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -50,9 +51,11 @@ namespace cw
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
void release( struct mtx_str<T>& m )
|
void release( struct mtx_str<T>& m )
|
||||||
{
|
{
|
||||||
|
if( cwIsNotFlag(m.flags,kDimV_NoReleaseFl) )
|
||||||
mem::release(m.dimV);
|
mem::release(m.dimV);
|
||||||
if( cwIsNotFlag(m.flags,kAliasNoReleaseFl) )
|
|
||||||
mem::release(m.base);
|
if( cwIsNotFlag(m.flags,kAliasNoReleaseFl) )
|
||||||
|
mem::release(m.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -65,6 +68,24 @@ namespace cw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release data memory when this matrix is released
|
||||||
|
template< typename T >
|
||||||
|
void set_memory_release_flag( struct mtx_str<T>& m, bool linkDimVFl=true )
|
||||||
|
{
|
||||||
|
m.flags = cwClearFlag(m.flags,kAliasNoReleaseFl);
|
||||||
|
if( linkDimVFl )
|
||||||
|
m.flags = cwClearFlag(m.flags,kDimV_NoReleaseFl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do NOT release data memory when this matrix is released.
|
||||||
|
template< typename T >
|
||||||
|
void clear_memory_release_flag( struct mtx_str<T>& m, bool linkDimVFl=true )
|
||||||
|
{
|
||||||
|
m.flags = cwSetFlag(m.flags,kAliasNoReleaseFl);
|
||||||
|
if( linkDimVFl )
|
||||||
|
m.flags = cwSetFlag(m.flags,kDimV_NoReleaseFl);
|
||||||
|
}
|
||||||
|
|
||||||
// Note that dimV[] is always copied and therefore is the reponsibility of the caller to free.
|
// Note that dimV[] is always copied and therefore is the reponsibility of the caller to free.
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct mtx_str<T>* _init( struct mtx_str<T>* m, unsigned dimN, const unsigned* dimV, T* base=nullptr, unsigned flags=0 )
|
struct mtx_str<T>* _init( struct mtx_str<T>* m, unsigned dimN, const unsigned* dimV, T* base=nullptr, unsigned flags=0 )
|
||||||
@ -133,14 +154,39 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct mtx_str<T>* alloc( const unsigned* dimV, unsigned dimN, T* base, unsigned flags=0 )
|
||||||
|
{ return _init<T>( nullptr, dimN, dimV, base, flags); }
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
struct mtx_str<T>* _alloc_( unsigned flags, unsigned* dimV, unsigned dimN)
|
||||||
|
{
|
||||||
|
return alloc<T>(dimV, dimN, nullptr, flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* _alloc_( unsigned flags, unsigned* dimV, unsigned dimN, unsigned n, ARGS&&... args)
|
||||||
|
{
|
||||||
|
unsigned _dimV[ dimN + 1 ];
|
||||||
|
vop::copy(_dimV,dimV,dimN);
|
||||||
|
_dimV[dimN] = n;
|
||||||
|
return _alloc_<T>(flags,_dimV, dimN+1, std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* alloc( unsigned flags, ARGS&&... args)
|
||||||
|
{ return _alloc_<T>(flags,nullptr,0,args...); }
|
||||||
|
|
||||||
|
|
||||||
// Allocate the matrix w/o zeroing the initial contents
|
// Allocate the matrix w/o zeroing the initial contents
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct mtx_str<T>* alloc( unsigned dimN, const unsigned* dimV )
|
struct mtx_str<T>* alloc( const unsigned* dimV, unsigned dimN )
|
||||||
{ return _init<T>( nullptr, dimN, dimV, nullptr, 0); }
|
{ return _init<T>( nullptr, dimN, dimV, nullptr, 0); }
|
||||||
|
|
||||||
// Allocate the matrix and zero the contents
|
// Allocate the matrix and zero the contents
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct mtx_str<T>* allocZ( unsigned dimN, const unsigned* dimV )
|
struct mtx_str<T>* allocZ( const unsigned* dimV, unsigned dimN )
|
||||||
{ return _init<T>( nullptr, dimN, dimV, nullptr, kZeroFl); }
|
{ return _init<T>( nullptr, dimN, dimV, nullptr, kZeroFl); }
|
||||||
|
|
||||||
// Allocate the matrix and copy the data from base[]
|
// Allocate the matrix and copy the data from base[]
|
||||||
@ -161,7 +207,7 @@ namespace cw
|
|||||||
|
|
||||||
unsigned _offsetDimV( const unsigned* dimV, unsigned dimN, unsigned* idxV );
|
unsigned _offsetDimV( const unsigned* dimV, unsigned dimN, unsigned* idxV );
|
||||||
unsigned _offsetMulV( const unsigned* dimV, unsigned dimN, unsigned* idxV );
|
unsigned _offsetMulV( const unsigned* dimV, unsigned dimN, unsigned* idxV );
|
||||||
unsigned _mtx_object_get_degree( const struct object_str* cfg );
|
unsigned _mtx_object_get_degree( const struct object_str* cfg );
|
||||||
rc_t _mtx_object_get_shape( const struct object_str* cfg, unsigned i, unsigned* dimV, unsigned dimN, unsigned& eleN );
|
rc_t _mtx_object_get_shape( const struct object_str* cfg, unsigned i, unsigned* dimV, unsigned dimN, unsigned& eleN );
|
||||||
|
|
||||||
// 'i' is the index into 'idxV[]' of the matrix dimension which 'cfg' refers to
|
// 'i' is the index into 'idxV[]' of the matrix dimension which 'cfg' refers to
|
||||||
@ -199,6 +245,7 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate a new matrix by parsing an object_t description.
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct mtx_str<T>* allocCfg( const struct object_str* cfg )
|
struct mtx_str<T>* allocCfg( const struct object_str* cfg )
|
||||||
{
|
{
|
||||||
@ -225,7 +272,7 @@ namespace cw
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// allocate the matrix
|
// allocate the matrix
|
||||||
if((m = alloc<T>(dimN,dimV)) == nullptr )
|
if((m = alloc<T>(dimV,dimN)) == nullptr )
|
||||||
cwLogError(kObjAllocFailRC,"A matrix allocation failed.");
|
cwLogError(kObjAllocFailRC,"A matrix allocation failed.");
|
||||||
else
|
else
|
||||||
//
|
//
|
||||||
@ -233,15 +280,151 @@ namespace cw
|
|||||||
return m;
|
return m;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void _slice_setup( const struct mtx_str<T>& m, const unsigned* sIdxV, const unsigned* sCntV, unsigned* siV, unsigned *snV )
|
||||||
|
{
|
||||||
|
// if sIdx is not given then assume it is the origin
|
||||||
|
if( sIdxV != nullptr )
|
||||||
|
vop::copy(siV,sIdxV,m.dimN);
|
||||||
|
else
|
||||||
|
vop::zero(siV,m.dimN);
|
||||||
|
|
||||||
|
// calculate the length in each dimension
|
||||||
|
for(unsigned i=0; i<m.dimN; ++i)
|
||||||
|
snV[i] = (sCntV==nullptr || sCntV[i] == kInvalidCnt) ? m.dimV[i]-siV[i] : sCntV[i];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate a new matrix by slicing an existing matrix and duplicating the contents into a new matrix
|
||||||
|
// Set the elements of sCntV to kInvalidCnt to indicate that the entire dimension following the offset index should be copied.
|
||||||
|
// Set sIdxV to nullptr to begin at 0,0,...
|
||||||
|
// Set sCntV to nullptr to take all elements after sIdxV.
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
struct mtx_str<T0>* alloc( const struct mtx_str<T1>& src, const unsigned* sIdxV, const unsigned* sCntV )
|
||||||
|
{
|
||||||
|
struct mtx_str<T0>* m;
|
||||||
|
unsigned siV[ src.dimN ];
|
||||||
|
unsigned snV[ src.dimN ];
|
||||||
|
unsigned dIdxV[ src.dimN ];
|
||||||
|
vop::zero(dIdxV,src.dimN);
|
||||||
|
|
||||||
|
_slice_setup<T1>(src,sIdxV,sCntV,siV,snV);
|
||||||
|
|
||||||
|
if((m = alloc<T0>(snV,src.dimN) ) == nullptr )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
copy(*m,dIdxV,src,siV,snV);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate a new matrix by slicing an existing matrix and aliasing the contents into a new matrix.
|
||||||
|
// Set the elements of sCntV to kInvalidCnt to indicate that the entire dimension following the offset index should be copied.
|
||||||
|
// Set sIdxV to nullptr to begin at 0,0,...
|
||||||
|
// Set sCntV to nullptr to take all elements after sIdxV.
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct mtx_str<T>* alloc( unsigned dimN, const unsigned* dimV, T* base=nullptr, unsigned flags=0 )
|
struct mtx_str<T>* sliceAlias( const struct mtx_str<T>& src, const unsigned* sIdxV, const unsigned* sCntV )
|
||||||
{ return _init<T>( nullptr, dimN, dimV, base, flags); }
|
{
|
||||||
|
struct mtx_str<T>* m;
|
||||||
|
unsigned siV[ src.dimN ];
|
||||||
|
unsigned snV[ src.dimN ];
|
||||||
|
|
||||||
|
_slice_setup(src,sIdxV,sCntV,siV,snV);
|
||||||
|
|
||||||
|
m = allocAliasNoRelease( src.dimN, snV, addr(src,siV) );
|
||||||
|
|
||||||
|
// the memory layout in the slice mtx is the same as the matrix
|
||||||
|
// that it aliases and therefore the 'mulV' vector is the same
|
||||||
|
// in both matrices.
|
||||||
|
vop::copy(m->mulV,src.mulV,src.dimN);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T0, typename T1>
|
||||||
|
struct mtx_str<T0>* _slice( const struct mtx_str<T1>& m, unsigned* iV, unsigned iN, unsigned index )
|
||||||
|
{
|
||||||
|
// the offset index vector must be fully specified
|
||||||
|
if( index < m.dimN )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"An invalid number index + count values was given to slice(). %i < %i.",index,m.dimN);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill in the end of iV[] with kInvalidCnt to indicate that all values after the offset should be copied
|
||||||
|
for(; index<iN; ++index)
|
||||||
|
iV[index] = kInvalidCnt;
|
||||||
|
|
||||||
|
// allocate a matrix to hold the slice
|
||||||
|
return alloc<T0,T1>(m,iV,iV+m.dimN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1, typename... ARGS>
|
||||||
|
struct mtx_str<T0>* _slice( const struct mtx_str<T1>& m, unsigned* iV, unsigned iN, unsigned index, unsigned n, ARGS&&... args)
|
||||||
|
{
|
||||||
|
if( index >= iN )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"Too many index/count arguments were passed to mtx::slice().");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
iV[index] = n;
|
||||||
|
return _slice<T0,T1>(m,iV,iN,index+1,std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is a wrapper around alloc(const struct mtx_str<T>& src, const unsigned* sIdxV, const unsigned* sCntV ).
|
||||||
|
// The argument list should specify the values for sIdxV[0:dimN] and sCntV[0:dimN].
|
||||||
|
// The count of arguments should therefore not exceed src.dimN*2.
|
||||||
|
// The sCntV[] argument list may be truncated, or set to kInvalidCnt, if all values after the offset for a given dimension are to be copied.
|
||||||
|
template< typename T0, typename T1, typename... ARGS>
|
||||||
|
struct mtx_str<T0>* slice( const struct mtx_str<T1>& m, ARGS&&... args)
|
||||||
|
{
|
||||||
|
unsigned iV[ m.dimN*2 ];
|
||||||
|
return _slice<T0,T1>(m, iV, m.dimN*2, 0, std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct mtx_str<T>* _sliceAlias( const struct mtx_str<T>& m, unsigned* iV, unsigned iN, unsigned index )
|
||||||
|
{
|
||||||
|
// the offset index vector must be fully specified
|
||||||
|
if( index < m.dimN )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"An invalid number index + count values was given to sliceAlias(). %i < %i.",index,m.dimN);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill in the end of iV[] with kInvalidCnt to indicate that all values after the offset should be copied
|
||||||
|
for(; index<iN; ++index)
|
||||||
|
iV[index] = kInvalidCnt;
|
||||||
|
|
||||||
|
// allocate a matrix to hold the slice
|
||||||
|
return sliceAlias<T>(m,iV,iV+m.dimN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* _sliceAlias( const struct mtx_str<T>& m, unsigned* iV, unsigned iN, unsigned index, unsigned n, ARGS&&... args)
|
||||||
|
{
|
||||||
|
if( index >= iN )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"Too many index/count arguments were passed to mtx::sliceAlias().");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
iV[index] = n;
|
||||||
|
return _sliceAlias<T>(m,iV,iN,index+1,std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* slice_alias( const struct mtx_str<T>& m, ARGS&&... args)
|
||||||
|
{
|
||||||
|
unsigned iV[ m.dimN*2 ];
|
||||||
|
return _sliceAlias<T>(m,iV, m.dimN*2, 0, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// resize m[]
|
// resize m[]
|
||||||
@ -255,57 +438,242 @@ namespace cw
|
|||||||
{ return resize(y,x->dimV,x->dimN); }
|
{ return resize(y,x->dimV,x->dimN); }
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
// Copy a slice of src[] into dst[] at a particular location.
|
||||||
unsigned offset( const struct mtx_str<T>* m, const unsigned* idxV )
|
// dst[] is assumed to be allocated with sufficient size to receive src[].
|
||||||
|
// Set dIdxV to nullptr to copy to the 0,0, ... of the dst matrix
|
||||||
|
// Set sIdxV to nullptr to copy from the 0,0, ... of the src matrix.
|
||||||
|
// Set sCntV to nullptr to cop all of the src matrix.
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
rc_t copy( struct mtx_str<T0>& dst, const unsigned* dIdxV, const struct mtx_str<T1>& src, const unsigned* sIdxV, const unsigned* sCntV )
|
||||||
{
|
{
|
||||||
unsigned offset = 0;
|
rc_t rc = kOkRC;
|
||||||
for(unsigned i=0; i<m->dimN; ++i)
|
unsigned nV[ src.dimN ];
|
||||||
offset += idxV[i] * m->mulV[i];
|
unsigned siV[ src.dimN ];
|
||||||
|
unsigned diV[ dst.dimN ];
|
||||||
|
vop::zero(nV,src.dimN);
|
||||||
|
|
||||||
return offset;
|
if( sCntV == nullptr )
|
||||||
|
sCntV = src.dimV;
|
||||||
|
|
||||||
|
if( sIdxV == nullptr )
|
||||||
|
vop::zero(siV,src.dimN);
|
||||||
|
else
|
||||||
|
vop::copy(siV,sIdxV,src.dimN);
|
||||||
|
|
||||||
|
if( dIdxV == nullptr )
|
||||||
|
vop::zero(diV,dst.dimN);
|
||||||
|
else
|
||||||
|
vop::copy(diV,dIdxV,dst.dimN);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
|
||||||
|
// verify the starting address
|
||||||
|
assert( is_legal_address(dst, diV) );
|
||||||
|
assert( is_legal_address(src, siV) );
|
||||||
|
|
||||||
|
vop::add(siV,sCntV,src.dimN);
|
||||||
|
vop::add(diV,sCntV,dst.dimN);
|
||||||
|
|
||||||
|
vop::sub(siV,1,src.dimN);
|
||||||
|
vop::sub(diV,1,dst.dimN);
|
||||||
|
|
||||||
|
//verify the ending address
|
||||||
|
assert( is_legal_address(dst, diV) );
|
||||||
|
assert( is_legal_address(src, siV) );
|
||||||
|
|
||||||
|
vop::copy(siV,sIdxV,src.dimN);
|
||||||
|
vop::copy(diV,dIdxV,dst.dimN);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// copy one element
|
||||||
|
ele(dst, diV ) = ele(src, siV );
|
||||||
|
|
||||||
|
|
||||||
|
for(int j=0; j >= 0; )
|
||||||
|
{
|
||||||
|
// increment the src and dst addr
|
||||||
|
|
||||||
|
// from highest to lowest degree
|
||||||
|
for(j=src.dimN-1; j>=0; --j)
|
||||||
|
{
|
||||||
|
// if incrementing the jth dim does not overflow ...
|
||||||
|
if( ++nV[j] < sCntV[j] )
|
||||||
|
{
|
||||||
|
siV[j] += 1;
|
||||||
|
diV[j] += 1;
|
||||||
|
|
||||||
|
// copy one element
|
||||||
|
ele(dst, diV ) = ele(src, siV );
|
||||||
|
|
||||||
|
break; // .. then incr siV[] and diV[] with the next src/dst address
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise reset the counter and address for this dim and backup by one dim.
|
||||||
|
nV[j] = 0;
|
||||||
|
diV[j] = dIdxV[j];
|
||||||
|
siV[j] = sIdxV[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
unsigned _offset( const struct mtx_str<T>* m, int i, unsigned offs )
|
rc_t _join_update_dims( unsigned index, unsigned* dimV, unsigned dimN, const struct mtx_str<T>& m )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
// verify that the degree of all matrices are the same
|
||||||
|
if( m.dimN != dimN )
|
||||||
|
return cwLogError(kInvalidArgRC,"Join matrix size mismatch. dimN:%i != %i", m.dimN, dimN);
|
||||||
|
|
||||||
|
// only the dimension specified by 'index' may be different
|
||||||
|
for(unsigned i=0; i<dimN; ++i)
|
||||||
|
{
|
||||||
|
if( i == index )
|
||||||
|
dimV[i] += m.dimV[i];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( dimV[i] != m.dimV[i] )
|
||||||
|
return cwLogError(kInvalidArgRC,"Join matrix dimV[%i] mismatch: (%i != %i). ",i,dimV[i],m.dimV[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void _join_copy( struct mtx_str<T>& dst, const struct mtx_str<T>& src, unsigned index, unsigned ii )
|
||||||
|
{
|
||||||
|
unsigned dIdxV[ dst.dimN ];
|
||||||
|
unsigned sIdxV[ src.dimN ];
|
||||||
|
vop::zero(dIdxV,dst.dimN);
|
||||||
|
vop::zero(sIdxV,src.dimN);
|
||||||
|
dIdxV[ index ] = ii;
|
||||||
|
copy(dst,dIdxV,src,sIdxV,src.dimV);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct mtx_str<T>* _join( unsigned index, unsigned* dimV, unsigned dimN, unsigned ii )
|
||||||
|
{
|
||||||
|
// Allocate an empty matrix to copy the joined matrices into.
|
||||||
|
return alloc<T>(dimV,dimN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* _join( unsigned index, unsigned* dimV, unsigned dimN, unsigned ii, const struct mtx_str<T>& m, ARGS&&... args)
|
||||||
|
{
|
||||||
|
struct mtx_str<T>* y = nullptr;
|
||||||
|
|
||||||
|
if( _join_update_dims<T>(index,dimV,dimN,m) != kOkRC )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if((y = _join<T>( index, dimV, dimN, ii + m.dimV[index], std::forward<ARGS>(args)...)) != nullptr )
|
||||||
|
{
|
||||||
|
_join_copy(*y,m,index,ii);
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
struct mtx_str<T>* join( unsigned index, const struct mtx_str<T>& m, ARGS&&... args)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct mtx_str<T>* y = nullptr;
|
||||||
|
unsigned dimV[ m.dimN ];
|
||||||
|
|
||||||
|
for(unsigned i=0; i<m.dimN; ++i)
|
||||||
|
dimV[i] = m.dimV[i];
|
||||||
|
|
||||||
|
if((y = _join( index, dimV, m.dimN, m.dimV[index], std::forward<ARGS>(args)...)) != nullptr )
|
||||||
|
{
|
||||||
|
_join_copy(*y,m,index,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool is_legal_address( const struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<m.dimN; ++i)
|
||||||
|
if( idxV[i] >= m.dimV[i] )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned offset( const struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
|
{ return vop::mac(idxV,m.mulV,m.dimN); }
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned _offset( const struct mtx_str<T>& m, int i, unsigned offs )
|
||||||
{ return offs; }
|
{ return offs; }
|
||||||
|
|
||||||
template< typename T, typename... ARGS>
|
template< typename T, typename... ARGS>
|
||||||
unsigned _offset( const struct mtx_str<T>* m, int i, unsigned offs, unsigned idx, ARGS&&... args)
|
unsigned _offset( const struct mtx_str<T>& m, int i, unsigned offs, unsigned idx, ARGS&&... args)
|
||||||
{ return _offset(m,i+1, offs + idx*m->mulV[i], std::forward<ARGS>(args)...); }
|
{ return _offset(m,i+1, offs + idx*m.mulV[i], std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
template< typename T, typename... ARGS>
|
|
||||||
unsigned offset( const struct mtx_str<T>* m, unsigned idx, ARGS&&... args)
|
|
||||||
{ return _offset(m,0,0,idx,std::forward<ARGS>(args)...); }
|
|
||||||
|
|
||||||
template< typename T, typename... ARGS>
|
template< typename T, typename... ARGS>
|
||||||
unsigned offset( const struct mtx_str<T>& m, unsigned idx, ARGS&&... args)
|
unsigned offset( const struct mtx_str<T>& m, unsigned idx, ARGS&&... args)
|
||||||
{ return _offset(&m,0,0,idx,std::forward<ARGS>(args)...); }
|
{ return _offset(m,0,0,idx,std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
T* addr( const struct mtx_str<T>* m, const unsigned* idxV )
|
T* addr( struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
{ return m->base + offset(m,idxV); }
|
{ return m.base + offset(m,idxV); }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T* addr( const struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
|
{ return m.base + offset(m,idxV); }
|
||||||
|
|
||||||
|
|
||||||
template< typename T, typename... ARGS>
|
template< typename T, typename... ARGS>
|
||||||
T* addr( struct mtx_str<T>* m, unsigned i, ARGS&&... args)
|
T* addr( struct mtx_str<T>& m, unsigned i, ARGS&&... args)
|
||||||
{ return m->base + offset(m,i,std::forward<ARGS>(args)...); }
|
{ return m.base + offset(m,i,std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
const T* addr( const struct mtx_str<T>& m, unsigned i, ARGS&&... args)
|
||||||
|
{ return m.base + offset(m,i,std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
T& ele( const struct mtx_str<T>* m, const unsigned* idxV )
|
T& ele( struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
|
{ return *addr(m,idxV); }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T& ele( const struct mtx_str<T>& m, const unsigned* idxV )
|
||||||
{ return *addr(m,idxV); }
|
{ return *addr(m,idxV); }
|
||||||
|
|
||||||
template< typename T, typename... ARGS>
|
template< typename T, typename... ARGS>
|
||||||
T& ele( struct mtx_str<T>* m, unsigned i, ARGS&&... args)
|
T& ele( struct mtx_str<T>& m, unsigned i, ARGS&&... args)
|
||||||
|
{ return *addr(m,i,std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T, typename... ARGS>
|
||||||
|
const T& ele( const struct mtx_str<T>& m, unsigned i, ARGS&&... args)
|
||||||
{ return *addr(m,i,std::forward<ARGS>(args)...); }
|
{ return *addr(m,i,std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
bool is_col_vector( const struct mtx_str<T>& m )
|
bool is_col_vector( const struct mtx_str<T>& m )
|
||||||
{ return m->dimN==1 || (m->dimN==2 && m->dimV[1]==1); };
|
{ return m.dimN==1 || (m.dimN==2 && m.dimV[1]==1); };
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
bool is_row_vector( const struct mtx_str<T>& m )
|
bool is_row_vector( const struct mtx_str<T>& m )
|
||||||
{ return m->dimN==2 && m->dimV[0]==1; }
|
{ return m.dimN==2 && m.dimV[0]==1; }
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
bool is_vector( const struct mtx_str<T>& m )
|
bool is_vector( const struct mtx_str<T>& m )
|
||||||
@ -318,11 +686,7 @@ namespace cw
|
|||||||
if( x0.dimN != x1.dimN )
|
if( x0.dimN != x1.dimN )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(unsigned i=0; i<x0.dimN; ++i)
|
return vop::is_equal(x0.dimV,x1.dimV,x0.dimN);
|
||||||
if( x0.dimV[i] != x1.dimV[i] )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -331,24 +695,14 @@ namespace cw
|
|||||||
if( !is_size_equal(x0,x1) )
|
if( !is_size_equal(x0,x1) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned N = ele_count(x0);
|
return vop::is_equal(x0.base,x1.base,ele_count(x0));
|
||||||
for(unsigned i=0; i<N; ++i)
|
|
||||||
if( x0.base[i] != x1.base[i] )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return the count of elements in the matrix
|
// Return the count of elements in the matrix
|
||||||
template< typename T >
|
template< typename T >
|
||||||
unsigned ele_count( const struct mtx_str<T>& x )
|
unsigned ele_count( const struct mtx_str<T>& x )
|
||||||
{
|
{ return vop::cumprod(x.dimV,x.dimN); }
|
||||||
unsigned eleN = 1;
|
|
||||||
for(unsigned i=0; i<x.dimN; ++i)
|
|
||||||
eleN *= x.dimV[i];
|
|
||||||
return eleN;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -372,7 +726,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if( i == m.dimN )
|
if( i == m.dimN )
|
||||||
{
|
{
|
||||||
double v = ele( &m, idxV );
|
double v = ele( m, idxV );
|
||||||
|
|
||||||
// print the value
|
// print the value
|
||||||
printf("%*.*f ",colWidth,decPl,v);
|
printf("%*.*f ",colWidth,decPl,v);
|
||||||
@ -408,7 +762,7 @@ namespace cw
|
|||||||
unsigned idxV[ m.dimN ];
|
unsigned idxV[ m.dimN ];
|
||||||
memset(idxV,0,sizeof(idxV));
|
memset(idxV,0,sizeof(idxV));
|
||||||
|
|
||||||
if( is_int<T>(*m.base) )
|
if( std::numeric_limits<T>::is_integer )
|
||||||
decPl = 0;
|
decPl = 0;
|
||||||
|
|
||||||
_print( m, idxV, 0, decPl, colWidth );
|
_print( m, idxV, 0, decPl, colWidth );
|
||||||
@ -441,9 +795,7 @@ namespace cw
|
|||||||
void mult( struct mtx_str<T>& y, const struct mtx_str<T>& x )
|
void mult( struct mtx_str<T>& y, const struct mtx_str<T>& x )
|
||||||
{
|
{
|
||||||
assert( is_size_equal(y,x) );
|
assert( is_size_equal(y,x) );
|
||||||
unsigned n = ele_count<T>(x);
|
vop::mul(y.base,x.base,ele_count<T>(x));
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] *= x.base[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// y = x * scalar (elementwise)
|
// y = x * scalar (elementwise)
|
||||||
@ -451,19 +803,13 @@ namespace cw
|
|||||||
void mult( struct mtx_str<T>& y, const struct mtx_str<T>& x, const T& scalar )
|
void mult( struct mtx_str<T>& y, const struct mtx_str<T>& x, const T& scalar )
|
||||||
{
|
{
|
||||||
resize<T>(&y,x); // resize y to the same dim's as m
|
resize<T>(&y,x); // resize y to the same dim's as m
|
||||||
unsigned n = ele_count<T>(x);
|
vop::mul(y.base,x.base,ele_count<T>(x),scalar);
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] = x.base[i] * scalar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// y *= scalar (elementwise)
|
// y *= scalar (elementwise)
|
||||||
template< typename T >
|
template< typename T >
|
||||||
void mult( struct mtx_str<T>& y, const T& scalar )
|
void mult( struct mtx_str<T>& y, const T& scalar )
|
||||||
{
|
{ vop::mul(y.base,scalar,ele_count<T>(y)); }
|
||||||
unsigned n = ele_count<T>(y);
|
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] *= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// y = m + x (elementwise)
|
// y = m + x (elementwise)
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -471,9 +817,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
assert( is_size_equal(x0,x1) );
|
assert( is_size_equal(x0,x1) );
|
||||||
resize<T>(&y,x0); // resize y to the same dim's as m
|
resize<T>(&y,x0); // resize y to the same dim's as m
|
||||||
unsigned n = ele_count<T>(x0);
|
vop::add(y.base,x0.base,x1.base,ele_count(x0));
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] = x0.base[i] + x1.base[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// y += x (elementwise)
|
// y += x (elementwise)
|
||||||
@ -481,9 +825,7 @@ namespace cw
|
|||||||
void add( struct mtx_str<T>& y, const struct mtx_str<T>& x )
|
void add( struct mtx_str<T>& y, const struct mtx_str<T>& x )
|
||||||
{
|
{
|
||||||
assert( is_size_equal(y,x) );
|
assert( is_size_equal(y,x) );
|
||||||
unsigned n = ele_count<T>(x);
|
vop::add(y.base,x.base,ele_count(x));
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] += x.base[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// y = x + scalar (elementwise)
|
// y = x + scalar (elementwise)
|
||||||
@ -491,21 +833,53 @@ namespace cw
|
|||||||
void add( struct mtx_str<T>& y, const struct mtx_str<T>& x, const T& scalar )
|
void add( struct mtx_str<T>& y, const struct mtx_str<T>& x, const T& scalar )
|
||||||
{
|
{
|
||||||
resize(&y,x);
|
resize(&y,x);
|
||||||
unsigned n = ele_count<T>(y);
|
vop::add(y.base,x.base,scalar,ele_count<T>(y));
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] = x.base[i] + scalar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// y += scalar (elementwise)
|
// y += scalar (elementwise)
|
||||||
template< typename T >
|
template< typename T >
|
||||||
void add( struct mtx_str<T>& y, const T& scalar )
|
void add( struct mtx_str<T>& y, const T& scalar )
|
||||||
{
|
{
|
||||||
unsigned n = ele_count<T>(y);
|
vop::add(y.base,scalar,ele_count<T>(y));
|
||||||
for(unsigned i=0; i<n; ++i)
|
|
||||||
y.base[i] += scalar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T >
|
||||||
|
const T max( const struct mtx_str<T>& x )
|
||||||
|
{
|
||||||
|
return vop::max(x.base,ele_count<T>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T >
|
||||||
|
const T min( const struct mtx_str<T>& x )
|
||||||
|
{
|
||||||
|
return vop::min(x.base,ele_count<T>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
struct mtx_str<T>* alloc_one_hot( const struct mtx_str<T>& mV )
|
||||||
|
{
|
||||||
|
if( !is_vector(mV) )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"Only vectors can be converted to one-hot matrices.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int min_val = (int)mtx::min<T>(mV);
|
||||||
|
int max_val = (int)mtx::max<T>(mV);
|
||||||
|
unsigned rN = (max_val - min_val) + 1;
|
||||||
|
unsigned cN = ele_count<T>(mV);
|
||||||
|
struct mtx::mtx_str<T>* zM = mtx::alloc<T>(kZeroFl,rN,cN);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<cN; ++i)
|
||||||
|
{
|
||||||
|
unsigned j = (unsigned)ele<T>(mV,i) - min_val;
|
||||||
|
ele(*zM, j, i) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zM;
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T0, typename T1 >
|
template< typename T0, typename T1 >
|
||||||
rc_t mtx_mul( struct mtx_str<T0>& y, const struct mtx_str<T0>& m, const struct mtx_str<T1>& x )
|
rc_t mtx_mul( struct mtx_str<T0>& y, const struct mtx_str<T0>& m, const struct mtx_str<T1>& x )
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user