/*
 * DON'T INCLUDE THIS DIRECTLY.
 */

#ifndef NPY_NDARRAYOBJECT_H
#define NPY_NDARRAYOBJECT_H
#ifdef __cplusplus
#define CONFUSE_EMACS {
#define CONFUSE_EMACS2 }
extern "C" CONFUSE_EMACS
#undef CONFUSE_EMACS
#undef CONFUSE_EMACS2
/* ... otherwise a semi-smart identer (like emacs) tries to indent
       everything when you're typing */
#endif

/* This is auto-generated by the installer */
#include "numpyconfig.h"

#ifdef NPY_ENABLE_SEPARATE_COMPILATION
        #define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN
#else
        #define NPY_NO_EXPORT static
#endif

/* Only use thread if configured in config and python supports it */
#if defined WITH_THREAD && !NPY_NO_SMP
        #define NPY_ALLOW_THREADS 1
#else
        #define NPY_ALLOW_THREADS 0
#endif

#include "npy_endian.h"

#include "utils.h"

/* There are several places in the code where an array of dimensions is
 * allocated statically.  This is the size of that static allocation.
 *
 * The array creation itself could have arbitrary dimensions but
 * all the places where static allocation is used would need to
 * be changed to dynamic (including inside of several structures)
 */

#define NPY_MAXDIMS 32
#define NPY_MAXARGS 32

/* Used for Converter Functions "O&" code in ParseTuple */
#define NPY_FAIL 0
#define NPY_SUCCEED 1

/* Binary compatibility version number.  This number is increased
   whenever the C-API is changed such that binary compatibility is
   broken, i.e. whenever a recompile of extension modules is
   needed. */
#define NPY_VERSION NPY_ABI_VERSION

/* Minor API version.  This number is increased whenever a change is
   made to the C-API -- whether it breaks binary compatibility or not.
   Some changes, such as adding a function pointer to the end of the
   function table, can be made without breaking binary compatibility.
   In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION)
   would be increased.  Whenever binary compatibility is broken, both
   NPY_VERSION and NPY_FEATURE_VERSION should be increased.
 */
#define NPY_FEATURE_VERSION NPY_API_VERSION

#include "npy_common.h"

enum NPY_TYPES {    NPY_BOOL=0,
                    NPY_BYTE, NPY_UBYTE,
                    NPY_SHORT, NPY_USHORT,
                    NPY_INT, NPY_UINT,
                    NPY_LONG, NPY_ULONG,
                    NPY_LONGLONG, NPY_ULONGLONG,
                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
                    NPY_OBJECT=17,
                    NPY_STRING, NPY_UNICODE,
                    NPY_VOID,
                    NPY_NTYPES,
                    NPY_NOTYPE,
                    NPY_CHAR,      /* special flag */
                    NPY_USERDEF=256  /* leave room for characters */
};

#define NPY_METADATA_DTSTR "__frequency__"

/* basetype array priority */
#define NPY_PRIORITY 0.0

/* default subtype priority */
#define NPY_SUBTYPE_PRIORITY 1.0

/* default scalar priority */
#define NPY_SCALAR_PRIORITY -1000000.0

/* How many floating point types are there */
#define NPY_NUM_FLOATTYPE 3

/* We need to match npy_intp to a signed integer of the same size as
   a pointer variable. npy_uintp to the equivalent unsigned integer
*/


/* These characters correspond to the array type and the
   struct module */

/*  except 'p' -- signed integer for pointer type */

enum NPY_TYPECHAR { NPY_BOOLLTR = '?',
                        NPY_BYTELTR = 'b',
                        NPY_UBYTELTR = 'B',
                        NPY_SHORTLTR = 'h',
                        NPY_USHORTLTR = 'H',
                        NPY_INTLTR = 'i',
                        NPY_UINTLTR = 'I',
                        NPY_LONGLTR = 'l',
                        NPY_ULONGLTR = 'L',
                        NPY_LONGLONGLTR = 'q',
                        NPY_ULONGLONGLTR = 'Q',
                        NPY_FLOATLTR = 'f',
                        NPY_DOUBLELTR = 'd',
                        NPY_LONGDOUBLELTR = 'g',
                        NPY_CFLOATLTR = 'F',
                        NPY_CDOUBLELTR = 'D',
                        NPY_CLONGDOUBLELTR = 'G',
                        NPY_OBJECTLTR = 'O',
                        NPY_STRINGLTR = 'S',
                        NPY_STRINGLTR2 = 'a',
                        NPY_UNICODELTR = 'U',
                        NPY_VOIDLTR = 'V',
                        NPY_DATETIMELTR = 'M',
                        NPY_TIMEDELTALTR = 'm',
                        NPY_CHARLTR = 'c',

                        /* No Descriptor, just a define -- this let's
                         Python users specify an array of integers
                         large enough to hold a pointer on the platform*/
                        NPY_INTPLTR = 'p',
                        NPY_UINTPLTR = 'P',

                        NPY_GENBOOLLTR ='b',
                        NPY_SIGNEDLTR = 'i',
                        NPY_UNSIGNEDLTR = 'u',
                        NPY_FLOATINGLTR = 'f',
                        NPY_COMPLEXLTR = 'c'
};

typedef enum {
        NPY_QUICKSORT=0,
        NPY_HEAPSORT=1,
        NPY_MERGESORT=2
} NPY_SORTKIND;
#define NPY_NSORTS (NPY_MERGESORT + 1)


typedef enum {
        NPY_SEARCHLEFT=0,
        NPY_SEARCHRIGHT=1
} NPY_SEARCHSIDE;
#define NPY_NSEARCHSIDES (NPY_SEARCHRIGHT + 1)


typedef enum {
        NPY_NOSCALAR=-1,
        NPY_BOOL_SCALAR,
        NPY_INTPOS_SCALAR,
        NPY_INTNEG_SCALAR,
        NPY_FLOAT_SCALAR,
        NPY_COMPLEX_SCALAR,
        NPY_OBJECT_SCALAR
} NPY_SCALARKIND;
#define NPY_NSCALARKINDS (NPY_OBJECT_SCALAR + 1)

typedef enum {
        NPY_ANYORDER=-1,
        NPY_CORDER=0,
        NPY_FORTRANORDER=1
} NPY_ORDER;


typedef enum {
        NPY_CLIP=0,
        NPY_WRAP=1,
        NPY_RAISE=2
} NPY_CLIPMODE;

typedef enum {
        NPY_FR_Y,
        NPY_FR_M,
        NPY_FR_W,
        NPY_FR_B,
        NPY_FR_D,
        NPY_FR_h,
        NPY_FR_m,
        NPY_FR_s,
        NPY_FR_ms,
        NPY_FR_us,
        NPY_FR_ns,
        NPY_FR_ps,
        NPY_FR_fs,
        NPY_FR_as
} NPY_DATETIMEUNIT;

#define NPY_DATETIME_NUMUNITS (NPY_FR_as + 1)
#define NPY_DATETIME_DEFAULTUNIT NPY_FR_us

#define NPY_STR_Y "Y"
#define NPY_STR_M "M"
#define NPY_STR_W "W"
#define NPY_STR_B "B"
#define NPY_STR_D "D"
#define NPY_STR_h "h"
#define NPY_STR_m "m"
#define NPY_STR_s "s"
#define NPY_STR_ms "ms"
#define NPY_STR_us "us"
#define NPY_STR_ns "ns"
#define NPY_STR_ps "ps"
#define NPY_STR_fs "fs"
#define NPY_STR_as "as"


/* This is to typedef npy_intp to the appropriate pointer size for this
 * platform.  Py_intptr_t, Py_uintptr_t are defined in pyport.h. */
