/* ========================================================================== */
/* === umfpack demo ========================================================= */
/* ========================================================================== */

/* -------------------------------------------------------------------------- */
/* UMFPACK Version 3.2 (Jan. 1, 2002), Copyright (c) 2002 by Timothy A.       */
/* Davis, University of Florida, davis@cise.ufl.edu.  All Rights Reserved.    */
/* See README, umfpack.h, or type "umfpack_details" in Matlab for License.    */
/* -------------------------------------------------------------------------- */

/*
  A demo of UMFPACK Version 3.2:  See umfpack_demo.m for a (roughly)
  equivalent Matlab version.  The main difference is that Matlab uses int's,
  not long's (umfpack_* routines instead of umfpack_l_*).
  The other difference is that while the Matlab
  umfpack mexFunction provides separate access to umfpack_symbolic, via
  umfpack (A, 'symbolic'), it does not use its output for a subsequent
  numerical factorization.  Thus, you will find that the output of this
  program and the Matlab diary are slightly different.  The Matlab output also
  uses 1-based matrix row and column indices, not 0-based (the internal
  represention is the same).

  First, factor and solve a 5-by-5 system, Ax=b, using default parameters,

      [ 2  3  0  0  0 ]      [  8 ]                  [ 1 ]
      [ 3  0  4  0  6 ]      [ 45 ]                  [ 2 ]
  A = [ 0 -1 -3  2  0 ], b = [ -3 ]. Solution is x = [ 3 ].
      [ 0  0  1  0  0 ]      [  3 ]                  [ 4 ]
      [ 0  4  2  0  1 ]      [ 19 ]                  [ 5 ]

  Then solve A'x=b, with solution:
        x = [  1.8158  1.4561 1.5000 -24.8509 10.2632 ]'
  using the factors of A.   Modify one entry (A (1,4) = 0, where the row and
  column indices range from 0 to 4, obtaining the system:

      [ 2  3  0  0  0 ]      [  8 ]                  [ 11.0    ]
      [ 3  0  4  0  0 ]      [ 45 ]                  [ -4.6667 ]
  A = [ 0 -1 -3  2  0 ], b = [ -3 ]. Solution is x = [  3.0    ].
      [ 0  0  1  0  0 ]      [  3 ]                  [  0.6667 ]
      [ 0  4  2  0  1 ]      [ 19 ]                  [ 31.6667 ]

  The pattern of A has not changed (it has explicitly zero entry), so a
  reanalysis with umfpack_l_symbolic does not need to be done (the Matlab
  umfpack_demo.m will need to redo it, because the Matlab caller is not
  provided with the Symbolic object).  Refactorize (with umfpack_l_numeric),
  and solve Ax=b.  Note that the pivot ordering has changed.  Next, change all
  of the entries in A, but not the pattern.  The system becomes

      [ 2 13  0  0  0 ]      [  8 ]                  [  8.5012 ]
      [ 2  0 23  0 39 ]      [ 45 ]                  [ -0.6925 ]
  A = [ 0  7 15 30  0 ], b = [ -3 ]. Solution is x = [  0.1667 ].
      [ 0  0 18  0  0 ]      [  3 ]                  [ -0.0218 ]
      [ 0 10 18  0 37 ]      [ 19 ]                  [  0.6196 ]

  Finally, compute B = A', and do the symbolic and numeric factorization of B.
  Factorizing A' can sometimes be better than factorizing A itself (less work
  and memory usage).  Solve B'x=b twice; the solution is the same as the
  solution to Ax=b for the above A.
*/

/* -------------------------------------------------------------------------- */
/* definitions */
/* -------------------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include "umfpack.h"

#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif

/* -------------------------------------------------------------------------- */
/* triplet form of the matrix.  The triplets can be in any order. */
/* -------------------------------------------------------------------------- */

