0

I am trying to write a function to extract a slice from a given matrix, where the input is 1D and the slice can be 1D or 2D. I am trying to use the push_back function for this purpose but for some reasons the push_back does not work. I receive an error in my line OutPut.push_back(DumyValue);

Can anyone help me why I am receiving this error? Also, it would be appreciated if you can tell me how to solve this issue. Also, if the first part becomes clear, can anyone tell me how I should use the push_back for inserting an integer in a specific location so I can use it for extracting a 2D slice?

If you remove the line OutPut.push_back(DumyValue); the code should work.

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



int MatrixSlice(vector<vector<int>> Input, int Row1, int Row2, int Col1, int Col2) {
 //define the slice size, if it is iD or 2D

 if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
      vector<vector<int>> OutPut; 
  }else{
      vector<int> OutPut; 
  }

   int i2;
   int j2;

   for (int i = Row1; i <= Row2; i++) {
        i2=0;
       for (int j = Col1; j <= Col2; j++) {
           int DumyValue=Input[i][j];
           OutPut.push_back(DumyValue);
           i2++;
           //cout << Input[i][j] << endl;
       }
       j2++; 
   }


   return 0;
}

int main() {
  //Define a matrix for test:
   vector<vector<int>> Matrix2(4, vector<int>(5, 1));
   int R = 4;
   int C = 4;
   vector<vector<int>> MatrixInput(R, vector<int>(C, 1));;
   for (int i = 0; i < MatrixInput.size(); i++) {
       for (int j = 0; j < MatrixInput[0].size(); j++) {
           int temp;
            temp = i^2+j^2;
           MatrixInput[i][j] = temp;
       }
   }


   MatrixSlice(MatrixInput, 0, 3, 1, 1);
printf("\n");


   return 0;
}
Alex
  • 1,194
  • 1
  • 12
  • 20
  • 1
    Could you also post the error you are getting? – Marek Vitek Jun 26 '17 at 18:02
  • error: ‘OutPut’ was not declared in this scope OutPut.push_back(DumyValue); – Alex Jun 26 '17 at 18:11
  • 2
    Totally off topic warning because `i^2+j^2` looks a lot like you might actually want `i*i + j*j` instead of `i XOR 2 + j XOR 2`. `^` is the XOR operator, not the exponent operator. – user4581301 Jun 26 '17 at 18:34

2 Answers2

1

Matrix slice has a couple problems:

  1. It is impossible define a variable with two possible types and have both active in the same scope.
  2. The return type of int makes little sense. The matrix is sliced up, but then what? It can't be handed back to the caller to do anything with it.

This can be fixed with a union, but yikes! The bookkeeping on that will be a Smurfing nightmare. Don't do it!

The next is to always use a vector of vectors, but I don't like that idea for a couple reasons I'll get into below.

Instead I pitch a simple wrapper object around a single vector. This is done for two reasons:

  1. It preserves the ability to back a 1 dimensional matrix with a 1 dimensional container. If you have many rows of one column, all of the row data remains contiguous and cache friendly.
  2. It tends to be much faster. The data of one vector is contiguous in memory and reaps the rewards of cache friendliness. A vector of vectors is basically a list of pointers to arrays of data, sending the poor CPU on an odyssey of pointer-chasing through memory to find the columns. If the columns are short, this can really, really hurt performance.

Here we go:

template<class TYPE>
class Matrix
{
private:
    size_t mNrRows; // note size_t. This is unsigned because there is no reason 
                    // for a matrix with a negative size. size_t is also guaranteed 
                    // to fit anything you can throw at it.
    size_t mNrColumns;
    std::vector<TYPE> mVec;
public:
    // make a default-initialized matrix
    Matrix(size_t nrRows, size_t nrColumns) :
            mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns)
    {

    }
    // make a def-initialized matrix
    Matrix(size_t nrRows, size_t nrColumns, TYPE def) :
            mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns,
                                                        def)
    {

    }

    // gimme a value and allow it to be changed
    TYPE & operator()(size_t row, size_t column)
    {
        // could check for out of bounds and throw an exception here
        return mVec[row * mNrColumns + column];
    }
    //gimme a value and do not allow it to be changed
    TYPE operator()(size_t row, size_t column) const
    {
        return mVec[row * mNrColumns + column];
    }
    // gimme the number of rows
    size_t getRows() const
    {
        return mNrRows;
    }
    // gimmie the number of columns.
    size_t getColumns() const
    {
        return mNrColumns;
    }

    // printing convenience
    friend std::ostream & operator<<(std::ostream & out, const Matrix & mat)
    {
        int count = 0;
        for (TYPE val: mat.mVec)
        {
            out << val;
            if (++count == mat.mNrColumns)
            {
                out << '\n';
                count = 0;
            }
            else
            {
                out << ' ';
            }
        }
        return out;
    }
};