typedef Py_intptr_t npy_intp;
typedef Py_uintptr_t npy_uintp;
#define NPY_SIZEOF_INTP NPY_SIZEOF_PY_INTPTR_T
#define NPY_SIZEOF_UINTP NPY_SIZEOF_PY_INTPTR_T

#ifdef constchar
#undef constchar
#endif

#if (PY_VERSION_HEX < 0x02050000)
  #ifndef PY_SSIZE_T_MIN
    typedef int Py_ssize_t;
    #define PY_SSIZE_T_MAX INT_MAX
    #define PY_SSIZE_T_MIN INT_MIN
  #endif
#define NPY_SSIZE_T_PYFMT "i"
#undef PyIndex_Check
#define constchar const char
#define PyIndex_Check(op) 0
#else
#define NPY_SSIZE_T_PYFMT "n"
#define constchar char
#endif

#if NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_INT
        #define NPY_INTP NPY_INT
        #define NPY_UINTP NPY_UINT
        #define PyIntpArrType_Type PyIntArrType_Type
        #define PyUIntpArrType_Type PyUIntArrType_Type
        #define NPY_MAX_INTP NPY_MAX_INT
        #define NPY_MIN_INTP NPY_MIN_INT
        #define NPY_MAX_UINTP NPY_MAX_UINT
        #define NPY_INTP_FMT "d"
#elif NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONG
        #define NPY_INTP NPY_LONG
        #define NPY_UINTP NPY_ULONG
        #define PyIntpArrType_Type PyLongArrType_Type
        #define PyUIntpArrType_Type PyULongArrType_Type
        #define NPY_MAX_INTP NPY_MAX_LONG
        #define NPY_MIN_INTP MIN_LONG
        #define NPY_MAX_UINTP NPY_MAX_ULONG
        #define NPY_INTP_FMT "ld"
#elif defined(PY_LONG_LONG) && (NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONGLONG)
        #define NPY_INTP NPY_LONGLONG
        #define NPY_UINTP NPY_ULONGLONG
        #define PyIntpArrType_Type PyLongLongArrType_Type
        #define PyUIntpArrType_Type PyULongLongArrType_Type
        #define NPY_MAX_INTP NPY_MAX_LONGLONG
        #define NPY_MIN_INTP NPY_MIN_LONGLONG
        #define NPY_MAX_UINTP NPY_MAX_ULONGLONG
        #define NPY_INTP_FMT "Ld"
#endif

/* We can only use C99 formats for npy_int_p if it is the same as intp_t, hence
 * the condition on HAVE_UNITPTR_T */
#if (NPY_USE_C99_FORMATS) == 1 \
        && (defined HAVE_UINTPTR_T) \
        && (defined HAVE_INTTYPES_H)
        #include <inttypes.h>
        #undef NPY_INTP_FMT
        #define NPY_INTP_FMT PRIdPTR
#endif

#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);

#define NPY_STRINGIFY(x) #x
#define NPY_TOSTRING(x) NPY_STRINGIFY(x)

  /* Macros to define how array, and dimension/strides data is
     allocated.
  */

  /* Data buffer */
#define PyDataMem_NEW(size) ((char *)malloc(size))
#define PyDataMem_FREE(ptr)  free(ptr)
#define PyDataMem_RENEW(ptr,size) ((char *)realloc(ptr,size))

#define NPY_USE_PYMEM 1

#if NPY_USE_PYMEM == 1
#define PyArray_malloc PyMem_Malloc
#define PyArray_free PyMem_Free
#define PyArray_realloc PyMem_Realloc
#else
#define PyArray_malloc malloc
#define PyArray_free free
#define PyArray_realloc realloc
#endif

/* Dimensions and strides */
#define PyDimMem_NEW(size)                                         \
    ((npy_intp *)PyArray_malloc(size*sizeof(npy_intp)))

#define PyDimMem_FREE(ptr) PyArray_free(ptr)

#define PyDimMem_RENEW(ptr,size)                                   \
        ((npy_intp *)PyArray_realloc(ptr,size*sizeof(npy_intp)))

/* forward declaration */
struct _PyArray_Descr;

  /* These must deal with unaligned and swapped data if necessary */
typedef PyObject * (PyArray_GetItemFunc) (void *, void *);
typedef int (PyArray_SetItemFunc)(PyObject *, void *, void *);

typedef void (PyArray_CopySwapNFunc)(void *, npy_intp, void *, npy_intp,
                                     npy_intp, int, void *);

typedef void (PyArray_CopySwapFunc)(void *, void *, int, void *);
typedef npy_bool (PyArray_NonzeroFunc)(void *, void *);


  /* These assume aligned and notswapped data -- a buffer will be
      used before or contiguous data will be obtained
  */
typedef int (PyArray_CompareFunc)(const void *, const void *, void *);
typedef int (PyArray_ArgFunc)(void*, npy_intp, npy_intp*, void *);

typedef void (PyArray_DotFunc)(void *, npy_intp, void *, npy_intp, void *,
                               npy_intp, void *);

typedef void (PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *,
                                       void *);

/* XXX the ignore argument should be removed next time the API version
   is bumped. It used to be the separator. */
typedef int (PyArray_ScanFunc)(FILE *fp, void *dptr,
                               char *ignore, struct _PyArray_Descr *);
typedef int (PyArray_FromStrFunc)(char *s, void *dptr, char **endptr,
                                  struct _PyArray_Descr *);

typedef int (PyArray_FillFunc)(void *, npy_intp, void *);

typedef int (PyArray_SortFunc)(void *, npy_intp, void *);
typedef int (PyArray_ArgSortFunc)(void *, npy_intp *, npy_intp, void *);

typedef int (PyArray_FillWithScalarFunc)(void *, npy_intp, void *, void *);

typedef int (PyArray_ScalarKindFunc)(void *);

typedef void (PyArray_FastClipFunc)(void *in, npy_intp n_in, void *min,
                                    void *max, void *out);
typedef void (PyArray_FastPutmaskFunc)(void *in, void *mask, npy_intp n_in,
                                       void *values, npy_intp nv);
typedef int  (PyArray_FastTakeFunc)(void *dest, void *src, npy_intp *indarray,
                                       npy_intp nindarray, npy_intp n_outer,
                                       npy_intp m_middle, npy_intp nelem,
                                       NPY_CLIPMODE clipmode);

typedef struct {
        npy_intp *ptr;
        int len;
} PyArray_Dims;

