I'm trying to store a structure of capacity 6 in another structure.
struct eachElement {
float centerX;
float centerY;
int flagMountain;
};
eachElement cn[6];
struct characters {
eachElement each[6];
};
characters chars[1500];
float strtPt = 235.0;
float initializer = strtPt;
float endPt = 120.0;
float holder = endPt;
int count = 0;
int ctr = 0;
int cr = 0;
int countCharacters = 0;
int dup = 0;
while (holder < m_img_height) {
for (float i = initializer ; i < m_img_width - 500; ) {
float j = holder;
int ck = 1;
while (ck < 4) {
cvCircle(image, cvPoint(i, j), 3, cvScalar(0, 255, 0), 1);
cr = ctr++;
cn[cr].centerX = i;
cn[cr].centerY = j;
cn[cr].flagMountain = 1;
cvCircle(image, cvPoint(i + 5, j + 5), 1, cvScalar(0, 255, 0), 1);
j += 9.448;
count++;
ck++;
}
if (count == 6) {
i += 23.811;
count = 0;
ctr = 0;
dup = countCharacters++;
chars[dup].each = cn;
}
else
i += 9.448;
}
holder += 56.686;
}
In this line,
chars[dup].each = cn;
it gives me an error saying expression must be a modifiable lvalue.
Even though I'm assigning it to the same type, I got this error.
Any help would be appreciated.
I don't know what you try to achieve with your code, but you must specify an array index for the each member array to access any of it's innards:
chars[dup].each[0] = cn[0];
// ^^^ ^^^
The array start address cannot be changed
chars[dup].each = cn;
hence the compiler error.
To fix that use std::copy():
std::copy(std::begin(cn),std::end(cn),std::begin(chars[dup].each));
Arrays do not have the copy assignment operator. You have to copy each element of one array into another array.
Thus this statement
chars[dup].each = cn;
is wrong.
You can use standard algorithm std::copy to copy one array into another. For example
#include <algorithm>
//...
std::copy( std::begin( cn ), std::end( cn ), std::begin( chars[dup].each ) );
Or if the compiler does not support function std::begin and std::end then you can just write
#include <algorithm>
//...
std::copy( cn, cn + 6, chars[dup].each );
or
std::copy( cn, cn + sizeof( cn ) / sizeof( *cn ), chars[dup].each );
Your struct has fixed buffer
struct characters {
eachElement each[6];
};
and your assignemt
chars[dup].each = cn;
will be legal (I don't know if will make sense) if the struct were like this:
struct characters {
eachElement * each;
};
The code is hard to understand for me, I cannot propose an equivalent solution for your goal. But such is the background of error message
maybe, given your declaration - but I don't understand the goal - this style would work:
for(int i=1;i<6;i++)
chars[dup].each[i] = cn;
Related
I am reading my hand pose from a Leap Motion sensor and I want to calculate how fast the hand moves (by calculating derivativex = dx / dt) in X direction. My solution is to put 100 hand pose values in an array and keep updating this array with new values when new messages (msg->palmpos.x) arrive in the callback function through topic leapmotion/data.
My question is when I print the derivativex = dx / dt with ROS_ERROR("Hello %f", "derivativex") the output is always: 0
what I've been doing wrong? link for the topic that my callback is listening.
my call back function:
#include "geometry_msgs/TwistStamped.h"
#include "jog_msgs/JogJoint.h"
#include "jog_msgs/leapros.h"
#include "ros/ros.h"
#include <ros/console.h>
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
namespace to_twist
{
class spaceNavToTwist
{
public:
spaceNavToTwist() : spinner_(1)
{
joy_sub_ = n_.subscribe("leapmotion/data", 1, &spaceNavToTwist::joyCallback, this);
// Changed "spacenav/joy" to topic "/leapmotion/data"
twist_pub_ = n_.advertise<geometry_msgs::TwistStamped>("jog_arm_server/delta_jog_cmds", 1);
joint_delta_pub_ = n_.advertise<jog_msgs::JogJoint>("jog_arm_server/joint_delta_jog_cmds", 1);
spinner_.start();
ros::waitForShutdown();
};
const int arraySize = 100;// constant variable can be used to specify array size
double vectorx[ arraySize ] = {};// initialize elements of array n to 0
int resolution = 10;
double derivativex = 0;
double dx = 0;
int dt = 0;
private:
ros::NodeHandle n_;
ros::Subscriber joy_sub_;
ros::Publisher twist_pub_, joint_delta_pub_;
ros::AsyncSpinner spinner_;
// Convert incoming joy commands to TwistStamped commands for jogging.
void joyCallback(const jog_msgs::leapros::ConstPtr& msg)
{
for ( int count = 0; count < arraySize; ++count ) {// store the values of poses
vectorx[ count ] = msg->palmpos.x;
if (count>resolution) {
dx = vectorx[ count-1 ] - vectorx[ count-(resolution-1) ];
dt = resolution;
derivativex = dx / dt;
ROS_ERROR("Hello %f", derivativex);
}
if (count == arraySize) {
count=0;
}
}
Issue 1: The log function ROS_ERROR is misused. You should pass a float instead of a string, otherwise, you will get an undefined behavior :
ROS_ERROR("Hello %f", derivativex); // <-- there is no double quotes.
Issue 2: derivative of X is always 0 because of the assignment at the beginning of the for loop:
for ( int count = 0; count < arraySize; ++count ) {// store the values of poses
//Could you please explain why the program needs this ???
vectorx[ count ] = msg->palmpos.x; // <-- every element in vectorx is set to this values (const in each function call).
if (count>resolution) {
dx = vectorx[ count-1 ] - vectorx[ count-(resolution-1) ]; // is the same as (msg->palmpos.x - msg->palmpos.x) --> 0
dt = resolution;
derivativex = dx / dt;
ROS_ERROR("Hello %f", derivativex);
}
if (count == arraySize) {
count = 0; //<-- never get here because of count is always lesser than arraySize
}
}
I guess that you want to append msg->palmpos.x to the vectorx ? You should use std::vector for vectorx, it will be much easier.
Here is the modified version of your program, using std::vector :
//add this to your file
#include <vector>
//Your program body ...
//...
//As we are using C++, try to use C++ facilities if possible.
//const int arraySize = 100;// constant variable can be used to specify array size
//double vectorx[ arraySize ] = {};// initialize elements of array n to 0
std::vector<double> vectorx;
int resolution = 10;
int max_vector_size = 100; //keep 100 elements in the vectorx.
//...
// Convert incoming joy commands to TwistStamped commands for jogging.
void joyCallback(const jog_msgs::leapros::ConstPtr& msg)
{
//store the x coordinate in the vectorx
vectorx.push_back( msg->palmpos.x );
if( vectorx.size() > resolution ){
int id_back = vectorx.size() - 1;
double dx = vectorx[id_back] - vectorx[ id_back - resolution ];
double dt = resolution;
derivativex = dx / dt;
ROS_ERROR("Hello %f", derivativex);
}
while(vectorx.size() > max_vector_size ) {
vectorx.erase( vectorx.begin() ); //remove the first element
}
}//eof joyCallback
FFT works fine, but when I want to take IFFT I always see the same graph from its results. Results are complex and graph always the same regardless of the original signal.
in real part graph is a -sin with period = frame size
in imaginary part it is a -cos with the same period
Where can be a problem?
original signal:
IFFT real value (on pics are only half of frame):
Algorithm FFT that I use.
double** FFT(double** f, int s, bool inverse) {
if (s == 1) return f;
int sH = s / 2;
double** fOdd = new double*[sH];
double** fEven = new double*[sH];
for (int i = 0; i < sH; i++) {
int j = 2 * i;
fOdd[i] = f[j];
fEven[i] = f[j + 1];
}
double** sOdd = FFT(fOdd, sH, inverse);
double** sEven = FFT(fEven, sH, inverse);
double**spectr = new double*[s];
double arg = inverse ? DoublePI / s : -DoublePI / s;
double*oBase = new double[2]{ cos(arg),sin(arg) };
double*o = new double[2]{ 1,0 };
for (int i = 0; i < sH; i++) {
double* sO1 = Mul(o, sOdd[i]);
spectr[i] = Sum(sEven[i], sO1);
spectr[i + sH] = Dif(sEven[i], sO1);
o = Mul(o, oBase);
}
return spectr;
}
The "butterfly" portion is applying the coefficients incorrectly:
for (int i = 0; i < sH; i++) {
double* sO1 = sOdd[i];
double* sE1 = Mul(o, sEven[i]);
spectr[i] = Sum(sO1, sE1);
spectr[i + sH] = Dif(sO1, sE1);
o = Mul(o, oBase);
}
Side Note:
I kept your notation but it makes things confusing:
fOdd has indexes 0, 2, 4, 6, ... so it should be fEven
fEven has indexes 1, 3, 5, 7, ... so it should be fOdd
really sOdd should be sLower and sEven should be sUpper since they correspond to the 0:s/2 and s/2:s-1 elements of the spectrum respectively:
sLower = FFT(fEven, sH, inverse); // fEven is 0, 2, 4, ...
sUpper = FFT(fOdd, sH, inverse); // fOdd is 1, 3, 5, ...
Then the butterfly becomes:
for (int i = 0; i < sH; i++) {
double* sL1 = sLower[i];
double* sU1 = Mul(o, sUpper[i]);
spectr[i] = Sum(sL1, sU1);
spectr[i + sH] = Dif(sL1, sU1);
o = Mul(o, oBase);
}
When written like this it is easier to compare to this pseudocode example on wikipedia.
And #Dai is correct you are going to leak a lot of memory
Regarding the memory, you can use the std::vector to encapsulate dynamically-allocated arrays and to ensure they're deallocated when execution leaves scope. You could use unique_ptr<double[]> but the performance gains are not worth it IMO and you lose the safety of the at() method.
(Based on #Robb's answer)
A few other tips:
Avoid cryptic identifiers - programs should be readable, and names like "f" and "s" make your program harder to read and maintain.
Type-based Hungarian notation is frowned upon as modern editors show type information automatically so it adds unnecessary complication to identifier names.
Use size_t for indexes, not int
The STL is your friend, use it!
Preemptively prevent bugs by using const to prevent accidental mutation of read-only data.
Like so:
#include <vector>
using namespace std;
vector<double> fastFourierTransform(const vector<double> signal, const bool inverse) {
if( signal.size() < 2 ) return signal;
const size_t half = signal.size() / 2;
vector<double> lower; lower.reserve( half );
vector<double> upper; upper.reserve( half );
bool isEven = true;
for( size_t i = 0; i < signal.size(); i++ ) {
if( isEven ) lower.push_back( signal.at( i ) );
else upper.push_back( signal.at( i ) );
isEven = !isEven;
}
vector<double> lowerFft = fastFourierTransform( lower, inverse );
vector<double> upperFft = fastFourierTransform( upper, inverse );
vector<double> result;
result.reserve( signal.size() );
double arg = ( inverse ? 1 : -1 ) * ( DoublePI / signal.size() );
// Ideally these should be local `double` values passed directly into `Mul`.
unique_ptr<double[]> oBase = make_unique<double[]>( 2 );
oBase[0] = cos(arg);
oBase[1] = sin(arg);
unique_ptr<double[]> o = make_unique<double[]>( 2 );
o[0] = 0;
o[1] = 0;
for( size_t i = 0; i < half; i++ ) {
double* lower1 = lower.at( i );
double* upper1 = Mul( o, upper.at( i ) );
result.at( i ) = Sum( lower1, upper1 );
result.at( i + half ) = Dif( lower1, upper1 );
o = Mul( o, oBase );
}
// My knowledge of move-semantics of STL containers is a bit rusty - so there's probably a better way to return the output 'result' vector.
return result;
}
I am trying to compile the files below. The PosLin.cpp contains the SurTriAuto and getSphere functions below. Although they are similar, I am not getting the same results. Is it because the "namespace TPiecesNS" causes them to be different?
I have a tpieces.h file
namespace TPiecesNS
{
class TPieces
{
public:
TPieces();
//other stuff
}
}
tpieces.cpp has:
void TPieces::addPoint(Vertex* point)
{
Vertex* p = new Vertex();
p->Point[0] = point->Point[0]; //similar for Point[1],[2]
p->Normal[0] = point->Normal[0]; //same for 1,2
m_Vertices.push_back(p);
}
geopar.h file has
#include "tpieces.h"
#include "Geo/Geo.h"
class Geo;
namespace TPiecesNS
{
class GeoPar;
{
public:
GeoPar();
TPieces* getSphere(Geo* geo);
TPieces* getSphere(Geo* geo, int permu);
private:
TPieces* SurTriAuto(TPieces* boundary, Geo* geo,int permu);
}
}
geopar.cpp file has
#include "tpieces/geo.h"
#include "tpieces.h"
#include "Geo/Geo.h"
using namespace TPiecesNS;
TPieces* GeoPar::getSphere(Geo* geo) {
return getSphere(geo, 0);
}
TPieces* GeoPar::getSphere(Geo* geo, int permu)
{
TPieces* boundary = new Sphere();
return SurTriAuto(boundary,geo,permu);
}
TPieces* GeoPar::SurTriAuto(TPieces* boundary, Geo* geo, int permu)
{
double maxx, maxy, maxz, minx, miny, minz;
double x,y,z,f,nx,ny,nz;
int number = 6;
ofstream file;
file.open("output.txt");
boundary->numbpts = geo->m_NumTriVerts;
boundary->numbtris = geo->m_NumTris;
file<<"NumVertices "<<boundary->numbpts<<endl;
file<<"NumTrianlges "<<boundary->numbtris<<endl;
for (i = 0 ; i < boundary->numbpts; i++)
{
x = geometry->m_TriVerts[i*3+0];
//also equalities for y,z, but I don't want to type here in order to save space
nx = geometry->m_TriVertNormals[i*3+0];
//ny, nz also
if (x < minx) minx = x;
//comparisons for y,z also and comparing to maxx, maxy, maxz
Vertex* point = new Vertex();
point->Point[0] = x;
point->Point[1] = y;
point->Point[2] = z;
point->Normal[0] = nx; //also assignments for ny, nz
file<<"xyz normals: "<<point->Point[0]<<endl;
//I also printed out y,z,nx,ny,nz
boundary->addPoint(point);
}
for (i = 0 ; i < boundary->numbtris; i++)
{
ii = geo->m_Tris[i*3+0]; //assignments for jj, kk also
if (ii < jj && jj < kk) { i1 = ii; i2 = jj; i3 = kk; }
//similar comparisons for jj and kk also here, but I want to save space
//...
if (kk < ii && ii < jj) { i1 = kk; i2 = ii; i3 = jj; } // result in i1 <= i2 <= i3
Face* facet = new Face();
facet->Index[0] = i1; //i2, i3 are also assigned
facet->IndexInR[0] = ii; //jj, kk also
boundary->addFacet(facet);
} /* end facet (i) loop */
for (i = 0 ; i <boundary->numbtris; i++)
{
for(int j=0;j<3;j++)
{
int index = boundary->m_Faces[i]->Index[j];
for(int k=0;k<3;k++)
{
file<<boundary->m_Faces[i]->Normal[k]<<" "<<boundary->m_Vertices[index]->Normal[k]<<endl;
boundary->m_Faces[i]->Normal[k] += boundary->m_Vertices[index]->Normal[k];
//ERROR IS HERE
file<<boundary->m_Faces[i]->Normal[k]<<endl;
}
}
}
return boundary;
}
and PosLin.h has
#include "TPieces/tpieces.h"
#include "TPieces/geoPar.h"
#include "Geo/Geo.h"
struct PosRotAndQ {
TPiecesNS::TPieces* boundary;
};
class PS{
public:
PosExCode computation(Geo* geo, POpinion* opinion, PositionRotation* matterboundary)
PositionRotation* matterboundary;
}
and PosLin.cpp has
#include "tpieces/tpieces.h"
#include "Geo/Geo.h"
PosExCode PS::computation(Geo* geo, POpinion* opinion, PositionRotation* matterboundary)
{
TPiecesNS::GeoPar* perform = new TPiecesNS::GeoPar();
TPiecesNS::TPieces* boundary = new TPiecesNS::Sphere();
boundary->sphere = perform->SurTriAuto(boundary, geo,0);//if I comment this line out and the line below and un-comment the 2 getSphere lines below, they do not produce the same output
boundary->sphereDark[0] = perform->SurTriAuto(boundary, geo,0); \
//boundary->sphere = perform->getSphere(geo,0);
//boundary->sphereDark[0] = perform->getSphere(geo,0);
}
I noticed that the getSphere and SurTriAuto get different outputs, specifically at the line surface->m_Faces[i]->Normal[k] +=
surface->m_Vertices[index]->Normal[k];
In the outputted textfile, before the += operation takes place, the values surface->m_Faces[i]->Normal[k] and surface->m_Vertices[index]->Normal[k] and are not the same for getSphere and SurTriAuto, even though all the other values (such as the x,y,z,index values) are the same.
I suspect this is because one of the boundary pointers loses values in TPieces* boundary = new Sphere(); in getSphere in GeoPar.cpp and/or TPiecesNS::TPieces* boundary = new TPiecesNS::Sphere(); in PosLin.cpp
In one case you have both functions using the same boundary object. In the other case each function uses a fresh boundary object.
You haven't shown what the TPieces class does, but I assume that addPoint and addFacet change the contents of the TPieces class, such that when you write the faces to the file in the second call, you end up getting the faces that were saved in the first call.
To make the two cases work the same, try using a different boundary object in the second call. Something like this:
TPiecesNS::GeoPar* perform = new TPiecesNS::GeoPar();
TPiecesNS::TPieces* boundary = new TPiecesNS::Sphere();
boundary->sphere = perform->SurTriAuto(boundary, geo,0);//if I comment this line out and the line below and un-comment the 2 getSphere lines below, they do not produce the same output
TPiecesNS::TPieces* boundary2 = new TPiecesNS::Sphere();
boundary->sphereDark[0] = perform->SurTriAuto(boundary2, geo,0);
//boundary->sphere = perform->getSphere(geo,0);
//boundary->sphereDark[0] = perform->getSphere(geo,0);
The following C++ code (as is) is from http://rosettacode.org/wiki/Entropy. There are mistakes - can anyone correct them?
#include <string>
#include <map>
#include <iostream>
#include <algorithm>
#include <cmath>
double log2( double number ) {
return log( number ) / log( 2 ) ;
}
int main( int argc , char *argv[ ] ) {
std::string teststring( argv[ 1 ] ) ;
std::map<char , int> frequencies ;
for ( char c : teststring )
frequencies[ c ] ++ ;
int numlen = teststring.length( ) ;
double infocontent = 0 ;
for ( std::pair<char , int> p : frequencies ) {
double freq = static_cast<double>( p.second ) / numlen ;
infocontent += freq * log2( freq ) ;
}
infocontent *= -1 ;
std::cout << "The information content of " << teststring
<< " is " << infocontent << " !\n" ;
return 0 ;
}
The first error seems to be fixed with:
double log2( double n )
{
// log(n)/log(2) is log2.
return log( n ) / log( 2. );
}
I'm unsure what they are trying to say with:
for ( char c : teststring )
This one work nice
template <typename T> static float ShannonEntropy(T data[],int elements){
float entropy=0;
std::map<T,long> counts;
typename std::map<T,long>::iterator it;
//
for (int dataIndex = 0; dataIndex < elements; ++dataIndex) {
counts[data[dataIndex]]++;
}
//
it = counts.begin();
while(it != counts.end()){
float p_x = (float)it->second/elements;
if (p_x>0) entropy-=p_x*log(p_x)/log(2);
it++;
}
return entropy;
}
The loop is a foreach loop. It means: For each character in teststring, put it into the variable c and do the loop body.
The same can be expressed with a regular for-loop and an index variable, but this way is much shorter and easier to read. Other languages like C# and Java had this for a long time, but C++ only had some template feature in the STL that were not as readable.
This is a new feature of C++ 11 and your compiler will complain if it's not compatible. If you get errors, try to get a better compiler.
Here is my java code for entropy of image
public static double getShannonEntropy_Image(BufferedImage actualImage){
List<String> values= new ArrayList<String>();
int n = 0;
Map<Integer, Integer> occ = new HashMap<>();
for(int i=0;i<actualImage.getHeight();i++){
for(int j=0;j<actualImage.getWidth();j++){
int pixel = actualImage.getRGB(j, i);
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
//0.2989 * R + 0.5870 * G + 0.1140 * B greyscale conversion
//System.out.println("i="+i+" j="+j+" argb: " + alpha + ", " + red + ", " + green + ", " + blue);
int d= (int)Math.round(0.2989 * red + 0.5870 * green + 0.1140 * blue);
if(!values.contains(String.valueOf(d)))
values.add(String.valueOf(d));
if (occ.containsKey(d)) {
occ.put(d, occ.get(d) + 1);
} else {
occ.put(d, 1);
}
++n;
}
}
double e = 0.0;
for (Map.Entry<Integer, Integer> entry : occ.entrySet()) {
int cx = entry.getKey();
double p = (double) entry.getValue() / n;
e += p * log2(p);
}
return -e;
}
The first error is because of the fiasco regarding names from the C library. It's not specified which overloads of log are dumped into the global namespace; presumably, the author's implementation only had one, so that log(2) is unambiguous, but yours has all of them, giving an ambiguity since there isn't one that takes type int. For portability, it should be std::log(2.). Better still, use std::log2 rather than reinventing it.
The second is a "range-based for statement", introduced to the language in 2011, which iterates over each element of an array, container, or other sequence. You'll need a reasonably modern compiler, and you may need to specifically enable C++11 support. For example, with GCC, you need the command-line argument -std=c++11 (or c++0x with older versions).
The above generic answer is very good, but for the particular case of strings, this one is simpler:
#include <cmath>
#include <string>
float shannon_entropy(const std::string & s)
{
int counts[256] = {};
for (unsigned char c: s)
{
counts[c]++;
}
float entropy = 0;
float length = (float)s.size();
for (int count: counts)
{
if (count == 0)
continue;
float p = (float)count / length;
entropy -= p * std::log2f(p);
}
return entropy;
}
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.