comparison libinterp/corefcn/lu.cc @ 18425:2a45b6b87bee stable

correct numerical errors in sparse LU factorization (bug #41116). * lu.cc: modified to apply pivots as warranted to L and U. * sparse-base-lu.cc: compute correct matrix size for single-output case.
author Michael C. Grant <mcg@cvxr.com>
date Mon, 03 Feb 2014 10:54:27 -0500
parents 175b392e91fe
children 807e21ebddd5
comparison
equal deleted inserted replaced
18418:1ad77b3e6bef 18425:2a45b6b87bee
204 if (arg_is_empty < 0) 204 if (arg_is_empty < 0)
205 return retval; 205 return retval;
206 else if (arg_is_empty > 0) 206 else if (arg_is_empty > 0)
207 return octave_value_list (5, SparseMatrix ()); 207 return octave_value_list (5, SparseMatrix ());
208 208
209 ColumnVector Qinit;
210 if (nargout < 4)
211 {
212 Qinit.resize (nc);
213 for (octave_idx_type i = 0; i < nc; i++)
214 Qinit (i) = i;
215 }
216
217 if (arg.is_real_type ()) 209 if (arg.is_real_type ())
218 { 210 {
211
219 SparseMatrix m = arg.sparse_matrix_value (); 212 SparseMatrix m = arg.sparse_matrix_value ();
220 213
221 switch (nargout) 214 if ( nargout < 4 )
222 { 215 {
223 case 0: 216
224 case 1: 217 ColumnVector Qinit;
225 case 2: 218 Qinit.resize (nc);
226 { 219 for (octave_idx_type i = 0; i < nc; i++)
227 SparseLU fact (m, Qinit, thres, false, true); 220 Qinit (i) = i;
228 221 SparseLU fact (m, Qinit, thres, false, true);
229 if (nargout < 2) 222
223 if ( nargout < 2 )
230 retval(0) = fact.Y (); 224 retval(0) = fact.Y ();
231 else 225 else
232 { 226 {
233 PermMatrix P = fact.Pr_mat (); 227
234 SparseMatrix L = P.transpose () * fact.L (); 228 retval(1)
235 retval(1) = octave_value (fact.U (), 229 = octave_value (
236 MatrixType (MatrixType::Upper)); 230 fact.U () * fact.Pc_mat ().transpose (),
237 231 MatrixType (MatrixType::Permuted_Upper,
238 retval(0) 232 nc, fact.col_perm ()));
239 = octave_value (L, MatrixType (MatrixType::Permuted_Lower, 233
240 nr, fact.row_perm ())); 234 PermMatrix P = fact.Pr_mat ();
241 } 235 SparseMatrix L = fact.L ();
242 } 236 if ( nargout < 3 )
243 break; 237 retval(0)
244 238 = octave_value ( P.transpose () * L,
245 case 3: 239 MatrixType (MatrixType::Permuted_Lower,
246 { 240 nr, fact.row_perm ()));
247 SparseLU fact (m, Qinit, thres, false, true); 241 else
248 242 {
249 if (vecout) 243 retval(0) = L;
250 retval(2) = fact.Pr_vec (); 244 if ( vecout )
251 else 245 retval(2) = fact.Pr_vec();
252 retval(2) = fact.Pr_mat (); 246 else
253 247 retval(2) = P;
254 retval(1) = octave_value (fact.U (), 248 }
255 MatrixType (MatrixType::Upper)); 249
256 retval(0) = octave_value (fact.L (), 250 }
257 MatrixType (MatrixType::Lower)); 251
258 } 252 }
259 break; 253 else
260 254 {
261 case 4: 255
262 default:
263 {
264 SparseLU fact (m, thres, scale); 256 SparseLU fact (m, thres, scale);
265 257
266 if (scale) 258 if (scale)
267 retval(4) = fact.R (); 259 retval(4) = fact.R ();
268 260
278 } 270 }
279 retval(1) = octave_value (fact.U (), 271 retval(1) = octave_value (fact.U (),
280 MatrixType (MatrixType::Upper)); 272 MatrixType (MatrixType::Upper));
281 retval(0) = octave_value (fact.L (), 273 retval(0) = octave_value (fact.L (),
282 MatrixType (MatrixType::Lower)); 274 MatrixType (MatrixType::Lower));
283 } 275 }
284 break; 276
285 }
286 } 277 }
287 else if (arg.is_complex_type ()) 278 else if (arg.is_complex_type ())
288 { 279 {
289 SparseComplexMatrix m = arg.sparse_complex_matrix_value (); 280 SparseComplexMatrix m = arg.sparse_complex_matrix_value ();
290 281
291 switch (nargout) 282 if ( nargout < 4 )
292 { 283 {
293 case 0: 284
294 case 1: 285 ColumnVector Qinit;
295 case 2: 286 Qinit.resize (nc);
296 { 287 for (octave_idx_type i = 0; i < nc; i++)
297 SparseComplexLU fact (m, Qinit, thres, false, true); 288 Qinit (i) = i;
298 289 SparseComplexLU fact (m, Qinit, thres, false, true);
299 if (nargout < 2) 290
291 if ( nargout < 2 )
292
300 retval(0) = fact.Y (); 293 retval(0) = fact.Y ();
301 else 294
302 { 295 else
303 PermMatrix P = fact.Pr_mat (); 296 {
304 SparseComplexMatrix L = P.transpose () * fact.L (); 297
305 retval(1) = octave_value (fact.U (), 298 retval(1)
306 MatrixType (MatrixType::Upper)); 299 = octave_value (
307 300 fact.U () * fact.Pc_mat ().transpose (),
308 retval(0) 301 MatrixType (MatrixType::Permuted_Upper,
309 = octave_value (L, MatrixType (MatrixType::Permuted_Lower, 302 nc, fact.col_perm ()));
310 nr, fact.row_perm ())); 303
311 } 304 PermMatrix P = fact.Pr_mat ();
312 } 305 SparseComplexMatrix L = fact.L ();
313 break; 306 if ( nargout < 3 )
314 307 retval(0)
315 case 3: 308 = octave_value ( P.transpose () * L,
316 { 309 MatrixType (MatrixType::Permuted_Lower,
317 SparseComplexLU fact (m, Qinit, thres, false, true); 310 nr, fact.row_perm ()));
318 311 else
319 if (vecout) 312 {
320 retval(2) = fact.Pr_vec (); 313 retval(0) = L;
321 else 314 if ( vecout )
322 retval(2) = fact.Pr_mat (); 315 retval(2) = fact.Pr_vec();
323 316 else
324 retval(1) = octave_value (fact.U (), 317 retval(2) = P;
325 MatrixType (MatrixType::Upper)); 318 }
326 retval(0) = octave_value (fact.L (), 319
327 MatrixType (MatrixType::Lower)); 320 }
328 } 321
329 break; 322 }
330 323 else
331 case 4: 324 {
332 default: 325
333 {
334 SparseComplexLU fact (m, thres, scale); 326 SparseComplexLU fact (m, thres, scale);
335 327
336 if (scale) 328 if (scale)
337 retval(4) = fact.R (); 329 retval(4) = fact.R ();
338 330
348 } 340 }
349 retval(1) = octave_value (fact.U (), 341 retval(1) = octave_value (fact.U (),
350 MatrixType (MatrixType::Upper)); 342 MatrixType (MatrixType::Upper));
351 retval(0) = octave_value (fact.L (), 343 retval(0) = octave_value (fact.L (),
352 MatrixType (MatrixType::Lower)); 344 MatrixType (MatrixType::Lower));
353 } 345 }
354 break; 346
355 }
356 } 347 }
357 else 348 else
358 gripe_wrong_type_arg ("lu", arg); 349 gripe_wrong_type_arg ("lu", arg);
359 } 350 }
360 else 351 else
580 %! assert (u, single ([5, 6; 0, 4/5]), sqrt (eps ("single"))); 571 %! assert (u, single ([5, 6; 0, 4/5]), sqrt (eps ("single")));
581 %! assert (p(:,:), single ([0, 0, 1; 1, 0, 0; 0 1 0]), sqrt (eps ("single"))); 572 %! assert (p(:,:), single ([0, 0, 1; 1, 0, 0; 0 1 0]), sqrt (eps ("single")));
582 573
583 %!error lu () 574 %!error lu ()
584 %!error <can not define pivoting threshold> lu ([1, 2; 3, 4], 2) 575 %!error <can not define pivoting threshold> lu ([1, 2; 3, 4], 2)
576
577 %!test
578 %! Bi = [1 2 3 4 5 2 3 6 7 8 4 5 7 8 9];
579 %! Bj = [1 3 4 5 6 7 8 9 11 12 13 14 15 16 17];
580 %! Bv = [1 1 1 1 1 1 -1 1 1 1 1 -1 1 -1 1];
581 %! B = sparse (Bi,Bj,Bv);
582 %! [L,U] = lu (B);
583 %! assert (nnz (B - L*U) == 0);
584 %! [L,U,P] = lu(B);
585 %! assert (nnz (B - P'*L*U) == 0);
586 %! [L,U,P,Q] = lu (B);
587 %! assert (nnz (B - P'*L*U*Q') == 0);
588
585 */ 589 */
586 590
587 static 591 static
588 bool check_lu_dims (const octave_value& l, const octave_value& u, 592 bool check_lu_dims (const octave_value& l, const octave_value& u,
589 const octave_value& p) 593 const octave_value& p)