changeset 6228:aa5df9ba98d5

[project @ 2007-01-05 22:49:03 by dbateman]
author dbateman
date Fri, 05 Jan 2007 22:49:57 +0000
parents 4c252a611d47
children 6e455cc83069
files liboctave/ChangeLog liboctave/oct-fftw.cc liboctave/oct-fftw.h src/ChangeLog src/DLD-FUNCTIONS/fftw.cc src/DLD-FUNCTIONS/fftw_wisdom.cc src/Makefile.in src/defaults.cc
diffstat 8 files changed, 494 insertions(+), 352 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,14 @@
+2007-01-05  David Bateman  <dbateman@free.fr>
+
+	* oct-fftw.cc: (octave_fftw_planner::method (void), 
+	octave_fftw_planner (FftwMethod)): New methods to interrogate and
+	set the FFTW wisdom method used.
+	(octave_fftw_planner::create_plan) Modify to allow different 
+	methods to be used.
+	(octave_fftw_planner): Move class definition from here.
+	* oct-fftw.h (octave_fftw_planner): To here. Add method methods
+	and FftwMethod enum.
+
 2007-01-03  David Bateman  <dbateman@free.fr>
 
 	* MSparse.cc (SPARSE_A2A2_OP, SPARSE_A2A2_FCN_1,
--- a/liboctave/oct-fftw.cc
+++ b/liboctave/oct-fftw.cc
@@ -33,15 +33,16 @@
 #include "quit.h"
 
 // Helper class to create and cache fftw plans for both 1d and
-// 2d. This implementation uses FFTW_ESTIMATE to create the plans,
-// which in theory is suboptimal, but provides quite reasonable
-// performance.
+// 2d. This implementation defaults to using FFTW_ESTIMATE to create
+// the plans, which in theory is suboptimal, but provides quit
+// reasonable performance.
 
 // Also note that if FFTW_ESTIMATE is not used the planner in FFTW3
-// destroys the input and output arrays. So with the form of the
-// current code we definitely want FFTW_ESTIMATE!! However, we use any
-// wsidom that is available, either in a FFTW3 system wide file or as
-// supplied by the user.
+// destroys the input and output arrays. We must therefore create a
+// temporary input array with the same size and 16-byte alignment as
+// the original array and use that for the planner. Note that we also
+// use any wisdom that is available, either in a FFTW3 system wide file
+//  or as supplied by the user.
 
 // FIXME -- if we can ensure 16 byte alignment in Array<T>
 // (<T> *data) the FFTW3 can use SIMD instructions for further
@@ -50,72 +51,9 @@
 // Note that it is profitable to store the FFTW3 plans, for small
 // ffts.
 
-class
-octave_fftw_planner
-{
-public:
-
-  octave_fftw_planner (void);
-
-  fftw_plan create_plan (int dir, const int rank, const dim_vector dims, 
-			 octave_idx_type howmany, octave_idx_type stride, octave_idx_type dist, 
-			 const Complex *in, Complex *out);
-
-  fftw_plan create_plan (const int rank, const dim_vector dims, 
-			 octave_idx_type howmany, octave_idx_type stride, octave_idx_type dist, 
-			 const double *in, Complex *out);
-
-private:
-
-  int plan_flags;
-
-  // FIXME -- perhaps this should be split into two classes?
-
-  // Plan for fft and ifft of complex values
-  fftw_plan plan[2];
-
-  // dist
-  octave_idx_type d[2];
-
-  // stride
-  octave_idx_type s[2];
-
-  // rank
-  int r[2];
-
-  // howmany
-  octave_idx_type h[2];
-
-  // dims
-  dim_vector n[2];
-
-  bool simd_align[2];
-  bool inplace[2];
-
-  // Plan for fft of real values
-  fftw_plan rplan;
-
-  // dist
-  octave_idx_type rd;
-
-  // stride
-  octave_idx_type rs;
-
-  // rank
-  int rr;
-
-  // howmany
-  octave_idx_type rh;
-
-  // dims
-  dim_vector rn;
-
-  bool rsimd_align;
-};
-
 octave_fftw_planner::octave_fftw_planner (void)
 {
-  plan_flags = FFTW_ESTIMATE;
+  meth = ESTIMATE;
 
   plan[0] = plan[1] = 0;
   d[0] = d[1] = s[0] = s[1] = r[0] = r[1] = h[0] = h[1] = 0;
@@ -132,6 +70,37 @@
   fftw_import_system_wisdom ();
 }
 
+octave_fftw_planner::FftwMethod
+octave_fftw_planner::method (void)
+{
+  return meth;
+}
+
+octave_fftw_planner::FftwMethod
+octave_fftw_planner::method (FftwMethod _meth)
+{
+  FftwMethod ret = meth;
+  if (_meth == ESTIMATE || _meth == MEASURE || 
+      _meth == PATIENT || _meth == EXHAUSTIVE ||
+      _meth == HYBRID)
+    {
+      if (meth != _meth) 
+	{
+	  meth = _meth;
+	  if (rplan)
+	    fftw_destroy_plan (rplan);
+	  if (plan[0])
+	    fftw_destroy_plan (plan[0]);
+	  if (plan[1])
+	    fftw_destroy_plan (plan[1]);
+	  rplan = plan[0] = plan[1] = 0;
+	}
+    }
+  else
+    ret = UNKNOWN;
+  return ret;
+}
+
 #define CHECK_SIMD_ALIGNMENT(x) \
   ((reinterpret_cast<ptrdiff_t> (x)) & 0xF == 0)
 
@@ -178,6 +147,46 @@
       inplace[which] = ioinplace;
       n[which] = dims;
 
+      // Note reversal of dimensions for column major storage in FFTW.
+      octave_idx_type nn = 1;
+      OCTAVE_LOCAL_BUFFER (int, tmp, rank);
+
+      for (int i = 0, j = rank-1; i < rank; i++, j--)
+	{
+	  tmp[i] = dims(j);
+	  nn *= dims(j);
+	}
+
+      int plan_flags = 0;
+      bool plan_destroys_in = true;
+
+      switch (meth) 
+	{
+	case UNKNOWN:
+	case ESTIMATE:
+	  plan_flags |= FFTW_ESTIMATE;
+	  plan_destroys_in = false;
+	  break;
+	case MEASURE:
+	  plan_flags |= FFTW_MEASURE;
+	  break;
+	case PATIENT:
+	  plan_flags |= FFTW_PATIENT;
+	  break;
+	case EXHAUSTIVE:
+	  plan_flags |= FFTW_EXHAUSTIVE;
+	  break;
+	case HYBRID:
+	  if (nn < 8193)
+	    plan_flags |= FFTW_MEASURE;
+	  else
+	    {
+	      plan_flags |= FFTW_ESTIMATE;
+	      plan_destroys_in = false;
+	    }
+	  break;
+	}
+
       if (ioalign)
 	plan_flags &= ~FFTW_UNALIGNED;
       else
@@ -186,18 +195,28 @@
       if (*cur_plan_p)
 	fftw_destroy_plan (*cur_plan_p);
 
-      // Note reversal of dimensions for column major storage in FFTW.
-
-      OCTAVE_LOCAL_BUFFER (int, tmp, rank);
+      if (plan_destroys_in)
+	{
+	  // Create matrix with the same size and 16-byte alignment as input
+	  OCTAVE_LOCAL_BUFFER (Complex, itmp, nn * howmany + 32);
+	  itmp = reinterpret_cast<Complex *>
+	    (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) + 
+	     ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
-      for (int i = 0, j = rank-1; i < rank; i++, j--)
-	tmp[i] = dims(j);
-
-      *cur_plan_p =
-	fftw_plan_many_dft (rank, tmp, howmany,
+	  *cur_plan_p =
+	    fftw_plan_many_dft (rank, tmp, howmany,
+	      reinterpret_cast<fftw_complex *> (itmp),
+	      0, stride, dist, reinterpret_cast<fftw_complex *> (out),
+	      0, stride, dist, dir, plan_flags);
+	}
+      else
+	{
+	  *cur_plan_p =
+	    fftw_plan_many_dft (rank, tmp, howmany,
 	      reinterpret_cast<fftw_complex *> (const_cast<Complex *> (in)),
 	      0, stride, dist, reinterpret_cast<fftw_complex *> (out),
 	      0, stride, dist, dir, plan_flags);
+	}
 
       if (*cur_plan_p == 0)
 	(*current_liboctave_error_handler) ("Error creating fftw plan");
@@ -243,6 +262,46 @@
       rsimd_align = ioalign;
       rn = dims;
 
+      // Note reversal of dimensions for column major storage in FFTW.
+      octave_idx_type nn = 1;
+      OCTAVE_LOCAL_BUFFER (int, tmp, rank);
+
+      for (int i = 0, j = rank-1; i < rank; i++, j--)
+	{
+	  tmp[i] = dims(j);
+	  nn *= dims(j);
+	}
+
+      int plan_flags = 0;
+      bool plan_destroys_in = true;
+
+      switch (meth) 
+	{
+	case UNKNOWN:
+	case ESTIMATE:
+	  plan_flags |= FFTW_ESTIMATE;
+	  plan_destroys_in = false;
+	  break;
+	case MEASURE:
+	  plan_flags |= FFTW_MEASURE;
+	  break;
+	case PATIENT:
+	  plan_flags |= FFTW_PATIENT;
+	  break;
+	case EXHAUSTIVE:
+	  plan_flags |= FFTW_EXHAUSTIVE;
+	  break;
+	case HYBRID:
+	  if (nn < 8193)
+	    plan_flags |= FFTW_MEASURE;
+	  else
+	    {
+	      plan_flags |= FFTW_ESTIMATE;
+	      plan_destroys_in = false;
+	    }
+	  break;
+	}
+
       if (ioalign)
 	plan_flags &= ~FFTW_UNALIGNED;
       else
@@ -251,18 +310,27 @@
       if (*cur_plan_p)
 	fftw_destroy_plan (*cur_plan_p);
 
-      // Note reversal of dimensions for column major storage in FFTW.
-
-      OCTAVE_LOCAL_BUFFER (int, tmp, rank);
+      if (plan_destroys_in)
+	{
+	  // Create matrix with the same size and 16-byte alignment as input
+	  OCTAVE_LOCAL_BUFFER (double, itmp, nn + 32);
+	  itmp = reinterpret_cast<double *>
+	    (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) + 
+	     ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
-      for (int i = 0, j = rank-1; i < rank; i++, j--)
-	tmp[i] = dims(j);
-
-      *cur_plan_p =
-	fftw_plan_many_dft_r2c (rank, tmp, howmany,
+	  *cur_plan_p =
+	    fftw_plan_many_dft_r2c (rank, tmp, howmany, itmp,
+	      0, stride, dist, reinterpret_cast<fftw_complex *> (out),
+	      0, stride, dist, plan_flags);
+	}
+      else
+	{
+	  *cur_plan_p =
+	    fftw_plan_many_dft_r2c (rank, tmp, howmany,
 	      (const_cast<double *> (in)),
 	      0, stride, dist, reinterpret_cast<fftw_complex *> (out),
 	      0, stride, dist, plan_flags);
+	}
 
       if (*cur_plan_p == 0)
 	(*current_liboctave_error_handler) ("Error creating fftw plan");
@@ -271,7 +339,7 @@
   return *cur_plan_p;
 }
 
-static octave_fftw_planner fftw_planner;
+octave_fftw_planner fftw_planner;
 
 static inline void
 convert_packcomplex_1d (Complex *out, size_t nr, size_t nc,
--- a/liboctave/oct-fftw.h
+++ b/liboctave/oct-fftw.h
@@ -29,6 +29,82 @@
 #include "dim-vector.h"
 
 class
+octave_fftw_planner
+{
+public:
+
+  octave_fftw_planner (void);
+
+  fftw_plan create_plan (int dir, const int rank, const dim_vector dims, 
+			 octave_idx_type howmany, octave_idx_type stride, octave_idx_type dist, 
+			 const Complex *in, Complex *out);
+
+  fftw_plan create_plan (const int rank, const dim_vector dims, 
+			 octave_idx_type howmany, octave_idx_type stride, octave_idx_type dist, 
+			 const double *in, Complex *out);
+
+  enum FftwMethod {
+    UNKNOWN = -1,
+    ESTIMATE,
+    MEASURE,
+    PATIENT,
+    EXHAUSTIVE,
+    HYBRID
+  };
+
+  FftwMethod method (void);
+
+  FftwMethod method (FftwMethod _meth);
+
+private:
+
+  FftwMethod meth;
+
+  // FIXME -- perhaps this should be split into two classes?
+
+  // Plan for fft and ifft of complex values
+  fftw_plan plan[2];
+
+  // dist
+  octave_idx_type d[2];
+
+  // stride
+  octave_idx_type s[2];
+
+  // rank
+  int r[2];
+
+  // howmany
+  octave_idx_type h[2];
+
+  // dims
+  dim_vector n[2];
+
+  bool simd_align[2];
+  bool inplace[2];
+
+  // Plan for fft of real values
+  fftw_plan rplan;
+
+  // dist
+  octave_idx_type rd;
+
+  // stride
+  octave_idx_type rs;
+
+  // rank
+  int rr;
+
+  // howmany
+  octave_idx_type rh;
+
+  // dims
+  dim_vector rn;
+
+  bool rsimd_align;
+};
+
+class
 octave_fftw
 {
 public:
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,13 @@
+2007-01-05  David Bateman  <dbateman@free.fr>
+
+	* Makefile.in (DLD_XSRC): Add fftw.cc and remove fftw_wisdom.cc
+	* DLD-FUNCTIONS/fftw.cc: New file.
+	* DLD-FUNCTIONS/fftw_wisdom.cc: Delete.
+	* defaults.cc (Vfftw_wisdom_program): Delete variable.
+	(set_default_fftw_wisdom_prog): Delete function that sets it.
+	(install_defaults): Delete set_default_fftw_prog from defaults.
+	(Ffftw_wisdom_program): Delete.
+
 2007-01-04  David Bateman  <dbateman@free.fr>
 
 	* ov-fcn-handle.cc (octave_fcn_handle::load_ascii,
new file mode 100644
--- /dev/null
+++ b/src/DLD-FUNCTIONS/fftw.cc
@@ -0,0 +1,240 @@
+/*
+
+Copyright (C) 2006 David Bateman
+
+This file is part of Octave.
+
+Octave 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, or (at your option) any
+later version.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <algorithm>
+#include "ov.h"
+#include "defun-dld.h"
+#include "error.h"
+
+#if defined (HAVE_FFTW3)
+#include "oct-fftw.h"
+#endif
+
+extern octave_fftw_planner fftw_planner;
+
+DEFUN_DLD (fftw, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Loadable Function} {@var{method} =} fftw ('planner')\n\
+@deftypefnx {Loadable Function} {} fftw ('planner', @var{method})\n\
+@deftypefnx {Loadable Function} {@var{wisdom} =} fftw ('dwisdom')\n\
+@deftypefnx {Loadable Function} {@var{wisdom} =} fftw ('dwisdom', @var{wisdom})\n\
+\n\
+Manage FFTW wisdom data. Wisdom data can be used to significantly\n\
+accelerate the calculation of the FFTs but implies a initial cost\n\
+in its calculation. The wisdom used by Octave can be imported directly,\n\
+usually from a file /etc/fftw/wisdom, or @dfn{fftw} can be used\n\
+to import wisdom. For example\n\
+\n\
+@example\n\
+@var{wisdom} = fftw ('dwisdom')\n\
+@end example\n\
+\n\
+will save the existing wisdom used by Octave to the string @var{wisdom}.\n\
+This string can then be saved in the usual manner. This existing wisdom\n\
+can be reimported as follows\n\
+\n\
+@example\n\
+fftw ('dwisdom', @var{wisdom})\n\
+@end example \n\
+\n\
+If @var{wisdom} is an empty matrix, then the wisdom used is cleared.\n\
+\n\
+During the calculation of fourier transforms further wisdom is generated.\n\
+The fashion in which this wisdom is generated is equally controlled by\n\
+the @dfn{fftw} function. There are five different manners in which the\n\
+wisdom can be treated, these being\n\
+\n\
+@table @asis\n\
+@item 'estimate'\n\
+This specifies that no run-time measurement of the optimal means of\n\
+calculating a particular is performed, and a simple heuristic is used\n\
+to pick a (probably sub-optimal) plan. The advantage of this method is\n\
+that there is little or no overhead in the generation of the plan, which\n\
+is appropriate for a fourier transform that will be calculated once.\n\
+\n\
+@item 'measure'\n\
+In this case a range of algorithms to perform the transform is considered\n\
+and the best is selected based on their execution time.\n\
+\n\
+@item 'patient'\n\
+This is like 'measure', but a wider range of algorithms is considered.\n\
+\n\
+@item 'exhasutive'\n\
+This is like 'meaure', but all possible algorithms that may be used to\n\
+treat the transform are considered.\n\
+\n\
+@item 'hybrid'\n\
+As run-time measurement of the algorithm can be expensive, this is a\n\
+compromise where 'measure' is used for transforms upto the size of 8192\n\
+and beyond that the 'estimate' method is used.\n\
+@end table\n\
+\n\
+The default method is 'estimate', and the method currently being used can\n\
+be probed with\n\
+\n\
+@example\n\
+@var{method} = fftw ('planner')\n\
+@end example\n\
+\n\
+and the method used can be set using\n\
+\n\
+@example\n\
+fftw ('planner', @var{method})\n\
+@end example\n\
+\n\
+Note that calculated wisdom will be lost when restarting Octave. However,\n\
+the wisdom data can be reloaded if it is saved to a file as described\n\
+above.  Also, any system-wide wisdom file that has been found will\n\
+also be used. Saved wisdom files should not be used on different\n\
+platforms since they will not be efficient and the point of calculating\n\
+the wisdom is lost.\n\
+@seealso{fft, ifft, fft2, ifft2, fftn, ifftn}\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length();
+
+  if (nargin < 1 || nargin > 2)
+    {
+      print_usage ();
+      return retval;
+    }
+
+#if defined (HAVE_FFTW3)
+  if (args(0).is_string ())
+    {
+      std::string arg0 = args(0).string_value ();
+
+      if (!error_state)
+	{
+	  // Use STL function to convert to lower case
+	  std::transform (arg0.begin (), arg0.end (), arg0.begin (), tolower);
+	  
+	  if (nargin == 2)
+	    {
+	      std::string arg1 = args(1).string_value ();
+	      if (!error_state)
+		{
+		  if (arg0 == "planner")
+		    {
+		      std::transform (arg1.begin (), arg1.end (), 
+				      arg1.begin (), tolower);
+		      octave_fftw_planner::FftwMethod meth;
+
+		      if (arg1 == "estimate")
+			meth = fftw_planner.method
+			  (octave_fftw_planner::ESTIMATE);
+		      else if (arg1 == "measure")
+			meth = fftw_planner.method 
+			  (octave_fftw_planner::MEASURE);
+		      else if (arg1 == "patient")
+			meth = fftw_planner.method 
+			  (octave_fftw_planner::PATIENT);
+		      else if (arg1 == "exhaustive")
+			meth = fftw_planner.method 
+			  (octave_fftw_planner::EXHAUSTIVE);
+		      else if (arg1 == "hybrid")
+			meth = fftw_planner.method 
+			  (octave_fftw_planner::HYBRID);
+		      else
+			error ("unrecognized planner method");
+
+		      if (!error_state)
+			{
+			  if (meth == octave_fftw_planner::MEASURE)
+			    retval = octave_value ("measure");
+			  else if (meth == octave_fftw_planner::PATIENT)
+			    retval = octave_value ("patient");
+			  else if (meth == octave_fftw_planner::EXHAUSTIVE)
+			    retval = octave_value ("exhaustive");
+			  else if (meth == octave_fftw_planner::HYBRID)
+			    retval = octave_value ("hybrid");
+			  else
+			    retval = octave_value ("estimate");
+			}
+		    }
+		  else if (arg0 == "dwisdom")
+		    {
+		      char *str = fftw_export_wisdom_to_string ();
+
+		      if (arg1.length() < 1)
+			fftw_forget_wisdom ();
+		      else if (! fftw_import_wisdom_from_string (arg1.c_str()))
+			error ("could not import supplied wisdom");
+
+		      if (!error_state)
+			retval = octave_value (std::string (str));
+
+		      free (str);
+		    }
+		  else if (arg0 == "swisdom")
+		    error ("single precision wisdom is not supported");
+		  else
+		    error ("unrecognized argument");
+		}
+	    }
+	  else
+	    {
+	      if (arg0 == "planner")
+		{
+		  octave_fftw_planner::FftwMethod meth = 
+		    fftw_planner.method ();
+
+		  if (meth == octave_fftw_planner::MEASURE)
+		    retval = octave_value ("measure");
+		  else if (meth == octave_fftw_planner::PATIENT)
+		    retval = octave_value ("patient");
+		  else if (meth == octave_fftw_planner::EXHAUSTIVE)
+		    retval = octave_value ("exhaustive");
+		  else if (meth == octave_fftw_planner::HYBRID)
+		    retval = octave_value ("hybrid");
+		  else
+		    retval = octave_value ("estimate");
+		}
+	      else if (arg0 == "dwisdom")
+		{
+		  char *str = fftw_export_wisdom_to_string ();
+		  retval = octave_value (std::string (str));
+		  free (str);
+		}
+	      else if (arg0 == "swisdom")
+		error ("single precision wisdom is not supported");
+	      else
+		error ("unrecognized argument");
+	    }
+	}
+    }
+#else
+
+  warning ("fftw: this copy of Octave was not configured to use FFTW3");
+
+#endif
+
+  return retval;
+}
+
deleted file mode 100644
--- a/src/DLD-FUNCTIONS/fftw_wisdom.cc
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
-
-Copyright (C) 2004 David Bateman
-
-This file is part of Octave.
-
-Octave 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, or (at your option) any
-later version.
-
-Octave 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 Octave; see the file COPYING.  If not, write to the Free
-Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#if defined (HAVE_FFTW3)
-#include <fftw3.h>
-#endif
-
-#include <sstream>
-
-#include "file-stat.h"
-
-#include "defaults.h"
-#include "defun-dld.h"
-#include "error.h"
-#include "file-ops.h"
-#include "gripes.h"
-#include "lo-mappers.h"
-#include "load-path.h"
-#include "oct-env.h"
-#include "oct-obj.h"
-#include "sighandlers.h"
-#include "utils.h"
-
-DEFUN_DLD (fftw_wisdom, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Loadable Function} {} fftw_wisdom (@var{file}, @var{mode})\n\
-Save or load FFTW wisdom data to @var{file}.  The optional argument\n\
-@var{mode} may be either @samp{\"r\"} or @samp{\"w\"}.  The default\n\
-value is @samp{\"r\"}.\n\
-\n\
-@deftypefnx {Loadable Function} {} fftw_wisdom (@var{n})\n\
-Pre-calculate FFTW wisdom data for an FFT of size @var{n}.\n\
-Each row of @var{n} represents the size of an FFT for\n\
-which it is desired to pre-calculate the wisdom needed to accelerate it.\n\
-Any value of the matrix that is less than 1, is assumed to indicate an\n\
-absent dimension.  For example,\n\
-\n\
-@example\n\
-fftw_wisdom ([102, 0, 0; 103, 103, 0; 102, 103, 105]);\n\
-a = fft (rand (1,102));\n\
-b = fft (rand (103,103));\n\
-c = fftn (rand ([102, 103, 105]));\n\
-@end example\n\
-\n\
-calculates the wisdom necessary to accelerate the 103, 102x102 and\n\
-the 102x103x105 FFTs. Note that calculated wisdom will be lost when\n\
-restarting Octave. However, the wisdom data can be reloaded if it is\n\
-saved to a file as described above.  Also, any system-wide wisdom\n\
-file that has been found will also be used. Saved wisdom files\n\
-should not be used on different platforms since they will not be\n\
-efficient and the point of calculating the wisdom is lost.\n\
-\n\
-Wisdom data can be used to significantly accelerate the calculation\n\
-of the FFTs but is only profitable if the same FFT is called many\n\
-times due to the overhead in calculating the wisdom data.\n\
-\n\
-Note that the program @code{fftw-wisdom} supplied with FFTW can equally\n\
-be used to create a file containing wisdom that can be imported into\n\
-Octave.\n\
-@seealso{fft, ifft, fft2, ifft2, fftn, ifftn}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length();
-
-  if (nargin < 1 || nargin > 2)
-    {
-      print_usage ();
-      return retval;
-    }
-
-#if defined (HAVE_FFTW3)
-
-  if (args(0).is_string ())
-    {
-      bool write_wisdom = false;
-
-      if (nargin == 2)
-	{
-	  std::string mode = args(1).string_value ();
-
-	  if (! error_state && (mode == "r" || mode == "w"))
-	    write_wisdom = mode == "w";
-	  else
-	    {
-	      error ("fftw_wisdom: expecting second argument to be \"r\" or \"w\"");
-	      return retval;
-	    }
-	}
-
-      std::string name = args(0).string_value ();
-
-      std::string wisdom = file_ops::tilde_expand (name);
-
-      if (! (write_wisdom || octave_env::absolute_pathname (wisdom)))
-	{
-	  file_stat fs (wisdom);
-
-	  if (! fs.exists ())
-	    {
-	      std::string tmp = octave_env::make_absolute
-		(load_path::find_file (wisdom), octave_env::getcwd ());
-
-	      if (! tmp.empty ())
-		{
-		  warning_with_id ("Octave:fftw-wisdom-file-in-path",
-				   "fftw_wisdom: file found in load path");
-		  wisdom = tmp;
-		}
-	    }
-	}
-
-      if (write_wisdom)
-	{
-	  FILE *ofile = fopen (wisdom.c_str (), "wb");
-
-	  if (! ofile)
-	    error ("fftw_wisdom: unable to open file `%s' for writing",
-		   wisdom.c_str());
-	  else
-	    {
-	      fftw_export_wisdom_to_file (ofile);
-	      fclose (ofile);
-	    }
-	}
-      else
-	{
-	  FILE *ifile = fopen (wisdom.c_str (), "r");
-
-	  if (! ifile)
-	    error ("fftw_wisdom: unable to open file `%s' for reading",
-		   wisdom.c_str ());
-	  else
-	    {
-	      if (! fftw_import_wisdom_from_file (ifile))
-		error ("fftw_wisdom: can not import wisdom from file"); 
-
-	      fclose (ifile);
-	    }
-	}
-    } 
-  else 
-    {
-      Matrix m = args (0).matrix_value ();
-
-      if (error_state)
-	{
-	  error ("fftw_wisdom: argument must be a matrix or a string");
-	  return retval;
-	}
-
-      std::string name = file_ops::tempnam ("", "oct-");
-
-      if (name.empty ())
-	{
-	  error ("fftw_wisdom: can not open temporary file");
-	  return retval;
-	}
-
-      std::ostringstream cmd_buf; 
-      cmd_buf << Vfftw_wisdom_program << " -n -o \"" << name << "\"";
-
-      for (octave_idx_type k = 0; k < m.rows (); k++)
-	{
-	  bool first = true;
-
-	  cmd_buf << " ";
-
-	  // Note reversal of dimensions for column major storage in FFTW
-	  for (octave_idx_type j = m.columns()-1; j >= 0; j--)
-	    if (NINTbig(m(k,j)) > 0)
-	      {
-		if (first)
-		  first = false;
-		else
-		  cmd_buf << "x";
-		cmd_buf << NINTbig(m(k,j)) ;
-	      }
-	} 
-
-      volatile octave_interrupt_handler old_interrupt_handler
-	= octave_ignore_interrupts ();
-
-      std::string cmd_buf_str = cmd_buf.str ();
-
-      int status = system (cmd_buf_str.c_str ());
-
-      octave_set_interrupt_handler (old_interrupt_handler);
-
-      if (WIFEXITED (status))
-	{
-	  FILE *ifile = fopen (name.c_str (), "r");
-	  if (! fftw_import_wisdom_from_file (ifile))
-	    error ("fftw_wisdom: can not import wisdom from temporary file"); 
-	  fclose (ifile);
-	}
-      else
-	error ("fftw_wisdom: error running %s", Vfftw_wisdom_program.c_str ());
-    }
-
-#else
-
-  warning ("fftw_wisdom: this copy of Octave was not configured to use FFTW3");
-
-#endif
-
-  return retval;
-}
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -50,7 +50,7 @@
 DLD_XSRC := balance.cc besselj.cc betainc.cc cellfun.cc chol.cc \
 	ccolamd.cc colamd.cc colloc.cc conv2.cc daspk.cc dasrt.cc \
 	dassl.cc det.cc dispatch.cc eig.cc expm.cc fft.cc fft2.cc \
-	fftn.cc fftw_wisdom.cc filter.cc find.cc fsolve.cc \
+	fftn.cc fftw.cc fftw_wisdom.cc filter.cc find.cc fsolve.cc \
 	gammainc.cc gcd.cc getgrent.cc getpwent.cc getrusage.cc \
 	givens.cc hess.cc inv.cc kron.cc lpsolve.cc lsode.cc \
 	lu.cc luinc.cc matrix_type.cc minmax.cc pinv.cc qr.cc \
--- a/src/defaults.cc
+++ b/src/defaults.cc
@@ -96,9 +96,6 @@
 std::string Vlocal_site_defaults_file;
 std::string Vsite_defaults_file;
 
-// Name of the FFTW wisdom program.
-std::string Vfftw_wisdom_program;
-
 static std::string
 subst_octave_home (const std::string& s)
 {
@@ -304,17 +301,6 @@
 }
 
 static void
-set_default_fftw_wisdom_prog (void)
-{
-  std::string oct_wisdom_prog = octave_env::getenv ("OCTAVE_FFTW_WISDOM_PROGRAM");
-
-  if (oct_wisdom_prog.empty ())
-    Vfftw_wisdom_program = "fftw-wisdom";
-  else
-    Vfftw_wisdom_program = std::string (oct_wisdom_prog);
-}
-
-static void
 set_default_editor (void)
 {
   VEDITOR = "emacs";
@@ -395,8 +381,6 @@
 
   set_default_info_prog ();
 
-  set_default_fftw_wisdom_prog ();
-
   set_default_editor ();
 
   set_local_site_defaults_file ();
@@ -445,20 +429,6 @@
   return retval;
 }
 
-DEFUN (fftw_wisdom_program, args, nargout,
-    "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} FFTW_WISDOM_PROGRAM ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} FFTW_WISDOM_PROGRAM (@var{new_val})\n\
-Query or set the internal variable that specifies the FFTW wisdom\n\
-program to use to create wisdom data to accelerate Fourier transforms.\n\
-If the environment variable @code{OCTAVE_WISDOM_PROGRAM} is set when\n\
-Octave starts, its value is used as the default. Otherwise,\n\
-@code{WISDOM_PROGRAM} is set to @code{\"fftw-wisdom\"}.\n\
-@end deftypefn")
-{
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (fftw_wisdom_program);
-}
-
 DEFUN (IMAGE_PATH, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} IMAGE_PATH ()\n\