/* ========================================================================== */
/* === Include/cholmod_internal.h =========================================== */
/* ========================================================================== */

/* -----------------------------------------------------------------------------
 * CHOLMOD/Include/cholmod_internal.h.
 * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
 * CHOLMOD/Include/cholmod_internal.h is licensed under Version 2.1 of the GNU
 * Lesser General Public License.  See lesser.txt for a text of the license.
 * CHOLMOD is also available under other licenses; contact authors for details.
 * -------------------------------------------------------------------------- */

/* CHOLMOD internal include file.
 *
 * This file contains internal definitions for CHOLMOD, not meant to be included
 * in user code.  They define macros that are not prefixed with CHOLMOD_.  This
 * file can safely #include'd in user code if you want to make use of the
 * macros defined here, and don't mind the possible name conflicts with your
 * code, however.
 *
 * Required by all CHOLMOD routines.  Not required by any user routine that
 * uses CHOLMOMD.  Unless debugging is enabled, this file does not require any
 * CHOLMOD module (not even the Core module).
 *
 * If debugging is enabled, all CHOLMOD modules require the Check module.
 * Enabling debugging requires that this file be editted.  Debugging cannot be
 * enabled with a compiler flag.  This is because CHOLMOD is exceedingly slow
 * when debugging is enabled.  Debugging is meant for development of CHOLMOD
 * itself, not by users of CHOLMOD.
 */

#ifndef CHOLMOD_INTERNAL_H
#define CHOLMOD_INTERNAL_H

/* ========================================================================== */
/* === large file I/O ======================================================= */
/* ========================================================================== */

/* Definitions for large file I/O must come before any other #includes.  If
 * this causes problems (may not be portable to all platforms), then compile
 * CHOLMOD with -DNLARGEFILE.  You must do this for MATLAB 6.5 and earlier,
 * for example. */

#include "cholmod_io64.h"

/* ========================================================================== */
/* === debugging and basic includes ========================================= */
/* ========================================================================== */

/* turn off debugging */
#ifndef NDEBUG
#define NDEBUG
#endif

/* Uncomment this line to enable debugging.  CHOLMOD will be very slow.
#undef NDEBUG
 */

#ifdef MATLAB_MEX_FILE
#include "mex.h"
#endif

#if !defined(NPRINT) || !defined(NDEBUG)
#include <stdio.h>
#endif

#include <stddef.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <stdlib.h>

/* ========================================================================== */
/* === basic definitions ==================================================== */
/* ========================================================================== */

/* Some non-conforming compilers insist on defining TRUE and FALSE. */
#undef TRUE
#undef FALSE
#define TRUE 1
#define FALSE 0
#define BOOLEAN(x) ((x) ? TRUE : FALSE)

/* NULL should already be defined, but ensure it is here. */
#ifndef NULL
#define NULL ((void *) 0)
#endif

/* FLIP is a "negation about -1", and is used to mark an integer i that is
 * normally non-negative.  FLIP (EMPTY) is EMPTY.  FLIP of a number > EMPTY
 * is negative, and FLIP of a number < EMTPY is positive.  FLIP (FLIP (i)) = i
 * for all integers i.  UNFLIP (i) is >= EMPTY. */
#define EMPTY (-1)
#define FLIP(i) (-(i)-2)
#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i))

/* MAX and MIN are not safe to use for NaN's */
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c)))
#define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d)))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define IMPLIES(p,q) (!(p) || (q))

/* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise.
 * Not safe for NaN's */
#define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0))

/* round up an integer x to a multiple of s */
#define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s)))

#define ERROR(status,msg) \
    CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common)

/* Check a pointer and return if null.  Set status to invalid, unless the
 * status is already "out of memory" */
#define RETURN_IF_NULL(A,result) \
{ \
    if ((A) == NULL) \
    { \
	if (Common->status != CHOLMOD_OUT_OF_MEMORY) \
	{ \
	    ERROR (CHOLMOD_INVALID, "argument missing") ; \
	} \
	return (result) ; \
    } \
}

/* Return if Common is NULL or invalid */
#define RETURN_IF_NULL_COMMON(result) \
{ \
    if (Common == NULL) \
    { \
	return (result) ; \
    } \
    if (Common->itype != ITYPE || Common->dtype != DTYPE) \
    { \
	Common->status = CHOLMOD_INVALID ; \
	return (result) ; \
    } \
}

#define IS_NAN(x)	CHOLMOD_IS_NAN(x)
#define IS_ZERO(x)	CHOLMOD_IS_ZERO(x)
#define IS_NONZERO(x)	CHOLMOD_IS_NONZERO(x)
#define IS_LT_ZERO(x)	CHOLMOD_IS_LT_ZERO(x)
#define IS_GT_ZERO(x)	CHOLMOD_IS_GT_ZERO(x)
#define IS_LE_ZERO(x)	CHOLMOD_IS_LE_ZERO(x)

/* 1e308 is a huge number that doesn't take many characters to print in a
 * file, in CHOLMOD/Check/cholmod_read and _write.  Numbers larger than this
 * are interpretted as Inf, since sscanf doesn't read in Inf's properly.
 * This assumes IEEE double precision arithmetic.  DBL_MAX would be a little
 * better, except that it takes too many digits to print in a file. */
#define HUGE_DOUBLE 1e308

/* ========================================================================== */
/* === int/long and double/float definitions ================================ */
/* ========================================================================== */

/* CHOLMOD is designed for 3 types of integer variables:
 *
 *	(1) all integers are int
 *	(2) most integers are int, some are SuiteSparse_long
 *	(3) all integers are SuiteSparse_long
 *
 * and two kinds of floating-point values:
 *
 *	(1) double
 *	(2) float
 *
 * the complex types (ANSI-compatible complex, and MATLAB-compatable zomplex)
 * are based on the double or float type, and are not selected here.  They
 * are typically selected via template routines.
 *
 * This gives 6 different modes in which CHOLMOD can be compiled (only the
 * first two are currently supported):
 *
 *	DINT	double, int			prefix: cholmod_
 *	DLONG	double, SuiteSparse_long	prefix: cholmod_l_
 *	DMIX	double, mixed int/SuiteSparse_long	prefix: cholmod_m_
 *	SINT	float, int			prefix: cholmod_si_
 *	SLONG	float, SuiteSparse_long		prefix: cholmod_sl_
 *	SMIX	float, mixed int/log		prefix: cholmod_sm_
 *
 * These are selected with compile time flags (-DDLONG, for example).  If no
 * flag is selected, the default is DINT.
 *
 * All six versions use the same include files.  The user-visible include files
 * are completely independent of which int/long/double/float version is being
 * used.  The integer / real types in all data structures (sparse, triplet,
 * dense, common, and triplet) are defined at run-time, not compile-time, so
 * there is only one "cholmod_sparse" data type.  Void pointers are used inside
 * that data structure to point to arrays of the proper type.  Each data
 * structure has an itype and dtype field which determines the kind of basic
 * types used.  These are defined in Include/cholmod_core.h.
 *
 * FUTURE WORK: support all six types (float, and mixed int/long)
 *
 * SuiteSparse_long is normally defined as long.  However, for WIN64 it is
 * __int64.  It can also be redefined for other platforms, by modifying
 * SuiteSparse_config.h.
 */

#include "SuiteSparse_config.h"

/* -------------------------------------------------------------------------- */
/* Size_max: the largest value of size_t */
/* -------------------------------------------------------------------------- */

#define Size_max ((size_t) (-1))

/* routines for doing arithmetic on size_t, and checking for overflow */
size_t cholmod_add_size_t (size_t a, size_t b, int *ok) ;
size_t cholmod_mult_size_t (size_t a, size_t k, int *ok) ;
size_t cholmod_l_add_size_t (size_t a, size_t b, int *ok) ;
size_t cholmod_l_mult_size_t (size_t a, size_t k, int *ok) ;

/* -------------------------------------------------------------------------- */
/* double (also complex double), SuiteSparse_long */
/* -------------------------------------------------------------------------- */

#ifdef DLONG
#define Real double
#define Int SuiteSparse_long
#define Int_max SuiteSparse_long_max
#define CHOLMOD(name) cholmod_l_ ## name
#define LONG
#define DOUBLE
#define ITYPE CHOLMOD_LONG
#define DTYPE CHOLMOD_DOUBLE
#define ID SuiteSparse_long_id

/* -------------------------------------------------------------------------- */
/* double (also complex double), int: this is the default */
/* -------------------------------------------------------------------------- */

#else

#ifndef DINT
#define DINT
#endif
#define INT
#define DOUBLE

#define Real double
#define Int int
#define Int_max INT_MAX
#define CHOLMOD(name) cholmod_ ## name
#define ITYPE CHOLMOD_INT
#define DTYPE CHOLMOD_DOUBLE
#define ID "%d"

/* GPU acceleration is not available for the int version of CHOLMOD */
#undef GPU_BLAS

#endif


/* ========================================================================== */
/* === real/complex arithmetic ============================================== */
/* ========================================================================== */

#include "cholmod_complexity.h"

/* ========================================================================== */
/* === Architecture and BLAS ================================================ */
/* ========================================================================== */

#define BLAS_OK Common->blas_ok
#include "cholmod_blas.h"

/* ========================================================================== */
/* === debugging definitions ================================================ */
/* ========================================================================== */

#ifndef NDEBUG

