1

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;
bean
  • 157
  • 6
  • I think there is a std::algorithm to do this. – 463035818_is_not_an_ai May 07 '15 at 15:16
  • @tobi303: I guess you mean [std::rotate](http://en.cppreference.com/w/cpp/algorithm/rotate)? – cfh May 07 '15 at 15:20
  • @cfh I tried, but actually I wouldnt know how to do this with std::algorithms without creating an unesessary copy of one of the vectors. Maybe you know? In the meantime I implemented it by wrapping the vector and overriding some iterator operators. (btw I am also making a copy in the constructor, but this could be fixed easily) – 463035818_is_not_an_ai May 07 '15 at 18:30
  • Honestly, the type of interface implied in my question probably doesn't make all that much sense. If the vector push function were simply a.push(b), taking a reference to the eigen type, then the internal implementation would me much simpler, and that interface makes more sense. On the other hand, if it were desired to simply index a segment of the circular buffer as an eigen type, like a.HeadSegment(Len) (a segment that would potentially wrap), then an answer to the above would be helpful to achieve this. The goal is to use eigen types as much as possible, to utilize the SIMD optimizations. – bean May 08 '15 at 03:07
  • I am not sure if I completely understand you... Did you take a look at my answer? In principle you can wrap also containers from Eigen, not only a vector. – 463035818_is_not_an_ai May 08 '15 at 10:07

2 Answers2

2

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 (e.g. for(it=begin();it<end();it++) would be an infinite loop. However, those are not needed to use it as input/output iterator.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

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;
}
florestan
  • 4,405
  • 2
  • 14
  • 28