Open In App

Fast convolution for 64-bit integers

Last Updated : 13 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Convolution is a mathematical operation used in signal processing, image processing, and other fields to combine two functions in order to produce a third function. It is defined as the integral of the product of two functions, one of which is flipped and shifted over time. It is often represented using the symbol “*” and is useful for filtering, smoothing, and other operations on signals and images.

Fast Convolution:

  • Fast convolution for 64-bit integers in competitive programming and provide an overview of the different algorithms and techniques that are commonly used. 
  • Additionally, it will explore the advantages and limitations of each method, as well as the trade-offs that must be made when choosing a particular approach. So let us move forward and unlock the power of lightning-fast calculations with the ultimate guide to Fast convolution for 64-bit integers in competitive programming.
  • Fast convolution is a technique used to efficiently calculate the convolution of two sequences, a, and b, which is defined as the sum of the products of the corresponding elements of a and b, shifted by different amounts. 

The convolution operation is commonly represented by the symbol ‘*’ and can be represented mathematically as:

c[n] = sum(a[m] * b[n – m]) for m = 0 to n

Steps involved in the implementation of the code:

  • Define the two functions (signal and filter)
  • Flip the filter function.
  • Shift the filter function over time.
  • Calculate the product of the two functions.
  • Integrate the product over time.
  • Plot the result.

Below is the code for the above approach:

C++




// C++ implementation of the above approach
#include <cmath>
#include <iostream>
using namespace std;
 
// Function to calculate the convolution
// of two functions
double convolution(double signal[], double filter[],
                   int size, int size_of_filter)
{
 
    double result = 0;
    for (int i = 0; i < size; i++) {
        int ind = size - i - 1;
        if (ind >= 0 & ind < size_of_filter) // we need to check if filter array does not go out of bounds
                                              //otherwise we take as 0
            result += signal[i] * filter[size - 1 - i];
    }
    return result;
}
 
// Driver code
int main()
{
 
    // Define the signal and filter
    double signal[] = { 1, 2, 3, 4, 5 };
    double filter[] = { 0.1, 0.2, 0.3 };
    int size = sizeof(signal) / sizeof(signal[0]);
    int size_of_filter = sizeof(filter) / sizeof(filter[0]);
 
    // Calculate the convolution
    double conv_result = convolution(signal, filter, size, size_of_filter);
 
    // Print the result
    cout << "Convolution result: " << conv_result << endl;
 
    return 0;
}


Java




import java.util.*;
 
public class Main {
 
    // Function to calculate the convolution
    // of two functions
    public static double convolution(double[] signal, double[] filter, int size, int size_of_filter) {
        double result = 0;
        for (int i = 0; i < size; i++) {
            int ind = size - i - 1;
            if (ind >= 0 && ind < size_of_filter) {
                // we need to check if filter array does not go out of bounds
                // otherwise we take as 0
                result += signal[i] * filter[size - 1 - i];
            }
        }
        return result;
    }
 
    // Driver code
    public static void main(String[] args) {
 
        // Define the signal and filter
        double[] signal = { 1, 2, 3, 4, 5 };
        double[] filter = { 0.1, 0.2, 0.3 };
        int size = signal.length;
        int size_of_filter = filter.length;
 
        // Calculate the convolution
        double conv_result = convolution(signal, filter, size, size_of_filter);
 
        // Print the result
        System.out.println("Convolution result: " + conv_result);
    }
}


Python3




def convolution(signal, filter):
    size = len(signal)
    size_of_filter = len(filter)
 
    result = 0
    for i in range(size):
        ind = size - i - 1
        if ind >= 0 and ind < size_of_filter: # we need to check if filter array does not go out of bounds
            #otherwise we take as 0
            result += signal[i] * filter[size - 1 - i]
    return result
 
# Driver code
if __name__ == '__main__':
 
    # Define the signal and filter
    signal = [1, 2, 3, 4, 5]
    filter = [0.1, 0.2, 0.3]
 
    # Calculate the convolution
    conv_result = convolution(signal, filter)
 
    # Print the result
    print("Convolution result: ", conv_result)


