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, Rejean Ducharme and University of Montreal 00006 // Copyright (C) 2001-2002 Nicolas Chapados, Ichiro Takeuchi, Jean-Sebastien Senecal 00007 // Copyright (C) 2002 Xiangdong Wang, Christian Dorion 00008 00009 // Redistribution and use in source and binary forms, with or without 00010 // modification, are permitted provided that the following conditions are met: 00011 // 00012 // 1. Redistributions of source code must retain the above copyright 00013 // notice, this list of conditions and the following disclaimer. 00014 // 00015 // 2. Redistributions in binary form must reproduce the above copyright 00016 // notice, this list of conditions and the following disclaimer in the 00017 // documentation and/or other materials provided with the distribution. 00018 // 00019 // 3. The name of the authors may not be used to endorse or promote 00020 // products derived from this software without specific prior written 00021 // permission. 00022 // 00023 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00024 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00025 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00026 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00028 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00029 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00030 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00031 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00032 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 // 00034 // This file is part of the PLearn library. For more information on the PLearn 00035 // library, go to the PLearn Web site at www.plearn.org 00036 00037 00038 /* ******************************************************* 00039 * $Id: DistanceKernel.cc 7675 2007-06-29 19:50:49Z tihocan $ 00040 * This file is part of the PLearn library. 00041 ******************************************************* */ 00042 00043 #include "DistanceKernel.h" 00044 #include "SelectedOutputCostFunction.h" 00045 00046 namespace PLearn { 00047 using namespace std; 00048 00049 00050 PLEARN_IMPLEMENT_OBJECT( 00051 DistanceKernel, 00052 "Implements an Ln distance (defaults to L2 i.e. euclidean distance).", 00053 "Output is as follows:\n" 00054 "- If option 'pow_distance' = 1,\n" 00055 " k(x1,x2) = \\sum_i |x1[i]-x2[i]|^n\n" 00056 "- If option 'pow_distance' = 0,\n" 00057 " k(x1,x2) = (\\sum_i |x1[i]-x2[i]|^2)^(1/n)"); 00058 00060 // DistanceKernel // 00062 DistanceKernel::DistanceKernel(real the_Ln, bool pd) 00063 : n(the_Ln), 00064 optimized(false), 00065 pow_distance(pd), 00066 ignore_missing(false) 00067 {} 00068 00070 // declareOptions // 00072 void DistanceKernel::declareOptions(OptionList& ol) 00073 { 00074 00075 declareOption(ol, "n", &DistanceKernel::n, OptionBase::buildoption, 00076 "This class implements a Ln distance (L2, the default is the usual euclidean distance)."); 00077 00078 declareOption(ol, "pow_distance", &DistanceKernel::pow_distance, OptionBase::buildoption, 00079 "If set to 1, the distance computed will be elevated to power n."); 00080 00081 declareOption(ol, "optimized", &DistanceKernel::optimized, OptionBase::buildoption, 00082 "If set to 1, the evaluate_i_j method will be faster, at the cost of potential\n" 00083 "approximations in the result."); 00084 00085 declareOption(ol, "ignore_missing", &DistanceKernel::ignore_missing, OptionBase::buildoption, 00086 "If set to false, nan will be propagated.\n" 00087 "If set to true, if a value is missing in the matrix of some examples, we will ignore this value for the distance\n" 00088 "If set to true, work only if pow_distance is set to 1."); 00089 00090 inherited::declareOptions(ol); 00091 } 00092 00094 // evaluate // 00096 real DistanceKernel::evaluate(const Vec& x1, const Vec& x2) const { 00097 if (ignore_missing && !pow_distance) 00098 PLERROR("In DistanceKernel::evaluate(int i, int j) - 'ignore_missing' " 00099 "implemented only if pow_distance is set"); 00100 00101 if (pow_distance) { 00102 return powdistance(x1, x2, n, ignore_missing); 00103 } else { 00104 return dist(x1, x2, n); 00105 } 00106 } 00107 00109 // evaluate_i_j // 00111 real DistanceKernel::evaluate_i_j(int i, int j) const { 00112 static real d; 00113 if (ignore_missing) 00114 PLERROR("DistanceKernel::evaluate_i_j(int i, int j) not implemented for ignore_missing"); 00115 00116 if (optimized && fast_exact_is_equal(n, 2.0)) { 00117 if (i == j) 00118 // The case 'i == j' can cause precision issues because of the optimized 00119 // formula below. Thus we make sure we always return 0. 00120 return 0; 00121 d = squarednorms[i] + squarednorms[j] - 2 * data->dot(i, j, data_inputsize); 00122 if (d < 0) { 00123 // This can happen (especially when compiled in -opt) if the two points 00124 // are the same, and the distance should be zero. 00125 if (d < -1e-2) 00126 // That should not happen. 00127 PLERROR("In DistanceKernel::evaluate_i_j - Found a (significantly) negative distance (%f), " 00128 "i = %d, j = %d, squarednorms[i] = %f, squarednorms[j] = %f, dot = %f", 00129 d, i, j, squarednorms[i], squarednorms[j], data->dot(i, j, data_inputsize)); 00130 d = 0; 00131 } 00132 if (pow_distance) 00133 return d; 00134 else 00135 return sqrt(d); 00136 } else { 00137 return inherited::evaluate_i_j(i,j); 00138 } 00139 } 00140 00142 // setDataForKernelMatrix // 00144 void DistanceKernel::setDataForKernelMatrix(VMat the_data) 00145 { 00146 if (ignore_missing) 00147 PLWARNING("DistanceKernel::setDataForKernelMatrix(VMat the_data) not tested for ignore_missing"); 00148 00149 inherited::setDataForKernelMatrix(the_data); 00150 if (fast_exact_is_equal(n, 2.0)) { 00151 squarednorms.resize(data.length()); 00152 for(int index=0; index<data.length(); index++) { 00153 squarednorms[index] = data->dot(index, index, data_inputsize); 00154 } 00155 } 00156 } 00157 00159 // absolute_deviation // 00161 CostFunc absolute_deviation(int singleoutputindex) 00162 { 00163 if(singleoutputindex>=0) 00164 return new SelectedOutputCostFunction(new DistanceKernel(1.0),singleoutputindex); 00165 else 00166 return new DistanceKernel(1.0); 00167 } 00168 00169 } // end of namespace PLearn 00170 00171 00172 /* 00173 Local Variables: 00174 mode:c++ 00175 c-basic-offset:4 00176 c-file-style:"stroustrup" 00177 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00178 indent-tabs-mode:nil 00179 fill-column:79 00180 End: 00181 */ 00182 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :