File: PowerEigenSolver.cpp

package info (click to toggle)
rdkit 201203-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 37,840 kB
  • sloc: cpp: 93,902; python: 51,897; java: 5,192; ansic: 3,497; xml: 2,499; sql: 1,641; yacc: 1,518; lex: 1,076; makefile: 325; fortran: 183; sh: 153; cs: 51
file content (101 lines) | stat: -rw-r--r-- 3,037 bytes parent folder | download
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: PowerEigenSolver.cpp 1528 2010-09-26 17:04:37Z glandrum $
//
//  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, maxEval;
      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;
          maxEval = -1.0;
          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;
    }
  }
}