PLearn 0.1
AsciiVMatrix.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // AsciiVMatrix.cc
00004 //
00005 // Copyright (C) 2003 Rejean Ducharme, Pascal Vincent
00006 //
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 //
00010 //  1. Redistributions of source code must retain the above copyright
00011 //     notice, this list of conditions and the following disclaimer.
00012 //
00013 //  2. Redistributions in binary form must reproduce the above copyright
00014 //     notice, this list of conditions and the following disclaimer in the
00015 //     documentation and/or other materials provided with the distribution.
00016 //
00017 //  3. The name of the authors may not be used to endorse or promote
00018 //     products derived from this software without specific prior written
00019 //     permission.
00020 //
00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 //
00032 // This file is part of the PLearn library. For more information on the PLearn
00033 // library, go to the PLearn Web site at www.plearn.org
00034 
00035 /* *******************************************************
00036  * $Id: AsciiVMatrix.cc 8617 2008-03-03 17:45:54Z nouiz $
00037  ******************************************************* */
00038 
00041 #include "AsciiVMatrix.h"
00042 #include <plearn/base/stringutils.h>
00043 #include <plearn/io/fileutils.h>      
00044 #include <plearn/io/openFile.h>
00045 
00046 namespace PLearn {
00047 using namespace std;
00048 
00049 
00050 PLEARN_IMPLEMENT_OBJECT(AsciiVMatrix,
00051                         "AsciiVMatrix implements a file in ASCII format",
00052                         ""
00053     );
00054 
00055 AsciiVMatrix::AsciiVMatrix()
00056     :readwritemode(false), newfile(true),
00057      rewrite_length(true)
00058 {}
00059 
00060 AsciiVMatrix::AsciiVMatrix(const string& fname, bool readwrite)
00061     :filename(fname), readwritemode(readwrite), newfile(false),
00062      rewrite_length(true)
00063 {
00064     build();
00065 }
00066 
00067 AsciiVMatrix::AsciiVMatrix(const string& fname, int the_width,
00068                            const TVec<string>& the_fieldnames,
00069                            const string& comment)
00070     :inherited(0,the_width), filename(fname),
00071      readwritemode(true), newfile(true), rewrite_length(true)
00072 {
00073     inherited::build();
00074 
00075     if (isfile(filename))
00076         PLERROR("In AsciiVMatrix constructor: filename %s already exists",filename.c_str());
00077     file = openFile(filename, PStream::raw_ascii, "w");
00078     // TODO Is this really the same as old code ?
00079     // file->open(filename.c_str(), fstream::in | fstream::out | fstream::trunc);
00080 
00081     file << "#size: ";
00082     PLERROR("In AsciiVMatrix::AsciiVMatrix - Code is not yet PStram compatible");
00083     // vmatlength_pos = file.tellp(); // TODO See how to do this with PStreams.
00084     length_max = 9999999;  // = 10 000 000 - 1
00085     file << "0 " << width() << "      " << endl;
00086 
00087 
00088     if(the_fieldnames.length()>0)
00089     {
00090         if(the_fieldnames.length()!=the_width)
00091             PLERROR("In AsciiVMatrix constructor: number of given fieldnames (%d) differs from given width (%d)",
00092                     the_fieldnames.length(), the_width);
00093         file << "#: ";
00094         for(int k=0; k<the_width; k++)
00095         {
00096             string field_k = space_to_underscore(the_fieldnames[k]);
00097             declareField(k, field_k);
00098             file << field_k << ' ';
00099         }
00100         file << endl;
00101     }
00102 
00103     if(comment!="")
00104     {
00105         if(comment[0]!='#')
00106             PLERROR("In AsciiVMatrix constructor: comment must start with a #");
00107         file << comment;
00108         if(comment[comment.length()-1]!='\n')
00109             file << endl;
00110     }
00111 
00112 }
00113 
00114 void AsciiVMatrix::build()
00115 {
00116     inherited::build();
00117     build_();
00118 }
00119 
00120 void AsciiVMatrix::build_()
00121 {
00122     updateMtime(filename);
00123 
00124     if(!newfile)  // open old file
00125     {
00126         if (!isfile(filename))
00127             PLERROR("In AsciiVMatrix constructor (with specified width), filename %s does not exists",filename.c_str());
00128         file = openFile(filename, PStream::raw_ascii, "w");
00129         // TODO Is this really the same as the old code ?
00130         // file->open(filename.c_str(), fstream::in | fstream::out);
00131 
00132         // read the matrix in old or new format
00133         int length = -1;
00134         int width = -1;
00135         bool could_be_old_amat = true;
00136         // file->seekg(0,fstream::beg); // TODO Will it work without this ?
00137         file >> ws;
00138         string line;
00139         while (file.peek()=='#')
00140         {
00141             PLERROR("In AsciiVMatrix::build_ - Code is not PStream-compatible yet");
00142             // streampos old_pos = file.tellg(); // TODO See how to do this with PStreams.
00143             file.getline(line);
00144             could_be_old_amat = false;
00145             size_t pos=line.find(":");
00146             if (pos!=string::npos)
00147             {
00148                 string sub=line.substr(0,pos);
00149                 if (sub=="#size") // we've found the dimension specification line
00150                 {
00151                     string siz=removeblanks((line.substr(pos)).substr(1));
00152                     vector<string> dim = split(siz," ");
00153                     if (dim.size()!=2)  PLERROR("I need exactly 2 dimensions for matrix");
00154                     length = toint(dim[0]);
00155                     width = toint(dim[1]);
00156 
00157                     // we set vmatlength_pos
00158                     // streampos current_pos = file.tellg(); // TODO See how to do this with PStreams.
00159                     PLERROR("In AsciiVMatrix::build_ - Code is not PStream-compatible yet");
00160                     // file->seekg(old_pos); // TODO How to do this with PStreams ?
00161                     char c = file.get();
00162                     while (c != ':')
00163                     {
00164                         c = file.get();
00165                     }
00166                     c = file.get();
00167                     // vmatlength_pos = file.tellp(); // TODO See how to do this with PStreams.
00168                     //file.seekg(current_pos); // TODO How to do this with PStreams ?
00169 
00170                     // we set length_max
00171                     int width_ndigits = (int)pl_log(real(width)) + 1;
00172                     string remain = removenewline(line.substr(pos+1));
00173                     int length_ndigits = (int)remain.length() - width_ndigits - 1;
00174                     length_max = (int)pow(10.0,double(length_ndigits)) - 1;
00175                 }
00176             }
00177             file >> ws;
00178         }
00179 
00180         if (length==-1)  // still looking for size info...
00181         {
00182             getNextNonBlankLine(file,line);
00183             int nfields1 = (int)split(line).size();
00184             getNextNonBlankLine(file,line);
00185             if (line=="") // only one line, no length nor width info
00186             {
00187                 length=1;
00188                 width=nfields1;
00189                 rewrite_length = false;
00190                 could_be_old_amat = false;
00191             }
00192             int nfields2 = (int)split(line).size();
00193             int guesslength = countNonBlankLinesOfFile(filename);
00194             real a, b;
00195             if (could_be_old_amat && nfields1==2) // could be an old .amat with first 2 numbers being length width
00196             {
00197                 PLERROR("In AsciiVMatrix::build_ - Code is not PStream-compatible yet");
00198                 // file.seekg(0,fstream::beg); // TODO How to do this with PStreams ?
00199                 // file.clear(); // TODO Same question
00200                 // vmatlength_pos = file.tellp(); // TODO See how to do this with PStreams.
00201                 file >> a >> b;
00202                 if (guesslength == int(a)+1              &&
00203                     fast_exact_is_equal(real(int(a)), a) &&
00204                     fast_exact_is_equal(real(int(b)), b) &&
00205                     a>0 && b>0 && int(b)==nfields2) // it's clearly an old .amat
00206                 {
00207                     length = int(a);
00208                     width = int(b);
00209 
00210                     // file.seekg(vmatlength_pos); // TODO How to do this with PStreams ?
00211                     file.getline(line);
00212                     int width_ndigits = (int)pl_log(real(width)) + 1;
00213                     int max_length_ndigits = (int)line.length() - width_ndigits - 1;
00214                     length_max = (int)pow(10.0,double(max_length_ndigits)) - 1;
00215                 }
00216             }
00217 
00218             if (length==-1) // still don't know size info...
00219             {
00220                 if (nfields1==nfields2) // looks like a plain ascii file
00221                 {
00222                     rewrite_length = false;
00223                     length=guesslength;
00224                     if (width!=-1 && width!=nfields1)
00225                     {
00226                         PLWARNING("In AsciiVMatrix:  Number of fieldnames and width mismatch in file %s.", filename.c_str());
00227                     }
00228                     width = nfields1;
00229                 }
00230                 else
00231                     PLERROR("In AsciiVMatrix: trying to load but couldn't determine file format automatically for %s",filename.c_str());
00232             }
00233         }
00234 
00235         length_ = length;
00236         width_ = width;
00237 
00238         // build the vector of position of the begining of the lines
00239         PLERROR("In AsciiVMatrix::build_ - Code is not PStream-compatible yet");
00240         // file.seekg(0,fstream::beg); // TODO How to do this with PStreams ?
00241         // file.clear();
00242         if (could_be_old_amat && rewrite_length)
00243         {
00244             file.getline(line);
00245         }
00246         pos_rows.clear();
00247         while (!file.eof())
00248         {
00249             file >> ws;
00250             // if (file.peek()!='#' && file.peek()!=EOF) pos_rows.push_back(file.tellg()); // TODO See how to do this with PStreams.
00251             file.getline(line);
00252         }
00253         // file.clear(); // TODO See how to do this with PStreams.
00254         if ((int)pos_rows.size() != length)
00255             PLERROR("In AsciiVMatrix: the matrix has not the rigth size");
00256     }
00257 }
00258 
00259 void AsciiVMatrix::getNewRow(int i, const Vec& v) const
00260 {
00261 #ifdef BOUNDCHECK
00262     if(i<0 || i>length())
00263         PLERROR("In AsciiVMatrix::getNewRow, bad row number %d",i);
00264     if(v.length() != width())
00265         PLERROR("In AsciiVMatrix::getNewRow, length of v (%d) does not match matrix width (%d)",v.length(),width());
00266 #endif
00267 
00268     // file.seekg(pos_rows[i]); // TODO How to do this with PStreams ?
00269     for (int j=0; j<width(); j++)
00270         file >> v[j];
00271 }
00272 
00273 void AsciiVMatrix::appendRow(Vec v)
00274 {
00275     if(v.length()!=width())
00276         PLERROR("In AsciiVMatrix::appendRow, length of Vec to append (%d) differs from width of matrix (%d)",v.length(), width());
00277 
00278     if (length() == length_max)
00279         PLERROR("AsciiVMatrix::appendRow aborted: the matrix has reach its maximum length.");
00280 
00281     if(!readwritemode)
00282         PLERROR("AsciiVMatrix::appendRow aborted: the vmat was opened in read only format.");
00283 
00284     // write the Vec at the end of the file
00285     // file.seekp(0,fstream::end); // TODO How to do this with PStreams ?
00286     // pos_rows.push_back(file.tellg()); // TODO How to do this with PStreams ?
00287 
00288     // file.precision(15); // TODO See what it means to remove it.
00289     for (int i=0; i<v.length(); i++)
00290         file << v[i] << ' ';
00291     file << endl;
00292 
00293     // update the length
00294     length_++;
00295     if (rewrite_length)
00296     {
00297         // file->seekp(vmatlength_pos); // TODO How to do this with PStreams ?
00298         file << length() << " " << width();
00299     }
00300 }
00301 
00302 void AsciiVMatrix::put(int i, int j, real value)
00303 { PLERROR("In AsciiVMatrix::put not permitted."); }
00304 void AsciiVMatrix::putSubRow(int i, int j, Vec v)
00305 { PLERROR("In AsciiVMatrix::putSubRow not permitted."); }
00306 void AsciiVMatrix::putRow(int i, Vec v)
00307 { PLERROR("In AsciiVMatrix::putRow not permitted."); }
00308 
00309 void AsciiVMatrix::declareOptions(OptionList& ol)
00310 {
00311     declareOption(ol, "filename", &AsciiVMatrix::filename, OptionBase::buildoption, "Filename of the matrix");
00312     declareOption(ol, "readwritemode", &AsciiVMatrix::readwritemode, OptionBase::buildoption, "Is the file to be opened in read/write mode");
00313     inherited::declareOptions(ol);
00314 }
00315 
00316 AsciiVMatrix::~AsciiVMatrix()
00317 {}
00318 
00319 } // end of namespace PLearn
00320 
00321 
00322 /*
00323   Local Variables:
00324   mode:c++
00325   c-basic-offset:4
00326   c-file-style:"stroustrup"
00327   c-file-offsets:((innamespace . 0)(inline-open . 0))
00328   indent-tabs-mode:nil
00329   fill-column:79
00330   End:
00331 */
00332 // 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