"use strict"; /** * @license * Copyright 2018 Google Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ Object.defineProperty(exports, "__esModule", { value: true }); var engine_1 = require("../engine"); var complex_ops_1 = require("../ops/complex_ops"); var operation_1 = require("../ops/operation"); var util_1 = require("../util"); var tensor_ops_1 = require("./tensor_ops"); /** * Fast Fourier transform. * * Computes the 1-dimensional discrete Fourier transform over the inner-most * dimension of input. * * ```js * const real = tf.tensor1d([1, 2, 3]); * const imag = tf.tensor1d([1, 2, 3]); * const x = tf.complex(real, imag); * * x.fft().print(); // tf.spectral.fft(x).print(); * ``` * @param input The complex input to compute an fft over. */ /** * @doc {heading: 'Operations', subheading: 'Spectral', namespace: 'spectral'} */ function fft_(input) { util_1.assert(input.dtype === 'complex64', function () { return "The dtype for tf.spectral.fft() must be complex64 " + ("but got " + input.dtype + "."); }); // Collapse all outer dimensions to a single batch dimension. var innerDimensionSize = input.shape[input.shape.length - 1]; var batch = input.size / innerDimensionSize; var input2D = input.as2D(batch, innerDimensionSize); var ret = engine_1.ENGINE.runKernelFunc(function (backend) { return backend.fft(input2D); }, { input: input }); return ret.reshape(input.shape); } /** * Inverse fast Fourier transform. * * Computes the inverse 1-dimensional discrete Fourier transform over the * inner-most dimension of input. * * ```js * const real = tf.tensor1d([1, 2, 3]); * const imag = tf.tensor1d([1, 2, 3]); * const x = tf.complex(real, imag); * * x.ifft().print(); // tf.spectral.ifft(x).print(); * ``` * @param input The complex input to compute an ifft over. */ /** * @doc {heading: 'Operations', subheading: 'Spectral', namespace: 'spectral'} */ function ifft_(input) { util_1.assert(input.dtype === 'complex64', function () { return "The dtype for tf.spectral.ifft() must be complex64 " + ("but got " + input.dtype + "."); }); // Collapse all outer dimensions to a single batch dimension. var innerDimensionSize = input.shape[input.shape.length - 1]; var batch = input.size / innerDimensionSize; var input2D = input.as2D(batch, innerDimensionSize); var ret = engine_1.ENGINE.runKernelFunc(function (backend) { return backend.ifft(input2D); }, { input: input }); return ret.reshape(input.shape); } /** * Real value input fast Fourier transform. * * Computes the 1-dimensional discrete Fourier transform over the * inner-most dimension of the real input. * * ```js * const real = tf.tensor1d([1, 2, 3]); * * real.rfft().print(); * ``` * @param input The real value input to compute an rfft over. */ /** * @doc {heading: 'Operations', subheading: 'Spectral', namespace: 'spectral'} */ function rfft_(input, fftLength) { util_1.assert(input.dtype === 'float32', function () { return "The dtype for rfft() must be real value but got " + input.dtype; }); var innerDimensionSize = input.shape[input.shape.length - 1]; var batch = input.size / innerDimensionSize; var adjustedInput; if (fftLength != null && fftLength < innerDimensionSize) { // Need to crop var begin = input.shape.map(function (v) { return 0; }); var size = input.shape.map(function (v) { return v; }); size[input.shape.length - 1] = fftLength; adjustedInput = input.slice(begin, size); innerDimensionSize = fftLength; } else if (fftLength != null && fftLength > innerDimensionSize) { // Need to pad with zeros var zerosShape = input.shape.map(function (v) { return v; }); zerosShape[input.shape.length - 1] = fftLength - innerDimensionSize; adjustedInput = input.concat(tensor_ops_1.zeros(zerosShape), input.shape.length - 1); innerDimensionSize = fftLength; } else { adjustedInput = input; } // Complement the input with zero imaginary numbers. var zerosInput = adjustedInput.zerosLike(); var complexInput = complex_ops_1.complex(adjustedInput, zerosInput).as2D(batch, innerDimensionSize); var ret = exports.fft(complexInput); // Exclude complex conjugations. These conjugations are put symmetrically. var half = Math.floor(innerDimensionSize / 2) + 1; var realValues = complex_ops_1.real(ret); var imagValues = complex_ops_1.imag(ret); var realComplexConjugate = realValues.split([half, innerDimensionSize - half], realValues.shape.length - 1); var imagComplexConjugate = imagValues.split([half, innerDimensionSize - half], imagValues.shape.length - 1); var outputShape = adjustedInput.shape.slice(); outputShape[adjustedInput.shape.length - 1] = half; return complex_ops_1.complex(realComplexConjugate[0], imagComplexConjugate[0]) .reshape(outputShape); } /** * Inversed real value input fast Fourier transform. * * Computes the 1-dimensional inversed discrete Fourier transform over the * inner-most dimension of the real input. * * ```js * const real = tf.tensor1d([1, 2, 3]); * const imag = tf.tensor1d([0, 0, 0]); * const x = tf.complex(real, imag); * * x.irfft().print(); * ``` * @param input The real value input to compute an irfft over. */ /** * @doc {heading: 'Operations', subheading: 'Spectral', namespace: 'spectral'} */ function irfft_(input) { var innerDimensionSize = input.shape[input.shape.length - 1]; var batch = input.size / innerDimensionSize; if (innerDimensionSize <= 2) { var complexInput = input.as2D(batch, innerDimensionSize); var ret = exports.ifft(complexInput); return complex_ops_1.real(ret); } else { // The length of unique components of the DFT of a real-valued signal // is 2 * (input_len - 1) var outputShape = [batch, 2 * (innerDimensionSize - 1)]; var realInput = complex_ops_1.real(input).as2D(batch, innerDimensionSize); var imagInput = complex_ops_1.imag(input).as2D(batch, innerDimensionSize); var realConjugate = realInput.slice([0, 1], [batch, innerDimensionSize - 2]).reverse(1); var imagConjugate = imagInput.slice([0, 1], [batch, innerDimensionSize - 2]) .reverse(1) .mul(tensor_ops_1.scalar(-1)); var r = realInput.concat(realConjugate, 1); var i = imagInput.concat(imagConjugate, 1); var complexInput = complex_ops_1.complex(r, i).as2D(outputShape[0], outputShape[1]); var ret = exports.ifft(complexInput); return complex_ops_1.real(ret); } } exports.fft = operation_1.op({ fft_: fft_ }); exports.ifft = operation_1.op({ ifft_: ifft_ }); exports.rfft = operation_1.op({ rfft_: rfft_ }); exports.irfft = operation_1.op({ irfft_: irfft_ }); //# sourceMappingURL=spectral_ops.js.map