static long   n = 5 ;
static long   nz = 12 ;
static long   Arow [ ] = { 0,  4,  1,  1,   2,   2,  0,  1,  2,  3,  4,  4} ;
static long   Acol [ ] = { 0,  4,  0,  2,   1,   2,  1,  4,  3,  2,  1,  2} ;
static double Aval [ ] = {2., 1., 3., 4., -1., -3., 3., 6., 2., 1., 4., 2.} ;
static double b [ ] = {8., 45., -3., 3., 19.} ;
static double x [5] ;
static double r [5] ;

/* -------------------------------------------------------------------------- */
/* error: print a message and exit */
/* -------------------------------------------------------------------------- */

static void error
(
    char *message
)
{
    printf ("\n\n====== error: %s =====\n\n", message) ;
    exit (1) ;
}


/* -------------------------------------------------------------------------- */
/* resid: compute the residual, r = Ax-b or r = A'x=b and return maxnorm (r) */
/* -------------------------------------------------------------------------- */

static double resid
(
    long n,
    long Ap [ ],
    long Ai [ ],
    double Ax [ ],
    double x [ ],
    double r [ ],
    long transpose
)
{
    long i, j, p ;
    double norm ;

    for (i = 0 ; i < n ; i++)
    {
	r [i] = -b [i] ;
    }
    if (transpose)
    {
	for (j = 0 ; j < n ; j++)
	{
	    for (p = Ap [j] ; p < Ap [j+1] ; p++)
	    {
		i = Ai [p] ;
		r [j] += Ax [p] * x [i] ;
	    }
	}
    }
    else
    {
	for (j = 0 ; j < n ; j++)
	{
	    for (p = Ap [j] ; p < Ap [j+1] ; p++)
	    {
		i = Ai [p] ;
		r [i] += Ax [p] * x [j] ;
	    }
	}
    }
    norm = 0. ;
    for (i = 0 ; i < n ; i++)
    {
	norm = MAX (norm, ABS (r [i])) ;
    }
    return (norm) ;
}


/* -------------------------------------------------------------------------- */
/* main program */
/* -------------------------------------------------------------------------- */