Javascript




function convolution(signal, filter) {
    const size = signal.length;
    const size_of_filter = filter.length;
 
    let result = 0;
    for (let i = 0; i < size; i++) {
        const ind = size - i - 1;
        if (ind >= 0 && ind < size_of_filter) { // we need to check if filter array does not go out of bounds
            //otherwise we take as 0
            result += signal[i] * filter[size - 1 - i];
        }
    }
    return result;
}
 
// Driver code
const signal = [1, 2, 3, 4, 5];
const filter = [0.1, 0.2, 0.3];
 
// Calculate the convolution
const conv_result = convolution(signal, filter);
 
// Print the result
console.log("Convolution result: ", conv_result);


C#




// C# implementation of the above approach
 
using System;
 
public class GFG {
    // Function to calculate the convolution
    // of two functions
    static double Convolution(double[] signal,
                              double[] filter, int size,
                              int size_of_filter)
    {
        double result = 0;
        for (int i = 0; i < size; i++) {
            int ind = size - i - 1;
            if (ind >= 0
                & ind < size_of_filter) // we need to check
                                        // if filter array
                                        // does not go out
                                        // of bounds
                                        // otherwise we take
                                        // as 0
                result += signal[i] * filter[size - 1 - i];
        }
        return result;
    }
 
    // Driver code
    public static void Main()
    {
        // Define the signal and filter
        double[] signal = { 1, 2, 3, 4, 5 };
        double[] filter = { 0.1, 0.2, 0.3 };
        int size = signal.Length;
        int size_of_filter = filter.Length;
 
        // Calculate the convolution
        double conv_result = Convolution(
            signal, filter, size, size_of_filter);
 
        // Print the result
        Console.WriteLine("Convolution result: "
                          + conv_result);
    }
}


Output

Convolution result: 2.2

Time Complexity: O(n).

Space Complexity: O(1) as no extra space has been used.

Popular Algorithms for Fast convolution are:

  • Fast Fourier Transform (FFT) algorithm
  • Karatsuba algorithm

Fast Fourier Transform (FFT) algorithm:

  • This algorithm uses the properties of complex numbers and trigonometric functions to convert the convolution operation into a point-wise multiplication operation in the frequency domain. 
  • This greatly reduces the computational complexity of the operation and makes it possible to perform convolutions of large sequences in a relatively short amount of time. 
  • However, the FFT algorithm can be difficult to implement and may not be suitable for all types of problems.

Karatsuba algorithm:

  • This algorithm is based on a divide-and-conquer approach and is often used to perform the multiplication of large integers. 
  • The Karatsuba algorithm can also be used for convolution by treating the input sequences as two large integers and then applying the multiplication algorithm to the sequences. 
  • The Karatsuba algorithm is relatively simple to implement and is often used as a fallback option when other algorithms are not suitable.

Karatsuba vs FFT algorithm:

  • The Karatsuba algorithm is an efficient algorithm for multiplying large integers. It reduces the number of multiplications required by breaking the integers into smaller chunks and using a recursive approach.
  • FFT (Fast Fourier Transform) is an efficient algorithm for calculating the discrete Fourier transform of a signal. It is widely used in signal processing and other fields to analyze signals and images.
  • In terms of performance, FFT is generally considered to be faster than Karatsuba for large inputs. FFT algorithms take advantage of the symmetry and periodicity of the input signal to reduce the number of calculations required. However, the Karatsuba algorithm is more efficient for small inputs.

Conclusion:

  • Fast convolution is a technique used to efficiently calculate the convolution of two sequences which is a fundamental operation in many areas of computer science, including competitive programming.
  • For large integers, different algorithms such as FFT, Karatsuba, and Toom-Cook can be used, each with its own advantages and limitations. 
  • Additionally, techniques such as modulus operation, sliding window approach, and the use of efficient libraries can be used to optimize performance and reduce computational complexity. 
  • In competitive programming, it’s important to consider the specific requirements of the problem and choose the best combination of algorithms, techniques and optimizations accordingly.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads