This commit is contained in:
Rasmus Munk Larsen 2016-02-06 16:36:56 -08:00
commit 86d6201d7b
15 changed files with 158 additions and 142 deletions

View File

@ -130,7 +130,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime)
{
EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
checkSanity();
checkSanity<Derived>();
}
EIGEN_DEVICE_FUNC
@ -142,7 +142,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
eigen_assert(vecSize >= 0);
eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize);
checkSanity();
checkSanity<Derived>();
}
EIGEN_DEVICE_FUNC
@ -152,7 +152,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
eigen_assert( (dataPtr == 0)
|| ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows)
&& cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)));
checkSanity();
checkSanity<Derived>();
}
#ifdef EIGEN_MAPBASE_PLUGIN
@ -161,14 +161,21 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
protected:
template<typename T>
EIGEN_DEVICE_FUNC
void checkSanity() const
void checkSanity(typename internal::enable_if<(internal::traits<T>::Alignment>0),void*>::type = 0) const
{
#if EIGEN_MAX_ALIGN_BYTES>0
eigen_assert(((size_t(m_data) % EIGEN_PLAIN_ENUM_MAX(1,internal::traits<Derived>::Alignment)) == 0) && "data is not aligned");
eigen_assert(( ((size_t(m_data) % internal::traits<Derived>::Alignment) == 0)
|| (cols() * rows() * innerStride() * sizeof(Scalar)) < internal::traits<Derived>::Alignment ) && "data is not aligned");
#endif
}
template<typename T>
EIGEN_DEVICE_FUNC
void checkSanity(typename internal::enable_if<internal::traits<T>::Alignment==0,void*>::type = 0) const
{}
PointerType m_data;
const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows;
const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols;

View File

@ -59,28 +59,6 @@
#endif
#ifndef EIGEN_HAS_POSIX_MEMALIGN
// See bug 554 (http://eigen.tuxfamily.org/bz/show_bug.cgi?id=554)
// It seems to be unsafe to check _POSIX_ADVISORY_INFO without including unistd.h first.
// Currently, let's include it only on unix systems:
#if EIGEN_OS_UNIX && !(EIGEN_OS_SUN || EIGEN_OS_SOLARIS)
#include <unistd.h>
#if (EIGEN_OS_QNX || (defined _GNU_SOURCE) || EIGEN_COMP_PGI || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
#define EIGEN_HAS_POSIX_MEMALIGN 1
#endif
#endif
#ifndef EIGEN_HAS_POSIX_MEMALIGN
#define EIGEN_HAS_POSIX_MEMALIGN 0
#endif
#endif
#if defined EIGEN_VECTORIZE_SSE || defined EIGEN_VECTORIZE_AVX
#define EIGEN_HAS_MM_MALLOC 1
#else
#define EIGEN_HAS_MM_MALLOC 0
#endif
namespace Eigen {
namespace internal {
@ -122,7 +100,7 @@ inline void handmade_aligned_free(void *ptr)
/** \internal
* \brief Reallocates aligned memory.
* Since we know that our handmade version is based on std::realloc
* Since we know that our handmade version is based on std::malloc
* we can use std::realloc to implement efficient reallocation.
*/
inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t = 0)
@ -141,47 +119,6 @@ inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t =
return aligned;
}
/*****************************************************************************
*** Implementation of generic aligned realloc (when no realloc can be used)***
*****************************************************************************/
EIGEN_DEVICE_FUNC void* aligned_malloc(std::size_t size);
EIGEN_DEVICE_FUNC void aligned_free(void *ptr);
/** \internal
* \brief Reallocates aligned memory.
* Allows reallocation with aligned ptr types. This implementation will
* always create a new memory chunk and copy the old data.
*/
inline void* generic_aligned_realloc(void* ptr, size_t size, size_t old_size)
{
if (ptr==0)
return aligned_malloc(size);
if (size==0)
{
aligned_free(ptr);
return 0;
}
void* newptr = aligned_malloc(size);
if (newptr == 0)
{
#ifdef EIGEN_HAS_ERRNO
errno = ENOMEM; // according to the standard
#endif
return 0;
}
if (ptr != 0)
{
std::memcpy(newptr, ptr, (std::min)(size,old_size));
aligned_free(ptr);
}
return newptr;
}
/*****************************************************************************
*** Implementation of portable aligned versions of malloc/free/realloc ***
*****************************************************************************/
@ -218,16 +155,11 @@ EIGEN_DEVICE_FUNC inline void* aligned_malloc(size_t size)
check_that_malloc_is_allowed();
void *result;
#if EIGEN_DEFAULT_ALIGN_BYTES==0
#if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED
result = std::malloc(size);
#elif EIGEN_MALLOC_ALREADY_ALIGNED
result = std::malloc(size);
#elif EIGEN_HAS_POSIX_MEMALIGN
if(posix_memalign(&result, EIGEN_DEFAULT_ALIGN_BYTES, size)) result = 0;
#elif EIGEN_HAS_MM_MALLOC
result = _mm_malloc(size, EIGEN_DEFAULT_ALIGN_BYTES);
#elif EIGEN_OS_WIN_STRICT
result = _aligned_malloc(size, EIGEN_DEFAULT_ALIGN_BYTES);
#if EIGEN_DEFAULT_ALIGN_BYTES==16
eigen_assert((size<16 || (std::size_t(result)%16)==0) && "System's malloc returned an unaligned pointer. Compile with EIGEN_MALLOC_ALREADY_ALIGNED=0 to fallback to handmade alignd memory allocator.");
#endif
#else
result = handmade_aligned_malloc(size);
#endif
@ -241,48 +173,25 @@ EIGEN_DEVICE_FUNC inline void* aligned_malloc(size_t size)
/** \internal Frees memory allocated with aligned_malloc. */
EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr)
{
#if EIGEN_DEFAULT_ALIGN_BYTES==0
#if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED
std::free(ptr);
#elif EIGEN_MALLOC_ALREADY_ALIGNED
std::free(ptr);
#elif EIGEN_HAS_POSIX_MEMALIGN
std::free(ptr);
#elif EIGEN_HAS_MM_MALLOC
_mm_free(ptr);
#elif EIGEN_OS_WIN_STRICT
_aligned_free(ptr);
#else
handmade_aligned_free(ptr);
#endif
}
/**
* \internal
* \brief Reallocates an aligned block of memory.
* \throws std::bad_alloc on allocation failure
**/
* \internal
* \brief Reallocates an aligned block of memory.
* \throws std::bad_alloc on allocation failure
*/
inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size)
{
EIGEN_UNUSED_VARIABLE(old_size);
void *result;
#if EIGEN_DEFAULT_ALIGN_BYTES==0
#if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED
result = std::realloc(ptr,new_size);
#elif EIGEN_MALLOC_ALREADY_ALIGNED
result = std::realloc(ptr,new_size);
#elif EIGEN_HAS_POSIX_MEMALIGN
result = generic_aligned_realloc(ptr,new_size,old_size);
#elif EIGEN_HAS_MM_MALLOC
// The defined(_mm_free) is just here to verify that this MSVC version
// implements _mm_malloc/_mm_free based on the corresponding _aligned_
// functions. This may not always be the case and we just try to be safe.
#if EIGEN_OS_WIN_STRICT && defined(_mm_free)
result = _aligned_realloc(ptr,new_size,EIGEN_DEFAULT_ALIGN_BYTES);
#else
result = generic_aligned_realloc(ptr,new_size,old_size);
#endif
#elif EIGEN_OS_WIN_STRICT
result = _aligned_realloc(ptr,new_size,EIGEN_DEFAULT_ALIGN_BYTES);
#else
result = handmade_aligned_realloc(ptr,new_size,old_size);
#endif

View File

@ -59,6 +59,8 @@ namespace Eigen {
\ingroup DenseMatrixManipulation_chapter */
/** \addtogroup TutorialMapClass
\ingroup DenseMatrixManipulation_chapter */
/** \addtogroup TutorialReshapeSlicing
\ingroup DenseMatrixManipulation_chapter */
/** \addtogroup TopicAliasing
\ingroup DenseMatrixManipulation_chapter */
/** \addtogroup TopicStorageOrders

View File

@ -87,9 +87,6 @@ run time. However, these assertions do cost time and can thus be turned off.
- \b EIGEN_STACK_ALLOCATION_LIMIT - defines the maximum bytes for a buffer to be allocated on the stack. For internal
temporary buffers, dynamic memory allocation is employed as a fall back. For fixed-size matrices or arrays, exceeding
this threshold raises a compile time assertion. Use 0 to set no limit. Default is 128 KB.
- \b EIGEN_HAS_POSIX_MEMALIGN - defines whether aligned memory allocation can be performed through the \c posix_memalign
function. The availability of \c posix_memalign is automatically checked on most platform, but this option allows to
by-pass %Eigen's built-in rules.
\section TopicPreprocessorDirectivesPlugins Plugins

View File

@ -0,0 +1,65 @@
namespace Eigen {
/** \eigenManualPage TutorialReshapeSlicing Reshape and Slicing
%Eigen does not expose convenient methods to take slices or to reshape a matrix yet.
Nonetheless, such features can easily be emulated using the Map class.
\eigenAutoToc
\section TutorialReshape Reshape
A reshape operation consists in modifying the sizes of a matrix while keeping the same coefficients.
Instead of modifying the input matrix itself, which is not possible for compile-time sizes, the approach consist in creating a different \em view on the storage using class Map.
Here is a typical example creating a 1D linear view of a matrix:
<table class="example">
<tr><th>Example:</th><th>Output:</th></tr>
<tr><td>
\include Tutorial_ReshapeMat2Vec.cpp
</td>
<td>
\verbinclude Tutorial_ReshapeMat2Vec.out
</td></tr></table>
Remark how the storage order of the input matrix modifies the order of the coefficients in the linear view.
Here is another example reshaping a 2x6 matrix to a 6x2 one:
<table class="example">
<tr><th>Example:</th><th>Output:</th></tr>
<tr><td>
\include Tutorial_ReshapeMat2Mat.cpp
</td>
<td>
\verbinclude Tutorial_ReshapeMat2Mat.out
</td></tr></table>
\section TutorialSlicing Slicing
Slicing consists in taking a set of rows, or columns, or elements, uniformly spaced within a matrix.
Again, the class Map allows to easily mimic this feature.
For instance, one can take skip every P elements in a vector:
<table class="example">
<tr><th>Example:</th><th>Output:</th></tr>
<tr><td>
\include Tutorial_SlicingVec.cpp
</td>
<td>
\verbinclude Tutorial_SlicingVec.out
</td></tr></table>
One can olso take one column over three using an adequate outer-stride or inner-stride depending on the actual storage order:
<table class="example">
<tr><th>Example:</th><th>Output:</th></tr>
<tr><td>
\include Tutorial_SlicingCol.cpp
</td>
<td>
\verbinclude Tutorial_SlicingCol.out
</td></tr></table>
*/
}

View File

@ -0,0 +1,6 @@
MatrixXf M1(2,6); // Column-major storage
M1 << 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12;
Map<MatrixXf> M2(M1.data(), 6,2);
cout << "M2:" << endl << M2 << endl;

View File

@ -0,0 +1,11 @@
MatrixXf M1(3,3); // Column-major storage
M1 << 1, 2, 3,
4, 5, 6,
7, 8, 9;
Map<RowVectorXf> v1(M1.data(), M1.size());
cout << "v1:" << endl << v1 << endl;
Matrix<float,Dynamic,Dynamic,RowMajor> M2(M1);
Map<RowVectorXf> v2(M2.data(), M2.size());
cout << "v2:" << endl << v2 << endl;

View File

@ -0,0 +1,11 @@
MatrixXf M1 = MatrixXf::Random(3,8);
cout << "Column major input:" << endl << M1 << "\n";
Map<MatrixXf,0,OuterStride<> > M2(M1.data(), M1.rows(), (M1.cols()+2)/3, OuterStride<>(M1.outerStride()*3));
cout << "1 column over 3:" << endl << M2 << "\n";
typedef Matrix<float,Dynamic,Dynamic,RowMajor> RowMajorMatrixXf;
RowMajorMatrixXf M3(M1);
cout << "Row major input:" << endl << M3 << "\n";
Map<RowMajorMatrixXf,0,Stride<Dynamic,3> > M4(M3.data(), M3.rows(), (M3.cols()+2)/3,
Stride<Dynamic,3>(M3.outerStride(),3));
cout << "1 column over 3:" << endl << M4 << "\n";

View File

@ -0,0 +1,4 @@
RowVectorXf v = RowVectorXf::LinSpaced(20,0,19);
cout << "Input:" << endl << v << endl;
Map<RowVectorXf,0,InnerStride<2> > v2(v.data(), v.size()/2);
cout << "Even:" << v2 << endl;

View File

@ -31,7 +31,7 @@ void check_handmade_aligned_malloc()
void check_aligned_malloc()
{
for(int i = 1; i < 1000; i++)
for(int i = ALIGNMENT; i < 1000; i++)
{
char *p = (char*)internal::aligned_malloc(i);
VERIFY(size_t(p)%ALIGNMENT==0);
@ -43,7 +43,7 @@ void check_aligned_malloc()
void check_aligned_new()
{
for(int i = 1; i < 1000; i++)
for(int i = ALIGNMENT; i < 1000; i++)
{
float *p = internal::aligned_new<float>(i);
VERIFY(size_t(p)%ALIGNMENT==0);
@ -55,7 +55,7 @@ void check_aligned_new()
void check_aligned_stack_alloc()
{
for(int i = 1; i < 400; i++)
for(int i = ALIGNMENT; i < 400; i++)
{
ei_declare_aligned_stack_constructed_variable(float,p,i,0);
VERIFY(size_t(p)%ALIGNMENT==0);

View File

@ -40,7 +40,7 @@ template<typename VectorType> void map_class_vector(const VectorType& m)
VERIFY_IS_EQUAL(ma1, ma3);
VERIFY_IS_EQUAL(ma1, ma4);
#ifdef EIGEN_VECTORIZE
if(internal::packet_traits<Scalar>::Vectorizable)
if(internal::packet_traits<Scalar>::Vectorizable && size>=AlignedMax)
VERIFY_RAISES_ASSERT((Map<VectorType,AlignedMax>(array3unaligned, size)))
#endif

View File

@ -49,8 +49,8 @@ template<typename MatrixType> void zeroSizedMatrix()
if(MatrixType::MaxColsAtCompileTime!=0 && MatrixType::MaxRowsAtCompileTime!=0)
{
Index rows = MatrixType::RowsAtCompileTime==Dynamic ? internal::random<Index>(1,10) : MatrixType::RowsAtCompileTime;
Index cols = MatrixType::ColsAtCompileTime==Dynamic ? internal::random<Index>(1,10) : MatrixType::ColsAtCompileTime;
Index rows = MatrixType::RowsAtCompileTime==Dynamic ? internal::random<Index>(1,10) : Index(MatrixType::RowsAtCompileTime);
Index cols = MatrixType::ColsAtCompileTime==Dynamic ? internal::random<Index>(1,10) : Index(MatrixType::ColsAtCompileTime);
MatrixType m(rows,cols);
zeroReduction(m.template block<0,MatrixType::ColsAtCompileTime>(0,0,0,cols));
zeroReduction(m.template block<MatrixType::RowsAtCompileTime,0>(0,0,rows,0));

View File

@ -206,7 +206,7 @@ struct TensorEvaluator<const TensorFFTOp<FFT, ArgType, FFTResultType, FFTDir>, D
}
for (size_t i = 0; i < m_fft.size(); ++i) {
int dim = m_fft[i];
Index dim = m_fft[i];
eigen_assert(dim >= 0 && dim < NumDims);
Index line_len = m_dimensions[dim];
eigen_assert(line_len >= 1);

View File

@ -117,7 +117,6 @@ if(EIGEN_TEST_CXX11)
ei_add_test(cxx11_tensor_of_const_values "-std=c++0x")
ei_add_test(cxx11_tensor_of_complex "-std=c++0x")
ei_add_test(cxx11_tensor_of_strings "-std=c++0x")
ei_add_test(cxx11_tensor_uint128 "-std=c++0x")
ei_add_test(cxx11_tensor_intdiv "-std=c++0x")
ei_add_test(cxx11_tensor_lvalue "-std=c++0x")
ei_add_test(cxx11_tensor_map "-std=c++0x")
@ -149,6 +148,11 @@ if(EIGEN_TEST_CXX11)
ei_add_test(cxx11_tensor_ifft "-std=c++0x")
ei_add_test(cxx11_tensor_empty "-std=c++0x")
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
# This test requires __uint128_t which is only available on 64bit systems
ei_add_test(cxx11_tensor_uint128 "-std=c++0x")
endif()
endif()
# These tests needs nvcc

View File

@ -14,7 +14,7 @@ using Eigen::Tensor;
template <int DataLayout>
static void test_fft_2D_golden() {
Tensor<float, 2, DataLayout, long> input(2, 3);
Tensor<float, 2, DataLayout> input(2, 3);
input(0, 0) = 1;
input(0, 1) = 2;
input(0, 2) = 3;
@ -22,11 +22,11 @@ static void test_fft_2D_golden() {
input(1, 1) = 5;
input(1, 2) = 6;
array<int, 2> fft;
array<ptrdiff_t, 2> fft;
fft[0] = 0;
fft[1] = 1;
Tensor<std::complex<float>, 2, DataLayout, long> output = input.template fft<Eigen::BothParts, Eigen::FFT_FORWARD>(fft);
Tensor<std::complex<float>, 2, DataLayout> output = input.template fft<Eigen::BothParts, Eigen::FFT_FORWARD>(fft);
std::complex<float> output_golden[6]; // in ColMajor order
output_golden[0] = std::complex<float>(21, 0);
@ -57,24 +57,24 @@ static void test_fft_2D_golden() {
}
static void test_fft_complex_input_golden() {
Tensor<std::complex<float>, 1, ColMajor, long> input(5);
Tensor<std::complex<float>, 1, ColMajor> input(5);
input(0) = std::complex<float>(1, 1);
input(1) = std::complex<float>(2, 2);
input(2) = std::complex<float>(3, 3);
input(3) = std::complex<float>(4, 4);
input(4) = std::complex<float>(5, 5);
array<int, 1> fft;
array<ptrdiff_t, 1> fft;
fft[0] = 0;
Tensor<std::complex<float>, 1, ColMajor, long> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
Tensor<std::complex<float>, 1, ColMajor, long> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
Tensor<std::complex<float>, 1, ColMajor> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
Tensor<std::complex<float>, 1, ColMajor> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor, long> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor, long> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor, long> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor, long> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
VERIFY_IS_EQUAL(forward_output_both_parts.dimension(0), input.dimension(0));
VERIFY_IS_EQUAL(reverse_output_both_parts.dimension(0), input.dimension(0));
@ -114,24 +114,24 @@ static void test_fft_complex_input_golden() {
}
static void test_fft_real_input_golden() {
Tensor<float, 1, ColMajor, long> input(5);
Tensor<float, 1, ColMajor> input(5);
input(0) = 1.0;
input(1) = 2.0;
input(2) = 3.0;
input(3) = 4.0;
input(4) = 5.0;
array<int, 1> fft;
array<ptrdiff_t, 1> fft;
fft[0] = 0;
Tensor<std::complex<float>, 1, ColMajor, long> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
Tensor<std::complex<float>, 1, ColMajor, long> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
Tensor<std::complex<float>, 1, ColMajor> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
Tensor<std::complex<float>, 1, ColMajor> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor, long> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor, long> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor, long> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor, long> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
Tensor<float, 1, ColMajor> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
Tensor<float, 1, ColMajor> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
VERIFY_IS_EQUAL(forward_output_both_parts.dimension(0), input.dimension(0));
VERIFY_IS_EQUAL(reverse_output_both_parts.dimension(0), input.dimension(0));
@ -178,21 +178,21 @@ static void test_fft_real_input_golden() {
template <int DataLayout, typename RealScalar, bool isComplexInput, int FFTResultType, int FFTDirection, int TensorRank>
static void test_fft_real_input_energy() {
Eigen::DSizes<long, TensorRank> dimensions;
int total_size = 1;
Eigen::DSizes<ptrdiff_t, TensorRank> dimensions;
ptrdiff_t total_size = 1;
for (int i = 0; i < TensorRank; ++i) {
dimensions[i] = rand() % 20 + 1;
total_size *= dimensions[i];
}
const DSizes<long, TensorRank> arr = dimensions;
const DSizes<ptrdiff_t, TensorRank> arr = dimensions;
typedef typename internal::conditional<isComplexInput == true, std::complex<RealScalar>, RealScalar>::type InputScalar;
Tensor<InputScalar, TensorRank, DataLayout, long> input;
Tensor<InputScalar, TensorRank, DataLayout> input;
input.resize(arr);
input.setRandom();
array<int, TensorRank> fft;
array<ptrdiff_t, TensorRank> fft;
for (int i = 0; i < TensorRank; ++i) {
fft[i] = i;
}