typedef struct {
        /* Functions to cast to all other standard types*/
        /* Can have some NULL entries */
        PyArray_VectorUnaryFunc *cast[NPY_NTYPES];

        /* The next four functions *cannot* be NULL */

        /* Functions to get and set items with standard
           Python types -- not array scalars */
        PyArray_GetItemFunc *getitem;
        PyArray_SetItemFunc *setitem;

        /* Copy and/or swap data.  Memory areas may not overlap */
        /*  Use memmove first if they might */
        PyArray_CopySwapNFunc *copyswapn;
        PyArray_CopySwapFunc *copyswap;

        /* Function to compare items */
        /* Can be NULL
         */
        PyArray_CompareFunc *compare;

        /* Function to select largest
           Can be NULL
        */
        PyArray_ArgFunc *argmax;

        /* Function to compute dot product */
        /* Can be NULL */
        PyArray_DotFunc *dotfunc;

        /* Function to scan an ASCII file and
           place a single value plus possible separator
           Can be NULL
        */
        PyArray_ScanFunc *scanfunc;

        /* Function to read a single value from a string */
        /* and adjust the pointer; Can be NULL */
        PyArray_FromStrFunc *fromstr;

        /* Function to determine if data is zero or not */
        /* If NULL a default version is */
        /* used at Registration time. */
        PyArray_NonzeroFunc *nonzero;

        /* Used for arange. Can be NULL.*/
        PyArray_FillFunc *fill;

        /* Function to fill arrays with scalar values
         Can be NULL*/
        PyArray_FillWithScalarFunc *fillwithscalar;

        /* Sorting functions; Can be NULL*/
        PyArray_SortFunc *sort[NPY_NSORTS];
        PyArray_ArgSortFunc *argsort[NPY_NSORTS];

        /* Dictionary of additional casting functions
           PyArray_VectorUnaryFuncs
           which can be populated to support casting
           to other registered types. Can be NULL*/
        PyObject *castdict;

        /* Functions useful for generalizing
           the casting rules.  Can be NULL;
        */
        PyArray_ScalarKindFunc *scalarkind;
        int **cancastscalarkindto;
        int *cancastto;

        PyArray_FastClipFunc *fastclip;
        PyArray_FastPutmaskFunc *fastputmask;
        PyArray_FastTakeFunc *fasttake;
} PyArray_ArrFuncs;

/* The item must be reference counted when it is inserted or extracted. */
#define NPY_ITEM_REFCOUNT   0x01
/* Same as needing REFCOUNT */
#define NPY_ITEM_HASOBJECT  0x01
/* Convert to list for pickling */
#define NPY_LIST_PICKLE     0x02
/* The item is a POINTER  */
#define NPY_ITEM_IS_POINTER 0x04
/* memory needs to be initialized for this data-type */
#define NPY_NEEDS_INIT      0x08
/* operations need Python C-API so don't give-up thread. */
#define NPY_NEEDS_PYAPI     0x10
/* Use f.getitem when extracting elements of this data-type */
#define NPY_USE_GETITEM     0x20
/* Use f.setitem when setting creating 0-d array from this data-type.*/
#define NPY_USE_SETITEM     0x40
/* define NPY_IS_COMPLEX */

/* These are inherited for global data-type if any data-types in the field
   have them */
#define NPY_FROM_FIELDS    (NPY_NEEDS_INIT | NPY_LIST_PICKLE |             \
                            NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)

#define NPY_OBJECT_DTYPE_FLAGS (NPY_LIST_PICKLE | NPY_USE_GETITEM |       \
                                NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \
                                NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)

#define PyDataType_FLAGCHK(dtype, flag)                                   \
        (((dtype)->hasobject & (flag)) == (flag))

#define PyDataType_REFCHK(dtype)                                          \
        PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)

/* Change dtype hasobject to 32-bit in 1.1 and change its name */
typedef struct _PyArray_Descr {
        PyObject_HEAD
        PyTypeObject *typeobj;  /* the type object representing an
                                   instance of this type -- should not
                                   be two type_numbers with the same type
                                   object. */
        char kind;              /* kind for this type */
        char type;              /* unique-character representing this type */
        char byteorder;         /* '>' (big), '<' (little), '|'
                                   (not-applicable), or '=' (native). */
        char hasobject;         /* non-zero if it has object arrays
                                   in fields */
        int type_num;          /* number representing this type */
        int elsize;             /* element size for this type */
        int alignment;          /* alignment needed for this type */
        struct _arr_descr                                       \
        *subarray;              /* Non-NULL if this type is
                                   is an array (C-contiguous)
                                   of some other type
                                */
        PyObject *fields;       /* The fields dictionary for this type */
                                /* For statically defined descr this
                                   is always Py_None */

        PyObject *names;        /* An ordered tuple of field names or NULL
                                   if no fields are defined */

        PyArray_ArrFuncs *f;     /* a table of functions specific for each
                                    basic data descriptor */

        PyObject *metadata;     /* Metadata about this dtype */
} PyArray_Descr;

typedef struct _arr_descr {
        PyArray_Descr *base;
        PyObject *shape;       /* a tuple */
} PyArray_ArrayDescr;

/*
  The main array object structure. It is recommended to use the macros
  defined below (PyArray_DATA and friends) access fields here, instead
  of the members themselves.
 */

typedef struct PyArrayObject {
        PyObject_HEAD
        char *data;             /* pointer to raw data buffer */
        int nd;                 /* number of dimensions, also called ndim */
        npy_intp *dimensions;       /* size in each dimension */
        npy_intp *strides;          /* bytes to jump to get to the
                                   next element in each dimension */
        PyObject *base;         /* This object should be decref'd
                                   upon deletion of array */
                                /* For views it points to the original array */
                                /* For creation from buffer object it points
                                   to an object that shold be decref'd on
                                   deletion */
                                /* For UPDATEIFCOPY flag this is an array
                                   to-be-updated upon deletion of this one */
        PyArray_Descr *descr;   /* Pointer to type structure */
        int flags;              /* Flags describing array -- see below*/
        PyObject *weakreflist;  /* For weakreferences */
} PyArrayObject;

#define NPY_AO PyArrayObject

#define fortran fortran_        /* For some compilers */

/* Array Flags Object */
typedef struct PyArrayFlagsObject {
        PyObject_HEAD
        PyObject *arr;
        int flags;
} PyArrayFlagsObject;

/* Mirrors buffer object to ptr */

typedef struct {
        PyObject_HEAD
        PyObject *base;
        void *ptr;
        npy_intp len;
        int flags;
} PyArray_Chunk;

#define PyDataType_GetDatetimeMetaData(descr) ((descr->metadata == NULL) ? NULL : ((PyArray_DatetimeMetaData *)(PyCObject_AsVoidPtr(PyDict_GetItemString(descr->metadata, NPY_METADATA_DTSTR)))))

typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);

/* Means c-style contiguous (last index varies the fastest). The
   data elements right after each other. */
#define NPY_CONTIGUOUS    0x0001
/* set if array is a contiguous Fortran array: the first index
   varies the fastest in memory (strides array is reverse of
   C-contiguous array)*/
#define NPY_FORTRAN       0x0002

#define NPY_C_CONTIGUOUS NPY_CONTIGUOUS
#define NPY_F_CONTIGUOUS NPY_FORTRAN

/*
  Note: all 0-d arrays are CONTIGUOUS and FORTRAN contiguous. If a
   1-d array is CONTIGUOUS it is also FORTRAN contiguous
*/

/* If set, the array owns the data: it will be free'd when the array
   is deleted. */
#define NPY_OWNDATA       0x0004

/* An array never has the next four set; they're only used as parameter
   flags to the the various FromAny functions */

/* Cause a cast to occur regardless of whether or not it is safe. */
#define NPY_FORCECAST     0x0010

/* Always copy the array. Returned arrays are always CONTIGUOUS, ALIGNED,
   and WRITEABLE. */
#define NPY_ENSURECOPY    0x0020

/* Make sure the returned array is a base-class ndarray */
#define NPY_ENSUREARRAY   0x0040

/* Make sure that the strides are in units of the element size
   Needed for some operations with record-arrays.
*/
#define NPY_ELEMENTSTRIDES 0x0080

/* Array data is aligned on the appropiate memory address for the
   type stored according to how the compiler would align things
   (e.g., an array of integers (4 bytes each) starts on
   a memory address that's a multiple of 4) */
#define NPY_ALIGNED       0x0100
/* Array data has the native endianness */
#define NPY_NOTSWAPPED    0x0200
/* Array data is writeable */
#define NPY_WRITEABLE     0x0400
/* If this flag is set, then base contains a pointer to an array of
   the same size that should be updated with the current contents of
   this array when this array is deallocated
*/
#define NPY_UPDATEIFCOPY  0x1000

/* This flag is for the array interface */
#define NPY_ARR_HAS_DESCR  0x0800


#define NPY_BEHAVED (NPY_ALIGNED | NPY_WRITEABLE)
#define NPY_BEHAVED_NS (NPY_ALIGNED | NPY_WRITEABLE | NPY_NOTSWAPPED)
#define NPY_CARRAY (NPY_CONTIGUOUS | NPY_BEHAVED)
#define NPY_CARRAY_RO (NPY_CONTIGUOUS | NPY_ALIGNED)
#define NPY_FARRAY (NPY_FORTRAN | NPY_BEHAVED)
#define NPY_FARRAY_RO (NPY_FORTRAN | NPY_ALIGNED)
#define NPY_DEFAULT NPY_CARRAY
#define NPY_IN_ARRAY NPY_CARRAY_RO
#define NPY_OUT_ARRAY NPY_CARRAY
#define NPY_INOUT_ARRAY (NPY_CARRAY | NPY_UPDATEIFCOPY)
#define NPY_IN_FARRAY NPY_FARRAY_RO
#define NPY_OUT_FARRAY NPY_FARRAY
#define NPY_INOUT_FARRAY (NPY_FARRAY | NPY_UPDATEIFCOPY)

#define NPY_UPDATE_ALL (NPY_CONTIGUOUS | NPY_FORTRAN | NPY_ALIGNED)


/* Size of internal buffers used for alignment */
/* Make BUFSIZE a multiple of sizeof(cdouble) -- ususally 16 */
/* So that ufunc buffers are aligned */
#define NPY_MIN_BUFSIZE ((int)sizeof(cdouble))
#define NPY_MAX_BUFSIZE (((int)sizeof(cdouble))*1000000)
#define NPY_BUFSIZE 10000
/* #define NPY_BUFSIZE 80*/

#define PyArray_MAX(a,b) (((a)>(b))?(a):(b))
#define PyArray_MIN(a,b) (((a)<(b))?(a):(b))
#define PyArray_CLT(p,q) ((((p).real==(q).real) ? ((p).imag < (q).imag) : \
                               ((p).real < (q).real)))
#define PyArray_CGT(p,q) ((((p).real==(q).real) ? ((p).imag > (q).imag) : \
                               ((p).real > (q).real)))
#define PyArray_CLE(p,q) ((((p).real==(q).real) ? ((p).imag <= (q).imag) : \
                               ((p).real <= (q).real)))
#define PyArray_CGE(p,q) ((((p).real==(q).real) ? ((p).imag >= (q).imag) : \
                               ((p).real >= (q).real)))
#define PyArray_CEQ(p,q) (((p).real==(q).real) && ((p).imag == (q).imag))
#define PyArray_CNE(p,q) (((p).real!=(q).real) || ((p).imag != (q).imag))

/*
 * C API:  consists of Macros and functions.  The MACROS are defined here.
 */


#define PyArray_CHKFLAGS(m, FLAGS)                              \
        ((((PyArrayObject *)(m))->flags & (FLAGS)) == (FLAGS))

#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_CONTIGUOUS)
#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_WRITEABLE)
#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ALIGNED)


#if NPY_ALLOW_THREADS
#define NPY_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#define NPY_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#define NPY_BEGIN_THREADS_DEF PyThreadState *_save=NULL;
#define NPY_BEGIN_THREADS _save = PyEval_SaveThread();
#define NPY_END_THREADS   do {if (_save) PyEval_RestoreThread(_save);} while (0);

#define NPY_BEGIN_THREADS_DESCR(dtype)                          \
        do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI)))      \
                NPY_BEGIN_THREADS;} while (0);

#define NPY_END_THREADS_DESCR(dtype)                            \
        do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI)))      \
                NPY_END_THREADS; } while (0);

#define NPY_ALLOW_C_API_DEF  PyGILState_STATE __save__;
#define NPY_ALLOW_C_API      __save__ = PyGILState_Ensure();
#define NPY_DISABLE_C_API    PyGILState_Release(__save__);
#else
#define NPY_BEGIN_ALLOW_THREADS
#define NPY_END_ALLOW_THREADS
#define NPY_BEGIN_THREADS_DEF
#define NPY_BEGIN_THREADS
#define NPY_END_THREADS
#define NPY_BEGIN_THREADS_DESCR(dtype)
#define NPY_END_THREADS_DESCR(dtype)
#define NPY_ALLOW_C_API_DEF
#define NPY_ALLOW_C_API
#define NPY_DISABLE_C_API
#endif

/*****************************
 * Basic iterator object
 *****************************/

/* FWD declaration */
typedef struct PyArrayIterObject_tag PyArrayIterObject;

/* type of the function which translates a set of coordinates to a pointer to
 * the data */
typedef char* (*npy_iter_get_dataptr_t)(PyArrayIterObject* iter, npy_intp*);

struct PyArrayIterObject_tag {
        PyObject_HEAD
        int               nd_m1;            /* number of dimensions - 1 */
        npy_intp          index, size;
        npy_intp          coordinates[NPY_MAXDIMS];/* N-dimensional loop */
        npy_intp          dims_m1[NPY_MAXDIMS];    /* ao->dimensions - 1 */
        npy_intp          strides[NPY_MAXDIMS];    /* ao->strides or fake */
        npy_intp          backstrides[NPY_MAXDIMS];/* how far to jump back */
        npy_intp          factors[NPY_MAXDIMS];     /* shape factors */
        PyArrayObject     *ao;
        char              *dataptr;        /* pointer to current item*/
        npy_bool          contiguous;

        npy_intp          bounds[NPY_MAXDIMS][2];
        npy_intp          limits[NPY_MAXDIMS][2];
        npy_intp          limits_sizes[NPY_MAXDIMS];
        npy_iter_get_dataptr_t translate;
} ;


/* Iterator API */
#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type)

#define _PyAIT(it) ((PyArrayIterObject *)(it))
#define PyArray_ITER_RESET(it) {                                        \
        _PyAIT(it)->index = 0;                                          \
        _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                     \
        memset(_PyAIT(it)->coordinates, 0,                              \
               (_PyAIT(it)->nd_m1+1)*sizeof(npy_intp));                 \
}

#define _PyArray_ITER_NEXT1(it) {                                       \
        (it)->dataptr += _PyAIT(it)->strides[0];                        \
        (it)->coordinates[0]++;                                         \
}

#define _PyArray_ITER_NEXT2(it) {                                       \
        if ((it)->coordinates[1] < (it)->dims_m1[1]) {                  \
                (it)->coordinates[1]++;                                 \
                (it)->dataptr += (it)->strides[1];                      \
        }                                                               \
        else {                                                          \
                (it)->coordinates[1] = 0;                               \
                (it)->coordinates[0]++;                                 \
                (it)->dataptr += (it)->strides[0] -                     \
                        (it)->backstrides[1];                           \
        }                                                               \
}

#define _PyArray_ITER_NEXT3(it) {                                       \
        if ((it)->coordinates[2] < (it)->dims_m1[2]) {                  \
                (it)->coordinates[2]++;                                 \
                (it)->dataptr += (it)->strides[2];                      \
        }                                                               \
        else {                                                          \
                (it)->coordinates[2] = 0;                               \
                (it)->dataptr -= (it)->backstrides[2];                  \
                if ((it)->coordinates[1] < (it)->dims_m1[1]) {          \
                        (it)->coordinates[1]++;                         \
                        (it)->dataptr += (it)->strides[1];              \
                }                                                       \
                else {                                                  \
                        (it)->coordinates[1] = 0;                       \
                        (it)->coordinates[0]++;                         \
                        (it)->dataptr += (it)->strides[0] -             \
                                (it)->backstrides[1];                   \
                }                                                       \
        }                                                               \
}

