/* ========================================================================== */
/* === umf_config.h ========================================================= */
/* ========================================================================== */

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

/*
    This file controls the compile-time configuration of UMFPACK.  Modify the
    Makefile, the architecture-dependent Make.* file, and this file if
    necessary, to control these options.  The following compile-time flags are
    available:

	-DNBLAS

	    BLAS mode.  If -DNBLAS is set, then no BLAS will be used.  Vanilla
	    C code will be used instead.  This is portable, and easier to
	    install, but you won't get the best performance.

	    If -DNBLAS is not set, then externally-available BLAS routines
	    (dgemm, dger, and dgemv or the equivalent C-BLAS routines) will be
	    used.  This will give you the best performance, but perhaps at the
	    expense of portability.

	    The default is to use the BLAS, for both the C-callable umfpack.a
	    library and the Matlab mexFunction.  If you have trouble installing
	    UMFPACK, set -DNBLAS.

	-DNCBLAS

	    If -DNCBLAS is set, then the C-BLAS will not be called.  This is the
	    default when compiling the Matlab mexFunction, or when compiling
	    umfpack.a on Sun Solaris or SGI IRIX.

	    If -DNCBLAS is not set, then the C-BLAS interface to the BLAS is
	    used.  If your vendor-supplied BLAS library does not have a C-BLAS
	    interface, you can obtain the ATLAS BLAS, available at
	    http://www.netlib.org/atlas.

	    Using the C-BLAS is the default when compiling umfpack.a on all
	    architectures except Sun Solaris (the Sun Performance Library is
	    somewhat faster).  The ANSI C interface to the BLAS is fully
	    portable.

	    This flag is ignored if -DNBLAS is set.

	-DLONGBLAS

	    If not defined, then the BLAS are not called in the long integer
	    version of UMFPACK (the umfpack_l_* routines).  The most common
	    definitions of the BLAS, unfortunately, use int arguments, and
	    are thus not suitable for use in the LP64 model.  Only the Sun
	    Performance Library, as far as I can tell, has a version of the
	    BLAS that allows long integer (64-bit) input arguments.  This
	    flag is set automatically in Sun Solaris if you are using the
	    Sun Performance BLAS.  You can set it yourself, too, if your BLAS
	    routines can take long integer input arguments.

	-DNSUNPERF

	    Applies only to Sun Solaris.  If -DNSUNPERF is set, then the Sun
	    Performance Library BLAS will not be used.

	    The Sun Performance Library BLAS is used by default when compiling
	    the C-callable umfpack.a library on Sun Solaris.

	    This flag is ignored if -DNBLAS is set.

	-DNSCSL

	    Applies only to SGI IRIX.  If -DSCSL is set, then the SGI SCSL
	    Scientific Library BLAS will not be used.

	    The SGI SCSL Scientific Library BLAS is used by default when
	    compiling the C-callable umfpack.a library on SGI IRIX.

	    This flag is ignored if -DNBLAS is set.

	-DGETRUSAGE

	    If -DGETRUSAGE is set, then your system's getrusage routine will be
	    used for getting the process CPU time.  Otherwise the ANSI C clock
	    routine will be used.  The default is to use getrusage on Sun
	    Solaris, SGI Irix, Linux, and AIX (IBM RS 6000) and to use clock on
	    all other architectures.

    C-to-Fortran interface, for the Fortran BLAS (these are set automatically
	for the C-BLAS or Sun Performance BLAS):

	-DBLAS_BY_VALUE		if scalars are passed by value, not reference
	-DBLAS_NO_UNDERSCORE	if no underscore should be appended
	-DBLAS_CHAR_ARG		if BLAS options are single char's, not strings

    You should normally not set these flags yourself:

	-DMATLAB_MEX_FILE

	    This flag is turned on when compiling the umfpack mexFunction for
	    use in Matlab.  When compiling the Matlab mexFunction, the Matlab
	    BLAS are used by default (this is set in the Makefile).

	-DMATHWORKS

	    This flag is turned on when compiling umfpack as a built-in routine
	    in Matlab.  It can also be used when compiling umfpack as a
	    mexFunction.  Internal routines utMalloc, utFree, utRealloc, and
	    utPrintf are used, and the "util.h" file is included.  This avoids
	    the problem discussed in the User Guide regarding memory allocation
	    in Matlab.  utMalloc returns NULL on failure, instead of terminating
	    the mexFunction (which is what mxMalloc does).  However, the ut*
	    routines are not documented by The MathWorks, Inc., so I cannot
	    guarantee that you will always be able to use them.

	-DNDEBUG

	    Debugging mode (if NDEBUG is not defined).  The default, of course,
	    is no debugging.  Turning on debugging takes some work (see below).

*/



/* ========================================================================== */
/* === NDEBUG =============================================================== */
/* ========================================================================== */

/*
    UMFPACK will be exceedingly slow when running in debug mode.  The next three
    lines ensure that debugging is turned off.  If you want to compile UMFPACK
    in debugging mode, you must comment out the three lines below:
*/
#ifndef NDEBUG
#define NDEBUG
#endif

/*
    Next, you must either remove the -DNDEBUG option in the Makefile, or simply
    add the following line:
#undef NDEBUG
*/


/* ========================================================================== */
/* === Memory allocator ===================================================== */
/* ========================================================================== */

/* The Matlab mexFunction uses Matlab's memory manager, while the C-callable */
/* umfpack.a library uses the ANSI C malloc, free, and realloc routines. */

#ifdef MATLAB_MEX_FILE
#include "matrix.h"
#define ALLOCATE mxMalloc
#define FREE mxFree
#define REALLOCATE mxRealloc
#else
#ifdef MATHWORKS
#include "util.h"
/* Compiling UMFPACK as a built-in routine. */
/* Since UMFPACK carefully checks for out-of-memory after every allocation, */
/* we can use ut* routines here. */
#define ALLOCATE utMalloc
#define FREE utFree
#define REALLOCATE utRealloc
#else
#define ALLOCATE malloc
#define FREE free
#define REALLOCATE realloc
#endif
#endif


/* ========================================================================== */
/* === PRINTF macro ========================================================= */
/* ========================================================================== */

/* All output goes through the PRINTF macro.  Printing occurs only from the */
/* UMFPACK_report_* routines. */

#ifdef MATLAB_MEX_FILE
#include "mex.h"
#define PRINTF(params) { (void) mexPrintf params ; }
#else
#ifdef MATHWORKS
/* Already #included "util.h" above in Memory allocator section */
#define PRINTF(params) { (void) utPrintf params ; }
#else
#define PRINTF(params) { (void) printf params ; }
#endif
#endif


/* ========================================================================== */
/* === 0-based or 1-based printing ========================================== */
/* ========================================================================== */

#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
/* In Matlab, matrices are 1-based to the user, but 0-based internally. */
/* One is added to all row and column indices when printing matrices */
/* in UMFPACK_report_*.  */
#define INDEX(i) ((i)+1)
#else
/* In ANSI C, matrices are 0-based and indices are reported as such. */
#define INDEX(i) (i)
#endif


/* ========================================================================== */
/* === Architecture ========================================================= */
/* ========================================================================== */

#if defined (__sun)
#define UMFPACK_ARCHITECTURE "Sun Solaris"
#endif

#if defined (__sgi)
#define UMFPACK_ARCHITECTURE "SGI Irix"
#endif

#if defined (__linux)
#define UMFPACK_ARCHITECTURE "Linux"
#endif

#if defined (_AIX)
#define UMFPACK_ARCHITECTURE "IBM AIX"
#endif

#if defined (__alpha)
#define UMFPACK_ARCHITECTURE "Compaq Alpha"
#endif

/* ========================================================================== */
/* === Timer ================================================================ */
/* ========================================================================== */

/*
    If you have the getrusage routine (all Unix systems I've test do), then use
    that.  Otherwise, use the ANSI C clock function.   Note that on many
    systems, the ANSI clock function wraps around after only 2147 seconds, or
    about 36 minutes.  BE CAREFUL:  if you compare the run time of UMFPACK with
    other sparse matrix packages, be sure to use the same timer.  See
    umfpack_timer.c for the timer used by UMFPACK.
*/

/* Sun Solaris, SGI Irix, Linux, Compaq Alpha, and IBM RS 6000 all have */
/* getrusage.  It's in BSD unix, so perhaps all unix systems have it. */
#if defined (__sun) || defined (__sgi) || defined (__linux) \
|| defined (__alpha) || defined (_AIX)
#define GETRUSAGE
#endif


/* ========================================================================== */
/* === BLAS ================================================================= */
/* ========================================================================== */

/*
    Determine if the BLAS exists for the long integer version.  It exists if
    LONGBLAS is defined in the Makefile, or if using the BLAS from the
    Sun Performance Library, or SGI's SCSL Scientific Library.
*/

#if !defined (MATLAB_MEX_FILE) && defined (__sun) && !defined (NSUNPERF)
#define BLAS_SUNPERF
#ifndef LONGBLAS
#define LONGBLAS
#endif
#endif

#if !defined (MATLAB_MEX_FILE) && defined (__sgi) && !defined (NSCSL)
#define BLAS_SCSL
#ifndef LONGBLAS
#define LONGBLAS
#endif
#endif

#if defined (DLONG) && !defined (LONGBLAS) && !defined (NBLAS)
#define NBLAS
#endif

/* -------------------------------------------------------------------------- */

#ifndef NBLAS

/*
    If the compile-time flag -DNBLAS is defined, then the BLAS are not used,
    portable vanilla C code is used instead, and the remainder of this file
    is ignored.

    Using the BLAS is much faster, but how C calls the Fortran BLAS is
    machine-dependent and thus can cause portability problems.  Thus, use
    -DNBLAS to ensure portability (at the expense of speed).

    Preferences:

	*** The best interface to use, regardless of the option you select
	    below, is the standard C-BLAS interface.  Not all vendor-supplied
	    BLAS libraries use this interface (as of April 2001).  The only
	    problem with this interface is that it does not extend to the LP64
	    model.

	1) most preferred:  use the optimized vendor-supplied library (such as
	    the Sun Performance Library, or IBM's ESSL).  This is often the
	    fastest, but might not be portable and might not always be
	    available.  When compiling a Matlab mexFunction it might be
	    difficult get the mex compiler script to recognize the vendor-
	    supplied BLAS (I was not able get my mexFunction to use the
	    Sun Performance Library BLAS, for example, because of linking
	    difficulties).

	2) When compiling the UMFPACK mexFunction to use UMFPACK in Matlab, use
	    the BLAS provided by The Mathworks, Inc.  This assumes you are using
	    Matlab V6 or higher, since the BLAS are not incorporated in V5 or
	    earlier versions.  On my Sun workstation, the Matlab BLAS gave
	    slightly worse performance than the Sun Perf. BLAS.  The advantage
	    of using the Matlab BLAS is that it's available on any computer that
	    has Matlab V6 or higher.  I have not tried using Matlab BLAS outside
	    of a mexFunction in a stand-alone C code, but Matlab (V6) allows for
	    this.  This is well worth trying if you have Matlab and don't want
	    to bother installing the ATLAS BLAS (option 3a, below).  The only
	    glitch to this is that Matlab does not provide a portable interface
	    to the BLAS (an underscore is required for some but not all
	    architectures).  These variations are taken into account in the
	    mexopts.sh file provided with UMFPACK.

	3) Use a portable high-performance BLAS library:

	    (a) The ATLAS BLAS, available at http://www.netlib.org/atlas,
		by R. Clint Whaley, Antoine Petitet, and Jack Dongarra.
		This has a standard C interface, and thus the interface to it is
		fully portable.  Its performance rivals, and sometimes exceeds,
		the vendor-supplied BLAS on many computers.

	    (b) The Fortran RISC BLAS by Michel Dayde', Iain Duff, Antoine
		Petitet, and Abderrahim Qrichi Aniba, available via anonymous
		ftp to ftp.enseeiht.fr in the pub/numerique/BLAS/RISC directory,
		See M. J. Dayde' and I. S. Duff, "The RISC BLAS:  A blocked
		implementation of level 3 BLAS for RISC processors, ACM Trans.
		Math. Software, vol. 25, no. 3., Sept. 1999.  This will give
		you good performance, but with the same C-to-Fortran portability
		problems as option (1).

	4) Use UMFPACK's built-in vanilla C code by setting -DNBLAS at compile
	    time.  The key advantage is portability, which is guaranteed if you
	    have an ANSI C compliant compiler.  You also don't need to download
	    any other package - UMFPACK is stand-alone.  No Fortran is used
	    anywhere in UMFPACK.  UMFPACK will be much slower than when using
	    options (1) through (3), however.

	5) least preferred:  use the standard Fortran implementation of the
	    BLAS, also available at Netlib (http://www.netlib.org/blas).  This
	    will be no faster than option (4), and not portable because of
	    C-to-Fortran calling conventions.  Don't bother trying option (5).

    The mechanics of how C calls the BLAS on various computers are as follows:

	* C-BLAS (from the ATLAS library, for example):

	    The same interface is used on all computers.  This is the default
	    (except on Sun Solaris, or when compiling the Matlab mexFunction).
	    SGI Irix provides a C-BLAS interface to its vendor-supplied BLAS.

	* Defaults for calling the Fortran BLAS:
	    add underscore, pass scalars by reference, use string arguments.

	* The Fortran BLAS on Sun Solaris (when compiling the Matlab mexFunction
	    or when using the Fortran RISC BLAS), SGI, Linux:
	    use defaults.

	* Sun Solaris (when using the C-callable Sun Performance library):
	    no underscore, pass scalars by value, use character arguments.

	* The Fortran BLAS (ESSL Library) on the IBM RS 6000:
	    no underscore, pass scalars by reference, use string arguments.

	* The Fortran BLAS on the HP PA:
	    no underscore, pass scalars by reference, use string arguments.
	    This has not been tested.  For the umfpack.a library, I recommend
	    using the C-BLAS in the ATLAS library instead.  The Matlab
	    mexFunction needs to have the -DBLAS_NO_UNDERSCORE compile-time
	    flag set.  I've modified the mexopts.sh file to do this, but have
	    not tested it.

	* The Fortran BLAS on Windows:
	    no underscore, pass scalars by reference, use string arguments.
	    This has not been tested.  For the umfpack.a library, I recommend
	    using the C-BLAS in the ATLAS library instead.  The Mathworks-
	    provided lcc compiler prepends an underscore to all C routine names.
	    Thus, dgemm becomes _dgemm.  However, the Mathworks BLAS library has
	    dgemm, not _dgemm.  I've contacted Mathworks and so far there is
	    no work-around for this problem.  Use another compiler.  If you must
	    use lcc then either do not use the BLAS in Matlab or use the C-BLAS.

*/



#ifndef NCBLAS

/* -------------------------------------------------------------------------- */
/* use the C-BLAS (any computer) */
/* -------------------------------------------------------------------------- */

/* This is the default, except for Solaris and IRIX umfpack.a, and for the */
/* mexFunction on any architecture. */

/* If you use the ATLAS C-BLAS, then be sure to set the -I flag to */
/* -I/path/ATLAS/include, where /path/ATLAS is the ATLAS installation */
/* directory.  Note that UMFPACK uses column-major storage for its dense */
/* matrices, but these are not visible to the user. */

#include "cblas.h"

#define BLAS_DGEMM_ROUTINE cblas_dgemm
#define BLAS_DGEMV_ROUTINE cblas_dgemv
#define BLAS_DGER_ROUTINE  cblas_dger

#define BLAS_NO_TRANSPOSE CblasNoTrans
#define BLAS_TRANSPOSE CblasTrans

/* This argument is present only for the C-BLAS: */
#define BLAS_COLUMN_MAJOR_ORDER CblasColMajor,

#define BLAS_SCALAR(n) n
#define BLAS_INT_SCALAR(n) n

#else

/* No such argument when not using the C-BLAS */
#define BLAS_COLUMN_MAJOR_ORDER


/* -------------------------------------------------------------------------- */
/* use Fortran (or other architecture-specific) BLAS */
/* -------------------------------------------------------------------------- */

/* Determine which architecture we're on and set options accordingly. */

#ifdef BLAS_SUNPERF
/* Sun Solaris sunperf library - the default for Solaris umfpack.a */
#include <sunperf.h>
#define BLAS_BY_VALUE
#define BLAS_NO_UNDERSCORE
#define BLAS_CHAR_ARG
#endif

#ifdef BLAS_SCSL
/* SGI SCSL library - the default for SGI umfpack.a */
#if defined (LP64)
#include <scsl_blas_i8.h>
#else
#include <scsl_blas.h>
#endif
#define BLAS_BY_VALUE
#define BLAS_NO_UNDERSCORE
#endif

/* The IBM RS 6000 does not add the underscore */
#if defined (_AIX)
#define BLAS_NO_UNDERSCORE
#endif

/*
    Add your own architecture-dependent settings here.
    For example, to call the Fortran BLAS on Windows, or HP PA:

    #if defined (__win32) || defined (__hppa)
    #define BLAS_NO_UNDERSCORE
    #endif
*/


/* -------------------------------------------------------------------------- */
/* BLAS names */
/* -------------------------------------------------------------------------- */

