/// /// This file is part of ILNumerics Community Edition. /// /// ILNumerics Community Edition - high performance computing for applications. /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net /// /// ILNumerics Community Edition is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License version 3 as published by /// the Free Software Foundation. /// /// ILNumerics Community Edition 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 ILNumerics Community Edition. See the file License.txt in the root /// of your distribution package. If not, see . /// /// In addition this software uses the following components and/or licenses: /// /// ================================================================================= /// The Open Toolkit Library License /// /// Copyright (c) 2006 - 2009 the Open Toolkit library. /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights to /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software is furnished to do /// so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in all /// copies or substantial portions of the Software. /// /// ================================================================================= /// #pragma warning disable 1591 using System; using System.Collections.Generic; using System.Text; using System.Security; using System.Runtime.InteropServices; using ILNumerics.Exceptions; using ILNumerics.Misc; namespace ILNumerics.Native { /// /// MKL configuration parameters (constant definitions) /// internal sealed class MKLParameter { /* Domain for forward transform. No default value */ public static readonly int FORWARD_DOMAIN = 0; /* Dimensionality; or rank. No default value */ public static readonly int DIMENSION = 1; /* Length(s) of transform. No default value */ public static readonly int LENGTHS = 2; /* Floating point precision. No default value */ public static readonly int PRECISION = 3; /* Scale factor for forward transform [1.0] */ public static readonly int FORWARD_SCALE = 4; /* Scale factor for backward transform [1.0] */ public static readonly int BACKWARD_SCALE = 5; /* Exponent sign for forward transform [NEGATIVE] */ /* FORWARD_SIGN = 6; ## NOT IMPLEMENTED */ /* Number of data sets to be transformed [1] */ public static readonly int NUMBER_OF_TRANSFORMS = 7; /* Storage of finite complex-valued sequences in complex domain [COMPLEX_COMPLEX] */ public static readonly int COMPLEX_STORAGE = 8; /* Storage of finite real-valued sequences in real domain [REAL_REAL] */ public static readonly int REAL_STORAGE = 9; /* Storage of finite complex-valued sequences in conjugate-even domain [COMPLEX_REAL] */ public static readonly int CONJUGATE_EVEN_STORAGE = 10; /* Placement of result [INPLACE] */ public static readonly int PLACEMENT = 11; /* Generalized strides for input data layout [tight; row-major for C] */ public static readonly int INPUT_STRIDES = 12; /* Generalized strides for output data layout [tight; row-major for C] */ public static readonly int OUTPUT_STRIDES = 13; /* Distance between first input elements for multiple transforms [0] */ public static readonly int INPUT_DISTANCE = 14; /* Distance between first output elements for multiple transforms [0] */ public static readonly int OUTPUT_DISTANCE = 15; /* Ordering of the result [ORDERED] */ public static readonly int ORDERING = 18; /* Possible transposition of result [NONE] */ public static readonly int TRANSPOSE = 19; /* User-settable descriptor name [""] */ public static readonly int DESCRIPTOR_NAME = 20; /* DEPRECATED */ /* Packing format for COMPLEX_REAL storage of finite conjugate-even sequences [CCS_FORMAT] */ public static readonly int PACKED_FORMAT = 21; /* Commit status of the descriptor - R/O parameter */ public static readonly int COMMIT_STATUS = 22; /* Version string for this DFTI implementation - R/O parameter */ public static readonly int VERSION = 23; /* Number of user threads that share the descriptor [1] */ public static readonly int NUMBER_OF_USER_THREADS = 26; } /// /// MKL configuration values (constant definitions) /// internal sealed class MKLValues { public static readonly int MKL_ALL = 0; public static readonly int MKL_BLAS = 1; public static readonly int MKL_FFT = 2; public static readonly int MKL_VML = 3; /* Values of the descriptor configuration parameters */ /* COMMIT_STATUS */ public static readonly int COMMITTED = 30; public static readonly int UNCOMMITTED = 31; /* FORWARD_DOMAIN */ public static readonly int COMPLEX = 32; public static readonly int REAL = 33; /* CONJUGATE_EVEN = 34; ## NOT IMPLEMENTED */ /* PRECISION */ public static readonly int SINGLE = 35; public static readonly int DOUBLE = 36; /* COMPLEX_STORAGE and CONJUGATE_EVEN_STORAGE */ public static readonly int COMPLEX_COMPLEX = 39; public static readonly int COMPLEX_REAL = 40; /* REAL_STORAGE */ public static readonly int REAL_COMPLEX = 41; public static readonly int REAL_REAL = 42; /* PLACEMENT */ public static readonly int INPLACE = 43; /* Result overwrites input */ public static readonly int NOT_INPLACE = 44; /* Have another place for result */ /* ORDERING */ public static readonly int ORDERED = 48; public static readonly int BACKWARD_SCRAMBLED = 49; /* Allow/avoid certain usages */ public static readonly int ALLOW = 51; /* Allow transposition or workspace */ public static readonly int NONE = 53; /* PACKED_FORMAT (for storing congugate-even finite sequence in real array) */ public static readonly int CCS_FORMAT = 54; /* Complex conjugate-symmetric */ public static readonly int PACK_FORMAT = 55; /* Pack format for real DFT */ public static readonly int PERM_FORMAT = 56; /* Perm format for real DFT */ public static readonly int CCE_FORMAT = 57; /* Complex conjugate-even */ /* Error classes */ public static readonly int NO_ERROR = 0; public static readonly int MEMORY_ERROR = 1; public static readonly int INVALID_CONFIGURATION = 2; public static readonly int INCONSISTENT_CONFIGURATION = 3; public static readonly int MULTITHREADED_ERROR = 4; public static readonly int BAD_DESCRIPTOR = 5; public static readonly int UNIMPLEMENTED = 6; public static readonly int MKL_INTERNAL_ERROR = 7; public static readonly int NUMBER_OF_THREADS_ERROR = 8; public static readonly int ONED_LENGTH_EXCEEDS_INT32 = 9; public static readonly int MAX_MESSAGE_LENGTH = 40; /* Maximum length of error string */ public static readonly int MAX_NAME_LENGTH = 10; /* Maximum length of descriptor name */ public static readonly int VERSION_LENGTH = 198; /* Maximum length of MKL version string */ } /// /// import functions (pinvoke) /// internal sealed class MKLImports { #region pinvoke definitions #if x64 #region 64 bit includes [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_domain_set_num_threads(ref int num, ref int mask); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_domain_get_max_threads(ref int mask); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern void mkl_set_num_threads(int num); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_get_max_threads(); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl)] internal static extern void omp_set_num_threads(int num); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int omp_get_num_threads(); [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern void mkl_set_dynamic(ref int boolean_value); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCreateDescriptor(ref IntPtr pDescriptor, int precision, int domain, int dimCount, int dim1); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCreateDescriptor(ref IntPtr pDescriptor, int precision, int domain, int dimCount, int[] dims); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiFreeDescriptor(ref IntPtr pDescriptor); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCommitDescriptor(IntPtr pDescriptor); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiErrorClass(int status, int ERROR_CLASS); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, int value); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, double value); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, int[] values); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiGetValue(IntPtr pDescriptor, int parameter, ref int value); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiGetValue(IntPtr pDescriptor, int parameter, ref double value); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiComputeForward(IntPtr pDescriptor, IntPtr pArray); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiComputeForward(IntPtr pDescriptor, IntPtr pInArray, IntPtr pOutArray); /** DFTI native DftiComputeForward declaration */ [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)] internal static extern int DftiComputeForward(IntPtr desc, [In] double[] x_in, [Out] double[] x_out); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiComputeBackward(IntPtr pDescriptor, IntPtr pArray); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiComputeBackward(IntPtr pDescriptor, IntPtr pInArray, IntPtr pOutArray); /** DFTI native DftiComputeBackward declaration */ [DllImport("mkl_custom64", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)] internal static extern int DftiComputeBackward(IntPtr desc, [In] double[] x_in, [Out] double[] x_out); [DllImport("mkl_custom64",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern string DftiErrorMessage(int errID); #endregion #else #region 32 bit includes [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_domain_set_num_threads(ref int num, ref int mask); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_domain_get_max_threads(ref int mask); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern void mkl_set_num_threads(int num); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern int mkl_get_max_threads(); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern void omp_set_num_threads(int num); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] internal static extern void mkl_set_dynamic(ref int boolean_value); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCreateDescriptor(ref IntPtr pDescriptor, int precision, int domain, int dimCount, int dim1); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCreateDescriptor(ref IntPtr pDescriptor, int precision, int domain, int dimCount, int[] dims); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiFreeDescriptor(ref IntPtr pDescriptor); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiCommitDescriptor(IntPtr pDescriptor); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiErrorClass(int status, int ERROR_CLASS); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, int value); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, double value); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiSetValue(IntPtr pDescriptor, int parameter, int[] values); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiGetValue(IntPtr pDescriptor, int parameter, ref int value); [DllImport("mkl_custom32",CallingConvention =CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity] public static extern int DftiGetValue(IntPtr pDescriptor, int parameter, ref double value); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int DftiComputeForward(IntPtr pDescriptor, IntPtr pArray); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int DftiComputeForward(IntPtr pDescriptor, IntPtr pInArray, IntPtr pOutArray); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int DftiComputeBackward(IntPtr pDescriptor, IntPtr pArray); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int DftiComputeBackward(IntPtr pDescriptor, IntPtr pInArray, IntPtr pOutArray); [DllImport("mkl_custom32", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern string DftiErrorMessage(int errID); #endregion #endif #endregion } internal sealed class MKLDescriptor : IDisposable { private int[] Stride; private int Precision; private int RealComplex; private bool InPlace; private ILSize Dimension; private int AlongDimensionIndex; private IntPtr Descriptor = IntPtr.Zero; private int Dimensionality; private int LocalLoopIncrement; private int LocalLoopLength; public IntPtr GetDescriptor(int precision, int realComplex, int dimensionality, int dim, ILSize dimension, bool inplace, out int localLoopLength, out int localLoopIncrement) { // DEBUG: remove "false" for descriptor caching! if (Descriptor != IntPtr.Zero && precision == Precision && realComplex == RealComplex && dimensionality == Dimensionality && dimension.IsSameShape(Dimension) && dim == AlongDimensionIndex && inplace == InPlace) { // reuse old descriptor localLoopIncrement = LocalLoopIncrement; localLoopLength = LocalLoopLength; return Descriptor; } else { // must create a new one if (Descriptor != IntPtr.Zero) { MKLImports.DftiFreeDescriptor(ref Descriptor); } IntPtr tmpDescriptor = IntPtr.Zero; int error; if (dimensionality == 1) { #region one dimensional transforms error = MKLImports.DftiCreateDescriptor(ref tmpDescriptor, precision ,realComplex, dimensionality, dimension[dim]); if (error != 0) { throw new ILInvalidOperationException ("error creating descriptor: " + MKLImports.DftiErrorMessage(error)); } // storage,number of subsequent transformations int nrTransGlobal = dimension.NumberOfElements / dimension[dim]; int nrTransPerPass; if (dim == 0) { // MKL does all transf. at once MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.NUMBER_OF_TRANSFORMS, nrTransGlobal); int distances = dimension[0]; MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.INPUT_DISTANCE, distances); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.OUTPUT_DISTANCE, distances); localLoopIncrement = 1; localLoopLength = 1; nrTransPerPass = 1; } else { nrTransPerPass = dimension.SequentialIndexDistance(dim); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.NUMBER_OF_TRANSFORMS, nrTransPerPass); int distances = 1; MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.INPUT_DISTANCE, distances); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.OUTPUT_DISTANCE, distances); localLoopIncrement = dimension.SequentialIndexDistance(dim) * dimension[dim]; localLoopLength = nrTransGlobal / nrTransPerPass; } // spacing between elements if (Stride == null || Stride.Length < 2) { Stride = new int[10]; } Stride[1] = nrTransPerPass; MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.INPUT_STRIDES, Stride); error = MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.OUTPUT_STRIDES, Stride); if (error != 0) { throw new ILInvalidOperationException("error: " + MKLImports.DftiErrorMessage(error)); } #endregion } else { #region multidimensional transforms int[] tmpDims = dimension.ToIntArray(10); error = MKLImports.DftiCreateDescriptor(ref tmpDescriptor, precision ,realComplex, dimensionality, tmpDims); // MKL will handle to do all transforms at once localLoopIncrement = 1; localLoopLength = 1; // how many transformations ? int nrElementsPerPass = dimension.SequentialIndexDistance(dimensionality); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.NUMBER_OF_TRANSFORMS, dimension.NumberOfElements / nrElementsPerPass); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.INPUT_DISTANCE, nrElementsPerPass); MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.OUTPUT_DISTANCE, nrElementsPerPass); // spacing between elements if (Stride == null || Stride.Length < dimensionality + 1) { Stride = new int[dimensionality + 1]; } int[] seqDistances = dimension.GetSequentialIndexDistances(dimensionality); for (int i = dimensionality; i-- > 0; ) { Stride[i + 1] = seqDistances[i]; } //Stride[0] = 0; // should never gotten changed MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.INPUT_STRIDES, Stride); error = MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.OUTPUT_STRIDES, Stride); if (error != 0) { throw new ILInvalidOperationException("error: " + MKLImports.DftiErrorMessage(error)); } #endregion } //// backward scale //if (!forwardTransform) { // MKLImports.DftiSetValue(tmpDescriptor,MKLParameter.BACKWARD_SCALE, __arglist(1.0/Dimension[dim])); //} if (!inplace) { error = MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.PLACEMENT, MKLValues.NOT_INPLACE); //error = MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.REAL_STORAGE, __arglist(MKLValues.REAL_REAL)); error = MKLImports.DftiSetValue(tmpDescriptor, MKLParameter.CONJUGATE_EVEN_STORAGE, MKLValues.COMPLEX_COMPLEX); } error = MKLImports.DftiCommitDescriptor(tmpDescriptor); if (error != 0) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } Precision = precision; RealComplex = realComplex; Dimensionality = dimensionality; Dimension = dimension; AlongDimensionIndex = dim; Descriptor = tmpDescriptor; LocalLoopIncrement = localLoopIncrement; LocalLoopLength = localLoopLength; InPlace = inplace; return Descriptor; } } public string GetDescriptorInfo() { if (Descriptor != IntPtr.Zero) { return GetDescriptorInfo(Descriptor); } else { return "(no descriptor set)"; } } public string GetDescriptorInfo(IntPtr descriptor) { StringBuilder ret = new StringBuilder(); int val = 0; MKLImports.DftiGetValue(descriptor, MKLParameter.PRECISION, ref val); ret.Append("Precision: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.FORWARD_DOMAIN, ref val); ret.Append("ForwDomain: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.DIMENSION, ref val); ret.Append("DIMENSION: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.LENGTHS, ref val); ret.Append("Length: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.PLACEMENT, ref val); ret.Append("PLACEMENT: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.NUMBER_OF_TRANSFORMS, ref val); ret.Append("NUMBER_OF_TRANSFORMS: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.COMPLEX_STORAGE, ref val); ret.Append("COMPLEX_STORAGE: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.CONJUGATE_EVEN_STORAGE, ref val); ret.Append("CONJUGATE_EVEN_STORAGE: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.INPUT_DISTANCE, ref val); ret.Append("INPUT_DISTANCE: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.OUTPUT_DISTANCE, ref val); ret.Append("OUTPUT_DISTANCE: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.INPUT_STRIDES, ref val); ret.Append("INPUT_STRIDES: " + val + " " + Environment.NewLine); MKLImports.DftiGetValue(descriptor, MKLParameter.OUTPUT_STRIDES, ref val); ret.Append("OUTPUT_STRIDES: " + val + " " + Environment.NewLine); return ret.ToString(); } #region IDisposable Members public void Dispose() { lock (this) if (Descriptor != IntPtr.Zero) { Descriptor = IntPtr.Zero; MKLImports.DftiFreeDescriptor(ref Descriptor); } } ~MKLDescriptor () { Dispose(); } #endregion } /// /// Wrapper for FFT interface using MKL 10_03 /// public class ILMKLFFT : IILFFT { public static void Init() { try { // unless the user explicitely configured the number of threads, let omp configure it! if (Settings.MaxNumberThreadsConfigured) { SetNumThreads(Settings.MaxNumberThreads); } } catch (System.IO.FileNotFoundException) {} } public static void SetNumThreads(int numThreads) { int mklfft = MKLValues.MKL_FFT; MKLImports.mkl_domain_set_num_threads(ref numThreads,ref mklfft); } public static int GetMaxThreads() { int mklfft = MKLValues.MKL_FFT; return MKLImports.mkl_domain_get_max_threads(ref mklfft); } private static void SetDynamicThreads(bool dynamic) { int val = dynamic ? 1 : 0; MKLImports.mkl_set_dynamic(ref val); } #region attributes [ThreadStatic] private static int[] s_strides; private static int[] Strides { get { if (s_strides == null) { s_strides = new int[10]; } return s_strides; } } [ThreadStatic] private static MKLDescriptor s_descriptor; private static MKLDescriptor DescriptorCache { get { if (s_descriptor == null) { s_descriptor = new MKLDescriptor(); } return s_descriptor; } } #endregion #region constructor public ILMKLFFT () { Init(); } #endregion #region IILFFT Member - 1-D public ILRetArray< complex > FFTForward1D (ILInArray< double > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< complex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return ILMath.tocomplex(A); // prepare output array ILArray< complex > ret = ILMath.tocomplex(A) ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeForward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } #region HYCALPER AUTO GENERATED CODE public ILRetArray< fcomplex > FFTBackward1D (ILInArray< fcomplex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< fcomplex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return A.C; // prepare output array ILArray< fcomplex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / new fcomplex(A.D[dim],0); return ret; } } public ILRetArray< complex > FFTBackward1D (ILInArray< complex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< complex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return A.C; // prepare output array ILArray< complex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / new complex(A.D[dim],0); return ret; } } public ILRetArray< fcomplex > FFTForward1D (ILInArray< fcomplex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< fcomplex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return A.C; // prepare output array ILArray< fcomplex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeForward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } public ILRetArray< fcomplex > FFTForward1D (ILInArray< float > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< fcomplex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return ILMath.tofcomplex(A); // prepare output array ILArray< fcomplex > ret = ILMath.tofcomplex(A) ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeForward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } public ILRetArray< complex > FFTForward1D (ILInArray< complex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILMath.empty< complex >(A.Size); if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) return A.C; // prepare output array ILArray< complex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE,MKLValues.COMPLEX,1,dim,A.Size,true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { for (int i = 0; i < localLoopLength && error == 0; i ++) error = MKLImports.DftiComputeForward(descriptor, (IntPtr)(retArr + i * localLoopIncrement)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } #endregion HYCALPER AUTO GENERATED CODE public ILRetArray< double > FFTBackwSym1D(ILInArray< complex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILArray< double >.empty(A.Size); if (A.IsScalar || A.Size[dim] == 1) return ILMath.real(A.C); // prepare output array, if we query the memory directly from // memory pool, we prevent from clearing the elements since every // single one will be overwritten by fft anyway int error = 0,inDim = A.Size[dim]; double [] retArr = ILMemoryPool.Pool.New< double >(A.Size.NumberOfElements); ILArray< double > ret = ILMath.array< double >(retArr,A.Size); int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE , MKLValues.REAL, 1, dim, A.S, false, out localLoopLength, out localLoopIncrement); // do the transform(s) unsafe { fixed ( double * retArrP = ret.GetArrayForWrite()) fixed ( complex * pA = A.GetArrayForRead()) { for (int i = 0; i < (localLoopLength * localLoopIncrement) && error == 0; i += localLoopIncrement) error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(pA + i), (IntPtr)(retArrP + i)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret / inDim; } } #region HYCALPER AUTO GENERATED CODE public ILRetArray< float > FFTBackwSym1D(ILInArray< fcomplex > A, int dim) { using (ILScope.Enter(A)) { if (object.Equals(A,null) || dim < 0) throw new ILArgumentException("invalid parameter"); if (A.IsEmpty) return ILArray< float >.empty(A.Size); if (A.IsScalar || A.Size[dim] == 1) return ILMath.real(A.C); // prepare output array, if we query the memory directly from // memory pool, we prevent from clearing the elements since every // single one will be overwritten by fft anyway int error = 0,inDim = A.Size[dim]; float [] retArr = ILMemoryPool.Pool.New< float >(A.Size.NumberOfElements); ILArray< float > ret = ILMath.array< float >(retArr,A.Size); int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE , MKLValues.REAL, 1, dim, A.S, false, out localLoopLength, out localLoopIncrement); // do the transform(s) unsafe { fixed ( float * retArrP = ret.GetArrayForWrite()) fixed ( fcomplex * pA = A.GetArrayForRead()) { for (int i = 0; i < (localLoopLength * localLoopIncrement) && error == 0; i += localLoopIncrement) error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(pA + i), (IntPtr)(retArrP + i)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret / inDim; } } #endregion HYCALPER AUTO GENERATED CODE #endregion #region IILFFT Member - n-D public ILRetArray< complex > FFTForward (ILInArray< double > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< complex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return ILMath.tocomplex(A) ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; if (nDims > 3) return FFTForward(ILMath.tocomplex(A),nDims); // prepare output array ILArray< complex > ret = ILMath.tocomplex(A) ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeForward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } #region HYCALPER AUTO GENERATED CODE public ILRetArray< complex > FFTBackward (ILInArray< complex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< complex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return A.C ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // prepare output array ILArray< complex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeBackward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / new complex(A.D.SequentialIndexDistance(nDims),0); return ret; } } public ILRetArray< fcomplex > FFTBackward (ILInArray< fcomplex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< fcomplex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return A.C ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // prepare output array ILArray< fcomplex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeBackward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / new fcomplex(A.D.SequentialIndexDistance(nDims),0); return ret; } } public ILRetArray< fcomplex > FFTForward (ILInArray< fcomplex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< fcomplex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return A.C ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // prepare output array ILArray< fcomplex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeForward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } public ILRetArray< fcomplex > FFTForward (ILInArray< float > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< fcomplex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return ILMath.tofcomplex(A) ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; if (nDims > 3) return FFTForward(ILMath.tofcomplex(A),nDims); // prepare output array ILArray< fcomplex > ret = ILMath.tofcomplex(A) ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( fcomplex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeForward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } public ILRetArray< complex > FFTForward (ILInArray< complex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILArray< complex > .empty(A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return A.C ; if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // prepare output array ILArray< complex > ret = A.C ; int localLoopLength, localLoopIncrement; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE , MKLValues.COMPLEX, nDims, 0, A.Size, true, out localLoopLength, out localLoopIncrement); int error = 0; // do the transform(s) unsafe { fixed ( complex * retArr = ret.GetArrayForWrite()) { error = MKLImports.DftiComputeForward (descriptor, (IntPtr)retArr); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } return ret; } } #endregion HYCALPER AUTO GENERATED CODE public ILRetArray< double > FFTBackwSym(ILInArray< complex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILMath.empty< double > (A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return ILMath.real(A.C); if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // MKL currently does not handle more than 3 dimensions this way if (nDims > 3) { return ILMath.real(FFTBackward(A,nDims)); } // prepare output array, if we query the memory directly from // memory pool, we prevent from clearing the elements since every // single one will be overwritten by fft anyway double [] retArr = ILMemoryPool.Pool.New< double >(A.Size.NumberOfElements); ILArray< double> ret = ILMath.array< double>(retArr, A.Size); int localLoopIncrement, localLoopLength; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.DOUBLE , MKLValues.REAL,nDims, 0, A.S, false, out localLoopIncrement, out localLoopLength); int error = 0; // do the transform(s) unsafe { fixed ( double * retArrP = retArr) fixed ( complex * inArr = A.GetArrayForRead()) { error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(inArr),(IntPtr)(retArrP)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / A.S.SequentialIndexDistance(nDims); return ret; } } #region HYCALPER AUTO GENERATED CODE public ILRetArray< float > FFTBackwSym(ILInArray< fcomplex > A, int nDims) { using (ILScope.Enter(A)) { if (object.Equals(A, null) || nDims <= 0 ) throw new ILArgumentException("invalid argument!"); if (A.IsEmpty) return ILMath.empty< float > (A.Size); if (A.IsScalar || (A.Size[0] == 1 && nDims == 1)) return ILMath.real(A.C); if (nDims > A.Size.NumberOfDimensions) nDims = A.Size.NumberOfDimensions; // MKL currently does not handle more than 3 dimensions this way if (nDims > 3) { return ILMath.real(FFTBackward(A,nDims)); } // prepare output array, if we query the memory directly from // memory pool, we prevent from clearing the elements since every // single one will be overwritten by fft anyway float [] retArr = ILMemoryPool.Pool.New< float >(A.Size.NumberOfElements); ILArray< float> ret = ILMath.array< float>(retArr, A.Size); int localLoopIncrement, localLoopLength; IntPtr descriptor = DescriptorCache.GetDescriptor( MKLValues.SINGLE , MKLValues.REAL,nDims, 0, A.S, false, out localLoopIncrement, out localLoopLength); int error = 0; // do the transform(s) unsafe { fixed ( float * retArrP = retArr) fixed ( fcomplex * inArr = A.GetArrayForRead()) { error = MKLImports.DftiComputeBackward(descriptor, (IntPtr)(inArr),(IntPtr)(retArrP)); } } if (isMKLError(error)) { throw new ILInvalidOperationException ("error: " + MKLImports.DftiErrorMessage(error)); } ret = ret / A.S.SequentialIndexDistance(nDims); return ret; } } #endregion HYCALPER AUTO GENERATED CODE #endregion #region IILFFT Member - Misc public bool CachePlans { get { return true; } } public void FreePlans() { DescriptorCache.Dispose(); } public bool SpeedyHermitian { get { return true; } } #endregion #region private helper private static bool isMKLError(int error) { // TODO check! only the first 32 bits seem to be relevant for error! //return MKLImports.DftiErrorClass(error, MKLValues.NO_ERROR) != 1; return error != MKLValues.NO_ERROR; } #endregion } }