简体   繁体   中英

Access column of matrix without creating copy of data, using Armadillo library

I have a (data/storage) class with a member arma::mat (a matrix), and I want to access just one column of this matrix ( arma::colvec ), but I don't want to create a copy of the data in the column. Is there any way of achieving this?

My first try was using .col(i) , but this returns a temporary, so taking a reference doesn't work.

Using .colptr(i) doesn't create a copy, but it also returns a double* instead of a vec , so it makes my life a bit hard.

struct Data
{
    mat A;

    /* constructors etc. */

    // reference to temporary (this is bad)
    const vec& getColumn(const uint i) { return A.col(i); }

    // doesn't create a copy, but doesn't return a vec either
    const double* getColumn2(const uint i) const { return A.colptr(i); }
}

The reason for wanting this is that the class has both vectors and matrices, and I want to make uniform getter and setter methods that access either one of the vectors, or a column in a matrix, depending on an index (for iteration purposes).

An example:

struct Data
{
    mat A;
    vec b;

    // getter
    const vec& operator()(const uint i) const
    {
        if (i == 0)
        {
            return b;
        }
        else if (i == 1)
        {
            // return first column of A
        }
        // etc.
    }

    // setter
    vec& operator()(const uint i)
    {
        // similar to above
    }
}

Solution

Based on the answer by zauguin I found the following way to achieve the wanted functionality:

struct Data
{
    mat A;
    vec b;

    // getter
    subview_col<mat::elem_type> operator()(const uint i)
    {
        if (i == 0)
        {
            return b.col(0);
        }
        else if (i > 0 && i < (1 + A.n_cols()))
        {
            return A.col(i - 1);
        }
        else
        {
            // should probably do some error checking here
        }
    }

    // setter
    vec& operator()(const uint i)
    {
        // same as the above, but without consts in declaration
    }
}

This returns subview_col<mat::elem_type> instead of vec , but the functionality is similar/identical for my purposes. I am not sure of the performance impact of using .col(0) on a vec , but I'm not that worried.

In arma, A.col(i) doesn't return a reference, but a temporary. You can return this temporary to get reference semantics. With C++14, just write

    auto getColumn(const uint i) { return A.col(i); }

Otherwise, you have to return the proxy type, it is

    subview_col<mat::elem_type> getColumn(const uint i) { return A.col(i); }

If you have to return a vec instead of a subview_col<...> , you can use A.unsafe_col(i) , but you have to be sure, that you don't try to use it, after the lifetime of A ended. see here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM