/**
 * Returns the symmetry axis for the given matrix
 *
 * According to ITA, 11.2 the axis of a symmetry operation can be determined by
 * solving the Eigenvalue problem \f$Wu = u\f$ for rotations or \f$Wu = -u\f$
 * for rotoinversions. This is implemented using the general real non-symmetric
 * eigen-problem solver provided by the GSL.
 *
 * @param matrix :: Matrix of a SymmetryOperation
 * @return Axis of symmetry element.
 */
V3R SymmetryElementWithAxisGenerator::determineAxis(
    const Kernel::IntMatrix &matrix) const {
  gsl_matrix *eigenMatrix = getGSLMatrix(matrix);
  gsl_matrix *identityMatrix =
      getGSLIdentityMatrix(matrix.numRows(), matrix.numCols());

  gsl_eigen_genv_workspace *eigenWs = gsl_eigen_genv_alloc(matrix.numRows());

  gsl_vector_complex *alpha = gsl_vector_complex_alloc(3);
  gsl_vector *beta = gsl_vector_alloc(3);
  gsl_matrix_complex *eigenVectors = gsl_matrix_complex_alloc(3, 3);

  gsl_eigen_genv(eigenMatrix, identityMatrix, alpha, beta, eigenVectors,
                 eigenWs);
  gsl_eigen_genv_sort(alpha, beta, eigenVectors, GSL_EIGEN_SORT_ABS_DESC);

  double determinant = matrix.determinant();

  Kernel::V3D eigenVector;

  for (size_t i = 0; i < matrix.numCols(); ++i) {
    double eigenValue = GSL_REAL(gsl_complex_div_real(
        gsl_vector_complex_get(alpha, i), gsl_vector_get(beta, i)));

    if (fabs(eigenValue - determinant) < 1e-9) {
      for (size_t j = 0; j < matrix.numRows(); ++j) {
        double element = GSL_REAL(gsl_matrix_complex_get(eigenVectors, j, i));

        eigenVector[j] = element;
      }
    }
  }

  eigenVector *= determinant;

  double sumOfElements = eigenVector.X() + eigenVector.Y() + eigenVector.Z();

  if (sumOfElements < 0) {
    eigenVector *= -1.0;
  }

  gsl_matrix_free(eigenMatrix);
  gsl_matrix_free(identityMatrix);
  gsl_eigen_genv_free(eigenWs);
  gsl_vector_complex_free(alpha);
  gsl_vector_free(beta);
  gsl_matrix_complex_free(eigenVectors);

  double min = 1.0;
  for (size_t i = 0; i < 3; ++i) {
    double absoluteValue = fabs(eigenVector[i]);
    if (absoluteValue != 0.0 &&
        (eigenVector[i] < min && (absoluteValue - fabs(min)) < 1e-9)) {
      min = eigenVector[i];
    }
  }

  V3R axis;
  for (size_t i = 0; i < 3; ++i) {
    axis[i] = static_cast<int>(boost::math::round(eigenVector[i] / min));
  }

  return axis;
}
Exemplo n.º 2
0
Arquivo: test.c Projeto: lemahdi/mglib
void
test_eigen_gen_pencil(const gsl_matrix * A, const gsl_matrix * B,
                      size_t count, const char * desc, int test_schur,
                      test_eigen_gen_workspace *w)
{
  const size_t N = A->size1;
  size_t i;

  gsl_matrix_memcpy(w->A, A);
  gsl_matrix_memcpy(w->B, B);

  if (test_schur)
    {
      gsl_eigen_genv_QZ(w->A, w->B, w->alphav, w->betav, w->evec, w->Q, w->Z, w->genv_p);
      test_eigen_schur(A, w->A, w->Q, w->Z, count, "genv/A", desc);
      test_eigen_schur(B, w->B, w->Q, w->Z, count, "genv/B", desc);
    }
  else
    gsl_eigen_genv(w->A, w->B, w->alphav, w->betav, w->evec, w->genv_p);

  test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "unsorted");

  gsl_matrix_memcpy(w->A, A);
  gsl_matrix_memcpy(w->B, B);

  if (test_schur)
    {
      gsl_eigen_gen_params(1, 1, 0, w->gen_p);
      gsl_eigen_gen_QZ(w->A, w->B, w->alpha, w->beta, w->Q, w->Z, w->gen_p);
      test_eigen_schur(A, w->A, w->Q, w->Z, count, "gen/A", desc);
      test_eigen_schur(B, w->B, w->Q, w->Z, count, "gen/B", desc);
    }
  else
    {
      gsl_eigen_gen_params(0, 0, 0, w->gen_p);
      gsl_eigen_gen(w->A, w->B, w->alpha, w->beta, w->gen_p);
    }

  /* compute eval = alpha / beta values */
  for (i = 0; i < N; ++i)
    {
      gsl_complex z, ai;
      double bi;

      ai = gsl_vector_complex_get(w->alpha, i);
      bi = gsl_vector_get(w->beta, i);
      GSL_SET_COMPLEX(&z, GSL_REAL(ai) / bi, GSL_IMAG(ai) / bi);
      gsl_vector_complex_set(w->eval, i, z);

      ai = gsl_vector_complex_get(w->alphav, i);
      bi = gsl_vector_get(w->betav, i);
      GSL_SET_COMPLEX(&z, GSL_REAL(ai) / bi, GSL_IMAG(ai) / bi);
      gsl_vector_complex_set(w->evalv, i, z);
    }

  /* sort eval and evalv and test them */
  gsl_eigen_nonsymmv_sort(w->eval, NULL, GSL_EIGEN_SORT_ABS_ASC);
  gsl_eigen_nonsymmv_sort(w->evalv, NULL, GSL_EIGEN_SORT_ABS_ASC);
  test_eigenvalues_complex(w->evalv, w->eval, "gen", desc);

  gsl_eigen_genv_sort(w->alphav, w->betav, w->evec, GSL_EIGEN_SORT_ABS_ASC);
  test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "abs/asc");
  gsl_eigen_genv_sort(w->alphav, w->betav, w->evec, GSL_EIGEN_SORT_ABS_DESC);
  test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "abs/desc");
} /* test_eigen_gen_pencil() */