power.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <util/alloc.h>
  11. #include "power.h"
  12. #include <sparse/SparseMatrix.h>
  13. // Maxium of iterations that will be done in power_method
  14. static const int maxit = 100;
  15. // Accuracy control (convergence criterion) for power_method
  16. static const double tolerance = 0.00001;
  17. double *power_method(void *A, int n, int random_seed) {
  18. /* find largest eigenvector of a matrix A.
  19. This converges only if the largest eigenvector/value is real (e.g., if A is symmetric) and the
  20. next largest eigenvalues separate from the largest ones
  21. input:
  22. A: the matrix
  23. n: dimension of matrix A
  24. random_seed: seed for eigenvector initialization
  25. matrix: max number f iterations
  26. output:
  27. eigv: eigenvectors. The i-th is at eigvs[i*n, i*(n+1) - 1]
  28. Function PowerIteration (A – m × m matrix )
  29. % This function computes u1, u2, . . . , uk, the first k eigenvectors of S.
  30. const tolerance ← 0.001
  31. ui ← random
  32. ui ← ui/||ui||
  33. do
  34. vi ← ui
  35. ui ← A vi/||A vi||
  36. while (ui^T vi < 1-tolerance) (halt when direction change is small)
  37. vi = ui
  38. return v1,v2,...
  39. */
  40. double *v, *u, *vv;
  41. int iter = 0;
  42. double res, unorm;
  43. int i;
  44. double *eigv = gv_calloc(n, sizeof(double));
  45. vv = gv_calloc(n, sizeof(double));
  46. u = gv_calloc(n, sizeof(double));
  47. srand((unsigned)random_seed);
  48. v = eigv;
  49. for (i = 0; i < n; i++) u[i] = drand();
  50. res = sqrt(vector_product(n, u, u));
  51. if (res > 0) res = 1/res;
  52. for (i = 0; i < n; i++) {
  53. u[i] = u[i]*res;
  54. v[i] = u[i];
  55. }
  56. iter = 0;
  57. do {
  58. SparseMatrix_multiply_vector(A, u, &vv);
  59. unorm = vector_product(n, vv, vv);/* ||u||^2 */
  60. unorm = sqrt(unorm);
  61. if (unorm > 0) {
  62. unorm = 1/unorm;
  63. } else {
  64. // ||A.v||=0, so v must be an eigenvec correspond to eigenvalue zero
  65. for (i = 0; i < n; i++) vv[i] = u[i];
  66. unorm = sqrt(vector_product(n, vv, vv));
  67. if (unorm > 0) unorm = 1/unorm;
  68. }
  69. res = 0.;
  70. for (i = 0; i < n; i++) {
  71. u[i] = vv[i]*unorm;
  72. res = res + u[i]*v[i];
  73. v[i] = u[i];
  74. }
  75. } while (res < 1 - tolerance && iter++ < maxit);
  76. free(u);
  77. free(vv);
  78. return eigv;
  79. }