diff --git a/src/algorithms/math/fast-fourier-transform/__test__/fastFourierTransform.test.js b/src/algorithms/math/fast-fourier-transform/__test__/fastFourierTransform.test.js index b5b89e27..49cda8cc 100644 --- a/src/algorithms/math/fast-fourier-transform/__test__/fastFourierTransform.test.js +++ b/src/algorithms/math/fast-fourier-transform/__test__/fastFourierTransform.test.js @@ -1,5 +1,6 @@ -import ComplexNumber from '../complex'; import fastFourierTransform from '../fastFourierTransform'; +import ComplexNumber from '../../complex-number/ComplexNumber'; + /** * @param {ComplexNumber[]} [seq1] * @param {ComplexNumber[]} [seq2] @@ -20,48 +21,62 @@ function approximatelyEqual(seq1, seq2, eps) { describe('fastFourierTransform', () => { it('should calculate the radix-2 discrete fourier transform after zero padding', () => { const eps = 1e-6; - const in1 = [new ComplexNumber(0, 0)]; - const expOut1 = [new ComplexNumber(0, 0)]; + const in1 = [new ComplexNumber({ real: 0, imaginary: 0 })]; + const expOut1 = [new ComplexNumber({ real: 0, imaginary: 0 })]; const out1 = fastFourierTransform(in1); const invOut1 = fastFourierTransform(out1, true); expect(approximatelyEqual(expOut1, out1, eps)).toBe(true); expect(approximatelyEqual(in1, invOut1, eps)).toBe(true); - const in2 = [new ComplexNumber(1, 2), new ComplexNumber(2, 3), - new ComplexNumber(8, 4)]; - const expOut2 = [new ComplexNumber(11, 9), new ComplexNumber(-10, 0), - new ComplexNumber(7, 3), new ComplexNumber(-4, -4)]; + const in2 = [ + new ComplexNumber({ real: 1, imaginary: 2 }), + new ComplexNumber({ real: 2, imaginary: 3 }), + new ComplexNumber({ real: 8, imaginary: 4 }), + ]; + + const expOut2 = [ + new ComplexNumber({ real: 11, imaginary: 9 }), + new ComplexNumber({ real: -10, imaginary: 0 }), + new ComplexNumber({ real: 7, imaginary: 3 }), + new ComplexNumber({ real: -4, imaginary: -4 }), + ]; const out2 = fastFourierTransform(in2); const invOut2 = fastFourierTransform(out2, true); expect(approximatelyEqual(expOut2, out2, eps)).toBe(true); expect(approximatelyEqual(in2, invOut2, eps)).toBe(true); - const in3 = [new ComplexNumber(-83656.9359385182, 98724.08038374918), - new ComplexNumber(-47537.415125808424, 88441.58381765135), - new ComplexNumber(-24849.657029355192, -72621.79007878687), - new ComplexNumber(31451.27290052717, -21113.301128347346), - new ComplexNumber(13973.90836288876, -73378.36721594246), - new ComplexNumber(14981.520420492234, 63279.524958963884), - new ComplexNumber(-9892.575367044381, -81748.44671677813), - new ComplexNumber(-35933.00356823792, -46153.47157161784), - new ComplexNumber(-22425.008561855735, -86284.24507370662), - new ComplexNumber(-39327.43830818355, 30611.949874562706)]; - const expOut3 = [new ComplexNumber(-203215.3322151, -100242.4827503), - new ComplexNumber(99217.0805705, 270646.9331932), - new ComplexNumber(-305990.9040412, 68224.8435751), - new ComplexNumber(-14135.7758282, 199223.9878095), - new ComplexNumber(-306965.6350922, 26030.1025439), - new ComplexNumber(-76477.6755206, 40781.9078990), - new ComplexNumber(-48409.3099088, 54674.7959662), - new ComplexNumber(-329683.0131713, 164287.7995937), - new ComplexNumber(-50485.2048527, -330375.0546527), - new ComplexNumber(122235.7738708, 91091.6398019), - new ComplexNumber(47625.8850387, 73497.3981523), - new ComplexNumber(-15619.8231136, 80804.8685410), - new ComplexNumber(192234.0276101, 160833.3072355), - new ComplexNumber(-96389.4195635, 393408.4543872), - new ComplexNumber(-173449.0825417, 146875.7724104), - new ComplexNumber(-179002.5662573, 239821.0124341)]; + const in3 = [ + new ComplexNumber({ real: -83656.9359385182, imaginary: 98724.08038374918 }), + new ComplexNumber({ real: -47537.415125808424, imaginary: 88441.58381765135 }), + new ComplexNumber({ real: -24849.657029355192, imaginary: -72621.79007878687 }), + new ComplexNumber({ real: 31451.27290052717, imaginary: -21113.301128347346 }), + new ComplexNumber({ real: 13973.90836288876, imaginary: -73378.36721594246 }), + new ComplexNumber({ real: 14981.520420492234, imaginary: 63279.524958963884 }), + new ComplexNumber({ real: -9892.575367044381, imaginary: -81748.44671677813 }), + new ComplexNumber({ real: -35933.00356823792, imaginary: -46153.47157161784 }), + new ComplexNumber({ real: -22425.008561855735, imaginary: -86284.24507370662 }), + new ComplexNumber({ real: -39327.43830818355, imaginary: 30611.949874562706 }), + ]; + + const expOut3 = [ + new ComplexNumber({ real: -203215.3322151, imaginary: -100242.4827503 }), + new ComplexNumber({ real: 99217.0805705, imaginary: 270646.9331932 }), + new ComplexNumber({ real: -305990.9040412, imaginary: 68224.8435751 }), + new ComplexNumber({ real: -14135.7758282, imaginary: 199223.9878095 }), + new ComplexNumber({ real: -306965.6350922, imaginary: 26030.1025439 }), + new ComplexNumber({ real: -76477.6755206, imaginary: 40781.9078990 }), + new ComplexNumber({ real: -48409.3099088, imaginary: 54674.7959662 }), + new ComplexNumber({ real: -329683.0131713, imaginary: 164287.7995937 }), + new ComplexNumber({ real: -50485.2048527, imaginary: -330375.0546527 }), + new ComplexNumber({ real: 122235.7738708, imaginary: 91091.6398019 }), + new ComplexNumber({ real: 47625.8850387, imaginary: 73497.3981523 }), + new ComplexNumber({ real: -15619.8231136, imaginary: 80804.8685410 }), + new ComplexNumber({ real: 192234.0276101, imaginary: 160833.3072355 }), + new ComplexNumber({ real: -96389.4195635, imaginary: 393408.4543872 }), + new ComplexNumber({ real: -173449.0825417, imaginary: 146875.7724104 }), + new ComplexNumber({ real: -179002.5662573, imaginary: 239821.0124341 }), + ]; + const out3 = fastFourierTransform(in3); const invOut3 = fastFourierTransform(out3, true); expect(approximatelyEqual(expOut3, out3, eps)).toBe(true); diff --git a/src/algorithms/math/fast-fourier-transform/complex.js b/src/algorithms/math/fast-fourier-transform/complex.js deleted file mode 100644 index 7a6279e6..00000000 --- a/src/algorithms/math/fast-fourier-transform/complex.js +++ /dev/null @@ -1,36 +0,0 @@ -export default class ComplexNumber { - /** - * @param {Number} [real] - * @param {Number} [imaginary] - */ - constructor(real, imaginary) { - this.real = real; - this.imaginary = imaginary; - } - - /** - * @param {ComplexNumber} [addend] - * @return {ComplexNumber} - */ - add(addend) { - return new ComplexNumber(this.real + addend.real, this.imaginary + addend.imaginary); - } - - /** - * @param {ComplexNumber} [subtrahend] - * @return {ComplexNumber} - */ - subtract(subtrahend) { - return new ComplexNumber(this.real - subtrahend.real, this.imaginary - subtrahend.imaginary); - } - - /** - * @param {ComplexNumber} [multiplicand] - * @return {ComplexNumber} - */ - multiply(multiplicand) { - const real = this.real * multiplicand.real - this.imaginary * multiplicand.imaginary; - const imaginary = this.real * multiplicand.imaginary + this.imaginary * multiplicand.real; - return new ComplexNumber(real, imaginary); - } -} diff --git a/src/algorithms/math/fast-fourier-transform/fastFourierTransform.js b/src/algorithms/math/fast-fourier-transform/fastFourierTransform.js index 3869d0d9..92e66275 100644 --- a/src/algorithms/math/fast-fourier-transform/fastFourierTransform.js +++ b/src/algorithms/math/fast-fourier-transform/fastFourierTransform.js @@ -1,7 +1,8 @@ -import ComplexNumber from './complex'; +import ComplexNumber from '../complex-number/ComplexNumber'; /** - * Return the no of bits used in the binary representation of input + * Return the no of bits used in the binary representation of input. + * * @param {Number} [input] * @return {Number} */ @@ -14,7 +15,8 @@ function bitLength(input) { } /** - * Returns the number which is the flipped binary representation of input + * Returns the number which is the flipped binary representation of input. + * * @param {Number} [input] * @param {Number} [bitlen] * @return {Number} @@ -29,8 +31,9 @@ function reverseBits(input, bitlen) { } /** - * Returns the radix-2 fast fourier transform of the given array - * Optionally computes the radix-2 inverse fast fourier transform + * Returns the radix-2 fast fourier transform of the given array. + * Optionally computes the radix-2 inverse fast fourier transform. + * * @param {ComplexNumber[]} [inputData] * @param {Boolean} [inverse] * @return {ComplexNumber[]} @@ -39,8 +42,12 @@ export default function fastFourierTransform(inputData, inverse = false) { const bitlen = bitLength(inputData.length - 1); const N = 1 << bitlen; - while (inputData.length < N) { inputData.push(new ComplexNumber(0, 0)); } - + while (inputData.length < N) { + inputData.push(new ComplexNumber({ + real: 0, + imaginary: 0, + })); + } const output = []; for (let i = 0; i < N; i += 1) { output[i] = inputData[reverseBits(i, bitlen)]; } @@ -48,15 +55,22 @@ export default function fastFourierTransform(inputData, inverse = false) { for (let blockLength = 2; blockLength <= N; blockLength *= 2) { let phaseStep; if (inverse) { - phaseStep = new ComplexNumber(Math.cos(2 * Math.PI / blockLength), - -1 * Math.sin(2 * Math.PI / blockLength)); + phaseStep = new ComplexNumber({ + real: Math.cos(2 * Math.PI / blockLength), + imaginary: -1 * Math.sin(2 * Math.PI / blockLength), + }); } else { - phaseStep = new ComplexNumber(Math.cos(2 * Math.PI / blockLength), - Math.sin(2 * Math.PI / blockLength)); + phaseStep = new ComplexNumber({ + real: Math.cos(2 * Math.PI / blockLength), + imaginary: Math.sin(2 * Math.PI / blockLength), + }); } for (let blockStart = 0; blockStart < N; blockStart += blockLength) { - let phase = new ComplexNumber(1, 0); + let phase = new ComplexNumber({ + real: 1, + imaginary: 0, + }); for (let idx = blockStart; idx < blockStart + blockLength / 2; idx += 1) { const upd1 = output[idx].add(output[idx + blockLength / 2].multiply(phase));