Ackermann’s function using Dynamic programming
Last Updated :
26 Sep, 2022
Given two non-zero integers M and N, the problem is to compute the result of the Ackermann function based on some particular equations.
Ackermann function is defined as:
Examples:
Input: M = 2, N = 2
Output: 7
Input: M = 2, N = 7
Output: 6141004759
The approach for Ackermann function described in this article, takes a very huge amount of time to compute the value for even small values of (M, N) or in most cases doesn’t result in anything.
Dynamic Programming approach:
Here are the following Ackermann equations that would be used to come up with efficient solution.
A(m, n) = A(m-1, A(m, n-1)) —– (Eq 1)
A(0, n) = n+1 —– (Eq 2)
A(m, 0) = A(m-1, 1) —– (Eq 3)
Let’s assume the value of m = 2 and n = 2
A 2d DP table of size ( (m+1) x (n+1) ) is created for storing the result of each sub-problem.
Following are the steps demonstrated to fill up the table.
- Empty Table – Initial Step
Filled using A ( 0, n ) = n + 1 The very next method is to fill all the base values, by taking the help of equation-2.
In the next step the whole 1st row would be filled,
A ( 1, 0 ) = A ( 0, 1 ) —– (refer Eq (3)) Since A ( 0, 1 ) = 2 Therefore, A ( 1, 0 ) = 2 —–(Eq 4)
A ( 1, 1 ) = A ( 0, A ( 1, 0 ) ) —– refer Eq (1) = A ( 0, 2 ) —– refer Eq (4) = 3 —– refer Eq (2) So, A ( 1, 1 ) = 3 —–(Eq 5)
A ( 1, 2 ) = A ( 0, A ( 1, 1 ) ) —– refer equation (1) = A ( 0, 3 ) —– refer equation (5) = 4 —– refer equation (2) So, A ( 1, 2 ) = 4 —–(Eq 6)
- Fill the table using equations and stored values
Let’s just fill the first column of the last row i.e (2, 0) in the same manner as above, because for the other two columns there are some unsolved values.
A ( 2, 0 ) = A ( 1, 1 ) —– refer equation (3) A ( 1, 1 ) = 3 So, A ( 2, 0 ) = 3 —– (Eq. 7)
Solving for A ( 2, 1 ) and A ( 2, 2 ).
For simplicity the process for solving above functions is divided into two steps,
- In the first one, the problem is identified.
A ( 2, 1 ) = A ( 1, A ( 2, 0 ) ) —– refer equation (1) A ( 2, 0 ) = 3 A ( 2, 1 ) = A ( 1, 3 ) So to compute this value, again use equation (1) A ( 1, 3 ) = A ( 0, A ( 1, 2 ) ) A ( 1, 2 ) = 4 A ( 1, 3 ) = A ( 0, 4 ) —– refer equation(2) = 5 Therefore A ( 2, 1 ) = A ( 1, 3 ) = 5 — (Eq 7)
- In the next one, methodology is described in detail and a generic formula is obtained to be logical while being used in program
Let’s solve A ( 2, 2 ) , with a theory upfront
A ( 2, 2 ) = A ( 1, A ( 2, 1 ) ) —– refer equation (1) A ( 2, 1) = 5 A ( 2, 2 ) = A ( 1, 5 )
To compute A(1, 5) in a generic manner, observe how it reduces itself!
A ( 1, 5 ) = A ( 0, A ( 1, 4 ) ) A ( 1, 4 ) = A( 0, A ( 1, 3 ) ) A ( 1, 3 ) = A ( 0, A ( 1, 2 ) ) A ( 1, 2 ) = 4 Returning back from the function we get, A ( 1, 3 ) = A ( 0, 4 ) = 5 —– refer equation (2) A ( 1, 4 ) = A ( 0, A (1, 3 ) ) = A ( 0, 5 ) = 6 —–Since A ( 1, 3 ) = 5 A ( 1, 5 ) = A ( 0, A ( 1, 4 ) ) = A ( 0, 6 ) = 7 So, A ( 2, 2 ) = 7 ——- (Eq 9)
- Final Table with result of each sub-problem
Below is the implementation of the above approach:
C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;
long long int Ackermann( int m, int n){
vector<vector< long long int >> cache(m + 1, vector< long long int >(n + 1, 0));
for ( int rows = 0 ; rows < m + 1 ; rows++){
for ( int cols = 0 ; cols < n + 1 ; cols++){
if (rows == 0){
cache[rows][cols] = cols + 1;
}
else if (cols == 0)
{
cache[rows][cols] = cache[rows-1][1];
}
else
{
long long int r = rows - 1;
long long int c = cache[rows][cols-1];
long long int ans;
if (r == 0){
ans = c + 1;
} else if (c <= n){
ans = cache[rows-1][cache[rows][cols-1]];
} else {
ans = (c-n)*(r) + cache[r][n];
}
cache[rows][cols] = ans;
}
}
}
return cache[m][n];
}
int main()
{
int m = 2;
int n = 2;
int m1 = 5;
int n1 = 7;
cout << "Ackermann value for m = " << m <<
" and n = " << n << " is -> " <<
Ackermann(m, n) << endl;
cout << "Ackermann value for m = " <<
m1 << " and n = " << n1 << " is -> " <<
Ackermann(m1, n1) << endl;
return 0;
}
|
Java
import java.util.*;
class GFG {
static long Ackermann( int m, int n)
{
ArrayList<ArrayList<Long> > cache
= new ArrayList<ArrayList<Long> >();
for ( int i = 0 ; i <= m; i++) {
cache.add( new ArrayList<Long>());
for ( int j = 0 ; j <= n; j++) {
ArrayList<Long> l1 = cache.get(i);
l1.add(0L);
cache.set(i, l1);
}
}
for ( int rows = 0 ; rows < m + 1 ; rows++) {
for ( int cols = 0 ; cols < n + 1 ; cols++) {
if (rows == 0 ) {
ArrayList<Long> l1 = cache.get(rows);
l1.set(cols, cols + 1L);
cache.set(rows, l1);
}
else if (cols == 0 ) {
ArrayList<Long> l1 = cache.get(rows);
l1.set(cols,
cache.get(rows - 1 ).get( 1 ));
cache.set(rows, l1);
}
else {
long r = rows - 1 ;
long c = cache.get(rows).get(cols - 1 );
long ans;
if (r == 0 ) {
ans = c + 1 ;
}
else if (c <= n) {
ans = cache.get(rows - 1 ).get(
Math.toIntExact(
cache.get(rows).get(
( int )cols - 1 )));
}
else {
ans = (c - n) * (r)
+ cache.get(( int )r).get(n);
}
ArrayList<Long> l1 = cache.get(rows);
l1.set(cols, ans);
cache.set(rows, l1);
}
}
}
return cache.get(m).get(n);
}
public static void main(String[] args)
{
int m = 2 ;
int n = 2 ;
int m1 = 5 ;
int n1 = 7 ;
System.out.println( "Ackermann value for m = " + m
+ " and n = " + n + " is -> "
+ Ackermann(m, n));
System.out.println( "Ackermann value for m = " + m1
+ " and n = " + n1 + " is -> "
+ Ackermann(m1, n1));
}
}
|
Python3
def Ackermann(m, n):
cache = [[ 0 for i in range (n + 1 )] for j in range (m + 1 )]
for rows in range (m + 1 ):
for cols in range (n + 1 ):
if rows = = 0 :
cache[rows][cols] = cols + 1
elif cols = = 0 :
cache[rows][cols] = cache[rows - 1 ][ 1 ]
else :
r = rows - 1
c = cache[rows][cols - 1 ]
if r = = 0 :
ans = c + 1
elif c < = n:
ans = cache[rows - 1 ][cache[rows][cols - 1 ]]
else :
ans = (c - n) * (r) + cache[r][n]
cache[rows][cols] = ans
return cache[m][n]
m = 2
n = 2
m1 = 5
n1 = 7
print ( "Ackermann value for m = " , m,
" and n = " , n, "is -> " ,
Ackermann(m, n))
print ( "Ackermann value for m = " , m1,
" and n = " , n1, "is -> " ,
Ackermann(m1, n1))
|
C#
using System;
using System.Collections.Generic;
class GFG {
static long Ackermann( int m, int n)
{
List<List< long > > cache = new List<List< long > >();
for ( int i = 0; i <= m; i++) {
cache.Add( new List< long >());
for ( int j = 0; j <= n; j++)
cache[i].Add(0);
}
for ( int rows = 0; rows < m + 1; rows++) {
for ( int cols = 0; cols < n + 1; cols++) {
if (rows == 0) {
cache[rows][cols] = cols + 1;
}
else if (cols == 0) {
cache[rows][cols] = cache[rows - 1][1];
}
else {
long r = rows - 1;
long c = cache[rows][cols - 1];
long ans;
if (r == 0) {
ans = c + 1;
}
else if (c <= n) {
ans = cache[rows - 1][(
int )cache[rows][cols - 1]];
}
else {
ans = (c - n) * (r)
+ cache[( int )r][n];
}
cache[rows][cols] = ans;
}
}
}
return cache[m][n];
}
public static void Main( string [] args)
{
int m = 2;
int n = 2;
int m1 = 5;
int n1 = 7;
Console.WriteLine( "Ackermann value for m = " + m
+ " and n = " + n + " is -> "
+ Ackermann(m, n));
Console.WriteLine( "Ackermann value for m = " + m1
+ " and n = " + n1 + " is -> "
+ Ackermann(m1, n1));
}
}
|
Javascript
function Ackermann(m, n)
{
let cache = new Array(m + 1);
for ( var i = 0; i <= m; i++)
cache[i] = new Array(n + 1).fill(0);
for ( var rows = 0 ; rows < m + 1 ; rows++){
for ( var cols = 0 ; cols < n + 1 ; cols++){
if (rows == 0){
cache[rows][cols] = cols + 1;
}
else if (cols == 0)
{
cache[rows][cols] = cache[rows-1][1];
}
else
{
let r = rows - 1;
let c = cache[rows][cols-1];
let ans;
if (r == 0){
ans = c + 1;
} else if (c <= n){
ans = cache[rows-1][cache[rows][cols-1]];
} else {
ans = (c-n)*(r) + cache[r][n];
}
cache[rows][cols] = ans;
}
}
}
return cache[m][n];
}
let m = 2;
let n = 2;
let m1 = 5;
let n1 = 7;
console.log( "Ackermann value for m = " + m +
" and n = " + n + " is -> " +
Ackermann(m, n));
console.log( "Ackermann value for m = " +
m1 + " and n = " + n1 + " is -> " +
Ackermann(m1, n1));
|
Output
Ackermann value for m = 2 and n = 2 is -> 7
Ackermann value for m = 5 and n = 7 is -> 6141004759
Time complexity: O( M * N )
Auxiliary Space: O( M * N )
Share your thoughts in the comments
Please Login to comment...