简体   繁体   中英

Eigen C++ wrapping assignment

In Matlab, it is possible to do the following:

% init
a =  1:10;
b = 18:23;

% wrapping assignment
a([8:end 1:3]) = b;

Is something like this possible with Eigen? I'm hoping to make a member function for a circular buffer class that returns some reference to an Eigen type, perhaps something like:

VectorXd b(5);
b << 1,2,3,4,5 ;
CircularBuf a( 6 /*capacity*/ );
a.push(1);a.push(2);a.push(3);
// 3 elements in buf
a.pop();a.pop();
// 1 element in buf
// next line probably wraps around internal buffer, depending on impl
a.pushRef( b.size() /*number of elements in ref*/ ) = b;

I am not sure if this is what you are looking for...Following an answer I got from Jerry Coffin , I came up with this:

#include <iostream> 
#include <vector>
#include <iterator>
template <class T>
class CircularVector {
    typedef std::vector<T> DVector;
public:
    CircularVector(const DVector& v) : v(v){}
    T at(int i){return v.at(i);}
    int size(){return v.size();}
    class iterator : 
      public std::iterator < std::random_access_iterator_tag, T > {
        CircularVector *vec;
        int index;
    public:
        iterator(CircularVector &d, int index) : vec(&d), index(index) {}
        iterator &operator++() { nextIndex(); return *this; }
        iterator operator++(int) { 
            iterator tmp(*vec, index); nextIndex(); return tmp; 
        }
        iterator operator+(int off) { 
            return iterator(*vec, (index + off)%vec->size()); 
        }
        iterator operator-(int off) { 
            return iterator(*vec, (index - off + vec->size())%vec->size()); 
        }
        T& operator*() { return (*vec).v[index];   }
        bool operator!=(iterator const &other) { return index != other.index; }
        //bool operator<(iterator const &other) { return index < other.index; }
    private:
        void nextIndex(){
            ++index;
            if (index==vec->size()){index=0;}
        }
    };
    iterator begin() { return iterator(*this, 0); }
    //iterator end() { return iterator(*this, size()); }
private:
    DVector v;
};

Your first example then can be written as:

int main() {
    std::vector<int> a;
    std::vector<int> b;
    for(int i=1;i<11;i++){a.push_back(i);}
    for(int i=18;i<24;i++){b.push_back(i);}

    CircularVector<int> ca(a);                   
    std::copy(b.begin(),b.end(),ca.begin()+7);    // copy elements starting 
                                                  // at index 8        
    for (int i=0;i<ca.size();i++){std::cout << ca.at(i) << std::endl;}
}

Actually, I was just curious to try it and I believe there are nicer ways to implement it. It is not the most efficient way to check if the index has to be wrapped each time it is increased. Obviously < and end() are not quite meaningful for a circular buffer and I decided not to implement them (eg for(it=begin();it<end();it++) would be an infinite loop. However, those are not needed to use it as input/output iterator.

I have another solution as described in my answer to this question . The code posted in the answer defines a custom expression for the circular shift, so you can benefit from Eigen's optimisations.

Given the circ_shift.h from the mentioned answer, you can do the following to achieve your goal: I hope this helps...

// main.cpp
#include "stdafx.h"
#include "Eigen/Core"
#include <iostream>
#include "circ_shift.h" // posted in the answer to the other quesiton.

using namespace Eigen;


int main()
{
    VectorXi a(10), b(6);

    a << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
    b << 18, 19, 20, 21, 22, 23;

    std::cout << "a = " << a.transpose() << std::endl << "b = " << b.transpose() << std::endl; 
    circShift(a, 3, 0).block(0, 0, b.size(), 1) = b;
    std::cout << "now: a = " << a.transpose() << std::endl; // prints 21, 22, 23, 4, 5, 6, 7, 18, 19, 20


    return 0;
}

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