00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00048
#ifndef TMat_decl_INC
00049
#define TMat_decl_INC
00050
00051
#include "TVec_impl.h"
00052
00053
namespace PLearn {
00054
using namespace std;
00055
00056
00057
template<
class T>
class TMatElementIterator;
00058
template<
class T>
class TMatRowsIterator;
00059
template<
class T>
class TMatColRowsIterator;
00060
template<
class T>
class TMatRowsAsArraysIterator;
00061
00062
00063
template <
class T>
00064 class TMat
00065 {
00066 friend class TVec<T>;
00067
friend class Variable;
00068
friend class VarArray;
00069
00070
protected:
00071 int offset_;
00072 int mod_;
00073 int length_;
00074 int width_;
00075 PP< Storage<T> > storage;
00077
public:
00078
00080 int nrows()
const {
return length_; }
00081 int ncols()
const {
return width_; }
00082
00083
public:
00084
00085 typedef T
value_type;
00086 typedef int size_type;
00087 typedef TMatElementIterator<T> iterator;
00088 typedef TMatElementIterator<T> const_iterator;
00089 typedef T*
compact_iterator;
00090 typedef T*
rowelements_iterator;
00091
00092 typedef TMatRowsIterator<T> rows_iterator;
00093 typedef TMatRowsAsArraysIterator<T> rows_as_arrays_iterator;
00094 typedef TMatColRowsIterator<T> colrows_iterator;
00095
00096
TMat<T>()
00097 :offset_(0), mod_(0), length_(0), width_(0)
00098 {}
00099
00100
TMat<T>(
int the_length,
int the_width)
00101 :offset_(0), mod_(0), length_(0), width_(0)
00102 {
resize(the_length, the_width); }
00103
00104 TMat<T>(
int the_length,
int the_width,
const T& init_value)
00105 :offset_(0), mod_(0), length_(0), width_(0)
00106 {
00107
resize(the_length, the_width);
00108 fill(init_value);
00109 }
00110
00111 TMat<T>(
int the_length,
int the_width, T* the_data)
00112 :
offset_(0),
mod_(the_width),
length_(the_length),
width_(the_width),
00113
storage(
new Storage<T>(the_length*the_width, the_data))
00114 {}
00115
00116 TMat<T>(
int the_length,
int the_width,
const TVec<T>& v);
00117
00119 inline const TMat<T>& operator=(
const TMat<T>& other)
00120 {
00121 storage = other.
storage;
00122 offset_ = other.
offset_;
00123 mod_ = other.
mod_;
00124 length_ = other.
length_;
00125 width_ = other.
width_;
00126
return *
this;
00127 }
00128
00130
inline iterator
begin() const;
00131 inline iterator end() const;
00132
00134 inline compact_iterator compact_begin()
const
00135
{
00136
#ifdef BOUNDCHECK
00137
if(
mod()!=
width())
00138
PLERROR(
"You cannot use a compact iterator to iterate over the elements of a non compact matrix");
00139
#endif
00140
return data();
00141 }
00142
00143 inline compact_iterator
compact_end()
const
00144
{
return data()+
size(); }
00145
00147 inline rowelements_iterator rowelements_begin(
int rownum)
const
00148
{
00149
#ifdef BOUNDCHECK
00150
if(rownum<0 || rownum>=
length())
00151
PLERROR(
"OUT OF RANGE rownum in rowelements_begin");
00152
#endif
00153
return data()+rownum*
mod();
00154 }
00155
00158 inline rowelements_iterator rowelements_end(
int rownum)
const
00159
{
return data()+rownum*
mod()+
width(); }
00160
00163
TMatRowsIterator<T> rows_begin();
00164
TMatRowsIterator<T> rows_end();
00165
00168
TMatRowsAsArraysIterator<T> rows_as_arrays_begin();
00169
TMatRowsAsArraysIterator<T> rows_as_arrays_end();
00170
00171
00175
TMatColRowsIterator<T> col_begin(
int column);
00176
00180
TMatColRowsIterator<T> col_end(
int column);
00181
00182
00189 void resize(
int newlength,
int newwidth,
int extrabytes=0)
00190 {
00191
#ifdef BOUNDCHECK
00192
if(newlength<0 || newwidth<0)
00193
PLERROR(
"IN TMat::resize(int newlength, int newwidth)\nInvalid arguments (<0)");
00194
#endif
00195
if (newlength==length_ && newwidth==width_)
return;
00196
if(storage.
isNull())
00197 {
00198 offset_ = 0;
00199 length_ = newlength;
00200 width_ = newwidth;
00201 mod_ = newwidth;
00202 storage =
new Storage<T>(
length()*
mod());
00203 }
00204
else
00205 {
00206
if(storage->usage()>1 && newwidth >
mod()-offset_%
mod())
00207
PLERROR(
"IN TMat::resize(int newlength, int newwidth)\nFor safety reasons, increasing the width() beyond mod() - offset_%mod() is not allowed when the storage is shared with others");
00208
00209
int newsize = offset_+newlength*
MAX(
mod(),newwidth);
00210
if(offset_+newsize>storage->length())
00211 storage->resize(offset_+newsize+extrabytes);
00212 length_ = newlength;
00213 width_ = newwidth;
00214
if(newwidth>
mod())
00215 mod_ = newwidth;
00216 }
00217 }
00218
00219 inline int length()
const
00220
{
return length_; }
00221
00222 inline int width()
const
00223
{
return width_; }
00224
00225 inline int size()
const
00226
{
return length_*width_; }
00227
00228 inline int mod()
const
00229
{
return mod_; }
00230
00231 inline PP< Storage<T> >
getStorage()
const
00232
{
return storage; }
00233
00234 inline bool isSquare()
const
00235
{
return length() ==
width(); }
00236
00237 bool hasMissing()
const
00238
{
00239
iterator it =
begin();
00240
iterator itend =
end();
00241
for(; it!=itend; ++it)
00242
if(
is_missing(*it))
00243
return true;
00244
return false;
00245 }
00246
00248 inline T*
data()
const
00249
{
00250
#ifdef BOUNDCHECK
00251
if(storage.
isNull())
00252
PLERROR(
"IN TMat::data()\nAttempted to get a pointer to the data of an empty matrix");
00253
#endif
00254
return storage->data+offset_;
00255 }
00256
00258 inline T* operator[](
int rownum)
const
00259
{
00260
#ifdef BOUNDCHECK
00261
if(rownum<0 || rownum>=
length())
00262
PLERROR(
"OUT OF BOUND ACCESS IN TMat::operator[](int rownum=%d), length=%d",rownum,
length());
00263
#endif
00264
return storage->data + offset_ +
mod()*rownum;
00265 }
00266
00267 inline T* rowdata(
int i)
const {
return (*this)[i]; }
00268
00269 inline T& operator()(
int rownum,
int colnum)
const
00270
{
00271
#ifdef BOUNDCHECK
00272
if(rownum<0 || rownum>=
length() || colnum<0 || colnum>=
width())
00273
PLERROR(
"OUT OF BOUND ACCESS IN TMat::operator()(int rownum, int colnum)"
00274
" width=%d; length=%d; colnum=%d; rownum=%d;",
width(),
length(), colnum, rownum);
00275
#endif
00276
return storage->data[offset_ +
mod()*rownum + colnum];
00277 }
00278
00279 inline TVec<T> operator()(
int rownum)
const
00280
{
00281
#ifdef BOUNDCHECK
00282
if(rownum<0 || rownum>=
length())
00283
PLERROR(
"OUT OF BOUND ACCESS IN TMat_impl::operator()(int rownum)");
00284
#endif
00285
TVec<T> tv;
00286 tv.
length_ =
width();
00287 tv.
offset_ = offset_ +
mod()*rownum;
00288 tv.
storage = storage;
00289
return tv;
00290 }
00291
00294 void write(
PStream& out)
const
00295
{
00296 T* ptr = 0;
00297
if(storage)
00298 ptr =
data();
00299
00300
switch(out.
outmode)
00301 {
00302
case PStream::raw_ascii:
00303
case PStream::pretty_ascii:
00304
for(
int i=0; i<length_; i++, ptr+=mod_)
00305 {
00306
for(
int j=0; j<width_; j++)
00307 {
00308 out << ptr[j];
00309 out.
put(
'\t');
00310 }
00311 out.
put(
'\n');
00312 }
00313
break;
00314
00315
case PStream::raw_binary:
00316
for(
int i=0; i<length_; i++, ptr+=mod_)
00317
binwrite_(out, ptr, width_);
00318
break;
00319
00320
case PStream::plearn_ascii:
00321 {
00322
if(!out.
implicit_storage)
00323 {
00324 out.
write(
"TMat(");
00325 out << length_ << width_ << mod_ << offset_ << storage;
00326 out.
write(
")\n");
00327 }
00328
else
00329 {
00330 out << length_;
00331 out.
put(
' ');
00332 out << width_;
00333 out.
write(
" [ \n");
00334
for(
int i=0; i<length_; i++, ptr+=mod_)
00335 {
00336
for(
int j=0; j<width_; j++)
00337 {
00338 out << ptr[j];
00339 out.
put(
'\t');
00340 }
00341 out.
put(
'\n');
00342 }
00343 out.
write(
"]\n");
00344 }
00345 }
00346
break;
00347
00348
case PStream::plearn_binary:
00349 {
00350
if(!out.
implicit_storage)
00351 {
00352 out.
write(
"TMat(");
00353 out << length_ << width_ << mod_ << offset_ << storage;
00354 out.
write(
")\n");
00355 }
00356
else
00357 {
00358
unsigned char typecode;
00359
if(
byte_order()==
LITTLE_ENDIAN_ORDER)
00360 {
00361 out.
put(0x14);
00362 typecode =
TypeTraits<T>::little_endian_typecode();
00363 }
00364
else
00365 {
00366 out.
put(0x15);
00367 typecode =
TypeTraits<T>::big_endian_typecode();
00368 }
00369
00370
00371 out.
put(typecode);
00372
00373
00374 out.
write((
char*)&length_,
sizeof(length_));
00375 out.
write((
char*)&width_,
sizeof(width_));
00376
00377
00378
for(
int i=0; i<length_; i++, ptr+=mod_)
00379
binwrite_(out, ptr, width_);
00380 }
00381 }
00382
break;
00383
00384
default:
00385
PLERROR(
"In TMat::write(PStream& out) unknown outmode!!!!!!!!!");
00386
break;
00387 }
00388 }
00389
00390
00391
00394 void read(
PStream& in)
00395 {
00396
switch(in.
inmode)
00397 {
00398
case PStream::raw_ascii:
00399
case PStream::raw_binary:
00400 {
00401 T* ptr =
data();
00402
for(
int i=0; i<length_; i++, ptr+=mod_)
00403
for(
int j=0; j<width_; j++)
00404 in >> ptr[j];
00405 }
00406
break;
00407
00408
case PStream::plearn_ascii:
00409
case PStream::plearn_binary:
00410 {
00411 in.
skipBlanksAndComments();
00412
int c = in.
peek();
00413
if(c==
'T')
00414 {
00415
char word[6];
00416
00417
00418
00419
for(
int i=0; i<5; i++)
00420 in.
get(word[i]);
00421
00422 word[5]=
'\0';
00423
if(strcmp(word,
"TMat(")!=0)
00424
PLERROR(
"In operator>>(PStream&, TMat&) '%s' not a proper header for a TMat!",word);
00425
00426 in >> length_ >> width_ >> mod_ >> offset_;
00427 in >> storage;
00428 in.
skipBlanksAndCommentsAndSeparators();
00429
int c = in.
get();
00430
if(c!=
')')
00431
PLERROR(
"In operator>>(PStream&, TMat&) expected a closing parenthesis, found '%c'",c);
00432 }
00433
else
00434 {
00435
if(isdigit(c))
00436 {
00437
int l,w;
00438 in >> l >> w;
00439 in.
skipBlanksAndComments();
00440 c = in.
get();
00441
if(c!=
'[')
00442
PLERROR(
"Error in TMat::read(PStream& in), expected '[', read '%c'",c);
00443 in.
skipBlanksAndCommentsAndSeparators();
00444
resize(l,w);
00445 T* ptr = (l>0 && w>0)?
data():0;
00446
for(
int i=0; i<length_; i++, ptr+=mod_)
00447
for(
int j=0; j<width_; j++)
00448 {
00449 in.
skipBlanksAndCommentsAndSeparators();
00450 in >> ptr[j];
00451 }
00452 in.
skipBlanksAndCommentsAndSeparators();
00453 c = in.
get();
00454
if(c!=
']')
00455
PLERROR(
"Error in TMat::read(PStream& in), expected ']', read '%c'",c);
00456 }
00457
else if(c==0x14 || c==0x15)
00458 {
00459 in.
get();
00460
unsigned char typecode = in.
get();
00461
int l, w;
00462 in.
read((
char*)&l,
sizeof(l));
00463 in.
read((
char*)&w,
sizeof(w));
00464
bool inverted_byte_order = ((c==0x14 &&
byte_order()==
BIG_ENDIAN_ORDER)
00465 || (c==0x15 &&
byte_order()==
LITTLE_ENDIAN_ORDER) );
00466
if(inverted_byte_order)
00467 {
00468
endianswap(&l);
00469
endianswap(&w);
00470 }
00471
resize(l,w);
00472 T* ptr =
data();
00473
for(
int i=0; i<length_; i++, ptr+=mod_)
00474
binread_(in, ptr, width_, typecode);
00475 }
00476
else
00477
PLERROR(
"In TMat::read(PStream& in) Char with ascii code %d not a proper first character in the header of a TMat!",c);
00478 }
00479 }
00480
break;
00481
00482
default:
00483
PLERROR(
"In TMat<T>::read(PStream& in) unknown inmode!!!!!!!!!");
00484
break;
00485 }
00486 }
00487
00488
00489
00490
00491
00492 void save(
const string& filename)
const {
savePMat(filename, *
this); }
00493 void load(
const string& filename) {
loadPMat(filename, *
this); }
00494
00496 inline TMat<T> column(
int colnum)
const
00497
{
return subMatColumns(colnum, 1); }
00498
00499 inline TMat<T> firstColumn()
const
00500
{
return column(0); }
00501
00502 inline TMat<T> lastColumn()
const
00503
{
return column(
width()-1); }
00504
00506 inline TMat<T> row(
int row)
const
00507
{
return subMatRows(row, 1); }
00508
00509 inline T&
firstElement()
const {
return *
data(); }
00510 inline T&
lastElement()
const {
return operator()(length-1,width-1); }
00511
00512 inline TVec<T> firstRow()
const {
return operator()(0); }
00513 inline TVec<T> lastRow()
const {
return operator()(length_ - 1); }
00514 inline TVec<T> front()
const {
return firstRow(); }
00515 inline TVec<T> back()
const {
return lastRow(); }
00516
00519
template<
class I>
00520 inline TMat<T> columns(
const TVec<I>& columns)
const
00521
{
00522
TMat<T> result(
length(),columns.
length());
00523
selectColumns(*
this,columns,result);
00524
return result;
00525 }
00526
00529
template<
class I>
00530 inline TMat<T> rows(
const TVec<I>& rows)
const
00531
{
00532
TMat<T> result(rows.
length(),
width());
00533
selectRows(*
this,rows,result);
00534
return result;
00535 }
00536
00537 inline bool operator==(
const TMat<T>& other)
const
00538
{
00539
if(
length() != other.
length() ||
width() != other.
width())
00540
return false;
00541
00542
iterator it =
begin();
00543
iterator end =
end();
00544
iterator otherIt = other.
begin();
00545
for(; it != end; ++it)
00546
if(*it == *otherIt)
00547 ++otherIt;
00548
else
00549
return false;
00550
00551
return true;
00552 }
00553
00554
template<
class I>
00555 inline TMat<T> operator()(
const TVec<I>& rows,
const TVec<I>& columns)
const
00556
{
00557
TMat<T> result(rows.
length(),columns.
length());
00558
select(*
this,rows,columns,result);
00559
return result;
00560 }
00561
00563 inline TMat<T> subMat(
int rowstart,
int colstart,
int newlength,
int newwidth)
const
00564
{
00565
#ifdef BOUNDCHECK
00566
if(rowstart<0 || newlength<0 || rowstart+newlength>
length()
00567 || colstart<0 || newwidth<0 || colstart+newwidth>
width())
00568
PLERROR(
"Mat::subMat(int rowstart, int colstart, int newlength, int newwidth) OUT OF BOUNDS"
00569
" rowstart=%d colstart=%d newlength=%d newwidth=%d length()=%d width()=%d",
00570 rowstart, colstart, newlength, newwidth,
length(),
width());
00571
#endif
00572
TMat<T> subm = *
this;
00573 subm.
length_ = newlength;
00574 subm.
width_ = newwidth;
00575 subm.
offset_ += rowstart*
mod() + colstart;
00576
return subm;
00577 }
00578
00580 inline TMat<T> subMatRows(
int rowstart,
int newlength)
const
00581
{
00582
#ifdef BOUNDCHECK
00583
if(rowstart<0 || newlength<0 || rowstart+newlength>
length())
00584
PLERROR(
"TMat::subMatRows(int rowstart, int newlength) OUT OF BOUNDS");
00585
#endif
00586
TMat<T> subm = *
this;
00587 subm.
length_ = newlength;
00588 subm.
offset_ += rowstart*
mod();
00589
return subm;
00590 }
00591
00593 inline TMat<T> subMatColumns(
int colstart,
int newwidth)
const
00594
{
00595
#ifdef BOUNDCHECK
00596
if(colstart<0 || newwidth<0 || colstart+newwidth>
width())
00597
PLERROR(
"Mat::subMatColumns(int colstart, int newwidth) OUT OF BOUNDS");
00598
#endif
00599
TMat<T> subm = *
this;
00600 subm.
width_ = newwidth;
00601 subm.
offset_ += colstart;
00602
return subm;
00603 }
00604
00606 TMat<T> copy()
const
00607
{
00608
TMat<T> freshcopy(
length(),
width());
00609 freshcopy << *
this;
00610
return freshcopy;
00611 }
00612
00614 void copyTo(T* x)
const
00615
{
00616 T* row =
data();
00617
int k=0;
00618
for(
int i=0; i<
length(); i++,row+=
mod())
00619
for (
int j=0;j<
width();j++,
k++)
00620
x[
k] = row[j];
00621 }
00622
00628
void makeDeepCopyFromShallowCopy(map<const void*, void*>& copies);
00629
00634
TMat<T> deepCopy(map<const void*, void*>& copies)
const;
00635
00636
00638
TVec<T> toVecCopy() const;
00639
00641
TVec<T> toVec() const;
00642
00643 bool isNull()
const
00644
{
return storage.
isNull(); }
00645
00646 bool isNotNull()
const
00647
{
return storage.
isNotNull(); }
00648
00649 bool isEmpty()
const
00650
{
return length_==0; }
00651
00652 bool isNotEmpty()
const
00653
{
return length_!=0; }
00654
00658
00660
00661
00662
00663
00665 inline bool operator!()
const
00666
{
return isEmpty(); }
00667
00668 void fill(
const T& value)
const
00669
{
00670
if (
isNotNull()) {
00671
if(
isCompact())
00672 fill_n(
data(),
size(),value);
00673
else
00674 {
00675
int l =
length();
00676 T* ptr =
data();
00677
while(l--)
00678 {
00679 fill_n(ptr,
width(), value);
00680 ptr +=
mod();
00681 }
00682 }
00683 }
00684 }
00685
00686 inline void operator=(
const T& f)
const
00687
{ fill(f); }
00688
00689 inline void clear()
const
00690
{
00691
if(
isCompact())
00692
clear_n(
data(),
size());
00693
else
00694 {
00695
int l =
length();
00696 T* ptr =
data();
00697
while(l--)
00698 {
00699
clear_n(ptr,
width());
00700 ptr +=
mod();
00701 }
00702 }
00703 }
00704
00706 void swapRows(
int i,
int j)
const
00707
{
00708
if(i!=j)
00709 {
00710
00711
00712 T* Mi = (*this)[i];
00713 T* Mj = (*this)[j];
00714
for (
int k=0;
k<
width();
k++)
00715 {
00716 T tmp = Mi[
k];
00717 Mi[
k] = Mj[
k];
00718 Mj[
k] = tmp;
00719 }
00720 }
00721 }
00722
00723
int findRow(
const TVec<T>& row)
const;
00724
00725
inline void appendRow(
const TVec<T>& newrow);
00726
00728 inline void push_back(
const TVec<T>& newrow) { appendRow(newrow); }
00729 inline void pop_back() { length_ -= 1; }
00730
00731
00732 bool isCompact()
const
00733
{
return mod() ==
width(); }
00734
00735 bool isSymmetric()
const
00736
{
00737
if (!
isSquare())
00738
return false;
00739
00740
if (
length() == 0)
00741 {
00742
PLWARNING(
"at bool TMat::isSymmetric(), the size of the matrix is 0\n");
00743
return false;
00744 }
00745
00746
for (
int i = 0; i <
length() - 1 ; i++)
00747
for (
int j = i + 1; j <
width(); j++)
00748
if ( (*this)[i][j] != (*this)[j][i] )
00749
return false;
00750
00751
return true;
00752 }
00753
00755 void compact()
00756 {
00757
if(storage->length() !=
length()*
width())
00758 {
00759
if(storage->usage()>1)
00760
PLERROR(
"IN Mat::compact() compact operation not allowed when matrix storage is shared (for obvious reasons)");
00761 operator=(
copy());
00762 }
00763 }
00764
00765 void transpose()
00766 {
00767
if(
mod()!=
width())
00768
PLERROR(
"In transpose() can transpose in place only compact matrices whose mod()==width() (that is often not the case for submatrices");
00769
for(
int i=0; i<
length(); i++)
00770 {
00771
00772 T* rowi = (*this)[i];
00773 T* colielem = rowi+i+
mod();
00774
for(
int j=i+1; j<
width(); j++, colielem+=
mod())
00775
swap(rowi[j], *colielem);
00776 }
00777 }
00778
00779 void swapUpsideDown()
const
00780
{
00781
int half =
length()/2;
00782
for(
int i=0; i<half; i++)
00783 swapRows(i,
length()-i-1);
00784 }
00785
00787
void print(ostream& out = cout)
const;
00788
void input(istream& in = cin)
const;
00789
00790
00791 void debugPrint(){
print(cerr);}
00792
00793
00794 inline void operator<<(
const string& datastring)
const
00795
{
00796 istrstream in(datastring.c_str());
00797 input(in);
00798 }
00799
00800 };
00801
00802 typedef TMat<real> Mat;
00803
00804
00805
00806
00807
template<
class T>
00808 class TypeTraits< TMat<T> >
00809 {
00810
public:
00811 static inline string name()
00812 {
return string(
"TMat< ") +
TypeTraits<T>::name()+
" >"; }
00813
00814 static inline unsigned char little_endian_typecode()
00815 {
return 0xFF; }
00816
00817 static inline unsigned char big_endian_typecode()
00818 {
return 0xFF; }
00819 };
00820
00821 }
00822
#endif