PLearn 0.1
RealMapping.cc
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  * $Id: RealMapping.cc 9203 2008-07-03 16:39:04Z nouiz $
00038  * This file is part of the PLearn library.
00039  ******************************************************* */
00040 
00041 #include "RealMapping.h"
00042 #include <algorithm>
00043 #include <plearn/io/fileutils.h>    
00044 //#include <sstream>
00045 #include "stringutils.h"  
00046 #include <plearn/io/PStream.h>
00047 
00048 namespace PLearn {
00049 using namespace std;
00050 
00051 
00052 PLEARN_IMPLEMENT_OBJECT(
00053     RealMapping,
00054     "Mapping between ranges and values.",
00055     "RealMapping is used as a component of binning operations.  It divides the\n"
00056     "real line in a set of ranges, and associates each range with a single\n"
00057     "(usually integer) value.  The ranges are specified as follows:\n"
00058     "\n"
00059     "- ]low,high[ : both endpoints are EXCLUDED\n"
00060     "- [low,high[ : lower endpoint INCLUDED, upper endpoint EXCLUDED\n"
00061     "- [low,high] : both endpoints are INCLUDED\n"
00062     "- ]low,high] : lower endpoint EXCLUDED, upper endpoint INCLUDED\n"
00063     );
00064 
00066 // << //
00068 PStream& operator<<(PStream& out, const RealRange& x) 
00069 { 
00070     out.put(x.leftbracket);
00071     out << x.low;
00072     switch(out.outmode) {
00073     case PStream::raw_ascii:
00074     case PStream::pretty_ascii:
00075         out << ' ';
00076         break;
00077     default:
00078         // Nothing to add.
00079         break;
00080     }
00081     out << x.high;
00082     out.put(x.rightbracket);
00083     return out;
00084 }
00085 
00087 // >> //
00089 PStream& operator>>(PStream& in, RealRange &x) 
00090 { 
00091     in.skipBlanksAndCommentsAndSeparators();
00092     x.leftbracket = in.get();
00093     in.skipBlanksAndComments();
00094     in >> x.low;
00095     in.skipBlanksAndComments();
00096     in >> x.high;
00097     in.skipBlanksAndComments();
00098     x.rightbracket = in.get();
00099     x.checkbrackets();
00100     return in;
00101 }
00102 
00103 string RealRange::getString() const 
00104 {
00105     ostringstream s;
00106     s << leftbracket << low << ' ' << high << rightbracket;
00107     return s.str();
00108 //    
00109 //    char s[50];
00110 //    sprintf(s,"%c%f %f%c",leftbracket,low,high,rightbracket);
00111 //    return s;
00112 }  
00113 
00114 
00115 bool RealRange::contains(real val) const
00116 { return (val>=low) && (val<=high)
00117                     && (!fast_exact_is_equal(val, low)  || leftbracket=='[')
00118                     && (!fast_exact_is_equal(val, high) || rightbracket==']');
00119 }
00120 
00121 bool RealRange::operator<(real x) const
00122 { return high < x || (fast_exact_is_equal(high, x) && rightbracket == '['); }
00123 
00124 bool RealRange::operator>(real x) const
00125 { return low > x || (fast_exact_is_equal(low, x) && leftbracket == ']'); }
00126 
00127 bool RealRange::operator<(const RealRange& x) const
00128 { return high < x.low || (fast_exact_is_equal(high, x.low) && (rightbracket=='[' || x.leftbracket==']')); }
00129 
00130 bool RealRange::operator>(const RealRange& x) const
00131 { return low > x.high || (fast_exact_is_equal(low, x.high) && (leftbracket==']' || x.rightbracket=='[')); }
00132 
00133 bool RealRange::operator==(const RealRange& rr) const
00134 {
00135     return (fast_exact_is_equal(rr.low, low)  && 
00136             fast_exact_is_equal(rr.high,high) && 
00137             rr.leftbracket == leftbracket     && 
00138             rr.rightbracket == rightbracket);
00139 }
00140 
00141 
00142 // ==============================================
00143 
00144 bool RealMapping::operator==(const RealMapping& rm) const
00145 {
00146     return (rm.mapping == mapping && 
00147             is_equal(rm.missing_mapsto, missing_mapsto, 1, 0, 0) &&
00148             rm.keep_other_as_is == keep_other_as_is &&
00149             is_equal(rm.other_mapsto, other_mapsto, 1, 0, 0));
00150 }
00151 
00152 bool operator<(RealMapping::single_mapping_t a, RealMapping::single_mapping_t b)
00153 {
00154     return a.first<b.first;
00155 }
00156 
00157 real RealMapping::maxMappedToValue()
00158 {
00159     real max = -9999999;
00160     mapping_t::iterator it = mapping.begin();
00161     mapping_t::iterator itend = mapping.end();
00162     for(; it!=itend; ++it)
00163         if(it->second > max)
00164             max = it->second;
00165     return max;
00166 }    
00167 
00168 void RealMapping::declareOptions(OptionList& ol) 
00169 {
00170     declareOption(
00171         ol, "mapping", &RealMapping::mapping, OptionBase::buildoption,
00172         "The mapping");
00173 
00174     declareOption(
00175         ol, "missing_mapsto", &RealMapping::missing_mapsto, OptionBase::buildoption,
00176         "Value to which to map missing values (can be missing value)");
00177 
00178     declareOption(
00179         ol, "keep_other_as_is", &RealMapping::keep_other_as_is,
00180         OptionBase::buildoption,
00181         "If true, values not in mapping are left as is, otherwise they're\n"
00182         "mapped to 'other_mapsto' (default=True)");
00183 
00184     declareOption(
00185         ol, "other_mapsto", &RealMapping::other_mapsto, OptionBase::buildoption,
00186         "Value to which to map values not in mapping, if 'keep_other_as_is' is\n"
00187         "false");
00188     
00189     // Now call the parent class' declareOptions
00190     inherited::declareOptions(ol);
00191 }
00192 
00193 void RealMapping::buildOrderedMapping()
00194 { 
00195     o_mapping.resize(0);
00196     for(iterator it = begin();it!=end();++it)
00197         o_mapping.push_back(*it);
00198     sort(o_mapping.begin(),o_mapping.end());
00199 }
00200 
00201 real RealMapping::map(real val) const
00202 {
00203     if(is_missing(val))
00204         return missing_mapsto;
00205     mapping_t::const_iterator it= mapping.lower_bound(RealRange('[',val,val,']'));
00206     if(it != mapping.end() && it->first.contains(val))
00207         return it->second;
00208     if(keep_other_as_is)
00209         return val;
00210     else
00211         return other_mapsto;      
00212 }
00213 
00214 
00215 void RealMapping::addMapping(const RealRange& range, real val)
00216 {
00217     //PStream perr(&cerr);
00218     //perr << "BEFORE " << mapping << endl;
00219     //perr << "ADDING " << range << "->" << val << endl;
00220     mapping[range]= val; 
00221     //perr << "AFTER " << mapping << endl;
00222     // cout<<"adding :"<<range<<" = "<<val<<endl;
00223     // cout<<"MAPPING:"<<*this<<endl;
00224 }
00225 //    { mapping.push_back(make_pair(range,val)); }
00226 
00227 
00228 int RealMapping::binnumber(real val) const
00229 {
00230     if(is_missing(val))
00231         return -2;
00232     mapping_t::const_iterator it = mapping.begin();
00233     mapping_t::const_iterator itend = mapping.end();
00234     for(int num=0; it!=itend; ++it,num++)
00235         if(it->first.contains(val))
00236             return num;
00237     return -1;      
00238 }
00239 
00240 
00241 void RealMapping::transform(const Vec& v) const
00242 {
00243     real* p = v.data();
00244     int l = v.length();
00245     while(l--)
00246     {
00247         *p = map(*p);
00248         ++p;
00249     }
00250 }
00251 
00253 // newwrite //
00255 void RealMapping::newwrite(PStream& out) const {
00256     switch (out.outmode) {
00257     case PStream::raw_ascii:
00258         out << "{ ";
00259         for(mapping_t::const_iterator it= mapping.begin();
00260             it != mapping.end(); ++it)
00261             out << it->first << " -> " << it->second << "; ";
00262         if(!is_missing(missing_mapsto))
00263             out << "MISSING -> " << missing_mapsto << "; " << endl;
00264         if(!keep_other_as_is)
00265             out << "OTHER -> " << other_mapsto;
00266         out << "} ";
00267         break;
00268     default:
00269         inherited::newwrite(out);
00270     }
00271 }
00272 
00273 // TODO  The following are probably deprecated.
00274 
00275 void RealMapping::print(ostream& out) const
00276 { 
00277     out << "{ ";
00278     out.precision(17);
00279     for(mapping_t::const_iterator it= mapping.begin(); 
00280         it != mapping.end(); ++it)
00281         out << it->first << " -> " << it->second << "; ";
00282     if(!is_missing(missing_mapsto))
00283         out << "MISSING -> " << missing_mapsto << "; " << endl;
00284     if(!keep_other_as_is)
00285         out << "OTHER -> " << other_mapsto;
00286     out << "} ";
00287 }
00288 
00289 void RealMapping::write(ostream& out) const
00290 { 
00291     writeHeader(out,"RealMapping",0);
00292     print(out);
00293     writeFooter(out,"RealMapping");
00294 }
00295 
00296 void RealMapping::read(PStream& in)
00297 {
00298     clear();//mapping.resize(0);
00299     missing_mapsto = MISSING_VALUE;
00300     keep_other_as_is = true;
00301 
00302     in >> ws;//skipBlanks(in);
00303     char c=in.get();
00304     bool uses_headers = false;
00305     
00306     if(c=='<')
00307     {
00308         in.unget();
00309         int version = readHeader(in,"RealMapping");
00310         if(version!=0)
00311             PLERROR("In RealMapping::read reading of version #%d not implemented",version);
00312         uses_headers = true;
00313         in >> ws;//skipBlanks(in);
00314         c = in.get();
00315     }
00316 
00317     if(c!='{')
00318         PLERROR("In RealMapping::read, expected a {, found a %c",c);
00319 
00320     while((c=peekAfterSkipBlanks(in))!='}' && !in.eof())
00321     {
00322         RealRange r;
00323             
00324         if(c==';'){c=in.get();}
00325         else if(c=='[' || c==']')
00326         {
00327             r.read(in);
00328             in >> ws;//skipBlanks(in);
00329             if(in.get()!='-' || in.get()!='>')
00330                 PLERROR("Expecting -> after range specification ( range syntax example : ]100 200] -> 10 )");
00331             real val;
00332             in >> val;
00333             addMapping(r,val);
00334         }
00335         else if (isdigit(c) || c == '-' || c == '.')
00336         {
00337             real val0, val;
00338             in >> val0 >> ws;
00339             r= RealRange('[', val0, val0, ']');
00340             char c0= in.get();
00341             char c1= in.get();
00342             if(c0!='-' || c1!='>')
00343                 PLERROR("Expecting '->' in mapping (syntax example : '100 -> 10') got '%c%c' instead",c0,c1);
00344             in >> val;
00345             addMapping(r,val);      
00346         }
00347         else 
00348         {
00349             string str;
00350             in.getline(str, '-');
00351             str=upperstring(removeblanks(str));
00352             if(str=="MISSING")
00353             {
00354                 if(in.get()!='>')
00355                     PLERROR("Expecting -> after MISSING");
00356                 real val;
00357                 in >> val;
00358                 setMappingForMissing(val);
00359             }
00360             else if (str=="OTHER")
00361             {
00362                 if(in.get()!='>')
00363                     PLERROR("Expecting -> after OTHER");
00364                 real val;
00365                 in >> val;
00366                 setMappingForOther(val);
00367             }
00368             else PLERROR("Unexpected string in mapping definition : %s",str.c_str());
00369         }
00370     }
00371     in.get();
00372     
00373     if(uses_headers)
00374     {
00375         in >> ws;//skipBlanks(in);
00376         readFooter(in,"RealMapping");        
00377     }
00378 }
00379 
00380 
00381 Vec RealMapping::getCutPoints() const
00382 {
00383     Vec v(length()+1);
00384     mapping_t::const_iterator it= mapping.begin();
00385     v[0]= it->first.low;
00386     for(int i= 1; it != mapping.end(); ++it, ++i)
00387         v[i]= it->first.high;
00388     return v;
00389 }
00390 
00391 // checks that the values which the 'n' ranges are mapped to span from 0..n-1 and that these values are integers
00392 bool RealMapping::checkConsistency()
00393 {
00394     mapping_t::const_iterator it= mapping.begin();
00395     int max = 0;
00396     for(;it != mapping.end(); ++it)
00397     {
00398         if(it->second <0 || it->second - (int)it->second > 0)
00399             return false;
00400         if(max < it->second)
00401             max = (int)it->second;
00402     }
00403     TVec<int> v(max+1,0);
00404     for(it=mapping.begin();it != mapping.end(); ++it)
00405     {
00406         if(v[(int)it->second] != 0)
00407             return false;
00408         v[(int)it->second]=1;
00409     }
00410     for(int i=0;i<max;i++)
00411         if(v[i]==0)
00412             return false;
00413     return true;  
00414 }
00415 
00416 } // end of namespace PLearn
00417 
00418 
00419 /*
00420   Local Variables:
00421   mode:c++
00422   c-basic-offset:4
00423   c-file-style:"stroustrup"
00424   c-file-offsets:((innamespace . 0)(inline-open . 0))
00425   indent-tabs-mode:nil
00426   fill-column:79
00427   End:
00428 */
00429 // 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