#define PyArray_ITER_NEXT(it) {                                            \
        _PyAIT(it)->index++;                                               \
        if (_PyAIT(it)->nd_m1 == 0) {                                      \
                _PyArray_ITER_NEXT1(_PyAIT(it));                           \
        }                                                                  \
        else if (_PyAIT(it)->contiguous)                                   \
                _PyAIT(it)->dataptr += _PyAIT(it)->ao->descr->elsize;      \
        else if (_PyAIT(it)->nd_m1 == 1) {                                 \
                _PyArray_ITER_NEXT2(_PyAIT(it));                           \
        }                                                                  \
        else {                                                             \
                int __npy_i;                                               \
                for (__npy_i=_PyAIT(it)->nd_m1; __npy_i >= 0; __npy_i--) { \
                        if (_PyAIT(it)->coordinates[__npy_i] <             \
                            _PyAIT(it)->dims_m1[__npy_i]) {                \
                                _PyAIT(it)->coordinates[__npy_i]++;        \
                                _PyAIT(it)->dataptr +=                     \
                                        _PyAIT(it)->strides[__npy_i];      \
                                break;                                     \
                        }                                                  \
                        else {                                             \
                                _PyAIT(it)->coordinates[__npy_i] = 0;      \
                                _PyAIT(it)->dataptr -=                     \
                                        _PyAIT(it)->backstrides[__npy_i];  \
                        }                                                  \
                }                                                          \
        }                                                                  \
}

#define PyArray_ITER_GOTO(it, destination) {                            \
        int __npy_i;                                                    \
        _PyAIT(it)->index = 0;                                          \
        _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                     \
        for (__npy_i = _PyAIT(it)->nd_m1; __npy_i>=0; __npy_i--) {      \
                if (destination[__npy_i] < 0) {                         \
                        destination[__npy_i] +=                         \
                                _PyAIT(it)->dims_m1[__npy_i]+1;         \
                }                                                       \
                _PyAIT(it)->dataptr += destination[__npy_i] *           \
                        _PyAIT(it)->strides[__npy_i];                   \
                _PyAIT(it)->coordinates[__npy_i] =                      \
                        destination[__npy_i];                           \
                _PyAIT(it)->index += destination[__npy_i] *             \
                        ( __npy_i==_PyAIT(it)->nd_m1 ? 1 :              \
                          _PyAIT(it)->dims_m1[__npy_i+1]+1) ;           \
        }                                                               \
}

#define PyArray_ITER_GOTO1D(it, ind) {                                     \
        int __npy_i;                                                       \
        npy_intp __npy_ind = (npy_intp) (ind);                             \
        if (__npy_ind < 0) __npy_ind += _PyAIT(it)->size;                  \
        _PyAIT(it)->index = __npy_ind;                                     \
        if (_PyAIT(it)->nd_m1 == 0) {                                      \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data +               \
                        __npy_ind * _PyAIT(it)->strides[0];                \
        }                                                                  \
        else if (_PyAIT(it)->contiguous)                                   \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data +               \
                        __npy_ind * _PyAIT(it)->ao->descr->elsize;         \
        else {                                                             \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                \
                for (__npy_i = 0; __npy_i<=_PyAIT(it)->nd_m1;              \
                     __npy_i++) {                                          \
                        _PyAIT(it)->dataptr +=                             \
                                (__npy_ind / _PyAIT(it)->factors[__npy_i]) \
                                * _PyAIT(it)->strides[__npy_i];            \
                        __npy_ind %= _PyAIT(it)->factors[__npy_i];         \
                }                                                          \
        }                                                                  \
}

#define PyArray_ITER_DATA(it) ((void *)(_PyAIT(it)->dataptr))

#define PyArray_ITER_NOTDONE(it) (_PyAIT(it)->index < _PyAIT(it)->size)


/*
   Any object passed to PyArray_Broadcast must be binary compatible with
   this structure.
*/

typedef struct {
        PyObject_HEAD
        int                  numiter;                 /* number of iters */
        npy_intp             size;                    /* broadcasted size */
        npy_intp             index;                   /* current index */
        int                  nd;                      /* number of dims */
        npy_intp             dimensions[NPY_MAXDIMS]; /* dimensions */
        PyArrayIterObject    *iters[NPY_MAXARGS];     /* iterators */
} PyArrayMultiIterObject;

#define _PyMIT(m) ((PyArrayMultiIterObject *)(m))
#define PyArray_MultiIter_RESET(multi) {                                      \
        int __npy_mi;                                                         \
        _PyMIT(multi)->index = 0;                                             \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter;  __npy_mi++) {    \
                PyArray_ITER_RESET(_PyMIT(multi)->iters[__npy_mi]);           \
        }                                                                     \
}

#define PyArray_MultiIter_NEXT(multi) {                                       \
        int __npy_mi;                                                         \
        _PyMIT(multi)->index++;                                               \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter;   __npy_mi++) {   \
                PyArray_ITER_NEXT(_PyMIT(multi)->iters[__npy_mi]);            \
        }                                                                     \
}

#define PyArray_MultiIter_GOTO(multi, dest) {                               \
        int __npy_mi;                                                       \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) {   \
                PyArray_ITER_GOTO(_PyMIT(multi)->iters[__npy_mi], dest);    \
        }                                                                   \
        _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index;              \
}

#define PyArray_MultiIter_GOTO1D(multi, ind) {                             \
        int __npy_mi;                                                      \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) {  \
                PyArray_ITER_GOTO1D(_PyMIT(multi)->iters[__npy_mi], ind);  \
        }                                                                  \
        _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index;             \
}

#define PyArray_MultiIter_DATA(multi, i)                \
        ((void *)(_PyMIT(multi)->iters[i]->dataptr))

#define PyArray_MultiIter_NEXTi(multi, i)               \
        PyArray_ITER_NEXT(_PyMIT(multi)->iters[i])

#define PyArray_MultiIter_NOTDONE(multi)                \
        (_PyMIT(multi)->index < _PyMIT(multi)->size)

/* Store the information needed for fancy-indexing over an array */

typedef struct {
        PyObject_HEAD
        /* Multi-iterator portion --- needs to be present in this order to
           work with PyArray_Broadcast */

        int                   numiter;                 /* number of index-array
                                                          iterators */
        npy_intp              size;                    /* size of broadcasted
                                                          result */
        npy_intp              index;                   /* current index */
        int                   nd;                      /* number of dims */
        npy_intp              dimensions[NPY_MAXDIMS]; /* dimensions */
        PyArrayIterObject     *iters[NPY_MAXDIMS];     /* index object
                                                          iterators */
        PyArrayIterObject     *ait;                    /* flat Iterator for
                                                          underlying array */

        /* flat iterator for subspace (when numiter < nd) */
        PyArrayIterObject     *subspace;

        /* if subspace iteration, then this is the array of
           axes in the underlying array represented by the
           index objects */
        int                   iteraxes[NPY_MAXDIMS];
        /* if subspace iteration, the these are the coordinates
           to the start of the subspace.
        */
        npy_intp              bscoord[NPY_MAXDIMS];

        PyObject              *indexobj;               /* creating obj */
        int                   consec;
        char                  *dataptr;

} PyArrayMapIterObject;

enum {
    NPY_NEIGHBORHOOD_ITER_ZERO_PADDING,
    NPY_NEIGHBORHOOD_ITER_ONE_PADDING,
    NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING,
    NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING,
    NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING
};

