PLearn 0.1
TMat_decl.h
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines