comparison liboctave/UMFPACK/UMFPACK/MATLAB/umfpackmex.c @ 5164:57077d0ddc8e

[project @ 2005-02-25 19:55:24 by jwe]
author jwe
date Fri, 25 Feb 2005 19:55:28 +0000
parents
children
comparison
equal deleted inserted replaced
5163:9f3299378193 5164:57077d0ddc8e
1 /* ========================================================================== */
2 /* === UMFPACK mexFunction ================================================== */
3 /* ========================================================================== */
4
5 /* -------------------------------------------------------------------------- */
6 /* UMFPACK Version 4.4, Copyright (c) 2005 by Timothy A. Davis. CISE Dept, */
7 /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */
8 /* web: http://www.cise.ufl.edu/research/sparse/umfpack */
9 /* -------------------------------------------------------------------------- */
10
11 /*
12 MATLAB interface for umfpack.
13
14 Factor or solve a sparse linear system, returning either the solution
15 x to Ax=b or A'x'=b', or the factorization LU=P(R\A)Q or LU=PAQ. A must be
16 sparse, with nonzero dimensions, but it may be complex, singular, and/or
17 rectangular. b must be a dense n-by-1 vector (real or complex).
18 L is unit lower triangular, U is upper triangular, and R is diagonal.
19 P and Q are permutation matrices (permutations of an identity matrix).
20
21 The matrix A is scaled, by default. Each row i is divided by r (i), where
22 r (i) is the sum of the absolute values of the entries in that row. The
23 scaled matrix has an infinity norm of 1. The scale factors r (i) are
24 returned in a diagonal sparse matrix. If the factorization is:
25
26 [L, U, P, Q, R] = umfpack (A) ;
27
28 then the factorization is
29
30 L*U = P * (R \ A) * Q
31
32 This is safer than returning a matrix R such that L*U = P*R*A*Q, because
33 it avoids the division by small entries. If r(i) is subnormal, multiplying
34 by 1/r(i) would result in an IEEE Infinity, but dividing by r(i) is safe.
35
36 The factorization
37
38 [L, U, P, Q] = umfpack (A) ;
39
40 returns LU factors such that L*U = P*A*Q, with no scaling.
41
42 See umfpack.m, umfpack_details.m, and umfpack.h for details.
43
44 Note that this mexFunction accesses only the user-callable UMFPACK routines.
45 Thus, is also provides another example of how user C code can access
46 UMFPACK.
47
48 If NO_TRANSPOSE_FORWARD_SLASH is not defined at compile time, then the
49 forward slash (/) operator acts almost like x = b/A in MATLAB 6.1. It is
50 solved by factorizing the array transpose, and then x = (A.'\b.').' is
51 solved. This is the default behavior (for historical reasons), since
52 factorizing A can behave perform much differently than factorizing its
53 transpose.
54
55 If NO_TRANSPOSE_FORWARD_SLASH is defined at compile time, then the forward
56 slash operator does not act like x=b/A in MATLAB 6.1. It is solved by
57 factorizing A, and then solving via the transposed L and U matrices.
58 The solution is still x = (A.'\b.').', except that A is factorized instead
59 of A.'.
60
61 Modified for v4.3.1, Jan 10, 2005: default has been changed to
62 NO_TRANSPOSE_FORWARD_SLASH, to test iterative refinement for b/A.
63 v4.4: added method for computing the determinant.
64 */
65 #define NO_TRANSPOSE_FORWARD_SLASH /* default has changed for v4.3.1 */
66
67 #include "umfpack.h"
68 #include "mex.h"
69 #include "matrix.h"
70 #include <string.h>
71 #include <math.h>
72 #include <float.h>
73
74 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
75 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
76 #define STRING_MATCH(s1,s2) (strcmp ((s1), (s2)) == 0)
77 #ifndef TRUE
78 #define TRUE (1)
79 #endif
80 #ifndef FALSE
81 #define FALSE (0)
82 #endif
83
84 /* ========================================================================== */
85 /* === error ================================================================ */
86 /* ========================================================================== */
87
88 /* Return an error message */
89
90 static void error
91 (
92 char *s,
93 int A_is_complex,
94 int nargout,
95 mxArray *pargout [ ],
96 double Control [UMFPACK_CONTROL],
97 double Info [UMFPACK_INFO],
98 int status,
99 int do_info
100 )
101 {
102 int i ;
103 double *OutInfo ;
104 if (A_is_complex)
105 {
106 umfpack_zi_report_status (Control, status) ;
107 umfpack_zi_report_info (Control, Info) ;
108 }
109 else
110 {
111 umfpack_di_report_status (Control, status) ;
112 umfpack_di_report_info (Control, Info) ;
113 }
114 if (do_info > 0)
115 {
116 /* return Info */
117 pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
118 OutInfo = mxGetPr (pargout [do_info]) ;
119 for (i = 0 ; i < UMFPACK_INFO ; i++)
120 {
121 OutInfo [i] = Info [i] ;
122 }
123 }
124 mexErrMsgTxt (s) ;
125 }
126
127
128 /* ========================================================================== */
129 /* === UMFPACK ============================================================== */
130 /* ========================================================================== */
131
132 void mexFunction
133 (
134 int nargout, /* number of outputs */
135 mxArray *pargout [ ], /* output arguments */
136 int nargin, /* number of inputs */
137 const mxArray *pargin [ ] /* input arguments */
138 )
139 {
140
141 /* ---------------------------------------------------------------------- */
142 /* local variables */
143 /* ---------------------------------------------------------------------- */
144
145 double Info [UMFPACK_INFO], Control [UMFPACK_CONTROL], dx, dz, dexp ;
146 double *Lx, *Lz, *Ux, *Uz, *Ax, *Az, *Bx, *Bz, *Xx, *Xz, *User_Control,
147 *p, *q, *OutInfo, *p1, *p2, *p3, *p4, *Ltx, *Ltz, *Rs, *Px, *Qx ;
148 void *Symbolic, *Numeric ;
149 int *Lp, *Li, *Up, *Ui, *Ap, *Ai, *P, *Q, do_solve, lnz, unz, nn, i,
150 transpose, size, do_info, do_numeric, *Front_npivcol, op, k, *Rp, *Ri,
151 *Front_parent, *Chain_start, *Chain_maxrows, *Chain_maxcols, nz, status,
152 nfronts, nchains, *Ltp, *Ltj, *Qinit, print_level, status2, no_scale,
153 *Front_1strow, *Front_leftmostdesc, n_row, n_col, n_inner, sys,
154 ignore1, ignore2, ignore3, A_is_complex, B_is_complex, X_is_complex,
155 *Pp, *Pi, *Qp, *Qi, do_recip, do_det ;
156 mxArray *Amatrix, *Bmatrix, *User_Control_matrix, *User_Qinit ;
157 char *operator, *operation ;
158 mxComplexity Atype, Xtype ;
159 char warning [200] ;
160
161 #ifndef NO_TRANSPOSE_FORWARD_SLASH
162 int *Cp, *Ci ;
163 double *Cx, *Cz ;
164 #endif
165
166 /* ---------------------------------------------------------------------- */
167 /* get inputs A, b, and the operation to perform */
168 /* ---------------------------------------------------------------------- */
169
170 User_Control_matrix = (mxArray *) NULL ;
171 User_Qinit = (mxArray *) NULL ;
172
173 do_info = 0 ;
174 do_solve = FALSE ;
175 do_numeric = TRUE ;
176 transpose = FALSE ;
177 no_scale = FALSE ;
178 do_det = FALSE ;
179
180 /* find the operator */
181 op = 0 ;
182 for (i = 0 ; i < nargin ; i++)
183 {
184 if (mxIsChar (pargin [i]))
185 {
186 op = i ;
187 break ;
188 }
189 }
190
191 if (op > 0)
192 {
193 operator = mxArrayToString (pargin [op]) ;
194
195 if (STRING_MATCH (operator, "\\"))
196 {
197
198 /* -------------------------------------------------------------- */
199 /* matrix left divide, x = A\b */
200 /* -------------------------------------------------------------- */
201
202 /*
203 [x, Info] = umfpack (A, '\', b) ;
204 [x, Info] = umfpack (A, '\', b, Control) ;
205 [x, Info] = umfpack (A, Qinit, '\', b, Control) ;
206 [x, Info] = umfpack (A, Qinit, '\', b) ;
207 */
208
209 operation = "x = A\\b" ;
210 do_solve = TRUE ;
211 Amatrix = (mxArray *) pargin [0] ;
212 Bmatrix = (mxArray *) pargin [op+1] ;
213
214 if (nargout == 2)
215 {
216 do_info = 1 ;
217 }
218 if (op == 2)
219 {
220 User_Qinit = (mxArray *) pargin [1] ;
221 }
222 if ((op == 1 && nargin == 4) || (op == 2 && nargin == 5))
223 {
224 User_Control_matrix = (mxArray *) pargin [nargin-1] ;
225 }
226 if (nargin < 3 || nargin > 5 || nargout > 2)
227 {
228 mexErrMsgTxt ("wrong number of arguments") ;
229 }
230
231 }
232 else if (STRING_MATCH (operator, "/"))
233 {
234
235 /* -------------------------------------------------------------- */
236 /* matrix right divide, x = b/A */
237 /* -------------------------------------------------------------- */
238
239 /*
240 [x, Info] = umfpack (b, '/', A) ;
241 [x, Info] = umfpack (b, '/', A, Control) ;
242 [x, Info] = umfpack (b, '/', A, Qinit) ;
243 [x, Info] = umfpack (b, '/', A, Qinit, Control) ;
244 */
245
246 operation = "x = b/A" ;
247 do_solve = TRUE ;
248 transpose = TRUE ;
249 Amatrix = (mxArray *) pargin [2] ;
250 Bmatrix = (mxArray *) pargin [0] ;
251
252 if (nargout == 2)
253 {
254 do_info = 1 ;
255 }
256 if (nargin == 5)
257 {
258 User_Qinit = (mxArray *) pargin [3] ;
259 User_Control_matrix = (mxArray *) pargin [4] ;
260 }
261 else if (nargin == 4)
262 {
263 /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
264 if (mxGetM (pargin [3]) == 1)
265 {
266 User_Qinit = (mxArray *) pargin [3] ;
267 }
268 else
269 {
270 User_Control_matrix = (mxArray *) pargin [3] ;
271 }
272 }
273 else if (nargin < 3 || nargin > 5 || nargout > 2)
274 {
275 mexErrMsgTxt ("wrong number of arguments") ;
276 }
277
278 }
279 else if (STRING_MATCH (operator, "symbolic"))
280 {
281
282 /* -------------------------------------------------------------- */
283 /* symbolic factorization only */
284 /* -------------------------------------------------------------- */
285
286 /*
287 [P Q Fr Ch Info] = umfpack (A, 'symbolic') ;
288 [P Q Fr Ch Info] = umfpack (A, 'symbolic', Control) ;
289 [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic') ;
290 [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic', Control) ;
291 */
292
293 operation = "symbolic factorization" ;
294 do_numeric = FALSE ;
295 Amatrix = (mxArray *) pargin [0] ;
296
297 if (nargout == 5)
298 {
299 do_info = 4 ;
300 }
301 if (op == 2)
302 {
303 User_Qinit = (mxArray *) pargin [1] ;
304 }
305 if ((op == 1 && nargin == 3) || (op == 2 && nargin == 4))
306 {
307 User_Control_matrix = (mxArray *) pargin [nargin-1] ;
308 }
309 if (nargin < 2 || nargin > 4 || nargout > 5 || nargout < 4)
310 {
311 mexErrMsgTxt ("wrong number of arguments") ;
312 }
313
314 }
315 else if (STRING_MATCH (operator, "det"))
316 {
317
318 /* -------------------------------------------------------------- */
319 /* compute the determinant */
320 /* -------------------------------------------------------------- */
321
322 /*
323 * [det] = umfpack (A, 'det') ;
324 * [dmantissa dexp] = umfpack (A, 'det') ;
325 */
326
327 operation = "determinant" ;
328 do_det = TRUE ;
329 Amatrix = (mxArray *) pargin [0] ;
330 if (nargin > 2 || nargout > 2)
331 {
332 mexErrMsgTxt ("wrong number of arguments") ;
333 }
334
335 }
336 else
337 {
338 mexErrMsgTxt ("operator must be '/', '\\', or 'symbolic'") ;
339 }
340 mxFree (operator) ;
341
342 }
343 else if (nargin > 0)
344 {
345
346 /* ------------------------------------------------------------------ */
347 /* LU factorization */
348 /* ------------------------------------------------------------------ */
349
350 /*
351 with scaling:
352 [L, U, P, Q, R, Info] = umfpack (A) ;
353 [L, U, P, Q, R, Info] = umfpack (A, Qinit) ;
354
355 scaling determined by Control settings:
356 [L, U, P, Q, R, Info] = umfpack (A, Control) ;
357 [L, U, P, Q, R, Info] = umfpack (A, Qinit, Control) ;
358
359 with no scaling:
360 [L, U, P, Q] = umfpack (A) ;
361 [L, U, P, Q] = umfpack (A, Control) ;
362 [L, U, P, Q] = umfpack (A, Qinit) ;
363 [L, U, P, Q] = umfpack (A, Qinit, Control) ;
364 */
365
366 operation = "numeric factorization" ;
367 Amatrix = (mxArray *) pargin [0] ;
368
369 no_scale = nargout <= 4 ;
370
371 if (nargout == 6)
372 {
373 do_info = 5 ;
374 }
375 if (nargin == 3)
376 {
377 User_Qinit = (mxArray *) pargin [1] ;
378 User_Control_matrix = (mxArray *) pargin [2] ;
379 }
380 else if (nargin == 2)
381 {
382 /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
383 if (mxGetM (pargin [1]) == 1)
384 {
385 User_Qinit = (mxArray *) pargin [1] ;
386 }
387 else
388 {
389 User_Control_matrix = (mxArray *) pargin [1] ;
390 }
391 }
392 else if (nargin > 3 || nargout > 6 || nargout < 4)
393 {
394 mexErrMsgTxt ("wrong number of arguments") ;
395 }
396
397 }
398 else
399 {
400
401 /* ------------------------------------------------------------------ */
402 /* return default control settings */
403 /* ------------------------------------------------------------------ */
404
405 /*
406 Control = umfpack ;
407 umfpack ;
408 */
409
410 if (nargout > 1)
411 {
412 mexErrMsgTxt ("wrong number of arguments") ;
413 }
414
415 pargout [0] = mxCreateDoubleMatrix (UMFPACK_CONTROL, 1, mxREAL) ;
416 User_Control = mxGetPr (pargout [0]) ;
417 umfpack_di_defaults (User_Control) ;
418
419 return ;
420 }
421
422 /* ---------------------------------------------------------------------- */
423 /* check inputs */
424 /* ---------------------------------------------------------------------- */
425
426 if (mxGetNumberOfDimensions (Amatrix) != 2)
427 {
428 mexErrMsgTxt ("input matrix A must be 2-dimensional") ;
429 }
430 n_row = mxGetM (Amatrix) ;
431 n_col = mxGetN (Amatrix) ;
432 nn = MAX (n_row, n_col) ;
433 n_inner = MIN (n_row, n_col) ;
434 if (do_solve && n_row != n_col)
435 {
436 mexErrMsgTxt ("input matrix A must square for '\\' or '/'") ;
437 }
438 if (!mxIsSparse (Amatrix))
439 {
440 mexErrMsgTxt ("input matrix A must be sparse") ;
441 }
442 if (n_row == 0 || n_col == 0)
443 {
444 mexErrMsgTxt ("input matrix A cannot have zero rows or zero columns") ;
445 }
446
447 /* The real/complex status of A determines which version to use, */
448 /* (umfpack_di_* or umfpack_zi_*). */
449 A_is_complex = mxIsComplex (Amatrix) ;
450 Atype = A_is_complex ? mxCOMPLEX : mxREAL ;
451 Ap = mxGetJc (Amatrix) ;
452 Ai = mxGetIr (Amatrix) ;
453 Ax = mxGetPr (Amatrix) ;
454 Az = mxGetPi (Amatrix) ;
455
456 if (do_solve)
457 {
458
459 if (n_row != n_col)
460 {
461 mexErrMsgTxt ("A must be square for \\ or /") ;
462 }
463 if (transpose)
464 {
465 if (mxGetM (Bmatrix) != 1 || mxGetN (Bmatrix) != nn)
466 {
467 mexErrMsgTxt ("b has the wrong dimensions") ;
468 }
469 }
470 else
471 {
472 if (mxGetM (Bmatrix) != nn || mxGetN (Bmatrix) != 1)
473 {
474 mexErrMsgTxt ("b has the wrong dimensions") ;
475 }
476 }
477 if (mxGetNumberOfDimensions (Bmatrix) != 2)
478 {
479 mexErrMsgTxt ("input matrix b must be 2-dimensional") ;
480 }
481 if (mxIsSparse (Bmatrix))
482 {
483 mexErrMsgTxt ("input matrix b cannot be sparse") ;
484 }
485 if (mxGetClassID (Bmatrix) != mxDOUBLE_CLASS)
486 {
487 mexErrMsgTxt ("input matrix b must double precision matrix") ;
488 }
489
490 B_is_complex = mxIsComplex (Bmatrix) ;
491 Bx = mxGetPr (Bmatrix) ;
492 Bz = mxGetPi (Bmatrix) ;
493
494 X_is_complex = A_is_complex || B_is_complex ;
495 Xtype = X_is_complex ? mxCOMPLEX : mxREAL ;
496 }
497
498 /* ---------------------------------------------------------------------- */
499 /* set the Control parameters */
500 /* ---------------------------------------------------------------------- */
501
502 if (A_is_complex)
503 {
504 umfpack_zi_defaults (Control) ;
505 }
506 else
507 {
508 umfpack_di_defaults (Control) ;
509 }
510 if (User_Control_matrix)
511 {
512 if (mxGetClassID (User_Control_matrix) != mxDOUBLE_CLASS ||
513 mxIsSparse (User_Control_matrix))
514 {
515 mexErrMsgTxt ("Control must be a dense real matrix") ;
516 }
517 size = UMFPACK_CONTROL ;
518 size = MIN (size, mxGetNumberOfElements (User_Control_matrix)) ;
519 User_Control = mxGetPr (User_Control_matrix) ;
520 for (i = 0 ; i < size ; i++)
521 {
522 Control [i] = User_Control [i] ;
523 }
524 }
525
526 if (no_scale)
527 {
528 /* turn off scaling for [L, U, P, Q] = umfpack (A) ;
529 * ignoring the input value of Control (24) for the usage
530 * [L, U, P, Q] = umfpack (A, Control) ; */
531 Control [UMFPACK_SCALE] = UMFPACK_SCALE_NONE ;
532 }
533
534 if (mxIsNaN (Control [UMFPACK_PRL]))
535 {
536 print_level = UMFPACK_DEFAULT_PRL ;
537 }
538 else
539 {
540 print_level = (int) Control [UMFPACK_PRL] ;
541 }
542
543 Control [UMFPACK_PRL] = print_level ;
544
545 /* ---------------------------------------------------------------------- */
546 /* get Qinit, if present */
547 /* ---------------------------------------------------------------------- */
548
549 if (User_Qinit)
550 {
551 if (mxGetM (User_Qinit) != 1 || mxGetN (User_Qinit) != n_col)
552 {
553 mexErrMsgTxt ("Qinit must be 1-by-n_col") ;
554 }
555 if (mxGetNumberOfDimensions (User_Qinit) != 2)
556 {
557 mexErrMsgTxt ("input Qinit must be 2-dimensional") ;
558 }
559 if (mxIsComplex (User_Qinit))
560 {
561 mexErrMsgTxt ("input Qinit must not be complex") ;
562 }
563 if (mxGetClassID (User_Qinit) != mxDOUBLE_CLASS)
564 {
565 mexErrMsgTxt ("input Qinit must be a double matrix") ;
566 }
567 if (mxIsSparse (User_Qinit))
568 {
569 mexErrMsgTxt ("input Qinit must be dense") ;
570 }
571 Qinit = (int *) mxMalloc (n_col * sizeof (int)) ;
572 p = mxGetPr (User_Qinit) ;
573 for (k = 0 ; k < n_col ; k++)
574 {
575 /* convert from 1-based to 0-based indexing */
576 Qinit [k] = ((int) (p [k])) - 1 ;
577 }
578
579 }
580 else
581 {
582 /* umfpack_*_qsymbolic will call colamd to get Qinit. This is the */
583 /* same as calling umfpack_*_symbolic with Qinit set to NULL*/
584 Qinit = (int *) NULL ;
585 }
586
587 /* ---------------------------------------------------------------------- */
588 /* report the inputs A and Qinit */
589 /* ---------------------------------------------------------------------- */
590
591 if (print_level >= 2)
592 {
593 /* print the operation */
594 mexPrintf ("\numfpack: %s\n", operation) ;
595 }
596
597 if (A_is_complex)
598 {
599 umfpack_zi_report_control (Control) ;
600 if (print_level >= 3) mexPrintf ("\nA: ") ;
601 (void) umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az,
602 1, Control) ;
603 if (Qinit)
604 {
605 if (print_level >= 3) mexPrintf ("\nQinit: ") ;
606 (void) umfpack_zi_report_perm (n_col, Qinit, Control) ;
607 }
608 }
609 else
610 {
611 umfpack_di_report_control (Control) ;
612 if (print_level >= 3) mexPrintf ("\nA: ") ;
613 (void) umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax,
614 1, Control) ;
615 if (Qinit)
616 {
617 if (print_level >= 3) mexPrintf ("\nQinit: ") ;
618 (void) umfpack_di_report_perm (n_col, Qinit, Control) ;
619 }
620 }
621
622 #ifndef NO_TRANSPOSE_FORWARD_SLASH
623 /* ---------------------------------------------------------------------- */
624 /* create the array transpose for x = b/A */
625 /* ---------------------------------------------------------------------- */
626
627 if (transpose)
628 {
629 /* note that in this case A will be square (nn = n_row = n_col) */
630 /* x = (A.'\b.').' will be computed */
631
632 /* make sure Ci and Cx exist, avoid malloc of zero-sized arrays. */
633 nz = MAX (Ap [nn], 1) ;
634
635 Cp = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
636 Ci = (int *) mxMalloc (nz * sizeof (int)) ;
637 Cx = (double *) mxMalloc (nz * sizeof (double)) ;
638 if (A_is_complex)
639 {
640 Cz = (double *) mxMalloc (nz * sizeof (double)) ;
641 status = umfpack_zi_transpose (nn, nn, Ap, Ai, Ax, Az,
642 (int *) NULL, (int *) NULL, Cp, Ci, Cx, Cz, FALSE) ;
643 }
644 else
645 {
646 status = umfpack_di_transpose (nn, nn, Ap, Ai, Ax,
647 (int *) NULL, (int *) NULL, Cp, Ci, Cx) ;
648 }
649
650 if (status != UMFPACK_OK)
651 {
652 error ("transpose of A failed", A_is_complex, nargout, pargout,
653 Control, Info, status, do_info);
654 return ;
655 }
656
657 /* modify pointers so that C will be factorized and solved, not A */
658 Ap = Cp ;
659 Ai = Ci ;
660 Ax = Cx ;
661 if (A_is_complex)
662 {
663 Az = Cz ;
664 }
665 }
666 #endif
667
668 /* ---------------------------------------------------------------------- */
669 /* perform the symbolic factorization */
670 /* ---------------------------------------------------------------------- */
671
672 if (A_is_complex)
673 {
674 status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az,
675 Qinit, &Symbolic, Control, Info) ;
676 }
677 else
678 {
679 status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax,
680 Qinit, &Symbolic, Control, Info) ;
681 }
682
683 if (Qinit)
684 {
685 mxFree (Qinit) ;
686 }
687
688 if (status < 0)
689 {
690 error ("symbolic factorization failed", A_is_complex, nargout, pargout,
691 Control, Info, status, do_info) ;
692 return ;
693 }
694
695 /* ---------------------------------------------------------------------- */
696 /* report the Symbolic object */
697 /* ---------------------------------------------------------------------- */
698
699 if (A_is_complex)
700 {
701 (void) umfpack_zi_report_symbolic (Symbolic, Control) ;
702 }
703 else
704 {
705 (void) umfpack_di_report_symbolic (Symbolic, Control) ;
706 }
707
708 /* ---------------------------------------------------------------------- */
709 /* perform numeric factorization, or just return symbolic factorization */
710 /* ---------------------------------------------------------------------- */
711
712 if (do_numeric)
713 {
714
715 /* ------------------------------------------------------------------ */
716 /* perform the numeric factorization */
717 /* ------------------------------------------------------------------ */
718
719 if (A_is_complex)
720 {
721 status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
722 Control, Info) ;
723 }
724 else
725 {
726 status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric,
727 Control, Info) ;
728 }
729
730 /* ------------------------------------------------------------------ */
731 /* free the symbolic factorization */
732 /* ------------------------------------------------------------------ */
733
734 if (A_is_complex)
735 {
736 umfpack_zi_free_symbolic (&Symbolic) ;
737 }
738 else
739 {
740 umfpack_di_free_symbolic (&Symbolic) ;
741 }
742
743 /* ------------------------------------------------------------------ */
744 /* report the Numeric object */
745 /* ------------------------------------------------------------------ */
746
747 if (status < 0)
748 {
749 error ("numeric factorization failed", A_is_complex, nargout,
750 pargout, Control, Info, status, do_info);
751 return ;
752 }
753
754 if (A_is_complex)
755 {
756 (void) umfpack_zi_report_numeric (Numeric, Control) ;
757 }
758 else
759 {
760 (void) umfpack_di_report_numeric (Numeric, Control) ;
761 }
762
763 /* ------------------------------------------------------------------ */
764 /* return the solution, determinant, or the factorization */
765 /* ------------------------------------------------------------------ */
766
767 if (do_solve)
768 {
769 /* -------------------------------------------------------------- */
770 /* solve Ax=b or A'x'=b', and return just the solution x */
771 /* -------------------------------------------------------------- */
772
773 #ifndef NO_TRANSPOSE_FORWARD_SLASH
774 if (transpose)
775 {
776 /* A.'x.'=b.' gives the same x=b/A as solving A'x'=b' */
777 /* since C=A.' was factorized, solve with sys = UMFPACK_A */
778 /* since x and b are vectors, x.' and b.' are implicit */
779 pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
780 }
781 else
782 {
783 pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
784 }
785 sys = UMFPACK_A ;
786 #else
787 if (transpose)
788 {
789 /* If A is real, A'x=b is the same as A.'x=b. */
790 /* x and b are vectors, so x and b are the same as x' and b'. */
791 /* If A is complex, then A.'x.'=b.' gives the same solution x */
792 /* as the complex conjugate transpose. If we used the A'x=b */
793 /* option in umfpack_*_solve, we would have to form b' on */
794 /* input and x' on output (negating the imaginary part). */
795 /* We can save this work by just using the A.'x=b option in */
796 /* umfpack_*_solve. Then, forming x.' and b.' is implicit, */
797 /* since x and b are just vectors anyway. */
798 /* In both cases, the system to solve is A.'x=b */
799 pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
800 sys = UMFPACK_Aat ;
801 }
802 else
803 {
804 pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
805 sys = UMFPACK_A ;
806 }
807 #endif
808
809 /* -------------------------------------------------------------- */
810 /* print the right-hand-side, B */
811 /* -------------------------------------------------------------- */
812
813 if (print_level >= 3) mexPrintf ("\nright-hand side, b: ") ;
814 if (B_is_complex)
815 {
816 (void) umfpack_zi_report_vector (nn, Bx, Bz, Control) ;
817 }
818 else
819 {
820 (void) umfpack_di_report_vector (nn, Bx, Control) ;
821 }
822
823 /* -------------------------------------------------------------- */
824 /* solve the system */
825 /* -------------------------------------------------------------- */
826
827 Xx = mxGetPr (pargout [0]) ;
828 Xz = mxGetPi (pargout [0]) ;
829 status2 = UMFPACK_OK ;
830
831 if (A_is_complex)
832 {
833 if (!B_is_complex)
834 {
835 /* umfpack_zi_solve expects a complex B */
836 Bz = (double *) mxCalloc (nn, sizeof (double)) ;
837 }
838 status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz,
839 Numeric, Control, Info) ;
840 if (!B_is_complex)
841 {
842 mxFree (Bz) ;
843 }
844 }
845 else
846 {
847 if (B_is_complex)
848 {
849 /* Ax=b when b is complex and A is sparse can be split */
850 /* into two systems, A*xr=br and A*xi=bi, where r denotes */
851 /* the real part and i the imaginary part of x and b. */
852 status2 = umfpack_di_solve (sys, Ap, Ai, Ax, Xz, Bz,
853 Numeric, Control, Info) ;
854 }
855 status = umfpack_di_solve (sys, Ap, Ai, Ax, Xx, Bx,
856 Numeric, Control, Info) ;
857 }
858
859 #ifndef NO_TRANSPOSE_FORWARD_SLASH
860 /* -------------------------------------------------------------- */
861 /* free the transposed matrix C */
862 /* -------------------------------------------------------------- */
863
864 if (transpose)
865 {
866 mxFree (Cp) ;
867 mxFree (Ci) ;
868 mxFree (Cx) ;
869 if (A_is_complex)
870 {
871 mxFree (Cz) ;
872 }
873 }
874 #endif
875
876 /* -------------------------------------------------------------- */
877 /* free the Numeric object */
878 /* -------------------------------------------------------------- */
879
880 if (A_is_complex)
881 {
882 umfpack_zi_free_numeric (&Numeric) ;
883 }
884 else
885 {
886 umfpack_di_free_numeric (&Numeric) ;
887 }
888
889 /* -------------------------------------------------------------- */
890 /* check error status */
891 /* -------------------------------------------------------------- */
892
893 if (status < 0 || status2 < 0)
894 {
895 mxDestroyArray (pargout [0]) ;
896 error ("solve failed", A_is_complex, nargout, pargout, Control,
897 Info, status, do_info) ;
898 return ;
899 }
900
901 /* -------------------------------------------------------------- */
902 /* print the solution, X */
903 /* -------------------------------------------------------------- */
904
905 if (print_level >= 3) mexPrintf ("\nsolution, x: ") ;
906 if (X_is_complex)
907 {
908 (void) umfpack_zi_report_vector (nn, Xx, Xz, Control) ;
909 }
910 else
911 {
912 (void) umfpack_di_report_vector (nn, Xx, Control) ;
913 }
914
915 /* -------------------------------------------------------------- */
916 /* warn about singular or near-singular matrices */
917 /* -------------------------------------------------------------- */
918
919 /* no warning is given if Control (1) is zero */
920
921 if (Control [UMFPACK_PRL] >= 1)
922 {
923 if (status == UMFPACK_WARNING_singular_matrix)
924 {
925 sprintf (warning, "matrix is singular\n"
926 "Try increasing Control (%d) and Control (%d).\n"
927 "(Suppress this warning with Control (%d) = 0.)\n",
928 1+UMFPACK_PIVOT_TOLERANCE,
929 1+UMFPACK_SYM_PIVOT_TOLERANCE,
930 1+UMFPACK_PRL) ;
931 mexWarnMsgTxt (warning) ;
932 }
933 else if (Info [UMFPACK_RCOND] < DBL_EPSILON)
934 {
935 sprintf (warning, "matrix is nearly singular, rcond = %g\n"
936 "Try increasing Control (%d) and Control (%d).\n"
937 "(Suppress this warning with Control (%d) = 0.)\n",
938 Info [UMFPACK_RCOND],
939 1+UMFPACK_PIVOT_TOLERANCE,
940 1+UMFPACK_SYM_PIVOT_TOLERANCE,
941 1+UMFPACK_PRL) ;
942 mexWarnMsgTxt (warning) ;
943 }
944 }
945
946 }
947 else if (do_det)
948 {
949
950 /* -------------------------------------------------------------- */
951 /* get the determinant */
952 /* -------------------------------------------------------------- */
953
954 if (nargout == 2)
955 {
956 /* [det dexp] = umfpack (A, 'det') ;
957 * return determinant in the form det * 10^dexp */
958 p = &dexp ;
959 }
960 else
961 {
962 /* [det] = umfpack (A, 'det') ;
963 * return determinant as a single scalar (overflow or
964 * underflow is much more likely) */
965 p = (double *) NULL ;
966 }
967 if (A_is_complex)
968 {
969 status = umfpack_zi_get_determinant (&dx, &dz, p,
970 Numeric, Info) ;
971 umfpack_zi_free_numeric (&Numeric) ;
972 }
973 else
974 {
975 status = umfpack_di_get_determinant (&dx, p,
976 Numeric, Info) ;
977 umfpack_di_free_numeric (&Numeric) ;
978 dz = 0 ;
979 }
980 if (status < 0)
981 {
982 error ("extracting LU factors failed", A_is_complex, nargout,
983 pargout, Control, Info, status, do_info) ;
984 }
985 if (A_is_complex)
986 {
987 pargout [0] = mxCreateDoubleMatrix (1, 1, mxCOMPLEX) ;
988 p = mxGetPr (pargout [0]) ;
989 *p = dx ;
990 p = mxGetPi (pargout [0]) ;
991 *p = dz ;
992 }
993 else
994 {
995 pargout [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
996 p = mxGetPr (pargout [0]) ;
997 *p = dx ;
998 }
999 if (nargout == 2)
1000 {
1001 pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
1002 p = mxGetPr (pargout [1]) ;
1003 *p = dexp ;
1004 }
1005
1006 }
1007 else
1008 {
1009
1010 /* -------------------------------------------------------------- */
1011 /* get L, U, P, Q, and r */
1012 /* -------------------------------------------------------------- */
1013
1014 if (A_is_complex)
1015 {
1016 status = umfpack_zi_get_lunz (&lnz, &unz, &ignore1, &ignore2,
1017 &ignore3, Numeric) ;
1018 }
1019 else
1020 {
1021 status = umfpack_di_get_lunz (&lnz, &unz, &ignore1, &ignore2,
1022 &ignore3, Numeric) ;
1023 }
1024
1025 if (status < 0)
1026 {
1027 if (A_is_complex)
1028 {
1029 umfpack_zi_free_numeric (&Numeric) ;
1030 }
1031 else
1032 {
1033 umfpack_di_free_numeric (&Numeric) ;
1034 }
1035 error ("extracting LU factors failed", A_is_complex, nargout,
1036 pargout, Control, Info, status, do_info) ;
1037 return ;
1038 }
1039
1040 /* avoid malloc of zero-sized arrays */
1041 lnz = MAX (lnz, 1) ;
1042 unz = MAX (unz, 1) ;
1043
1044 /* get temporary space, for the *** ROW *** form of L */
1045 Ltp = (int *) mxMalloc ((n_row+1) * sizeof (int)) ;
1046 Ltj = (int *) mxMalloc (lnz * sizeof (int)) ;
1047 Ltx = (double *) mxMalloc (lnz * sizeof (double)) ;
1048 if (A_is_complex)
1049 {
1050 Ltz = (double *) mxMalloc (lnz * sizeof (double)) ;
1051 }
1052 else
1053 {
1054 Ltz = (double *) NULL ;
1055 }
1056
1057 /* create permanent copy of the output matrix U */
1058 pargout [1] = mxCreateSparse (n_inner, n_col, unz, Atype) ;
1059 Up = mxGetJc (pargout [1]) ;
1060 Ui = mxGetIr (pargout [1]) ;
1061 Ux = mxGetPr (pargout [1]) ;
1062 Uz = mxGetPi (pargout [1]) ;
1063
1064 /* temporary space for the integer permutation vectors */
1065 P = (int *) mxMalloc (n_row * sizeof (int)) ;
1066 Q = (int *) mxMalloc (n_col * sizeof (int)) ;
1067
1068 /* get scale factors, if requested */
1069 status2 = UMFPACK_OK ;
1070 if (!no_scale)
1071 {
1072 /* create a diagonal sparse matrix for the scale factors */
1073 pargout [4] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
1074 Rp = mxGetJc (pargout [4]) ;
1075 Ri = mxGetIr (pargout [4]) ;
1076 for (i = 0 ; i < n_row ; i++)
1077 {
1078 Rp [i] = i ;
1079 Ri [i] = i ;
1080 }
1081 Rp [n_row] = n_row ;
1082 Rs = mxGetPr (pargout [4]) ;
1083 }
1084 else
1085 {
1086 Rs = (double *) NULL ;
1087 }
1088
1089 /* get Lt, U, P, Q, and Rs from the numeric object */
1090 if (A_is_complex)
1091 {
1092 status = umfpack_zi_get_numeric (Ltp, Ltj, Ltx, Ltz, Up, Ui, Ux,
1093 Uz, P, Q, (double *) NULL, (double *) NULL,
1094 &do_recip, Rs, Numeric) ;
1095 umfpack_zi_free_numeric (&Numeric) ;
1096 }
1097 else
1098 {
1099 status = umfpack_di_get_numeric (Ltp, Ltj, Ltx, Up, Ui,
1100 Ux, P, Q, (double *) NULL,
1101 &do_recip, Rs, Numeric) ;
1102 umfpack_di_free_numeric (&Numeric) ;
1103 }
1104
1105 /* for the mexFunction, -DNRECIPROCAL must be set,
1106 * so do_recip must be FALSE */
1107
1108 if (status < 0 || status2 < 0 || do_recip)
1109 {
1110 mxFree (Ltp) ;
1111 mxFree (Ltj) ;
1112 mxFree (Ltx) ;
1113 if (Ltz) mxFree (Ltz) ;
1114 mxFree (P) ;
1115 mxFree (Q) ;
1116 mxDestroyArray (pargout [1]) ;
1117 error ("extracting LU factors failed", A_is_complex, nargout,
1118 pargout, Control, Info, status, do_info) ;
1119 return ;
1120 }
1121
1122 /* create sparse permutation matrix for P */
1123 pargout [2] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
1124 Pp = mxGetJc (pargout [2]) ;
1125 Pi = mxGetIr (pargout [2]) ;
1126 Px = mxGetPr (pargout [2]) ;
1127 for (k = 0 ; k < n_row ; k++)
1128 {
1129 Pp [k] = k ;
1130 Px [k] = 1 ;
1131 Pi [P [k]] = k ;
1132 }
1133 Pp [n_row] = n_row ;
1134
1135 /* create sparse permutation matrix for Q */
1136 pargout [3] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
1137 Qp = mxGetJc (pargout [3]) ;
1138 Qi = mxGetIr (pargout [3]) ;
1139 Qx = mxGetPr (pargout [3]) ;
1140 for (k = 0 ; k < n_col ; k++)
1141 {
1142 Qp [k] = k ;
1143 Qx [k] = 1 ;
1144 Qi [k] = Q [k] ;
1145 }
1146 Qp [n_col] = n_col ;
1147
1148 /* permanent copy of L */
1149 pargout [0] = mxCreateSparse (n_row, n_inner, lnz, Atype) ;
1150 Lp = mxGetJc (pargout [0]) ;
1151 Li = mxGetIr (pargout [0]) ;
1152 Lx = mxGetPr (pargout [0]) ;
1153 Lz = mxGetPi (pargout [0]) ;
1154
1155 /* convert L from row form to column form */
1156 if (A_is_complex)
1157 {
1158 /* non-conjugate array transpose */
1159 status = umfpack_zi_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
1160 Ltz, (int *) NULL, (int *) NULL, Lp, Li, Lx, Lz, FALSE) ;
1161 }
1162 else
1163 {
1164 status = umfpack_di_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
1165 (int *) NULL, (int *) NULL, Lp, Li, Lx) ;
1166 }
1167
1168 mxFree (Ltp) ;
1169 mxFree (Ltj) ;
1170 mxFree (Ltx) ;
1171 if (Ltz) mxFree (Ltz) ;
1172
1173 if (status < 0)
1174 {
1175 mxFree (P) ;
1176 mxFree (Q) ;
1177 mxDestroyArray (pargout [0]) ;
1178 mxDestroyArray (pargout [1]) ;
1179 mxDestroyArray (pargout [2]) ;
1180 mxDestroyArray (pargout [3]) ;
1181 error ("constructing L failed", A_is_complex, nargout, pargout,
1182 Control, Info, status, do_info) ;
1183 return ;
1184 }
1185
1186 /* -------------------------------------------------------------- */
1187 /* print L, U, P, and Q */
1188 /* -------------------------------------------------------------- */
1189
1190 if (A_is_complex)
1191 {
1192 if (print_level >= 3) mexPrintf ("\nL: ") ;
1193 (void) umfpack_zi_report_matrix (n_row, n_inner, Lp, Li,
1194 Lx, Lz, 1, Control) ;
1195 if (print_level >= 3) mexPrintf ("\nU: ") ;
1196 (void) umfpack_zi_report_matrix (n_inner, n_col, Up, Ui,
1197 Ux, Uz, 1, Control) ;
1198 if (print_level >= 3) mexPrintf ("\nP: ") ;
1199 (void) umfpack_zi_report_perm (n_row, P, Control) ;
1200 if (print_level >= 3) mexPrintf ("\nQ: ") ;
1201 (void) umfpack_zi_report_perm (n_col, Q, Control) ;
1202 }
1203 else
1204 {
1205 if (print_level >= 3) mexPrintf ("\nL: ") ;
1206 (void) umfpack_di_report_matrix (n_row, n_inner, Lp, Li,
1207 Lx, 1, Control) ;
1208 if (print_level >= 3) mexPrintf ("\nU: ") ;
1209 (void) umfpack_di_report_matrix (n_inner, n_col, Up, Ui,
1210 Ux, 1, Control) ;
1211 if (print_level >= 3) mexPrintf ("\nP: ") ;
1212 (void) umfpack_di_report_perm (n_row, P, Control) ;
1213 if (print_level >= 3) mexPrintf ("\nQ: ") ;
1214 (void) umfpack_di_report_perm (n_col, Q, Control) ;
1215 }
1216
1217 mxFree (P) ;
1218 mxFree (Q) ;
1219
1220 }
1221
1222 }
1223 else
1224 {
1225
1226 /* ------------------------------------------------------------------ */
1227 /* return the symbolic factorization */
1228 /* ------------------------------------------------------------------ */
1229
1230 Q = (int *) mxMalloc (n_col * sizeof (int)) ;
1231 P = (int *) mxMalloc (n_row * sizeof (int)) ;
1232 Front_npivcol = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1233 Front_parent = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1234 Front_1strow = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1235 Front_leftmostdesc = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1236 Chain_start = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1237 Chain_maxrows = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1238 Chain_maxcols = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
1239
1240 if (A_is_complex)
1241 {
1242 status = umfpack_zi_get_symbolic (&ignore1, &ignore2, &ignore3,
1243 &nz, &nfronts, &nchains, P, Q, Front_npivcol,
1244 Front_parent, Front_1strow, Front_leftmostdesc,
1245 Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
1246 umfpack_zi_free_symbolic (&Symbolic) ;
1247 }
1248 else
1249 {
1250 status = umfpack_di_get_symbolic (&ignore1, &ignore2, &ignore3,
1251 &nz, &nfronts, &nchains, P, Q, Front_npivcol,
1252 Front_parent, Front_1strow, Front_leftmostdesc,
1253 Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
1254 umfpack_di_free_symbolic (&Symbolic) ;
1255 }
1256
1257 if (status < 0)
1258 {
1259 mxFree (P) ;
1260 mxFree (Q) ;
1261 mxFree (Front_npivcol) ;
1262 mxFree (Front_parent) ;
1263 mxFree (Front_1strow) ;
1264 mxFree (Front_leftmostdesc) ;
1265 mxFree (Chain_start) ;
1266 mxFree (Chain_maxrows) ;
1267 mxFree (Chain_maxcols) ;
1268 error ("extracting symbolic factors failed", A_is_complex, nargout,
1269 pargout, Control, Info, status, do_info) ;
1270 return ;
1271 }
1272
1273 /* create sparse permutation matrix for P */
1274 pargout [0] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
1275 Pp = mxGetJc (pargout [0]) ;
1276 Pi = mxGetIr (pargout [0]) ;
1277 Px = mxGetPr (pargout [0]) ;
1278 for (k = 0 ; k < n_row ; k++)
1279 {
1280 Pp [k] = k ;
1281 Px [k] = 1 ;
1282 Pi [P [k]] = k ;
1283 }
1284 Pp [n_row] = n_row ;
1285
1286 /* create sparse permutation matrix for Q */
1287 pargout [1] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
1288 Qp = mxGetJc (pargout [1]) ;
1289 Qi = mxGetIr (pargout [1]) ;
1290 Qx = mxGetPr (pargout [1]) ;
1291 for (k = 0 ; k < n_col ; k++)
1292 {
1293 Qp [k] = k ;
1294 Qx [k] = 1 ;
1295 Qi [k] = Q [k] ;
1296 }
1297 Qp [n_col] = n_col ;
1298
1299 /* create Fr */
1300 pargout [2] = mxCreateDoubleMatrix (nfronts+1, 4, mxREAL) ;
1301
1302 p1 = mxGetPr (pargout [2]) ;
1303 p2 = p1 + nfronts + 1 ;
1304 p3 = p2 + nfronts + 1 ;
1305 p4 = p3 + nfronts + 1 ;
1306 for (i = 0 ; i <= nfronts ; i++)
1307 {
1308 /* convert parent, 1strow, and leftmostdesc to 1-based */
1309 p1 [i] = (double) (Front_npivcol [i]) ;
1310 p2 [i] = (double) (Front_parent [i] + 1) ;
1311 p3 [i] = (double) (Front_1strow [i] + 1) ;
1312 p4 [i] = (double) (Front_leftmostdesc [i] + 1) ;
1313 }
1314
1315 /* create Ch */
1316 pargout [3] = mxCreateDoubleMatrix (nchains+1, 3, mxREAL) ;
1317 p1 = mxGetPr (pargout [3]) ;
1318 p2 = p1 + nchains + 1 ;
1319 p3 = p2 + nchains + 1 ;
1320 for (i = 0 ; i < nchains ; i++)
1321 {
1322 p1 [i] = (double) (Chain_start [i] + 1) ; /* convert to 1-based */
1323 p2 [i] = (double) (Chain_maxrows [i]) ;
1324 p3 [i] = (double) (Chain_maxcols [i]) ;
1325 }
1326 p1 [nchains] = Chain_start [nchains] + 1 ;
1327 p2 [nchains] = 0 ;
1328 p3 [nchains] = 0 ;
1329
1330 mxFree (P) ;
1331 mxFree (Q) ;
1332 mxFree (Front_npivcol) ;
1333 mxFree (Front_parent) ;
1334 mxFree (Front_1strow) ;
1335 mxFree (Front_leftmostdesc) ;
1336 mxFree (Chain_start) ;
1337 mxFree (Chain_maxrows) ;
1338 mxFree (Chain_maxcols) ;
1339 }
1340
1341 /* ---------------------------------------------------------------------- */
1342 /* report Info */
1343 /* ---------------------------------------------------------------------- */
1344
1345 if (A_is_complex)
1346 {
1347 umfpack_zi_report_info (Control, Info) ;
1348 }
1349 else
1350 {
1351 umfpack_di_report_info (Control, Info) ;
1352 }
1353
1354 if (do_info > 0)
1355 {
1356 /* return Info */
1357 pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
1358 OutInfo = mxGetPr (pargout [do_info]) ;
1359 for (i = 0 ; i < UMFPACK_INFO ; i++)
1360 {
1361 OutInfo [i] = Info [i] ;
1362 }
1363 }
1364 }