PLearn 0.1
|
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 :