GenericKernel.h
Go to the documentation of this file.
1 // (C) Copyright Renaud Detry 2007-2015.
2 // Distributed under the GNU General Public License and under the
3 // BSD 3-Clause License (See accompanying file LICENSE.txt).
4 
5 /** @file */
6 
7 #ifndef NUKLEI_GENERIC_KERNEL_H
8 #define NUKLEI_GENERIC_KERNEL_H
9 
10 #include <nuklei/Definitions.h>
11 #include <nuklei/LinearAlgebra.h>
12 
13 namespace nuklei {
14 
15 
16  // ****************************************** //
17  // Selectors
18  // ****************************************** //
19 
20  namespace groupS
21  {
22  struct r3 { typedef Vector3 element_t; };
23  struct so3 { typedef Quaternion element_t; };
24  struct s2 { typedef Vector3 element_t; };
25  struct s2p { typedef Vector3 element_t; };
26  }
27 
28  // Use fast function implementations (e.g. FastACos)
29  namespace func_implS
30  {
31  struct approx {};
32  struct exact {};
33  }
34 
35  namespace shapeS
36  {
37  struct box {};
38  struct triangle {};
39  struct gauss {};
40  }
41 
42  // Use squared distances, to avoid to sqrt then ^2
43  namespace squaredS
44  {
45  struct yes {};
46  struct no {};
47  }
48 
49  // Kernel integrates to 1 or kernel max == 1
50  namespace value_scaleS
51  {
52  struct normalized {};
53  struct max1 {};
54  }
55 
56  // Use intrinsic width (cf. Watson/VMF), or a dist-proportional width
57  namespace h_scaleS
58  {
59  struct intrinsic {};
60  struct dist {};
61  }
62 
63  // ****************************************** //
64  // Metric Definition
65  // ****************************************** //
66 
67  template
68  <
69  class Group,
70  class FunctionImpl = func_implS::approx,
71  class Squared = squaredS::no
72  >
73  struct dist {};
74 
75  template<class FunctionImpl>
76  struct dist<groupS::r3, FunctionImpl, squaredS::no>
77  {
78  static coord_t d(const Vector3 &v1, const Vector3 &v2)
79  {
80  return (v1-v2).Length();
81  }
82  };
83 
84  template<class FunctionImpl>
85  struct dist<groupS::r3, FunctionImpl, squaredS::yes>
86  {
87  static coord_t d(const Vector3 &v1, const Vector3 &v2)
88  {
89  return (v1-v2).SquaredLength();
90  }
91  };
92 
93  template<>
94  struct dist<groupS::so3, func_implS::exact, squaredS::no>
95  {
96  static coord_t d(const Quaternion &q1, const Quaternion &q2)
97  {
98  coord_t productAbs = std::fabs(q1.Dot(q2));
99  return 2*ACos( productAbs );
100  }
101  };
102 
103  template<>
104  struct dist<groupS::so3, func_implS::approx, squaredS::no>
105  {
106  static coord_t d(const Quaternion &q1, const Quaternion &q2)
107  {
108  coord_t productAbs = std::fabs(q1.Dot(q2));
109  return 2*FastACos(productAbs);
110  }
111  };
112 
113  template<>
114  struct dist<groupS::s2, func_implS::exact, squaredS::no>
115  {
116  static coord_t d(const Vector3 &v1, const Vector3 &v2)
117  {
118  coord_t product = v1.Dot(v2);
119  return ACos(product);
120  }
121  };
122 
123  template<>
124  struct dist<groupS::s2, func_implS::approx, squaredS::no>
125  {
126  static coord_t d(const Vector3 &v1, const Vector3 &v2)
127  {
128  coord_t product = v1.Dot(v2);
129  return FastACos(product);
130  }
131  };
132 
133  template<>
134  struct dist<groupS::s2p, func_implS::exact, squaredS::no>
135  {
136  static coord_t d(const Vector3 &v1, const Vector3 &v2)
137  {
138  coord_t product = std::fabs(v1.Dot(v2));
139  return ACos(product);
140  }
141  };
142 
143  template<>
144  struct dist<groupS::s2p, func_implS::approx, squaredS::no>
145  {
146  static coord_t d(const Vector3 &v1, const Vector3 &v2)
147  {
148  coord_t product = std::fabs(v1.Dot(v2));
149  return FastACos(product);
150  }
151  };
152 
153  // ****************************************** //
154  // Random Elements
155  // ****************************************** //
156 
157  template<class Group>
158  struct random_element {};
159 
160  template<>
161  struct random_element<groupS::so3>
162  {
163  static Quaternion r()
164  {
165  return Random::uniformQuaternion();
166  }
167  };
168 
169  template<>
170  struct random_element<groupS::s2>
171  {
172  static Vector3 r()
173  {
175  }
176  };
177 
178  template<>
179  struct random_element<groupS::s2p>
180  {
181  static Vector3 r()
182  {
184  }
185  };
186 
187  // ****************************************** //
188  // Kernel Shapes
189  // ****************************************** //
190 
191  template<class Shape, class FunctionImpl, class Squared = squaredS::no>
192  struct shape_function {};
193 
194  template<class FunctionImpl>
195  struct shape_function<shapeS::box, FunctionImpl, squaredS::no>
196  {
197  static coord_t s(const coord_t h, const coord_t d)
198  {
199  if (std::fabs(d) > h) return 0;
200  else return 1;
201  }
202  static coord_t cut_point(const coord_t h)
203  {
204  return std::fabs(h);
205  }
206  };
207 
208  template<class FunctionImpl>
209  struct shape_function<shapeS::triangle, FunctionImpl, squaredS::no>
210  {
211  static coord_t s(const coord_t h, const coord_t d)
212  {
213  coord_t abs_d = std::fabs(d);
214  if (abs_d > gauss_equiv_spread*h) return 0;
215  else return 1 - abs_d/(gauss_equiv_spread*h);
216  }
217  static coord_t cut_point(const coord_t h)
218  {
219  return gauss_equiv_spread*std::fabs(h);
220  }
221 
222  static const coord_t gauss_equiv_spread;
223  };
224 
225  template<class FunctionImpl>
226  const coord_t shape_function
227  <
229  FunctionImpl,
231  >::gauss_equiv_spread = 2;
232 
233  template<class FunctionImpl>
234  struct shape_function<shapeS::triangle, FunctionImpl, squaredS::yes>
235  {
236  static coord_t s(const coord_t h, const coord_t d)
237  {
238  coord_t abs_d = std::fabs(d);
239  if (abs_d > gauss_equiv_spread*h*gauss_equiv_spread*h) return 0;
240  else return 1 - std::sqrt(abs_d)/(gauss_equiv_spread*h);
241  }
242  static coord_t cut_point(const coord_t h)
243  {
244  return gauss_equiv_spread*std::fabs(h);
245  }
246 
247  static const coord_t gauss_equiv_spread;
248  };
249 
250  template<class FunctionImpl>
251  const coord_t shape_function
252  <
254  FunctionImpl,
256  >::gauss_equiv_spread = 2;
257 
258  template<>
260  {
261  static coord_t s(const coord_t h, const coord_t d)
262  {
263  return std::exp( - d*d / (2*h*h) );
264  }
265  static coord_t cut_point(const coord_t h)
266  {
267  return std::numeric_limits<coord_t>::infinity();
268  }
269  };
270 
271  template<>
273  {
274  static coord_t s(const coord_t h, const coord_t d)
275  {
276  return FastNegExp( d*d / (2*h*h) );
277  }
278  static coord_t cut_point(const coord_t h)
279  {
280  return std::numeric_limits<coord_t>::infinity();
281  }
282  };
283 
284 
285  // ****************************************** //
286  // Kernels
287  // ****************************************** //
288 
289  template
290  <
291  class Group,
292  class Shape = shapeS::triangle,
293  class FunctionImpl = func_implS::approx
294  >
296  {
297  typedef Group group_t;
298  typedef FunctionImpl function_impl_t;
299 
302 
303  template<class T>
304  static coord_t eval(const T &mean, const coord_t h, const T &p)
305  {
306  return shape_function_t::s(h, dist_t::d(mean, p));
307  }
308 
309  static coord_t cut_point(const coord_t h)
310  {
311  return shape_function_t::cut_point(h);
312  }
313  };
314 
315  template<class FunctionImpl>
317  <groupS::r3, shapeS::triangle, FunctionImpl>
318  {
319  typedef groupS::r3 group_t;
320  typedef FunctionImpl function_impl_t;
321 
322  typedef
325 
326  typedef
328  dist_t;
329 
330  static coord_t eval(const Vector3 &mean, const coord_t h, const Vector3 &p)
331  {
332  return shape_function_t::s(h, dist_t::d(mean, p));
333  }
334 
335  static coord_t cut_point(const coord_t h)
336  {
337  return shape_function_t::cut_point(h);
338  }
339  };
340 
341  template
342  <
343  class ValueScale = value_scaleS::max1,
344  class FunctionImpl = func_implS::approx
345  >
347  {
348  typedef groupS::so3 group_t;
349  typedef FunctionImpl function_impl_t;
350 
351  static coord_t eval(const Quaternion &mean, const coord_t h,
352  const Quaternion &p)
353  {
354  return eval(mean, h, p, ValueScale(), FunctionImpl());
355  }
356 
357  static coord_t eval(const Quaternion &mean, const coord_t h,
358  const Quaternion &p,
360  {
361  coord_t arg = std::pow(mean.Dot(p), 2);
362  return std::exp( h*(arg-1) );
363  }
364 
365  static coord_t eval(const Quaternion &mean, const coord_t h,
366  const Quaternion &p,
368  {
369  coord_t arg = std::pow(mean.Dot(p), 2);
370  return FastNegExp( h*(1-arg) );
371  }
372 
373  // Overflows when h >~ 1000
374  template<class FI>
375  static coord_t eval(const Quaternion &mean, const coord_t h,
376  const Quaternion &p,
378  {
379  coord_t arg = std::pow(mean.Dot(p), 2);
380  return std::exp( h*arg ) / confluentHypergeometric1F1(.5, 2, h);
381  }
382  };
383 
384  template
385  <
386  class Group,
387  class ValueScale = value_scaleS::max1,
388  class FunctionImpl = func_implS::approx,
389  class HScale = h_scaleS::dist
390  >
392  {
393  typedef Group group_t;
394  typedef typename Group::element_t element_t;
395  typedef FunctionImpl function_impl_t;
396 
397  // Generic evaluation
398  static coord_t eval(const element_t &mean, const coord_t h,
399  const element_t &p)
400  {
401  return eval(mean, h, p, Group(), ValueScale(), FunctionImpl(), HScale());
402  }
403 
404  // Heuristic for computing h from angle_h
405  static coord_t h_from_angle_h(coord_t angle_h)
406  {
407  return h_from_angle_h(angle_h, Group());
408  }
409 
410  // Inverse heuristic
411  static coord_t angle_h_from_h(coord_t h)
412  {
413  return angle_h_from_h(h, Group());
414  }
415 
416  private:
417 
418  // Heuristic for computing h from angle_h (SO3)
419  static coord_t h_from_angle_h(coord_t angle_h, groupS::so3)
420  {
421  NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
422  return 1./( 1-std::cos(angle_h/2) );
423  }
424 
425  // Inverse heuristic (SO3)
426  static coord_t angle_h_from_h(coord_t h, groupS::so3)
427  {
428  NUKLEI_FAST_ASSERT(1 <= h);
429  return 2*FastACos(1-1./h);
430  }
431 
432  // Heuristic for computing h from angle_h (S^2_+)
433  static coord_t h_from_angle_h(coord_t angle_h, groupS::s2p)
434  {
435  NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
436  return 1./( 1-std::cos(angle_h) );
437  }
438 
439  // Inverse heuristic (S^2_+)
440  static coord_t angle_h_from_h(coord_t h, groupS::s2p)
441  {
442  NUKLEI_FAST_ASSERT(1 <= h);
443  return FastACos(1-1./h);
444  }
445 
446  // Heuristic for computing h from angle_h (S^2)
447  static coord_t h_from_angle_h(coord_t angle_h, groupS::s2)
448  {
449  NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
450  return 1./( 1-std::cos(angle_h) );
451  }
452 
453  // Inverse heuristic (S^2)
454  static coord_t angle_h_from_h(coord_t h, groupS::s2)
455  {
456  NUKLEI_FAST_ASSERT(1 <= h);
457  return FastACos(1-1./h);
458  }
459 
460  // Evaluation, dist-proportional width
461  template<class GP, class VS, class FI>
462  static coord_t eval(const element_t &mean, const coord_t h,
463  const element_t &p,
464  GP, VS, FI, h_scaleS::dist)
465  {
466  return eval(mean, h_from_angle_h(h), p,
467  GP(), VS(), FI(), h_scaleS::intrinsic());
468  }
469 
470  static coord_t dist_exponent(const element_t &mean,
471  const element_t &p,
472  groupS::so3)
473  {
474  return std::fabs(mean.Dot(p));
475  }
476 
477  static coord_t dist_exponent(const element_t &mean,
478  const element_t &p,
479  groupS::s2p)
480  {
481  return std::fabs(mean.Dot(p));
482  }
483 
484  static coord_t dist_exponent(const element_t &mean,
485  const element_t &p,
486  groupS::s2)
487  {
488  return mean.Dot(p);
489  }
490 
491  // Normalized VMF SO3 evaluation
492  template<class FI>
493  static coord_t eval(const element_t &mean, const coord_t h,
494  const element_t &p,
497  {
498  coord_t arg = dist_exponent(mean, p, groupS::so3());
499 
500  // This function should return
501  // std::exp( h*arg ) * h / (4 * M_PI * M_PI * besselI1(h));
502  // However, besselI1 quickly overflows, and it is slow.
503  // The below approximation works very well.
504 
505  // See "Clustering Documents with an Exponential-Family Approximation of
506  // the Dirichlet Compound Multinomial Distribution"
507  // http://cseweb.ucsd.edu/~elkan/edcm.pdf
508 
509  const coord_t alpha = 1+ h*h;
510  const coord_t sqrt_alpha = std::sqrt(alpha);
511  const coord_t eta = sqrt_alpha + std::log(h) - std::log(1+sqrt_alpha);
512  const coord_t minus_log_sqrt_2_pi = -0.918938533204673;
513  const coord_t log_bessel_I1_h = (minus_log_sqrt_2_pi + eta -
514  .25*std::log(alpha));
515  return std::exp( h*arg - log_bessel_I1_h ) * h / (4 * M_PI * M_PI);
516  }
517 
518  // Normalized VMF S2 evaluation
519  template<class FI>
520  static coord_t eval(const element_t &mean, const coord_t h,
521  const element_t &p,
524  {
525  coord_t arg = dist_exponent(mean, p, groupS::s2());
526  return (h / (2 * M_PI * (1-std::exp(-2*h)))) * std::exp( h*(arg-1) );
527  }
528 
529  template<class GP>
530  static coord_t eval(const element_t &mean, const coord_t h,
531  const element_t &p,
534  {
535  coord_t arg = dist_exponent(mean, p, GP());
536  return std::exp( h*(arg-1) );
537  }
538 
539  template<class GP>
540  static coord_t eval(const element_t &mean, const coord_t h,
541  const element_t &p,
544  {
545  coord_t arg = dist_exponent(mean, p, GP());
546  return FastNegExp( h*(1-arg) );
547  }
548 
549  };
550 
551  // ****************************************** //
552  // Kernel Sampling
553  // ****************************************** //
554 
555  template<class Kernel>
556  typename Kernel::group_t::element_t
557  importance_sampling_uniform_proposal(typename Kernel::group_t::element_t mean,
558  coord_t h)
559  {
560  typename Kernel::group_t::element_t q;
561  coord_t kernelMaxPoint = Kernel::eval(mean, h, mean);
562  for (;;)
563  {
565  coord_t e = Kernel::eval(mean, h, q);
566  // if e == 0, avoid drawing a random number
567  if (e == 0) continue;
568  if (kernelMaxPoint*Random::uniform() < e)
569  break;
570  }
571  return q;
572  }
573 
574  template<class Kernel>
575  typename Kernel::group_t::element_t
576  importance_sampling_similar_proposal(typename Kernel::group_t::element_t mean,
577  coord_t h_target, coord_t h_proposal)
578  {
579  typename Kernel::group_t::element_t q;
580  coord_t targetMaxPoint = Kernel::eval(mean, h_target, mean);
581  coord_t proposalMaxPoint = Kernel::eval(mean, h_proposal, mean);
582  for (;;)
583  {
584  q = importance_sampling_uniform_proposal<Kernel>(mean, h_proposal);
585  coord_t e_target = Kernel::eval(mean, h_target, q)/targetMaxPoint;
586  coord_t e_proposal = Kernel::eval(mean, h_proposal, q)/proposalMaxPoint;
587  NUKLEI_ASSERT(e_target <= e_proposal);
588  // if e_target == 0, avoid drawing a random number
589  if (e_target == 0) continue;
590  if (e_proposal*Random::uniform() < e_target)
591  break;
592  }
593  return q;
594  }
595 
596 
597  template<class Kernel> struct sampler {};
598 
599 
600  // R^3
601 
602  template<class FunctionImpl>
603  struct sampler
604  <
605  unnormalized_shape_dist_kernel<groupS::r3, shapeS::gauss, FunctionImpl>
606  >
607  {
609  <groupS::r3, shapeS::gauss, FunctionImpl> kernel_t;
610  typedef typename kernel_t::group_t group_t;
611  typedef typename kernel_t::function_impl_t function_impl_t;
612 
613  static Vector3 s(const Vector3 &mean, const coord_t h)
614  {
615  Vector3 s(mean);
616  for (int i = 0; i < 3; ++i)
617  s[i] += Random::gaussian(h);
618  return s;
619  }
620  };
621 
622  template<class Shape, class FunctionImpl>
623  struct sampler
624  <
625  unnormalized_shape_dist_kernel<groupS::r3, Shape, FunctionImpl>
626  >
627  {
629  <groupS::r3, Shape, FunctionImpl> kernel_t;
630  typedef typename kernel_t::group_t group_t;
631  typedef typename kernel_t::function_impl_t function_impl_t;
632 
633  static Vector3 s(const Vector3 &mean, const coord_t h)
634  {
635  Vector3 zero(Vector3::ZERO);
636  coord_t kernelMaxPoint = kernel_t::eval(zero, h, zero);
637  coord_t cutPoint = kernel_t::cut_point(h);
638  Vector3 r;
639  for (;;)
640  {
641  r.X() = Random::uniform(-cutPoint, cutPoint);
642  r.Y() = Random::uniform(-cutPoint, cutPoint);
643  r.Z() = Random::uniform(-cutPoint, cutPoint);
644  coord_t e = kernel_t::eval(zero, h, r);
645  // if e == 0, avoid drawing a random number
646  if (e == 0) continue;
647  if (kernelMaxPoint*Random::uniform() < e)
648  break;
649  }
650  for (int i = 0; i < 3; ++i)
651  r[i] += mean[i];
652  return r;
653  }
654  };
655 
656  // SO(3) ( S^3_+ )
657 
658  template<class Shape, class FunctionImpl>
659  struct sampler
660  <
661  unnormalized_shape_dist_kernel<groupS::so3, Shape, FunctionImpl>
662  >
663  {
665  <groupS::so3, Shape, FunctionImpl> kernel_t;
666  typedef typename kernel_t::group_t group_t;
667  typedef typename kernel_t::function_impl_t function_impl_t;
668 
669  static Quaternion s(const Quaternion &mean, const coord_t h)
670  {
671  if (h < .1) NUKLEI_WARN("S^2 IS with h=" + stringify(h) + " is slow.");
672  // The max angle between two quaternions is pi/2.
673  // Actually no, this is taken care of in the metric function
674  // h /= 2.0;
675  return importance_sampling_uniform_proposal<kernel_t>(mean, h);
676  }
677  };
678 
679  template
680  <
681  class ValueScale,
682  class FunctionImpl
683  >
684  struct sampler
685  <
686  watson_kernel<ValueScale, FunctionImpl>
687  >
688  {
690  typedef typename kernel_t::group_t group_t;
691  typedef typename kernel_t::function_impl_t function_impl_t;
692 
693  static Quaternion s(const Quaternion &mean, const coord_t h)
694  {
695  return importance_sampling_uniform_proposal<kernel_t>(mean, h);
696  }
697  };
698 
699  template
700  <
701  class Group,
702  class ValueScale,
703  class FunctionImpl,
704  class HScale
705  >
706  struct sampler
707  <
708  von_mises_fisher_kernel<Group, ValueScale, FunctionImpl, HScale>
709  >
710  {
711  typedef
713  kernel_t;
714  typedef typename kernel_t::group_t group_t;
715  typedef typename group_t::element_t element_t;
716  typedef typename kernel_t::function_impl_t function_impl_t;
717 
718  static element_t s(const element_t &mean, const coord_t h)
719  {
720  return s(mean, h, Group(), HScale());
721  }
722 
723  private:
724 
725  template<class GP>
726  static element_t s(const element_t &mean, const coord_t h,
727  GP, h_scaleS::dist)
728  {
729  return s(mean, kernel_t::h_from_angle_h(h), GP(), h_scaleS::intrinsic());
730  }
731 
732  static Quaternion s(const Quaternion &mean, const coord_t h,
734  {
735  //return importance_sampling_uniform_proposal<kernel_t>(mean, h);
736  const int d = 4;
737  const coord_t t1 = std::sqrt(4*h*h + (d-1)*(d-1));
738  const coord_t b = (-2*h+t1)/(d-1);
739  const coord_t x0 = (1-b)/(1+b);
740 
741  const coord_t m = (d-1.0)/2;
742  const coord_t c = h*x0 + (d-1) * std::log(1-x0*x0);
743  coord_t w = -1;
744  for (;;)
745  {
746  coord_t z = Random::beta(m,m);
747  w = (1-(1+b)*z)/(1-(1-b)*z);
748  coord_t t = h*w + (d-1)*std::log(1-x0*w)-c;
749  if ( ! (t < std::log( Random::uniform() )) )
750  break;
751  }
752  Vector3 v = std::sqrt(1 - w*w) * Random::uniformDirection3d();
753  Quaternion q(v.X(), v.Y(), v.Z(), w);
754  NUKLEI_FAST_DEBUG_ASSERT(std::fabs(1-q.Length()) < 1e-6);
755  Quaternion sample = (mean * Quaternion(0, 0, 0, 1).Conjugate()) * q;
756  sample.Normalize();
757  // Technically, in SO3, sample is equivalent to -sample.
758  // We randomize the sign of sample to make this equivalence explicit.
759  if (Random::uniformInt(2))
760  return sample;
761  else
762  return -sample;
763  }
764 
765  static Vector3 s(const Vector3 &mean, const coord_t h,
767  {
768  const int d = 3;
769  const coord_t t1 = std::sqrt(4*h*h + (d-1)*(d-1));
770  const coord_t b = (-2*h+t1)/(d-1);
771  const coord_t x0 = (1-b)/(1+b);
772 
773  const coord_t m = (d-1.)/2;
774  const coord_t c = h*x0 + (d-1) * std::log(1-x0*x0);
775  coord_t w = -1;
776  for (;;)
777  {
778  coord_t z = Random::beta(m,m);
779  w = (1-(1+b)*z)/(1-(1-b)*z);
780  coord_t t = h*w + (d-1)*std::log(1-x0*w)-c;
781  if ( ! (t < std::log( Random::uniform() )) )
782  break;
783  }
784  Vector2 v = std::sqrt(1 - w*w) * Random::uniformDirection2d();
785  Vector3 q(v.X(), v.Y(), w);
786  NUKLEI_FAST_DEBUG_ASSERT(std::fabs(1-q.Length()) < 1e-6);
787  Vector3 cross = Vector3::UNIT_Z.Cross(mean);
788  Quaternion rotation(1+Vector3::UNIT_Z.Dot(mean),
789  cross.X(),
790  cross.Y(),
791  cross.Z());
792  rotation.Normalize();
793  return la::normalized(rotation.Rotate(q));
794  }
795 
796  static Vector3 s(const Vector3 &mean, const coord_t h,
798  {
799  Vector3 sample = s(mean, h, groupS::s2(), h_scaleS::intrinsic());
800  // Technically, in s2p, sample is equivalent to -sample.
801  // We randomize the sign of sample to make this equivalence explicit.
802  if (Random::uniformInt(2))
803  return sample;
804  else
805  return -sample;
806  }
807  };
808 
809  // S^2
810 
811  template<class Shape, class FunctionImpl>
812  struct sampler
813  <
814  unnormalized_shape_dist_kernel<groupS::s2, Shape, FunctionImpl>
815  >
816  {
818  <groupS::s2, Shape, FunctionImpl> kernel_t;
819  typedef typename kernel_t::group_t group_t;
820  typedef typename kernel_t::function_impl_t function_impl_t;
821 
822  static Vector3 s(const Vector3 &mean, const coord_t h)
823  {
824  if (h < .1) NUKLEI_WARN("S^2 IS with h=" + stringify(h) + " is slow.");
825  return importance_sampling_uniform_proposal<kernel_t>(mean, h);
826  }
827  };
828 
829 
830  // S^2_+
831 
832  template<class Shape, class FunctionImpl>
833  struct sampler
834  <
835  unnormalized_shape_dist_kernel<groupS::s2p, Shape, FunctionImpl>
836  >
837  {
839  <groupS::s2p, Shape, FunctionImpl> kernel_t;
840  typedef typename kernel_t::group_t group_t;
841  typedef typename kernel_t::function_impl_t function_impl_t;
842 
843  static Vector3 s(const Vector3 &mean, const coord_t h)
844  {
845  if (h < .1) NUKLEI_WARN("S^2 IS with h=" + stringify(h) + " is slow.");
846  return importance_sampling_uniform_proposal<kernel_t>(mean, h);
847  }
848  };
849 
850 }
851 
852 #endif
static double beta(double a, double b)
This function returns a random variate from the beta distribution.
Definition: Random.cpp:277
Public namespace.
Definition: Color.cpp:9
Definition: GenericKernel.h:46
std::string stringify(const T &x, int precision=-1, int width=0)
Converts an object to a std::string using operator<<.
Definition: Common.h:333
Definition: GenericKernel.h:24
Definition: GenericKernel.h:23
static Vector2 uniformDirection2d()
This function returns a random direction vector in two dimensions.
Definition: Random.cpp:292
#define NUKLEI_ASSERT(expression)
Throws an Error if expression is not true.
Definition: Common.h:113
Definition: GenericKernel.h:85
static unsigned long int uniformInt(unsigned long int n)
This function returns a random integer from 0 to n-1 inclusive.
Definition: Random.cpp:195
Definition: GenericKernel.h:52
static Quaternion uniformQuaternion()
This function returns rotation uniformly distributed on .
Definition: Random.cpp:347
double coord_t
Type for point coordinates.
Definition: Definitions.h:25
Definition: GenericKernel.h:53
Definition: GenericKernel.h:32
Definition: GenericKernel.h:37
Definition: GenericKernel.h:73
Definition: GenericKernel.h:31
static double uniform()
This function returns a double precision floating point number uniformly distributed in the range .
Definition: Random.cpp:159
Definition: GenericKernel.h:22
Definition: GenericKernel.h:39
Definition: GenericKernel.h:38
Definition: GenericKernel.h:59
static Vector3 uniformDirection3d()
This function returns a random direction vector in three dimensions.
Definition: Random.cpp:320
Definition: GenericKernel.h:60
static double gaussian(double sigma)
This function returns a Gaussian random variate, with mean zero and standard deviation sigma.
Definition: Random.cpp:253
Definition: GenericKernel.h:45
Definition: GenericKernel.h:25
© Copyright 2007-2013 Renaud Detry.
Distributed under the terms of the GNU General Public License (GPL).
(See accompanying file LICENSE.txt or copy at http://www.gnu.org/copyleft/gpl.html.)
Revised Sun Sep 13 2020 19:10:06.