PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // KroneckerBaseKernel.cc 00004 // 00005 // Copyright (C) 2007 Nicolas Chapados 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 // Authors: Nicolas Chapados 00036 00039 #include "KroneckerBaseKernel.h" 00040 #include <plearn/base/lexical_cast.h> 00041 #include <plearn/math/TMat_maths.h> 00042 00043 namespace PLearn { 00044 using namespace std; 00045 00046 PLEARN_IMPLEMENT_OBJECT( 00047 KroneckerBaseKernel, 00048 "Base class for kernels that make use of Kronecker terms", 00049 "This kernel allows the specification of product a of Kronecker delta terms\n" 00050 "when there is a match of VALUE in ONE DIMENSION. (This may be generalized\n" 00051 "in the future to allow match according to a subset of the input variables,\n" 00052 "but is not currently done for performance reasons). With these terms, the\n" 00053 "kernel function takes the form:\n" 00054 "\n" 00055 " k(x,y) = \\product_i delta_x[kr(i)],y[kr(i)]\n" 00056 "\n" 00057 "where kr(i) is the i-th element of 'kronecker_indexes' (representing an\n" 00058 "index into the input vectors) Derived classes can either integrate these\n" 00059 "terms additively (e.g. KroneckerBaseKernel) or multiplicatively\n" 00060 "(e.g. ARDBaseKernel and derived classes). Note that this class does not\n" 00061 "provide any hyperparameter associated with this product; an hyperparameter\n" 00062 "may be included by derived classes as required. (Currently, only\n" 00063 "IIDNoiseKernel needs one; in other kernels, this is absorbed by the global\n" 00064 "function noise hyperparameter)\n" 00065 "\n" 00066 "The basic idea for Kronecker terms is to selectively build in parts of a\n" 00067 "covariance function based on matches in the value of some input variables.\n" 00068 "They are useful in conjunction with a \"covariance function builder\" such as\n" 00069 "SummationKernel.\n" 00070 ); 00071 00072 00073 KroneckerBaseKernel::KroneckerBaseKernel() 00074 : m_default_value(0.) 00075 { } 00076 00077 00078 //##### declareOptions ###################################################### 00079 00080 void KroneckerBaseKernel::declareOptions(OptionList& ol) 00081 { 00082 declareOption( 00083 ol, "kronecker_indexes", &KroneckerBaseKernel::m_kronecker_indexes, 00084 OptionBase::buildoption, 00085 "Element index in the input vectors that should be subject to additional\n" 00086 "Kronecker delta terms"); 00087 00088 // Now call the parent class' declareOptions 00089 inherited::declareOptions(ol); 00090 } 00091 00092 00093 //##### build ############################################################### 00094 00095 void KroneckerBaseKernel::build() 00096 { 00097 // ### Nothing to add here, simply calls build_ 00098 inherited::build(); 00099 build_(); 00100 } 00101 00102 00103 //##### build_ ############################################################## 00104 00105 void KroneckerBaseKernel::build_() 00106 { } 00107 00108 00109 //##### evaluate ############################################################ 00110 00111 real KroneckerBaseKernel::evaluate(const Vec& x1, const Vec& x2) const 00112 { 00113 const int n = m_kronecker_indexes.size(); 00114 if (n > 0) { 00115 int* cur_index = m_kronecker_indexes.data(); 00116 for (int i=0 ; i<n ; ++i, ++cur_index) 00117 if (! fast_is_equal(x1[*cur_index], x2[*cur_index])) 00118 return 0.0; 00119 return 1.0; 00120 } 00121 return m_default_value; 00122 } 00123 00124 00125 //##### computeGramMatrix ################################################### 00126 00127 void KroneckerBaseKernel::computeGramMatrix(Mat K) const 00128 { 00129 if (!data) 00130 PLERROR("Kernel::computeGramMatrix: setDataForKernelMatrix not yet called"); 00131 if (!is_symmetric) 00132 PLERROR("Kernel::computeGramMatrix: not supported for non-symmetric kernels"); 00133 if (K.length() != data.length() || K.width() != data.length()) 00134 PLERROR("Kernel::computeGramMatrix: the argument matrix K should be\n" 00135 "of size %d x %d (currently of size %d x %d)", 00136 data.length(), data.length(), K.length(), K.width()); 00137 00138 PLASSERT( K.size() == 0 || m_data_cache.size() > 0 ); // Ensure data cached OK 00139 00140 // Prepare kronecker iteration 00141 int kronecker_num = m_kronecker_indexes.size(); 00142 int* kronecker_indexes = ( kronecker_num > 0? 00143 m_kronecker_indexes.data() : 0 ); 00144 00145 // Compute Gram Matrix 00146 int l = data->length(); 00147 int m = K.mod(); 00148 int cache_mod = m_data_cache.mod(); 00149 00150 real *data_start = &m_data_cache(0,0); 00151 real Kij = m_default_value; 00152 real *Ki, *Kji; 00153 real *xi = data_start; 00154 00155 for (int i=0 ; i<l ; ++i, xi += cache_mod) { 00156 Ki = K[i]; 00157 Kji = &K[0][i]; 00158 real *xj = data_start; 00159 00160 for (int j=0; j<=i; ++j, Kji += m, xj += cache_mod) { 00161 if (kronecker_num > 0) { 00162 real product = 1.0; 00163 int* cur_index = kronecker_indexes; 00164 00165 // Go over Kronecker terms, skipping over an eventual omitted term 00166 for (int k=0 ; k<kronecker_num ; ++k, ++cur_index) 00167 if (! fast_is_equal(xi[*cur_index], xj[*cur_index])) { 00168 product = 0.0; 00169 break; 00170 } 00171 00172 Kij = product; 00173 } 00174 *Ki++ = Kij; 00175 } 00176 } 00177 } 00178 00179 00180 //##### softplusFloor ####################################################### 00181 00182 real KroneckerBaseKernel::softplusFloor(real& value, real floor) 00183 { 00184 real sp = softplus(value); 00185 if (sp < floor) { 00186 value = pl_log(exp(floor)-1); // inverse soft-plus 00187 return floor; 00188 } 00189 return sp; 00190 } 00191 00192 00193 //##### makeDeepCopyFromShallowCopy ######################################### 00194 00195 void KroneckerBaseKernel::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00196 { 00197 inherited::makeDeepCopyFromShallowCopy(copies); 00198 deepCopyField(m_kronecker_indexes, copies); 00199 } 00200 00201 } // end of namespace PLearn 00202 00203 00204 /* 00205 Local Variables: 00206 mode:c++ 00207 c-basic-offset:4 00208 c-file-style:"stroustrup" 00209 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00210 indent-tabs-mode:nil 00211 fill-column:79 00212 End: 00213 */ 00214 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :