Exemplo n.º 1
0
    def test_is_byte_aligned(self):
        a = empty_aligned(100)
        self.assertTrue(is_byte_aligned(a, get_expected_alignment(None)))

        a = empty_aligned(100, n=16)
        self.assertTrue(is_byte_aligned(a, n=16))

        a = empty_aligned(100, n=5)
        self.assertTrue(is_byte_aligned(a, n=5))

        a = empty_aligned(100, dtype="float32", n=16)[1:]
        self.assertFalse(is_byte_aligned(a, n=16))
        self.assertTrue(is_byte_aligned(a, n=4))
Exemplo n.º 2
0
    def test_is_byte_aligned(self):
        a = empty_aligned(100)
        self.assertTrue(is_byte_aligned(a, get_expected_alignment(None)))

        a = empty_aligned(100, n=16)
        self.assertTrue(is_byte_aligned(a, n=16))

        a = empty_aligned(100, n=5)
        self.assertTrue(is_byte_aligned(a, n=5))

        a = empty_aligned(100, dtype='float32', n=16)[1:]
        self.assertFalse(is_byte_aligned(a, n=16))
        self.assertTrue(is_byte_aligned(a, n=4))
Exemplo n.º 3
0
    def set_data(self, self_array, array, shape, dtype, copy=True, name=None):
        """
        :param self_array: array owned by the current instance
                           (either self.data_in or self.data_out).
        :type: numpy.ndarray
        :param self_array: data to set
        :type: numpy.ndarray
        :type tuple shape: shape of the array
        :param dtype: type of the array
        :type: numpy.dtype
        :param bool copy: should we copy the array
        :param str name: name of the array

        Copies are avoided when possible.
        """
        self.check_array(array, shape, dtype)
        if id(self.refs[name]) == id(array):
            # nothing to do: fft is performed on self.data_in or self.data_out
            arr_to_use = self.refs[name]
        if self.check_alignment and not(pyfftw.is_byte_aligned(array)):
            # If the array is not properly aligned,
            # create a temp. array copy it to self.data_in or self.data_out
            self_array[:] = array[:]
            arr_to_use = self_array
        else:
            # If the array is properly aligned, use it directly
            if copy:
                arr_to_use = np.copy(array)
            else:
                arr_to_use = array
        return arr_to_use
Exemplo n.º 4
0
Arquivo: fftw.py Projeto: vasole/silx
    def check_array(self, array, shape, dtype, copy=True):
        """
        Check that a given array is compatible with the FFTW plans,
        in terms of alignment and data type.

        If the provided array does not meet any of the checks, a new array
        is returned.
        """
        if array.shape != shape:
            raise ValueError("Invalid data shape: expected %s, got %s" %
                (shape, array.shape)
            )
        if array.dtype != dtype:
            raise ValueError("Invalid data type: expected %s, got %s" %
                (dtype, array.dtype)
            )
        if self.check_alignment and not(pyfftw.is_byte_aligned(array)):
            array2 = pyfftw.zeros_aligned(self.shape, dtype=self.dtype_in)
            np.copyto(array2, array)
        else:
            if copy:
                array2 = np.copy(array)
            else:
                array2 = array
        return array2
Exemplo n.º 5
0
    def check_array(self, array, shape, dtype, copy=True):
        """
        Check that a given array is compatible with the FFTW plans,
        in terms of alignment and data type.

        If the provided array does not meet any of the checks, a new array
        is returned.
        """
        if array.shape != shape:
            raise ValueError("Invalid data shape: expected %s, got %s" %
                             (shape, array.shape))
        if array.dtype != dtype:
            raise ValueError("Invalid data type: expected %s, got %s" %
                             (dtype, array.dtype))
        if self.check_alignment and not (pyfftw.is_byte_aligned(array)):
            array2 = pyfftw.zeros_aligned(self.shape, dtype=self.dtype_in)
            np.copyto(array2, array)
        else:
            if copy:
                array2 = np.copy(array)
            else:
                array2 = array
        return array2
Exemplo n.º 6
0
def _Xfftn(a, s, axes, overwrite_input,
        planner_effort, threads, auto_align_input, auto_contiguous,
        avoid_copy, inverse, real, normalise_idft=True, ortho=False):
    '''Generic transform interface for all the transforms. No
    defaults exist. The transform must be specified exactly.
    '''
    a_orig = a
    invreal = inverse and real

    if inverse:
        direction = 'FFTW_BACKWARD'
    else:
        direction = 'FFTW_FORWARD'

    if planner_effort not in _valid_efforts:
        raise ValueError('Invalid planner effort: ', planner_effort)

    s, axes = _cook_nd_args(a, s, axes, invreal)

    input_shape, output_shape = _compute_array_shapes(
            a, s, axes, inverse, real)

    a_is_complex = numpy.iscomplexobj(a)

    # Make the input dtype correct by transforming to an available type
    if a.dtype.char not in _rc_dtype_pairs:
        dtype = _default_dtype
        if a.dtype == numpy.dtype('float16') and '32' in pyfftw._supported_types:
            # convert half-precision to single precision, if available
            dtype = numpy.dtype('float32')

        # warn when losing precision but not when using a higher precision
        if dtype.itemsize < a.dtype.itemsize:
            warnings.warn("Narrowing conversion from %s to %s precision" % (a.dtype, dtype))

        if not real or inverse:
            # It's going to be complex
            dtype = numpy.dtype(_rc_dtype_pairs[dtype.char])

        # finally convert the input array
        a = numpy.asarray(a, dtype=dtype)
    elif not (real and not inverse) and not a_is_complex:
        # We need to make it a complex dtype
        a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

    elif (real and not inverse) and a_is_complex:
        # It should be real
        a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

    # Make the output dtype correct
    if not real:
        output_dtype = a.dtype

    else:
        output_dtype = _rc_dtype_pairs[a.dtype.char]

    if not avoid_copy:
        a_copy = a.copy()

    output_array = pyfftw.empty_aligned(output_shape, output_dtype)

    flags = [planner_effort]

    if not auto_align_input:
        flags.append('FFTW_UNALIGNED')

    if overwrite_input:
        flags.append('FFTW_DESTROY_INPUT')

    if not a.shape == input_shape:

        if avoid_copy:
            raise ValueError('Cannot avoid copy: '
                    'The transform shape is not the same as the array size. '
                    '(from avoid_copy flag)')

        # This means we need to use an _FFTWWrapper object
        # and so need to create slicers.
        update_input_array_slicer, FFTW_array_slicer = (
                _setup_input_slicers(a.shape, input_shape))

        # Also, the input array will be a different shape to the shape of
        # `a`, so we need to create a new array.
        input_array = pyfftw.empty_aligned(input_shape, a.dtype)

        FFTW_object = _FFTWWrapper(input_array, output_array, axes, direction,
                flags, threads, input_array_slicer=update_input_array_slicer,
                FFTW_array_slicer=FFTW_array_slicer,
                normalise_idft=normalise_idft, ortho=ortho)

        # We copy the data back into the internal FFTW object array
        internal_array = FFTW_object.input_array
        internal_array[:] = 0
        internal_array[FFTW_array_slicer] = (
                a_copy[update_input_array_slicer])

    else:
        # Otherwise we can use `a` as-is

        input_array = a

        if auto_contiguous:
            # We only need to create a new array if it's not already
            # contiguous
            if not (a.flags['C_CONTIGUOUS'] or a.flags['F_CONTIGUOUS']):
                if avoid_copy:
                    raise ValueError('Cannot avoid copy: '
                            'The input array is not contiguous and '
                            'auto_contiguous is set. (from avoid_copy flag)')

                input_array = pyfftw.empty_aligned(a.shape, a.dtype)

        if (auto_align_input and not pyfftw.is_byte_aligned(input_array)):

            if avoid_copy:
                raise ValueError('Cannot avoid copy: '
                        'The input array is not aligned and '
                        'auto_align is set. (from avoid_copy flag)')

            input_array = pyfftw.byte_align(input_array)


        FFTW_object = pyfftw.FFTW(input_array, output_array, axes, direction,
                flags, threads, normalise_idft=normalise_idft, ortho=ortho)

        if not avoid_copy:
            # Copy the data back into the (likely) destroyed array
            FFTW_object.input_array[:] = a_copy

    return FFTW_object
Exemplo n.º 7
0
def _Xfftn(a, s, axes, overwrite_input,
           planner_effort, threads, auto_align_input, auto_contiguous,
           avoid_copy, inverse, real, normalise_idft=True, ortho=False,
           real_direction_flag=None):
    '''Generic transform interface for all the transforms. No
    defaults exist. The transform must be specified exactly.

    The argument ``real_direction_flag`` is a slight exception to this
    rule: for backwards compatibility this function defaults to standard
    Fourier transforms (and not the specialized real to real variants).
    If this flag is set to one of the standard real transform types
    (e.g., 'FFTW_RODFT00') then the arguments ``inverse`` and ``real``
    are ignored.
    '''
    a_orig = a
    invreal = inverse and real

    if real_direction_flag is not None:
        direction = real_direction_flag
        real_to_real = True
    elif inverse:
        direction = 'FFTW_BACKWARD'
        real_to_real = False
    else:
        direction = 'FFTW_FORWARD'
        real_to_real = False

    if planner_effort not in _valid_efforts:
        raise ValueError('Invalid planner effort: ', planner_effort)

    s, axes = _cook_nd_args(a, s, axes, invreal)

    input_shape, output_shape = _compute_array_shapes(
            a, s, axes, inverse, real)

    a_is_complex = numpy.iscomplexobj(a)

    # Make the input dtype correct by transforming to an available type
    if real_to_real:
        if a.dtype not in _real_to_real_dtypes:
            a = numpy.asarray(a, dtype=_default_dtype)
    else:
        if a.dtype.char not in _rc_dtype_pairs:
            dtype = _default_dtype
            if a.dtype == numpy.dtype('float16') and '32' in pyfftw._supported_types:
                # convert half-precision to single precision, if available
                dtype = numpy.dtype('float32')

            # warn when losing precision but not when using a higher precision
            if dtype.itemsize < a.dtype.itemsize:
                warnings.warn("Narrowing conversion from %s to %s precision" % (a.dtype, dtype))

            if not real or inverse:
                # It's going to be complex
                dtype = numpy.dtype(_rc_dtype_pairs[dtype.char])

            # finally convert the input array
            a = numpy.asarray(a, dtype=dtype)
        elif not (real and not inverse) and not a_is_complex:
            # We need to make it a complex dtype
            a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

        elif (real and not inverse) and a_is_complex:
            # It should be real
            a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

    # Make the output dtype correct
    if not real: # 'real' implies c2r or r2c; hence 'not real' means r2r or c2c.
        output_dtype = a.dtype

    else:
        output_dtype = _rc_dtype_pairs[a.dtype.char]

    if not avoid_copy:
        a_copy = a.copy()

    output_array = pyfftw.empty_aligned(output_shape, output_dtype)

    flags = [planner_effort]

    if not auto_align_input:
        flags.append('FFTW_UNALIGNED')

    if overwrite_input:
        flags.append('FFTW_DESTROY_INPUT')

    if not a.shape == input_shape:

        if avoid_copy:
            raise ValueError('Cannot avoid copy: '
                    'The transform shape is not the same as the array size. '
                    '(from avoid_copy flag)')

        # This means we need to use an _FFTWWrapper object
        # and so need to create slicers.
        update_input_array_slicer, FFTW_array_slicer = (
                _setup_input_slicers(a.shape, input_shape))

        # Also, the input array will be a different shape to the shape of
        # `a`, so we need to create a new array.
        input_array = pyfftw.empty_aligned(input_shape, a.dtype)

        FFTW_object = _FFTWWrapper(input_array, output_array, axes, direction,
                flags, threads, input_array_slicer=update_input_array_slicer,
                FFTW_array_slicer=FFTW_array_slicer,
                normalise_idft=normalise_idft, ortho=ortho)

        # We copy the data back into the internal FFTW object array
        internal_array = FFTW_object.input_array
        internal_array[:] = 0
        internal_array[FFTW_array_slicer] = (
                a_copy[update_input_array_slicer])

    else:
        # Otherwise we can use `a` as-is

        input_array = a

        if auto_contiguous:
            # We only need to create a new array if it's not already
            # contiguous
            if not (a.flags['C_CONTIGUOUS'] or a.flags['F_CONTIGUOUS']):
                if avoid_copy:
                    raise ValueError('Cannot avoid copy: '
                            'The input array is not contiguous and '
                            'auto_contiguous is set. (from avoid_copy flag)')

                input_array = pyfftw.empty_aligned(a.shape, a.dtype)

        if (auto_align_input and not pyfftw.is_byte_aligned(input_array)):

            if avoid_copy:
                raise ValueError('Cannot avoid copy: '
                        'The input array is not aligned and '
                        'auto_align is set. (from avoid_copy flag)')

            input_array = pyfftw.byte_align(input_array)


        FFTW_object = pyfftw.FFTW(input_array, output_array, axes, direction,
                flags, threads, normalise_idft=normalise_idft, ortho=ortho)

        if not avoid_copy:
            # Copy the data back into the (likely) destroyed array
            FFTW_object.input_array[:] = a_copy

    return FFTW_object
Exemplo n.º 8
0
def _Xfftn(a, s, axes, overwrite_input,
        planner_effort, threads, auto_align_input, auto_contiguous,
        avoid_copy, inverse, real):
    '''Generic transform interface for all the transforms. No
    defaults exist. The transform must be specified exactly.
    '''
    a_orig = a
    invreal = inverse and real

    if inverse:
        direction = 'FFTW_BACKWARD'
    else:
        direction = 'FFTW_FORWARD'

    if planner_effort not in _valid_efforts:
        raise ValueError('Invalid planner effort: ', planner_effort)

    s, axes = _cook_nd_args(a, s, axes, invreal)

    input_shape, output_shape = _compute_array_shapes(
            a, s, axes, inverse, real)

    a_is_complex = numpy.iscomplexobj(a)

    # Make the input dtype correct
    if a.dtype.char not in _rc_dtype_pairs:
        if a.dtype == numpy.dtype('float16'):
            # convert half-precision to single precision rather than double
            if not real or inverse:
                a = numpy.asarray(
                    a, dtype=_rc_dtype_pairs[numpy.dtype('float32').char])
            else:
                a = numpy.asarray(a, dtype=numpy.dtype('float32').char)
        else:
            # We make it the default dtype
            if not real or inverse:
                # It's going to be complex
                a = numpy.asarray(
                    a, dtype=_rc_dtype_pairs[_default_dtype.char])
            else:
                a = numpy.asarray(a, dtype=_default_dtype)

    elif not (real and not inverse) and not a_is_complex:
        # We need to make it a complex dtype
        a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

    elif (real and not inverse) and a_is_complex:
        # It should be real
        a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])

    # Make the output dtype correct
    if not real:
        output_dtype = a.dtype

    else:
        output_dtype = _rc_dtype_pairs[a.dtype.char]

    if not avoid_copy:
        a_copy = a.copy()

    output_array = pyfftw.empty_aligned(output_shape, output_dtype)

    flags = [planner_effort]

    if not auto_align_input:
        flags.append('FFTW_UNALIGNED')

    if overwrite_input:
        flags.append('FFTW_DESTROY_INPUT')

    if not a.shape == input_shape:

        if avoid_copy:
            raise ValueError('Cannot avoid copy: '
                    'The transform shape is not the same as the array size. '
                    '(from avoid_copy flag)')

        # This means we need to use an _FFTWWrapper object
        # and so need to create slicers.
        update_input_array_slicer, FFTW_array_slicer = (
                _setup_input_slicers(a.shape, input_shape))

        # Also, the input array will be a different shape to the shape of
        # `a`, so we need to create a new array.
        input_array = pyfftw.empty_aligned(input_shape, a.dtype)

        FFTW_object = _FFTWWrapper(input_array, output_array, axes, direction,
                flags, threads, input_array_slicer=update_input_array_slicer,
                FFTW_array_slicer=FFTW_array_slicer)

        # We copy the data back into the internal FFTW object array
        internal_array = FFTW_object.input_array
        internal_array[:] = 0
        internal_array[FFTW_array_slicer] = (
                a_copy[update_input_array_slicer])

    else:
        # Otherwise we can use `a` as-is

        input_array = a

        if auto_contiguous:
            # We only need to create a new array if it's not already
            # contiguous
            if not (a.flags['C_CONTIGUOUS'] or a.flags['F_CONTIGUOUS']):
                if avoid_copy:
                    raise ValueError('Cannot avoid copy: '
                            'The input array is not contiguous and '
                            'auto_contiguous is set. (from avoid_copy flag)')

                input_array = pyfftw.empty_aligned(a.shape, a.dtype)

        if (auto_align_input and not pyfftw.is_byte_aligned(input_array)):

            if avoid_copy:
                raise ValueError('Cannot avoid copy: '
                        'The input array is not aligned and '
                        'auto_align is set. (from avoid_copy flag)')

            input_array = pyfftw.byte_align(input_array)


        FFTW_object = pyfftw.FFTW(input_array, output_array, axes, direction,
                flags, threads)

        if not avoid_copy:
            # Copy the data back into the (likely) destroyed array
            FFTW_object.input_array[:] = a_copy

    return FFTW_object
Exemplo n.º 9
0
    def test_differing_aligned_arrays_update(self):
        '''Test to see if the alignment code is working as expected
        '''

        # Start by creating arrays that are only on various byte
        # alignments (4, 16 and 32)
        _input_array = empty_aligned(len(self.input_array.ravel())*2+5,
                                     dtype='float32', n=32)
        _output_array = empty_aligned(len(self.output_array.ravel())*2+5,
                                      dtype='float32', n=32)

        _input_array[:] = 0
        _output_array[:] = 0

        input_array_4 = (
                numpy.frombuffer(_input_array[1:-4].data, dtype='complex64')
                .reshape(self.input_array.shape))
        output_array_4 = (
                numpy.frombuffer(_output_array[1:-4].data, dtype='complex64')
                .reshape(self.output_array.shape))

        input_array_16 = (
                numpy.frombuffer(_input_array[4:-1].data, dtype='complex64')
                .reshape(self.input_array.shape))
        output_array_16 = (
                numpy.frombuffer(_output_array[4:-1].data, dtype='complex64')
                .reshape(self.output_array.shape))

        input_array_32 = (
                numpy.frombuffer(_input_array[:-5].data, dtype='complex64')
                .reshape(self.input_array.shape))
        output_array_32 = (
                numpy.frombuffer(_output_array[:-5].data, dtype='complex64')
                .reshape(self.output_array.shape))

        input_arrays = {4: input_array_4,
                16: input_array_16,
                32: input_array_32}

        output_arrays = {4: output_array_4,
                16: output_array_16,
                32: output_array_32}

        alignments = (4, 16, 32)

        # Test the arrays are aligned on 4 bytes...
        self.assertTrue(is_byte_aligned(input_arrays[4], n=4))
        self.assertTrue(is_byte_aligned(output_arrays[4], n=4))

        # ...and on 16...
        self.assertFalse(is_byte_aligned(input_arrays[4], n=16))
        self.assertFalse(is_byte_aligned(output_arrays[4], n=16))
        self.assertTrue(is_byte_aligned(input_arrays[16], n=16))
        self.assertTrue(is_byte_aligned(output_arrays[16], n=16))

        # ...and on 32...
        self.assertFalse(is_byte_aligned(input_arrays[16], n=32))
        self.assertFalse(is_byte_aligned(output_arrays[16], n=32))
        self.assertTrue(is_byte_aligned(input_arrays[32], n=32))
        self.assertTrue(is_byte_aligned(output_arrays[32], n=32))

        if len(pyfftw.pyfftw._valid_simd_alignments) > 0:
            max_align = pyfftw.pyfftw._valid_simd_alignments[0]
        else:
            max_align = simd_alignment

        for in_align in alignments:
            for out_align in alignments:
                expected_align = min(in_align, out_align, max_align)
                fft = FFTW(input_arrays[in_align], output_arrays[out_align])

                self.assertTrue(fft.input_alignment == expected_align)
                self.assertTrue(fft.output_alignment == expected_align)

                for update_align in alignments:

                    if update_align < expected_align:
                        # This should fail (not aligned properly)
                        self.assertRaisesRegex(ValueError,
                                'Invalid input alignment',
                                fft.update_arrays,
                                input_arrays[update_align],
                                output_arrays[out_align])

                        self.assertRaisesRegex(ValueError,
                                'Invalid output alignment',
                                fft.update_arrays,
                                input_arrays[in_align],
                                output_arrays[update_align])

                    else:
                        # This should work (and not segfault!)
                        fft.update_arrays(input_arrays[update_align],
                                output_arrays[out_align])
                        fft.update_arrays(input_arrays[in_align],
                                output_arrays[update_align])
                        fft.execute()