WeightedSumKernel.h
Go to the documentation of this file.
1 //===========================================================================
2 /*!
3  *
4  *
5  * \brief Weighted sum of m_base kernels.
6  *
7  *
8  *
9  * \author T.Glasmachers, O. Krause, M. Tuma
10  * \date 2010, 2011
11  *
12  *
13  * \par Copyright 1995-2015 Shark Development Team
14  *
15  * <BR><HR>
16  * This file is part of Shark.
17  * <http://image.diku.dk/shark/>
18  *
19  * Shark is free software: you can redistribute it and/or modify
20  * it under the terms of the GNU Lesser General Public License as published
21  * by the Free Software Foundation, either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * Shark is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU Lesser General Public License for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public License
30  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
33 //===========================================================================
34 
35 #ifndef SHARK_MODELS_KERNELS_WEIGHTED_SUM_KERNEL_H
36 #define SHARK_MODELS_KERNELS_WEIGHTED_SUM_KERNEL_H
37 
38 
40 
41 #include <boost/utility/enable_if.hpp>
42 namespace shark {
43 
44 
45 /// \brief Weighted sum of kernel functions
46 ///
47 /// For a set of positive definite kernels \f$ k_1, \dots, k_n \f$
48 /// with positive coeffitients \f$ w_1, \dots, w_n \f$ the sum
49 /// \f[ \tilde k(x_1, x_2) := \sum_{i=1}^{n} w_i \cdot k_i(x_1, x_2) \f]
50 /// is again a positive definite kernel function.
51 /// Internally, the weights are represented as
52 /// \f$ w_i = \exp(\xi_i) \f$
53 /// to allow for unconstrained optimization.
54 ///
55 /// This variant of the weighted sum kernel eleminates one redundant
56 /// degree of freedom by fixing the first kernel weight to 1.0.
57 ///
58 /// The result of the kernel evaluation is devided by the sum of the
59 /// kernel weights, so that in total, this amounts to fixing the sum
60 /// of the of the weights to one.
61 ///
62 template<class InputType=RealVector>
63 class WeightedSumKernel : public AbstractKernelFunction<InputType>
64 {
65 private:
67 
68  struct InternalState: public State{
69  RealMatrix result;
70  std::vector<RealMatrix> kernelResults;
71  std::vector<boost::shared_ptr<State> > kernelStates;
72 
73  InternalState(std::size_t numSubKernels)
74  :kernelResults(numSubKernels),kernelStates(numSubKernels){}
75 
76  void resize(std::size_t sizeX1, std::size_t sizeX2){
77  result.resize(sizeX1, sizeX2);
78  for(std::size_t i = 0; i != kernelResults.size(); ++i){
79  kernelResults[i].resize(sizeX1, sizeX2);
80  }
81  }
82  };
83 public:
87 
89  SHARK_CHECK( base.size() > 0, "[WeightedSumKernel::WeightedSumKernel] There should be at least one sub-kernel.");
90 
91  m_base.resize( base.size() );
92  m_numParameters = m_base.size()-1;
93 
94  for (std::size_t i=0; i != m_base.size() ; i++) {
95  SHARK_ASSERT( base[i] != NULL );
96  m_base[i].kernel = base[i];
97  m_base[i].weight = 1.0;
98  m_base[i].adaptive = false;
99  }
100  m_weightsum = m_base.size();
101 
102  // set m_base class features
103  bool hasFirstParameterDerivative = true;
104  for ( unsigned int i=0; i<m_base.size(); i++ ){
105  if ( !m_base[i].kernel->hasFirstParameterDerivative() ) {
106  hasFirstParameterDerivative = false;
107  break;
108  }
109  }
110  bool hasFirstInputDerivative = true;
111  for ( unsigned int i=0; i<m_base.size(); i++ ){
112  if ( !m_base[i].kernel->hasFirstInputDerivative() ) {
113  hasFirstInputDerivative = false;
114  break;
115  }
116  }
117 
118  if ( hasFirstParameterDerivative )
120 
121  if ( hasFirstInputDerivative )
123  }
124 
125  /// \brief From INameable: return the class name.
126  std::string name() const
127  { return "WeightedSumKernel"; }
128 
129  /// Check whether m_base kernel index is adaptive.
130  bool isAdaptive( std::size_t index ) const {
131  return m_base[index].adaptive;
132  }
133  /// Set adaptivity of m_base kernel index.
134  void setAdaptive( std::size_t index, bool b = true ) {
135  m_base[index].adaptive = b;
137  }
138  /// Set adaptivity of all m_base kernels.
139  void setAdaptiveAll( bool b = true ) {
140  for (std::size_t i=0; i!= m_base.size(); i++)
141  m_base[i].adaptive = b;
143  }
144 
145  /// Get the weight of a kernel
146  double weight(std::size_t index){
147  RANGE_CHECK(index < m_base.size());
148  return m_base[index].weight;
149  }
150 
151  /// return the parameter vector. The first N-1 entries are the (log-encoded) kernel
152  /// weights, the sub-kernel's parameters are stacked behind each other after that.
153  RealVector parameterVector() const {
154  std::size_t num = numberOfParameters();
155  RealVector ret(num);
156 
157  std::size_t index = 0;
158  for (; index != m_base.size()-1; index++){
159  ret(index) = std::log(m_base[index+1].weight);
160 
161  }
162  for (std::size_t i=0; i != m_base.size(); i++){
163  if (m_base[i].adaptive){
164  std::size_t n = m_base[i].kernel->numberOfParameters();
165  subrange(ret,index,index+n) = m_base[i].kernel->parameterVector();
166  index += n;
167  }
168  }
169  return ret;
170  }
171 
172  ///\brief creates the internal state of the kernel
173  boost::shared_ptr<State> createState()const{
174  InternalState* state = new InternalState(m_base.size());
175  for(std::size_t i = 0; i != m_base.size(); ++i){
176  state->kernelStates[i]=m_base[i].kernel->createState();
177  }
178  return boost::shared_ptr<State>(state);
179  }
180 
181  /// set the parameter vector. The first N-1 entries are the (log-encoded) kernel
182  /// weights, the sub-kernel's parameters are stacked behind each other after that.
183  void setParameterVector(RealVector const& newParameters) {
184  SIZE_CHECK(newParameters.size() == numberOfParameters());
185 
186  m_weightsum = 1.0;
187  std::size_t index = 0;
188  for (; index != m_base.size()-1; index++){
189  double w = newParameters(index);
190  m_base[index+1].weight = std::exp(w);
191  m_weightsum += m_base[index+1].weight;
192 
193  }
194  for (std::size_t i=0; i != m_base.size(); i++){
195  if (m_base[i].adaptive){
196  std::size_t n = m_base[i].kernel->numberOfParameters();
197  m_base[i].kernel->setParameterVector(subrange(newParameters,index,index+n));
198  index += n;
199  }
200  }
201  }
202 
203  std::size_t numberOfParameters() const {
204  return m_numParameters;
205  }
206 
207  /// Evaluate the weighted sum kernel (according to the following equation:)
208  /// \f$ k(x, y) = \frac{\sum_i \exp(w_i) k_i(x, y)}{sum_i exp(w_i)} \f$
209  double eval(ConstInputReference x1, ConstInputReference x2) const{
210  double numerator = 0.0;
211  for (std::size_t i=0; i != m_base.size(); i++){
212  double result = m_base[i].kernel->eval(x1, x2);
213  numerator += m_base[i].weight*result;
214  }
215  return numerator / m_weightsum;
216  }
217 
218  /// Evaluate the kernel according to the equation:
219  /// \f$ k(x, y) = \frac{\sum_i \exp(w_i) k_i(x, y)}{sum_i exp(w_i)} \f$
220  /// for two batches of inputs.
221  void eval(ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix& result) const{
222  std::size_t sizeX1=shark::size(batchX1);
223  std::size_t sizeX2=shark::size(batchX2);
224  ensure_size(result,sizeX1,sizeX2);
225  result.clear();
226 
227  RealMatrix kernelResult(sizeX1,sizeX2);
228  for (std::size_t i = 0; i != m_base.size(); i++){
229  m_base[i].kernel->eval(batchX1, batchX2,kernelResult);
230  result += m_base[i].weight*kernelResult;
231  }
232  result /= m_weightsum;
233  }
234 
235  /// Evaluate the kernel according to the equation:
236  /// \f$ k(x, y) = \frac{\sum_i \exp(w_i) k_i(x, y)}{sum_i exp(w_i)} \f$
237  /// for two batches of inputs.
238  /// (see the documentation of numberOfIntermediateValues for the workings of the intermediates)
239  void eval(ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix& result, State& state) const{
240  std::size_t sizeX1=shark::size(batchX1);
241  std::size_t sizeX2=shark::size(batchX2);
242  ensure_size(result,sizeX1,sizeX2);
243  result.clear();
244 
245  InternalState& s = state.toState<InternalState>();
246  s.resize(sizeX1,sizeX2);
247 
248  for (std::size_t i=0; i != m_base.size(); i++){
249  m_base[i].kernel->eval(batchX1,batchX2,s.kernelResults[i],*s.kernelStates[i]);
250  result += m_base[i].weight*s.kernelResults[i];
251  }
252  //store summed result
253  s.result=result;
254  result /= m_weightsum;
255  }
256 
258  ConstBatchInputReference batchX1,
259  ConstBatchInputReference batchX2,
260  RealMatrix const& coefficients,
261  State const& state,
262  RealVector& gradient
263  ) const{
264  ensure_size(gradient,numberOfParameters());
265 
266  std::size_t numKernels = m_base.size(); //how far the loop goes;
267 
268  InternalState const& s = state.toState<InternalState>();
269 
270  double sumSquared = sqr(m_weightsum); //denominator
271 
272  //first the derivative with respect to the (log-encoded) weight parameter
273  //the first weight is not a parameter and does not need a gradient.
274  //[Theoretically, we wouldn't need to store its result .]
275  //calculate the weighted sum over all results
276  double numeratorSum = sum(coefficients * s.result);
277  for (std::size_t i = 1; i != numKernels; i++) {
278  //calculate the weighted sum over all results of this kernel
279  double summedK=sum(coefficients * s.kernelResults[i]);
280  gradient(i-1) = m_base[i].weight * (summedK * m_weightsum - numeratorSum) / sumSquared;
281  }
282 
283  std::size_t gradPos = numKernels-1; //starting position of subkerel gradient
284  RealVector kernelGrad;
285  for (std::size_t i=0; i != numKernels; i++) {
286  if (isAdaptive(i)){
287  double coeff = m_base[i].weight / m_weightsum;
288  m_base[i].kernel->weightedParameterDerivative(batchX1,batchX2,coefficients,*s.kernelStates[i],kernelGrad);
289  std::size_t n = kernelGrad.size();
290  noalias(subrange(gradient,gradPos,gradPos+n)) = coeff * kernelGrad;
291  gradPos += n;
292  }
293  }
294  }
295 
296  /// Input derivative, calculated according to the equation:
297  /// <br/>
298  /// \f$ \frac{\partial k(x, y)}{\partial x}
299  /// \frac{\sum_i \exp(w_i) \frac{\partial k_i(x, y)}{\partial x}}
300  /// {\sum_i exp(w_i)} \f$
301  /// and summed up over all of the second batch
303  ConstBatchInputReference batchX1,
304  ConstBatchInputReference batchX2,
305  RealMatrix const& coefficientsX2,
306  State const& state,
307  BatchInputType& gradient
308  ) const{
309  SIZE_CHECK(coefficientsX2.size1() == shark::size(batchX1));
310  SIZE_CHECK(coefficientsX2.size2() == shark::size(batchX2));
311  weightedInputDerivativeImpl<BatchInputType>(batchX1,batchX2,coefficientsX2,state,gradient);
312  }
313 
314  void read(InArchive& ar){
315  for(std::size_t i = 0;i != m_base.size(); ++i ){
316  ar >> m_base[i].weight;
317  ar >> m_base[i].adaptive;
318  ar >> *(m_base[i].kernel);
319  }
320  ar >> m_weightsum;
321  ar >> m_numParameters;
322  }
323  void write(OutArchive& ar) const{
324  for(std::size_t i=0;i!= m_base.size();++i){
325  ar << m_base[i].weight;
326  ar << m_base[i].adaptive;
327  ar << const_cast<AbstractKernelFunction<InputType> const&>(*(m_base[i].kernel));
328  }
329  ar << m_weightsum;
330  ar << m_numParameters;
331  }
332 
333 protected:
334  /// structure describing a single m_base kernel
335  struct tBase
336  {
337  AbstractKernelFunction<InputType>* kernel; ///< pointer to the m_base kernel object
338  double weight; ///< weight in the linear combination
339  bool adaptive; ///< whether the parameters of the kernel are part of the WeightedSumKernel's parameter vector?
340  };
341 
343  m_numParameters = m_base.size()-1;
344  for (std::size_t i=0; i != m_base.size(); i++)
345  if (m_base[i].adaptive)
346  m_numParameters += m_base[i].kernel->numberOfParameters();
347  }
348 
349  //we need to choose the correct implementation at compile time to ensure, that in the case, InputType
350  //does not implement the needed operations, the implementation is replaced by a safe default which throws an exception
351  //for this, we use enable_if/disable_if. The method is called with BatchInputType as template argument.
352  //real implementation first.
353  template <class T>
355  ConstBatchInputReference batchX1,
356  ConstBatchInputReference batchX2,
357  RealMatrix const& coefficientsX2,
358  State const& state,
359  BatchInputType& gradient,
360  typename boost::enable_if<boost::is_same<T,RealMatrix > >::type* dummy = 0
361  )const{
362  std::size_t numKernels = m_base.size(); //how far the loop goes;
363  InternalState const& s = state.toState<InternalState>();
364 
365 
366  //initialize gradient with the first kernel
367  m_base[0].kernel->weightedInputDerivative(batchX1, batchX2, coefficientsX2, *s.kernelStates[0], gradient);
368  gradient *= m_base[0].weight / m_weightsum;
369  BatchInputType kernelGrad;
370  for (std::size_t i=1; i != numKernels; i++){
371  m_base[i].kernel->weightedInputDerivative(batchX1, batchX2, coefficientsX2, *s.kernelStates[i], kernelGrad);
372  double coeff = m_base[i].weight / m_weightsum;
373  gradient += coeff * kernelGrad;
374  }
375  }
376  template <class T>
378  ConstBatchInputReference batchX1,
379  ConstBatchInputReference batchX2,
380  RealMatrix const& coefficientsX2,
381  State const& state,
382  BatchInputType& gradient,
383  typename boost::disable_if<boost::is_same<T,RealMatrix > >::type* dummy = 0
384  )const{
385  throw SHARKEXCEPTION("[WeightedSumKernel::weightdInputDerivative] The used BatchInputType is no Vector");
386  }
387 
388  std::vector<tBase> m_base; ///< collection of m_base kernels
389  double m_weightsum; ///< sum of all weights
390  std::size_t m_numParameters; ///< total number of parameters
391 };
392 
395 
396 
397 
398 
399 //~ /// \brief Weighted sum of kernel functions
400 //~ ///
401 //~ /// For a set of positive definite kernels \f$ k_1, \dots, k_n \f$
402 //~ /// with positive coeffitients \f$ w_1, \dots, w_n \f$ the sum
403 //~ /// \f[ \tilde k(x_1, x_2) := \sum_{i=1}^{n} w_i \cdot k_i(x_1, x_2) \f]
404 //~ /// is again a positive definite kernel function.
405 //~ /// Internally, the weights are represented as
406 //~ /// \f$ w_i = \exp(\xi_i) \f$
407 //~ /// to allow for unconstrained optimization.
408 //~ ///
409 //~ /// This variant of the weighted sum kernel allows weights for all member
410 //~ /// kernels, whereas the simple #WeightedSumKernel fixes the first weight
411 //~ /// to 1.0, thus eliminating one redundant degree of freedom.
412 //~ ///
413 //~ /// The result of the kernel evaluation is devided by the sum of the
414 //~ /// kernel weights, so that in total, this amounts to fixing the sum
415 //~ /// of the of the weights to one.
416 //~ ///
417 //~ template<class InputType=RealVector>
418 //~ class FullyWeightedSumKernel : public AbstractKernelFunction<InputType>
419 //~ {
420 //~ public:
421  //~ typedef typename VectorMatrixTraits<InputType>::SuperType InputSuperVectorType;
422 //~ private:
423  //~ typedef AbstractKernelFunction<InputType> Base;
424 //~ public:
425  //~ FullyWeightedSumKernel(const std::vector<AbstractKernelFunction<InputType>* >& base){
426  //~ std::size_t kernels = base.size();
427  //~ SHARK_CHECK( kernels > 0, "[FullyWeightedSumKernel::FullyWeightedSumKernel] There should be at least one sub-kernel.");
428  //~ m_base.resize(kernels);
429  //~ for (std::size_t i=0; i != kernels ; i++){
430  //~ SHARK_ASSERT( base[i] != NULL );
431  //~ m_base[i].kernel = base[i];
432  //~ m_base[i].weight = 1.0;
433  //~ m_base[i].adaptive = false;
434  //~ }
435  //~ m_weightsum = kernels;
436  //~ bool tmp = true;
437  //~ for ( unsigned int i=0; i<kernels; i++ ) if ( !m_base[i].kernel->hasFirstParameterDerivative() ) { tmp = false; break; }
438  //~ if ( tmp ) this->m_features|=Base::HAS_FIRST_PARAMETER_DERIVATIVE;
439  //~ tmp = true;
440  //~ for ( unsigned int i=0; i<kernels; i++ ) if ( !m_base[i].kernel->hasFirstInputDerivative() ) { tmp = false; break; }
441  //~ if ( tmp ) this->m_features|=Base::HAS_FIRST_INPUT_DERIVATIVE;
442  //~ }
443 //~ /// Check whether m_base kernel index is adaptive.
444 //~ bool isAdaptive(std::size_t index) const
445 //~ { return m_base[index].adaptive; }
446 //~ /// Set adaptivity of m_base kernel index.
447 //~ void setAdaptive(std::size_t index, bool b = true)
448 //~ { m_base[index].adaptive = b; }
449 //~ /// Set adaptivity of all m_base kernels.
450 //~ void setAdaptiveAll(bool b = true){
451 //~ for (std::size_t i=0; i!= m_base.size(); i++)
452 //~ m_base[i].adaptive = b;
453 //~ }
454 
455 //~ RealVector parameterVector() const{
456 //~ std::size_t num = numberOfParameters();
457 //~ std::size_t index = m_base.size();
458 //~ RealVector ret(num);
459 //~ for (std::size_t i=0; i!= m_base.size(); i++){
460 //~ ret(i) = std::log(m_base[i].weight);
461 //~ if (m_base[i].adaptive){
462 //~ std::size_t n = m_base[i].kernel->numberOfParameters();
463 //~ subrange(ret,index,index+n) = m_base[i].kernel->parameterVector();
464 //~ index += n;
465 //~ }
466 //~ }
467 //~ return ret;
468 //~ }
469 
470 //~ void setParameterVector(RealVector const& newParameters){
471 //~ SIZE_CHECK(newParameters.size() == numberOfParameters());
472 //~ std::size_t index = m_base.size();
473 //~ m_weightsum = 0.0;
474 //~ for (std::size_t i=0; i != m_base.size(); i++){
475 //~ double w = newParameters(i);
476 //~ m_weightsum += std::exp(w);
477 //~ m_base[i].weight = std::exp(w);
478 //~ if (m_base[i].adaptive){
479 //~ std::size_t n = m_base[i].kernel->numberOfParameters();
480 // m_base[i].kernel->setParameterVector(RealVector(subrange(newParameters,index,index+n)));
481 //~ index += n;
482 //~ }
483 //~ }
484 //~ }
485  //~ std::size_t numberOfParameters() const{
486  //~ std::size_t num = m_base.size();
487  //~ for (std::size_t i=0; i != m_base.size(); i++)
488  //~ if (m_base[i].adaptive)
489  //~ num += m_base[i].kernel->numberOfParameters();
490  //~ return num;
491  //~ }
492 
493  //~ std::size_t numberOfIntermediateValues(InputType const& x1, InputType const& x2)const{
494  //~ std::size_t num = m_base.size()+1;
495  //~ for (std::size_t i=0; i != m_base.size(); i++){
496  //~ num += m_base[i].kernel->numberOfIntermediateValues(x1,x2);
497  //~ }
498  //~ return num;
499  //~ }
500 
501  //~ /// \f$ k(x, y) = \frac{\sum_i \exp(w_i) k_i(x, y)}{sum_i exp(w_i)} \f$
502  //~ double eval(InputType const& x1, InputType const& x2) const{
503  //~ SIZE_CHECK(x1.size() == x2.size());
504  //~ double numerator = 0.0;
505  //~ for (std::size_t i=0; i != m_base.size(); i++){
506  //~ double result = m_base[i].kernel->eval(x1, x2);
507  //~ numerator += m_base[i].weight*result;
508  //~ }
509  //~ return numerator / m_weightsum;
510  //~ }
511 //~ /// \f$ k(x, y) = \frac{\sum_i \exp(w_i) k_i(x, y)}{sum_i exp(w_i)} \f$
512 //~ double eval(ConstInputReference x1, ConstInputReference x2, Intermediate& intermediate) const{
513 //~ SIZE_CHECK(x1.size() == x2.size());
514 //~ intermediate.resize(numberOfIntermediateValues(x1,x2));
515 //~ double numerator = 0.0;
516 //~ std::size_t currentIntermediate = 1;
517 //~ for (std::size_t i=0; i != m_base.size(); i++){
518 //~ std::size_t endIntermediate = currentIntermediate+1+m_base[i].kernel->numberOfIntermediateValues(x1,x2);
519 //~ Intermediate curIntermediate(intermediate,currentIntermediate+1,endIntermediate);
520 //~ double result = m_base[i].kernel->eval(x1, x2,curIntermediate);
521 //~ numerator += m_base[i].weight*result;
522 //~ intermediate[currentIntermediate]=result;
523 //~ currentIntermediate=endIntermediate;
524 //~ }
525 //~ intermediate[0]=numerator;
526 //~ return numerator / m_weightsum;
527 //~ }
528 
529 //~ /// Weight parameter derivative:
530 //~ /// <br/>
531 //~ /// \f$ \frac{\partial k(x, y)}{\partial w_j} =
532 //~ /// \frac{\exp(w_j) \left( k_j(x, y) \left[ \sum_i \exp(w_i) \right] - \left[ \sum_i \exp(w_i) k_i(x, y) \right] \right)}
533 //~ /// {\left[ \sum_i \exp(w_i) \right]^2} \f$
534 //~ /// <br/>
535 //~ /// Adaptive kernel paramater derivative:
536 //~ /// <br/>
537 //~ /// \f$ \frac{\partial k(x, y)}{\partial p}
538 //~ /// \frac{\exp(w_j) \frac{\partial k_j(x, y)}{\partial p}}
539 //~ /// {\sum_i \exp(w_i)} \f$,
540 //~ /// where p is a parameter of the j-th kernel.
541 //~ void parameterDerivative(ConstInputReference x1, const InputReference x2, Intermediate const& intermediate, RealVector& gradient) const{
542 //~ SIZE_CHECK(x1.size() == x2.size());
543 //~ SIZE_CHECK(intermediate.size() == numberOfIntermediateValues(x1,x2));
544 //~ gradient.resize(numberOfParameters());
545 //~ std::size_t ic = m_base.size();
546 //~ std::size_t index = ic;
547 //~ RealVector kernelGrad;
548 //~ double sumSquared = sqr(m_weightsum);
549 //~ std::size_t currentIntermediate = 1;
550 //~ double numerator = intermediate[0];
551 //~ for (std::size_t i=0; i<ic; i++) {
552 //~ std::size_t endIntermediate = currentIntermediate+1+m_base[i].kernel->numberOfIntermediateValues(x1,x2);
553 //~ double result = intermediate[currentIntermediate];
554 //~ gradient(i) = m_base[i].weight * (result * m_weightsum - numerator) / sumSquared;
555 //~ if (m_base[i].adaptive){
556 //~ Intermediate curIntermediate(intermediate,currentIntermediate+1,endIntermediate);
557 //~ double coeff = m_base[i].weight / m_weightsum;
558 //~ size_t n = m_base[i].kernel->numberOfParameters();
559 //~ m_base[i].kernel->parameterDerivative(x1,x2,curIntermediate,kernelGrad);
560 // noalias(subrange(gradient,index,index+n)) = coeff * kernelGrad;
561 //~ index += n;
562 //~ }
563 //~ currentIntermediate = endIntermediate;
564 //~ }
565 //~ }
566 
567 //~ /// Input derivative:
568 //~ /// <br/>
569 //~ /// \f$ \frac{\partial k(x, y)}{\partial x}
570 //~ /// \frac{\sum_i \exp(w_i) \frac{\partial k_i(x, y)}{\partial x}}
571 //~ /// {\sum_i exp(w_i)} \f$
572 //~ void inputDerivative(ConstInputReference x1, const InputReference x2, Intermediate const& intermediate, InputSuperVectorType& gradient) const{
573 //~ SIZE_CHECK(x1.size() == x2.size());
574 //~ gradient.resize(x1.size());
575 //~ gradient.clear();
576 //~ std::size_t ic = m_base.size();
577 //~ InputSuperVectorType kernelGrad;
578 //~ std::size_t currentIntermediate = 1;
579 //~ for (std::size_t i=0; i<ic; i++){
580 //~ std::size_t endIntermediate = currentIntermediate+1+m_base[i].kernel->numberOfIntermediateValues(x1,x2);
581 //~ Intermediate curIntermediate(intermediate,currentIntermediate+1,endIntermediate);
582 //~ m_base[i].kernel->inputDerivative(x1, x2, curIntermediate, kernelGrad);
583 //~ noalias(gradient) += (m_base[i].weight / m_weightsum) * kernelGrad;
584 //~ currentIntermediate=endIntermediate;
585 //~ }
586 //~ }
587 
588 //~ void read(InArchive& ar){
589 //~ ar >> m_weightsum;
590 //~ for(std::size_t i=0;i!= m_base.size();++i){
591 //~ ar >> m_base[i].weight;
592 //~ ar >> m_base[i].adaptive;
593 //~ ar >> *(m_base[i].kernel);
594 //~ }
595 //~ }
596 //~ void write(OutArchive& ar) const{
597 //~ ar << m_weightsum;
598 //~ for(std::size_t i=0;i!= m_base.size();++i){
599 //~ ar << m_base[i].weight;
600 //~ ar << m_base[i].adaptive;
601 //~ ar << *(m_base[i].kernel);
602 //~ }
603 //~ }
604 
605 //protected:
606 //~ /// structure describing a single m_base kernel
607 //~ struct tBase
608 //~ {
609 //~ AbstractKernelFunction<InputType>* kernel; ///< pointer to the m_base kernel object
610 //~ double weight; ///< weight in the linear combination
611 //~ bool adaptive; ///< whether the parameters of the kernel are part of the FullyWeightedSumKernel's parameter vector?
612 //~ };
613 
614 //~ std::vector<tBase> m_base; ///< collection of m_base kernels
615 //~ double m_weightsum; ///< sum of all weights
616 //};
617 
618 //typedef FullyWeightedSumKernel<> DenseFullyWeightedSumKernel;
619 //typedef FullyWeightedSumKernel<CompressedRealVector> CompressedFullyWeightedSumKernel;
620 
621 
622 }
623 #endif