typedef struct {
    PyObject_HEAD

    /*
     * PyArrayIterObject part: keep this in this exact order
     */
    int               nd_m1;            /* number of dimensions - 1 */
    npy_intp          index, size;
    npy_intp          coordinates[NPY_MAXDIMS];/* N-dimensional loop */
    npy_intp          dims_m1[NPY_MAXDIMS];    /* ao->dimensions - 1 */
    npy_intp          strides[NPY_MAXDIMS];    /* ao->strides or fake */
    npy_intp          backstrides[NPY_MAXDIMS];/* how far to jump back */
    npy_intp          factors[NPY_MAXDIMS];     /* shape factors */
    PyArrayObject     *ao;
    char              *dataptr;        /* pointer to current item*/
    npy_bool          contiguous;

    npy_intp          bounds[NPY_MAXDIMS][2];
    npy_intp          limits[NPY_MAXDIMS][2];
    npy_intp          limits_sizes[NPY_MAXDIMS];
    npy_iter_get_dataptr_t translate;

    /*
     * New members
     */
    npy_intp nd;

    /* Dimensions is the dimension of the array */
    npy_intp dimensions[NPY_MAXDIMS];

    /* Neighborhood points coordinates are computed relatively to the point pointed
     * by _internal_iter */
    PyArrayIterObject* _internal_iter;
    /* To keep a reference to the representation of the constant value for
     * constant padding */
    char* constant;

    int mode;
} PyArrayNeighborhoodIterObject;

/*
 * Neighborhood iterator API
 */

/* General: those work for any mode */
static NPY_INLINE int
PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject* iter);
static NPY_INLINE int
PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject* iter);
#if 0
static NPY_INLINE int
PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter);
#endif

/* Include inline implementations - functions defined there are not considered
 * public API */
#define _NPY_INCLUDE_NEIGHBORHOOD_IMP
#include "_neighborhood_iterator_imp.h"
#undef _NPY_INCLUDE_NEIGHBORHOOD_IMP

/* The default array type
 */
#define NPY_DEFAULT_TYPE NPY_DOUBLE
#define PyArray_DEFAULT NPY_DEFAULT_TYPE
/* All sorts of useful ways to look into a PyArrayObject.
   These are the recommended over casting to PyArrayObject and accessing
   the members directly.
 */

#define PyArray_NDIM(obj) (((PyArrayObject *)(obj))->nd)
#define PyArray_ISONESEGMENT(m) (PyArray_NDIM(m) == 0 ||                      \
                                 PyArray_CHKFLAGS(m, NPY_CONTIGUOUS) ||       \
                                 PyArray_CHKFLAGS(m, NPY_FORTRAN))

#define PyArray_ISFORTRAN(m) (PyArray_CHKFLAGS(m, NPY_FORTRAN) &&             \
                             (PyArray_NDIM(m) > 1))

#define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_FORTRAN) ?            \
                              NPY_FORTRAN : 0))

#define FORTRAN_IF PyArray_FORTRAN_IF
#define PyArray_DATA(obj) ((void *)(((PyArrayObject *)(obj))->data))
#define PyArray_BYTES(obj) (((PyArrayObject *)(obj))->data)
#define PyArray_DIMS(obj) (((PyArrayObject *)(obj))->dimensions)
#define PyArray_STRIDES(obj) (((PyArrayObject *)(obj))->strides)
#define PyArray_DIM(obj,n) (PyArray_DIMS(obj)[n])
#define PyArray_STRIDE(obj,n) (PyArray_STRIDES(obj)[n])
#define PyArray_BASE(obj) (((PyArrayObject *)(obj))->base)
#define PyArray_DESCR(obj) (((PyArrayObject *)(obj))->descr)
#define PyArray_FLAGS(obj) (((PyArrayObject *)(obj))->flags)
#define PyArray_ITEMSIZE(obj) (((PyArrayObject *)(obj))->descr->elsize)
#define PyArray_TYPE(obj) (((PyArrayObject *)(obj))->descr->type_num)

#define PyArray_GETITEM(obj,itemptr)                                          \
        ((PyArrayObject *)(obj))->descr->f->getitem((char *)(itemptr),        \
                                                 (PyArrayObject *)(obj))

#define PyArray_SETITEM(obj,itemptr,v)                                        \
        ((PyArrayObject *)(obj))->descr->f->setitem((PyObject *)(v),          \
                                                    (char *)(itemptr),        \
                                                    (PyArrayObject *)(obj))


#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL)

#define PyTypeNum_ISUNSIGNED(type) (((type) == NPY_UBYTE) ||   \
                                 ((type) == NPY_USHORT) ||     \
                                 ((type) == NPY_UINT) ||       \
                                 ((type) == NPY_ULONG) ||      \
                                 ((type) == NPY_ULONGLONG))

#define PyTypeNum_ISSIGNED(type) (((type) == NPY_BYTE) ||      \
                               ((type) == NPY_SHORT) ||        \
                               ((type) == NPY_INT) ||          \
                               ((type) == NPY_LONG) ||         \
                               ((type) == NPY_LONGLONG))

#define PyTypeNum_ISINTEGER(type) (((type) >= NPY_BYTE) &&     \
                                ((type) <= NPY_ULONGLONG))

#define PyTypeNum_ISFLOAT(type) (((type) >= NPY_FLOAT) &&      \
                              ((type) <= NPY_LONGDOUBLE))

#define PyTypeNum_ISNUMBER(type) ((type) <= NPY_CLONGDOUBLE)

#define PyTypeNum_ISSTRING(type) (((type) == NPY_STRING) ||    \
                                  ((type) == NPY_UNICODE))

#define PyTypeNum_ISCOMPLEX(type) (((type) >= NPY_CFLOAT) &&   \
                                ((type) <= NPY_CLONGDOUBLE))

#define PyTypeNum_ISPYTHON(type) (((type) == NPY_LONG) ||      \
                                  ((type) == NPY_DOUBLE) ||    \
                                  ((type) == NPY_CDOUBLE) ||   \
                                  ((type) == NPY_BOOL) ||      \
                                  ((type) == NPY_OBJECT ))

#define PyTypeNum_ISFLEXIBLE(type) (((type) >=NPY_STRING) &&  \
                                    ((type) <=NPY_VOID))

#define PyTypeNum_ISDATETIME(type) (((type) >=NPY_DATETIME) &&  \
                                    ((type) <=NPY_TIMEDELTA))

#define PyTypeNum_ISUSERDEF(type) (((type) >= NPY_USERDEF) && \
                                   ((type) < NPY_USERDEF+     \
                                    NPY_NUMUSERTYPES))

#define PyTypeNum_ISEXTENDED(type) (PyTypeNum_ISFLEXIBLE(type) ||  \
                                    PyTypeNum_ISUSERDEF(type))

#define PyTypeNum_ISOBJECT(type) ((type) == NPY_OBJECT)


#define PyDataType_ISBOOL(obj) PyTypeNum_ISBOOL(_PyADt(obj))
#define PyDataType_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISSIGNED(obj) PyTypeNum_ISSIGNED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISINTEGER(obj) PyTypeNum_ISINTEGER(((PyArray_Descr*)(obj))->type_num )
#define PyDataType_ISFLOAT(obj) PyTypeNum_ISFLOAT(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISNUMBER(obj) PyTypeNum_ISNUMBER(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISSTRING(obj) PyTypeNum_ISSTRING(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISPYTHON(obj) PyTypeNum_ISPYTHON(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISDATETIME(obj) PyTypeNum_ISDATETIME(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISOBJECT(obj) PyTypeNum_ISOBJECT(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_HASFIELDS(obj) (((PyArray_Descr *)(obj))->names != NULL)

