1 /*  testFactor.c  */
2 
3 #include "../FrontMtx.h"
4 #include "../../Drand.h"
5 #include "../../SymbFac.h"
6 #include "../../timings.h"
7 #include "../../misc.h"
8 
9 /*--------------------------------------------------------------------*/
10 
11 int
main(int argc,char * argv[])12 main ( int argc, char *argv[] )
13 /*
14    -----------------------------------------------------
15    test the factor method for a grid matrix
16    (1) read in an InpMtx object
17    (2) read in an ETree object
18    (3) create a solution matrix object
19    (4) multiply the solution with the matrix
20        to get a right hand side matrix object
21    (5) factor the matrix
22    (6) solve the system
23 
24    created -- 98sep05, cca
25    -----------------------------------------------------
26 */
27 {
28 char            *etreeFileName, *mtxFileName ;
29 Chv             *chv, *rootchv ;
30 ChvManager      *chvmanager ;
31 DenseMtx        *mtxB, *mtxX, *mtxZ ;
32 double          one[2] = { 1.0, 0.0 } ;
33 FrontMtx        *frontmtx ;
34 InpMtx          *mtxA ;
35 SubMtxManager   *mtxmanager ;
36 double          cputotal, droptol, factorops ;
37 double          cpus[9] ;
38 Drand           drand ;
39 double          nops, tau, t1, t2   ;
40 ETree           *frontETree   ;
41 FILE            *msgFile ;
42 int             error, loc, lockflag, msglvl, neqns, nrhs, nzf,
43                 pivotingflag, rc, seed, sparsityflag, symmetryflag,
44                 type ;
45 int             stats[6] ;
46 IV              *newToOldIV, *oldToNewIV ;
47 IVL             *symbfacIVL ;
48 
49 if ( argc != 13 ) {
50    fprintf(stdout,
51 "\n\n usage : %s msglvl msgFile mtxFile etreeFile"
52 "\n         seed symmetryflag sparsityflag "
53 "\n         pivotingflag tau droptol lockflag nrhs"
54 "\n    msglvl    -- message level"
55 "\n    msgFile   -- message file"
56 "\n    mtxFile   -- file to read in InpMtx matrix object"
57 "\n    etreeFile -- file to read in ETree front tree object"
58 "\n    seed      -- random number seed"
59 "\n    symmetryflag -- symmetry flag"
60 "\n       0 --> symmetric "
61 "\n       1 --> hermitian"
62 "\n       2 --> nonsymmetric"
63 "\n    sparsityflag -- sparsity flag"
64 "\n       0 --> store dense fronts"
65 "\n       1 --> store sparse fronts, use droptol to drop entries"
66 "\n    pivotingflag -- pivoting flag"
67 "\n       0 --> do not pivot"
68 "\n       1 --> enable pivoting"
69 "\n    tau     -- upper bound on factor entries"
70 "\n               used only with pivoting"
71 "\n    droptol -- lower bound on factor entries"
72 "\n               used only with sparse fronts"
73 "\n    lockflag -- flag to specify lock status"
74 "\n       0 --> mutex lock is not allocated or initialized"
75 "\n       1 --> mutex lock is allocated and it can synchronize"
76 "\n             only threads in this process."
77 "\n       2 --> mutex lock is allocated and it can synchronize"
78 "\n             only threads in this and other processes."
79 "\n    nrhs     -- # of right hand sides"
80 "\n", argv[0]) ;
81    return(-1) ;
82 }
83 msglvl = atoi(argv[1]) ;
84 if ( strcmp(argv[2], "stdout") == 0 ) {
85    msgFile = stdout ;
86 } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) {
87    fprintf(stderr, "\n fatal error in %s"
88            "\n unable to open file %s\n",
89            argv[0], argv[2]) ;
90    return(-1) ;
91 }
92 mtxFileName   = argv[3] ;
93 etreeFileName = argv[4] ;
94 seed          = atoi(argv[5]) ;
95 symmetryflag  = atoi(argv[6]) ;
96 sparsityflag  = atoi(argv[7]) ;
97 pivotingflag  = atoi(argv[8]) ;
98 tau           = atof(argv[9]) ;
99 droptol       = atof(argv[10]) ;
100 lockflag      = atoi(argv[11]) ;
101 nrhs          = atoi(argv[12]) ;
102 fprintf(msgFile,
103         "\n %s "
104         "\n msglvl        -- %d"
105         "\n msgFile       -- %s"
106         "\n mtxFileName   -- %s"
107         "\n etreeFileName -- %s"
108         "\n seed          -- %d"
109         "\n symmetryflag  -- %d"
110         "\n sparsityflag  -- %d"
111         "\n pivotingflag  -- %d"
112         "\n tau           -- %e"
113         "\n droptol       -- %e"
114         "\n lockflag      -- %d"
115         "\n nrhs          -- %d"
116         "\n",
117         argv[0], msglvl, argv[2], mtxFileName, etreeFileName,
118         seed, symmetryflag, sparsityflag, pivotingflag,
119         tau, droptol, lockflag, nrhs) ;
120 fflush(msgFile) ;
121 /*
122    --------------------------------------
123    initialize the random number generator
124    --------------------------------------
125 */
126 Drand_setDefaultFields(&drand) ;
127 Drand_init(&drand) ;
128 Drand_setSeed(&drand, seed) ;
129 /*
130 Drand_setUniform(&drand, 0.0, 1.0) ;
131 */
132 Drand_setNormal(&drand, 0.0, 1.0) ;
133 /*
134    -------------------------
135    read in the InpMtx object
136    -------------------------
137 */
138 if ( strcmp(mtxFileName, "none") == 0 ) {
139    fprintf(msgFile, "\n no file to read from") ;
140    exit(0) ;
141 }
142 mtxA = InpMtx_new() ;
143 MARKTIME(t1) ;
144 rc = InpMtx_readFromFile(mtxA, mtxFileName) ;
145 MARKTIME(t2) ;
146 fprintf(msgFile, "\n CPU %8.3f : read in mtxA from file %s",
147         t2 - t1, mtxFileName) ;
148 if ( rc != 1 ) {
149    fprintf(msgFile,
150            "\n return value %d from InpMtx_readFromFile(%p,%s)",
151            rc, mtxA, mtxFileName) ;
152    exit(-1) ;
153 }
154 type = mtxA->inputMode ;
155 neqns = 1 + IVmax(mtxA->nent, InpMtx_ivec1(mtxA), &loc) ;
156 if ( INPMTX_IS_BY_ROWS(mtxA) ) {
157    fprintf(msgFile, "\n matrix coordinate type is rows") ;
158 } else if ( INPMTX_IS_BY_COLUMNS(mtxA) ) {
159    fprintf(msgFile, "\n matrix coordinate type is columns") ;
160 } else if ( INPMTX_IS_BY_CHEVRONS(mtxA) ) {
161    fprintf(msgFile, "\n matrix coordinate type is chevrons") ;
162 } else {
163    fprintf(msgFile, "\n\n, error, bad coordinate type") ;
164    exit(-1) ;
165 }
166 if ( INPMTX_IS_RAW_DATA(mtxA) ) {
167    fprintf(msgFile, "\n matrix storage mode is raw data\n") ;
168 } else if ( INPMTX_IS_SORTED(mtxA) ) {
169    fprintf(msgFile, "\n matrix storage mode is sorted\n") ;
170 } else if ( INPMTX_IS_BY_VECTORS(mtxA) ) {
171    fprintf(msgFile, "\n matrix storage mode is by vectors\n") ;
172 } else {
173    fprintf(msgFile, "\n\n, error, bad storage mode") ;
174    exit(-1) ;
175 }
176 {
177 int   maxcol, maxrow, mincol, minrow ;
178 InpMtx_range(mtxA, &mincol, &maxcol, &minrow, &maxrow) ;
179 fprintf(msgFile, "\n range of entries = [%d, %d] x [%d,%d]",
180         minrow, maxrow, mincol, maxcol) ;
181 }
182 /*
183 {
184 int      nent = InpMtx_nent(mtxA) ;
185 double   *dvec = InpMtx_dvec(mtxA) ;
186 Drand    *drand ;
187 
188 drand = Drand_new() ;
189 Drand_setUniform(drand, 0., 1.) ;
190 Drand_fillDvector(drand, nent, dvec) ;
191 }
192 */
193 if ( msglvl > 1 ) {
194    fprintf(msgFile, "\n\n after reading InpMtx object from file %s",
195            mtxFileName) ;
196    if ( msglvl == 2 ) {
197       InpMtx_writeStats(mtxA, msgFile) ;
198    } else {
199       InpMtx_writeForHumanEye(mtxA, msgFile) ;
200    }
201    fflush(msgFile) ;
202 }
203 /*
204    --------------------------------------------------------
205    generate the linear system
206    1. generate solution matrix and fill with random numbers
207    2. generate rhs matrix and fill with zeros
208    3. compute matrix-matrix multiply
209    --------------------------------------------------------
210 */
211 MARKTIME(t1) ;
212 mtxX = DenseMtx_new() ;
213 DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ;
214 DenseMtx_fillRandomEntries(mtxX, &drand) ;
215 mtxB = DenseMtx_new() ;
216 DenseMtx_init(mtxB, type, 1, -1, neqns, nrhs, 1, neqns) ;
217 DenseMtx_zero(mtxB) ;
218 fprintf(msgFile, "\n B and X initialized") ;
219 fflush(msgFile) ;
220 switch ( symmetryflag ) {
221 case SPOOLES_SYMMETRIC :
222    InpMtx_sym_mmm(mtxA, mtxB, one, mtxX) ;
223    break ;
224 case SPOOLES_HERMITIAN :
225    InpMtx_herm_mmm(mtxA, mtxB, one, mtxX) ;
226    break ;
227 case SPOOLES_NONSYMMETRIC :
228    InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ;
229    break ;
230 default :
231    break ;
232 }
233 fprintf(msgFile, "\n mvm done") ;
234 fflush(msgFile) ;
235 MARKTIME(t2) ;
236 fprintf(msgFile, "\n CPU %8.3f : set up the solution and rhs ",
237         t2 - t1) ;
238 if ( msglvl > 2 ) {
239    fprintf(msgFile, "\n\n original mtxX") ;
240    DenseMtx_writeForHumanEye(mtxX, msgFile) ;
241    fprintf(msgFile, "\n\n original mtxB") ;
242    DenseMtx_writeForHumanEye(mtxB, msgFile) ;
243    fflush(msgFile) ;
244 }
245 DenseMtx_writeToFile(mtxB, "rhs.densemtxb") ;
246 /*
247 InpMtx_writeForMatlab(mtxA, "A", msgFile) ;
248 DenseMtx_writeForMatlab(mtxX, "X", msgFile) ;
249 DenseMtx_writeForMatlab(mtxB, "B", msgFile) ;
250 */
251 /*
252    ------------------------
253    read in the ETree object
254    ------------------------
255 */
256 if ( strcmp(etreeFileName, "none") == 0 ) {
257    fprintf(msgFile, "\n no file to read from") ;
258    exit(0) ;
259 }
260 frontETree = ETree_new() ;
261 MARKTIME(t1) ;
262 rc = ETree_readFromFile(frontETree, etreeFileName) ;
263 MARKTIME(t2) ;
264 fprintf(msgFile, "\n CPU %8.3f : read in frontETree from file %s",
265         t2 - t1, etreeFileName) ;
266 if ( rc != 1 ) {
267    fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)",
268            rc, frontETree, etreeFileName) ;
269    exit(-1) ;
270 }
271 ETree_leftJustify(frontETree) ;
272 if ( msglvl > 1 ) {
273    fprintf(msgFile, "\n\n after reading ETree object from file %s",
274            etreeFileName) ;
275    if ( msglvl == 2 ) {
276       ETree_writeStats(frontETree, msgFile) ;
277    } else {
278       ETree_writeForHumanEye(frontETree, msgFile) ;
279    }
280 }
281 fflush(msgFile) ;
282 /*
283    --------------------------------------------------
284    get the permutations, permute the matrix and the
285    front tree, and compute the symbolic factorization
286    --------------------------------------------------
287 */
288 MARKTIME(t1) ;
289 oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ;
290 newToOldIV = ETree_newToOldVtxPerm(frontETree) ;
291 MARKTIME(t2) ;
292 fprintf(msgFile, "\n CPU %8.3f : get permutations", t2 - t1) ;
293 MARKTIME(t1) ;
294 ETree_permuteVertices(frontETree, oldToNewIV) ;
295 MARKTIME(t2) ;
296 fprintf(msgFile, "\n CPU %8.3f : permute front tree", t2 - t1) ;
297 MARKTIME(t1) ;
298 InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ;
299 MARKTIME(t2) ;
300 fprintf(msgFile, "\n CPU %8.3f : permute mtxA", t2 - t1) ;
301 if (  symmetryflag == SPOOLES_SYMMETRIC
302    || symmetryflag == SPOOLES_HERMITIAN ) {
303    MARKTIME(t1) ;
304    InpMtx_mapToUpperTriangle(mtxA) ;
305    MARKTIME(t2) ;
306    fprintf(msgFile, "\n CPU %8.3f : map to upper triangle", t2 - t1) ;
307 }
308 if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) {
309    MARKTIME(t1) ;
310    InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ;
311    MARKTIME(t2) ;
312    fprintf(msgFile, "\n CPU %8.3f : change coordinate type", t2 - t1) ;
313 }
314 if ( INPMTX_IS_RAW_DATA(mtxA) ) {
315    MARKTIME(t1) ;
316    InpMtx_changeStorageMode(mtxA, INPMTX_SORTED) ;
317    MARKTIME(t2) ;
318    fprintf(msgFile, "\n CPU %8.3f : sort entries ", t2 - t1) ;
319 }
320 if ( INPMTX_IS_SORTED(mtxA) ) {
321    MARKTIME(t1) ;
322    InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ;
323    MARKTIME(t2) ;
324    fprintf(msgFile, "\n CPU %8.3f : convert to vectors ", t2 - t1) ;
325 }
326 MARKTIME(t1) ;
327 symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ;
328 MARKTIME(t2) ;
329 fprintf(msgFile, "\n CPU %8.3f : symbolic factorization", t2 - t1) ;
330 MARKTIME(t1) ;
331 DenseMtx_permuteRows(mtxB, oldToNewIV) ;
332 MARKTIME(t2) ;
333 fprintf(msgFile, "\n CPU %8.3f : permute rhs", t2 - t1) ;
334 /*
335 DenseMtx_writeForMatlab(mtxB, "Bhat", msgFile) ;
336 */
337 /*
338    ------------------------------
339    initialize the FrontMtx object
340    ------------------------------
341 */
342 MARKTIME(t1) ;
343 frontmtx   = FrontMtx_new() ;
344 mtxmanager = SubMtxManager_new() ;
345 SubMtxManager_init(mtxmanager, lockflag, 0) ;
346 FrontMtx_init(frontmtx, frontETree, symbfacIVL,
347               type, symmetryflag, sparsityflag, pivotingflag,
348               lockflag, 0, NULL, mtxmanager, msglvl, msgFile) ;
349 MARKTIME(t2) ;
350 fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix",
351         t2 - t1) ;
352 if ( msglvl > 1 ) {
353    fprintf(msgFile,
354            "\n nendD  = %d, nentL = %d, nentU = %d",
355            frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ;
356 }
357 if ( msglvl > 2 ) {
358    fprintf(msgFile, "\n front matrix initialized") ;
359    FrontMtx_writeForHumanEye(frontmtx, msgFile) ;
360    fflush(msgFile) ;
361 }
362 SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ;
363 /*
364    -----------------
365    factor the matrix
366    -----------------
367 */
368 nzf       = ETree_nFactorEntries(frontETree, symmetryflag) ;
369 factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ;
370 fprintf(msgFile,
371         "\n %d factor entries, %.0f factor ops, %8.3f ratio",
372         nzf, factorops, factorops/nzf) ;
373 IVzero(6, stats) ;
374 DVzero(9, cpus) ;
375 chvmanager = ChvManager_new() ;
376 ChvManager_init(chvmanager, lockflag, 1) ;
377 MARKTIME(t1) ;
378 rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol,
379                                 chvmanager, &error, cpus,
380                                 stats, msglvl, msgFile) ;
381 MARKTIME(t2) ;
382 fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops",
383         t2 - t1, 1.e-6*factorops/(t2-t1)) ;
384 if ( rootchv != NULL ) {
385    fprintf(msgFile, "\n\n factorization did not complete") ;
386    for ( chv = rootchv ; chv != NULL ; chv = chv->next ) {
387       fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d",
388               chv->id, chv->nD, chv->nL, chv->nU) ;
389    }
390 }
391 if ( error >= 0 ) {
392    fprintf(msgFile, "\n\n error encountered at front %d\n", error) ;
393    exit(-1) ;
394 }
395 fprintf(msgFile,
396         "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns",
397         stats[0], stats[1], stats[2]) ;
398 if ( frontmtx->rowadjIVL != NULL ) {
399    fprintf(msgFile,
400            "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ;
401 }
402 if ( frontmtx->coladjIVL != NULL ) {
403    fprintf(msgFile,
404            ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ;
405 }
406 if ( frontmtx->upperblockIVL != NULL ) {
407    fprintf(msgFile,
408            "\n %d fronts, %d entries in upperblockIVL",
409            frontmtx->nfront, frontmtx->upperblockIVL->tsize) ;
410 }
411 if ( frontmtx->lowerblockIVL != NULL ) {
412    fprintf(msgFile,
413            ", %d entries in lowerblockIVL",
414            frontmtx->lowerblockIVL->tsize) ;
415 }
416 fprintf(msgFile,
417         "\n %d entries in D, %d entries in L, %d entries in U",
418         stats[3], stats[4], stats[5]) ;
419 fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ;
420 if (  FRONTMTX_IS_SYMMETRIC(frontmtx)
421    || FRONTMTX_IS_HERMITIAN(frontmtx) ) {
422    int   nneg, npos, nzero ;
423 
424    FrontMtx_inertia(frontmtx, &nneg, &nzero, &npos) ;
425    fprintf(msgFile,
426            "\n %d negative, %d zero and %d positive eigenvalues",
427            nneg, nzero, npos) ;
428    fflush(msgFile) ;
429 }
430 cputotal = cpus[8] ;
431 if ( cputotal > 0.0 ) {
432    fprintf(msgFile,
433    "\n    initialize fronts       %8.3f %6.2f"
434    "\n    load original entries   %8.3f %6.2f"
435    "\n    update fronts           %8.3f %6.2f"
436    "\n    assemble postponed data %8.3f %6.2f"
437    "\n    factor fronts           %8.3f %6.2f"
438    "\n    extract postponed data  %8.3f %6.2f"
439    "\n    store factor entries    %8.3f %6.2f"
440    "\n    miscellaneous           %8.3f %6.2f"
441    "\n    total time              %8.3f",
442    cpus[0], 100.*cpus[0]/cputotal,
443    cpus[1], 100.*cpus[1]/cputotal,
444    cpus[2], 100.*cpus[2]/cputotal,
445    cpus[3], 100.*cpus[3]/cputotal,
446    cpus[4], 100.*cpus[4]/cputotal,
447    cpus[5], 100.*cpus[5]/cputotal,
448    cpus[6], 100.*cpus[6]/cputotal,
449    cpus[7], 100.*cpus[7]/cputotal, cputotal) ;
450 }
451 SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ;
452 ChvManager_writeForHumanEye(chvmanager, msgFile) ;
453 if ( msglvl > 2 ) {
454    fprintf(msgFile, "\n\n front factor matrix") ;
455    FrontMtx_writeForHumanEye(frontmtx, msgFile) ;
456 }
457 /*
458 fprintf(msgFile, "\n L = eye(%d,%d) ;", neqns, neqns) ;
459 fprintf(msgFile, "\n U = eye(%d,%d) ;", neqns, neqns) ;
460 fprintf(msgFile, "\n D = zeros(%d,%d) ;", neqns, neqns) ;
461 FrontMtx_writeForMatlab(frontmtx, "L", "D", "U", msgFile) ;
462 */
463 /*
464    ------------------------------
465    post-process the factor matrix
466    ------------------------------
467 */
468 MARKTIME(t1) ;
469 FrontMtx_postProcess(frontmtx, msglvl, msgFile) ;
470 MARKTIME(t2) ;
471 fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ;
472 if ( msglvl > 2 ) {
473    fprintf(msgFile, "\n\n front factor matrix after post-processing") ;
474    FrontMtx_writeForHumanEye(frontmtx, msgFile) ;
475 }
476 fprintf(msgFile, "\n\n after post-processing") ;
477 SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ;
478 /*
479    ----------------
480    solve the system
481    ----------------
482 */
483 neqns = mtxB->nrow ;
484 nrhs  = mtxB->ncol ;
485 mtxZ  = DenseMtx_new() ;
486 DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ;
487 DenseMtx_zero(mtxZ) ;
488 if ( type == SPOOLES_REAL ) {
489    nops = frontmtx->nentD + 2*frontmtx->nentU ;
490    if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) {
491       nops += 2*frontmtx->nentL ;
492    } else {
493       nops += 2*frontmtx->nentU ;
494    }
495 } else if ( type == SPOOLES_COMPLEX ) {
496    nops = 8*frontmtx->nentD + 8*frontmtx->nentU ;
497    if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) {
498       nops += 8*frontmtx->nentL ;
499    } else {
500       nops += 8*frontmtx->nentU ;
501    }
502 }
503 nops *= nrhs ;
504 if ( msglvl > 2 ) {
505    fprintf(msgFile, "\n\n rhs") ;
506    DenseMtx_writeForHumanEye(mtxB, msgFile) ;
507    fflush(stdout) ;
508 }
509 DVzero(6, cpus) ;
510 MARKTIME(t1) ;
511 FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager,
512                cpus, msglvl, msgFile) ;
513 MARKTIME(t2) ;
514 fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops",
515         t2 - t1, 1.e-6*nops/(t2 - t1)) ;
516 cputotal = t2 - t1 ;
517 if ( cputotal > 0.0 ) {
518    fprintf(msgFile,
519    "\n    set up solves               %8.3f %6.2f"
520    "\n    load rhs and store solution %8.3f %6.2f"
521    "\n    forward solve               %8.3f %6.2f"
522    "\n    diagonal solve              %8.3f %6.2f"
523    "\n    backward solve              %8.3f %6.2f"
524    "\n    total time                  %8.3f",
525    cpus[0], 100.*cpus[0]/cputotal,
526    cpus[1], 100.*cpus[1]/cputotal,
527    cpus[2], 100.*cpus[2]/cputotal,
528    cpus[3], 100.*cpus[3]/cputotal,
529    cpus[4], 100.*cpus[4]/cputotal, cputotal) ;
530 }
531 if ( msglvl > 2 ) {
532    fprintf(msgFile, "\n\n computed solution") ;
533    DenseMtx_writeForHumanEye(mtxZ, msgFile) ;
534    fflush(stdout) ;
535 }
536 /*
537 DenseMtx_writeForMatlab(mtxZ, "Xhat", msgFile) ;
538 */
539 /*
540    -------------------------------------------------------------
541    permute the computed solution back into the original ordering
542    -------------------------------------------------------------
543 */
544 MARKTIME(t1) ;
545 DenseMtx_permuteRows(mtxZ, newToOldIV) ;
546 MARKTIME(t2) ;
547 fprintf(msgFile, "\n CPU %8.3f : permute solution", t2 - t1) ;
548 if ( msglvl > 2 ) {
549    fprintf(msgFile, "\n\n permuted solution") ;
550    DenseMtx_writeForHumanEye(mtxZ, msgFile) ;
551    fflush(stdout) ;
552 }
553 /*
554    -----------------
555    compute the error
556    -----------------
557 */
558 DenseMtx_sub(mtxZ, mtxX) ;
559 fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ;
560 if ( msglvl > 2 ) {
561    fprintf(msgFile, "\n\n error") ;
562    DenseMtx_writeForHumanEye(mtxZ, msgFile) ;
563    fflush(stdout) ;
564 }
565 fprintf(msgFile, "\n\n after solve") ;
566 SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ;
567 /*
568    ------------------------
569    free the working storage
570    ------------------------
571 */
572 IV_free(oldToNewIV) ;
573 IV_free(newToOldIV) ;
574 InpMtx_free(mtxA) ;
575 DenseMtx_free(mtxX) ;
576 DenseMtx_free(mtxB) ;
577 DenseMtx_free(mtxZ) ;
578 FrontMtx_free(frontmtx) ;
579 ETree_free(frontETree) ;
580 IVL_free(symbfacIVL) ;
581 ChvManager_free(chvmanager) ;
582 SubMtxManager_free(mtxmanager) ;
583 
584 fprintf(msgFile, "\n") ;
585 fclose(msgFile) ;
586 
587 return(1) ; }
588 
589 /*--------------------------------------------------------------------*/
590