PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // diff.h 00004 // 00005 // Copyright (C) 2005 Olivier Delalleau 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: .pyskeleton_header 544 2003-09-01 00:05:31Z plearner $ 00037 ******************************************************* */ 00038 00039 // Authors: Olivier Delalleau 00040 00044 #ifndef diff_INC 00045 #define diff_INC 00046 00047 //#include <plearn/base/Object.h> 00048 #include <plearn/base/OptionBase.h> 00049 #include <plearn/base/tostring.h> 00050 #include <plearn/io/openString.h> 00051 #include <plearn/io/PStream.h> 00052 #include <plearn/math/pl_math.h> 00053 #include <plearn/math/TVec_decl.h> 00054 #include <map> 00055 #include <string> 00056 00057 using namespace std; 00058 00059 namespace PLearn { 00060 00062 class Object; 00063 template<class ObjectType, class OptionType> class Option; 00064 //template <class T> class TVec; TODO Use this if possible. 00065 class Var; 00066 class VMat; 00067 class VMatrix; 00068 class PLearnDiff; 00069 void addDiffPrefix(PLearnDiff* diffs, const string& prefix, int n); 00070 void setSaveDiffs(PLearnDiff* diffs, bool save_diffs, 00071 bool* save_diffs_backup); 00072 int diff(PLearnDiff* diffs, 00073 const string& refer, const string& other, const string& name); 00074 real get_absolute_tolerance(PLearnDiff* diffs); 00075 real get_relative_tolerance(PLearnDiff* diffs); 00076 00077 // TODO Clean code (more comments, less duplications, maybe less 'hacky' code 00078 // too...). 00079 00081 int diff(PP<Object> refer, PP<Object> other, PLearnDiff* diffs = 0); 00082 00084 template<class ObjectType, class OptionType> 00085 int diff(const string& refer, const string& other, 00086 const Option<ObjectType, OptionType>* opt, PLearnDiff* diffs) 00087 { 00088 /* 00089 pout << "Calling basic diff with Option< ObjectType, " 00090 << opt->optiontype() << " >" << endl; 00091 */ 00092 PLASSERT( diffs ); 00093 return diff(diffs, refer, other, opt->optionname()); 00094 } 00095 00097 template<class ObjectType> 00098 int diff(const string& refer, const string& other, const Option<ObjectType, double>* opt, PLearnDiff* diffs) 00099 { 00100 double x_refer, x_other; 00101 PStream in = openString(refer, PStream::plearn_ascii); 00102 in >> x_refer; 00103 in.flush(); 00104 in = openString(other, PStream::plearn_ascii); 00105 in >> x_other; 00106 in.flush(); 00107 if (is_equal(real(x_refer), real(x_other), 1.0, 00108 get_absolute_tolerance(diffs), get_relative_tolerance(diffs))) 00109 return 0; 00110 else 00111 return diff(diffs, refer, other, opt->optionname()); 00112 } 00113 00115 template<class ObjectType> 00116 int diff(const string& refer, const string& other, const Option<ObjectType, float>* opt, PLearnDiff* diffs) 00117 { 00118 // TODO Avoid code duplication with double. 00119 float x_refer, x_other; 00120 PStream in = openString(refer, PStream::plearn_ascii); 00121 in >> x_refer; 00122 in.flush(); 00123 in = openString(other, PStream::plearn_ascii); 00124 in >> x_other; 00125 in.flush(); 00126 if (is_equal(real(x_refer), real(x_other), 1.0, 00127 get_absolute_tolerance(diffs), get_relative_tolerance(diffs))) 00128 return 0; 00129 else 00130 return diff(diffs, refer, other, opt->optionname()); 00131 } 00132 00134 template<class ObjectType, class VecElementType> 00135 int diff(const string& refer, const string& other, const Option<ObjectType, TVec<VecElementType> >* opt, PLearnDiff* diffs) 00136 { 00137 // pout << "Calling diff(..., const Option<ObjectType, TVec<T> > opt, ...)" << endl; 00138 int n_diffs = 0; 00139 TVec<VecElementType> refer_vec; 00140 TVec<VecElementType> other_vec; 00141 string option = opt->optionname(); 00142 PStream in; 00143 in = openString(refer, PStream::plearn_ascii); 00144 in >> refer_vec; 00145 in = openString(other, PStream::plearn_ascii); 00146 in >> other_vec; 00147 in.flush(); 00148 int n = refer_vec.length(); 00149 if (other_vec.length() != n) { 00150 // pout << "Not same length" << endl; 00151 // If the two vectors do not have the same size, no need to go further. 00152 n_diffs += diff(diffs, tostring(n), tostring(other_vec.length()), 00153 opt->optionname() + ".length"); 00154 } 00155 else { 00156 PP<OptionBase> option_elem = new Option<ObjectType, VecElementType> 00157 ("", 0, 0, TypeTraits<VecElementType>::name(), "", "", opt->level());//level could be anything here, I guess? -xsm 00158 string refer_i, other_i; 00159 // pout << "TVec of " << TypeTraits<VecElementType>::name() << endl; 00160 for (int i = 0; i < n; i++) { 00161 option_elem->setOptionName(opt->optionname() + "[" + tostring(i) + "]"); 00162 PStream out = openString(refer_i, PStream::plearn_ascii, "w"); 00163 out << refer_vec[i]; 00164 out.flush(); 00165 out = openString(other_i, PStream::plearn_ascii, "w"); 00166 out << other_vec[i]; 00167 out.flush(); 00168 n_diffs += option_elem->diff(refer_i, other_i, diffs); 00169 } 00170 } 00171 return n_diffs; 00172 } 00173 00175 template<class ObjectType, class MatElementType> 00176 int diff(const string& refer, const string& other, const Option<ObjectType, TMat<MatElementType> >* opt, PLearnDiff* diffs) 00177 { 00178 // pout << "Calling diff(..., const Option<ObjectType, TMat<T> > opt, ...)" << endl; 00179 TMat<MatElementType> refer_mat; 00180 TMat<MatElementType> other_mat; 00181 string option = opt->optionname(); 00182 PStream in; 00183 in = openString(refer, PStream::plearn_ascii); 00184 in >> refer_mat; 00185 in = openString(other, PStream::plearn_ascii); 00186 in >> other_mat; 00187 in.flush(); 00188 int n = refer_mat.length(); 00189 if (other_mat.length() != n) 00190 // If the two matrices do not have the same length, no need to go further. 00191 return diff(diffs, tostring(n), tostring(other_mat.length()), 00192 opt->optionname() + ".length"); 00193 int w = refer_mat.width(); 00194 if (other_mat.width() != w) 00195 // If the two matrices do not have the same width, no need to go further. 00196 return diff(diffs, tostring(w), tostring(other_mat.width()), 00197 opt->optionname() + ".width"); 00198 int n_diffs = 0; 00199 PP<OptionBase> option_elem = new Option<ObjectType, MatElementType> 00200 ("", 0, 0, TypeTraits<MatElementType>::name(), "", "", opt->level());//level could be anything here, I guess? -xsm 00201 string refer_ij, other_ij; 00202 for (int i = 0; i < n; i++) 00203 for (int j = 0; j < w; j++) { 00204 option_elem->setOptionName(opt->optionname() + "(" + tostring(i) 00205 + "," + tostring(j) + ")"); 00206 PStream out = openString(refer_ij, PStream::plearn_ascii, "w"); 00207 out << refer_mat(i,j); 00208 out.flush(); 00209 out = openString(other_ij, PStream::plearn_ascii, "w"); 00210 out << other_mat(i,j); 00211 out.flush(); 00212 n_diffs += option_elem->diff(refer_ij, other_ij, diffs); 00213 } 00214 return n_diffs; 00215 } 00216 00218 template<class ObjectType, class MapKeyType, class MapElementType> 00219 int diff(const string& refer, const string& other, const Option<ObjectType, 00220 map<MapKeyType, MapElementType> >* opt, PLearnDiff* diffs) 00221 { 00222 // pout << "Calling diff(..., const Option<ObjectType, TVec<T> > opt, ...)" << endl; 00223 int n_diffs = 0; 00224 map<MapKeyType, MapElementType> refer_map; 00225 map<MapKeyType, MapElementType> other_map; 00226 string option = opt->optionname(); 00227 PStream in; 00228 in = openString(refer, PStream::plearn_ascii); 00229 in >> refer_map; 00230 in = openString(other, PStream::plearn_ascii); 00231 in >> other_map; 00232 in.flush(); 00233 PP<OptionBase> option_elem = new Option<ObjectType, MapElementType> 00234 ("", 0, 0, TypeTraits<MapElementType>::name(), "", "", opt->level());//level could be anything here, I guess? -xsm 00235 string refer_i, other_i; 00236 typename map<MapKeyType, MapElementType>::iterator it_refer; 00237 typename map<MapKeyType, MapElementType>::iterator it_other; 00238 it_refer = refer_map.begin(); 00239 it_other = other_map.begin(); 00240 TVec<string> missing_in_refer, missing_in_other; 00241 while (it_refer != refer_map.end()) { 00242 const MapKeyType& refer_key = it_refer->first; 00243 option_elem->setOptionName(opt->optionname() + "[ " + 00244 tostring(refer_key) + " ]"); 00245 if (other_map.find(refer_key) == other_map.end()) { 00246 // 'refer_map' contains a key 'other_map' does not. 00247 PStream out = 00248 openString(refer_i, PStream::plearn_ascii, "w"); 00249 out << refer_key; 00250 out.flush(); 00251 /* 00252 refer_i = "<In map>"; 00253 other_i = "<Not in map>"; 00254 n_diffs += option_elem->diff(refer_i, other_i, diffs); 00255 */ 00256 missing_in_other.append(refer_i); 00257 } else { 00258 // Compare the two values. 00259 const MapElementType& refer_val = it_refer->second; 00260 const MapElementType& other_val = other_map[refer_key]; 00261 PStream out = 00262 openString(refer_i, PStream::plearn_ascii, "w"); 00263 out << refer_val; 00264 out.flush(); 00265 out = 00266 openString(other_i, PStream::plearn_ascii, "w"); 00267 out << other_val; 00268 out.flush(); 00269 n_diffs += option_elem->diff(refer_i, other_i, diffs); 00270 } 00271 it_refer++; 00272 } 00273 // Now look for keys in 'other_map' not present in 'refer_map'. 00274 while (it_other != other_map.end()) { 00275 const MapKeyType& other_key = it_other->first; 00276 option_elem->setOptionName(opt->optionname() + "[ " + 00277 tostring(other_key) + " ]"); 00278 if (refer_map.find(other_key) == refer_map.end()) { 00279 PStream out = 00280 openString(other_i, PStream::plearn_ascii, "w"); 00281 out << other_key; 00282 out.flush(); 00283 /* 00284 refer_i = "<Not in map>"; 00285 other_i = "<In map>"; 00286 n_diffs += option_elem->diff(refer_i, other_i, diffs); 00287 */ 00288 missing_in_refer.append(other_i); 00289 } 00290 it_other++; 00291 } 00292 /* TODO See how to compare keys properly. 00293 */ 00294 // Now deal with different keys. 00295 PP<OptionBase> option_key = new Option<ObjectType, MapKeyType> 00296 ("", 0, 0, TypeTraits<MapKeyType>::name(), "", "", opt->level());//level could be anything here, I guess? -xsm 00297 bool save_diffs_backup; 00298 setSaveDiffs(diffs, false, &save_diffs_backup); 00299 for (int i = 0; i < missing_in_other.length(); i++) { 00300 for (int j = 0; j < missing_in_refer.length(); j++) { 00301 int is_diff = 00302 option_key->diff(missing_in_other[i], missing_in_refer[j], 00303 diffs); 00304 if (is_diff == 0) { 00305 // The keys are actually the same (even if not exactly). 00306 missing_in_refer.remove(j); 00307 j = missing_in_refer.length(); // No need to go further. 00308 missing_in_other.remove(i); 00309 i--; 00310 } 00311 } 00312 } 00313 setSaveDiffs(diffs, save_diffs_backup, 0); 00314 for (int i = 0; i < missing_in_other.length(); i++) { 00315 n_diffs += diff(diffs, "<In map>", "<Not in map>", 00316 opt->optionname() + "[ " + missing_in_other[i] + " ] "); 00317 } 00318 for (int i = 0; i < missing_in_refer.length(); i++) { 00319 n_diffs += diff(diffs, "<Not in map>", "<In map>", 00320 opt->optionname() + "[ " + missing_in_refer[i] + " ] "); 00321 } 00322 00323 return n_diffs; 00324 } 00325 00329 template<class ObjectType, class PointedType> 00330 int diff(const string& refer, const string& other, const Option<ObjectType, PP<PointedType> >* opt, PLearnDiff* diffs) 00331 { 00332 // pout << "Calling diff with Option< ObjectType, " << opt->optiontype() << " >" << endl; 00333 PP<PointedType> refer_pp, other_pp; 00334 PP<Object> refer_obj, other_obj; 00335 PStream in = openString(refer, PStream::plearn_ascii); 00336 in >> refer_pp; 00337 in = openString(other, PStream::plearn_ascii); 00338 in >> other_pp; 00339 refer_obj = dynamic_cast<Object*>((PointedType*) refer_pp); 00340 if (refer_obj.isNull()) 00341 // This is actually not an object: just compare the two strings. 00342 return diff(diffs, refer, other, opt->optionname()); 00343 other_obj = dynamic_cast<Object*>((PointedType*) other_pp); 00344 PLASSERT( other_obj.isNotNull() ); 00345 int n_diffs = diff(refer_obj, other_obj, diffs); 00346 addDiffPrefix(diffs, opt->optionname() + ".", n_diffs); 00347 return n_diffs; 00348 } 00349 00350 /* 00352 template<class ObjectType, class OptionType> 00353 int diff(const string& refer, const string& other, 00354 const Option<ObjectType, OptionType>* opt, PLearnDiff* diffs, 00355 // TODO Continue here 00356 00357 const Object* ptr = 0) 00358 { 00359 pout << "Calling diff_Object with Option< ObjectType, " << opt->optiontype() << " >" << endl; 00360 PP<OptionBase> new_opt = new Option<ObjectType, PP<OptionType> > 00361 (opt->optionname(), 0, 0, "", "", ""); 00362 return new_opt->diff(refer, other, diffs); 00363 */ 00364 00365 /* 00366 PP<PointedType> refer_obj; PP<PointedType> other_obj; PStream in = 00367 openString(refer, PStream::plearn_ascii); in >> refer_obj; in = 00368 openString(other, PStream::plearn_ascii); in >> other_obj; int n_diffs = 00369 diff(static_cast<PointedType*>(refer_obj), 00370 static_cast<PointedType*>(other_obj), diffs); addDiffPrefix(diffs, 00371 opt->optionname() + ".", n_diffs); return n_diffs; 00372 return 0; 00373 */ 00374 /* 00375 } 00376 */ 00377 00378 00380 #ifndef _MSC_VER 00381 // Currently, this piece of code is problematic with Visual Studio .Net 2003: 00382 // it triggers an error when compiling certain files (e.g. RealMapping.cc) 00383 // that do not depend on VMat.h: even though it looks like in such a case this 00384 // specific diff function should not be compiled, Visual C++ does compile it, 00385 // resulting in an error about the PStream >> VMat operation not being defined. 00386 // As a workaround, this function is thus disabled with Visual Studio: this is 00387 // however not a good solution, since it means diffs performed on a VMat option 00388 // will not behave as expected, and the test PL_diff_VMat will fail. 00389 template<class ObjectType> 00390 int diff(const string& refer, const string& other, const Option<ObjectType, VMat >* opt, PLearnDiff* diffs) 00391 { 00392 return diff(refer, other, 00393 (Option<ObjectType, PP<VMatrix> >*) opt, diffs); 00394 } 00395 #endif 00396 00398 template<class ObjectType> 00399 int diff(const string& refer, const string& other, const Option<ObjectType, Var >* opt, PLearnDiff* diffs) 00400 { 00401 return diff(refer, other, 00402 (Option<ObjectType, PP<Variable> >*) opt, diffs); 00403 } 00404 00405 00407 void addDiffPrefix(const string& prefix, PLearnDiff* diffs, int n); 00408 00409 /* 00410 template<class ObjectType, class VecElementType> 00411 int diff(PP<Object> refer, PP<Object> other, const Option<ObjectType, TVec<VecElementType> >* opt, vector<string>& diffs) 00412 { 00413 string refer_str, other_str; 00414 } 00415 */ 00416 00417 00418 /* 00422 // TODO Update comment. 00423 int diff(const string& refer, const string& other, const string& name, 00424 vector<string>& diffs); 00425 */ 00426 00427 } // end of namespace PLearn 00428 00429 #endif 00430 00431 00432 /* 00433 Local Variables: 00434 mode:c++ 00435 c-basic-offset:4 00436 c-file-style:"stroustrup" 00437 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00438 indent-tabs-mode:nil 00439 fill-column:79 00440 End: 00441 */ 00442 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :