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.
Related
So I have this test case and am trying to no have to make one million operator overloads or handle overload collisions or complexity. I want to be able to handle literal array constants with operator overloads. This is sort of a requirement to create ease of use for an intended library (this test case shoots in the same direction.)
I am looking for a solution to being able to add, subtract variable length carray literal constants. I have a few solutions, one that works but only if both C_COORDS and N_COORDS are more than one. I am using defines instead of Templates to simplify the test case but those defines would be replaced with Templates in the final hour.
Any suggestions welcome. Note, I'm sure I could make this more clear but can't see how at the moment. I use to do lots of C programming 30 years ago. But haven't touched CPP much since then, yes I understand CPP mostly and the differences between it and old C, but not much experience yet. I am just noting because I am sure I am missing a few OBVIOUS things. Thanks. My testcase follows....
/** Coord.cpp */
#include <iostream>
#include <cstring>
#include <initializer_list>
#include <cassert>
#define T_COORDS float // the type of coordinates
#define N_COORDS (2) // the coordinates per item
#define C_COORDS (2) // the number of coordinate items
#define L_COORDS (N_COORDS*C_COORDS) // the number of coordinate items
using namespace std;
class Coords {
public:
T_COORDS coords[L_COORDS];
Coords()
{
memset(this->coords, 0, sizeof(Coords));
}
Coords(const T_COORDS inits[L_COORDS])
{
memmove(this->coords, &inits, sizeof(Coords));
}
Coords(initializer_list<T_COORDS> inits) : coords{}
{
copy( inits.begin(), next( inits.begin(), L_COORDS ), coords );
}
friend Coords operator + (const Coords &coords0, const Coords &coords1)
{
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1.coords[i];
return result;
}
/* original that complains about taking size from a temporary array. the next
* 2 UNCOMMENTED overloads accept a fixed length array, but then I have to
* have for every case and they cannot overlap.
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
*/
/* bad solution was to make to overloads that match of a fixed length array,
* however it sucks because if N_COORDS is 1, then it also won't compile
* because it ends up with duplicate overloads as L_COORDS is equal to
* C_COORDS when N_COORDS is one, and same is true is C_COORDS is one.
* WHat I hope for is a way to accept any array or at least any array with a
* length >= and on boundaries of C_COORDS and not more the L_COORDS */
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[C_COORDS])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
/* as above, so below but for different size array */
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[L_COORDS])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
};
void print_coords(const char* label, Coords coords)
{
cout << label << ": ( " << coords.coords[0];
for (int i=1; i < L_COORDS; i++) {
cout << ", " << coords.coords[i];
}
cout << " }" << endl;
};
int main () {
Coords coords0;
print_coords("coords0", coords0);
Coords coords1 {4,5,6,7};
print_coords("coords1", coords1);
Coords coords2 {8,9,10,11};
print_coords("coords2", coords2);
Coords coords3 = coords1 + coords2;
print_coords("coords3", coords3);
T_COORDS tmp[] = {-2,-2,-2,-2};
Coords coords4 = coords3 + tmp;
print_coords("coords4", coords4);
T_COORDS tmp2[] = {-2,-2};
Coords coords5 = coords4 + tmp2;
print_coords("coords5", coords5);
Coords coords6 = coords5 + (T_COORDS[]){10,20,30,40};
print_coords("coords6", coords6);
Coords coords7 = coords6 + (T_COORDS[]){10,20};
print_coords("coords7", coords7);
/* this won't compile with fixes length overloads because it don't match and thats ok.
try {
Coords coords8 = coords7 + (T_COORDS[]){10,20,30};
print_coords("coords8", coords8);
} catch (const char* msg) {
cout << "threw exception on 3 coordinates as expected" << endl;
}
*/
cout << "Done!" << endl;
return 0;
}
/**
* g++ Coord.cpp -o coord
* ./coord
* RESULING OUTPUT:
* coords0: ( 0, 0, 0, 0 }
* coords1: ( 4, 5, 6, 7 }
* coords2: ( 8, 9, 10, 11 }
* coords3: ( 12, 14, 16, 18 }
* n = 4
* coords4: ( 10, 12, 14, 16 }
* n = 2
* coords5: ( 8, 10, 12, 14 }
* n = 4
* coords6: ( 18, 30, 42, 54 }
* n = 2
* coords7: ( 28, 50, 52, 74 }
* Done!
*/
const T_COORDS (& coords1)[] is array of unknown bound. you know the size, so it is not what you want.
You might use template:
template <std::size_t N>
// SFINAE, instead of throw
// care, then Coords+Coords is viable and no exception in Coords(initializer_list)
// For invalid size
/*, std::enable_if_t<N != 0 && N <= L_COORDS && N % N_COORDS == 0, bool> = false*/>
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[N])
{
if ( ! N || N > L_COORDS || N % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
std::cout << "n = " << N << std::endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%N];
return result;
}
Demo
I am trying to build a spars Matrix using a Eigen or Armadillo library in C++ to solve a system of linear equations Ax=b. A is the coefficient matrix with a dimension of n*n, and B is a vector of right hand side with a dimension of n
the Spars Matrix A is like this, see the figure
I had a look though the Eigen document but I have a problem with defining and filling the Spars Matrix in C++.
could you please give me an example code to define the spars matrix and how to fill the values into the matrix using Eigen library in c++?
consider for example a simple spars matrix A:
1 2 0 0
0 3 0 0
0 0 4 5
0 0 6 7
int main()
{
SparseMatrix<double> A;
// fill the A matrix ????
VectorXd b, x;
SparseCholesky<SparseMatrix<double> > solver;
solver.compute(A);
x = solver.solve(b);
return 0;
}
The sparse matrix could be filled with the values mentioned in the post by using the .coeffRef() member function, as shown in this routine:
SparseMatrix<double> fillMatrix() {
int N = 4;
int M = 4;
SparseMatrix<double> m1(N,M);
m1.reserve(VectorXi::Constant(M, 4)); // 4: estimated number of non-zero enties per column
m1.coeffRef(0,0) = 1;
m1.coeffRef(0,1) = 2.;
m1.coeffRef(1,1) = 3.;
m1.coeffRef(2,2) = 4.;
m1.coeffRef(2,3) = 5.;
m1.coeffRef(3,2) = 6.;
m1.coeffRef(3,3) = 7.;
m1.makeCompressed();
return m1;
}
However, the SparseCholesky module (SimplicialCholesky<SparseMatrix<double> >) won't work in this case because the matrix is not Hermitian. The system could be solved with a LU or BiCGStab solver. Also note that sizes ofx and b need to be defined:
VectorXd b(A.rows()), x(A.cols());
In case of larger sparse matrices you may also want to look at the .reserve() function in order to allocate memory before filling the elements. The .reserve() function can be used to provide an estimate of the number of non-zero entries per column (or row, depending on the storage order. The default is comumn-major). In the example above that estimate is 4, but it does not make sense in such a small matrix. The documentation states that it is preferable to overestimate the number of non-zeros per column.
Since this question also asks about Armadillo, here is the corresponding Armadillo-based code. Best to use Armadillo version 9.100+ or later, and link with SuperLU.
#include <armadillo>
using namespace arma;
int main()
{
sp_mat A(4,4); // don't need to explicitly reserve the number of non-zeros
// fill with direct element access
A(0,0) = 1.0;
A(0,1) = 2.0;
A(1,1) = 3.0;
A(2,2) = 4.0;
A(2,3) = 5.0;
A(3,2) = 6.0;
A(3,3) = 7.0; // etc
// or load the sparse matrix from a text file with the data stored in coord format
sp_mat AA;
AA.load("my_sparse_matrix.txt", coord_ascii)
vec b; // ... fill b here ...
vec x = spsolve(A,b); // solve sparse system
return 0;
}
See also the documentation for SpMat, element access, .load(), spsolve().
The coord file format is simple. It stores non-zeros values.
Each line contains:
row col value
The row and column counts start at zero. Example:
0 0 1.0
0 1 2.0
1 1 3.0
2 2 4.0
2 3 5.0
3 2 6.0
3 3 7.0
1000 2000 9.0
Values not explicitly listed are assumed to be zero.
#include <vector>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/Core>
#include <cstdlib>
using namespace Eigen;
using namespace std;
int main()
{
double L = 5; // Length
const int N = 120; // No of cells
double L_cell = L / N;
double k = 100; // Thermal Conductivity
double T_A = 100.;
double T_B = 200.;
double S = 1000.;
Vector<double, N> d, D, A, aL, aR, aP, S_u, S_p;
vector<double> xp;
xp.push_back((0 + L_cell) / 2.0);
double xm = xp[0];
for (int i = 0; i < N - 1; i++)
{
xm = xm + L_cell;
xp.push_back(xm);
}
for (int i = 0; i < N; i++)
{
A(i) = .1;
d(i) = L_cell;
D(i) = k / d(i);
}
aL(0) = 0;
aR(0) = D(0) * A(0);
S_p(0) = -2 * D(0) * A(0);
aP(0) = aL(0) + aR(0) - S_p(0);
S_u(0) = 2 * D(0) * A(0) * T_A + S * L_cell * A(0);
for (int i = 1; i < N - 1; i++)
{
aL(i) = D(i) * A(i);
aR(i) = D(i) * A(i);
S_p(i) = 0;
aP(i) = aL(i) + aR(i) - S_p(i);
S_u(i) = S * A(i) * L_cell;
}
aL(N - 1) = D(N - 1) * A(N - 1);
aR(N - 1) = 0;
S_p(N - 1) = -2 * D(N - 1) * A(N - 1);
aP(N - 1) = aL(N - 1) + aR(N - 1) - S_p(N - 1);
S_u(N - 1) = 2 * D(N - 1) * A(N - 1) * T_B + S * L_cell * A(N - 1);
typedef Eigen::Triplet<double> T;
std::vector<T> tripletList;
tripletList.reserve(N * 3);
Matrix<double, N, 3> v; // v is declared here
v << (-1) * aL, aP, (-1) * aR;
for (int i = 0, j = 0; i < N && j < N; i++, j++)
{
tripletList.push_back(T(i, j, v(i, 1)));
if (i + 1 < N && j + 1 < N)
{
tripletList.push_back(T(i + 1, j, v(i + 1, 0)));
tripletList.push_back(T(i, j + 1, v(i, 2)));
}
}
SparseMatrix<double> coeff(N, N);
coeff.setFromTriplets(tripletList.begin(), tripletList.end());
SimplicialLDLT<SparseMatrix<double> > solver;
solver.compute(coeff);
if (solver.info() != Success) {
cout << "decomposition failed" << endl;
return;
}
Vector<double, N> temparature;
temparature = solver.solve(S_u);
if (solver.info() != Success)
{
cout << "Solving failed" << endl;
return;
}
vector<double> Te = {}, x = {};
Te.push_back(T_A);
x.push_back(0);
for (int i = 0; i < N; i++)
{
Te.push_back(temparature(i));
x.push_back(xp[i]);
}
Te.push_back(T_B);
x.push_back(L);
for (int i = 0; i < N + 2; i++)
{
cout << x[i] << " " << Te[i] << endl;
}
return 0;
}
Here is a full code of a solution to numerical problem which uses SparseMatrix. Look at the matrix v. It has the values of all the nonzero elements of coeff matrix yet to be defined. In the next loop I made a series of tripletList.push_back(...) adding a triplet consisting of row and column index and corresponding value taken from v for each non-zero element of coeff. Now declare a Sparse Matrix coeff with appropriate size and use the method setFromTriplets (documentation) to set its non-zero elements from tripletList triplets.
I have a vector with digits of number, vector represents big integer in system with base 2^32. For example:
vector <unsigned> vec = {453860625, 469837947, 3503557200, 40}
This vector represent this big integer:
base = 2 ^ 32
3233755723588593872632005090577 = 40 * base ^ 3 + 3503557200 * base ^ 2 + 469837947 * base + 453860625
How to get this decimal representation in string?
Here is an inefficient way to do what you want, get a decimal string from a vector of word values representing an integer of arbitrary size.
I would have preferred to implement this as a class, for better encapsulation and so math operators could be added, but to better comply with the question, this is just a bunch of free functions for manipulating std::vector<unsigned> objects. This does use a typedef BiType as an alias for std::vector<unsigned> however.
Functions for doing the binary division make up most of this code. Much of it duplicates what can be done with std::bitset, but for bitsets of arbitrary size, as vectors of unsigned words. If you want to improve efficiency, plug in a division algorithm which does per-word operations, instead of per-bit. Also, the division code is general-purpose, when it is only ever used to divide by 10, so you could replace it with special-purpose division code.
The code generally assumes a vector of unsigned words and also that the base is the maximum unsigned value, plus one. I left a comment wherever things would go wrong for smaller bases or bases which are not a power of 2 (binary division requires base to be a power of 2).
Also, I only tested for 1 case, the one you gave in the OP -- and this is new, unverified code, so you might want to do some more testing. If you find a problem case, I'll be happy to fix the bug here.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
namespace bigint {
using BiType = std::vector<unsigned>;
// cmp compares a with b, returning 1:a>b, 0:a==b, -1:a<b
int cmp(const BiType& a, const BiType& b) {
const auto max_size = std::max(a.size(), b.size());
for(auto i=max_size-1; i+1; --i) {
const auto wa = i < a.size() ? a[i] : 0;
const auto wb = i < b.size() ? b[i] : 0;
if(wa != wb) { return wa > wb ? 1 : -1; }
}
return 0;
}
bool is_zero(BiType& bi) {
for(auto w : bi) { if(w) return false; }
return true;
}
// canonize removes leading zero words
void canonize(BiType& bi) {
const auto size = bi.size();
if(!size || bi[size-1]) return;
for(auto i=size-2; i+1; --i) {
if(bi[i]) {
bi.resize(i + 1);
return;
}
}
bi.clear();
}
// subfrom subtracts b from a, modifying a
// a >= b must be guaranteed by caller
void subfrom(BiType& a, const BiType& b) {
unsigned borrow = 0;
for(std::size_t i=0; i<b.size(); ++i) {
if(b[i] || borrow) {
// TODO: handle error if i >= a.size()
const auto w = a[i] - b[i] - borrow;
// this relies on the automatic w = w (mod base),
// assuming unsigned max is base-1
// if this is not the case, w must be set to w % base here
borrow = w >= a[i];
a[i] = w;
}
}
for(auto i=b.size(); borrow; ++i) {
// TODO: handle error if i >= a.size()
borrow = !a[i];
--a[i];
// a[i] must be set modulo base here too
// (this is automatic when base is unsigned max + 1)
}
}
// binary division and its helpers: these require base to be a power of 2
// hi_bit_set is base/2
// the definition assumes CHAR_BIT == 8
const auto hi_bit_set = unsigned(1) << (sizeof(unsigned) * 8 - 1);
// shift_right_1 divides bi by 2, truncating any fraction
void shift_right_1(BiType& bi) {
unsigned carry = 0;
for(auto i=bi.size()-1; i+1; --i) {
const auto next_carry = (bi[i] & 1) ? hi_bit_set : 0;
bi[i] >>= 1;
bi[i] |= carry;
carry = next_carry;
}
// if carry is nonzero here, 1/2 was truncated from the result
canonize(bi);
}
// shift_left_1 multiplies bi by 2
void shift_left_1(BiType& bi) {
unsigned carry = 0;
for(std::size_t i=0; i<bi.size(); ++i) {
const unsigned next_carry = !!(bi[i] & hi_bit_set);
bi[i] <<= 1; // assumes high bit is lost, i.e. base is unsigned max + 1
bi[i] |= carry;
carry = next_carry;
}
if(carry) { bi.push_back(1); }
}
// sets an indexed bit in bi, growing the vector when required
void set_bit_at(BiType& bi, std::size_t index, bool set=true) {
std::size_t widx = index / (sizeof(unsigned) * 8);
std::size_t bidx = index % (sizeof(unsigned) * 8);
if(bi.size() < widx + 1) { bi.resize(widx + 1); }
if(set) { bi[widx] |= unsigned(1) << bidx; }
else { bi[widx] &= ~(unsigned(1) << bidx); }
}
// divide divides n by d, returning the result and leaving the remainder in n
// this is implemented using binary division
BiType divide(BiType& n, BiType d) {
if(is_zero(d)) {
// TODO: handle divide by zero
return {};
}
std::size_t shift = 0;
while(cmp(n, d) == 1) {
shift_left_1(d);
++shift;
}
BiType result;
do {
if(cmp(n, d) >= 0) {
set_bit_at(result, shift);
subfrom(n, d);
}
shift_right_1(d);
} while(shift--);
canonize(result);
canonize(n);
return result;
}
std::string get_decimal(BiType bi) {
std::string dec_string;
// repeat division by 10, using the remainder as a decimal digit
// this will build a string with digits in reverse order, so
// before returning, it will be reversed to correct this.
do {
const auto next_bi = divide(bi, {10});
const char digit_value = static_cast<char>(bi.size() ? bi[0] : 0);
dec_string.push_back('0' + digit_value);
bi = next_bi;
} while(!is_zero(bi));
std::reverse(dec_string.begin(), dec_string.end());
return dec_string;
}
}
int main() {
bigint::BiType my_big_int = {453860625, 469837947, 3503557200, 40};
auto dec_string = bigint::get_decimal(my_big_int);
std::cout << dec_string << '\n';
}
Output:
3233755723588593872632005090577
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;
}
I have a dynamic programming algorithm for Knapsack in C++. When it was implemented as a function and accessing variables passed into it, it was taking 22 seconds to run on a particular instance. When I made it the member function of my class KnapsackInstance and had it use variables that were data members of that class, it started taking 37 seconds to run. As far as I know, only accessing member functions goes through the vtable so I'm at a loss to explain what might be happening.
Here's the code of the function
int KnapsackInstance::dpSolve() {
int i; // Current item number
int d; // Current weight
int * tbl; // Array of size weightLeft
int toret;
tbl = new int[weightLeft+1];
if (!tbl) return -1;
memset(tbl, 0, (weightLeft+1)*sizeof(int));
for (i = 1; i <= numItems; ++i) {
for (d = weightLeft; d >= 0; --d) {
if (profitsWeights.at(i-1).second <= d) {
/* Either add this item or don't */
int v1 = profitsWeights.at(i-1).first + tbl[d-profitsWeights.at(i-1).second];
int v2 = tbl[d];
tbl[d] = (v1 < v2 ? v2 : v1);
}
}
}
toret = tbl[weightLeft];
delete[] tbl;
return toret;
}
tbl is one column of the DP table. We start from the first column and go on until the last column. The profitsWeights variable is a vector of pairs, the first element of which is the profit and the second the weight. toret is the value to return.
Here is the code of the original function :-
int dpSolve(vector<pair<int, int> > profitsWeights, int weightLeft, int numItems) {
int i; // Current item number
int d; // Current weight
int * tbl; // Array of size weightLeft
int toret;
tbl = new int[weightLeft+1];
if (!tbl) return -1;
memset(tbl, 0, (weightLeft+1)*sizeof(int));
for (i = 1; i <= numItems; ++i) {
for (d = weightLeft; d >= 0; --d) {
if (profitsWeights.at(i-1).second <= d) {
/* Either add this item or don't */
int v1 = profitsWeights.at(i-1).first + tbl[d-profitsWeights.at(i-1).second];
int v2 = tbl[d];
tbl[d] = (v1 < v2 ? v2 : v1);
}
}
}
toret = tbl[weightLeft];
delete[] tbl;
return toret;
}
This was run on Debian Lenny with g++-4.3.2 and -O3 -DNDEBUG turned on
Thanks
In a typical implementation, a member function receives a pointer to the instance data as a hidden parameter (this). As such, access to member data is normally via a pointer, which may account for the slow-down you're seeing.
On the other hand, it's hard to do more than guess with only one version of the code to look at.
After looking at both pieces of code, I think I'd write the member function more like this:
int KnapsackInstance::dpSolve() {
std::vector<int> tbl(weightLeft+1, 0);
std::vector<pair<int, int> > weights(profitWeights);
int v1;
for (int i = 0; i <numItems; ++i)
for (int d = weightLeft; d >= 0; --d)
if ((weights[i+1].second <= d) &&
((v1 = weights[i].first + tbl[d-weights[i-1].second])>tbl[d]))
tbl[d] = v1;
return tbl[weightLeft];
}