<commit_before>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !windows,!darwin

// Package fftw wraps the FFTW library to perform Fourier Transforms
// using the "fast" method by <NAME>
package fftw

/*
#cgo LDFLAGS: -lfftw3 -lm

#include "fftw3.h"
*/
import "C"

import (
	"unsafe"

	"github.com/cpmech/gosl/chk"
)

// Plan1d implements the FFTW3 plan structure; i.e. a "plan" to compute direct or inverse 1D FTs
type Plan1d struct {
	p      C.fftw_plan // FFTW "plan" structure
	Xin    []float64   // input: complex pairs len=2*N
	Xout   []float64   // output: complex pairs len=2*N
	realIn bool        // set with real input?
}

// NewPlan1d allocates a new "plan" to compute 1D Fourier Transforms with complex numbers input
//
//   Computes:
//                      N-1         -i 2 π k l / N
//               X[l] =  Σ  x[k] ⋅ e
//                      k=0
//   INPUT:
//
//     data -- is a complex array stored as a real array of length 2*n. [real,imag, real,imag, ...]
//             data may be nil, in this case N must be provided
//
//     N -- half-size of the data array. Use this to allocate input (data) array.
//          data must be non-nil to use N
//
//     inverse -- will perform inverse transform; otherwise will perform direct
//                Note: both transforms are non-normalised;
//                i.e. the user will have to multiply by (1/n) if computing inverse transforms
//
//     inplace -- use data array as output as well, thus data will be overwritten
//
//     measure -- use the FFTW_MEASURE flag for better optimisation analysis (slower initialisation times)
//                Note: using this flag with given "data" as input will cause the allocation
//                of a temporary array and the execution of two copy commands with size len(data)
//
//   NOTE: the user must remember to call Free to deallocate FFTW data
//
func NewPlan1d(data []float64, N int, inverse, inplace, measure bool) (o *Plan1d, err error) {

	// allocate new object and set/allocate input array
	usingData := false
	if len(data) < 2 {
		if N < 2 {
			err = chk.Err("N must be greater than 1 when data==nil or len(data)<2. N=%d is invalid\n", N)
			return
		}
		o = new(Plan1d)
		o.Xin = make([]float64, 2*N)
	} else {
		ldata := len(data)
		if ldata%2 > 0 {
			err = chk.Err("len(data) must be even. %d is invalid\n", ldata)
			return
		}
		N = ldata / 2
		o = new(Plan1d)
		o.Xin = data
		usingData = true
	}

	// set or allocate output array
	if inplace {
		o.Xout = o.Xin
	} else {
		o.Xout = make([]float64, 2*N)
	}

	// set flags
	var sign C.int = C.FFTW_FORWARD
	var flag C.uint = C.FFTW_ESTIMATE
	if inverse {
		sign = C.FFTW_BACKWARD
	}
	if measure {
		flag = C.FFTW_MEASURE
	}

	// the measure flag will change the input; thus a temporary is required if "data" is being used
	var temp []float64
	if usingData && measure {
		temp = make([]float64, len(data))
		copy(temp, data)
	}

	// set FFTW plan
	in := (*C.fftw_complex)(unsafe.Pointer(&o.Xin[0]))
	out := (*C.fftw_complex)(unsafe.Pointer(&o.Xout[0]))
	o.p = C.fftw_plan_dft_1d(C.int(N), in, out, sign, flag)

	// fix data (changed by 'measure')
	if usingData && measure {
		copy(data, temp)
	}
	return
}

// NewPlan1dReal allocates a new "plan" to compute 1D Fourier Transforms with real numbers input
//   INPUT:
//     data -- is a real array of length N and may be nil, in this case N must be non-zero
//   NOTE: (1) see NewPlan1d for further information on the input
//         (2) the user must remember to call Free to deallocate FFTW data
func NewPlan1dReal(data []float64, N int, inverse, measure bool) (o *Plan1d, err error) {

	// allocate new object and set/allocate input array
	usingData := false
	if len(data) < 2 {
		if N < 2 {
			err = chk.Err("N must be greater than 1 when data==nil or len(data)<2. N=%d is invalid\n", N)
			return
		}
		o = new(Plan1d)
		o.Xin = make([]float64, N)
	} else {
		N = len(data)
		o = new(Plan1d)
		o.Xin = data
		usingData = true
	}
	o.realIn = true

	// allocate output array
	o.Xout = make([]float64, 2*(N/2+1)) // ×2 => complex128
<commit_msg>Add TODO check in NewPlan1dReal<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !windows,!darwin

// Package fftw wraps the FFTW library to perform Fourier Transforms
// using the "fast" method by <NAME>
package fftw

/*
#cgo LDFLAGS: -lfftw3 -lm

#include "fftw3.h"
*/
import "C"

import (
	"unsafe"

	"github.com/cpmech/gosl/chk"
)

// Plan1d implements the FFTW3 plan structure; i.e. a "plan" to compute direct or inverse 1D FTs
type Plan1d struct {
	p      C.fftw_plan // FFTW "plan" structure
	Xin    []float64   // input: complex pairs len=2*N
	Xout   []float64   // output: complex pairs len=2*N
	realIn bool        // set with real input?
}

// NewPlan1d allocates a new "plan" to compute 1D Fourier Transforms with complex numbers input
//
//   Computes:
//                      N-1         -i 2 π k l / N
//               X[l] =  Σ  x[k] ⋅ e
//                      k=0
//   INPUT:
//
//     data -- is a complex array stored as a real array of length 2*n. [real,imag, real,imag, ...]
//             data may be nil, in this case N must be provided
//
//     N -- half-size of the data array. Use this to allocate input (data) array.
//          data must be non-nil to use N
//
//     inverse -- will perform inverse transform; otherwise will perform direct
//                Note: both transforms are non-normalised;
//                i.e. the user will have to multiply by (1/n) if computing inverse transforms
//
//     inplace -- use data array as output as well, thus data will be overwritten
//
//     measure -- use the FFTW_MEASURE flag for better optimisation analysis (slower initialisation times)
//                Note: using this flag with given "data" as input will cause the allocation
//                of a temporary array and the execution of two copy commands with size len(data)
//
//   NOTE: the user must remember to call Free to deallocate FFTW data
//
func NewPlan1d(data []float64, N int, inverse, inplace, measure bool) (o *Plan1d, err error) {

	// allocate new object and set/allocate input array
	usingData := false
	if len(data) < 2 {
		if N < 2 {
			err = chk.Err("N must be greater than 1 when data==nil or len(data)<2. N=%d is invalid\n", N)
			return
		}
		o = new(Plan1d)
		o.Xin = make([]float64, 2*N)
	} else {
		ldata := len(data)
		if ldata%2 > 0 {
			err = chk.Err("len(data) must be even. %d is invalid\n", ldata)
			return
		}
		N = ldata / 2
		o = new(Plan1d)
		o.Xin = data
		usingData = true
	}

	// set or allocate output array
	if inplace {
		o.Xout = o.Xin
	} else {
		o.Xout = make([]float64, 2*N)
	}

	// set flags
	var sign C.int = C.FFTW_FORWARD
	var flag C.uint = C.FFTW_ESTIMATE
	if inverse {
		sign = C.FFTW_BACKWARD
	}
	if measure {
		flag = C.FFTW_MEASURE
	}

	// the measure flag will change the input; thus a temporary is required if "data" is being used
	var temp []float64
	if usingData && measure {
		temp = make([]float64, len(data))
		copy(temp, data)
	}

	// set FFTW plan
	in := (*C.fftw_complex)(unsafe.Pointer(&o.Xin[0]))
	out := (*C.fftw_complex)(unsafe.Pointer(&o.Xout[0]))
	o.p = C.fftw_plan_dft_1d(C.int(N), in, out, sign, flag)

	// fix data (changed by 'measure')
	if usingData && measure {
		copy(data, temp)
	}
	return
}

// NewPlan1dReal allocates a new "plan" to compute 1D Fourier Transforms with real numbers input
//   INPUT:
//     data -- is a real array of length N and may be nil, in this case N must be non-zero
//   NOTE: (1) see NewPlan1d for further information on the input
//         (2) the user must remember to call Free to deallocate FFTW data
func NewPlan1dReal(data []float64, N int, inverse, measure bool) (o *Plan1d, err error) {

	if inverse {
		chk.Panic("TODO: need to implement the inverse FFT using NewPlan1dReal")
	}

	// allocate new object and set/allocate input array
	usingData := false
	if len(data) < 2 {
		if N < 2 {
			err = chk.Err("N must be greater than 1 when data==nil or len(data)<2. N=%d is invalid\n", N)
			return
		}
		o = new(Plan1d)
		o.Xin = make([]float64, N)
	} else {
		N = len(data)
		o = new(Plan1d)
		o.Xin = data
		usingData = true
	}
	o.realIn = true

	// allocate output array
	o.Xout = make([]float64, 2*(N/2+1)) // ×2 => complex128

{'fraction_non_alphanumeric': 0.11709491962923853, 'fraction_numerical': 0.017834095975595446, 'mean_word_length': 2.510708401976936, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6911831', 'n_tokens_mistral': 3141, 'n_tokens_neox': 2921, 'n_words': 1109}