Intrusive values/addresses when crossing an dynamic allocated 2d array in c++ - c++

2D array initialization:
....
int main (...) {
....
double **hes = allocArray (2, 2);
// function (....) returning double
hes[0][0] = function (3, &_X, &_Y, _usrvar_a, _usrvar_b);
hes[0][1] = function (4, &_X, &_Y, _usrvar_a, _usrvar_b);
hes[1][0] = function (4, &_X, &_Y, _usrvar_a, _usrvar_b);
hes[1][1] = function (5, &_X, &_Y, _usrvar_a, _usrvar_b);
....
return 0;
}
double **allocArray (int row, int col) {
double **ptr = new double*[row];
for (int i = 0; i < row; i++)
{
ptr[i] = new double[col];
}
return ptr;
}
Values of 2d double type array is:
12 2
2 14
I know that because I have crossed it with iterators (i, j)
void otherFunc (double **h, ....) {
....
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
std::cout << " " << h[i][j];
....
}
Output is
12 2 2 14
(I do not need to separate the rows of 2D array in output, do not write about that)
I want to cross it with pointer:
void otherFunc (double **h, ....) {
....
for (double *ptr = h[0]; ptr <= &h[1][1]; ptr++)
std::cout << " " << *ptr;
....
}
Output is:
12 2 0 1.63042e-322 2 14
Why 0 and 1.63042e-322 appeared here?

h[0] and h[1] in your run are not one just after the other:
h[1] in your specific run happens to be four numbers after h[0].
This behavior probably is random meaning that (as far as we know from your question) probably you didn't explicitly specify the relative positions of h[0] and h[1]. If this is the case the next time you run your code h[1] could even be smaller than h[0] this results in undefined behavior.
What you probably want is something of this kind: allocate four doubles and assign the address of the first to a pointer double* hh = malloc(4 * sizeof(double)); And then for the variable h which is a pointer to pointer double* h[2]; you want to assign the pointers as follows:
h[0] = hh;
h[1] = hh+2;
of course there are safer ways to do this. But this could be a good start.

Related

Stack around the variable 'Yarray' was corrupted

