SHOGUN  3.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MMDKernelSelectionComb.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * Written (W) 2012-2013 Heiko Strathmann
8  */
9 
13 
14 using namespace shogun;
15 
18 {
19  init();
20 }
21 
24 {
25  init();
26 }
27 
29 {
30 }
31 
32 void CMMDKernelSelectionComb::init()
33 {
34 #ifdef HAVE_LAPACK
35  SG_ADD(&m_opt_max_iterations, "opt_max_iterations", "Maximum number of "
36  "iterations for qp solver", MS_NOT_AVAILABLE);
37  SG_ADD(&m_opt_epsilon, "opt_epsilon", "Stopping criterion for qp solver",
39  SG_ADD(&m_opt_low_cut, "opt_low_cut", "Low cut value for optimization "
40  "kernel weights", MS_NOT_AVAILABLE);
41 
42  /* sensible values for optimization */
44  m_opt_epsilon=10E-15;
45  m_opt_low_cut=10E-7;
46 #endif
47 }
48 
49 #ifdef HAVE_LAPACK
50 /* no reference counting, use the static context constructor of SGMatrix */
52 
54 {
55  return &m_Q[m_Q.num_rows*i];
56 }
57 
59 void CMMDKernelSelectionComb::print_state(libqp_state_T state)
60 {
61  SG_SDEBUG("CMMDKernelSelectionComb::print_state: libqp state:"
62  " primal=%f\n", state.QP);
63 }
64 
66 {
67  /* cast is safe due to assertion in constructor */
69 
70  /* optimise for kernel weights and set them */
72  combined->set_subkernel_weights(weights);
73 
74  /* note that kernel is SG_REF'ed from getter above */
75  return combined;
76 }
77 
80 {
81  /* readability */
82  index_t num_kernels=mmds.vlen;
83 
84  /* compute sum of mmds to generate feasible point for convex program */
85  float64_t sum_mmds=0;
86  for (index_t i=0; i<mmds.vlen; ++i)
87  sum_mmds+=mmds[i];
88 
89  /* QP: 0.5*x'*Q*x + f'*x
90  * subject to
91  * mmds'*x = b
92  * LB[i] <= x[i] <= UB[i] for all i=1..n */
93  SGVector<float64_t> Q_diag(num_kernels);
94  SGVector<float64_t> f(num_kernels);
95  SGVector<float64_t> lb(num_kernels);
96  SGVector<float64_t> ub(num_kernels);
97  SGVector<float64_t> weights(num_kernels);
98 
99  /* init everything, there are two cases possible: i) at least one mmd is
100  * is positive, ii) all mmds are negative */
101  bool one_pos=false;
102  for (index_t i=0; i<mmds.vlen; ++i)
103  {
104  if (mmds[i]>0)
105  {
106  SG_DEBUG("found at least one positive MMD\n")
107  one_pos=true;
108  break;
109  }
110  }
111 
112  if (!one_pos)
113  {
114  SG_WARNING("CMMDKernelSelectionComb::solve_optimization(): all mmd "
115  "estimates are negative. This is techically possible, although "
116  "extremely rare. Consider using different kernels. "
117  "This combination will lead to a bad two-sample test. Since any"
118  "combination is bad, will now just return equally distributed "
119  "kernel weights\n");
120 
121  /* if no element is positive, we can choose arbritary weights since
122  * the results will be bad anyway */
123  weights.set_const(1.0/num_kernels);
124  }
125  else
126  {
127  SG_DEBUG("one MMD entry is positive, performing optimisation\n")
128  /* do optimisation, init vectors */
129  for (index_t i=0; i<num_kernels; ++i)
130  {
131  Q_diag[i]=m_Q(i,i);
132  f[i]=0;
133  lb[i]=0;
134  ub[i]=CMath::INFTY;
135 
136  /* initial point has to be feasible, i.e. mmds'*x = b */
137  weights[i]=1.0/sum_mmds;
138  }
139 
140  /* start libqp solver with desired parameters */
141  SG_DEBUG("starting libqp optimization\n")
142  libqp_state_T qp_exitflag=libqp_gsmo_solver(&get_Q_col, Q_diag.vector,
143  f.vector, mmds.vector,
144  one_pos ? 1 : -1,
145  lb.vector, ub.vector,
146  weights.vector, num_kernels, m_opt_max_iterations,
148 
149  SG_DEBUG("libqp returns: nIts=%d, exit_flag: %d\n", qp_exitflag.nIter,
150  qp_exitflag.exitflag);
151 
152  /* set really small entries to zero and sum up for normalization */
153  float64_t sum_weights=0;
154  for (index_t i=0; i<weights.vlen; ++i)
155  {
156  if (weights[i]<m_opt_low_cut)
157  {
158  SG_DEBUG("lowcut: weight[%i]=%f<%f setting to zero\n", i, weights[i],
159  m_opt_low_cut);
160  weights[i]=0;
161  }
162 
163  sum_weights+=weights[i];
164  }
165 
166  /* normalize (allowed since problem is scale invariant) */
167  for (index_t i=0; i<weights.vlen; ++i)
168  weights[i]/=sum_weights;
169  }
170 
171  return weights;
172 }
173 #else
175 {
176  SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
177  "installed in order to use weight optimisation for combined "
178  "kernels!\n");
179  return NULL;
180 }
181 
183 {
184  SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
185  "installed in order to use weight optimisation for combined "
186  "kernels!\n");
187  return SGVector<float64_t>();
188 }
189 
191  SGVector<float64_t> mmds)
192 {
193  SG_ERROR("CMMDKernelSelectionComb::solve_optimization(): LAPACK needs to be "
194  "installed in order to use weight optimisation for combined "
195  "kernels!\n");
196  return SGVector<float64_t>();
197 }
198 #endif

SHOGUN Machine Learning Toolbox - Documentation