/*ARGSUSED0*/	/* argc and argv are unused */
int main
(
    int argc,
    char **argv
)
{
    double Info [UMFPACK_INFO], Control [UMFPACK_CONTROL], *Ax, *Bx, *Lx, *Ux,
	*W, *Y, *Z, *S, t ;
    long *Ap, *Ai, *Bp, *Bi, row, col, p, lnz, unz, nn, *Lp, *Li, *Ui, *Up,
	*P, *Q, *Lj, i, j, k, anz, nfr, nchains, nsparse_col, *Qtree, fnpiv,
	status, *Front_npivots, *Front_parent, *Chain_start, *Wi,
	*Chain_maxrows, *Chain_maxcols ;
    void *Symbolic, *Numeric ;

    /* ---------------------------------------------------------------------- */
    /* initializations */
    /* ---------------------------------------------------------------------- */

    t = umfpack_timer ( ) ;

    printf ("\n%s (long) demo:\n", UMFPACK_VERSION) ;

    /* get the default control parameters */
    umfpack_l_defaults (Control) ;

    /* change the default print level for this demo */
    /* (otherwise, nothing will print) */
    Control [UMFPACK_PRL] = 6 ;

    /* print the license agreement */
    umfpack_l_report_status (Control, UMFPACK_OK) ;
    Control [UMFPACK_PRL] = 5 ;

    /* print the control parameters */
    umfpack_l_report_control (Control) ;

    /* ---------------------------------------------------------------------- */
    /* print A and b, and convert A to column-form */
    /* ---------------------------------------------------------------------- */

    /* print the right-hand-side */
    (void) umfpack_l_report_vector ("b", n, b, Control) ;

    /* print the triplet form of the matrix */
    (void) umfpack_l_report_triplet ("A", n, nz, Arow, Acol, Aval, Control) ;

    /* convert to column form */
    Ap = (long *) malloc ((n+1) * sizeof (long)) ;
    Ai = (long *) malloc (nz * sizeof (long)) ;
    Ax = (double *) malloc (nz * sizeof (double)) ;
    if (!Ap || !Ai || !Ax)
    {
	error ("out of memory") ;
    }
    status = umfpack_l_triplet_to_col (n, nz, Arow, Acol, Aval, Ap, Ai, Ax) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_triplet_to_col failed") ;
    }

    /* print the column-form of A */
    (void) umfpack_l_report_matrix ("A", n, Ap, Ai, Ax, "column", Control) ;

    /* ---------------------------------------------------------------------- */
    /* symbolic factorization */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_symbolic (n, Ap, Ai, &Symbolic, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_info (Control, Info) ;
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_symbolic failed") ;
    }

    /* print the symbolic factorization */
    (void) umfpack_l_report_symbolic ("Symbolic factorization of A",
	Symbolic, Control) ;

    /* ---------------------------------------------------------------------- */
    /* numeric factorization */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_info (Control, Info) ;
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_numeric failed") ;
    }

    /* print the numeric factorization */
    (void) umfpack_l_report_numeric ("Numeric factorization of A",
	Numeric, Control) ;

    /* ---------------------------------------------------------------------- */
    /* solve Ax=b */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_solve ("Ax=b", Ap, Ai, Ax, x, b, Numeric, Control,
	Info) ;
    umfpack_l_report_info (Control, Info) ;
    umfpack_l_report_status (Control, status) ;
    if (status != UMFPACK_OK)
    {
	error ("umfpack_l_solve failed") ;
    }
    (void) umfpack_l_report_vector ("x (solution of Ax=b)", n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Ap, Ai, Ax, x, r, FALSE)) ;

    /* ---------------------------------------------------------------------- */
    /* solve A'x=b */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_solve ("A'x=b", Ap, Ai, Ax, x, b, Numeric, Control,
	Info) ;
    umfpack_l_report_info (Control, Info) ;
    if (status != UMFPACK_OK)
    {
	error ("umfpack_l_solve failed") ;
    }
    (void) umfpack_l_report_vector ("x (solution of A'x=b)", n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Ap, Ai, Ax, x, r, TRUE)) ;

    /* ---------------------------------------------------------------------- */
    /* modify one numerical value in the column-form of A */
    /* ---------------------------------------------------------------------- */

    /* change A (1,4), look for row index 1 in column 4. */
    row = 1 ;
    col = 4 ;
    for (p = Ap [col] ; p < Ap [col+1] ; p++)
    {
	if (row == Ai [p])
	{
	    printf ("\nchanging A (%ld,%ld) from %g", row, col, Ax [p]) ;
	    Ax [p] = 0.0 ;
	    printf (" to %g\n", Ax [p]) ;
	    break ;
	}
    }
    (void) umfpack_l_report_matrix ("modified A", n, Ap, Ai, Ax, "column",
	Control) ;

    /* ---------------------------------------------------------------------- */
    /* redo the numeric factorization */
    /* ---------------------------------------------------------------------- */

    /* The pattern (Ap and Ai) hasn't changed, so the symbolic factorization */
    /* doesn't have to be redone, no matter how much we change Ax. */

    /* We don't need the Numeric object any more, so free it. */
    umfpack_l_free_numeric (&Numeric) ;

    /* Note that a memory leak would have occured if the old Numeric */
    /* had not been free'd with umfpack_l_free_numeric above. */
    status = umfpack_l_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_info (Control, Info) ;
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_numeric failed") ;
    }
    (void) umfpack_l_report_numeric ("Numeric factorization of modified A",
	Numeric, Control) ;

    /* ---------------------------------------------------------------------- */
    /* solve Ax=b, with the modified A */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_solve ("Ax=b", Ap, Ai, Ax, x, b, Numeric, Control,
	Info) ;
    umfpack_l_report_info (Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_solve failed") ;
    }
    (void) umfpack_l_report_vector ("x (with modified A)", n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Ap, Ai, Ax, x, r, FALSE)) ;

    /* ---------------------------------------------------------------------- */
    /* modify all of the numerical values of A, but not the pattern */
    /* ---------------------------------------------------------------------- */

    for (col = 0 ; col < n ; col++)
    {
	for (p = Ap [col] ; p < Ap [col+1] ; p++)
	{
	    row = Ai [p] ;
	    printf ("changing A (%ld,%ld) from %g", row, col, Ax [p]) ;
	    Ax [p] = Ax [p] + col*10 - row ;
	    printf (" to %g\n", Ax [p]) ;
	}
    }
    (void) umfpack_l_report_matrix ("completely modified A (same pattern)",
	n, Ap, Ai, Ax, "column", Control) ;

    /* ---------------------------------------------------------------------- */
    /* redo the numeric factorization */
    /* ---------------------------------------------------------------------- */

    umfpack_l_free_numeric (&Numeric) ;
    status = umfpack_l_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_info (Control, Info) ;
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_numeric failed") ;
    }
    (void) umfpack_l_report_numeric (
    "Numeric factorization of completely modified A", Numeric, Control) ;

    /* ---------------------------------------------------------------------- */
    /* solve Ax=b, with the modified A */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_solve ("Ax=b", Ap, Ai, Ax, x, b, Numeric, Control,
	Info) ;
    umfpack_l_report_info (Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_solve failed") ;
    }
    (void) umfpack_l_report_vector ("x (with completely modified A)",
	n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Ap, Ai, Ax, x, r, FALSE)) ;

    /* ---------------------------------------------------------------------- */
    /* free the symbolic and numeric factorization */
    /* ---------------------------------------------------------------------- */

    umfpack_l_free_symbolic (&Symbolic) ;
    umfpack_l_free_numeric (&Numeric) ;

    /* ---------------------------------------------------------------------- */
    /* B = transpose of A */
    /* ---------------------------------------------------------------------- */

    Bp = (long *) malloc ((n+1) * sizeof (long)) ;
    Bi = (long *) malloc (nz * sizeof (long)) ;
    Bx = (double *) malloc (nz * sizeof (double)) ;
    if (!Bp || !Bi || !Bx)
    {
	error ("out of memory") ;
    }
    status = umfpack_l_transpose (n, Ap, Ai, Ax, (long *) NULL, (long *) NULL,
	Bp, Bi, Bx) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_transpose failed") ;
    }
    (void) umfpack_l_report_matrix ("B (transpose of A)",
	n, Bp, Bi, Bx, "column", Control) ;

    /* ---------------------------------------------------------------------- */
    /* symbolic factorization of B */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_symbolic (n, Bp, Bi, &Symbolic, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_info (Control, Info) ;
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_symbolic failed") ;
    }
    (void) umfpack_l_report_symbolic ("Symbolic factorization of B",
	Symbolic, Control) ;

    /* ---------------------------------------------------------------------- */
    /* copy the contents of Symbolic into user arrays print them */
    /* ---------------------------------------------------------------------- */

    printf ("\nGet the contents of the Symbolic object for B:\n") ;
    printf ("(compare with umfpack_l_report_symbolic output, above)\n") ;
    Qtree = (long *) malloc (n * sizeof (long)) ;
    Front_npivots = (long *) malloc (n * sizeof (long)) ;
    Front_parent = (long *) malloc (n * sizeof (long)) ;
    Chain_start = (long *) malloc ((n+1) * sizeof (long)) ;
    Chain_maxrows = (long *) malloc (n * sizeof (long)) ;
    Chain_maxcols = (long *) malloc (n * sizeof (long)) ;
    if (!Qtree || !Front_npivots || !Front_parent || !Chain_start ||
	!Chain_maxrows || !Chain_maxcols)
    {
	error ("out of memory") ;
    }

    status = umfpack_l_get_symbolic (&nn, &anz, &nfr, &nchains, &nsparse_col,
	Qtree, Front_npivots, Front_parent, Chain_start,
	Chain_maxrows, Chain_maxcols, Symbolic) ;

    printf ("From the Symbolic object, B is of dimension n = %ld\n", nn) ;
    printf ("   with nz = %ld, number of fronts = %ld,\n", nz, nfr) ;
    printf ("   number of frontal matrix chains = %ld\n", nchains) ;

    printf ("\nPivot columns in each front, and parent of each front:\n") ;
    k = 0 ;
    for (i = 0 ; i < nfr ; i++)
    {
	fnpiv = Front_npivots [i] ;
	printf ("    Front %ld: parent front: %ld number of pivots: %ld\n",
		i, Front_parent [i], fnpiv) ;
	for (j = 0 ; j < fnpiv ; j++)
	{
	    col = Qtree [k] ;
	    printf ("        %ld-th pivot column is column %ld in original"
		" matrix\n", k, col) ;
	    k++ ;
	}
    }

    printf ("\nNote that the column ordering, above, will be refined\n") ;
    printf ("in the numeric factorization below.  The assignment of pivot\n") ;
    printf ("columns to frontal matrices will always remain unchanged.\n") ;

    printf ("\nTotal number of pivot columns in frontal matrices: %ld\n", k) ;

    printf ("\nFrontal matrix chains:\n") ;
    for (j = 0 ; j < nchains ; j++)
    {
	printf ("   Frontal matrices %ld to %ld are factorized in a single\n",
	    Chain_start [j], Chain_start [j+1] - 1) ;
	printf ("        working array of size %ld-by-%ld\n",
	    Chain_maxrows [j], Chain_maxcols [j]) ;
    }

    /* ---------------------------------------------------------------------- */
    /* numeric factorization of B */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_numeric (Bp, Bi, Bx, Symbolic, &Numeric, Control, Info) ;
    if (status != UMFPACK_OK)
    {
	error ("umfpack_l_numeric failed") ;
    }
    (void) umfpack_l_report_numeric ("Numeric factorization of B",
	Numeric, Control) ;

    /* ---------------------------------------------------------------------- */
    /* extract the LU factors of B and print them */
    /* ---------------------------------------------------------------------- */

    if (umfpack_l_get_lunz (&lnz, &unz, &nn, Numeric) != UMFPACK_OK)
    {
	error ("umfpack_l_get_lunz failed") ;
    }
    Lp = (long *) malloc ((n+1) * sizeof (long)) ;
    Li = (long *) malloc (lnz * sizeof (long)) ;
    Lx = (double *) malloc (lnz * sizeof (double)) ;
    Up = (long *) malloc ((n+1) * sizeof (long)) ;
    Ui = (long *) malloc (unz * sizeof (long)) ;
    Ux = (double *) malloc (unz * sizeof (double)) ;
    P = (long *) malloc (n * sizeof (long)) ;
    Q = (long *) malloc (n * sizeof (long)) ;
    if (!Lp || !Li || !Lx || !Up || !Ui || !Ux || !P || !Q)
    {
	error ("out of memory") ;
    }
    status = umfpack_l_get_numeric (Lp, Li, Lx, Up, Ui, Ux, P, Q, Numeric) ;
    if (status != UMFPACK_OK)
    {
	error ("umfpack_l_get_numeric failed") ;
    }
    (void) umfpack_l_report_matrix ("L (lower triangular factor of B)",
	n, Lp, Li, Lx, "row", Control) ;
    (void) umfpack_l_report_matrix ("U (upper triangular factor of B)",
	n, Up, Ui, Ux, "column", Control) ;
    (void) umfpack_l_report_perm ("P", n, P, Control) ;
    (void) umfpack_l_report_perm ("Q", n, Q, Control) ;

    /* ---------------------------------------------------------------------- */
    /* convert L to triplet form and print it */
    /* ---------------------------------------------------------------------- */

    printf ("\nConverting L to triplet form, and printing it:\n") ;
    Lj = (long *) malloc (lnz * sizeof (long)) ;
    if (!Lj)
    {
	error ("out of memory") ;
    }
    if (umfpack_l_col_to_triplet (n, Lp, Lj) != UMFPACK_OK)
    {
	error ("umfpack_l_col_to_triplet failed") ;
    }
    (void) umfpack_l_report_triplet ("L, in triplet form", n, lnz, Li, Lj, Lx,
	Control) ;

    /* ---------------------------------------------------------------------- */
    /* solve B'x=b */
    /* ---------------------------------------------------------------------- */

    status = umfpack_l_solve ("A'x=b", Bp, Bi, Bx, x, b, Numeric, Control,
	Info) ;
    umfpack_l_report_info (Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_solve failed") ;
    }
    (void) umfpack_l_report_vector ("x (solution of B'x=b)", n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Bp, Bi, Bx, x, r, TRUE)) ;

    /* ---------------------------------------------------------------------- */
    /* solve B'x=b again, using umfpack_l_wsolve instead */
    /* ---------------------------------------------------------------------- */

    printf ("\nSolving B'x=b again, using umfpack_l_wsolve instead:\n") ;
    Wi = (long *) malloc (n * sizeof (long)) ;
    W = (double *) malloc (n * sizeof (double)) ;
    Y = (double *) malloc (n * sizeof (double)) ;
    Z = (double *) malloc (n * sizeof (double)) ;
    S = (double *) malloc (n * sizeof (double)) ;
    if (!Wi || !W || !Y || !Z || !S)
    {
	error ("out of memory") ;
    }

    status = umfpack_l_wsolve ("A'x=b", Bp, Bi, Bx, x, b, Numeric, Control,
	Info, Wi, W, Y, Z, S) ;
    umfpack_l_report_info (Control, Info) ;
    if (status != UMFPACK_OK)
    {
	umfpack_l_report_status (Control, status) ;
	error ("umfpack_l_wsolve failed") ;
    }
    (void) umfpack_l_report_vector ("x (solution of B'x=b)", n, x, Control) ;
    printf ("maxnorm of residual: %g\n\n", resid (n, Bp, Bi, Bx, x, r, TRUE)) ;

    /* ---------------------------------------------------------------------- */
    /* free everything */
    /* ---------------------------------------------------------------------- */

    /* This is not strictly required since the process is exiting and the */
    /* system will reclaim the memory anyway.  It's useful, though, just as */
    /* a list of what is currently malloc'ed by this program.  Plus, it's */
    /* always a good habit to explicitly free whatever you malloc. */

    free (Ap) ;
    free (Ai) ;
    free (Ax) ;

    free (Bp) ;
    free (Bi) ;
    free (Bx) ;

    free (Qtree) ;
    free (Front_npivots) ;
    free (Front_parent) ;
    free (Chain_start) ;
    free (Chain_maxrows) ;
    free (Chain_maxcols) ;

    free (Lp) ;
    free (Li) ;
    free (Lx) ;

    free (Up) ;
    free (Ui) ;
    free (Ux) ;

    free (P) ;
    free (Q) ;

    free (Lj) ;

    free (Wi) ;
    free (W) ;
    free (Y) ;
    free (Z) ;
    free (S) ;

    umfpack_l_free_symbolic (&Symbolic) ;
    umfpack_l_free_numeric (&Numeric) ;

    /* ---------------------------------------------------------------------- */
    /* print the total time spent in this demo */
    /* ---------------------------------------------------------------------- */

    t = umfpack_timer ( ) - t ;
    printf ("\numfpack (long) demo complete.  Total time: %5.2f (seconds)\n",
    	t) ;

    return (0) ;
}

