-1

I am trying to make a table data structure in C++. Currently I have written the following code :



map<array<int, 3>, array<int, 6>> q_table;

void qtable(){
    for (int i =-SIZE; i<SIZE; i++){ //SIZE is a constant say 10
        for (int j =-SIZE; j<SIZE; j++){
            for (int k =-SIZE; k<SIZE; k++){
                
                q_table[{i,j,k}][0] = (rand() % 5)+1; //Initializing with random numbers
                q_table[{i,j,k}][1] =  (rand() % 5)+1;
                q_table[{i,j,k}][2] =  (rand() % 5)+1;
                q_table[{i,j,k}][3] =  (rand() % 5)+1;
                q_table[{i,j,k}][4] =  (rand() % 5)+1;
                q_table[{i,j,k}][5] =  (rand() % 5)+1; 
//Here I am creating a map such which looks like :
// q_table[{0,0,0}][0] = -0.1;
// q_table[{0,0,0}][1] = 0.2;
// q_table[{0,0,0}][2] = -0.3;
// q_table[{0,0,0}][3] = -3.2;
// q_table[{0,0,0}][4] = -1.2;
// q_table[{0,0,0}][5] = 9.2;
// q_table[{0,0,1}][0] = 5.7;
// q_table[{0,0,1}][1] = -0.9; 
// q_table[{0,0,1}][2] = 3.4;
// q_table[{0,0,1}][3] = 7.9;
// q_table[{0,0,1}][4] = 6.4;
// q_table[{0,0,1}][5] = 3.6; and so on
                
            }
        }
    }
}

Here I have initialized the map(q_table) above by giving a constant value of 3 and 6 respectively. Accordingly I have made 3 for loops for its proper initialization.

Now I want to improve the project by taking the value from the user as an input to create the map during run time. I am not able to find a way to create the map during run time. The main challenge I am facing is since for loops are use to create the map then how can I write a function with unknown number of for loops if I don't know how many of them I would need.

2 Answers2

0

Something along these lines (untested)

int dims = ...;  // the number of dimensions
int size = ...;  // All dimensions run 0 through size-1
std::vector<int> indices(dims);  // starting with all zeros
bool done = false;
while (!done) {
  // Do something with the tuple of indices

  // Advance to next tuple
  for (int dim = dims - 1; dim >= 0; --dim) {
    if (++indices[dim] < size) break;
    indices[dim] = 0;
    done = (dim == 0);
  }
}
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
0

If things are decided at runtime then you might want std::arrays as your key-value pairs.

There are many ways to index multidimensional arrays with a single for-loop. Going from a multidimensional array to a one-dimensional array is easy. If i, j, k are your indices, then you'll store this at position index=k*N*N+j*N+i; in your multidimensional array (where in your case, N=2*SIZE. If you meant to type for (int i =-SIZE; i<=SIZE; i++), then you'd have N=2*SIZE+1). So if you have an n-dimensional array and index[k] is an array of indices, you can pack this into a one-dimesional index with the following algorithm:

//dynamically allocated array of size depth
std::vector<int> index(depth,0); 
// ... populate some interesting index here, where 0<=index[i]<N
//for depth=3, this would calculate 0*N*N*N+index[2]*N*N+index[1]*N+index[0].
int one_dimensional_index=0;
for(int i=depth-1; i>=0; i--) {
    one_dimensional_index*=N;
    one_dimensional_index+=index[i];
}
std::cout<<"Multidimensional index is stored at one-dimensional index: "<<one_dimensional_index<<std::endl;

But if I understand correctly, you want to do the inverse problem. This can be done by using integer division and modular arithmetic. (index[2]*N*N+index[1]*N+index[0])%N is just index[0], and (index[2]*N*N+index[1]*N+index[0])/N is just index[2]*N+index[1], so by doing division and modulo operations you can get the indices back. In the end, you'd have an implementation that looks something like this:

std::vector<int> indexFromMulti(int one_dimensional_index,int nn, int depth){
    std::vector<int> index(depth,0);
    for(int i=0; i<depth; i++) {
        index[i]=(one_dimensional_index%N);
        one_dimensional_index/=N;
    }
    return index;
}

Here is a full implementation that prints the following for size=1, depth=4, and breadth=4.

user@desktop:~$ g++ test.cpp
user@desktop:~$ ./a.out
qtable populated with: 
qtable[{-1, -1, -1, -1}]=[4, 2, 3, 1];
qtable[{-1, -1, -1, 0}]=[3, 4, 5, 3];
qtable[{-1, -1, 0, -1}]=[1, 2, 3, 2];
(...)
qtable[{0, 0, -1, 0}]=[5, 3, 4, 5];
qtable[{0, 0, 0, -1}]=[3, 1, 5, 3];
qtable[{0, 0, 0, 0}]=[1, 1, 5, 3];

Source code:

#include <iostream> 
#include <vector>
#include <map>

std::vector<int> indexFromMulti(int one_dimensional_index,int nn, int depth){
    std::vector<int> index(depth,0);
    for(int i=0; i<depth; i++) {
        index[i]=(one_dimensional_index%nn);
        one_dimensional_index/=nn;
    }
    return index;
}

//integer power from https://stackoverflow.com/a/1505791/13783653
int int_pow(int x, int p)
{
  if (p == 0) return 1;
  if (p == 1) return x;

  int tmp = int_pow(x, p/2);
  if (p%2 == 0) return tmp * tmp;
  else return x * tmp * tmp;
}

//Function to print with pretty formatting
void print_qtable(std::map<std::vector<int>, std::vector<int>> qtable){
    std::cout<<"qtable populated with: "<<std::endl;
    for(auto iter = qtable.begin(); iter != qtable.end(); ++iter) {
        std::cout<<"qtable[{";
        for(size_t i=0;i<iter->first.size();i++){
            std::cout<<iter->first[i];
            if(i!=iter->first.size()-1)
                std::cout<<", ";
        }
        std::cout<<"}]=[";
        for(size_t i=0;i<iter->second.size();i++){
            std::cout<<iter->second[i];
            if(i!=iter->second.size()-1)
                std::cout<<", ";
        }
        std::cout<<"];"<<std::endl;
    }
}

std::map<std::vector<int>, std::vector<int>> qtable(int size, int depth, int breadth){
    int nn=2*size;
    int max_index=int_pow(nn,depth);

    std::map<std::vector<int>, std::vector<int>> q_table;
    for (int i=0;i<max_index;i++){
        std::vector<int> key=indexFromMulti(i,nn,depth);
        //change the interval [0,nn) to the interval [-size,size).
        for(int j=0;j<depth;j++)
            key[j]-=size;

        //Fill in the value
        std::vector<int> value(breadth,0);
        for(int j=0;j<breadth;j++)
            value[j] = (rand() % 5)+1;

        q_table[key]=value;
    }
    return q_table;
}

int main() {
    print_qtable(qtable(1,4,4));
    return 0;
}
David
  • 136
  • 3