When I declare an array to store the Y values of each coordinate, define its values then use each of the element values to send into a rounding function, i obtain the error 'Run-Time Check Failure #2 - Stack around the variable 'Yarray; was corrupted. The output is mostly what is expected although i'm wondering why this is happening and if i can mitigate it, cheers.
void EquationElement::getPolynomial(int * values)
{
//Takes in coefficients to calculate Y values for a polynomial//
double size = 40;
double step = 1;
int Yarray[40];
int third = *values;
int second = *(values + 1);
int first = *(values + 2);
int constant = *(values + 3);
double x, Yvalue;
for (int i = 0; i < size + size + 1; ++i) {
x = (i - (size));
x = x * step;
double Y = (third *(x*x*x)) + (second *(x*x)) + (first * (x))
Yvalue = Y / step;
Yarray[i] = int(round(Yvalue)); //<-MAIN ISSUE HERE?//
cout << Yarray[i] << endl;
}
}
double EquationElement::round(double number)
{
return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5);
// if n<0 then ceil(n-0.5) else if >0 floor(n+0.5) ceil to round up floor to round down
}
// values could be null, you should check that
// if instead of int* values, you took std::vector<int>& values
// You know besides the values, the quantity of them
void EquationElement::getPolynomial(const int* values)
{
//Takes in coefficients to calculate Y values for a polynomial//
static const int size = 40; // No reason for size to be double
static const int step = 1; // No reason for step to be double
int Yarray[2*size+1]{}; // 40 will not do {} makes them initialized to zero with C++11 onwards
int third = values[0];
int second = values[1]; // avoid pointer arithmetic
int first = values[2]; // [] will work with std::vector and is clearer
int constant = values[3]; // Values should point at least to 4 numbers; responsability goes to caller
for (int i = 0; i < 2*size + 1; ++i) {
double x = (i - (size)) * step; // x goes from -40 to 40
double Y = (third *(x*x*x)) + (second *(x*x)) + (first * (x)) + constant;
// Seems unnatural that x^1 is values and x^3 is values+2, being constant at values+3
double Yvalue= Y / step; // as x and Yvalue will not be used outside the loop, no need to declare them there
Yarray[i] = int(round(Yvalue)); //<-MAIN ISSUE HERE?//
// Yep, big issue, i goes from 0 to size*2; you need size+size+1 elements
cout << Yarray[i] << endl;
}
}
Instead of
void EquationElement::getPolynomial(const int* values)
You could also declare
void EquationElement::getPolynomial(const int (&values)[4])
Which means that now you need to call it with a pointer to 4 elements; no more and no less.
Also, with std::vector:
void EquationElement::getPolynomial(const std::vector<int>& values)
{
//Takes in coefficients to calculate Y values for a polynomial//
static const int size = 40; // No reason for size to be double
static const int step = 1; // No reason for step to be double
std::vector<int> Yarray;
Yarray.reserve(2*size+1); // This is just optimization. Yarran *Can* grow above this limit.
int third = values[0];
int second = values[1]; // avoid pointer arithmetic
int first = values[2]; // [] will work with std::vector and is clearer
int constant = values[3]; // Values should point at least to 4 numbers; responsability goes to caller
for (int i = 0; i < 2*size + 1; ++i) {
double x = (i - (size)) * step; // x goes from -40 to 40
double Y = (third *(x*x*x)) + (second *(x*x)) + (first * (x)) + constant;
// Seems unnatural that x^1 is values and x^3 is values+2, being constant at values+3
double Yvalue= Y / step; // as x and Yvalue will not be used outside the loop, no need to declare them there
Yarray.push_back(int(round(Yvalue)));
cout << Yarray.back() << endl;
}
}

Matrix calculation error appears when dimensions become large [duplicate]

