PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal 00006 // 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 00037 00038 00039 /* ******************************************************* 00040 * $Id: TMat_decl.h 10069 2009-03-27 18:14:38Z tihocan $ 00041 * AUTHORS: Pascal Vincent & Yoshua Bengio 00042 * This file is part of the PLearn library. 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 // predeclarations 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; // iterator over elements 00088 typedef TMatElementIterator<T> const_iterator; // iterator over elements 00089 typedef T* compact_iterator; // super-efficient iterator over elements but works reliably only for compact matrices 00090 typedef T* rowelements_iterator; // iterator over elements of a 00091 // particular row 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 00200 void resize(int new_length, int new_width, int extra=0, bool preserve_content=false) 00201 { 00202 #ifdef BOUNDCHECK 00203 resizeBoundCheck(new_length, new_width); 00204 #endif 00205 if (new_length==length_ && new_width==width_) 00206 return; 00207 else if(storage.isNull()) 00208 { 00209 offset_ = 0; 00210 length_ = new_length; 00211 width_ = new_width; 00212 mod_ = new_width; 00213 long newsize=(long)length()*mod() + extra; 00214 storage = new Storage<T>(newsize); 00215 } 00216 else 00217 { 00218 int usage = storage->usage(); 00219 if (usage > 1 && mod() != 0 && new_width > mod()-offset_%mod()) 00220 resizeModError(); 00221 else if (preserve_content && size() > 0) 00222 resizePreserve(new_length, new_width, extra); 00223 else { 00224 // 'new_size' takes into account the ABSOLUTELY REQUIRED size 00225 // to hold the elements of the matrix. We only resize the 00226 // underlying storage when the latter is not big enough to hold 00227 // 'new_size'. When resizing the storage, we include 'extra' 00228 // more elements to anticipate further resizes (e.g. coming 00229 // from appendRow()). IMPORTANT NOTE: don't include those 00230 // 'extra' bytes in the computation of 'new_size', for 00231 // otherwise a matrix reallocation will occur EVERY TIME 00232 // appendRow is called, turning an amortized O(N) algorithm 00233 // into an O(N^2) one. 00234 long new_size = offset_+(long)new_length*MAX(mod(),new_width); 00235 if(new_size > storage->length()) 00236 storage->resize(new_size + extra); 00237 if(new_width > mod()) 00238 mod_ = new_width; 00239 } 00240 length_ = new_length; 00241 width_ = new_width; 00242 } 00243 } 00244 00245 inline int length() const 00246 { return length_; } 00247 00248 inline int width() const 00249 { return width_; } 00250 00251 inline int size() const 00252 { return length_*width_; } 00253 00254 inline int mod() const 00255 { return mod_; } 00256 00259 inline bool isContiguous() const 00260 { return mod_==width_; } 00261 00264 inline bool isNotContiguous() const 00265 { return mod_!=width_; } 00266 00271 void setMod(int new_mod) 00272 { 00273 if (new_mod == mod()) 00274 // Nothing to do (the new mod is equal to the old one). 00275 return; 00276 if (storage.isNull()) { 00277 mod_ = new_mod; 00278 return; 00279 } 00280 if (storage->usage() > 1) 00281 PLERROR("In setMod - You cannot change the 'mod' of a matrix " 00282 "whose storage is shared"); 00283 if (new_mod > mod()) { 00284 // The mod is increased: we may need a larger storage. To this 00285 // extent, the matrix is first resized to a width equal to the new 00286 // mod, to ensure the storage is large enough for the new mod. 00287 int width_backup = width(); 00288 resize(length(), new_mod); 00289 PLASSERT( mod() == new_mod ); 00290 width_ = width_backup; 00291 } else { 00292 // Note that since new_mod < curent mod, then the storage is 00293 // necessarily already large enough and does not need resizing. 00294 mod_ = new_mod; 00295 if (new_mod < width()) { 00296 // We cannot just change the mod, because in order to be a 00297 // valid Mat, we must have mod >= width. Thus we also change 00298 // the width to match the new mod. 00299 width_ = new_mod; 00300 } 00301 } 00302 } 00303 00304 inline PP< Storage<T> > getStorage() const 00305 { return storage; } 00306 00307 inline bool isSquare() const 00308 { return length() == width(); } 00309 00310 bool hasMissing() const 00311 { 00312 if ( isEmpty() ) 00313 return false; 00314 00315 iterator it = begin(); 00316 iterator itend = end(); 00317 for(; it!=itend; ++it) 00318 if(is_missing(*it)) 00319 return true; 00320 return false; 00321 } 00322 00324 inline T* data() const 00325 { 00326 #ifdef BOUNDCHECK 00327 if(storage.isNull()) 00328 PLERROR("IN TMat::data()\nAttempted to get a pointer to the data of an empty matrix"); 00329 #endif 00330 return storage->data+offset_; 00331 } 00332 00334 inline T* operator[](int rownum) const 00335 { 00336 #ifdef BOUNDCHECK 00337 if(rownum<0 || rownum>=length()) 00338 PLERROR("OUT OF BOUND ACCESS IN TMat::operator[](int rownum=%d), length=%d",rownum,length()); 00339 #endif 00340 return storage->data + offset_ + mod()*rownum; 00341 } 00342 00343 inline T* rowdata(int i) const { return (*this)[i]; } 00344 00345 inline T& operator()(int rownum, int colnum) const 00346 { 00347 #ifdef BOUNDCHECK 00348 if(rownum<0 || rownum>=length() || colnum<0 || colnum>=width()) 00349 PLERROR("OUT OF BOUND ACCESS IN TMat::operator()(int rownum, int colnum)" 00350 " width=%d; length=%d; colnum=%d; rownum=%d;", width(), length(), colnum, rownum); 00351 #endif 00352 return storage->data[offset_ + mod()*rownum + colnum]; 00353 } 00354 00355 inline TVec<T> operator()(int rownum) const 00356 { 00357 #ifdef BOUNDCHECK 00358 if(rownum<0 || rownum>=length()) 00359 PLERROR("OUT OF BOUND ACCESS IN TMat_impl::operator()(int rownum)"); 00360 #endif 00361 TVec<T> tv; 00362 tv.length_ = width(); 00363 tv.offset_ = offset_ + mod()*rownum; 00364 tv.storage = storage; 00365 return tv; 00366 } 00367 00370 void write(PStream& out) const 00371 { 00372 T* ptr = 0; 00373 if(storage) 00374 ptr = data(); 00375 00376 switch(out.outmode) 00377 { 00378 case PStream::raw_ascii: 00379 case PStream::pretty_ascii: 00380 for(int i=0; i<length_; i++, ptr+=mod_) 00381 { 00382 for(int j=0; j<width_; j++) 00383 { 00384 out << ptr[j]; 00385 out.put('\t'); 00386 } 00387 out.put('\n'); 00388 } 00389 break; 00390 00391 case PStream::raw_binary: 00392 for(int i=0; i<length_; i++, ptr+=mod_) 00393 binwrite_(out, ptr, width_); 00394 break; 00395 00396 case PStream::plearn_ascii: 00397 { 00398 if(!out.implicit_storage) 00399 { 00400 out.write("TMat("); 00401 out << length_ << width_ << mod_ << offset_ << storage; 00402 out.write(")\n"); 00403 } 00404 else // implicit storage 00405 { 00406 out << length_; 00407 out.put(' '); 00408 out << width_; 00409 out.write(" [ \n"); 00410 for(int i=0; i<length_; i++, ptr+=mod_) 00411 { 00412 for(int j=0; j<width_; j++) 00413 { 00414 out << ptr[j]; 00415 out.put('\t'); 00416 } 00417 out.put('\n'); 00418 } 00419 out.write("]\n"); 00420 } 00421 } 00422 break; 00423 00424 case PStream::plearn_binary: 00425 { 00426 if(!out.implicit_storage) 00427 { 00428 out.write("TMat("); 00429 out << length_ << width_ << mod_ << offset_ << storage; 00430 out.write(")\n"); 00431 } 00432 else // implicit storage 00433 { 00434 unsigned char typecode; 00435 if(byte_order()==LITTLE_ENDIAN_ORDER) 00436 { 00437 out.put(0x14); // 2D little-endian 00438 typecode = TypeTraits<T>::little_endian_typecode(); 00439 } 00440 else 00441 { 00442 out.put(0x15); // 2D big-endian 00443 typecode = TypeTraits<T>::big_endian_typecode(); 00444 } 00445 00446 // write typecode 00447 out.put(typecode); 00448 00449 // write length and width in raw_binary 00450 out.write((char*)&length_, sizeof(length_)); 00451 out.write((char*)&width_, sizeof(width_)); 00452 00453 // write the data 00454 for(int i=0; i<length_; i++, ptr+=mod_) 00455 binwrite_(out, ptr, width_); 00456 } 00457 } 00458 break; 00459 00460 default: 00461 PLERROR("In TMat::write(PStream& out) unknown outmode!!!!!!!!!"); 00462 break; 00463 } 00464 } 00465 00466 00467 00470 void read(PStream& in) 00471 { 00472 00473 switch(in.inmode) 00474 { 00475 case PStream::raw_ascii: 00476 case PStream::raw_binary: 00477 { 00478 T* ptr = (length_>0 && width_>0)? data():0; 00479 for(int i=0; i<length_; i++, ptr+=mod_) 00480 for(int j=0; j<width_; j++) 00481 in >> ptr[j]; 00482 } 00483 break; 00484 00485 case PStream::plearn_ascii: 00486 case PStream::plearn_binary: 00487 { 00488 in.skipBlanksAndComments(); 00489 int c = in.peek(); 00490 if(c=='T') // explicit storage 00491 { 00492 char word[6]; 00493 // !!!! BUG: For some reason, this hangs!!! 00494 // in.read(word,5); 00495 00496 for(int i=0; i<5; i++) 00497 in.get(word[i]); 00498 00499 word[5]='\0'; 00500 if(strcmp(word,"TMat(")!=0) 00501 PLERROR("In operator>>(PStream&, TMat&) '%s' not a proper header for a TMat!",word); 00502 // v.storage = 0; 00503 in >> length_ >> width_ >> mod_ >> offset_; 00504 in >> storage; 00505 in.skipBlanksAndCommentsAndSeparators(); 00506 int c = in.get(); // skip ')' 00507 if(c!=')') 00508 PLERROR("In operator>>(PStream&, TMat&) expected a closing parenthesis, found '%c'",c); 00509 } 00510 else // implicit storage 00511 { 00512 if(isdigit(c)) // ascii mode with length and width given 00513 { 00514 int l,w; 00515 in >> l >> w; 00516 in.skipBlanksAndComments(); 00517 c = in.get(); 00518 if(c!='[') 00519 PLERROR("Error in TMat::read(PStream& in), expected '[', read '%c'",c); 00520 in.skipBlanksAndCommentsAndSeparators(); 00521 resize(l,w); 00522 T* ptr = (l>0 && w>0)? data():0; 00523 for(int i=0; i<length_; i++, ptr+=mod_) 00524 for(int j=0; j<width_; j++) 00525 { 00526 in.skipBlanksAndCommentsAndSeparators(); 00527 try{ 00528 in >> ptr[j]; 00529 } 00530 catch(const PLearnError& e) { 00531 PLERROR("In TMat::read() - Error while reading a serialised TMat<T>." 00532 " Did you set correctly the mat size?\n" 00533 "%s",e.message().c_str()); 00534 } 00535 } 00536 in.skipBlanksAndCommentsAndSeparators(); 00537 c = in.get(); 00538 if(c!=']') 00539 PLERROR("Error in TMat::read(PStream& in), expected ']', read '%c'",c); 00540 } 00541 else if(c==0x14 || c==0x15) // it's a binary 2D sequence 00542 { 00543 in.get(); // eat c 00544 unsigned char typecode = in.get(); 00545 int l, w; 00546 in.read((char*)&l,sizeof(l)); 00547 in.read((char*)&w,sizeof(w)); 00548 bool inverted_byte_order = ((c==0x14 && byte_order()==BIG_ENDIAN_ORDER) 00549 || (c==0x15 && byte_order()==LITTLE_ENDIAN_ORDER) ); 00550 if(inverted_byte_order) 00551 { 00552 endianswap(&l); 00553 endianswap(&w); 00554 } 00555 resize(l,w); 00556 T* ptr = (l>0 && w>0)? data():0; 00557 for(int i=0; i<length_; i++, ptr+=mod_) 00558 binread_(in, ptr, width_, typecode); 00559 } 00560 else 00561 PLERROR("In TMat::read(PStream& in) Char with ascii code %d not a proper first character in the header of a TMat!",c); 00562 } 00563 } 00564 break; 00565 00566 default: 00567 PLERROR("In TMat<T>::read(PStream& in) unknown inmode!!!!!!!!!"); 00568 break; 00569 } 00570 } 00571 00572 // The following methods are deprecated, and just call corresponding functions. 00573 // Please call those functions directly in new code 00574 //void write(ostream& out) const { PLearn::write(out, *this); } 00575 //void read(istream& in) { PLearn::read(in, *this); } 00576 // void save(const string& filename) const { savePMat(filename, *this); } 00577 // void load(const string& filename) { loadPMat(filename, *this); } 00578 00580 inline TMat<T> column(int colnum) const 00581 { return subMatColumns(colnum, 1); } 00582 00583 inline TMat<T> firstColumn() const 00584 { return column(0); } 00585 00586 inline TMat<T> lastColumn() const 00587 { return column(width()-1); } 00588 00590 inline TMat<T> row(int row) const 00591 { return subMatRows(row, 1); } 00592 00593 inline T& firstElement() const { return *data(); } 00594 inline T& lastElement() const { return operator()(length_-1,width_-1); } 00595 00596 inline TVec<T> firstRow() const { return operator()(0); } 00597 inline TVec<T> lastRow() const { return operator()(length_ - 1); } 00598 inline TVec<T> front() const { return firstRow(); } 00599 inline TVec<T> back() const { return lastRow(); } 00600 00603 template<class I> 00604 inline TMat<T> columns(const TVec<I>& columns) const 00605 { 00606 TMat<T> result(length(),columns.length()); 00607 selectColumns(*this,columns,result); 00608 return result; 00609 } 00610 00613 template<class I> 00614 inline TMat<T> rows(const TVec<I>& rows) const 00615 { 00616 TMat<T> result(rows.length(),width()); 00617 selectRows(*this,rows,result); 00618 return result; 00619 } 00620 00621 inline bool operator==(const TMat<T>& other) const; 00622 inline bool isEqual(const TMat<T>& other, real precision=1e-6) const; 00623 00624 template<class I> 00625 inline TMat<T> operator()(const TVec<I>& rows, const TVec<I>& columns) const 00626 { 00627 TMat<T> result(rows.length(),columns.length()); 00628 select(*this,rows,columns,result); 00629 return result; 00630 } 00631 00633 inline TMat<T> subMat(int rowstart, int colstart, int newlength, int newwidth) const 00634 { 00635 #ifdef BOUNDCHECK 00636 if(rowstart<0 || newlength<0 || rowstart+newlength>length() 00637 || colstart<0 || newwidth<0 || colstart+newwidth>width()) 00638 PLERROR("Mat::subMat(int rowstart, int colstart, int newlength, int newwidth) OUT OF BOUNDS" 00639 " rowstart=%d colstart=%d newlength=%d newwidth=%d length()=%d width()=%d", 00640 rowstart, colstart, newlength, newwidth, length(), width()); 00641 #endif 00642 TMat<T> subm = *this; 00643 subm.length_ = newlength; 00644 subm.width_ = newwidth; 00645 subm.offset_ += rowstart*mod() + colstart; 00646 return subm; 00647 } 00648 00650 inline TMat<T> subMatRows(int rowstart, int newlength) const 00651 { 00652 #ifdef BOUNDCHECK 00653 if(rowstart<0 || newlength<0 || rowstart+newlength>length()) 00654 PLERROR("TMat::subMatRows(int rowstart, int newlength) OUT OF BOUNDS" 00655 "length=%d, rowstart=%d, newlength=%d", length(), rowstart, newlength); 00656 #endif 00657 TMat<T> subm = *this; 00658 subm.length_ = newlength; 00659 subm.offset_ += rowstart*mod(); 00660 return subm; 00661 } 00662 00664 inline TMat<T> subMatColumns(int colstart, int newwidth) const 00665 { 00666 #ifdef BOUNDCHECK 00667 if(colstart<0 || newwidth<0 || colstart+newwidth>width()) 00668 PLERROR("Mat::subMatColumns(int colstart, int newwidth) OUT OF BOUNDS"); 00669 #endif 00670 TMat<T> subm = *this; 00671 subm.width_ = newwidth; 00672 subm.offset_ += colstart; 00673 return subm; 00674 } 00675 00677 TMat<T> copy() const 00678 { 00679 TMat<T> freshcopy(length(),width()); 00680 freshcopy << *this; 00681 return freshcopy; 00682 } 00683 00685 void copyTo(T* x) const 00686 { 00687 T* row = data(); // get data start 00688 int k=0; 00689 for(int i=0; i<length(); i++,row+=mod()) 00690 for (int j=0;j<width();j++,k++) 00691 x[k] = row[j]; 00692 } 00693 00696 void copyColumnTo(int col, T* x) const 00697 { 00698 T* s = data()+col; 00699 for(int i=0;i<length();i++){ 00700 *x=*s; 00701 x++; 00702 s+=mod(); 00703 } 00704 } 00710 void makeDeepCopyFromShallowCopy(CopiesMap& copies); 00711 00716 TMat<T> deepCopy(CopiesMap& copies) const; 00717 00718 00720 TVec<T> toVecCopy() const; 00721 00723 TVec<T> toVec() const; 00724 00725 bool isNull() const 00726 { return storage.isNull(); } 00727 00728 bool isNotNull() const 00729 { return storage.isNotNull(); } 00730 00731 bool isEmpty() const 00732 { return length_ == 0 || width_ == 0; } 00733 00734 bool isNotEmpty() const 00735 { return length_ != 0 && width_ != 0; } 00736 00740 /* 00742 inline operator bool() const 00743 { return isNotEmpty(); } 00744 */ 00745 00747 inline bool operator!() const 00748 { return isEmpty(); } 00749 00750 void fill(const T& value) const 00751 { 00752 if (isNotEmpty()) { 00753 if(isCompact()) 00754 fill_n(data(),size(),value); 00755 else 00756 { 00757 int l = length(); 00758 T* ptr = data(); 00759 while(l--) 00760 { 00761 fill_n(ptr, width(), value); 00762 ptr += mod(); 00763 } 00764 } 00765 } 00766 } 00767 00768 inline void operator=(const T& f) const 00769 { fill(f); } 00770 00771 inline void clear() const 00772 { 00773 if(isNotEmpty()) 00774 { 00775 if(isCompact()) 00776 clear_n(data(),size()); 00777 else 00778 { 00779 int l = length(); 00780 T* ptr = data(); 00781 while(l--) 00782 { 00783 clear_n(ptr, width()); 00784 ptr += mod(); 00785 } 00786 } 00787 } 00788 } 00789 00793 void swapRows(int i, int j) const 00794 { 00795 if(i!=j) 00796 { 00797 //T* Mi = rowdata(i); 00798 //T* Mj = rowdata(j); 00799 T* Mi = (*this)[i]; 00800 T* Mj = (*this)[j]; 00801 for (int k=0;k<width();k++) 00802 { 00803 T tmp = Mi[k]; 00804 Mi[k] = Mj[k]; 00805 Mj[k] = tmp; 00806 } 00807 } 00808 } 00809 00811 void swapColumns(int i, int j) const 00812 { 00813 if (i != j) 00814 { 00815 T* Mi = data() + i; 00816 T* Mj = data() + j; 00817 int n = length(); 00818 for (int k = 0; k < n; k++) { 00819 T tmp = *Mi; 00820 *Mi = *Mj; 00821 *Mj = tmp; 00822 Mi += mod(); 00823 Mj += mod(); 00824 } 00825 } 00826 } 00827 00828 int findRow(const TVec<T>& row) const; 00829 00830 inline void appendRow(const TVec<T>& newrow); 00831 00833 inline void push_back(const TVec<T>& newrow) { appendRow(newrow); } 00834 inline void pop_back() { length_ -= 1; } 00835 00841 void makeSharedValue(T* x, int n) 00842 { 00843 #ifdef BOUNDCHECK 00844 int m = size(); 00845 if(n != m) 00846 PLERROR("IN TMat::makeSharedValue(T* x, int n)\nn(%d)!=size(%d)", 00847 n,m); 00848 if(offset_!=0) 00849 PLERROR("IN TMat::makeSharedValue(T* x, int n)\noffset should be 0."); 00850 if (mod_!=width_) 00851 PLERROR("IN TMat::makeSharedValue(T* x, int n)\nMatrix should be compact (mod==width), but isn't."); 00852 #endif 00853 T* v = data(); 00854 for(int i=0,k=0; i<length_; i++, v+=mod_) 00855 for (int j=0;j<width_; j++, k++) 00856 x[k] = v[j]; 00857 storage->pointTo(n,x); 00858 } 00859 00860 bool isCompact() const 00861 { return mod() == width(); } 00862 00870 bool isSymmetric(bool exact_check = true, bool accept_empty = false) const 00871 { 00872 if (!isSquare()) 00873 return false; 00874 00875 if (isEmpty()) 00876 { 00877 if (accept_empty) 00878 return true; 00879 else { 00880 PLWARNING("In TMat::isSymmetric - The matrix is empty, considering " 00881 "it is not symmetric (use 'accept_empty' if you want to " 00882 " allow it)"); 00883 return false; 00884 } 00885 } 00886 00887 int n = length(); 00888 PLASSERT( width() == n ); 00889 00890 if (exact_check) { 00891 for (int i = 0; i < n - 1 ; i++) 00892 for (int j = i + 1; j < n; j++) 00893 if ( !fast_exact_is_equal((*this)[i][j], (*this)[j][i]) ) 00894 return false; 00895 } else { 00896 for (int i = 0; i < n ; i++) 00897 for (int j = i + 1; j < n; j++) 00898 if ( !is_equal((*this)[i][j], (*this)[j][i] ) ) 00899 return false; 00900 } 00901 00902 return true; 00903 } 00904 00906 void compact() 00907 { 00908 if(storage->length() != length()*width()) 00909 { 00910 if(storage->usage()>1) 00911 PLERROR("In TMat<T>::compact() - Compact operation not allowed" 00912 " when matrix storage is shared, for obvious reasons"); 00913 operator=(copy()); 00914 } 00915 } 00916 00919 void transpose() 00920 { 00921 if (length() != width()) 00922 PLERROR("In TMat<T>::tranpose() - Only implemented for square " 00923 "matrices"); 00924 for (int i = 0; i < length(); i++) 00925 { 00926 T* rowi = (*this)[i] + i + 1; 00927 T* colielem = rowi - 1 + mod(); 00928 for(int j = i + 1; j < width(); j++, colielem += mod(), rowi++) 00929 pl_swap(*rowi, *colielem); 00930 } 00931 } 00932 00933 void swapUpsideDown() const 00934 { 00935 int half = length()/2; 00936 for(int i=0; i<half; i++) 00937 swapRows(i, length()-i-1); 00938 } 00939 00941 void print(ostream& out = cout) const; 00942 void input(istream& in = cin) const; 00943 void input(PStream& in) const; 00944 00945 // calls print with cerr, usefull with gdb (> call obj.debugprint() ) 00946 void debugPrint(){print(cerr);} 00947 00948 00949 inline void operator<<(const string& datastring) const 00950 { 00951 // istrstream in(datastring.c_str()); 00952 PStream in = openString(datastring,PStream::plearn_ascii); 00953 input(in); 00954 } 00955 00956 protected: 00958 void resizePreserve(int new_length, int new_width, int extra=0); 00959 00961 inline void resizeBoundCheck(int new_length, int new_width); 00962 00964 void resizeModError(); 00965 }; 00966 00967 typedef TMat<real> Mat; 00968 00969 inline void deepCopyField(Mat*& field, CopiesMap& copies); 00970 00971 // Type traits (especially type "names" for displaying optionHelp() ) 00972 00973 template<class T> 00974 class TypeTraits< TMat<T> > 00975 { 00976 public: 00977 static inline string name() 00978 { return string("TMat< ") + TypeTraits<T>::name()+" >"; } 00979 00980 static inline unsigned char little_endian_typecode() 00981 { return 0xFF; } 00982 00983 static inline unsigned char big_endian_typecode() 00984 { return 0xFF; } 00985 }; 00986 00987 template <class T> 00988 inline int sizeInBytes(const TMat<T>& x) { 00989 int n=x.size(); 00990 int s=sizeof(TMat<T>); 00991 if (n>0) s+=n*sizeInBytes(x(0,0)); 00992 return s; 00993 } 00994 00995 } // end of namespace PLearn 00996 #endif 00997 00998 00999 /* 01000 Local Variables: 01001 mode:c++ 01002 c-basic-offset:4 01003 c-file-style:"stroustrup" 01004 c-file-offsets:((innamespace . 0)(inline-open . 0)) 01005 indent-tabs-mode:nil 01006 fill-column:79 01007 End: 01008 */ 01009 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :