/* -*- C -*- */
/*
 * Copyright (c) 1997-1999, 2003 Massachusetts Institute of Technology
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/* fftw.h -- system-wide definitions */
/* $Id: fftw.h.in,v 1.57 2003/03/16 23:43:46 stevenj Exp $ */

#ifndef FFTW_H
#define FFTW_H

#include <stdlib.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C"
{
#endif				/* __cplusplus */

/* Define for using single precision */
/*
 * If you can, use configure --enable-float instead of changing this
 * flag directly 
 */
/* #undef FFTW_ENABLE_FLOAT */

/* our real numbers */
#ifdef FFTW_ENABLE_FLOAT
  typedef float fftw_real;
#else
  typedef double fftw_real;
#endif

/*********************************************
 * Complex numbers and operations 
 *********************************************/
  typedef struct
  {
    fftw_real re, im;
  } fftw_complex;

#ifndef c_re
#define c_re(c)  ((c).re)
#endif
#ifndef c_im
#define c_im(c)  ((c).im)
#endif

  typedef enum
  {
    FFTW_FORWARD = -1, FFTW_BACKWARD = 1
  } fftw_direction;

/* backward compatibility with FFTW-1.3 */
  typedef fftw_complex FFTW_COMPLEX;
  typedef fftw_real FFTW_REAL;

#ifndef FFTW_1_0_COMPATIBILITY
#define FFTW_1_0_COMPATIBILITY 0
#endif

#if FFTW_1_0_COMPATIBILITY
/* backward compatibility with FFTW-1.0 */
#define REAL fftw_real
#define COMPLEX fftw_complex
#endif

/*********************************************
 * Success or failure status
 *********************************************/

  typedef enum
  {
    FFTW_SUCCESS = 0, FFTW_FAILURE = -1
  } fftw_status;

/*********************************************
 *              Codelets
 *********************************************/
  typedef void (fftw_notw_codelet)
    (const fftw_complex *, fftw_complex *, int, int);
  typedef void (fftw_twiddle_codelet)
    (fftw_complex *, const fftw_complex *, int, int, int);
  typedef void (fftw_generic_codelet)
    (fftw_complex *, const fftw_complex *, int, int, int, int);
  typedef void (fftw_real2hc_codelet)
    (const fftw_real *, fftw_real *, fftw_real *, int, int, int);
  typedef void (fftw_hc2real_codelet)
    (const fftw_real *, const fftw_real *, fftw_real *, int, int, int);
  typedef void (fftw_hc2hc_codelet)
    (fftw_real *, const fftw_complex *, int, int, int);
  typedef void (fftw_rgeneric_codelet)
    (fftw_real *, const fftw_complex *, int, int, int, int);

/*********************************************
 *     Configurations
 *********************************************/
/*
 * A configuration is a database of all known codelets
 */

  enum fftw_node_type
  {
    FFTW_NOTW, FFTW_TWIDDLE, FFTW_GENERIC, FFTW_RADER,
    FFTW_REAL2HC, FFTW_HC2REAL, FFTW_HC2HC, FFTW_RGENERIC
  };

/* description of a codelet */
  typedef struct
  {
    const char *name;		/* name of the codelet */
    void (*codelet) ();		/* pointer to the codelet itself */
    int size;			/* size of the codelet */
    fftw_direction dir;		/* direction */
    enum fftw_node_type type;	/* TWIDDLE or NO_TWIDDLE */
    int signature;		/* unique id */
    int ntwiddle;		/* number of twiddle factors */
    const int *twiddle_order;	/* 
				 * array that determines the order 
				 * in which the codelet expects
				 * the twiddle factors
				 */
  } fftw_codelet_desc;

/* On Win32, you need to do funny things to access global variables
   in shared libraries.  Thanks to Andrew Sterian for this hack. */
#ifdef HAVE_WIN32
#  if defined(BUILD_FFTW_DLL)
#    define DL_IMPORT(type) __declspec(dllexport) type
#  elif defined(USE_FFTW_DLL)
#    define DL_IMPORT(type) __declspec(dllimport) type
#  else
#    define DL_IMPORT(type) type
#  endif
#else
#  define DL_IMPORT(type) type
#endif

  extern DL_IMPORT (const char *) fftw_version;

/*****************************
 *        Plans
 *****************************/
/*
 * A plan is a sequence of reductions to compute a FFT of
 * a given size.  At each step, the FFT algorithm can:
 *
 * 1) apply a notw codelet, or
 * 2) recurse and apply a twiddle codelet, or
 * 3) apply the generic codelet.
 */

/* structure that contains twiddle factors */
  typedef struct fftw_twiddle_struct
  {
    int n;
    const fftw_codelet_desc *cdesc;
    fftw_complex *twarray;
    struct fftw_twiddle_struct *next;
    int refcnt;
  } fftw_twiddle;

  typedef struct fftw_rader_data_struct
  {
    struct fftw_plan_struct *plan;
    fftw_complex *omega;
    int g, ginv;
    int p, flags, refcount;
    struct fftw_rader_data_struct *next;
    fftw_codelet_desc *cdesc;
  } fftw_rader_data;

  typedef void (fftw_rader_codelet)
    (fftw_complex *, const fftw_complex *, int, int, int, fftw_rader_data *);

/* structure that holds all the data needed for a given step */
  typedef struct fftw_plan_node_struct
  {
    enum fftw_node_type type;

    union
    {
      /* nodes of type FFTW_NOTW */
      struct
      {
	int size;
	fftw_notw_codelet *codelet;
	const fftw_codelet_desc *codelet_desc;
      } notw;

      /* nodes of type FFTW_TWIDDLE */
      struct
      {
	int size;
	fftw_twiddle_codelet *codelet;
	fftw_twiddle *tw;
	struct fftw_plan_node_struct *recurse;
	const fftw_codelet_desc *codelet_desc;
      } twiddle;

      /* nodes of type FFTW_GENERIC */
      struct
      {
	int size;
	fftw_generic_codelet *codelet;
	fftw_twiddle *tw;
	struct fftw_plan_node_struct *recurse;
      } generic;

      /* nodes of type FFTW_RADER */
      struct
      {
	int size;
	fftw_rader_codelet *codelet;
	fftw_rader_data *rader_data;
	fftw_twiddle *tw;
	struct fftw_plan_node_struct *recurse;
      } rader;

      /* nodes of type FFTW_REAL2HC */
      struct
      {
	int size;
	fftw_real2hc_codelet *codelet;
	const fftw_codelet_desc *codelet_desc;
      } real2hc;

      /* nodes of type FFTW_HC2REAL */
      struct
      {
	int size;
	fftw_hc2real_codelet *codelet;
	const fftw_codelet_desc *codelet_desc;
      } hc2real;

      /* nodes of type FFTW_HC2HC */
      struct
      {
	int size;
	fftw_direction dir;
	fftw_hc2hc_codelet *codelet;
	fftw_twiddle *tw;
	struct fftw_plan_node_struct *recurse;
	const fftw_codelet_desc *codelet_desc;
      } hc2hc;

      /* nodes of type FFTW_RGENERIC */
      struct
      {
	int size;
	fftw_direction dir;
	fftw_rgeneric_codelet *codelet;
	fftw_twiddle *tw;
	struct fftw_plan_node_struct *recurse;
      } rgeneric;
    } nodeu;

    int refcnt;
  } fftw_plan_node;

  typedef enum
  {
    FFTW_NORMAL_RECURSE = 0,
    FFTW_VECTOR_RECURSE = 1
  } fftw_recurse_kind;

  struct fftw_plan_struct
  {
    int n;
    int refcnt;
    fftw_direction dir;
    int flags;
    int wisdom_signature;
    enum fftw_node_type wisdom_type;
    struct fftw_plan_struct *next;
    fftw_plan_node *root;
    double cost;
    fftw_recurse_kind recurse_kind;
    int vector_size;
  };

  typedef struct fftw_plan_struct *fftw_plan;

/* flags for the planner */
#define  FFTW_ESTIMATE (0)
#define  FFTW_MEASURE  (1)

#define FFTW_OUT_OF_PLACE (0)
#define FFTW_IN_PLACE (8)
#define FFTW_USE_WISDOM (16)

#define FFTW_THREADSAFE (128)	/* guarantee plan is read-only so that the
				   same plan can be used in parallel by
				   multiple threads */

#define FFTWND_FORCE_BUFFERED (256)	/* internal flag, forces buffering
					   in fftwnd transforms */

#define FFTW_NO_VECTOR_RECURSE (512)	/* internal flag, prevents use
					   of vector recursion */

  extern fftw_plan fftw_create_plan_specific (int n, fftw_direction dir,
					      int flags,
					      fftw_complex * in,
					      int istride,
					      fftw_complex * out,
					      int ostride);
#define FFTW_HAS_PLAN_SPECIFIC
  extern fftw_plan fftw_create_plan (int n, fftw_direction dir, int flags);
  extern void fftw_print_plan (fftw_plan plan);
  extern void fftw_destroy_plan (fftw_plan plan);
  extern void fftw (fftw_plan plan, int howmany, fftw_complex * in,
		    int istride, int idist, fftw_complex * out,
		    int ostride, int odist);
  extern void fftw_one (fftw_plan plan, fftw_complex * in,
			fftw_complex * out);
  extern void fftw_die (const char *s);
  extern void *fftw_malloc (size_t n);
  extern void fftw_free (void *p);
  extern void fftw_check_memory_leaks (void);
  extern void fftw_print_max_memory_usage (void);

  typedef void *(*fftw_malloc_type_function) (size_t n);
  typedef void (*fftw_free_type_function) (void *p);
  typedef void (*fftw_die_type_function) (const char *errString);
  extern DL_IMPORT (fftw_malloc_type_function) fftw_malloc_hook;
  extern DL_IMPORT (fftw_free_type_function) fftw_free_hook;
  extern DL_IMPORT (fftw_die_type_function) fftw_die_hook;

  extern size_t fftw_sizeof_fftw_real (void);

/* Wisdom: */
/*
 * define this symbol so that users know we are using a version of FFTW
 * with wisdom
 */
#define FFTW_HAS_WISDOM
  extern void fftw_forget_wisdom (void);
  extern void fftw_export_wisdom (void (*emitter) (char c, void *),
				  void *data);
  extern fftw_status fftw_import_wisdom (int (*g) (void *), void *data);
  extern void fftw_export_wisdom_to_file (FILE * output_file);
  extern fftw_status fftw_import_wisdom_from_file (FILE * input_file);
  extern char *fftw_export_wisdom_to_string (void);
  extern fftw_status fftw_import_wisdom_from_string (const char
						     *input_string);

/*
 * define symbol so we know this function is available (it is not in
 * older FFTWs)
 */
#define FFTW_HAS_FPRINT_PLAN
  extern void fftw_fprint_plan (FILE * f, fftw_plan plan);

/*****************************
 *    N-dimensional code
 *****************************/
  typedef struct
  {
    int is_in_place;		/* 1 if for in-place FFTs, 0 otherwise */

    int rank;			/* 
				 * the rank (number of dimensions) of the
				 * array to be FFTed 
				 */
    int *n;			/*
				 * the dimensions of the array to the
				 * FFTed 
				 */
    fftw_direction dir;

    int *n_before;		/*
				 * n_before[i] = product of n[j] for j < i 
				 */
    int *n_after;		/* n_after[i] = product of n[j] for j > i */

    fftw_plan *plans;		/* 1d fftw plans for each dimension */

    int nbuffers, nwork;
    fftw_complex *work;		/* 
				 * work array big enough to hold
				 * nbuffers+1 of the largest dimension 
				 * (has nwork elements)
				 */
  } fftwnd_data;

  typedef fftwnd_data *fftwnd_plan;

/* Initializing the FFTWND plan: */
  extern fftwnd_plan fftw2d_create_plan (int nx, int ny,
					 fftw_direction dir, int flags);
  extern fftwnd_plan fftw3d_create_plan (int nx, int ny, int nz,
					 fftw_direction dir, int flags);
  extern fftwnd_plan fftwnd_create_plan (int rank, const int *n,
					 fftw_direction dir, int flags);

  extern fftwnd_plan fftw2d_create_plan_specific (int nx, int ny,
						  fftw_direction dir,
						  int flags,
						  fftw_complex * in,
						  int istride,
						  fftw_complex * out,
						  int ostride);
  extern fftwnd_plan fftw3d_create_plan_specific (int nx, int ny, int nz,
						  fftw_direction dir,
						  int flags,
						  fftw_complex * in,
						  int istride,
						  fftw_complex * out,
						  int ostride);
  extern fftwnd_plan fftwnd_create_plan_specific (int rank, const int *n,
						  fftw_direction dir,
						  int flags,
						  fftw_complex * in,
						  int istride,
						  fftw_complex * out,
						  int ostride);

/* Freeing the FFTWND plan: */
  extern void fftwnd_destroy_plan (fftwnd_plan plan);

/* Printing the plan: */
  extern void fftwnd_fprint_plan (FILE * f, fftwnd_plan p);
  extern void fftwnd_print_plan (fftwnd_plan p);
#define FFTWND_HAS_PRINT_PLAN

/* Computing the N-Dimensional FFT */
  extern void fftwnd (fftwnd_plan plan, int howmany,
		      fftw_complex * in, int istride, int idist,
		      fftw_complex * out, int ostride, int odist);
  extern void fftwnd_one (fftwnd_plan p, fftw_complex * in,
			  fftw_complex * out);

#ifdef __cplusplus
}				/* extern "C" */
#endif				/* __cplusplus */
#endif				/* FFTW_H */