#define PyArray_ISBOOL(obj) PyTypeNum_ISBOOL(PyArray_TYPE(obj))
#define PyArray_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(PyArray_TYPE(obj))
#define PyArray_ISSIGNED(obj) PyTypeNum_ISSIGNED(PyArray_TYPE(obj))
#define PyArray_ISINTEGER(obj) PyTypeNum_ISINTEGER(PyArray_TYPE(obj))
#define PyArray_ISFLOAT(obj) PyTypeNum_ISFLOAT(PyArray_TYPE(obj))
#define PyArray_ISNUMBER(obj) PyTypeNum_ISNUMBER(PyArray_TYPE(obj))
#define PyArray_ISSTRING(obj) PyTypeNum_ISSTRING(PyArray_TYPE(obj))
#define PyArray_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(PyArray_TYPE(obj))
#define PyArray_ISPYTHON(obj) PyTypeNum_ISPYTHON(PyArray_TYPE(obj))
#define PyArray_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj))
#define PyArray_ISDATETIME(obj) PyTypeNum_ISDATETIME(PyArray_TYPE(obj))
#define PyArray_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(PyArray_TYPE(obj))
#define PyArray_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(PyArray_TYPE(obj))
#define PyArray_ISOBJECT(obj) PyTypeNum_ISOBJECT(PyArray_TYPE(obj))
#define PyArray_HASFIELDS(obj) PyDataType_HASFIELDS(PyArray_DESCR(obj))

    /* FIXME: This should check for a flag on the data-type
       that states whether or not it is variable length.
       Because the ISFLEXIBLE check is hard-coded to the
       built-in data-types.
     */
#define PyArray_ISVARIABLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj))

#define PyArray_SAFEALIGNEDCOPY(obj) (PyArray_ISALIGNED(obj) && !PyArray_ISVARIABLE(obj))


#define NPY_LITTLE '<'
#define NPY_BIG '>'
#define NPY_NATIVE '='
#define NPY_SWAP 's'
#define NPY_IGNORE '|'

#if NPY_BYTE_ORDER == NPY_BIG_ENDIAN
#define NPY_NATBYTE NPY_BIG
#define NPY_OPPBYTE NPY_LITTLE
#else
#define NPY_NATBYTE NPY_LITTLE
#define NPY_OPPBYTE NPY_BIG
#endif

#define PyArray_ISNBO(arg) ((arg) != NPY_OPPBYTE)
#define PyArray_IsNativeByteOrder PyArray_ISNBO
#define PyArray_ISNOTSWAPPED(m) PyArray_ISNBO(PyArray_DESCR(m)->byteorder)
#define PyArray_ISBYTESWAPPED(m) (!PyArray_ISNOTSWAPPED(m))

#define PyArray_FLAGSWAP(m, flags) (PyArray_CHKFLAGS(m, flags) &&       \
                                    PyArray_ISNOTSWAPPED(m))

#define PyArray_ISCARRAY(m) PyArray_FLAGSWAP(m, NPY_CARRAY)
#define PyArray_ISCARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_CARRAY_RO)
#define PyArray_ISFARRAY(m) PyArray_FLAGSWAP(m, NPY_FARRAY)
#define PyArray_ISFARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_FARRAY_RO)
#define PyArray_ISBEHAVED(m) PyArray_FLAGSWAP(m, NPY_BEHAVED)
#define PyArray_ISBEHAVED_RO(m) PyArray_FLAGSWAP(m, NPY_ALIGNED)


#define PyDataType_ISNOTSWAPPED(d) PyArray_ISNBO(((PyArray_Descr *)(d))->byteorder)
#define PyDataType_ISBYTESWAPPED(d) (!PyDataType_ISNOTSWAPPED(d))


/* This is the form of the struct that's returned pointed by the
   PyCObject attribute of an array __array_struct__. See
   http://numpy.scipy.org/array_interface.shtml for the full
   documentation. */
typedef struct {
    int two;              /* contains the integer 2 as a sanity check */
    int nd;               /* number of dimensions */
    char typekind;        /* kind in array --- character code of typestr */
    int itemsize;         /* size of each element */
    int flags;            /* how should be data interpreted. Valid
                             flags are CONTIGUOUS (1), FORTRAN (2),
                             ALIGNED (0x100), NOTSWAPPED (0x200), and
                             WRITEABLE (0x400).
                             ARR_HAS_DESCR (0x800) states that arrdescr
                                field is present in structure */
    npy_intp *shape;          /* A length-nd array of shape information */
    npy_intp *strides;        /* A length-nd array of stride information */
    void *data;           /* A pointer to the first element of the array */
    PyObject *descr;      /* A list of fields or NULL (ignored if flags
                                does not have ARR_HAS_DESCR flag set) */
} PyArrayInterface;


/* Includes the "function" C-API -- these are all stored in a
   list of pointers --- one for each file
   The two lists are concatenated into one in multiarray.

   They are available as import_array()
*/

#include "__multiarray_api.h"


/* C-API that requries previous API to be defined */

#define PyArray_DescrCheck(op) ((op)->ob_type == &PyArrayDescr_Type)

#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type)
#define PyArray_CheckExact(op) ((op)->ob_type == &PyArray_Type)

#define PyArray_HasArrayInterfaceType(op, type, context, out)                 \
        ((((out)=PyArray_FromStructInterface(op)) != Py_NotImplemented) ||    \
         (((out)=PyArray_FromInterface(op)) != Py_NotImplemented) ||          \
         (((out)=PyArray_FromArrayAttr(op, type, context)) !=                 \
          Py_NotImplemented))

#define PyArray_HasArrayInterface(op, out)                                    \
        PyArray_HasArrayInterfaceType(op, NULL, NULL, out)

#define PyArray_IsZeroDim(op) (PyArray_Check(op) && (PyArray_NDIM(op) == 0))

#define PyArray_IsScalar(obj, cls)                                            \
        (PyObject_TypeCheck(obj, &Py##cls##ArrType_Type))

#define PyArray_CheckScalar(m) (PyArray_IsScalar(m, Generic) ||               \
                                PyArray_IsZeroDim(m))

#define PyArray_IsPythonNumber(obj)                                           \
        (PyInt_Check(obj) || PyFloat_Check(obj) || PyComplex_Check(obj) ||    \
         PyLong_Check(obj) || PyBool_Check(obj))

#define PyArray_IsPythonScalar(obj)                                           \
        (PyArray_IsPythonNumber(obj) || PyString_Check(obj) ||                \
         PyUnicode_Check(obj))

#define PyArray_IsAnyScalar(obj)                                              \
        (PyArray_IsScalar(obj, Generic) || PyArray_IsPythonScalar(obj))

#define PyArray_CheckAnyScalar(obj) (PyArray_IsPythonScalar(obj) ||           \
                                     PyArray_CheckScalar(obj))

#define PyArray_IsIntegerScalar(obj) (PyInt_Check(obj)                        \
              || PyLong_Check(obj)                                            \
              || PyArray_IsScalar((obj), Integer))


#define PyArray_GETCONTIGUOUS(m) (PyArray_ISCONTIGUOUS(m) ?                   \
                                  Py_INCREF(m), (m) :                         \
                                  (PyArrayObject *)(PyArray_Copy(m)))