This question already has answers here:
C programming, why does this large array declaration produce a segmentation fault?
(6 answers)
Closed 6 years ago.
I am running a code where I am simply creating 2 matrices: one matrix is of dimensions arows x nsame and the other has dimensions nsame x bcols. The result is an array of dimensions arows x bcols. This is fairly simple to implement using BLAS and the following code appears to work as intended when using the below master-slave model with OpenMPI:`
#include <iostream>
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <mpi.h>
#include <gsl/gsl_blas.h>
using namespace std;`
int main(int argc, char** argv){
int noprocs, nid;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &nid);
MPI_Comm_size(MPI_COMM_WORLD, &noprocs);
int master = 0;
const int nsame = 500; //must be same if matrices multiplied together = acols = brows
const int arows = 500;
const int bcols = 527; //works for 500 x 500 x 527 and 6000 x 100 x 36
int rowsent;
double buff[nsame];
double b[nsame*bcols];
double c[arows][bcols];
double CC[1*bcols]; //here ncols corresponds to numbers of rows for matrix b
for (int i = 0; i < bcols; i++){
CC[i] = 0.;
};
// Master part
if (nid == master ) {
double a [arows][nsame]; //creating identity matrix of dimensions arows x nsame (it is I if arows = nsame)
for (int i = 0; i < arows; i++){
for (int j = 0; j < nsame; j++){
if (i == j)
a[i][j] = 1.;
else
a[i][j] = 0.;
}
}
double b[nsame*bcols];//here ncols corresponds to numbers of rows for matrix b
for (int i = 0; i < (nsame*bcols); i++){
b[i] = (10.*i + 3.)/(3.*i - 2.) ;
};
MPI_Bcast(b,nsame*bcols, MPI_DOUBLE_PRECISION, master, MPI_COMM_WORLD);
rowsent=0;
for (int i=1; i < (noprocs); i++) {
// Note A is a 2D array so A[rowsent]=&A[rowsent][0]
MPI_Send(a[rowsent], nsame, MPI_DOUBLE_PRECISION,i,rowsent+1,MPI_COMM_WORLD);
rowsent++;
}
for (int i=0; i<arows; i++) {
MPI_Recv(CC, bcols, MPI_DOUBLE_PRECISION, MPI_ANY_SOURCE, MPI_ANY_TAG,
MPI_COMM_WORLD, &status);
int sender = status.MPI_SOURCE;
int anstype = status.MPI_TAG; //row number+1
int IND_I = 0;
while (IND_I < bcols){
c[anstype - 1][IND_I] = CC[IND_I];
IND_I++;
}
if (rowsent < arows) {
MPI_Send(a[rowsent], nsame,MPI_DOUBLE_PRECISION,sender,rowsent+1,MPI_COMM_WORLD);
rowsent++;
}
else { // tell sender no more work to do via a 0 TAG
MPI_Send(MPI_BOTTOM,0,MPI_DOUBLE_PRECISION,sender,0,MPI_COMM_WORLD);
}
}
}
// Slave part
else {
MPI_Bcast(b,nsame*bcols, MPI_DOUBLE_PRECISION, master, MPI_COMM_WORLD);
MPI_Recv(buff,nsame,MPI_DOUBLE_PRECISION,master,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
while(status.MPI_TAG != 0) {
int crow = status.MPI_TAG;
gsl_matrix_view AAAA = gsl_matrix_view_array(buff, 1, nsame);
gsl_matrix_view BBBB = gsl_matrix_view_array(b, nsame, bcols);
gsl_matrix_view CCCC = gsl_matrix_view_array(CC, 1, bcols);
/* Compute C = A B */
gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, &AAAA.matrix, &BBBB.matrix,
0.0, &CCCC.matrix);
MPI_Send(CC,bcols,MPI_DOUBLE_PRECISION, master, crow, MPI_COMM_WORLD);
MPI_Recv(buff,nsame,MPI_DOUBLE_PRECISION,master,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
}
}
// output c here on master node //uncomment the below lines if I wish to see the output
// if (nid == master){
// if (rowsent == arows){
// // cout << rowsent;
// int IND_F = 0;
// while (IND_F < arows){
// int IND_K = 0;
// while (IND_K < bcols){
// cout << "[" << IND_F << "]" << "[" << IND_K << "] = " << c[IND_F][IND_K] << " ";
// IND_K++;
// }
// cout << "\n";
// IND_F++;
// }
// }
// }
MPI_Finalize();
//free any allocated space here
return 0;
};
Now what appears odd is that when I increase size of the matrices (e.g. from nsame = 500 to nsame = 501), the code no longer works. I receive the following error:
mpirun noticed that process rank 0 with PID 0 on node Users-MacBook-Air exited on signal 11 (Segmentation fault: 11).
I have tried this with other combinations of sizes for the matrices and there always appears to be an upper limit for the size of the matrices themselves (which seems to vary based on how I vary the different dimensions themselves). I have also tried modifying the values of the matrices themselves although this does not appear to change anything. I realize there are alternative ways to initialize the matrices in my example (e.g. using vector) but am simply wondering why my current scheme of multiplying matrices of arbitrary size seems to only work to a certain extent.
You're declaring too many big local variables, which is causing stack space related problems. a, in particular, is 500x500 doubles (250000 8 byte elements, or 2 million bytes). b is even larger.
You'll need to dynamically allocate space for some or all of those arrays.
There might be a compiler option to increase the initial stack space but that isn't a good long term solution.

Pass arrays between VB.NET and VC++

I've a written a function to calculate the correlation matrix for variables (risks) held in a flat file structure. I.e. RiskID | Year | Amount
I have written the function because the library routines that I can find necessitate a matrix input. That is, RiskID as 2nd dimension and year as the 1st dimension - with amounts as actual array values. The matrix needs to be complete, in that zero values must be included also and hence for sparsely populated non zero data - this leads to wasted iterations which can be bypassed. The routine relies upon the data being sorted first by Year (asc) then by RiskID (asc)
I have written the routine in C++ (for speed) to be compiled as a dll and referenced in VB.NET. I need to pass 3 arrays (one each for each of the headers) and return a 2 dimensional array back to VB.NET. I guess I'm cheating by passing 3 individual 1d arrays instead of a 2d array but there you go. I'll post the full C++ routine as others may find it useful if seeking to do something similar. I'd be surprised if this hasn't been done before - but I just can't find it.
I lack the interop knowledge to implement this properly and am getting nowhere googling around. As far as I can workout I may need to use SAFEARRAY ?
Or is there a quick fix to this problem? Or is SAFEARRAY a piece of cake. Either way an example would be very helpful.
Also, as a side note - I'm sure the memory management is failing somewhere?
Here is the Visual C++ (VS2013)
Header File
#ifndef CorrelLib_EXPORTS
#define CorrelLib_API __declspec(dllexport)
#else
#define CorrelLib_API __declspec(dllimport)
#endif
// Returns correlation matrix for values in flat file
extern "C" CorrelLib_API double** __stdcall CalcMatrix(int* Risk, int* Year, double* Loss, const int& RowNo, const int& RiskNo, const int& NoSimYear);
CPP File
#include "stdafx.h"
#include "CorrelLib.h"
#include <memory>
#include <ctime>
using namespace std;
extern "C" CorrelLib_API double** __stdcall CalcMatrix(int* Risk, int* Year, double* Loss, const int& RowNo, const int& RiskNo, const int& NoSimYear)
{
int a, b;
int i, j, k;
int YearCount, MissingYears;
int RowTrack;
//Relies on Year and Risk being sorted in ascending order in those respective orders Year asc, Risk asc
double *RiskTrack = new double[RiskNo](); //array of pointers?
int *RiskTrackBool = new int[RiskNo](); //() sets inital values to zero
double *RiskAvg = new double[RiskNo]();
double *RiskSD = new double[RiskNo]();
//Create 2d array to hold results 'array of pointers to 1D arrays of doubles'
double** Res = new double*[RiskNo];
for (i = 0; i < RiskNo; ++i)
{
Res[i] = new double[RiskNo](); //()sets initial values to zero
}
//calculate average
for (i = 0; i < RowNo; i++)
{
a = Risk[i];
RiskAvg[a] = RiskAvg[a] + Loss[i];
}
for (i = 0; i < RiskNo; i++)
{
RiskAvg[i] = RiskAvg[i] / NoSimYear;
}
//Enter Main Loop
YearCount = 0;
i = 0; //start at first row
do {
YearCount = YearCount + 1;
a = Risk[i];
RiskTrack[a] = Loss[i] - RiskAvg[a];
RiskTrackBool[a] = 1;
j = i + 1;
do
{
if (Year[j] != Year[i])
{
break;
}
b = (int)Risk[j];
RiskTrack[b] = Loss[j] - RiskAvg[b];
RiskTrackBool[b] = 1;
j = j + 1;
} while (j < RowNo);
RowTrack = j;
//check through RiskTrack and if no entry set to 0 - avg
for (j = 0; j < RiskNo; j++)
{
if (RiskTrackBool[j] == 0)
{
RiskTrack[j] = -1.0 * RiskAvg[j];
RiskTrackBool[j] = 1;
}
}
//Now loop through and perform calcs
for (j = 0; j < RiskNo; j++)
{
//SD
RiskSD[j] = RiskSD[j] + RiskTrack[j] * RiskTrack[j];
//Covar
for (k = j + 1; k < RiskNo; k++)
{
Res[j][k] = Res[j][k] + RiskTrack[j] * RiskTrack[k];
}
}
//Reset RiskTrack
for (k = 0; k<RiskNo; k++)
{
RiskTrack[k] = 0.0;
RiskTrackBool[k] = 0;
}
i = RowTrack;
} while (i < RowNo);
//Account For Missing Years
MissingYears = NoSimYear - YearCount;
for (i = 0; i < RiskNo; i++)
{
//SD
RiskSD[i] = RiskSD[i] + MissingYears * RiskAvg[i] * RiskAvg[i];
//Covar
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] + MissingYears * RiskAvg[i] * RiskAvg[j];
}
}
//Covariance Matrix
for (i = 0; i < RiskNo; i++)
{
//SD
RiskSD[i] = sqrt(RiskSD[i] / (NoSimYear - 1));
if (RiskSD[i] == 0.0)
{
RiskSD[i] = 1.0;
}
//Covar
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] / (NoSimYear - 1);
}
}
//Correlation Matrix
for (i = 0; i < RiskNo; i++)
{
Res[i][i] = 1.0;
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] / (RiskSD[i] * RiskSD[j]);
}
}
//Clean up
delete[] RiskTrack;
delete[] RiskTrackBool;
delete[] RiskAvg;
delete[] RiskSD;
//Return Array
return Res;
}
Def File
LIBRARY CorrelLib
EXPORTS
CalcMatrix
VB.NET
I've created a simple winform with a button which triggers the code below. I wish to link to the dll, pass the arrays and receive the result as a 2d array.
Imports System
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("CorrelLib.dll", EntryPoint:="CalcMatrix", CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function CorrelMatrix2(ByRef Risk_FE As Integer, ByRef Year_FE As Integer, ByRef Loss_FE As Double, _
ByRef RowNo As Long, ByRef RiskNo As Long, ByRef NoSimYear As Long) As Double(,)
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer, j As Integer
Dim Risk() As Long, Year() As Long, Loss() As Double
Dim NoRisks As Long, NoSimYear As Long, NoRows As Long
Dim counter As Long
Dim Result(,) As Double
NoRisks = 50
NoSimYear = 10000
NoRows = NoRisks * NoSimYear
ReDim Risk(0 To NoRows - 1), Year(0 To NoRows - 1), Loss(0 To NoRows - 1)
counter = 0
For i = 1 To NoSimYear
For j = 1 To NoRisks
Risk(counter) = j
Year(counter) = i
Loss(counter) = CDbl(Math.Floor((1000000 - 1 + 1) * Rnd())) + 1
counter = counter + 1
Next j
Next i
Dim dllDirectory As String = "C:\Users\Documents\Visual Studio 2013\Projects\CorrelLibTestForm"
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + dllDirectory)
Result = CorrelMatrix2(Risk(1), Year(1), Loss(1), NoRows, NoRisks, NoSimYear)
End Sub
End Class
Current Error Message
An unhandled exception of type >'System.Runtime.InteropServices.MarshalDirectiveException' occurred in >CorrelLibTestForm.exe
Additional information: Cannot marshal 'return value': Invalid >managed/unmanaged type combination.
A double ** pointer to a pointer is not the same with a 2 dimension array in vb. Your best bet is to return just a pointer:
double *pdbl;
pdbl = &res[0][0];
return pdbl; //pdbl points to the first element
In vb you use an IntPtr to get the pointer:
Dim Result As IntPtr = Marshal.AllocHGlobal(4)
Dim dbl As Double
Result = CorrelMatrix2(Risk(1), Year(1), Loss(1), NoRows, NoRisks, NoSimYear)
//derefference the double pointer, i(integer) is actually the index in the array of doubles
dbl = CType(Marshal.PtrToStructure(IntPtr.Add(Result, i * 8), GetType(Double)), Double)
Your res array in c++ function needs to be public so the memory allocated to it is valid after the function returns.

Array Partition with pointer

I have a 20 x 20 array and need to iterate over it by reading a 4 x 4 array. I thought I could do this with pointed assignment, but it does not do much except force close
const char SOURCE[20][20];
const char **pointer;
for(int x = 0; x < 20; x+=4)
{
for(int y = 0; y < 20; y+=4)
{
pointer = (const char **)&SOURCE[x][y];
printGrid(pointer);
}
}
void printGrid(const char **grid)
{
// do something usefull
}
Just casting a pointer to a different type doesn't change the
type of what it points to (and will usually lead to undefined
behavior, unless you really know what you're doing). If you
cannot change printGrid, you'll have to create an array of
pointers on the fly:
for ( int x = 0; x < 20; x += 4 ) {
for ( int y = 0; y < 20; y += 4 ) {
char const* p4[4] =
{
source[x] + y,
source[x + 1] + y,
source[x + 2] + y,
source[x + 3] + y
};
printGrid( p4 );
}
}
A pointer to a pointer is not the same as an array of arrays.
You can however use a pointer to an array instead:
const char (*pointer)[20];
You of course need to update the printGrid function to match the type.
As for the reason why a pointer-to-pointer and an array-of-array (also often called a matrix) see e.g. this old answer of mine that shows the memory layout of the two.
Your 2D-array is of type char:
const char SOURCE[20][20];
When you are iterating through it, you can either look at the char or reference the address with a char*:
for(int x = 0; x < 20; x+=4)
{
for(int y = 0; y < 20; y+=4)
{
printGrid(SOURCE[x][y]); // do this unless you need to do something with pointer
}
}
Then you can make printGrid with either of the following signatures:
void printGrid(const char& grid)
{
// do something usefull
}
or
void printGrid(const char* grid)
{
// do something usefull
}
Extending James's Answer, you may change your code as below as it sees that the it passes pointer to an array of 4 char rather than just array of char.
for(int x = 0; x < 20; x+=4)
{
for(int y = 0; y < 20; y+=4)
{
char const (*p4[4])[4] =
{
(const char(*)[4])(SOURCE[x] + y),
(const char(*)[4])(SOURCE[x + 1] + y),
(const char(*)[4])(SOURCE[x + 2] + y),
(const char(*)[4])(SOURCE[x + 3] + y)
};
}
}

Is there an example for accumarray() in C/C++

We are trying to understand accumarray function of MATLAB, wanted to write C/C++ code for the same for our understanding. Can someone help us with a sample/pseudo code?
According to the documentation,
The function processes the input as follows:
Find out how many unique indices there are in subs. Each unique index defines a bin in the output array. The maximum index value in
subs determines the size of the output array.
Find out how many times each index is repeated.
This determines how many elements of vals are going to be accumulated at each bin in the output array.
Create an output array. The output array is of size max(subs) or of size sz.
Accumulate the entries in vals into bins using the values of the indices in subs and apply fun to the entries in each bin.
Fill the values in the output for positions not referred to by subs. Default fill value is zero; use fillval to set a different
value.
So, translating to C++ (this is untested code),
template< typename sub_it, typename val_it, typename out_it,
typename fun = std::plus< typename std::iterator_traits< val_it >::value_type >,
typename T = typename fun::result_type >
out_it accumarray( sub_it first_index, sub_it last_index,
val_it first_value, // val_it last_value, -- 1 value per index
out_it first_out,
fun f = fun(), T fillval = T() ) {
std::size_t sz = std::max_element( first_index, last_index ); // 1. Get size.
std::vector< bool > used_indexes; // 2-3. remember which indexes are used
std::fill_n( first_out, sz, T() ); // 4. initialize output
while ( first_index != last_index ) {
std::size_t index = * first_index;
used_indexes[ index ] = true; // 2-3. remember that this index was used
first_out[ index ] = f( first_out[ index ], * first_value ); // 5. accumulate
++ first_value;
++ first_index;
}
// If fill is different from zero, reinitialize untouched values
if ( fillval != T() ) {
out_it fill_it = first_out;
for ( std::vector< bool >::iterator used_it = used_indexes.begin();
used_it != used_indexes.end(); ++ used_it ) {
if ( * used_it ) * fill_it = fillval;
}
}
return first_out + sz;
}
This has a few shortcomings, for example the accumulation function is called repeatedly instead of once with the entire column vector. The output is placed in pre-allocated storage referenced by first_out. The index vector must be the same size as the value vector. But most of the features should be captured pretty well.
Many thanks for your response. We were able to fully understand and implement the same in C++ (we used armadillo). Here is the code:
colvec TestProcessing::accumarray(icolvec cf, colvec T, double nf, int p)
{
/* ******* Description *******
here cf is the matrix of indices
T is the values whose data is to be
accumulted in the output array S.
if T is not given (or is scaler)then accumarray simply converts
to calculation of histogram of the input data
nf is the the size of output Array
nf >= max(cf)
so pass the argument accordingly
p is not used in the function
********************************/
colvec S; // output Array
S.set_size(int(nf)); // preallocate the output array
for(int i = 0 ; i < (int)nf ; i++)
{
// find the indices in cf corresponding to 1 to nf
// and store in unsigned integer array q1
uvec q1 = find(cf == (i+1));
vec q ;
double sum1 = 0 ;
if(!q1.is_empty())
{
q = T.elem(q1) ; // find the elements in T having indices in q1
// make sure q1 is not empty
sum1 = arma::sum(q); // calculate the sum and store in output array
S(i) = sum1;
}
// if q1 is empty array just put 0 at that particular location
else
{
S(i) = 0 ;
}
}
return S;
}
Hope this will help others too!
Thanks again to everybody who contributed :)
Here's what I came up with. Note: I went for readability (since you wanted to understand best), rather than being optimized. Oh, and I've never used MATLAB, I was just going off of this sample I saw just now:
val = 101:105;
subs = [1; 2; 4; 2; 4]
subs =
1
2
4
2
4
A = accumarray(subs, val)
A =
101 % A(1) = val(1) = 101
206 % A(2) = val(2)+val(4) = 102+104 = 206
0 % A(3) = 0
208 % A(4) = val(3)+val(5) = 103+105 = 208
Anyway, here's the code sample:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <map>
class RangeValues
{
public:
RangeValues(int startValue, int endValue)
{
int range = endValue - startValue;
// Reserve all needed space up front
values.resize(abs(range) + 1);
unsigned int index = 0;
for ( int i = startValue; i != endValue; iterateByDirection(range, i), ++index )
{
values[index] = i;
}
}
std::vector<int> GetValues() const { return values; }
private:
void iterateByDirection(int range, int& value)
{
( range < 0 ) ? --value : ++value;
}
private:
std::vector<int> values;
};
typedef std::map<unsigned int, int> accumMap;
accumMap accumarray( const RangeValues& rangeVals )
{
accumMap aMap;
std::vector<int> values = rangeVals.GetValues();
unsigned int index = 0;
std::vector<int>::const_iterator itr = values.begin();
for ( itr; itr != values.end(); ++itr, ++index )
{
aMap[index] = (*itr);
}
return aMap;
}
int main()
{
// Our value range will be from -10 to 10
RangeValues values(-10, 10);
accumMap aMap = accumarray(values);
// Now iterate through and check out what values map to which indices.
accumMap::const_iterator itr = aMap.begin();
for ( itr; itr != aMap.end(); ++itr )
{
std::cout << "Index: " << itr->first << ", Value: " << itr->second << '\n';
}
//Or much like the MATLAB Example:
cout << aMap[5]; // -5, since out range was from -10 to 10
}
In addition to Vicky Budhiraja "armadillo" example, this one is a 2D version of accumarray using similar semantic than matlab function:
arma::mat accumarray (arma::mat& subs, arma::vec& val, arma::rowvec& sz)
{
arma::u32 ar = sz.col(0)(0);
arma::u32 ac = sz.col(1)(0);
arma::mat A; A.set_size(ar, ac);
for (arma::u32 r = 0; r < ar; ++r)
{
for (arma::u32 c = 0; c < ac; ++c)
{
arma::uvec idx = arma::find(subs.col(0) == r &&
subs.col(1) == c);
if (!idx.is_empty())
A(r, c) = arma::sum(val.elem(idx));
else
A(r, c) = 0;
}
}
return A;
}
The sz input is a two columns vector that contain : num rows / num cols for the output matrix A. The subs matrix is a 2 columns with same num rows of val. Num rows of val is basically sz.rows by sz.cols.
The sz (size) input is not really mandatory and can be deduced easily by searching the max in subs columns.
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = arma::max(subs.col(1)) + 1;
or
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = val.n_elem / sz_rows;
the output matrix is now :
arma::mat A (sz_rows, sz_cols);
the accumarray function become :
arma::mat accumarray (arma::mat& subs, arma::vec& val)
{
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = arma::max(subs.col(1)) + 1;
arma::mat A (sz_rows, sz_cols);
for (arma::u32 r = 0; r < sz_rows; ++r)
{
for (arma::u32 c = 0; c < sz_cols; ++c)
{
arma::uvec idx = arma::find(subs.col(0) == r &&
subs.col(1) == c);
if (!idx.is_empty())
A(r, c) = arma::sum(val.elem(idx));
else
A(r, c) = 0;
}
}
return A;
}
For example :
arma::vec val = arma::regspace(101, 106);
arma::mat subs;
subs << 0 << 0 << arma::endr
<< 1 << 1 << arma::endr
<< 2 << 1 << arma::endr
<< 0 << 0 << arma::endr
<< 1 << 1 << arma::endr
<< 3 << 0 << arma::endr;
arma::mat A = accumarray (subs, val);
A.raw_print("A =");
Produce this result :
A =
205 0
0 207
0 103
106 0
This example is found here : http://fr.mathworks.com/help/matlab/ref/accumarray.html?requestedDomain=www.mathworks.com
except for the indices of subs, armadillo is 0-based indice where matlab is 1-based.
Unfortunaly, the previous code is not suitable for big matrix. Two for-loop with a find in vector in between is really bad thing. The code is good to understand the concept but can be optimized as a single loop like this one :
arma::mat accumarray(arma::mat& subs, arma::vec& val)
{
arma::u32 ar = arma::max(subs.col(0)) + 1;
arma::u32 ac = arma::max(subs.col(1)) + 1;
arma::mat A(ar, ac);
A.zeros();
for (arma::u32 r = 0; r < subs.n_rows; ++r)
A(subs(r, 0), subs(r, 1)) += val(r);
return A;
}
The only change are :
init the output matrix with zero's.
loop over subs rows to get the output indice(s)
accumulate val to output (subs & val are row synchronized)
A 1-D version (vector) of the function can be something like :
arma::vec accumarray (arma::ivec& subs, arma::vec& val)
{
arma::u32 num_elems = arma::max(subs) + 1;
arma::vec A (num_elems);
A.zeros();
for (arma::u32 r = 0; r < subs.n_rows; ++r)
A(subs(r)) += val(r);
return A;
}
For testing 1D version :
arma::vec val = arma::regspace(101, 105);
arma::ivec subs;
subs << 0 << 2 << 3 << 2 << 3;
arma::vec A = accumarray(subs, val);
A.raw_print("A =");
The result is conform with matlab examples (see previous link)
A =
101
0
206
208
This is not a strict copy of matlab accumarray function. For example, the matlab function allow to output vec/mat with size defined by sz that is larger than the intrinsec size of the subs/val duo.
Maybe that can be a idea for addition to the armadillo api. Allowing a single interface for differents dimensions & types.