File: PowerEigenSolver.cpp

package info (click to toggle)
rdkit 201809.1%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 123,688 kB
  • sloc: cpp: 230,509; python: 70,501; java: 6,329; ansic: 5,427; sql: 1,899; yacc: 1,739; lex: 1,243; makefile: 445; xml: 229; fortran: 183; sh: 123; cs: 93
file content (101 lines) | stat: -rw-r--r-- 2,673 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// $Id$
//
//  Copyright (C) 2004-2008 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include "PowerEigenSolver.h"
#include <Numerics/Vector.h>
#include <Numerics/Matrix.h>
#include <Numerics/SymmMatrix.h>
#include <RDGeneral/Invariant.h>
#include <time.h>

#define MAX_ITERATIONS 1000
#define TOLERANCE 0.001
#define HUGE_EIGVAL 1.0e10
#define TINY_EIGVAL 1.0e-10

namespace RDNumeric {
namespace EigenSolvers {
bool powerEigenSolver(unsigned int numEig, DoubleSymmMatrix &mat,
                      DoubleVector &eigenValues, DoubleMatrix *eigenVectors,
                      int seed) {
  // first check all the sizes
  unsigned int N = mat.numRows();
  CHECK_INVARIANT(eigenValues.size() >= numEig, "");
  CHECK_INVARIANT(numEig <= N, "");
  if (eigenVectors) {
    unsigned int evRows, evCols;
    evRows = eigenVectors->numRows();
    evCols = eigenVectors->numCols();
    CHECK_INVARIANT(evCols >= N, "");
    CHECK_INVARIANT(evRows >= numEig, "");
  }

  unsigned int ei;
  double eigVal, prevVal;
  bool converged = false;
  unsigned int i, j, id, iter, evalId;

  DoubleVector v(N), z(N);
  if (seed <= 0) seed = clock();
  for (ei = 0; ei < numEig; ei++) {
    eigVal = -HUGE_EIGVAL;
    seed += ei;
    v.setToRandom(seed);

    converged = false;
    for (iter = 0; iter < MAX_ITERATIONS; iter++) {
      // z = mat*v
      multiply(mat, v, z);
      prevVal = eigVal;
      evalId = z.largestAbsValId();
      eigVal = z.getVal(evalId);

      if (fabs(eigVal) < TINY_EIGVAL) {
        break;
      }

      // compute the next estimate for the eigen vector
      v.assign(z);
      v /= eigVal;
      if (fabs(eigVal - prevVal) < TOLERANCE) {
        converged = true;
        break;
      }
    }
    if (!converged) {
      break;
    }
    v.normalize();

    // save this is a eigen vector and value
    // directly access the data instead of setVal so that we save time
    double *vdata = v.getData();
    if (eigenVectors) {
      id = ei * eigenVectors->numCols();
      double *eigVecData = eigenVectors->getData();
      for (i = 0; i < N; i++) {
        eigVecData[id + i] = vdata[i];
      }
    }
    eigenValues[ei] = eigVal;

    // now remove this eigen vector space out of the matrix
    double *matData = mat.getData();
    for (i = 0; i < N; i++) {
      id = i * (i + 1) / 2;
      for (j = 0; j < i + 1; j++) {
        matData[id + j] -= (eigVal * vdata[i] * vdata[j]);
      }
    }
  }
  return converged;
}
}
}