#define PyArray_SAMESHAPE(a1,a2) ((PyArray_NDIM(a1) == PyArray_NDIM(a2)) &&   \
                                  PyArray_CompareLists(PyArray_DIMS(a1),      \
                                                       PyArray_DIMS(a2),      \
                                                       PyArray_NDIM(a1)))

#define PyArray_SIZE(m) PyArray_MultiplyList(PyArray_DIMS(m), PyArray_NDIM(m))
#define PyArray_NBYTES(m) (PyArray_ITEMSIZE(m) * PyArray_SIZE(m))
#define PyArray_FROM_O(m) PyArray_FromAny(m, NULL, 0, 0, 0, NULL)

#define PyArray_FROM_OF(m,flags) PyArray_CheckFromAny(m, NULL, 0, 0, flags,   \
                                                      NULL)

#define PyArray_FROM_OT(m,type) PyArray_FromAny(m,                            \
                                PyArray_DescrFromType(type), 0, 0, 0, NULL);

#define PyArray_FROM_OTF(m, type, flags)                                      \
        PyArray_FromAny(m, PyArray_DescrFromType(type), 0, 0,                 \
                        (((flags) & NPY_ENSURECOPY) ?                         \
                         ((flags) | NPY_DEFAULT) : (flags)), NULL)

#define PyArray_FROMANY(m, type, min, max, flags)                             \
        PyArray_FromAny(m, PyArray_DescrFromType(type), min, max,             \
                        (((flags) & NPY_ENSURECOPY) ?                         \
                         (flags) | NPY_DEFAULT : (flags)), NULL)

#define PyArray_ZEROS(m, dims, type, fortran)                                 \
        PyArray_Zeros(m, dims, PyArray_DescrFromType(type), fortran)

#define PyArray_EMPTY(m, dims, type, fortran)                                 \
        PyArray_Empty(m, dims, PyArray_DescrFromType(type), fortran)

#define PyArray_FILLWBYTE(obj, val) memset(PyArray_DATA(obj), val,            \
                                           PyArray_NBYTES(obj))

#define PyArray_REFCOUNT(obj) (((PyObject *)(obj))->ob_refcnt)
#define NPY_REFCOUNT PyArray_REFCOUNT
#define NPY_MAX_ELSIZE (2 * NPY_SIZEOF_LONGDOUBLE)

#define PyArray_ContiguousFromAny(op, type, min_depth, max_depth)             \
        PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth,           \
                              max_depth, NPY_DEFAULT, NULL)

#define PyArray_EquivArrTypes(a1, a2)                                         \
        PyArray_EquivTypes(PyArray_DESCR(a1), PyArray_DESCR(a2))

#define PyArray_EquivByteorders(b1, b2)                                       \
        (((b1) == (b2)) || (PyArray_ISNBO(b1) == PyArray_ISNBO(b2)))

#define PyArray_SimpleNew(nd, dims, typenum)                                  \
        PyArray_New(&PyArray_Type, nd, dims, typenum, NULL, NULL, 0, 0, NULL)

#define PyArray_SimpleNewFromData(nd, dims, typenum, data)                    \
        PyArray_New(&PyArray_Type, nd, dims, typenum, NULL,                   \
                    data, 0, NPY_CARRAY, NULL)

#define PyArray_SimpleNewFromDescr(nd, dims, descr)                           \
        PyArray_NewFromDescr(&PyArray_Type, descr, nd, dims,                  \
                             NULL, NULL, 0, NULL)

#define PyArray_ToScalar(data, arr)                                           \
        PyArray_Scalar(data, PyArray_DESCR(arr), (PyObject *)arr)


/* These might be faster without the dereferencing of obj
   going on inside -- of course an optimizing compiler should
   inline the constants inside a for loop making it a moot point
*/

#define PyArray_GETPTR1(obj, i) ((void *)(PyArray_BYTES(obj) +                \
                                         (i)*PyArray_STRIDES(obj)[0]))

#define PyArray_GETPTR2(obj, i, j) ((void *)(PyArray_BYTES(obj) +             \
                                            (i)*PyArray_STRIDES(obj)[0] +     \
                                            (j)*PyArray_STRIDES(obj)[1]))

#define PyArray_GETPTR3(obj, i, j, k) ((void *)(PyArray_BYTES(obj) +          \
                                            (i)*PyArray_STRIDES(obj)[0] +     \
                                            (j)*PyArray_STRIDES(obj)[1] +     \
                                            (k)*PyArray_STRIDES(obj)[2]))

#define PyArray_GETPTR4(obj, i, j, k, l) ((void *)(PyArray_BYTES(obj) +       \
                                            (i)*PyArray_STRIDES(obj)[0] +     \
                                            (j)*PyArray_STRIDES(obj)[1] +     \
                                            (k)*PyArray_STRIDES(obj)[2] +     \
                                            (l)*PyArray_STRIDES(obj)[3]))

#define PyArray_XDECREF_ERR(obj) \
        if (obj && (PyArray_FLAGS(obj) & NPY_UPDATEIFCOPY)) {                 \
                PyArray_FLAGS(PyArray_BASE(obj)) |= NPY_WRITEABLE;            \
                PyArray_FLAGS(obj) &= ~NPY_UPDATEIFCOPY;                      \
        }                                                                     \
        Py_XDECREF(obj)

#define PyArray_DESCR_REPLACE(descr) do {                                     \
                PyArray_Descr *_new_;                                         \
                _new_ = PyArray_DescrNew(descr);                              \
                Py_XDECREF(descr);                                            \
                descr = _new_;                                                \
        } while(0)

/* Copy should always return contiguous array */
#define PyArray_Copy(obj) PyArray_NewCopy(obj, NPY_CORDER)

#define PyArray_FromObject(op, type, min_depth, max_depth)                    \
        PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth,           \
                              max_depth, NPY_BEHAVED | NPY_ENSUREARRAY, NULL)

#define PyArray_ContiguousFromObject(op, type, min_depth, max_depth)          \
        PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth,           \
                              max_depth, NPY_DEFAULT | NPY_ENSUREARRAY, NULL)

#define PyArray_CopyFromObject(op, type, min_depth, max_depth)                \
        PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth,           \
                        max_depth, NPY_ENSURECOPY | NPY_DEFAULT |             \
                        NPY_ENSUREARRAY, NULL)

#define PyArray_Cast(mp, type_num)                                            \
        PyArray_CastToType(mp, PyArray_DescrFromType(type_num), 0)

#define PyArray_Take(ap, items, axis)                                         \
        PyArray_TakeFrom(ap, items, axis, NULL, NPY_RAISE)

#define PyArray_Put(ap, items, values)                                        \
        PyArray_PutTo(ap, items, values, NPY_RAISE)

/* Compatibility with old Numeric stuff -- don't use in new code */

#define PyArray_FromDimsAndData(nd, d, type, data)                            \
        PyArray_FromDimsAndDataAndDescr(nd, d, PyArray_DescrFromType(type),   \
                                        data)

#include "old_defines.h"

/*
   Check to see if this key in the dictionary is the "title"
   entry of the tuple (i.e. a duplicate dictionary entry in the fields
   dict.
*/

#define NPY_TITLE_KEY(key, value) ((PyTuple_GET_SIZE((value))==3) && \
                                   (PyTuple_GET_ITEM((value), 2) == (key)))


/* Define python version independent deprecation macro */

#if PY_VERSION_HEX >= 0x02050000
#define DEPRECATE(msg) PyErr_WarnEx(PyExc_DeprecationWarning,msg,1)
#else
#define DEPRECATE(msg) PyErr_Warn(PyExc_DeprecationWarning,msg)
#endif


#ifdef __cplusplus
}
#endif


#endif /* NPY_NDARRAYOBJECT_H */
