SHOGUN  v3.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LogitLikelihood.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) 2013 Roman Votyakov
8  */
9 
11 
12 #ifdef HAVE_EIGEN3
13 
18 
19 using namespace shogun;
20 using namespace Eigen;
21 
22 namespace shogun
23 {
24 
25 #ifndef DOXYGEN_SHOULD_SKIP_THIS
26 
28 class CNormalPDF : public CFunction
29 {
30 public:
32  CNormalPDF()
33  {
34  m_mu=0.0;
35  m_sigma=1.0;
36  }
37 
43  CNormalPDF(float64_t mu, float64_t sigma)
44  {
45  m_mu=mu;
46  m_sigma=sigma;
47  }
48 
53  void set_mu(float64_t mu) { m_mu=mu; }
54 
59  void set_sigma(float64_t sigma) { m_sigma=sigma; }
60 
67  virtual float64_t operator() (float64_t x)
68  {
69  return (1.0/(CMath::sqrt(2*CMath::PI)*m_sigma))*
70  CMath::exp(-CMath::sq(x-m_mu)/(2.0*CMath::sq(m_sigma)));
71  }
72 
73 private:
74  /* mean */
75  float64_t m_mu;
76 
77  /* standard deviation */
78  float64_t m_sigma;
79 };
80 
82 class CSigmoidFunction : public CFunction
83 {
84 public:
86  CSigmoidFunction()
87  {
88  m_a=0.0;
89  }
90 
95  CSigmoidFunction(float64_t a)
96  {
97  m_a=a;
98  }
99 
104  void set_a(float64_t a) { m_a=a; }
105 
112  virtual float64_t operator() (float64_t x)
113  {
114  return 1.0/(1.0+CMath::exp(-m_a*x));
115  }
116 
117 private:
119  float64_t m_a;
120 };
121 
123 class CProductFunction : public CFunction
124 {
125 public:
131  CProductFunction(CFunction* f, CFunction* g)
132  {
133  SG_REF(f);
134  SG_REF(g);
135  m_f=f;
136  m_g=g;
137  }
138 
139  virtual ~CProductFunction()
140  {
141  SG_UNREF(m_f);
142  SG_UNREF(m_g);
143  }
144 
151  virtual float64_t operator() (float64_t x)
152  {
153  return (*m_f)(x)*(*m_g)(x);
154  }
155 
156 private:
158  CFunction* m_f;
160  CFunction* m_g;
161 };
162 
164 class CLinearFunction : public CFunction
165 {
166 public:
168  CLinearFunction() { }
169 
170  virtual ~CLinearFunction() { }
171 
178  virtual float64_t operator() (float64_t x)
179  {
180  return x;
181  }
182 };
183 
185 class CQuadraticFunction : public CFunction
186 {
187 public:
189  CQuadraticFunction() { }
190 
191  virtual ~CQuadraticFunction() { }
192 
199  virtual float64_t operator() (float64_t x)
200  {
201  return CMath::sq(x);
202  }
203 };
204 
205 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
206 
208 {
209 }
210 
212 {
213 }
214 
216  SGVector<float64_t> mu, SGVector<float64_t> s2, const CLabels* lab) const
217 {
219  Map<VectorXd> eigen_lp(lp.vector, lp.vlen);
220 
222  Map<VectorXd> eigen_r(r.vector, r.vlen);
223 
224  // evaluate predictive mean: ymu=2*p-1
225  eigen_r=2.0*eigen_lp.array().exp()-1.0;
226 
227  return r;
228 }
229 
231  SGVector<float64_t> mu, SGVector<float64_t> s2, const CLabels* lab) const
232 {
234  Map<VectorXd> eigen_lp(lp.vector, lp.vlen);
235 
237  Map<VectorXd> eigen_r(r.vector, r.vlen);
238 
239  // evaluate predictive variance: ys2=1-(2*p-1).^2
240  eigen_r=1-(2.0*eigen_lp.array().exp()-1.0).square();
241 
242  return r;
243 }
244 
246  SGVector<float64_t> func) const
247 {
248  // check the parameters
249  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
251  "Labels must be type of CBinaryLabels\n")
252  REQUIRE(lab->get_num_labels()==func.vlen, "Number of labels must match "
253  "length of the function vector\n")
254 
255  SGVector<float64_t> y=((CBinaryLabels*)lab)->get_labels();
256  Map<VectorXd> eigen_y(y.vector, y.vlen);
257 
258  Map<VectorXd> eigen_f(func.vector, func.vlen);
259 
260  SGVector<float64_t> r(func.vlen);
261  Map<VectorXd> eigen_r(r.vector, r.vlen);
262 
263  // compute log probability: -log(1+exp(-f.*y))
264  eigen_r=-(1.0+(-eigen_y.array()*eigen_f.array()).exp()).log();
265 
266  return r;
267 }
268 
270  const CLabels* lab, SGVector<float64_t> func, index_t i) const
271 {
272  // check the parameters
273  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
275  "Labels must be type of CBinaryLabels\n")
276  REQUIRE(lab->get_num_labels()==func.vlen, "Number of labels must match "
277  "length of the function vector\n")
278  REQUIRE(i>=1 && i<=3, "Index for derivative should be 1, 2 or 3\n")
279 
280  SGVector<float64_t> y=((CBinaryLabels*)lab)->get_labels();
281  Map<VectorXd> eigen_y(y.vector, y.vlen);
282 
283  Map<VectorXd> eigen_f(func.vector, func.vlen);
284 
285  SGVector<float64_t> r(func.vlen);
286  Map<VectorXd> eigen_r(r.vector, r.vlen);
287 
288  // compute s(f)=1./(1+exp(-f))
289  VectorXd eigen_s=(VectorXd::Ones(func.vlen)).cwiseQuotient((1.0+
290  (-eigen_f).array().exp()).matrix());
291 
292  // compute derivatives of log probability wrt f
293  if (i == 1)
294  {
295  // compute the first derivative: dlp=(y+1)/2-s(f)
296  eigen_r=(eigen_y.array()+1.0)/2.0-eigen_s.array();
297  }
298  else if (i == 2)
299  {
300  // compute the second derivative: d2lp=-s(f).*(1-s(f))
301  eigen_r=-eigen_s.array()*(1.0-eigen_s.array());
302  }
303  else if (i == 3)
304  {
305  // compute the third derivative: d2lp=-s(f).*(1-s(f)).*(1-2*s(f))
306  eigen_r=-eigen_s.array()*(1.0-eigen_s.array())*(1.0-2*eigen_s.array());
307  }
308  else
309  {
310  SG_ERROR("Invalid index for derivative\n")
311  }
312 
313  return r;
314 }
315 
317  SGVector<float64_t> mu, SGVector<float64_t> s2, const CLabels* lab) const
318 {
320 
321  if (lab)
322  {
323  REQUIRE((mu.vlen==s2.vlen) && (mu.vlen==lab->get_num_labels()),
324  "Length of the vector of means (%d), length of the vector of "
325  "variances (%d) and number of labels (%d) should be the same\n",
326  mu.vlen, s2.vlen, lab->get_num_labels())
328  "Labels must be type of CBinaryLabels\n")
329 
330  y=((CBinaryLabels*)lab)->get_labels();
331  }
332  else
333  {
334  REQUIRE(mu.vlen==s2.vlen, "Length of the vector of means (%d) and "
335  "length of the vector of variances (%d) should be the same\n",
336  mu.vlen, s2.vlen)
337 
339  y.set_const(1.0);
340  }
341 
342  // create an object of normal pdf function
343  CNormalPDF* f=new CNormalPDF();
344 
345  // create an object of sigmoid function
346  CSigmoidFunction* g=new CSigmoidFunction();
347 
348  // create an object of product of sigmoid and normal pdf functions
349  CProductFunction* h=new CProductFunction(f, g);
350  SG_REF(h);
351 
352  // compute probabilities using numerical integration
354 
355  for (index_t i=0; i<mu.vlen; i++)
356  {
357  // set normal pdf parameters
358  f->set_mu(mu[i]);
359  f->set_sigma(CMath::sqrt(s2[i]));
360 
361  // set sigmoid parameters
362  g->set_a(y[i]);
363 
364  // evaluate integral on (-inf, inf)
367  }
368 
369  SG_UNREF(h);
370 
371  r.log();
372 
373  return r;
374 }
375 
377  SGVector<float64_t> s2, const CLabels *lab, index_t i) const
378 {
379  // check the parameters
380  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
381  REQUIRE((mu.vlen==s2.vlen) && (mu.vlen==lab->get_num_labels()),
382  "Length of the vector of means (%d), length of the vector of "
383  "variances (%d) and number of labels (%d) should be the same\n",
384  mu.vlen, s2.vlen, lab->get_num_labels())
385  REQUIRE(i>=0 && i<=mu.vlen, "Index (%d) out of bounds!\n", i)
387  "Labels must be type of CBinaryLabels\n")
388 
389  SGVector<float64_t> y=((CBinaryLabels*)lab)->get_labels();
390 
391  // create an object of f(x)=N(x|mu,sigma^2)
392  CNormalPDF* f=new CNormalPDF(mu[i], CMath::sqrt(s2[i]));
393 
394  // create an object of g(x)=sigmoid(x)
395  CSigmoidFunction* g=new CSigmoidFunction(y[i]);
396 
397  // create an object of h(x)=N(x|mu,sigma^2)*sigmoid(x)
398  CProductFunction* h=new CProductFunction(f, g);
399 
400  // create an object of l(x)=x
401  CLinearFunction* l=new CLinearFunction();
402 
403  // create an object of k(x)=x*N(x|mu,sigma^2)*sigmoid(x)
404  CProductFunction* k=new CProductFunction(l, h);
405  SG_REF(k);
406 
407  // compute Z = \int N(x|mu,sigma)*sigmoid(a*x) dx
410 
411  // compute 1st moment: E[x] = Z^-1 * \int x*N(x|mu,sigma)*sigmoid(a*x)dx
414 
415  SG_UNREF(k);
416 
417  return Ex;
418 }
419 
421  SGVector<float64_t> s2, const CLabels *lab, index_t i) const
422 {
423  // check the parameters
424  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
425  REQUIRE((mu.vlen==s2.vlen) && (mu.vlen==lab->get_num_labels()),
426  "Length of the vector of means (%d), length of the vector of "
427  "variances (%d) and number of labels (%d) should be the same\n",
428  mu.vlen, s2.vlen, lab->get_num_labels())
429  REQUIRE(i>=0 && i<=mu.vlen, "Index (%d) out of bounds!\n", i)
431  "Labels must be type of CBinaryLabels\n")
432 
433  SGVector<float64_t> y=((CBinaryLabels*)lab)->get_labels();
434 
435  // create an object of f(x)=N(x|mu,sigma^2)
436  CNormalPDF* f=new CNormalPDF(mu[i], CMath::sqrt(s2[i]));
437 
438  // create an object of g(x)=sigmoid(a*x)
439  CSigmoidFunction* g=new CSigmoidFunction(y[i]);
440 
441  // create an object of h(x)=N(x|mu,sigma^2)*sigmoid(a*x)
442  CProductFunction* h=new CProductFunction(f, g);
443 
444  // create an object of l(x)=x
445  CLinearFunction* l=new CLinearFunction();
446 
447  // create an object of k(x)=x*N(x|mu,sigma^2)*sigmoid(a*x)
448  CProductFunction* k=new CProductFunction(l, h);
449  SG_REF(k);
450 
451  // create an object of q(x)=x^2
452  CQuadraticFunction* q=new CQuadraticFunction();
453 
454  // create an object of p(x)=x^2*N(x|mu,sigma^2)*sigmoid(x)
455  CProductFunction* p=new CProductFunction(q, h);
456  SG_REF(p);
457 
458  // compute Z = \int N(x|mu,sigma)*sigmoid(a*x) dx
461 
462  // compute 1st moment: E[x] = Z^-1 * \int x*N(x|mu,sigma)*sigmoid(a*x)dx
465 
466  // compute E[x^2] = Z^-1 * \int x^2*N(x|mu,sigma)*sigmoid(a*x)dx
469 
470  SG_UNREF(k);
471  SG_UNREF(p);
472 
473  // return 2nd moment: Var[x]=E[x^2]-E[x]^2
474  return Ex2-CMath::sq(Ex);;
475 }
476 }
477 
478 #endif /* HAVE_EIGEN3 */

SHOGUN Machine Learning Toolbox - Documentation