PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PartsDistanceKernel.cc 00004 // Copyright (C) 2008 Pascal Vincent 00005 // 00006 // Redistribution and use in source and binary forms, with or without 00007 // modification, are permitted provided that the following conditions are met: 00008 // 00009 // 1. Redistributions of source code must retain the above copyright 00010 // notice, this list of conditions and the following disclaimer. 00011 // 00012 // 2. Redistributions in binary form must reproduce the above copyright 00013 // notice, this list of conditions and the following disclaimer in the 00014 // documentation and/or other materials provided with the distribution. 00015 // 00016 // 3. The name of the authors may not be used to endorse or promote 00017 // products derived from this software without specific prior written 00018 // permission. 00019 // 00020 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00021 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00022 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00023 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00025 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00026 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00027 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00028 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 // 00031 // This file is part of the PLearn library. For more information on the PLearn 00032 // library, go to the PLearn Web site at www.plearn.org 00033 00036 /* ******************************************************* 00037 * $Id: PartsDistanceKernel.cc 7675 2007-06-29 19:50:49Z tihocan $ 00038 * This file is part of the PLearn library. 00039 ******************************************************* */ 00040 00041 #include "PartsDistanceKernel.h" 00042 00043 #include <plearn/vmat/VMat_basic_stats.h> 00044 00045 namespace PLearn { 00046 using namespace std; 00047 00048 00049 PLEARN_IMPLEMENT_OBJECT( 00050 PartsDistanceKernel, 00051 "Implements a parts distance", 00052 ""); 00053 00055 // PartsDistanceKernel // 00057 PartsDistanceKernel::PartsDistanceKernel() 00058 { 00059 partsize = 0.9; 00060 n = 2; 00061 standardize = true; 00062 min_stddev = 1e-8; 00063 epsilon = 1e-8; 00064 pow_distance = false; 00065 } 00066 00068 // declareOptions // 00070 void PartsDistanceKernel::declareOptions(OptionList& ol) 00071 { 00072 declareOption(ol, "n", &PartsDistanceKernel::n, OptionBase::buildoption, 00073 "This class implements a Ln parts distance (L2 is the default)."); 00074 00075 declareOption(ol, "pow_distance", &PartsDistanceKernel::pow_distance, OptionBase::buildoption, 00076 "If set to 1 (true), the distance computed will be elevated to power n."); 00077 00078 declareOption(ol, "standardize", &PartsDistanceKernel::standardize, OptionBase::buildoption, 00079 "If set to 1 (true), the inverse standard deviation inv_stddev will be used to scale the vector differences."); 00080 00081 declareOption(ol, "min_stddev", &PartsDistanceKernel::min_stddev, OptionBase::buildoption, 00082 "When method train computes inv_stddev, it will set it to FLT_MAX for \n" 00083 "any component for which the standard deviation is below min_stddev"); 00084 00085 declareOption(ol, "epsilon", &PartsDistanceKernel::epsilon, OptionBase::buildoption, 00086 "This is added to the absolute value of the elementwise difference between the 2 vectors.\n" 00087 "It's especially important for this to be non-zero when standardizing."); 00088 00089 declareOption(ol, "partsize", &PartsDistanceKernel::partsize, OptionBase::buildoption, 00090 "This determines the number of elements (the size of the part) that will be used to compute the distance.\n" 00091 "If >=1 it's interpreted as anabsolute number of elements. If it's <1 it's taken to mean a fraction of all the elements.\n"); 00092 00093 declareOption(ol, "inv_stddev", &PartsDistanceKernel::inv_stddev, OptionBase::learntoption, 00094 "This is computed when calling method train, and will be used when evaluating distances only if standardize is true.\n" 00095 "It crresponds to the inverse of the standard deviation of inputs in the dataset passed to train. But see also min_stddev.\n"); 00096 00097 inherited::declareOptions(ol); 00098 } 00099 00100 void PartsDistanceKernel::train(VMat data) 00101 { 00102 if(standardize) 00103 { 00104 Vec meanvec; 00105 Vec stddev; 00106 computeInputMeanAndStddev(data, meanvec, stddev, 0.0); 00107 int l = stddev.length(); 00108 inv_stddev.resize(l); 00109 for(int i=0; i<l; i++) 00110 { 00111 if(stddev[i]<min_stddev) 00112 inv_stddev[i] = FLT_MAX; 00113 else 00114 inv_stddev[i] = 1/stddev[i]; 00115 } 00116 } 00117 } 00118 00120 // evaluate // 00122 00123 real PartsDistanceKernel::evaluate(const Vec& x1, const Vec& x2) const 00124 { 00125 int l = x1.length(); 00126 if(x2.length() != l) 00127 PLERROR("vectors x1 and x2 must have the same size"); 00128 00129 if(standardize && l!=inv_stddev.length()) 00130 PLERROR("In PartsDistanceKernel::evaluate, size of vectors (%d) does not match size of inv_stddev (%d). Make sure you called train on the kernel with appropriate dataset",l,inv_stddev.length()); 00131 00132 elementdist.resize(l); 00133 00134 const real* px1 = x1.data(); 00135 const real* px2 = x2.data(); 00136 real* pelementdist = elementdist.data(); 00137 real* pinv_stddev = 0; 00138 if(standardize) 00139 pinv_stddev = inv_stddev.data(); 00140 00141 char specialn = 0; 00142 if(n==2) 00143 specialn = 2; 00144 else if(n==1) 00145 specialn = 1; 00146 00147 for(int i=0; i<l; i++) 00148 { 00149 real d; 00150 if(standardize && pinv_stddev[i]>=FLT_MAX ) 00151 d = FLT_MAX; 00152 else 00153 { 00154 d = fabs(px1[i]-px2[i])+epsilon; 00155 if(standardize) 00156 d *= pinv_stddev[i]; 00157 00158 switch(specialn) 00159 { 00160 case 2: 00161 d *= d; 00162 break; 00163 case 1: 00164 break; 00165 default: 00166 d = mypow(d,n); 00167 } 00168 } 00169 pelementdist[i] = d; 00170 } 00171 00172 int ps = (partsize>=1 ? (int)partsize :(int)(partsize*l+0.5)); 00173 if(ps<l) 00174 sortElements(elementdist); 00175 else 00176 ps = l; 00177 00178 real res = 0; 00179 00180 for(int i=0; i<ps; i++) 00181 { 00182 real d = elementdist[i]; 00183 if(d<FLT_MAX) 00184 res += d; 00185 } 00186 00187 if(!pow_distance) 00188 res = mypow(res, 1/n); 00189 00190 return res; 00191 } 00192 00193 00194 } // end of namespace PLearn 00195 00196 00197 /* 00198 Local Variables: 00199 mode:c++ 00200 c-basic-offset:4 00201 c-file-style:"stroustrup" 00202 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00203 indent-tabs-mode:nil 00204 fill-column:79 00205 End: 00206 */ 00207 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :