blob: 3237770e29d57b23aec6f0b3a92e948a60d8a817 [file] [log] [blame]
// Copyright ©2018 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This is a translation of the FFTPACK rfft functions by
// Paul N Swarztrauber, placed in the public domain at
// http://www.netlib.org/fftpack/.
package fftpack
import (
"math"
"math/cmplx"
)
// Rffti initializes the array work which is used in both Rfftf
// and Rfftb. The prime factorization of n together with a
// tabulation of the trigonometric functions are computed and
// stored in work.
//
// Input parameter:
//
// n The length of the sequence to be transformed.
//
// Output parameters:
//
// work A work array which must be dimensioned at least 2*n.
// The same work array can be used for both Rfftf and Rfftb
// as long as n remains unchanged. different work arrays
// are required for different values of n. The contents of
// work must not be changed between calls of Rfftf or Rfftb.
//
// ifac A work array containing the factors of n. ifac must have
// length of at least 15.
func Rffti(n int, work []float64, ifac []int) {
if len(work) < 2*n {
panic("fourier: short work")
}
if len(ifac) < 15 {
panic("fourier: short ifac")
}
if n == 1 {
return
}
rffti1(n, work[n:2*n], ifac[:15])
}
func rffti1(n int, wa []float64, ifac []int) {
ntryh := [4]int{4, 2, 3, 5}
nl := n
nf := 0
outer:
for j, ntry := 0, 0; ; j++ {
if j < 4 {
ntry = ntryh[j]
} else {
ntry += 2
}
for {
if nl%ntry != 0 {
continue outer
}
ifac[nf+2] = ntry
nl /= ntry
nf++
if ntry == 2 && nf != 1 {
for i := 1; i < nf; i++ {
ib := nf - i + 1
ifac[ib+1] = ifac[ib]
}
ifac[2] = 2
}
if nl == 1 {
break outer
}
}
}
ifac[0] = n
ifac[1] = nf
if nf == 1 {
return
}
argh := 2 * math.Pi / float64(n)
is := 0
l1 := 1
for k1 := 0; k1 < nf-1; k1++ {
ip := ifac[k1+2]
ld := 0
l2 := l1 * ip
ido := n / l2
for j := 0; j < ip-1; j++ {
ld += l1
i := is
fi := 0.0
argld := float64(ld) * argh
for ii := 2; ii < ido; ii += 2 {
fi++
arg := fi * argld
wa[i] = math.Cos(arg)
wa[i+1] = math.Sin(arg)
i += 2
}
is += ido
}
l1 = l2
}
}
// Rfftf computes the Fourier coefficients of a real perodic sequence
// (Fourier analysis). The transform is defined below at output
// parameter r.
//
// Input parameters:
//
// n The length of the array r to be transformed. The method
// is most efficient when n is a product of small primes.
// n may change so long as different work arrays are provided.
//
// r A real array of length n which contains the sequence
// to be transformed.
//
// work a work array which must be dimensioned at least 2*n.
// in the program that calls Rfftf. the work array must be
// initialized by calling subroutine rffti(n,work,ifac) and a
// different work array must be used for each different
// value of n. This initialization does not have to be
// repeated so long as n remains unchanged. Thus subsequent
// transforms can be obtained faster than the first.
// The same work array can be used by Rfftf and Rfftb.
//
// ifac A work array containing the factors of n. ifac must have
// length of at least 15.
//
// Output parameters:
//
// r r[0] = the sum from i=0 to i=n-1 of r[i]
//
// if n is even set l=n/2, if n is odd set l = (n+1)/2
// then for k = 1, ..., l-1
// r[2*k-1] = the sum from i = 0 to i = n-1 of
// r[i]*cos(k*i*2*pi/n)
// r[2*k] = the sum from i = 0 to i = n-1 of
// -r[i]*sin(k*i*2*pi/n)
//
// if n is even
// r[n-1] = the sum from i = 0 to i = n-1 of
// (-1)^i*r[i]
//
// This transform is unnormalized since a call of Rfftf
// followed by a call of Rfftb will multiply the input
// sequence by n.
//
// work contains results which must not be destroyed between
// calls of Rfftf or Rfftb.
// ifac contains results which must not be destroyed between
// calls of Rfftf or Rfftb.
func Rfftf(n int, r, work []float64, ifac []int) {
if len(r) < n {
panic("fourier: short sequence")
}
if len(work) < 2*n {
panic("fourier: short work")
}
if len(ifac) < 15 {
panic("fourier: short ifac")
}
if n == 1 {
return
}
rfftf1(n, r[:n], work[:n], work[n:2*n], ifac[:15])
}
func rfftf1(n int, c, ch, wa []float64, ifac []int) {
nf := ifac[1]
na := true
l2 := n
iw := n - 1
for k1 := 1; k1 <= nf; k1++ {
kh := nf - k1
ip := ifac[kh+2]
l1 := l2 / ip
ido := n / l2
idl1 := ido * l1
iw -= (ip - 1) * ido
na = !na
switch ip {
case 4:
ix2 := iw + ido
ix3 := ix2 + ido
if na {
radf4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:])
} else {
radf4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:])
}
case 2:
if na {
radf2(ido, l1, ch, c, wa[iw:])
} else {
radf2(ido, l1, c, ch, wa[iw:])
}
case 3:
ix2 := iw + ido
if na {
radf3(ido, l1, ch, c, wa[iw:], wa[ix2:])
} else {
radf3(ido, l1, c, ch, wa[iw:], wa[ix2:])
}
case 5:
ix2 := iw + ido
ix3 := ix2 + ido
ix4 := ix3 + ido
if na {
radf5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
} else {
radf5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
}
default:
if ido == 1 {
na = !na
}
if na {
radfg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:])
na = false
} else {
radfg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:])
na = true
}
}
l2 = l1
}
if na {
return
}
for i := 0; i < n; i++ {
c[i] = ch[i]
}
}
func radf2(ido, l1 int, cc, ch, wa1 []float64) {
cc3 := newThreeArray(ido, l1, 2, cc)
ch3 := newThreeArray(ido, 2, l1, ch)
for k := 0; k < l1; k++ {
ch3.set(0, 0, k, cc3.at(0, k, 0)+cc3.at(0, k, 1))
ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 1))
}
if ido < 2 {
return
}
if ido > 2 {
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
t2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+t2)
// This is left as conj(z1)-conj(z2) rather than conj(z1-z2)
// to retain current signed zero behaviour.
ch3.setCmplx(ic-1, 1, k, cmplx.Conj(cc3.atCmplx(i-1, k, 0))-cmplx.Conj(t2))
}
}
if ido%2 == 1 {
return
}
}
for k := 0; k < l1; k++ {
ch3.set(0, 1, k, -cc3.at(ido-1, k, 1))
ch3.set(ido-1, 0, k, cc3.at(ido-1, k, 0))
}
}
func radf3(ido, l1 int, cc, ch, wa1, wa2 []float64) {
const (
taur = -0.5
taui = 0.866025403784439 // sqrt(3)/2
)
cc3 := newThreeArray(ido, l1, 3, cc)
ch3 := newThreeArray(ido, 3, l1, ch)
for k := 0; k < l1; k++ {
cr2 := cc3.at(0, k, 1) + cc3.at(0, k, 2)
ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2)
ch3.set(0, 2, k, taui*(cc3.at(0, k, 2)-cc3.at(0, k, 1)))
ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+taur*cr2)
}
if ido < 2 {
return
}
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
c2 := d2 + d3
ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2)
t2 := cc3.atCmplx(i-1, k, 0) + scale(taur, c2)
t3 := scale(taui, cmplx.Conj(swap(d2-d3)))
ch3.setCmplx(i-1, 2, k, t2+t3)
ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t3))
}
}
}
func radf4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) {
const hsqt2 = math.Sqrt2 / 2
cc3 := newThreeArray(ido, l1, 4, cc)
ch3 := newThreeArray(ido, 4, l1, ch)
for k := 0; k < l1; k++ {
tr1 := cc3.at(0, k, 1) + cc3.at(0, k, 3)
tr2 := cc3.at(0, k, 0) + cc3.at(0, k, 2)
ch3.set(0, 0, k, tr1+tr2)
ch3.set(ido-1, 3, k, tr2-tr1)
ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 2))
ch3.set(0, 2, k, cc3.at(0, k, 3)-cc3.at(0, k, 1))
}
if ido < 2 {
return
}
if ido > 2 {
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
c2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
c3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
c4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3)
t1 := c2 + c4
t2 := cc3.atCmplx(i-1, k, 0) + c3
t3 := cc3.atCmplx(i-1, k, 0) - c3
t4 := cmplx.Conj(c4 - c2)
ch3.setCmplx(i-1, 0, k, t1+t2)
ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t2-t1))
ch3.setCmplx(i-1, 2, k, swap(t4)+t3)
ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t3-swap(t4)))
}
}
if ido%2 == 1 {
return
}
}
for k := 0; k < l1; k++ {
ti1 := -hsqt2 * (cc3.at(ido-1, k, 1) + cc3.at(ido-1, k, 3))
tr1 := hsqt2 * (cc3.at(ido-1, k, 1) - cc3.at(ido-1, k, 3))
ch3.set(ido-1, 0, k, tr1+cc3.at(ido-1, k, 0))
ch3.set(ido-1, 2, k, cc3.at(ido-1, k, 0)-tr1)
ch3.set(0, 1, k, ti1-cc3.at(ido-1, k, 2))
ch3.set(0, 3, k, ti1+cc3.at(ido-1, k, 2))
}
}
func radf5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) {
const (
tr11 = 0.309016994374947
ti11 = 0.951056516295154
tr12 = -0.809016994374947
ti12 = 0.587785252292473
)
cc3 := newThreeArray(ido, l1, 5, cc)
ch3 := newThreeArray(ido, 5, l1, ch)
for k := 0; k < l1; k++ {
cr2 := cc3.at(0, k, 4) + cc3.at(0, k, 1)
cr3 := cc3.at(0, k, 3) + cc3.at(0, k, 2)
ci4 := cc3.at(0, k, 3) - cc3.at(0, k, 2)
ci5 := cc3.at(0, k, 4) - cc3.at(0, k, 1)
ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2+cr3)
ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+tr11*cr2+tr12*cr3)
ch3.set(0, 2, k, ti11*ci5+ti12*ci4)
ch3.set(ido-1, 3, k, cc3.at(0, k, 0)+tr12*cr2+tr11*cr3)
ch3.set(0, 4, k, ti12*ci5-ti11*ci4)
}
if ido < 2 {
return
}
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
d4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3)
d5 := complex(wa4[i-2], -wa4[i-1]) * cc3.atCmplx(i-1, k, 4)
c2 := d2 + d5
c3 := d3 + d4
c4 := cmplx.Conj(swap(d3 - d4))
c5 := cmplx.Conj(swap(d2 - d5))
ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2+c3)
t2 := cc3.atCmplx(i-1, k, 0) + scale(tr11, c2) + scale(tr12, c3)
t3 := cc3.atCmplx(i-1, k, 0) + scale(tr12, c2) + scale(tr11, c3)
t4 := scale(ti12, c5) - scale(ti11, c4)
t5 := scale(ti11, c5) + scale(ti12, c4)
ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t5))
ch3.setCmplx(i-1, 2, k, t2+t5)
ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t3-t4))
ch3.setCmplx(i-1, 4, k, t3+t4)
}
}
}
func radfg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) {
cc3 := newThreeArray(ido, ip, l1, cc)
c13 := newThreeArray(ido, l1, ip, c1)
ch3 := newThreeArray(ido, l1, ip, ch)
c2m := newTwoArray(idl1, ip, c2)
ch2m := newTwoArray(idl1, ip, ch2)
arg := 2 * math.Pi / float64(ip)
dcp := math.Cos(arg)
dsp := math.Sin(arg)
ipph := (ip + 1) / 2
nbd := (ido - 1) / 2
if ido == 1 {
for ik := 0; ik < idl1; ik++ {
c2m.set(ik, 0, ch2m.at(ik, 0))
}
} else {
for ik := 0; ik < idl1; ik++ {
ch2m.set(ik, 0, c2m.at(ik, 0))
}
for j := 1; j < ip; j++ {
for k := 0; k < l1; k++ {
ch3.set(0, k, j, c13.at(0, k, j))
}
}
is := -ido - 1
if nbd > l1 {
for j := 1; j < ip; j++ {
is += ido
for k := 0; k < l1; k++ {
idij := is
for i := 2; i < ido; i += 2 {
idij += 2
ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j))
}
}
}
} else {
for j := 1; j < ip; j++ {
is += ido
idij := is
for i := 2; i < ido; i += 2 {
idij += 2
for k := 0; k < l1; k++ {
ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j))
}
}
}
}
if nbd < l1 {
for j := 1; j < ipph; j++ {
jc := ip - j
for i := 2; i < ido; i += 2 {
for k := 0; k < l1; k++ {
c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))))
}
}
}
} else {
for j := 1; j < ipph; j++ {
jc := ip - j
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))))
}
}
}
}
}
for j := 1; j < ipph; j++ {
jc := ip - j
for k := 0; k < l1; k++ {
c13.set(0, k, j, ch3.at(0, k, j)+ch3.at(0, k, jc))
c13.set(0, k, jc, ch3.at(0, k, jc)-ch3.at(0, k, j))
}
}
ar1 := 1.0
ai1 := 0.0
for l := 1; l < ipph; l++ {
lc := ip - l
ar1h := dcp*ar1 - dsp*ai1
ai1 = dcp*ai1 + dsp*ar1
ar1 = ar1h
for ik := 0; ik < idl1; ik++ {
ch2m.set(ik, l, c2m.at(ik, 0)+ar1*c2m.at(ik, 1))
ch2m.set(ik, lc, ai1*c2m.at(ik, ip-1))
}
dc2 := ar1
ds2 := ai1
ar2 := ar1
ai2 := ai1
for j := 2; j < ipph; j++ {
jc := ip - j
ar2h := dc2*ar2 - ds2*ai2
ai2 = dc2*ai2 + ds2*ar2
ar2 = ar2h
for ik := 0; ik < idl1; ik++ {
ch2m.add(ik, l, ar2*c2m.at(ik, j))
ch2m.add(ik, lc, ai2*c2m.at(ik, jc))
}
}
}
for j := 1; j < ipph; j++ {
for ik := 0; ik < idl1; ik++ {
ch2m.add(ik, 0, c2m.at(ik, j))
}
}
if ido < l1 {
for i := 0; i < ido; i++ {
for k := 0; k < l1; k++ {
cc3.set(i, 0, k, ch3.at(i, k, 0))
}
}
} else {
for k := 0; k < l1; k++ {
for i := 0; i < ido; i++ {
cc3.set(i, 0, k, ch3.at(i, k, 0))
}
}
}
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for k := 0; k < l1; k++ {
cc3.set(ido-1, j2-1, k, ch3.at(0, k, j))
cc3.set(0, j2, k, ch3.at(0, k, jc))
}
}
if ido == 1 {
return
}
if nbd < l1 {
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for i := 2; i < ido; i += 2 {
ic := ido - i
for k := 0; k < l1; k++ {
cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))
}
}
}
return
}
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := ido - i
cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))
}
}
}
}
// Rfftb computes the real perodic sequence from its Fourier
// coefficients (Fourier synthesis). The transform is defined
// below at output parameter r.
//
// Input parameters
//
// n The length of the array r to be transformed. The method
// is most efficient when n is a product of small primes.
// n may change so long as different work arrays are provided.
//
// r A real array of length n which contains the sequence
// to be transformed.
//
// work A work array which must be dimensioned at least 2*n.
// in the program that calls Rfftb. The work array must be
// initialized by calling subroutine rffti(n,work,ifac) and a
// different work array must be used for each different
// value of n. This initialization does not have to be
// repeated so long as n remains unchanged thus subsequent
// transforms can be obtained faster than the first.
// The same work array can be used by Rfftf and Rfftb.
//
// ifac A work array containing the factors of n. ifac must have
// length of at least 15.
//
// output parameters
//
// r for n even and for i = 0, ..., n
// r[i] = r[0]+(-1)^i*r[n-1]
// plus the sum from k=1 to k=n/2-1 of
// 2*r(2*k-1)*cos(k*i*2*pi/n)
// -2*r(2*k)*sin(k*i*2*pi/n)
//
// for n odd and for i = 0, ..., n-1
// r[i] = r[0] plus the sum from k=1 to k=(n-1)/2 of
// 2*r(2*k-1)*cos(k*i*2*pi/n)
// -2*r(2*k)*sin(k*i*2*pi/n)
//
// This transform is unnormalized since a call of Rfftf
// followed by a call of Rfftb will multiply the input
// sequence by n.
//
// work Contains results which must not be destroyed between
// calls of Rfftf or Rfftb.
// ifac Contains results which must not be destroyed between
// calls of Rfftf or Rfftb.
func Rfftb(n int, r, work []float64, ifac []int) {
if len(r) < n {
panic("fourier: short sequence")
}
if len(work) < 2*n {
panic("fourier: short work")
}
if len(ifac) < 15 {
panic("fourier: short ifac")
}
if n == 1 {
return
}
rfftb1(n, r[:n], work[:n], work[n:2*n], ifac[:15])
}
func rfftb1(n int, c, ch, wa []float64, ifac []int) {
nf := ifac[1]
na := false
l1 := 1
iw := 0
for k1 := 1; k1 <= nf; k1++ {
ip := ifac[k1+1]
l2 := ip * l1
ido := n / l2
idl1 := ido * l1
switch ip {
case 4:
ix2 := iw + ido
ix3 := ix2 + ido
if na {
radb4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:])
} else {
radb4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:])
}
na = !na
case 2:
if na {
radb2(ido, l1, ch, c, wa[iw:])
} else {
radb2(ido, l1, c, ch, wa[iw:])
}
na = !na
case 3:
ix2 := iw + ido
if na {
radb3(ido, l1, ch, c, wa[iw:], wa[ix2:])
} else {
radb3(ido, l1, c, ch, wa[iw:], wa[ix2:])
}
na = !na
case 5:
ix2 := iw + ido
ix3 := ix2 + ido
ix4 := ix3 + ido
if na {
radb5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
} else {
radb5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
}
na = !na
default:
if na {
radbg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:])
} else {
radbg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:])
}
if ido == 1 {
na = !na
}
}
l1 = l2
iw += (ip - 1) * ido
}
if na {
for i := 0; i < n; i++ {
c[i] = ch[i]
}
}
}
func radb2(ido, l1 int, cc, ch, wa1 []float64) {
cc3 := newThreeArray(ido, 2, l1, cc)
ch3 := newThreeArray(ido, l1, 2, ch)
for k := 0; k < l1; k++ {
ch3.set(0, k, 0, cc3.at(0, 0, k)+cc3.at(ido-1, 1, k))
ch3.set(0, k, 1, cc3.at(0, 0, k)-cc3.at(ido-1, 1, k))
}
if ido < 2 {
return
}
if ido > 2 {
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
t2 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*t2)
}
}
if ido%2 == 1 {
return
}
}
for k := 0; k < l1; k++ {
ch3.set(ido-1, k, 0, 2*cc3.at(ido-1, 0, k))
ch3.set(ido-1, k, 1, -2*cc3.at(0, 1, k))
}
}
func radb3(ido, l1 int, cc, ch, wa1, wa2 []float64) {
const (
taur = -0.5
taui = 0.866025403784439 // sqrt(3)/2
)
cc3 := newThreeArray(ido, 3, l1, cc)
ch3 := newThreeArray(ido, l1, 3, ch)
for k := 0; k < l1; k++ {
tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
cr2 := cc3.at(0, 0, k) + taur*tr2
ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2)
ci3 := taui * (cc3.at(0, 2, k) + cc3.at(0, 2, k))
ch3.set(0, k, 1, cr2-ci3)
ch3.set(0, k, 2, cr2+ci3)
}
if ido == 1 {
return
}
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
c2 := cc3.atCmplx(i-1, 0, k) + scale(taur, t2)
ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2)
c3 := scale(taui, cc3.atCmplx(i-1, 2, k)-cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
d2 := c2 - cmplx.Conj(swap(c3))
d3 := c2 + cmplx.Conj(swap(c3))
ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2)
ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3)
}
}
}
func radb4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) {
cc3 := newThreeArray(ido, 4, l1, cc)
ch3 := newThreeArray(ido, l1, 4, ch)
for k := 0; k < l1; k++ {
tr1 := cc3.at(0, 0, k) - cc3.at(ido-1, 3, k)
tr2 := cc3.at(0, 0, k) + cc3.at(ido-1, 3, k)
tr3 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
tr4 := cc3.at(0, 2, k) + cc3.at(0, 2, k)
ch3.set(0, k, 0, tr2+tr3)
ch3.set(0, k, 1, tr1-tr4)
ch3.set(0, k, 2, tr2-tr3)
ch3.set(0, k, 3, tr1+tr4)
}
if ido < 2 {
return
}
if ido > 2 {
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
t1 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
t2 := cc3.atCmplx(i-1, 0, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
t3 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
t4 := swap(cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
ch3.setCmplx(i-1, k, 0, t2+t3)
c2 := t1 - cmplx.Conj(t4)
c3 := t2 - t3
c4 := t1 + cmplx.Conj(t4)
ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*c2)
ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*c3)
ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*c4)
}
}
if ido%2 == 1 {
return
}
}
for k := 0; k < l1; k++ {
tr1 := cc3.at(ido-1, 0, k) - cc3.at(ido-1, 2, k)
ti1 := cc3.at(0, 1, k) + cc3.at(0, 3, k)
tr2 := cc3.at(ido-1, 0, k) + cc3.at(ido-1, 2, k)
ti2 := cc3.at(0, 3, k) - cc3.at(0, 1, k)
ch3.set(ido-1, k, 0, tr2+tr2)
ch3.set(ido-1, k, 1, math.Sqrt2*(tr1-ti1))
ch3.set(ido-1, k, 2, ti2+ti2)
ch3.set(ido-1, k, 3, -math.Sqrt2*(tr1+ti1))
}
}
func radb5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) {
const (
tr11 = 0.309016994374947
ti11 = 0.951056516295154
tr12 = -0.809016994374947
ti12 = 0.587785252292473
)
cc3 := newThreeArray(ido, 5, l1, cc)
ch3 := newThreeArray(ido, l1, 5, ch)
for k := 0; k < l1; k++ {
tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
tr3 := cc3.at(ido-1, 3, k) + cc3.at(ido-1, 3, k)
ti4 := cc3.at(0, 4, k) + cc3.at(0, 4, k)
ti5 := cc3.at(0, 2, k) + cc3.at(0, 2, k)
ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2+tr3)
cr2 := cc3.at(0, 0, k) + tr11*tr2 + tr12*tr3
cr3 := cc3.at(0, 0, k) + tr12*tr2 + tr11*tr3
ci4 := ti12*ti5 - ti11*ti4
ci5 := ti11*ti5 + ti12*ti4
ch3.set(0, k, 1, cr2-ci5)
ch3.set(0, k, 2, cr3-ci4)
ch3.set(0, k, 3, cr3+ci4)
ch3.set(0, k, 4, cr2+ci5)
}
if ido == 1 {
return
}
idp2 := ido + 1
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := idp2 - (i + 1)
t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
t3 := cc3.atCmplx(i-1, 4, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
t4 := cc3.atCmplx(i-1, 4, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
t5 := cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2+t3)
c2 := cc3.atCmplx(i-1, 0, k) + scale(tr11, t2) + scale(tr12, t3)
c3 := cc3.atCmplx(i-1, 0, k) + scale(tr12, t2) + scale(tr11, t3)
c4 := scale(ti12, t5) - scale(ti11, t4)
c5 := scale(ti11, t5) + scale(ti12, t4)
d2 := c2 - cmplx.Conj(swap(c5))
d3 := c3 - cmplx.Conj(swap(c4))
d4 := c3 + cmplx.Conj(swap(c4))
d5 := c2 + cmplx.Conj(swap(c5))
ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2)
ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3)
ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*d4)
ch3.setCmplx(i-1, k, 4, complex(wa4[i-2], wa4[i-1])*d5)
}
}
}
func radbg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) {
cc3 := newThreeArray(ido, ip, l1, cc)
c13 := newThreeArray(ido, l1, ip, c1)
ch3 := newThreeArray(ido, l1, ip, ch)
c2m := newTwoArray(idl1, ip, c2)
ch2m := newTwoArray(idl1, ip, ch2)
arg := 2 * math.Pi / float64(ip)
dcp := math.Cos(arg)
dsp := math.Sin(arg)
ipph := (ip + 1) / 2
nbd := (ido - 1) / 2
if ido < l1 {
for i := 0; i < ido; i++ {
for k := 0; k < l1; k++ {
ch3.set(i, k, 0, cc3.at(i, 0, k))
}
}
} else {
for k := 0; k < l1; k++ {
for i := 0; i < ido; i++ {
ch3.set(i, k, 0, cc3.at(i, 0, k))
}
}
}
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for k := 0; k < l1; k++ {
ch3.set(0, k, j, cc3.at(ido-1, j2-1, k)+cc3.at(ido-1, j2-1, k))
ch3.set(0, k, jc, cc3.at(0, j2, k)+cc3.at(0, j2, k))
}
}
if ido != 1 {
if nbd < l1 {
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for i := 2; i < ido; i += 2 {
ic := ido - i
for k := 0; k < l1; k++ {
ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
}
}
}
} else {
for j := 1; j < ipph; j++ {
jc := ip - j
j2 := 2 * j
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ic := ido - i
ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
}
}
}
}
}
ar1 := 1.0
ai1 := 0.0
for l := 1; l < ipph; l++ {
lc := ip - l
ar1h := dcp*ar1 - dsp*ai1
ai1 = dcp*ai1 + dsp*ar1
ar1 = ar1h
for ik := 0; ik < idl1; ik++ {
c2m.set(ik, l, ch2m.at(ik, 0)+ar1*ch2m.at(ik, 1))
c2m.set(ik, lc, ai1*ch2m.at(ik, ip-1))
}
dc2 := ar1
ds2 := ai1
ar2 := ar1
ai2 := ai1
for j := 2; j < ipph; j++ {
jc := ip - j
ar2h := dc2*ar2 - ds2*ai2
ai2 = dc2*ai2 + ds2*ar2
ar2 = ar2h
for ik := 0; ik < idl1; ik++ {
c2m.add(ik, l, ar2*ch2m.at(ik, j))
c2m.add(ik, lc, ai2*ch2m.at(ik, jc))
}
}
}
for j := 1; j < ipph; j++ {
for ik := 0; ik < idl1; ik++ {
ch2m.add(ik, 0, ch2m.at(ik, j))
}
}
for j := 1; j < ipph; j++ {
jc := ip - j
for k := 0; k < l1; k++ {
ch3.set(0, k, j, c13.at(0, k, j)-c13.at(0, k, jc))
ch3.set(0, k, jc, c13.at(0, k, j)+c13.at(0, k, jc))
}
}
if ido != 1 {
if nbd < l1 {
for j := 1; j < ipph; j++ {
jc := ip - j
for i := 2; i < ido; i += 2 {
for k := 0; k < l1; k++ {
ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
}
}
}
} else {
for j := 1; j < ipph; j++ {
jc := ip - j
for k := 0; k < l1; k++ {
for i := 2; i < ido; i += 2 {
ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
}
}
}
}
}
if ido == 1 {
return
}
for ik := 0; ik < idl1; ik++ {
c2m.set(ik, 0, ch2m.at(ik, 0))
}
for j := 1; j < ip; j++ {
for k := 0; k < l1; k++ {
c13.set(0, k, j, ch3.at(0, k, j))
}
}
is := -ido - 1
if nbd > l1 {
for j := 1; j < ip; j++ {
is += ido
for k := 0; k < l1; k++ {
idij := is
for i := 2; i < ido; i += 2 {
idij += 2
c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j))
}
}
}
return
}
for j := 1; j < ip; j++ {
is += ido
idij := is
for i := 2; i < ido; i += 2 {
idij += 2
for k := 0; k < l1; k++ {
c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j))
}
}
}
}