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