pivot.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /* pivot.c
  2. provides a simple function to do a full pivot search while doing an LU factorization
  3. */
  4. #include <math.h>
  5. #include <assert.h>
  6. #include "openmodelica.h"
  7. /* Matrixes using column major order (as in Fortran) */
  8. #ifndef set_matrix_elt
  9. #define set_matrix_elt(A,r,c,n_rows,value) A[r + n_rows * c] = value
  10. #endif
  11. #ifndef get_matrix_elt
  12. #define get_matrix_elt(A,r,c,n_rows) A[r + n_rows * c]
  13. #endif
  14. /* Matrixes using column major order (as in Fortran) */
  15. /* colInd, rowInd, n_rows is added implicitly, makes code easier to read but may be considered bad programming style! */
  16. #define set_pivot_matrix_elt(A,r,c,value) set_matrix_elt(A,rowInd[r],colInd[c],n_rows,value)
  17. /* #define set_pivot_matrix_elt(A,r,c,value) set_matrix_elt(A,colInd[c],rowInd[r],n_cols,value) */
  18. #define get_pivot_matrix_elt(A,r,c) get_matrix_elt(A,rowInd[r],colInd[c],n_rows)
  19. /* #define get_pivot_matrix_elt(A,r,c) get_matrix_elt(A,colInd[c],rowInd[r],n_cols) */
  20. #define swap(a,b) { modelica_integer _swap=a; a=b; b=_swap; }
  21. #ifndef min
  22. #define min(a,b) ((a > b) ? (b) : (a))
  23. #endif
  24. /*
  25. find the maximum element below (and including) line/row start
  26. */
  27. int maxsearch( double *A, modelica_integer start, modelica_integer n_rows, modelica_integer n_cols, modelica_integer *rowInd, modelica_integer *colInd, modelica_integer *maxrow, modelica_integer *maxcol, double *maxabsval)
  28. {
  29. /* temporary variables */
  30. modelica_integer row;
  31. modelica_integer col;
  32. /* Initialization */
  33. modelica_integer mrow = -1;
  34. modelica_integer mcol = -1;
  35. double mabsval = 0.0;
  36. /* go through all rows and columns */
  37. for(row=start; row<n_rows; row++)
  38. {
  39. for(col=start; col<n_cols; col++)
  40. {
  41. double tmp = fabs(get_pivot_matrix_elt(A,row,col));
  42. /* Compare element to current maximum */
  43. if (tmp > mabsval)
  44. {
  45. mrow = row;
  46. mcol = col;
  47. mabsval = tmp;
  48. }
  49. }
  50. }
  51. /* assert that the matrix is not identical to zero */
  52. if ((mrow < 0) || (mcol < 0)) return -1;
  53. /* return result */
  54. *maxrow = mrow;
  55. *maxcol = mcol;
  56. *maxabsval = mabsval;
  57. return 0;
  58. }
  59. /*
  60. pivot performs a full pivotization of a rectangular matrix A of dimension n_cols x n_rows
  61. rowInd and colInd are vectors of length nrwos and n_cols respectively.
  62. They hold the old (and new) pivoting information, such that
  63. A_pivoted[i,j] = A[rowInd[i], colInd[j]]
  64. */
  65. int pivot( double *A, modelica_integer n_rows, modelica_integer n_cols, modelica_integer *rowInd, modelica_integer *colInd )
  66. {
  67. /* parameter, determines how much larger an element should be before rows and columns are interchanged */
  68. const double fac = 1.125; /* approved by dymola ;) */
  69. /* temporary variables */
  70. modelica_integer row;
  71. modelica_integer i,j;
  72. modelica_integer maxrow;
  73. modelica_integer maxcol;
  74. double maxabsval;
  75. double pivot;
  76. /* go over all pivot elements */
  77. for(row=0; row<min(n_rows,n_cols); row++)
  78. {
  79. /* get current pivot */
  80. pivot = fabs(get_pivot_matrix_elt(A,row,row));
  81. /* find the maximum element in matrix
  82. result is stored in maxrow, maxcol and maxabsval */
  83. if (maxsearch(A, row, n_rows, n_cols, rowInd, colInd, &maxrow, &maxcol, &maxabsval) != 0) return -1;
  84. /* compare max element and pivot (scaled by fac) */
  85. if (maxabsval > (fac*pivot))
  86. {
  87. /* row interchange */
  88. swap(rowInd[row], rowInd[maxrow]);
  89. /* column interchange */
  90. swap(colInd[row], colInd[maxcol]);
  91. }
  92. /* get pivot (without abs, may have changed because of row/column interchange */
  93. pivot = get_pivot_matrix_elt(A,row,row);
  94. /* internal error, pivot element should never be zero if maxsearch succeeded */
  95. assert(pivot != 0);
  96. /* perform one step of Gaussian Elimination */
  97. for(i=row+1;i<n_rows;i++)
  98. {
  99. double leader = get_pivot_matrix_elt(A,i,row);
  100. if (leader != 0.0)
  101. {
  102. double scale = -leader/pivot;
  103. /* set leader to zero */
  104. set_pivot_matrix_elt(A,i,row, 0.0);
  105. /* subtract scaled equation from pivot row from current row */
  106. for(j=row+1;j<n_cols;j++)
  107. {
  108. double t1 = get_pivot_matrix_elt(A,i,j);
  109. double t2 = get_pivot_matrix_elt(A,row,j);
  110. double tmp = t1 + scale*t2;
  111. set_pivot_matrix_elt(A,i,j, tmp);
  112. }
  113. }
  114. }
  115. }
  116. /* all fine */
  117. return 0;
  118. }