Open In App

Introduction to Dirichlet convolution

Dirichlet convolution is a mathematical operation that combines two arithmetic functions to create a third function. It is named after the mathematician Peter Gustav Lejeune Dirichlet and is closely related to the concept of convolution in signal processing.

In mathematics, an arithmetic function is a function that takes positive integers as input and returns a number as output. The most well-known example of an arithmetic function is the divisor function, which counts the number of positive divisors a given number has.



The Dirichlet convolution of two arithmetic functions f and g is denoted by (f * g) and is defined as:

(f * g)(n) = ∑f(d) * g(n/d)



where the sum is taken over all positive divisors d of n.

Examples:

One example of a Dirichlet convolution is the convolution of the divisor function with itself, denoted by (φ * φ). This results in the Euler totient function, which is defined as:

φ(n) = ∑φ(d) * φ(n/d)

where φ(n) is the number of positive integers less than n that are relatively prime to n.

Another example of a Dirichlet convolution is the convolution of the divisor function with the function that returns 1 for all input values. This results in the identity function, which is defined as:

id(n) = ∑φ(d) * 1(n/d)

where id(n) is the function that returns n for all input values.

Approaches:

There are several approaches to implementing Dirichlet convolution, depending on the specific requirements of the application. 

One simple approach is to use a brute-force method, which involves iterating over all positive divisors of the input value and summing the results of the arithmetic functions at each divisor. This approach has a time complexity of O(n), where n is the input value.

A more efficient approach is to use a sieve algorithm, which pre-calculates the values of the arithmetic functions for all integers up to a certain maximum value and stores them in an array. The Dirichlet convolution can then be calculated by simply multiplying and summing the values in the array. This approach has a time complexity of O(max), where max is the maximum value for which the arithmetic functions are pre-calculated.

Implementation of the Dirichlet convolution in Python:




// C++ code for the above approach
// This function counts the number of
// positive divisors of a given number
#include<bits/stdc++.h>
using namespace std;
 
// This function calculates the greatest
// common divisor of two numbers
int gcd(int a, int b)
{
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}
 
// This function calculates the Euler
// totient function of a given number
int eulerTotient(int n)
{
    int result = 0;
    for (int i = 1; i <= n; i++)
    {
        // If i is relatively prime to n,
        // increment the result
        if (gcd(i, n) == 1) {
            result++;
      }
}
    return result;
}
 
 
// This function counts the number of
// positive divisors of a given number
int divisorFunction(int n)
{
    int result = 0;
    for (int d = 1; d <= n; d++)
    {
        // If d is a divisor of n,
        // increment the result
        if (n % d == 0) {
            result++;
        }
    }
    return result;
}
 
// This function performs the Dirichlet
// convolution of two arithmetic functions
int dirichletConvolution(int n)
{
    int result = 0;
    for (int d = 1; d <= n; d++)
    {
        // If d is a divisor of n,
        // add f(d) * g(n//d) to the result
        if (n % d == 0) {
        result += divisorFunction(d) * eulerTotient(n / d);
      }
}
    return result;
}
 
int main(){
    for (int i = 1; i <= 10; i++) {
      cout<<"φ(" << i << ") = " << eulerTotient(i)<<endl;
    }
}
 
// This code is contributed by poojaagarwal2.




// Java code for the above approach
// This function counts the number of
// positive divisors of a given number
import java.io.*;
 
class GFG {
 
  // This function counts the number of
  // positive divisors of a given number
  public static int divisorFunction(int n)
  {
    int result = 0;
    for (int d = 1; d <= n; d++)
    {
       
      // If d is a divisor of n,
      // increment the result
      if (n % d == 0) {
        result++;
      }
    }
    return result;
  }
 
  // This function performs the Dirichlet
  // convolution of two arithmetic functions
  public static int dirichletConvolution(int n)
  {
    int result = 0;
    for (int d = 1; d <= n; d++)
    {
       
      // If d is a divisor of n,
      // add f(d) * g(n//d) to the result
      if (n % d == 0) {
        result += divisorFunction(d)
          * eulerTotient(n / d);
      }
    }
    return result;
  }
 
  // This function calculates the greatest
  // common divisor of two numbers
  public static int gcd(int a, int b)
  {
    while (b != 0) {
      int temp = b;
      b = a % b;
      a = temp;
    }
    return a;
  }
 
  // This function calculates the Euler
  // totient function of a given number
  public static int eulerTotient(int n)
  {
    int result = 0;
    for (int i = 1; i <= n; i++)
    {
       
      // If i is relatively prime to n,
      // increment the result
      if (gcd(i, n) == 1) {
        result++;
      }
    }
    return result;
  }
 
  public static void main(String[] args)
  {
    for (int i = 1; i <= 10; i++) {
      System.out.println("φ(" + i
                         + ") = " + eulerTotient(i));
    }
  }
}
 
// This code is contributed by lokesh.




# This function counts the number of
# positive divisors of a given number
 
 
def divisor_function(n):
    result = 0
    for d in range(1, n + 1):
 
        # If d is a divisor of n,
        # increment the result
        if n % d == 0:
            result += 1
    return result
 
# This function performs the Dirichlet
# convolution of two arithmetic functions
 
 
def dirichlet_convolution(f, g, n):
    result = 0
    for d in range(1, n + 1):
 
        # If d is a divisor of n,
        # add f(d) * g(n//d) to the result
        if n % d == 0:
            result += f(d) * g(n//d)
    return result
 
# This function calculates the greatest
# common divisor of two numbers
 
 
def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a
 
# This function calculates the Euler
# totient function of a given number
 
 
def euler_totient(n):
    result = 0
    for i in range(1, n + 1):
 
        # If i is relatively prime to n,
        # increment the result
        if gcd(i, n) == 1:
            result += 1
    return result
 
 
# Print the values of the Euler totient
# function for the integers 1 through 10
for i in range(1, 11):
    print(f"φ({i}) = {euler_totient(i)}")




// C# code for the above approach
// This function counts the number of
// positive divisors of a given number
using System;
public class GFG {
 
  // This function counts the number of
  // positive divisors of a given number
  public static int divisorFunction(int n)
  {
    int result = 0;
    for (int d = 1; d <= n; d++) {
 
      // If d is a divisor of n,
      // increment the result
      if (n % d == 0) {
        result++;
      }
    }
    return result;
  }
 
  // This function performs the Dirichlet
  // convolution of two arithmetic functions
  public static int dirichletConvolution(int n)
  {
    int result = 0;
    for (int d = 1; d <= n; d++) {
 
      // If d is a divisor of n,
      // add f(d) * g(n//d) to the result
      if (n % d == 0) {
        result += divisorFunction(d)
          * eulerTotient(n / d);
      }
    }
    return result;
  }
 
  // This function calculates the greatest
  // common divisor of two numbers
  public static int gcd(int a, int b)
  {
    while (b != 0) {
      int temp = b;
      b = a % b;
      a = temp;
    }
    return a;
  }
 
  // This function calculates the Euler
  // totient function of a given number
  public static int eulerTotient(int n)
  {
    int result = 0;
    for (int i = 1; i <= n; i++) {
 
      // If i is relatively prime to n,
      // increment the result
      if (gcd(i, n) == 1) {
        result++;
      }
    }
    return result;
  }
 
  static public void Main()
  {
 
    // Code
    for (int i = 1; i <= 10; i++) {
      Console.WriteLine("φ(" + i
                        + ") = " + eulerTotient(i));
    }
  }
}
 
/* Note: When you compile this C# program,
         you may notice that 'φ' symbol not
         being printed. That's because of the
         console.
*/
 
// This code is contributed by lokeshmvs21.




<script>
   //JavaScript code for the above approach
   // This function counts the number of
   // positive divisors of a given number
   function divisorFunction(n) {
     let result = 0;
     for (let d = 1; d <= n; d++) {
       // If d is a divisor of n,
       // increment the result
       if (n % d === 0) {
         result++;
       }
     }
     return result;
   }
 
   // This function performs the Dirichlet
   // convolution of two arithmetic functions
   function dirichletConvolution(f, g, n) {
     let result = 0;
     for (let d = 1; d <= n; d++) {
       // If d is a divisor of n,
       // add f(d) * g(n//d) to the result
       if (n % d === 0) {
         result += f(d) * g(Math.floor(n / d));
       }
     }
     return result;
   }
 
   // This function calculates the greatest
   // common divisor of two numbers
   function gcd(a, b) {
     while (b !== 0) {
       [a, b] = [b, a % b];
     }
     return a;
   }
 
   // This function calculates the Euler
   // totient function of a given number
   function eulerTotient(n) {
     let result = 0;
     for (let i = 1; i <= n; i++) {
       // If i is relatively prime to n,
       // increment the result
       if (gcd(i, n) === 1) {
         result++;
       }
     }
     return result;
   }
 
   // Print the values of the Euler totient
   // function for the integers 1 through 10
   for (let i = 1; i <= 10; i++) {
     document.write(`φ(${i}) = ${eulerTotient(i)} <br>`);
   }
 
 
// This code is contributed by Potta Lokesh
 
 </script>

Output
φ(1) = 1
φ(2) = 1
φ(3) = 2
φ(4) = 2
φ(5) = 4
φ(6) = 2
φ(7) = 6
φ(8) = 4
φ(9) = 6
φ(10) = 4

Complexity analysis:

Time Complexity: In terms of complexity analysis, the time complexity of Dirichlet convolution depends on the specific implementation used. As mentioned earlier, the brute-force method has a time complexity of O(n), while the sieve algorithm has a time complexity of O(max)

Auxiliary Space: The space complexity of both approaches is O(n), as the values of the arithmetic functions must be stored for all positive integers up to the input value.

Optimization technique:
An optimization technique that can be used to improve the performance of Dirichlet convolution is memoization, which involves storing the results of the arithmetic functions in a cache so that they can be quickly retrieved when needed. This can greatly reduce the time required to perform the convolution, especially for large input values.


Article Tags :