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