#include <assert.h>
#include "cholmod.h"

/* The cholmod_dump routines are in the Check module.  No CHOLMOD routine
 * calls the cholmod_check_* or cholmod_print_* routines in the Check module,
 * since they use Common workspace that may already be in use.  Instead, they
 * use the cholmod_dump_* routines defined there, which allocate their own
 * workspace if they need it. */

#ifndef EXTERN
#define EXTERN extern
#endif

/* double, int */
EXTERN int cholmod_dump ;
EXTERN int cholmod_dump_malloc ;
SuiteSparse_long cholmod_dump_sparse (cholmod_sparse  *, const char *,
    cholmod_common *) ;
int  cholmod_dump_factor (cholmod_factor  *, const char *, cholmod_common *) ;
int  cholmod_dump_triplet (cholmod_triplet *, const char *, cholmod_common *) ;
int  cholmod_dump_dense (cholmod_dense   *, const char *, cholmod_common *) ;
int  cholmod_dump_subset (int *, size_t, size_t, const char *,
    cholmod_common *) ;
int  cholmod_dump_perm (int *, size_t, size_t, const char *, cholmod_common *) ;
int  cholmod_dump_parent (int *, size_t, const char *, cholmod_common *) ;
void cholmod_dump_init (const char *, cholmod_common *) ;
int  cholmod_dump_mem (const char *, SuiteSparse_long, cholmod_common *) ;
void cholmod_dump_real (const char *, Real *, SuiteSparse_long,
    SuiteSparse_long, int, int, cholmod_common *) ;
void cholmod_dump_super (SuiteSparse_long, int *, int *, int *, int *, double *,
    int, cholmod_common *) ;
int  cholmod_dump_partition (SuiteSparse_long, int *, int *, int *, int *,
    SuiteSparse_long, cholmod_common *) ;
int  cholmod_dump_work(int, int, SuiteSparse_long, cholmod_common *) ;

/* double, SuiteSparse_long */
EXTERN int cholmod_l_dump ;
EXTERN int cholmod_l_dump_malloc ;
SuiteSparse_long cholmod_l_dump_sparse (cholmod_sparse  *, const char *,
    cholmod_common *) ;
int  cholmod_l_dump_factor (cholmod_factor  *, const char *, cholmod_common *) ;
int  cholmod_l_dump_triplet (cholmod_triplet *, const char *, cholmod_common *);
int  cholmod_l_dump_dense (cholmod_dense   *, const char *, cholmod_common *) ;
int  cholmod_l_dump_subset (SuiteSparse_long *, size_t, size_t, const char *,
    cholmod_common *) ;
int  cholmod_l_dump_perm (SuiteSparse_long *, size_t, size_t, const char *,
    cholmod_common *) ;
int  cholmod_l_dump_parent (SuiteSparse_long *, size_t, const char *,
    cholmod_common *) ;
void cholmod_l_dump_init (const char *, cholmod_common *) ;
int  cholmod_l_dump_mem (const char *, SuiteSparse_long, cholmod_common *) ;
void cholmod_l_dump_real (const char *, Real *, SuiteSparse_long,
    SuiteSparse_long, int, int, cholmod_common *) ;
void cholmod_l_dump_super (SuiteSparse_long, SuiteSparse_long *,
    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
    double *, int, cholmod_common *) ;
int  cholmod_l_dump_partition (SuiteSparse_long, SuiteSparse_long *,
    SuiteSparse_long *, SuiteSparse_long *,
    SuiteSparse_long *, SuiteSparse_long, cholmod_common *) ;
int  cholmod_l_dump_work(int, int, SuiteSparse_long, cholmod_common *) ;

#define DEBUG_INIT(s,Common)  { CHOLMOD(dump_init)(s, Common) ; }
#define ASSERT(expression) (assert (expression))

#define PRK(k,params) \
{ \
    if (CHOLMOD(dump) >= (k) && SuiteSparse_config.printf_func != NULL) \
    { \
	(SuiteSparse_config.printf_func) params ; \
    } \
}

#define PRINT0(params) PRK (0, params)
#define PRINT1(params) PRK (1, params)
#define PRINT2(params) PRK (2, params)
#define PRINT3(params) PRK (3, params)

#define PRINTM(params) \
{ \
    if (CHOLMOD(dump_malloc) > 0) \
    { \
	printf params ; \
    } \
}

#define DEBUG(statement) statement

#else

/* Debugging disabled (the normal case) */
#define PRK(k,params)
#define DEBUG_INIT(s,Common)
#define PRINT0(params)
#define PRINT1(params)
#define PRINT2(params)
#define PRINT3(params)
#define PRINTM(params)
#define ASSERT(expression)
#define DEBUG(statement)
#endif

#endif