#if defined (LP64) && defined (BLAS_SUNPERF)

/* 64-bit sunperf BLAS, for Sun Solaris only */
#define BLAS_DGEMM_ROUTINE dgemm_64
#define BLAS_DGEMV_ROUTINE dgemv_64
#define BLAS_DGER_ROUTINE  dger_64

#else

/* naming convention (use underscore, or not) */
#ifdef BLAS_NO_UNDERSCORE
#define BLAS_DGEMM_ROUTINE dgemm
#define BLAS_DGEMV_ROUTINE dgemv
#define BLAS_DGER_ROUTINE  dger
#else
/* default:  add underscore */
#define BLAS_DGEMM_ROUTINE dgemm_
#define BLAS_DGEMV_ROUTINE dgemv_
#define BLAS_DGER_ROUTINE  dger_
#endif

#endif /* LP64 && BLAS_SUNPERF */

/* -------------------------------------------------------------------------- */
/* BLAS scalars */
/* -------------------------------------------------------------------------- */

/* pass scalars by value or by reference */
#ifdef BLAS_BY_VALUE
#define BLAS_SCALAR(n) n
#else
/* default:  pass scalars by reference */
#define BLAS_SCALAR(n) &(n)
#endif

#if defined (BLAS_SCSL) && defined (LP64)
#define BLAS_INT_SCALAR(n) ((long long) n)
#else
#define BLAS_INT_SCALAR(n) BLAS_SCALAR(n)
#endif

/* -------------------------------------------------------------------------- */
/* BLAS strings */
/* -------------------------------------------------------------------------- */

/* pass strings or single characters */
#ifdef BLAS_CHAR_ARG
#define BLAS_NO_TRANSPOSE 'N'
#define BLAS_TRANSPOSE 'T'
#else
/* default:  use string arguments */
#define BLAS_NO_TRANSPOSE "N"
#define BLAS_TRANSPOSE "T"
#endif


#endif /* NCBLAS */



/* -------------------------------------------------------------------------- */
/* BLAS macros, for all interfaces */
/* -------------------------------------------------------------------------- */


/* C = C - A*B, where A is m-by-k, B is k-by-n, and leading dimension is d */
#define BLAS_DGEMM(m,n,k,A,B,C,d) \
{ \
    double alpha = -1.0 ; \
    double beta = 1.0 ; \
    (void) BLAS_DGEMM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
	BLAS_NO_TRANSPOSE, BLAS_NO_TRANSPOSE, \
	BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_INT_SCALAR (k), \
	BLAS_SCALAR (alpha), \
	A, BLAS_INT_SCALAR (d), B, BLAS_INT_SCALAR (d), BLAS_SCALAR (beta), \
	C, BLAS_INT_SCALAR (d)) ; \
}


/* A = A - x*y', where A is m-by-n with leading dimension d */
#define BLAS_DGER(m,n,x,y,A,d) \
{ \
    double alpha = -1.0 ; \
    Int incx = 1 ; \
    (void) BLAS_DGER_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
	BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \
	x, BLAS_INT_SCALAR (incx), y, BLAS_INT_SCALAR (d), A, BLAS_INT_SCALAR (d)) ; \
}


/* y = y - A'*x, where A is m-by-n with leading dimension d, */
/* and x and y are row vectors with stride d */
#define BLAS_DGEMV_ROW(m,n,A,x,y,d) \
{ \
    double alpha = -1.0 ; \
    double beta = 1.0 ; \
    (void) BLAS_DGEMV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
	BLAS_TRANSPOSE, \
	BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \
	A, BLAS_INT_SCALAR (d), x, BLAS_INT_SCALAR (d), BLAS_SCALAR (beta), \
	y, BLAS_INT_SCALAR (d)) ; \
}


/* y = y - A*x, where A is m-by-n with leading dimension d, */
/* and x and y are column vectors with stride 1 */
#define BLAS_DGEMV_COL(m,n,A,x,y,d) \
{ \
    double alpha = -1.0 ; \
    double beta = 1.0 ; \
    Int incx = 1 ; \
    Int incy = 1 ; \
    (void) BLAS_DGEMV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
	BLAS_NO_TRANSPOSE, \
	BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \
	A, BLAS_INT_SCALAR (d), x, BLAS_INT_SCALAR (incx), BLAS_SCALAR (beta), \
	y, BLAS_INT_SCALAR (incy)) ; \
}


#endif	/* NBLAS */



