PLearn 0.1
DiffCommand.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // DiffCommand.cc
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 #include "DiffCommand.h"
00045 #include <plearn/base/Object.h>
00046 #include <plearn/base/PLearnDiff.h>
00047 #include <plearn/io/PyPLearnScript.h>
00048 #include <plearn/math/TVec_decl.h>
00049 
00050 namespace PLearn {
00051 using namespace std;
00052 
00054 PLearnCommandRegistry DiffCommand::reg_(new DiffCommand);
00055 
00056 DiffCommand::DiffCommand():
00057     PLearnCommand("diff",
00058         "Compare PLearn objects",
00059         prgname() + " diff <reference.psave> <other_1.psave> ..."
00060                     "<other_n.psave> "
00061                     "[ <tolerance> [ <relative_tolerance> ] ]\n"
00062         "The files with the objects' specifications are given in argument,\n"
00063         "the first one being the reference object.\n"
00064         "If 'tolerance' is specified, it is taken as the absolute tolerance\n"
00065         "(when two numbers are less than 1), and as the relative tolerance\n"
00066         "(when one of two numbers is more than 1) unless "
00067         "'relative_tolerance'\n"
00068         "is also specified.\n"
00069     )
00070 {}
00071 
00073 void DiffCommand::run(const vector<string>& args)
00074 {
00075     const char* error_msg = "In DiffCommand::run - You need to provide at "
00076                             "least two file names";
00077     if (args.size() < 2) PLERROR(error_msg);
00078     // Parse arguments.
00079     // First check whether some tolerance is given.
00080     real absolute_tolerance = ABSOLUTE_TOLERANCE;
00081     real relative_tolerance = RELATIVE_TOLERANCE;
00082     real tol;
00083     string tol_str = args[args.size() - 1];
00084     int to_ignore = 0;  // Number of arguments to ignore at end of 'args'.
00085     if (pl_isnumber(tol_str, &tol)) {
00086         relative_tolerance = tol;
00087         tol_str = args[args.size() - 2];
00088         to_ignore++;
00089         if (pl_isnumber(tol_str, &tol)) {
00090             to_ignore++;
00091             absolute_tolerance = tol;
00092         } else
00093             absolute_tolerance = relative_tolerance;
00094     }
00095     // Then read the object specifications paths.
00096     TVec<PPath> obj_spec;
00097     int n = int(args.size()) - to_ignore;
00098     if (n < 2) PLERROR(error_msg);
00099     for (vector<string>::size_type i = 0; i<vector<string>::size_type(n); i++)
00100         obj_spec.append(args[i]);
00101     // Load objects.
00102     TVec< PP<Object> > obj;
00103     for (int i = 0; i < n; i++) {
00104         PP<Object> new_object = smartLoadObject(obj_spec[i]);
00105 
00106         if (!new_object)
00107             PLERROR("In DiffCommand::run - Unable to serialize file %s as an Object",
00108                     obj_spec[i].absolute().c_str());
00109         obj.append(new_object);
00110     }
00111     // Compare objects.
00112     PStream& out = pout;
00113     PP<Object> refer = obj[0];
00114     PP<PLearnDiff> diffs = new PLearnDiff();
00115     diffs->absolute_tolerance = absolute_tolerance;
00116     diffs->relative_tolerance = relative_tolerance;
00117     for (int i = 1; i < n; i++) {
00118         PP<Object> other = obj[i];
00119         diffs->forget();
00120         int n_diffs = diff(refer, other, diffs);
00121         if (n_diffs > 0) {
00122             out << "Reference (" << obj_spec[0] << ") and object " << i << " ("
00123                 << obj_spec[i] << ") differ:" << endl;
00124             diffs->printDiffs(out);
00125         }
00126         /*
00127           if (!diffs.empty()) {
00128           for (vector<string>::size_type j = 0; j < diffs.size(); j += 3)
00129           out << "  " << diffs[j] << " = " << diffs[j+1] << " != " << diffs[j+2] << endl;
00130           }
00131         */
00132     }
00133 }
00134 
00135 /*
00137 // newDiff //
00139 void DiffCommand::newDiff(vector<string>& diffs, const string& name,
00140 const string& val1,  const string& val2)
00141 {
00142 static TVec<string> new_diff;
00143 new_diff.resize(3);
00144 new_diff[0] = name;
00145 new_diff[1] = val1;
00146 new_diff[2] = val2;
00147 diffs.appendRow(new_diff);
00148 }
00149 */
00150 
00151 /*
00153 // diff //
00155 int DiffCommand::diff(PP<Object> refer, PP<Object> other,
00156 vector<string>& diffs)
00157 {
00158 int n_diffs = 0;
00159 OptionBase::newDiff("classname", refer->classname(),
00160 other->classname(), diffs, n_diffs);
00161 if (n_diffs > 0)
00162 return n_diffs; // We cannot compare two objects from different classes.
00163 OptionList& options = refer->getOptionList();
00164 for (OptionList::const_iterator it = options.begin(); it != options.end(); it++) {
00165 // pout << "Comparing " << (*it)->optionname() << endl;
00166 n_diffs += (*it)->isDiff(refer->getOption((*it)->optionname()),
00167 other->getOption((*it)->optionname()),
00168 diffs);
00169 }
00170 return n_diffs;
00171 }
00172 */
00173 
00174 /*
00175   bool DiffCommand::diff(PP<Object> refer, PP<Object> other, PP<OptionBase> opt,
00176   vector<string>& diffs)
00177   {
00178   string optionname = opt->optionname();
00179   string optiontype = opt->optiontype();
00180   string refer_opt = refer->getOption(optionname);
00181   string other_opt = other->getOption(optionname);
00182   // pout << "Comparing " << opt->optionname() << ":" << endl;
00183   // pout << "Refer = " << refer_opt << endl;
00184   // pout << "Other = " << other_opt << endl;
00185   return diff(refer_opt, other_opt, optionname, optiontype, diffs);
00186   // pout << "Total: " << diffs.length() << " differences" << endl;
00187   }
00188 
00189   bool DiffCommand::diff(const string& refer, const string& other, const string& name,
00190   const string& type, vector<string>& diffs)
00191   {
00192   bool is_diff;
00193   if (type == "double") {
00194   double val_refer = todouble(refer);
00195   double val_other = todouble(other);
00196   is_diff = !is_equal(val_refer, val_other);
00197   } else if (type == "float") {
00198   float val_refer = tofloat(refer);
00199   float val_other = tofloat(other);
00200   is_diff = !is_equal(val_refer, val_other);
00201   } else
00202   // Default: just compare the strings.
00203   is_diff = (refer != other);
00204   if (is_diff)
00205   newDiff(diffs, name, refer, other);
00206   return is_diff;
00207   }
00208 */
00209 
00210 } // end of namespace PLearn
00211 
00212 
00213 /*
00214   Local Variables:
00215   mode:c++
00216   c-basic-offset:4
00217   c-file-style:"stroustrup"
00218   c-file-offsets:((innamespace . 0)(inline-open . 0))
00219   indent-tabs-mode:nil
00220   fill-column:79
00221   End:
00222 */
00223 // 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