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