CppNoddy  0.92
Loading...
Searching...
No Matches
DenseLinearSystem.cpp
Go to the documentation of this file.
1/// \file DenseLinearSystem.cpp
2/// Implementation for the LinearSystem class
3
4#include <vector>
5#include <string>
6
7#include <FortranLAPACK.h>
8#include <FortranData.h>
9#include <DenseLinearSystem.h>
10#include <Exceptions.h>
11
12namespace CppNoddy {
13
14 template <typename _Type>
17 std::string which) :
18 m_minPivot(1.e-12), m_detSign(0), m_monitorDet(false) {
19 this -> m_pA = p_A;
20 this -> m_pB = p_B;
21 m_version = which;
22 if((m_version != "lapack") && (m_version != "native")) {
23 std::string problem;
24 problem = "The DenseLinearSystem has been instantiated with an unrecognised\n";
25 problem += "request for a solver type. Options are 'native' or 'lapack'. \n";
26 throw ExceptionRuntime(problem);
27 }
28 }
29
30 template <typename _Type>
32 if("lapack" == m_version) {
33 solve_lapack();
34 } else { // we catch incorrect m_version choices in the ctor
35 solve_native();
36 }
37 }
38
39 template <typename _Type>
41 std::string problem;
42 problem = "The solve method for a DenseLinearSystem has not been implemented\n";
43 problem += "for the element type used here. \n";
44 throw ExceptionExternal(problem);
45 }
46
47 // lapack LU solver for double-element dense matrices
48 template <>
49 void DenseLinearSystem<double>::solve_lapack() {
50#ifndef LAPACK
51 std::string problem = "The DenseLinearSystem::solve_lapack method has been called\n";
52 problem += "but the compiler option -DLAPACK was not provided when\n";
53 problem += "the library was built and so LAPACK support is not available.";
54 throw ExceptionExternal(problem);
55#else
56
57 std::size_t N = m_pA -> nrows();
58 FortranData Af(*m_pA);
59 // a vector to store the pivots
60 std::vector<int> pivots(N, 0);
61 // LAPACK information integer
62 int info(0);
63 // Call FORTRAN LAPACK
64 LAPACK_DGESV(N, 1, Af.base(), N, &pivots[ 0 ], &(m_pB -> operator[](0)), N, info);
65 if(0 != info) {
66 std::string problem(" The LAPACK::LU method has detected a failure \n");
67 throw ExceptionExternal(problem, info);
68 }
69 // compute the determinant sign if asked
70 if(m_monitorDet) {
71 m_detSign = signature(pivots);
72 // product of the diagonals
73 for(std::size_t i = 0; i < N; ++i) {
74 if(Af[ i * N + i ] < 0.0) {
75 m_detSign *= -1;
76 }
77 }
78 }
79#endif
80
81 }
82
83
84 template <>
85 void DenseLinearSystem<D_complex>::solve_lapack() {
86#ifndef LAPACK
87 std::string problem = "The DenseLinearSystem::solve_lapack method has been called\n";
88 problem += "but the compiler option -DLAPACK was not provided when\n";
89 problem += "the library was built and so LAPACK support is not available.";
90 throw ExceptionExternal(problem);
91#else
92
93 std::size_t N = m_pA -> nrows();
94 FortranData Af(*m_pA);
95 // a vector to store the pivots
96 std::vector<int> pivots(N, 0);
97 // LAPACK information integer
98 int info(0);
99 // Call FORTRAN LAPACK
100 // LAPACK_ZGESV( N, 1, Af.base(), N, &pivots[ 0 ], &( m_pB -> operator[]( 0 ).real() ), N, info );
101 LAPACK_ZGESV(N, 1, Af.base(), N, &pivots[ 0 ], &reinterpret_cast<double(&)[2]>(m_pB -> operator[](0))[0], N, info);
102 if(0 != info) {
103 std::string problem(" The LAPACK::LU method has detected a failure \n");
104 throw ExceptionExternal(problem, info);
105 }
106#endif
107
108 }
109
110
111 template <typename _Type>
112 void DenseLinearSystem<_Type>::solve_native() {
113 // keep track of row interchanges
114 m_detSign = 1;
115 // first row
116 row_iter first_row(m_pA -> begin());
117 // last row
118 row_iter last_row(m_pA -> end());
119 // first RHS elt
120 elt_iter first_rhs(m_pB -> begin());
121 // last RHS elt
122 elt_iter last_rhs(m_pB -> end());
123 // iterator start point for the RHS
124 elt_iter current_rhs_elt(first_rhs);
125 // step through rows
126 for(row_iter current_row = first_row;
127 current_row != last_row;
128 ++current_row, ++current_rhs_elt) {
129 // calc an index offset from the first row
130 const std::size_t l = distance(first_row, current_row);
131 // find max index in column 'l' in the range [l, last_row)
132 row_iter max_row = m_pA -> max_in_col(l, current_row, last_row);
133 // if index of max elt is not the diagonal then swap the rows
134 if(current_row != max_row) {
135 // flip the determinant sign
136 m_detSign *= -1;
137 // to switch row with max diagonal element to be the current row
138 // we could just use
139 // std:swap<DenseVector<_Type>>( *current_row, *max_row );
140 // but there is no need to swap the eliminated entries
141 // to the left of the diagonal
142 {
143 elt_iter max_row_elt = max_row -> begin() + l;
144 for(elt_iter current_row_elt = current_row -> begin() + l;
145 current_row_elt != current_row -> end();
146 ++current_row_elt, ++max_row_elt) {
147 std::swap(*current_row_elt, *max_row_elt);
148 }
149 }
150 // switch the elts in RHS R-vector to be consistent
151 std::swap<_Type>(*current_rhs_elt, *(first_rhs + distance(first_row, max_row)));
152 }
153 // de-reference the element to get diagonal entry value
154 const _Type diag_entry = *(current_row -> begin() + l);
155 // check it
156 if(std::abs(diag_entry) < m_minPivot) {
157 std::string problem("A pivot in NDMatrix.GJE is under the minimum tolerance => singular matrix. \n");
158 throw ExceptionRuntime(problem);
159 }
160 // eliminate all entries below current row in the diagonal's column
161 {
162 // iterator to the corresponding RHS element
163 elt_iter elim_rhs(m_pB -> begin() + l + 1);
164 // loop through the rows
165 for(row_iter elim_row = current_row + 1;
166 elim_row != last_row;
167 ++elim_row, ++elim_rhs) {
168 // work out the appropriate multiplier for the elimination
169 const _Type mult = *(elim_row -> begin() + l) / diag_entry;
170 // elimination of all columns would be *elim_row -= *current_row * mult;
171 // but instead optimise out the zero elements to the left of diagonal
172 for(elt_iter col = elim_row -> begin() + l; col != elim_row -> end(); ++col) {
173 const unsigned col_offset(distance(elim_row -> begin(), col));
174 *col -= *(current_row -> begin() + col_offset) * mult;
175 }
176 // apply the same operation to the RHS vector
177 *elim_rhs -= *current_rhs_elt * mult;
178 }
179 }
180 } // close l-loop
181 backsub();
182 if(m_monitorDet) {
183 for(row_iter row = first_row; row != last_row; ++row) {
184 const unsigned l = distance(first_row, row);
185 if(lt(*(row -> begin() + l))) {
186 m_detSign *= -1;
187 }
188 }
189 }
190 }
191
192
193 template <typename _Type>
194 bool DenseLinearSystem<_Type>::lt(_Type value) const {
195 std::string problem;
196 problem = "You've turned on monitoring of the sign of the determinant for a \n";
197 problem += "DenseLinearSystem whose elements are not of type <double>.\n";
198 throw ExceptionRuntime(problem);
199 }
200
201
202 template <typename _Type>
203 int DenseLinearSystem<_Type>::signature(const std::vector<int> &pivots) const {
204 int sign(1);
205 for(std::size_t i = 0; i < pivots.size(); ++i) {
206 if(pivots[ i ] - 1 != int(i)) {
207 sign *= -1;
208 }
209 }
210 return sign;
211 }
212
213 template <typename _Type>
214 void DenseLinearSystem<_Type >::backsub() const {
215 // last row
216 row_riter rend_row(m_pA -> rend());
217 // first RHS elt
218 elt_riter rbegin_rhs(m_pB -> rbegin());
219 // iterator start point for the RHS
220 elt_riter current_rhs_elt(rbegin_rhs);
221 row_riter current_row(m_pA -> rbegin());
222 // step through the rows in reverse order
223 for(;
224 current_row != rend_row;
225 ++current_row, ++current_rhs_elt) {
226 _Type sum = 0.0;
227 elt_riter a_elt(current_row -> rbegin());
228 elt_riter b_elt(rbegin_rhs);
229 // step through the columns/elts in reverse order
230 for(;
231 b_elt != current_rhs_elt;
232 ++a_elt, ++b_elt) {
233 sum += *a_elt * *b_elt;
234 }
235 // set the solution using the RHS vector
236 *current_rhs_elt = (*current_rhs_elt - sum) / *a_elt;
237 }
238 }
239
240 template <typename _Type>
242 return m_detSign;
243 }
244
245 template <typename _Type>
247 m_monitorDet = flag;
248 }
249
250
251
252 template class DenseLinearSystem<D_complex>
253 ;
254 template class DenseLinearSystem<double>
255 ;
256
257} // end namespace
Specification of the linear system class.
The collection of CppNoddy exceptions.
Some interface definitions for calling external fortran routines in LAPACK.
A linear system class for vector right-hand sides.
DenseLinearSystem(DenseMatrix< _Type > *m_pA, DenseVector< _Type > *m_pB, std::string which="native")
Constructor for a dense linear system object.
void set_monitor_det(bool flag)
Store the sign of the determinant of the LHS matrix every time a solve is requested on a real system.
int get_det_sign() const
Get the sign of the determinant of the LHS matrix from the linear system just computed.
void solve()
Solve the sparse system.
A matrix class that constructs a DENSE matrix as a row major std::vector of DenseVectors.
Definition: DenseMatrix.h:25
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
An exception to indicate that an error has been detected in an external (LAPACK) routine.
Definition: Exceptions.h:20
A generic runtime exception.
Definition: Exceptions.h:158
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt