/* ========================================================================== */
/* === UMFPACK_wsolve ======================================================= */
/* ========================================================================== */

/* -------------------------------------------------------------------------- */
/* 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.  Solves a linear system using the numerical factorization
    computed by UMFPACK_numeric.  See umfpack_wsolve.h for more details.
*/

#include "umf_internal.h"
#include "umf_valid_numeric.h"
#include "umf_solve.h"

GLOBAL Int UMFPACK_wsolve
(
    const char sys [ ],
    const Int Ap [ ],
    const Int Ai [ ],
    const double Ax [ ],
    double X [ ],
    const double B [ ],
    void *NumericHandle,
    const double Control [UMFPACK_CONTROL],
    double User_Info [UMFPACK_INFO]
    , Int Pattern [ ],
    double W [ ],
    double Y [ ],
    double Z [ ],
    double S [ ]
)
{
    /* ---------------------------------------------------------------------- */
    /* local variables */
    /* ---------------------------------------------------------------------- */

    NumericType *Numeric ;
    Int n, i, irstep, status ;
    double Info2 [UMFPACK_INFO], *Info, tstart, tend ;

    /* ---------------------------------------------------------------------- */
    /* get the amount of time used by the process so far */
    /* ---------------------------------------------------------------------- */

    tstart = umfpack_timer ( ) ;

    /* ---------------------------------------------------------------------- */
    /* get parameters */
    /* ---------------------------------------------------------------------- */

    if (Control)
    {
	/* use the Control array passed to us by the caller. */
	irstep = (Int) Control [UMFPACK_IRSTEP] ;
    }
    else
    {
	/* no Control passed - use defaults instead */
	irstep = UMFPACK_DEFAULT_IRSTEP ;
    }

    if (User_Info)
    {
	/* return Info in user's array */
	Info = User_Info ;
	for (i = UMFPACK_IR_TAKEN ; i <= UMFPACK_SOLVE_TIME ; i++)
	{
	    Info [i] = EMPTY ;
	}
    }
    else
    {
	/* no Info array passed - use local one instead */
	Info = Info2 ;
	for (i = 0 ; i < UMFPACK_INFO ; i++)
	{
	    Info [i] = EMPTY ;
	}
    }
    Info [UMFPACK_STATUS] = UMFPACK_OK ;
    Info [UMFPACK_SOLVE_FLOPS] = 0 ;

    Numeric = (NumericType *) NumericHandle ;
    if (!UMF_valid_numeric (Numeric))
    {
	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;
	return (UMFPACK_ERROR_invalid_Numeric_object) ;
    }

    n = Numeric->n ;
    Info [UMFPACK_N] = n ;

    if (!X || !B || !sys)
    {
	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
	return (UMFPACK_ERROR_argument_missing) ;
    }

    /* ---------------------------------------------------------------------- */
    /* check the workspace */
    /* ---------------------------------------------------------------------- */

    /* UMF_solve requires W and Pattern for solving any system */
    if (!W || !Pattern)
    {
	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
	return (UMFPACK_ERROR_argument_missing) ;
    }
    if (irstep > 0 && sys)
    {
	if (STRING_MATCH (sys, "Ax=b") || (STRING_MATCH (sys, "A'x=b")))
	{
	    /* UMF_solve needs 3*n double workspace for iter. refinement */
	    if (!Y || !Z || !S)
	    {
		Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
		return (UMFPACK_ERROR_argument_missing) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* solve the system */
    /* ---------------------------------------------------------------------- */

    status = UMF_solve (sys, Ap, Ai, Ax, X, B, Numeric,
	irstep, Info, Pattern, W, Y, Z, S) ;

    /* ---------------------------------------------------------------------- */
    /* get the time used by UMFPACK_wsolve */
    /* ---------------------------------------------------------------------- */

    Info [UMFPACK_STATUS] = status ;
    if (status == UMFPACK_OK)
    {
	tend = umfpack_timer ( ) ;
	Info [UMFPACK_SOLVE_TIME] = MAX (0, tend - tstart) ;
    }

    return (status) ;
}

