1 | //
|
---|
2 | // Copyright (c) 2000-2002
|
---|
3 | // Joerg Walter, Mathias Koch
|
---|
4 | //
|
---|
5 | // Permission to use, copy, modify, distribute and sell this software
|
---|
6 | // and its documentation for any purpose is hereby granted without fee,
|
---|
7 | // provided that the above copyright notice appear in all copies and
|
---|
8 | // that both that copyright notice and this permission notice appear
|
---|
9 | // in supporting documentation. The authors make no representations
|
---|
10 | // about the suitability of this software for any purpose.
|
---|
11 | // It is provided "as is" without express or implied warranty.
|
---|
12 | //
|
---|
13 | // The authors gratefully acknowledge the support of
|
---|
14 | // GeNeSys mbH & Co. KG in producing this work.
|
---|
15 | //
|
---|
16 |
|
---|
17 | #ifndef _BOOST_UBLAS_LU_
|
---|
18 | #define _BOOST_UBLAS_LU_
|
---|
19 |
|
---|
20 | #include <boost/numeric/ublas/operation.hpp>
|
---|
21 | #include <boost/numeric/ublas/matrix_expression.hpp>
|
---|
22 | #include <boost/numeric/ublas/vector.hpp>
|
---|
23 | #include <boost/numeric/ublas/detail/matrix_assign.hpp>
|
---|
24 |
|
---|
25 | // LU factorizations in the spirit of LAPACK and Golub & van Loan
|
---|
26 |
|
---|
27 | namespace boost { namespace numeric { namespace ublas {
|
---|
28 |
|
---|
29 | template<class T = std::size_t, class A = unbounded_array<T> >
|
---|
30 | class permutation_matrix:
|
---|
31 | public vector<T, A> {
|
---|
32 | public:
|
---|
33 | typedef vector<T, A> vector_type;
|
---|
34 | typedef typename vector_type::size_type size_type;
|
---|
35 |
|
---|
36 | // Construction and destruction
|
---|
37 | BOOST_UBLAS_INLINE
|
---|
38 | permutation_matrix (size_type size):
|
---|
39 | vector<T, A> (size) {
|
---|
40 | for (size_type i = 0; i < size; ++ i)
|
---|
41 | (*this) (i) = i;
|
---|
42 | }
|
---|
43 | BOOST_UBLAS_INLINE
|
---|
44 | ~permutation_matrix () {}
|
---|
45 |
|
---|
46 | // Assignment
|
---|
47 | BOOST_UBLAS_INLINE
|
---|
48 | permutation_matrix &operator = (const permutation_matrix &m) {
|
---|
49 | vector_type::operator = (m);
|
---|
50 | return *this;
|
---|
51 | }
|
---|
52 | };
|
---|
53 |
|
---|
54 | template<class PM, class MV>
|
---|
55 | BOOST_UBLAS_INLINE
|
---|
56 | void swap_rows (const PM &pm, MV &mv, vector_tag) {
|
---|
57 | typedef typename PM::size_type size_type;
|
---|
58 | typedef typename MV::value_type value_type;
|
---|
59 |
|
---|
60 | size_type size = pm.size ();
|
---|
61 | for (size_type i = 0; i < size; ++ i) {
|
---|
62 | if (i != pm (i))
|
---|
63 | std::swap (mv (i), mv (pm (i)));
|
---|
64 | }
|
---|
65 | }
|
---|
66 | template<class PM, class MV>
|
---|
67 | BOOST_UBLAS_INLINE
|
---|
68 | void swap_rows (const PM &pm, MV &mv, matrix_tag) {
|
---|
69 | typedef typename PM::size_type size_type;
|
---|
70 | typedef typename MV::value_type value_type;
|
---|
71 |
|
---|
72 | size_type size = pm.size ();
|
---|
73 | for (size_type i = 0; i < size; ++ i) {
|
---|
74 | if (i != pm (i))
|
---|
75 | row (mv, i).swap (row (mv, pm (i)));
|
---|
76 | }
|
---|
77 | }
|
---|
78 | // Dispatcher
|
---|
79 | template<class PM, class MV>
|
---|
80 | BOOST_UBLAS_INLINE
|
---|
81 | void swap_rows (const PM &pm, MV &mv) {
|
---|
82 | swap_rows (pm, mv, typename MV::type_category ());
|
---|
83 | }
|
---|
84 |
|
---|
85 | // LU factorization without pivoting
|
---|
86 | template<class M>
|
---|
87 | typename M::size_type lu_factorize (M &m) {
|
---|
88 | typedef M matrix_type;
|
---|
89 | typedef typename M::size_type size_type;
|
---|
90 | typedef typename M::value_type value_type;
|
---|
91 |
|
---|
92 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
93 | matrix_type cm (m);
|
---|
94 | #endif
|
---|
95 | int singular = 0;
|
---|
96 | size_type size1 = m.size1 ();
|
---|
97 | size_type size2 = m.size2 ();
|
---|
98 | size_type size = (std::min) (size1, size2);
|
---|
99 | for (size_type i = 0; i < size; ++ i) {
|
---|
100 | matrix_column<M> mci (column (m, i));
|
---|
101 | matrix_row<M> mri (row (m, i));
|
---|
102 | if (m (i, i) != value_type/*zero*/()) {
|
---|
103 | project (mci, range (i + 1, size1)) *= value_type (1) / m (i, i);
|
---|
104 | } else if (singular == 0) {
|
---|
105 | singular = i + 1;
|
---|
106 | }
|
---|
107 | project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
|
---|
108 | outer_prod (project (mci, range (i + 1, size1)),
|
---|
109 | project (mri, range (i + 1, size2))));
|
---|
110 | }
|
---|
111 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
112 | BOOST_UBLAS_CHECK (singular != 0 ||
|
---|
113 | detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
---|
114 | triangular_adaptor<matrix_type, upper> (m)),
|
---|
115 | cm), internal_logic ());
|
---|
116 | #endif
|
---|
117 | return singular;
|
---|
118 | }
|
---|
119 |
|
---|
120 | // LU factorization with partial pivoting
|
---|
121 | template<class M, class PM>
|
---|
122 | typename M::size_type lu_factorize (M &m, PM &pm) {
|
---|
123 | typedef M matrix_type;
|
---|
124 | typedef typename M::size_type size_type;
|
---|
125 | typedef typename M::value_type value_type;
|
---|
126 |
|
---|
127 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
128 | matrix_type cm (m);
|
---|
129 | #endif
|
---|
130 | int singular = 0;
|
---|
131 | size_type size1 = m.size1 ();
|
---|
132 | size_type size2 = m.size2 ();
|
---|
133 | size_type size = (std::min) (size1, size2);
|
---|
134 | for (size_type i = 0; i < size; ++ i) {
|
---|
135 | matrix_column<M> mci (column (m, i));
|
---|
136 | matrix_row<M> mri (row (m, i));
|
---|
137 | size_type i_norm_inf = i + index_norm_inf (project (mci, range (i, size1)));
|
---|
138 | BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
---|
139 | if (m (i_norm_inf, i) != value_type/*zero*/()) {
|
---|
140 | if (i_norm_inf != i) {
|
---|
141 | pm (i) = i_norm_inf;
|
---|
142 | row (m, i_norm_inf).swap (mri);
|
---|
143 | } else {
|
---|
144 | BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
---|
145 | }
|
---|
146 | project (mci, range (i + 1, size1)) *= value_type (1) / m (i, i);
|
---|
147 | } else if (singular == 0) {
|
---|
148 | singular = i + 1;
|
---|
149 | }
|
---|
150 | project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
|
---|
151 | outer_prod (project (mci, range (i + 1, size1)),
|
---|
152 | project (mri, range (i + 1, size2))));
|
---|
153 | }
|
---|
154 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
155 | swap_rows (pm, cm);
|
---|
156 | BOOST_UBLAS_CHECK (singular != 0 ||
|
---|
157 | detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
---|
158 | triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
|
---|
159 | #endif
|
---|
160 | return singular;
|
---|
161 | }
|
---|
162 |
|
---|
163 | template<class M, class PM>
|
---|
164 | typename M::size_type axpy_lu_factorize (M &m, PM &pm) {
|
---|
165 | typedef M matrix_type;
|
---|
166 | typedef typename M::size_type size_type;
|
---|
167 | typedef typename M::value_type value_type;
|
---|
168 | typedef vector<value_type> vector_type;
|
---|
169 |
|
---|
170 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
171 | matrix_type cm (m);
|
---|
172 | #endif
|
---|
173 | int singular = 0;
|
---|
174 | size_type size1 = m.size1 ();
|
---|
175 | size_type size2 = m.size2 ();
|
---|
176 | size_type size = (std::min) (size1, size2);
|
---|
177 | #ifndef BOOST_UBLAS_LU_WITH_INPLACE_SOLVE
|
---|
178 | matrix_type mr (m);
|
---|
179 | mr.assign (zero_matrix<value_type> (size1, size2));
|
---|
180 | vector_type v (size1);
|
---|
181 | for (size_type i = 0; i < size; ++ i) {
|
---|
182 | matrix_range<matrix_type> lrr (project (mr, range (0, i), range (0, i)));
|
---|
183 | vector_range<matrix_column<matrix_type> > urr (project (column (mr, i), range (0, i)));
|
---|
184 | urr.assign (solve (lrr, project (column (m, i), range (0, i)), unit_lower_tag ()));
|
---|
185 | project (v, range (i, size1)).assign (
|
---|
186 | project (column (m, i), range (i, size1)) -
|
---|
187 | axpy_prod<vector_type> (project (mr, range (i, size1), range (0, i)), urr));
|
---|
188 | size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
|
---|
189 | BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
---|
190 | if (v (i_norm_inf) != value_type/*zero*/()) {
|
---|
191 | if (i_norm_inf != i) {
|
---|
192 | pm (i) = i_norm_inf;
|
---|
193 | std::swap (v (i_norm_inf), v (i));
|
---|
194 | project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
|
---|
195 | } else {
|
---|
196 | BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
---|
197 | }
|
---|
198 | project (column (mr, i), range (i + 1, size1)).assign (
|
---|
199 | project (v, range (i + 1, size1)) / v (i));
|
---|
200 | if (i_norm_inf != i) {
|
---|
201 | project (row (mr, i_norm_inf), range (0, i)).swap (project (row (mr, i), range (0, i)));
|
---|
202 | }
|
---|
203 | } else if (singular == 0) {
|
---|
204 | singular = i + 1;
|
---|
205 | }
|
---|
206 | mr (i, i) = v (i);
|
---|
207 | }
|
---|
208 | m.assign (mr);
|
---|
209 | #else
|
---|
210 | matrix_type lr (m);
|
---|
211 | matrix_type ur (m);
|
---|
212 | lr.assign (identity_matrix<value_type> (size1, size2));
|
---|
213 | ur.assign (zero_matrix<value_type> (size1, size2));
|
---|
214 | vector_type v (size1);
|
---|
215 | for (size_type i = 0; i < size; ++ i) {
|
---|
216 | matrix_range<matrix_type> lrr (project (lr, range (0, i), range (0, i)));
|
---|
217 | vector_range<matrix_column<matrix_type> > urr (project (column (ur, i), range (0, i)));
|
---|
218 | urr.assign (project (column (m, i), range (0, i)));
|
---|
219 | inplace_solve (lrr, urr, unit_lower_tag ());
|
---|
220 | project (v, range (i, size1)).assign (
|
---|
221 | project (column (m, i), range (i, size1)) -
|
---|
222 | axpy_prod<vector_type> (project (lr, range (i, size1), range (0, i)), urr));
|
---|
223 | size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
|
---|
224 | BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
---|
225 | if (v (i_norm_inf) != value_type/*zero*/()) {
|
---|
226 | if (i_norm_inf != i) {
|
---|
227 | pm (i) = i_norm_inf;
|
---|
228 | std::swap (v (i_norm_inf), v (i));
|
---|
229 | project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
|
---|
230 | } else {
|
---|
231 | BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
---|
232 | }
|
---|
233 | project (column (lr, i), range (i + 1, size1)).assign (
|
---|
234 | project (v, range (i + 1, size1)) / v (i));
|
---|
235 | if (i_norm_inf != i) {
|
---|
236 | project (row (lr, i_norm_inf), range (0, i)).swap (project (row (lr, i), range (0, i)));
|
---|
237 | }
|
---|
238 | } else if (singular == 0) {
|
---|
239 | singular = i + 1;
|
---|
240 | }
|
---|
241 | ur (i, i) = v (i);
|
---|
242 | }
|
---|
243 | m.assign (triangular_adaptor<matrix_type, strict_lower> (lr) +
|
---|
244 | triangular_adaptor<matrix_type, upper> (ur));
|
---|
245 | #endif
|
---|
246 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
247 | swap_rows (pm, cm);
|
---|
248 | BOOST_UBLAS_CHECK (singular != 0 ||
|
---|
249 | detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
---|
250 | triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
|
---|
251 | #endif
|
---|
252 | return singular;
|
---|
253 | }
|
---|
254 |
|
---|
255 | // LU substitution
|
---|
256 | template<class M, class E>
|
---|
257 | void lu_substitute (const M &m, vector_expression<E> &e) {
|
---|
258 | typedef const M const_matrix_type;
|
---|
259 | typedef vector<typename E::value_type> vector_type;
|
---|
260 |
|
---|
261 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
262 | vector_type cv1 (e);
|
---|
263 | #endif
|
---|
264 | inplace_solve (m, e, unit_lower_tag ());
|
---|
265 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
266 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cv1), internal_logic ());
|
---|
267 | vector_type cv2 (e);
|
---|
268 | #endif
|
---|
269 | inplace_solve (m, e, upper_tag ());
|
---|
270 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
271 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cv2), internal_logic ());
|
---|
272 | #endif
|
---|
273 | }
|
---|
274 | template<class M, class E>
|
---|
275 | void lu_substitute (const M &m, matrix_expression<E> &e) {
|
---|
276 | typedef const M const_matrix_type;
|
---|
277 | typedef matrix<typename E::value_type> matrix_type;
|
---|
278 |
|
---|
279 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
280 | matrix_type cm1 (e);
|
---|
281 | #endif
|
---|
282 | inplace_solve (m, e, unit_lower_tag ());
|
---|
283 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
284 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cm1), internal_logic ());
|
---|
285 | matrix_type cm2 (e);
|
---|
286 | #endif
|
---|
287 | inplace_solve (m, e, upper_tag ());
|
---|
288 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
289 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cm2), internal_logic ());
|
---|
290 | #endif
|
---|
291 | }
|
---|
292 | template<class M, class PMT, class PMA, class MV>
|
---|
293 | void lu_substitute (const M &m, const permutation_matrix<PMT, PMA> &pm, MV &mv) {
|
---|
294 | swap_rows (pm, mv);
|
---|
295 | lu_substitute (m, mv);
|
---|
296 | }
|
---|
297 | template<class E, class M>
|
---|
298 | void lu_substitute (vector_expression<E> &e, const M &m) {
|
---|
299 | typedef const M const_matrix_type;
|
---|
300 | typedef vector<typename E::value_type> vector_type;
|
---|
301 |
|
---|
302 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
303 | vector_type cv1 (e);
|
---|
304 | #endif
|
---|
305 | inplace_solve (e, m, upper_tag ());
|
---|
306 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
307 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cv1), internal_logic ());
|
---|
308 | vector_type cv2 (e);
|
---|
309 | #endif
|
---|
310 | inplace_solve (e, m, unit_lower_tag ());
|
---|
311 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
312 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cv2), internal_logic ());
|
---|
313 | #endif
|
---|
314 | }
|
---|
315 | template<class E, class M>
|
---|
316 | void lu_substitute (matrix_expression<E> &e, const M &m) {
|
---|
317 | typedef const M const_matrix_type;
|
---|
318 | typedef matrix<typename E::value_type> matrix_type;
|
---|
319 |
|
---|
320 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
321 | matrix_type cm1 (e);
|
---|
322 | #endif
|
---|
323 | inplace_solve (e, m, upper_tag ());
|
---|
324 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
325 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cm1), internal_logic ());
|
---|
326 | matrix_type cm2 (e);
|
---|
327 | #endif
|
---|
328 | inplace_solve (e, m, unit_lower_tag ());
|
---|
329 | #if BOOST_UBLAS_TYPE_CHECK
|
---|
330 | BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cm2), internal_logic ());
|
---|
331 | #endif
|
---|
332 | }
|
---|
333 | template<class MV, class M, class PMT, class PMA>
|
---|
334 | void lu_substitute (MV &mv, const M &m, const permutation_matrix<PMT, PMA> &pm) {
|
---|
335 | swap_rows (pm, mv);
|
---|
336 | lu_substitute (mv, m);
|
---|
337 | }
|
---|
338 |
|
---|
339 | }}}
|
---|
340 |
|
---|
341 | #endif
|
---|