ATLAS Offline Software
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
ClusterMomentsCalculator::RealSymmetricMatrixSolver Struct Reference

#include <GPUClusterInfoAndMomentsCalculatorImpl.h>

Collaboration diagram for ClusterMomentsCalculator::RealSymmetricMatrixSolver:

Public Member Functions

CUDA_HOS_DEV RealSymmetricMatrixSolver (const float a_orig, const float b_orig, const float c_orig, const float d_orig, const float e_orig, const float f_orig)
 
CUDA_HOS_DEV void get_eigenvalues (float &e_1, float &e_2, float &e_3) const
 Calculate shifted and scaled eigenvalues of the matrix, in ascending value. More...
 
CUDA_HOS_DEV void extract_one (const float eigenvalue, float(&res)[3], float(&representative)[3]) const
 
CUDA_HOS_DEV void get_eigenvectors (float(&res)[3][3], const float e_1, const float e_2, const float e_3, const float epsilon=s_typical_epsilon) const
 Calculate the eigenvectors of the matrix, using the (possibly unscaled) eigenvalues e_1, e_2, e_3 (in ascending order of magnitude) and epsilon to guard against undefined cases. More...
 
CUDA_HOS_DEV void get_solution (float(&eigenvalues)[3], float(&eigenvectors)[3][3], bool rescale_and_reshift_values=true, const float epsilon=s_typical_epsilon)
 Get the full eigenvalues and eigenvectors for this matrix. More...
 

Public Attributes

float a
 
float b
 
float c
 
float d
 
float e
 
float f
 
float shift
 
float scale
 

Static Public Attributes

static constexpr float s_typical_epsilon = std::numeric_limits<float>::epsilon()
 

Detailed Description

Definition at line 445 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

Constructor & Destructor Documentation

◆ RealSymmetricMatrixSolver()

CUDA_HOS_DEV ClusterMomentsCalculator::RealSymmetricMatrixSolver::RealSymmetricMatrixSolver ( const float  a_orig,
const float  b_orig,
const float  c_orig,
const float  d_orig,
const float  e_orig,
const float  f_orig 
)
inline

Definition at line 455 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

456  {
457  using namespace std;
458 
459  shift = sum_kahan_babushka_neumaier(a_orig, b_orig, c_orig) / 3.f;
460  a = a_orig - shift;
461  b = b_orig - shift;
462  c = c_orig - shift;
463  const float max_ab = max( fabsf(a), fabsf(b) );
464  const float max_cd = max( fabsf(c), fabsf(d_orig) );
465  const float max_ef = max( fabsf(e_orig), fabsf(f_orig) );
466  scale = max(max_ab, max(max_cd, max_ef) );
467  if (scale == 0.f)
468  {
469  scale = 1.f;
470  }
471  const float inv_scale = 1.0f / scale;
472  a *= inv_scale;
473  b *= inv_scale;
474  c *= inv_scale;
475  d = d_orig * inv_scale;
476  e = e_orig * inv_scale;
477  f = f_orig * inv_scale;
478  }

Member Function Documentation

◆ extract_one()

CUDA_HOS_DEV void ClusterMomentsCalculator::RealSymmetricMatrixSolver::extract_one ( const float  eigenvalue,
float(&)  res[3],
float(&)  representative[3] 
) const
inline

Definition at line 547 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

548  {
549  using namespace std;
550 
551  const float diag[3] = { a - eigenvalue,
552  b - eigenvalue,
553  c - eigenvalue
554  };
555 
556  float vec_1[3], vec_2[3];
557 
558  int max_diag = -1;
559  float max_value = -1.f;
560 
561  for (int i = 0; i < 3; ++i)
562  {
563  const float this_diag = fabsf(diag[i]);
564  if (this_diag >= max_value)
565  {
566  max_diag = i;
567  max_value = this_diag;
568  }
569  }
570 
571  if (max_diag == 0)
572  {
573  representative[0] = diag[0];
574  representative[1] = d;
575  representative[2] = f;
576 
577  vec_1[0] = d;
578  vec_1[1] = diag[1];
579  vec_1[2] = e;
580 
581  vec_2[0] = f;
582  vec_2[1] = e;
583  vec_2[2] = diag[2];
584  }
585  else if (max_diag == 1)
586  {
587  representative[0] = d;
588  representative[1] = diag[1];
589  representative[2] = e;
590 
591  vec_1[0] = f;
592  vec_1[1] = e;
593  vec_1[2] = diag[2];
594 
595  vec_2[0] = diag[0];
596  vec_2[1] = d;
597  vec_2[2] = f;
598 
599  }
600  else /*if (max_diag == 2)*/
601  {
602  representative[0] = f;
603  representative[1] = e;
604  representative[2] = diag[2];
605 
606  vec_1[0] = diag[0];
607  vec_1[1] = d;
608  vec_1[2] = f;
609 
610  vec_2[0] = d;
611  vec_2[1] = diag[1];
612  vec_2[2] = e;
613  }
614 
615  corrected_cross_product(res, representative, vec_1);
616  corrected_cross_product(vec_1, representative, vec_2);
617  //Can safely override previous value...
618 
619 #ifdef __CUDA_ARCH__
620  const float norm_1 = rnorm3df(res[0], res[1], res[2]);
621  const float norm_2 = rnorm3df(vec_1[0], vec_1[1], vec_1[2]);
622 #else
623  const float norm_1 = 1.f / hypot(res[0], res[1], res[2]);
624  const float norm_2 = 1.f / hypot(vec_1[0], vec_1[1], vec_1[2]);
625 #endif
626 
627  if (norm_1 <= norm_2)
628  //Greater magnitude -> multiply by a smaller value
629  {
630  res[0] *= norm_1;
631  res[1] *= norm_1;
632  res[2] *= norm_1;
633  }
634  else
635  {
636  res[0] = vec_1[0] * norm_2;
637  res[1] = vec_1[1] * norm_2;
638  res[2] = vec_1[2] * norm_2;
639  }
640  }

◆ get_eigenvalues()

CUDA_HOS_DEV void ClusterMomentsCalculator::RealSymmetricMatrixSolver::get_eigenvalues ( float &  e_1,
float &  e_2,
float &  e_3 
) const
inline

Calculate shifted and scaled eigenvalues of the matrix, in ascending value.

To get the actual eigenvalues, you should multiply by scale and then add shift.

Definition at line 483 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

484  {
485  using namespace std;
486 
487  const float ab = a * b;
488  const float corr_ab = fmaf(a, b, -ab);
489  const float dd = d * d;
490  const float corr_dd = fmaf(d, d, -dd);
491  const float ac = a * c;
492  const float corr_ac = fmaf(a, c, -ac);
493  const float ff = f * f;
494  const float corr_ff = fmaf(f, f, -ff);
495  const float bc = b * c;
496  const float corr_bc = fmaf(b, c, -bc);
497  const float ee = e * e;
498  const float corr_ee = fmaf(e, e, -ee);
499 
500  const float c_0 = fmaf(2 * d, f * e,
503  //Consider using some other strategy to select the best pairs
504  //to minimize error here?
505 
506  const float c_1 = sum_kahan_babushka_neumaier(ab, -dd, ac, -ff, bc, -ee, corr_ab, -corr_dd, corr_ac, -corr_ff, corr_bc, corr_ee);
507 
508  const float c_2 = sum_kahan_babushka_neumaier(a, b, c);
509 
510  constexpr float inv_3 = 1.f / 3.f;
511 
512  const float c_2_over_3 = c_2 * inv_3;
513 
514  const float a_over_3 = max(fma(c_2, c_2_over_3, -c_1) * inv_3, 0.f);
515 
516  const float half_b = 0.5f * (fma(c_2_over_3, fma(2.f * c_2_over_3, c_2_over_3, -c_1), c_0));
517 
518  const float q = max(product_sum_cornea_harrison_tang(a_over_3, a_over_3 * a_over_3, -half_b, half_b), 0.f);
519 
520  //None of what we are doing here is the best choice.
521  //We would need to perform a proper, formal, numerical analysis
522  //to figure out all possible errors and so on.
523 
524  const float rho = sqrtf(a_over_3);
525 
526 #ifdef __CUDA_ARCH__
527  const float theta = atan2f(1.0f, rsqrtf(q) * half_b) * inv_3;
528 #else
529  const float theta = atan2f(sqrtf(q), half_b) * inv_3;
530 #endif
531 
532 #ifdef __CUDA_ARCH__
533  float sin_theta, cos_theta;
534  sincosf(theta, &sin_theta, &cos_theta);
535 #else
536  const float sin_theta = sinf(theta);
537  const float cos_theta = cosf(theta);
538 #endif
539 
540  const float sqrt_3 = sqrtf(3.f);
541 
542  e_1 = fma(-rho, fma( sqrt_3, sin_theta, cos_theta), c_2_over_3);
543  e_2 = fma(-rho, fma(-sqrt_3, sin_theta, cos_theta), c_2_over_3);
544  e_3 = fma( rho, 2.0f * cos_theta, c_2_over_3);
545  }

◆ get_eigenvectors()

CUDA_HOS_DEV void ClusterMomentsCalculator::RealSymmetricMatrixSolver::get_eigenvectors ( float(&)  res[3][3],
const float  e_1,
const float  e_2,
const float  e_3,
const float  epsilon = s_typical_epsilon 
) const
inline

Calculate the eigenvectors of the matrix, using the (possibly unscaled) eigenvalues e_1, e_2, e_3 (in ascending order of magnitude) and epsilon to guard against undefined cases.

Definition at line 647 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

648  {
649  using namespace std;
650 
651  if (e_3 - e_1 <= epsilon)
652  {
653  res[0][0] = 1.f;
654  res[0][1] = 0.f;
655  res[0][2] = 0.f;
656 
657  res[1][0] = 0.f;
658  res[1][1] = 1.f;
659  res[1][2] = 0.f;
660 
661  res[2][0] = 0.f;
662  res[2][1] = 0.f;
663  res[2][2] = 1.f;
664  }
665  else
666  {
667  const float d_0 = e_3 - e_2;
668  const float d_1 = e_2 - e_1;
669 
670  const float d_min = min(d_0, d_1);
671  const float d_max = max(d_0, d_1);
672 
673  int k, j;
674  float first_e, second_e;
675 
676  if (d_0 > d_1)
677  {
678  k = 2;
679  j = 0;
680 
681  first_e = e_3;
682  second_e = e_1;
683  }
684  else
685  {
686  k = 0;
687  j = 2;
688 
689  first_e = e_1;
690  second_e = e_3;
691  }
692 
693  extract_one(first_e, res[k], res[j]);
694 #if USE_ORIGINAL_EIGEN
695  if (d_min <= 2 * epsilon * d1)
696  {
697 #ifdef __CUDA_ARCH__
698  const float base_norm = rnorm3df(res[j][0], res[j][1], res[j][2]);
699 #else
700  const float base_norm = 1.f / hypot(res[j][0], res[j][1], res[j][2]);
701 #endif
702  const float extra_factor = 1.f - corrected_dot_product(res[k], res[j]);
703 
704  const float norm = base_norm / extra_factor;
705 
706  res[j][0] *= norm;
707  res[j][1] *= norm;
708  res[j][2] *= norm;
709  }
710 #else
711  if (d_min <= 2 * epsilon * d_max)
712  //Eigen has d0 <= 2 * eps <= d1, but d0 is overwritten while d1 isn't...
713  {
714  //Eigen speaks about ortho-normalization
715  //but does eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l))*eivecs.col(l)
716  //which... does not ortho-normalize anything.
717 
718  const float prod = corrected_dot_product(res[k], res[j]);
719 
720  res[j][0] -= res[k][0] * prod;
721  res[j][1] -= res[k][1] * prod;
722  res[j][2] -= res[k][2] * prod;
723 
724 #ifdef __CUDA_ARCH__
725  const float norm = rnorm3df(res[j][0], res[j][1], res[j][2]);
726 #else
727  const float norm = 1.f / hypot(res[j][0], res[j][1], res[j][2]);
728 #endif
729  res[j][0] *= norm;
730  res[j][1] *= norm;
731  res[j][2] *= norm;
732  }
733 #endif
734  else
735  {
736  float extra_vector[3];
737 
738  extract_one(second_e, res[j], extra_vector);
739  }
740 
741  corrected_cross_product(res[1], res[2], res[0]);
742 
743 #ifdef __CUDA_ARCH__
744  const float norm = rnorm3df(res[1][0], res[1][1], res[1][2]);
745 #else
746  const float norm = 1.f / hypot(res[1][0], res[1][1], res[1][2]);
747 #endif
748 
749  res[1][0] *= norm;
750  res[1][1] *= norm;
751  res[1][2] *= norm;
752  }
753  }

◆ get_solution()

CUDA_HOS_DEV void ClusterMomentsCalculator::RealSymmetricMatrixSolver::get_solution ( float(&)  eigenvalues[3],
float(&)  eigenvectors[3][3],
bool  rescale_and_reshift_values = true,
const float  epsilon = s_typical_epsilon 
)
inline

Get the full eigenvalues and eigenvectors for this matrix.

If rescale_and_reshift_values is true, the eigenvalues are scaled and shifted back to their proper value, given the original matrix.

Definition at line 759 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

760  {
761  get_eigenvalues(eigenvalues[0], eigenvalues[1], eigenvalues[2]);
762  get_eigenvectors(eigenvectors, eigenvalues[0], eigenvalues[1], eigenvalues[2], epsilon);
763 
764  if (rescale_and_reshift_values)
765  {
766  eigenvalues[0] = fmaf(eigenvalues[0], scale, shift);
767  eigenvalues[1] = fmaf(eigenvalues[1], scale, shift);
768  eigenvalues[2] = fmaf(eigenvalues[2], scale, shift);
769  }
770  }

Member Data Documentation

◆ a

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::a

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ b

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::b

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ c

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::c

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ d

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::d

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ e

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::e

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ f

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::f

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ s_typical_epsilon

constexpr float ClusterMomentsCalculator::RealSymmetricMatrixSolver::s_typical_epsilon = std::numeric_limits<float>::epsilon()
staticconstexpr

Definition at line 642 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ scale

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::scale

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.

◆ shift

float ClusterMomentsCalculator::RealSymmetricMatrixSolver::shift

Definition at line 448 of file GPUClusterInfoAndMomentsCalculatorImpl.h.


The documentation for this struct was generated from the following file:
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:75
ClusterMomentsCalculator::RealSymmetricMatrixSolver::a
float a
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
dq_defect_virtual_defect_validation.d1
d1
Definition: dq_defect_virtual_defect_validation.py:79
ClusterMomentsCalculator::corrected_cross_product
CUDA_HOS_DEV void corrected_cross_product(float(&res)[3], const float a1, const float a2, const float a3, const float b1, const float b2, const float b3)
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:93
ClusterMomentsCalculator::RealSymmetricMatrixSolver::extract_one
CUDA_HOS_DEV void extract_one(const float eigenvalue, float(&res)[3], float(&representative)[3]) const
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:547
ClusterMomentsCalculator::RealSymmetricMatrixSolver::e
float e
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
ClusterMomentsCalculator::product_sum_cornea_harrison_tang
CUDA_HOS_DEV float product_sum_cornea_harrison_tang(const float a, const float b, const float c, const float d)
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:54
lumiFormat.i
int i
Definition: lumiFormat.py:85
D3PDSizeSummary.ff
ff
Definition: D3PDSizeSummary.py:305
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
ClusterMomentsCalculator::corrected_dot_product
CUDA_HOS_DEV float corrected_dot_product(const float a_1, const float a_2, const float a_3, const float b_1, const float b_2, const float b_3)
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:69
ClusterMomentsCalculator::RealSymmetricMatrixSolver::f
float f
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
ClusterMomentsCalculator::sum_kahan_babushka_neumaier
CUDA_HOS_DEV float sum_kahan_babushka_neumaier(const Floats &... fs)
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:40
ClusterMomentsCalculator::RealSymmetricMatrixSolver::b
float b
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
ClusterMomentsCalculator::RealSymmetricMatrixSolver::get_eigenvectors
CUDA_HOS_DEV void get_eigenvectors(float(&res)[3][3], const float e_1, const float e_2, const float e_3, const float epsilon=s_typical_epsilon) const
Calculate the eigenvectors of the matrix, using the (possibly unscaled) eigenvalues e_1,...
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:647
ClusterMomentsCalculator::RealSymmetricMatrixSolver::get_eigenvalues
CUDA_HOS_DEV void get_eigenvalues(float &e_1, float &e_2, float &e_3) const
Calculate shifted and scaled eigenvalues of the matrix, in ascending value.
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:483
ClusterMomentsCalculator::RealSymmetricMatrixSolver::shift
float shift
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
ClusterMomentsCalculator::RealSymmetricMatrixSolver::scale
float scale
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
extractSporadic.q
list q
Definition: extractSporadic.py:97
ClusterMomentsCalculator::RealSymmetricMatrixSolver::c
float c
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
ClusterMomentsCalculator::RealSymmetricMatrixSolver::d
float d
Definition: GPUClusterInfoAndMomentsCalculatorImpl.h:448
fitman.rho
rho
Definition: fitman.py:532
fitman.k
k
Definition: fitman.py:528