5
\$\begingroup\$

i'm rewriting some Matlab code to c++ using armadillo, a libs for linear algebra. really good libs, IMHO. but i had to translate some matlab construct because armadillo isn't matlab.

i want to share my little snippet because i think there should be a better way (in terms of speed, mainly) to solve thoose little problems. i hope someone here could help me to improve my code!

static mat log(mat A) {
    /*
     * log function operates element-wise on matrix A
     * MATLAB code> log(A)
     */
    mat X(A);
    mat::iterator a = X.begin();
    mat::iterator b = X.end();

    for(mat::iterator i=a; i!=b; ++i) {
        (*i) = log(*i);
    }
    return X;
}

-

static mat vectorize(mat A) {
    /*
     * vectorise a matrix (ie. concatenate all the columns or rows)
     * MATLAB code> A(:)
     */
    mat B = mat(A);
    B.reshape(B.n_rows*B.n_cols, 1);
    return B;
}

-

static bool any(mat X, double n) {
    /*
     * check if there are some n in X
     * MATLAB code> any(X==n)
     * TODO: i'm not sure of description but it works for me
     */
    uvec _s = find(, n);
    if ( _s.is_empty() ) 
        return true;
    else
        return false;
}

-

static double sum(mat X) {
    /*
     * sum a matrix
     * MATLAB code> sum(X)
     */
    return sum(sum(X))
}

-

static field<rowvec num2cell(mat X) {
    /*
     *  converts matrix X into field by placing each row of X into a separate row
     *  this method assume that a cell is a field<rowvec>, mayebe a template should be used to generalize..
     *  MATLAB code> num2cell(X)
     */
    field<rowvec> data1(X.n_rows,1);
for (uint r = 0; r < X.n_rows; ++r) {
    data1(r,0) = X.row(r);
}
    return data1;
}
\$\endgroup\$

3 Answers 3

7
\$\begingroup\$
  1. You're doing a copy in most of those snippets: if it was possible to do without a copy, it could be faster. Libraries such as Boost often offer two versions of a specific function: one which copies and another one which modifies in place.

  2. *i is enough, you don't need (*i):

    *i = log(*i);
    
  3. This code:

    if ( _s.is_empty() ) 
        return true;
    else
        return false;
    

    can be written as:

    return _s.is_empty();
    
\$\endgroup\$
4
\$\begingroup\$

For new users coming to this page, Armadillo has come a long way since 2012. All of these functions have native Armadillo implementations.

Armadillo has had element-wise functions since inception I think (someone please correct me): log(A), log2(A), and log10(A):

using namespace arma;
// Generate a matrix with the elements set to random floating point values
// randu() uses a uniform distribution in the [0,1] interval 
mat A = randu<mat>(5,5);    // or mat A(5, 5, fill::randu);
mat B = log(A);

Added any and vectorize in version 3.910:

vec V = randu<vec>(10);
mat X = randu<mat>(5,5);


// status1 will be set to true if vector V has any non-zero elements
bool status1 = any(V);

// status2 will be set to true if vector V has any elements greater than 0.5
bool status2 = any(V > 0.5);

// status3 will be set to true if matrix X has any elements greater than 0.6;
// note the use of vectorise()
bool status3 = any(vectorise(X) > 0.6);

// generate a row vector indicating which columns of X have elements greater than 0.7
urowvec A = any(X > 0.7);

Added accu before version 4.6:

mat A(5, 6, fill::randu); // fill matrix with random values
mat B(5, 6, fill::randu);
double x = accu(A);
double y = accu(A % B);  // "multiply-and-accumulate" operation
                         // operator % performs element-wise multiplication

The accu function 'accumulates a sum', while the sum function generates a row or column vector that is the sum of the specified matrix dimension. For a column vector, the sum of the elements is returned:

colvec v = randu<colvec>(10,1);
double x = sum(v);

mat    M = randu<mat>(10,10);

rowvec a = sum(M);
rowvec b = sum(M,0);
colvec c = sum(M,1);

double y = accu(M);   // find the overall sum regardless of object type

And Armadillo has its own field class template:

using namespace arma;
mat A = randn(2,3);
mat B = randn(4,5);

field<mat> F(2,1);
F(0,0) = A;
F(1,0) = B; 

F.print("F:");
F.save("mat_field");
\$\endgroup\$
3
\$\begingroup\$

Cannot say much about the speed, but here are two observations:

  • Your implementation of any appears to give true and false in the opposite way that Matlab would give them.

  • If you want to mimic the n dimensional matrix sum in Matlab, the output should not be a number but a n-1 dimensional matrix. In case of a 'regular' matrix the output should be a vector.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.