/* ========================================================================== */
/* === UMFPACK_report_matrix ================================================ */
/* ========================================================================== */

/* -------------------------------------------------------------------------- */
/* 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.    */
/* -------------------------------------------------------------------------- */

/*
    User-callable.  Prints a column or row-oriented matrix.  See
    umfpack_report_matrix.h for details.

    Dynamic memory usage:  Allocates a size n integer workspace via a single
    call to UMF_malloc and then frees all of it via UMF_free on return.  The
    workspace is not allocated if an early error return occurs before the
    workspace is needed.

*/

#include "umf_internal.h"
#include "umf_malloc.h"
#include "umf_free.h"

GLOBAL Int UMFPACK_report_matrix
(
    const char name [ ],
    Int n,
    const Int Ap [ ],
    const Int Ai [ ],
    const double Ax [ ],
    const char form [ ],
    const double Control [UMFPACK_CONTROL]
)
{
    Int prl, row, col, length, last_row, p, nz, prl1, col_form, p1, p2, nempty,
	note, result, *W ;
    char *vector, *index ;

    /* ---------------------------------------------------------------------- */
    /* determine the form, and check if inputs exist */
    /* ---------------------------------------------------------------------- */

    if (Control)
    {
	prl = (Int) Control [UMFPACK_PRL] ;
    }
    else
    {
	prl = UMFPACK_DEFAULT_PRL ;
    }

    if (prl <= 2)
    {
	return (UMFPACK_OK) ;
    }

    if (form)
    {
	col_form = !STRING_MATCH (form, "row") ;
    }
    else
    {
	col_form = TRUE ;
    }
    if (col_form)
    {
	vector = "column" ;	/* column vectors */
	index = "row" ;		/* with row indices */
    }
    else
    {
	vector = "row" ;	/* row vectors */
	index = "column" ;	/* with column indices */
    }

    PRINTF (("\n")) ;
    if (name)
    {
	PRINTF (("%s: ", name)) ;
    }
    PRINTF (("%s-form matrix, n = "ID", ", vector, n)) ;

    if (n <= 0)
    {
	PRINTF (("ERROR: n <= 0\n\n")) ;
	return (UMFPACK_ERROR_n_nonpositive) ;
    }

    if (!Ap)
    {
	PRINTF (("ERROR: Ap missing\n\n")) ;
	return (UMFPACK_ERROR_argument_missing) ;
    }

    nz = Ap [n] ;
    PRINTF (("nz = "ID". ", nz)) ;
    if (nz < 0)
    {
	PRINTF (("ERROR: number of entries < 0\n\n")) ;
	return (UMFPACK_ERROR_nz_negative) ;
    }

    if (Ap [0] != 0)
    {
	PRINTF (("ERROR: Ap ["ID"] = "ID" must be "ID"\n\n",
	    (Int) INDEX (0), INDEX (Ap [0]), (Int) INDEX (0))) ;
	return (UMFPACK_ERROR_Ap0_nonzero) ;
    }

    if (!Ai)
    {
	PRINTF (("ERROR: Ai missing\n\n")) ;
	return (UMFPACK_ERROR_argument_missing) ;
    }

    PRINTF4 (("\n")) ;
    note = FALSE ;
    if (nz == 0)
    {
	PRINTF4 (("    NOTE: no entries\n")) ;
	note = TRUE ;
    }

    /* ---------------------------------------------------------------------- */
    /* check the column pointers, Ap */
    /* ---------------------------------------------------------------------- */

    nempty = 0 ;

    for (col = 0 ; col < n ; col++)
    {
	if (Ap [col] < 0)
	{
	    PRINTF (("ERROR: Ap ["ID"] < 0\n\n", INDEX (col))) ;
	    return (UMFPACK_ERROR_col_length_negative) ;
	}
	if (Ap [col] > nz)
	{
	    PRINTF (("ERROR: Ap ["ID"] > size of Ai\n\n", INDEX (col))) ;
	    return (UMFPACK_ERROR_col_length_negative) ;
	}
    }

    for (col = 0 ; col < n ; col++)
    {
	length = Ap [col+1] - Ap [col] ;
	if (length < 0)
	{
	    PRINTF (("ERROR: # entries in %s "ID" is < 0\n\n",
		vector, INDEX (col))) ;
	    return (UMFPACK_ERROR_col_length_negative) ;
	}
	if (length == 0)
	{
	    note = TRUE ;
	    nempty++ ;
	    if ((prl == 4 && nempty < 10) || prl > 4)
	    {
		PRINTF (("    NOTE: %s "ID" has no entries\n",
		    vector, INDEX (col))) ;
	    }
	    else if (prl == 4 && nempty == 10)
	    {
		PRINTF (("    ...\n")) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* print each column */
    /* ---------------------------------------------------------------------- */

    W = (Int *) UMF_malloc (n, sizeof (Int)) ;
    if (!W)
    {
	PRINTF (("ERROR: out of memory to check matrix\n\n")) ;
	return (UMFPACK_ERROR_out_of_memory) ;
    }

    for (row = 0 ; row < n ; row++)
    {
	W [row] = TRUE ;
    }

    prl1 = prl ;

    for (col = 0 ; col < n ; col++)
    {
	/* if prl is 4, print the first 10 entries of the first 10 columns */
	if (col < 10)
	{
	    prl = prl1 ;
	}
	/* get the column pointers */
	p1 = Ap [col] ;
	p2 = Ap [col+1] ;
	length = p2 - p1 ;
	PRINTF4 (("\n    %s "ID": start: "ID" end: "ID" entries: "ID"\n",
	    vector, INDEX (col), p1, p2-1, length)) ;
	last_row = EMPTY ;
	for (p = p1 ; p < p2 ; p++)
	{
	    row = Ai [p] ;
	    PRINTF4 (("\t%s "ID" ", index, INDEX (row))) ;
	    if (Ax)
	    {
		PRINTF4 ((": %g ", Ax [p])) ;
	    }
	    if (row < 0 || row >= n)
	    {
		PRINTF (("ERROR: %s index "ID" out of range in %s "ID"\n\n",
		    index, INDEX (row), vector, INDEX (col))) ;
		(void) UMF_free ((void *) W) ;
		return (UMFPACK_ERROR_row_index_out_of_bounds) ;
	    }
	    if (row <= last_row)
	    {
		PRINTF (("ERROR: %s index "ID" out of order (or duplicate) in "
		    "%s "ID"\n\n", index, INDEX (row), vector, INDEX (col))) ;
		(void) UMF_free ((void *) W) ;
		return (UMFPACK_ERROR_jumbled_matrix) ;
	    }
	    PRINTF4 (("\n")) ;
	    /* mark the row */
	    W [row] = FALSE ;
	    /* truncate printout, but continue to check matrix */
	    if (prl == 4 && (p - p1) == 9 && length > 10)
	    {
		PRINTF4 (("\t...\n")) ;
		prl-- ;
	    }
	    last_row = row ;
	}
	/* truncate printout, but continue to check matrix */
	if (prl == 4 && col == 9 && n > 10)
	{
	    PRINTF4 (("\n    ...\n")) ;
	    prl-- ;
	}
    }
    prl = prl1 ;

    /* ---------------------------------------------------------------------- */
    /* check for empty rows */
    /* ---------------------------------------------------------------------- */

    nempty = 0 ;

    for (row = 0 ; row < n ; row++)
    {
	if (W [row])
	{
	    /* the row has not been marked */
	    nempty++ ;
	    note = TRUE ;
	    if ((prl == 4 && nempty < 10) || prl > 4)
	    {
		PRINTF (("    NOTE: %s "ID" has no entries\n",
		    index, INDEX (row))) ;
	    }
	    else if (prl == 4 && nempty == 10)
	    {
		PRINTF (("    ...\n")) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* return the status of the matrix */
    /* ---------------------------------------------------------------------- */

    PRINTF4 (("    ")) ;
    if (name)
    {
	PRINTF4 (("%s: ", name)) ;
    }
    PRINTF4 (("%s-form matrix ", vector)) ;

    if (note)
    {
	PRINTF (("valid but structurally singular\n")) ;
	result = UMFPACK_ERROR_singular_matrix ;
    }
    else
    {
	PRINTF (("OK\n")) ;
	result = UMFPACK_OK ;
    }
    PRINTF (("\n")) ;

    (void) UMF_free ((void *) W) ;
    return (result) ;
}

