0

Ok, this is for a homework assignment, so please just try to direct me without giving me the straight-up answer. I'm trying to institute memoization with the Ackermann function (C++). It does not do what I would expect when reaching Ackermann(1,2). Something tells me that I should maybe be trying to institute a map instead of an array for the memoization? Any input is appreciated.

#include <iostream>
using namespace std;

static int ackerMemoization[1000];


int acker(int m, int n)
{
    if (m == 0)
        return n + 1;

    if (n == 0)
        return acker(m - 1, 1);

    if (ackerMemoization[m] != 0)
        return ackerMemoization[m - 1];

    else
    {
        ackerMemoization[m] = acker(m - 1, acker(m, n - 1));
        return ackerMemoization[m];
        //return acker(m - 1, acker(m, n - 1));
    }
}

int main()
{
    for (int i = 0; i < 1000; i++)
    {
        ackerMemoization[i] = 0;
    }

    //cout << "Ackermann(3, 20) = " << acker(3, 20) << endl;
    //cout << "Ackermann(4, 0) = " << acker(4, 0) << endl;
    //cout << "Ackermann(4, 1) = " << acker(4, 1) << endl;


    for (int m = 0; m <= 4; ++m)
    {
        for (int n = 0; n < 20; ++n)
        {
            cout << "Ackermann(" << m << ", " << n << ") = " << acker(m, n) << "\n";

        }
    }


    cin.get();
    return 0;
}

So below is my new approach. But I can't figure out why I can't use memoMap.insert(make_pair(m, n), (acker(m - 1, 1))); from within my acker function??

#include <iostream>
#include <map>
using namespace std;

static map<pair<int, int>, int> memoMap;

int acker(int m, int n)
{
    if (m == 0)
        return n + 1;

    if (n == 0)
    {
        //memoMap.emplace[make_pair(m, n), (acker(m - 1, 1)];
        memoMap.insert(make_pair(m, n), (acker(m - 1, 1)));
        return acker(m - 1, 1);
    }

    else
    {
        return acker(m - 1, acker(m, n - 1));
    }
}

int main()
{

    //static map<pair<int, int>, int> memoMap;

    //cout << "Ackermann(3, 20) = " << acker(3, 20) << endl;
    //cout << "Ackermann(4, 0) = " << acker(4, 0) << endl;
    //cout << "Ackermann(4, 1) = " << acker(4, 1) << endl;

    for (int n = 0; n <= 20; ++n)
    {

        cout << "Ackermann(" << 0 << ", " << n << ") = " << acker(0, n) << endl;
    }

    cout << endl;

    for (int n = 1; n <= 20; ++n)
    {

        cout << "Ackermann(" << 1 << ", " << n << ") = " << acker(1, n) << endl;
    }

    cout << endl;

    for (int n = 2; n <= 20; ++n)
    {

        cout << "Ackermann(" << 2 << ", " << n << ") = " << acker(2, n) << endl;
    }

    cout << endl;

    for (int n = 3; n <= 20; ++n)
    {

        cout << "Ackermann(" << 3 << ", " << n << ") = " << acker(3, n) << endl;
    }

    cout << endl;

    for (int n = 4; n <= 2; ++n)
    {

        cout << "Ackermann(" << 4 << ", " << n << ") = " << acker(4, n) << endl;
    }

    cin.get();
    return 0;
}
davejr72
  • 13
  • 6

2 Answers2

1

Memoization of a function requires remembering if the entire argument tuple has been seen before. Using an array indexed by a single integer won't do that for this problem: There are two arguments! You could use a 2-dimensional array, one dimension for m and the other for n. This is practical for functions that have only small arguments. Therefore the 2d array could be small and still cover cases of interest. You can do some reading and experimentation to determine if Ackerman meets this criterion. In general, though, you'll want to use a map from (m,n) pairs to results. C++ maps are a great data structure to learn about, so I suggest you try them here. I won't provide code unless you're stumped. It's far better to learn how to figure out how to use libraries from documentation and available examples than to be given code that solves your problem.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • 1
    Thank you. I will play with that a bit. The more I look at the code I posted, the more I can see my logic is flawed in more than one area. – davejr72 Feb 11 '18 at 22:49
0

map.insert() would take a pair. The pair should be a pair of a pair of integers (for m,n) and an integer (for the Ack func value).

Thus, it would be as follows:

auto key = make_pair(m, n);
auto value = acker(m-1, 1);
memoMap.insert(make_pair(key, value));

If you are using c++03 or older standard, auto may not work. They should be:

pair<int, int> key = make_pair(m, n);
int  value = acker(m-1, 1);

I think you are on the way. I am wondering why you do not look up the memoMap before calculating non-trivial cases. E.g. acker(m-1, n) might be calculated multiple times. Also, when mn != 0, the code block does not seem to have table recording and/or look up.

Stephen
  • 609
  • 6
  • 12
  • Thank you for the input! I submitted the assignment late and incomplete, but I still want to revisit it this week and make functional for understanding. – davejr72 Feb 13 '18 at 02:08