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 * $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 :