7 #ifndef NUKLEI_GENERIC_KERNEL_H
8 #define NUKLEI_GENERIC_KERNEL_H
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; };
50 namespace value_scaleS
75 template<
class FunctionImpl>
78 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
80 return (v1-v2).Length();
84 template<
class FunctionImpl>
87 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
89 return (v1-v2).SquaredLength();
96 static coord_t d(
const Quaternion &q1,
const Quaternion &q2)
98 coord_t productAbs = std::fabs(q1.Dot(q2));
99 return 2*ACos( productAbs );
106 static coord_t d(
const Quaternion &q1,
const Quaternion &q2)
108 coord_t productAbs = std::fabs(q1.Dot(q2));
109 return 2*FastACos(productAbs);
116 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
119 return ACos(product);
126 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
129 return FastACos(product);
136 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
138 coord_t product = std::fabs(v1.Dot(v2));
139 return ACos(product);
146 static coord_t d(
const Vector3 &v1,
const Vector3 &v2)
148 coord_t product = std::fabs(v1.Dot(v2));
149 return FastACos(product);
157 template<
class Group>
163 static Quaternion r()
191 template<
class Shape,
class FunctionImpl,
class Squared = squaredS::no>
194 template<
class FunctionImpl>
199 if (std::fabs(d) > h)
return 0;
208 template<
class FunctionImpl>
214 if (abs_d > gauss_equiv_spread*h)
return 0;
215 else return 1 - abs_d/(gauss_equiv_spread*h);
219 return gauss_equiv_spread*std::fabs(h);
222 static const coord_t gauss_equiv_spread;
225 template<
class FunctionImpl>
231 >::gauss_equiv_spread = 2;
233 template<
class FunctionImpl>
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);
244 return gauss_equiv_spread*std::fabs(h);
247 static const coord_t gauss_equiv_spread;
250 template<
class FunctionImpl>
256 >::gauss_equiv_spread = 2;
263 return std::exp( - d*d / (2*h*h) );
267 return std::numeric_limits<coord_t>::infinity();
276 return FastNegExp( d*d / (2*h*h) );
280 return std::numeric_limits<coord_t>::infinity();
297 typedef Group group_t;
298 typedef FunctionImpl function_impl_t;
306 return shape_function_t::s(h, dist_t::d(mean, p));
311 return shape_function_t::cut_point(h);
315 template<
class FunctionImpl>
320 typedef FunctionImpl function_impl_t;
330 static coord_t eval(
const Vector3 &mean,
const coord_t h,
const Vector3 &p)
332 return shape_function_t::s(h, dist_t::d(mean, p));
337 return shape_function_t::cut_point(h);
349 typedef FunctionImpl function_impl_t;
354 return eval(mean, h, p, ValueScale(), FunctionImpl());
361 coord_t arg = std::pow(mean.Dot(p), 2);
362 return std::exp( h*(arg-1) );
369 coord_t arg = std::pow(mean.Dot(p), 2);
370 return FastNegExp( h*(1-arg) );
379 coord_t arg = std::pow(mean.Dot(p), 2);
380 return std::exp( h*arg ) / confluentHypergeometric1F1(.5, 2, h);
393 typedef Group group_t;
394 typedef typename Group::element_t element_t;
395 typedef FunctionImpl function_impl_t;
401 return eval(mean, h, p, Group(), ValueScale(), FunctionImpl(), HScale());
407 return h_from_angle_h(angle_h, Group());
413 return angle_h_from_h(h, Group());
421 NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
422 return 1./( 1-std::cos(angle_h/2) );
428 NUKLEI_FAST_ASSERT(1 <= h);
429 return 2*FastACos(1-1./h);
435 NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
436 return 1./( 1-std::cos(angle_h) );
442 NUKLEI_FAST_ASSERT(1 <= h);
443 return FastACos(1-1./h);
449 NUKLEI_FAST_ASSERT(0 <= angle_h && angle_h <= M_PI);
450 return 1./( 1-std::cos(angle_h) );
456 NUKLEI_FAST_ASSERT(1 <= h);
457 return FastACos(1-1./h);
461 template<
class GP,
class VS,
class FI>
466 return eval(mean, h_from_angle_h(h), p,
470 static coord_t dist_exponent(
const element_t &mean,
474 return std::fabs(mean.Dot(p));
477 static coord_t dist_exponent(
const element_t &mean,
481 return std::fabs(mean.Dot(p));
484 static coord_t dist_exponent(
const element_t &mean,
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);
526 return (h / (2 * M_PI * (1-std::exp(-2*h)))) * std::exp( h*(arg-1) );
535 coord_t arg = dist_exponent(mean, p, GP());
536 return std::exp( h*(arg-1) );
545 coord_t arg = dist_exponent(mean, p, GP());
546 return FastNegExp( h*(1-arg) );
555 template<
class Kernel>
556 typename Kernel::group_t::element_t
557 importance_sampling_uniform_proposal(
typename Kernel::group_t::element_t mean,
560 typename Kernel::group_t::element_t q;
561 coord_t kernelMaxPoint = Kernel::eval(mean, h, mean);
565 coord_t e = Kernel::eval(mean, h, q);
567 if (e == 0)
continue;
574 template<
class Kernel>
575 typename Kernel::group_t::element_t
576 importance_sampling_similar_proposal(
typename Kernel::group_t::element_t mean,
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);
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;
589 if (e_target == 0)
continue;
602 template<
class FunctionImpl>
610 typedef typename kernel_t::group_t group_t;
611 typedef typename kernel_t::function_impl_t function_impl_t;
613 static Vector3 s(
const Vector3 &mean,
const coord_t h)
616 for (
int i = 0; i < 3; ++i)
622 template<
class Shape,
class FunctionImpl>
630 typedef typename kernel_t::group_t group_t;
631 typedef typename kernel_t::function_impl_t function_impl_t;
633 static Vector3 s(
const Vector3 &mean,
const coord_t h)
635 Vector3 zero(Vector3::ZERO);
636 coord_t kernelMaxPoint = kernel_t::eval(zero, h, zero);
637 coord_t cutPoint = kernel_t::cut_point(h);
644 coord_t e = kernel_t::eval(zero, h, r);
646 if (e == 0)
continue;
650 for (
int i = 0; i < 3; ++i)
658 template<
class Shape,
class FunctionImpl>
666 typedef typename kernel_t::group_t group_t;
667 typedef typename kernel_t::function_impl_t function_impl_t;
669 static Quaternion s(
const Quaternion &mean,
const coord_t h)
671 if (h < .1) NUKLEI_WARN(
"S^2 IS with h=" +
stringify(h) +
" is slow.");
675 return importance_sampling_uniform_proposal<kernel_t>(mean, h);
691 typedef typename kernel_t::function_impl_t function_impl_t;
693 static Quaternion s(
const Quaternion &mean,
const coord_t h)
695 return importance_sampling_uniform_proposal<kernel_t>(mean, h);
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;
718 static element_t s(
const element_t &mean,
const coord_t h)
720 return s(mean, h, Group(), HScale());
726 static element_t s(
const element_t &mean,
const coord_t h,
732 static Quaternion s(
const Quaternion &mean,
const coord_t h,
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);
742 const coord_t c = h*x0 + (d-1) * std::log(1-x0*x0);
747 w = (1-(1+b)*z)/(1-(1-b)*z);
748 coord_t t = h*w + (d-1)*std::log(1-x0*w)-c;
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;
765 static Vector3 s(
const Vector3 &mean,
const coord_t h,
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);
774 const coord_t c = h*x0 + (d-1) * std::log(1-x0*x0);
779 w = (1-(1+b)*z)/(1-(1-b)*z);
780 coord_t t = h*w + (d-1)*std::log(1-x0*w)-c;
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),
792 rotation.Normalize();
793 return la::normalized(rotation.Rotate(q));
796 static Vector3 s(
const Vector3 &mean,
const coord_t h,
811 template<
class Shape,
class FunctionImpl>
819 typedef typename kernel_t::group_t group_t;
820 typedef typename kernel_t::function_impl_t function_impl_t;
822 static Vector3 s(
const Vector3 &mean,
const coord_t h)
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);
832 template<
class Shape,
class FunctionImpl>
840 typedef typename kernel_t::group_t group_t;
841 typedef typename kernel_t::function_impl_t function_impl_t;
843 static Vector3 s(
const Vector3 &mean,
const coord_t h)
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);