Garima Singh
Garima Singh

Reputation: 1490

C/C++: circular shift on matrices

I am trying to write an efficient code to perform circular shift which I need to implement it on multiple times on big matrices during my data processing.

On my first trial, compiler throws some exception and it seems that I may be trying to access matrix element outside its size and I have no idea what is going on wrong.

1) I am also using Armadillo lib which has "mat" definition. 2) I intend to shift it by row and/ or column.

Here is my try:

#include "stdafx.h"
#include <vector>
#include <iostream>
#include "C:\Users\kumar\Documents\Visual Studio 2012\UserLibs\armadillo-3-910-0\include\armadillo"

#include <stdlib.h>     /* srand, rand */
using namespace arma;



template<class ty>
void circshift(ty *out, const ty *in, int xdim, int ydim, int xshift, int yshift)
{

    int iOutputInd, iInputInd, ii, jj;

    for (int i =0; i < xdim; i++) 
    {
        ii = (i + xshift) % xdim;
        for (int j = 0; j < ydim; j++) 
        {
            jj = (j + yshift) % ydim;

            iOutputInd = ii * ydim + jj;
            iInputInd = i * ydim + j;
            std::cout << " iOutputInd --> " << iOutputInd << " ;  iInputInd -->" << iInputInd << "\n";


            out[iOutputInd] = in[iInputInd]; // EXCEPTION BEING THROWN HERE
        }
    }
}



int _tmain(int argc, _TCHAR* argv[])
{

    //a = [1 2 3; 4 5 6; 7 8 9];
    mat a, a_out;   // "mat" defined in C++ lib Armadillo
    a << 1 << 2 << 3 << endr
      << 4 << 5 << 6 << endr
      << 7 << 8 << 9  <<endr;
    a.reshape(3,3);
    //a.print();

    a_out = a;

    int xdim = 3; int ydim = 3; int xshift = 1; int yshift = 0;
    circshift(&a_out, &a, xdim, ydim, xshift, yshift);
    a_out.print();

    return 0;
}

It compiles fine. However, when I try to run, Visual studio throws following error:

Unhandled exception at 0x3FF00000 in Circshift_Example.exe: 0xC0000005: Access violation (parameters: 0x00000008).

I get another error in visual studio console, which complains:

error: Mat::init(): requested size is too large

Update: FINAL SOLUTION I am posting my code as it may be useful for some users.

Please note that I am using "Armadillo" library to create matrix. One can replace Armadillo "mat" class wwith their own matrix class.

Please up-vote if you use this code.

#include "stdafx.h"
#include "armadillo-3-910-0\include\armadillo"

using namespace arma;


template<class ty>
void circshift(ty& out, const ty& in, int xshift, int yshift)
{
    int iOutputInd, iInputInd, ii, jj;
    int ydim = in.n_cols;
    int xdim = in.n_rows;
    for (int j =0; j < ydim; j++) 
    {
        jj = (j + yshift) % ydim;
        if (jj <0) jj = jj + ydim;
        for (int i = 0; i < xdim; i++) 
        {
            ii = (i + xshift) % xdim;
            if (ii <0) ii = ii + xdim;
            out[jj * xdim + ii] = in[j * xdim + i];
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{

    //a = [1 2 3; 4 5 6; 7 8 9];
    mat a, a_out;   
    a << 1 << 2 << 3 << endr
      << 4 << 5 << 6 << endr
      << 7 << 8 << 9  <<endr;
    a.reshape(3,3);

    a_out = a;

    int xshift = 1; int yshift = 0;
    circshift(a_out, a, xshift, yshift);
    a_out.print();  

    xshift = 1; yshift = -1;
    circshift(a_out, a, xshift, yshift);
    a_out.print();


    return 0;
}

Upvotes: 0

Views: 1514

Answers (1)

Frederic Lachasse
Frederic Lachasse

Reputation: 721

The main error here is that you pass pointers to mat type objects to the circshift() function (the out and in argument, but then use these arguments as arrays to mat. The following line is not interpreted as you think

out[iOutputInd] = in[iInputInd];

because out and in are not mat objects. They are pointers to mat objects, so the compiler will interpret in and out as being pointer to arrays of mat and index these arrays, copying a non-existant mat from in[...] to another non-existant location.

One simple way to fix that is to use references instead of pointers to pass the mat objects, i.e.:

template<class ty> void circshift(ty& out, const ty& in, int xdim, int ydim, int xshift, int yshift)
{
    ...
}

and call it in _tmain using:

circshift(a_out, a, xdim, ydim, xshift, yshift);

Upvotes: 1

Related Questions