cgv
Loading...
Searching...
No Matches
gaussj.h
1#pragma once
2#include <cgv/math/mat.h>
3
4
5namespace cgv{
6 namespace math {
7
8
9
14template <typename T>
15bool gaussj(mat<T>& a, mat<T>& b)
16{
17 assert(a.nrows() == a.ncols());
18 const unsigned N = a.nrows();
19 const unsigned M = b.ncols();
20
21 // Some important hints for understanding this implementation
22 // - The input matrix is gradually replaced by the inverse matrix.
23 // Whenever a column reaches the identity form it is instantly
24 // replaced by the emerging inverse matrix.
25 // - The same is true for the vectors b whose elements are gradually
26 // replaced by their solution vectors
27
28
29 // the position of the chosen pivot element
30 unsigned int pivotPos[2];
31 const int COL = 0;
32 const int ROW = 1;
33
34 // these integer arrays are used for bookkeeping which swaps were done for the pivoting
35 mat<unsigned int> swapedRows(N,2);
36 //unsigned int swapedRows[N][2];
37 const int REDUCED_COLUMN = 0;
38 const int PIVOT_ROW = 1;
39
40 bool *isPivotCol = new bool[N];
41 for (unsigned int i = 0; i < N; i++) isPivotCol[i] = false;
42
43 // main loop over all columns to be reduced to identity form
44 for (unsigned int columnCnt = 0; columnCnt < N; columnCnt++)
45 {
46 // for maximum numerical stability we try to find the largest absolute value
47 // in the matrix (excluding the columns which contained previous pivot elements
48 // and now already contain parts of the inverse matrix!) as current pivot element
49 T largestAbsVal = T(0);
50 for (unsigned int j = 0; j < N; j++)
51 {
52 if (!isPivotCol[j])
53 for (unsigned int k = 0; k < N; k++)
54 {
55 if (!isPivotCol[k])
56 if (std::abs(a(j,k)) > largestAbsVal)
57 {
58 largestAbsVal = std::abs(a(j,k));
59 pivotPos[ROW] = j;
60 pivotPos[COL] = k;
61 }
62 }
63 }
64 isPivotCol[pivotPos[COL]] = true;
65
66 // if the pivot element is not on the diagonal, we have to interchange rows
67 if (pivotPos[ROW] != pivotPos[COL])
68 {
69 for (unsigned int l = 0; l < N; l++) std::swap(a(pivotPos[ROW],l),a(pivotPos[COL],l));
70 for (unsigned int l = 0; l < M; l++) std::swap(b(pivotPos[ROW],l),b(pivotPos[COL],l));
71 }
72 swapedRows(columnCnt,PIVOT_ROW) = pivotPos[ROW];
73 swapedRows(columnCnt,REDUCED_COLUMN) = pivotPos[COL];
74
75 // return false if no pivot element > 0 could be found and thus the matrix is singular
76 if (a(pivotPos[COL],pivotPos[COL]) == T(0))
77 {
78 delete [] isPivotCol;
79 return false;
80 }
81
82 // divide the pivot row by the pivot element
83 T pivotInv = T(1) / a(pivotPos[COL],pivotPos[COL]);
84 // set this pivot element to one now to get the corresponding element of inverse matrix
85 // instead of one AFTER the multiplication with the inverse of the pivot element
86 a(pivotPos[COL],pivotPos[COL]) = T(1);
87 for (unsigned int l = 0; l < N; l++) a(pivotPos[COL],l) *= pivotInv;
88 for (unsigned int l = 0; l < M; l++) b(pivotPos[COL],l) *= pivotInv;
89
90 // for all rows
91 for (unsigned int ll = 0; ll < N; ll++)
92 // excluding the row containing the current pivot element
93 if (ll != pivotPos[COL])
94 {
95 // set the factor to get a zero in the pivot colum when subtracting the pivot row
96 T factor = a(ll,pivotPos[COL]);
97 // set this element in the pivot column to zero to get the corresponding element of inverse matrix
98 // instead of a zero AFTER the subtraction
99 a(ll,pivotPos[COL]) = T(0);
100 // substract the pivot row multiplied with the factor
101 for (unsigned int l = 0; l < N; l++) a(ll,l) -= a(pivotPos[COL],l) * factor;
102 }
103
104
105 }
106
107 for (int undoSwapStep = N-1; undoSwapStep >= 0; undoSwapStep--)
108 {
109 if (swapedRows(undoSwapStep,PIVOT_ROW) != swapedRows(undoSwapStep,REDUCED_COLUMN))
110 {
111 for (unsigned int k = 0; k < N; k++)
112 std::swap( a(k,swapedRows(undoSwapStep,PIVOT_ROW)), a(k,swapedRows(undoSwapStep,REDUCED_COLUMN)) );
113
114 }
115 }
116 delete [] isPivotCol;
117 return true;
118}
119
120
124template <typename T>
125bool gaussj(mat<T>& a)
126{
127 assert(a.nrows() == a.ncols());
128 const unsigned N = a.nrows();
129
130 // Some important hints for understanding this implementation
131 // - The input matrix is gradually replaced by the inverse matrix.
132 // Whenever a column reaches the identity form it is instantly
133 // replaced by the emerging inverse matrix.
134
135
136 // the position of the chosen pivot element
137 unsigned int pivotPos[2];
138 const int COL = 0;
139 const int ROW = 1;
140
141 // these integer arrays are used for bookkeeping which swaps were done for the pivoting
142 mat<unsigned int> swapedRows(N,2);
143 //unsigned int swapedRows[N][2];
144 const int REDUCED_COLUMN = 0;
145 const int PIVOT_ROW = 1;
146
147 bool *isPivotCol = new bool[N];
148 for (unsigned int i = 0; i < N; i++) isPivotCol[i] = false;
149
150 // main loop over all columns to be reduced to identity form
151 for (unsigned int columnCnt = 0; columnCnt < N; columnCnt++)
152 {
153 // for maximum numerical stability we try to find the largest absolute value
154 // in the matrix (excluding the columns which contained previous pivot elements
155 // and now already contain parts of the inverse matrix!) as current pivot element
156 T largestAbsVal = T(0);
157 for (unsigned int j = 0; j < N; j++)
158 {
159 if (!isPivotCol[j])
160 for (unsigned int k = 0; k < N; k++)
161 {
162 if (!isPivotCol[k])
163 if (std::abs(a(j,k)) > largestAbsVal)
164 {
165 largestAbsVal = std::abs(a(j,k));
166 pivotPos[ROW] = j;
167 pivotPos[COL] = k;
168 }
169 }
170 }
171 isPivotCol[pivotPos[COL]] = true;
172
173 // if the pivot element is not on the diagonal, we have to interchange rows
174 if (pivotPos[ROW] != pivotPos[COL])
175 {
176 for (unsigned int l = 0; l < N; l++) std::swap(a(pivotPos[ROW],l),a(pivotPos[COL],l));
177 }
178 swapedRows(columnCnt,PIVOT_ROW) = pivotPos[ROW];
179 swapedRows(columnCnt,REDUCED_COLUMN) = pivotPos[COL];
180
181 // return false if no pivot element > 0 could be found and thus the matrix is singular
182 if (a(pivotPos[COL],pivotPos[COL]) == T(0))
183 {
184 delete [] isPivotCol;
185 return false;
186 }
187
188 // divide the pivot row by the pivot element
189 T pivotInv = T(1) / a(pivotPos[COL],pivotPos[COL]);
190 // set this pivot element to one now to get the corresponding element of inverse matrix
191 // instead of one AFTER the multiplication with the inverse of the pivot element
192 a(pivotPos[COL],pivotPos[COL]) = T(1);
193 for (unsigned int l = 0; l < N; l++) a(pivotPos[COL],l) *= pivotInv;
194
195 // for all rows
196 for (unsigned int ll = 0; ll < N; ll++)
197 // excluding the row containing the current pivot element
198 if (ll != pivotPos[COL])
199 {
200 // set the factor to get a zero in the pivot colum when subtracting the pivot row
201 T factor = a(ll,pivotPos[COL]);
202 // set this element in the pivot column to zero to get the corresponding element of inverse matrix
203 // instead of a zero AFTER the subtraction
204 a(ll,pivotPos[COL]) = T(0);
205 // substract the pivot row multiplied with the factor
206 for (unsigned int l = 0; l < N; l++) a(ll,l) -= a(pivotPos[COL],l) * factor;
207 }
208
209
210 }
211
212 for (int undoSwapStep = N-1; undoSwapStep >= 0; undoSwapStep--)
213 {
214 if (swapedRows(undoSwapStep,PIVOT_ROW) != swapedRows(undoSwapStep,REDUCED_COLUMN))
215 {
216 for (unsigned int k = 0; k < N; k++)
217 std::swap( a(k,swapedRows(undoSwapStep,PIVOT_ROW)), a(k,swapedRows(undoSwapStep,REDUCED_COLUMN)) );
218
219 }
220 }
221 delete [] isPivotCol;
222 return true;
223}
224
225
226}
227}
the cgv namespace
Definition print.h:11