The vector member handles all of the heavy lifting so the Rule of Zero recommends leaving the copy and move constructors, assignment operators, and destructor up to the compiler.

What does this do to MatrixSlice? Well, first it now received and returns a Matrix instead of vector<vector> and int. The insides use Matrix and the confusion about 1D or 2D is just plain gone, resulting in a simpler function.

Matrix<int> MatrixSlice(const Matrix<int> & Input,
                        int Row1,
                        int Row2,
                        int Col1,
                        int Col2)
{
    Matrix<int> OutPut(Row2-Row1 + 1,
                       Col2-Col1 + 1); // but what if Row1 > Row2?

    int i2;
    int j2= 0; // definitely need to initialize this sucker.

    for (int i = Row1; i <= Row2; i++) // logical problem here: What if Row2 >= input.getRows()?
    {
        i2 = 0;
        for (int j = Col1; j <= Col2; j++) // similar problem here
        {
            int DumyValue = Input(i, j);
            OutPut(j2, i2) = DumyValue;
            i2++;
        }
        j2++;
    }

    return OutPut;
}

Not that this completely ignores the very logical option of making slice a Matrix method. While it makes sense, it doesn't need to be a method and the stock recommendation is to prefer a free function. One good improvement is to make the function a template so that it can handle all sorts of Matrix in addition to Matrix<int>.

And finally, what happens to main?

int main()
{
    //Define a matrix for test:
    Matrix<int> Matrix2(4, 5, 1); // initialize matrix to all 1s
    int R = 4;
    int C = 4;
    Matrix<int> MatrixInput(R, C); // default initialize the matrix
    for (int i = 0; i < MatrixInput.getRows(); i++)
    {
        for (int j = 0; j < MatrixInput.getColumns(); j++)
        {
            int temp;
            temp = i ^ 2 + j ^ 2;
            // WARNING: ^ is XOR, not exponent. Maybe OP wants i XOR 2, but not
            // likely. But if XOR is the desired operation, there is a lurking
            // order of operation bug that needs to be addressed
            MatrixInput(i, j) = temp;
        }
    }

    std::cout << MatrixInput << '\n';
    std::cout << MatrixSlice(MatrixInput, 0, 3, 1, 1);

    return 0;
}
user4581301
  • 33,082
  • 7
  • 33
  • 54
0

In your code

if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
      vector<vector<int> > OutPut; 
      // OutPut dies here
  }else{
      vector<int> OutPut;
      // OutPut dies here 
  }
  // here is no OutPut

OutPut lives only to the end of IF statement.

You either use it without the if statement or you add all code that uses it to the if statement.

Marek Vitek
  • 1,573
  • 9
  • 20
  • This actually looks like an attempt to declare variable with different types depending on condition. Which obviously does not work. – user7860670 Jun 26 '17 at 18:07
  • @VTT yes, by moving OutPut outside IF statement it compiles. – Marek Vitek Jun 26 '17 at 18:09
  • Yes if I dont use the IF it would be fine, but I need to switch between 1D and 2D vector depending on the size of my slice. any suggestion on how to define the vector using the IF statement? – Alex Jun 26 '17 at 18:14
  • @Alex You have two different objects which means you will have to handle it differently. So all code that handles your OutPut will go to the IF statement. And yes, it will be duplicated. So you move the for loop inside your IF into both branches. – Marek Vitek Jun 26 '17 at 18:25
  • @Alex also think on what that function will return. `return 0` seems odd for a function that sounds like it should return a slice of the matrix. In this case, duplicating the code will not be enough because you will trip over whether you want to return a `vector` or a `vector>`. You can't return both. I always sticking to `vector>` is the simplest solution followed by defining a simple `Matrix` class. For example, the TwoDee class here: https://stackoverflow.com/a/32418684/4581301 – user4581301 Jun 26 '17 at 18:45
  • You could also always define `vector>` and in case of 1D use only one dimension. – Marek Vitek Jun 26 '17 at 19:17
  • @MarekVitek @VTT If I go just with `vector> OutPut;` it is giving me the same error. – Alex Jun 27 '17 at 18:38
  • But you have to move it out of that IF statement. Did you do that? – Marek Vitek Jun 27 '17 at 18:43