Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ stl convolution

Is there a nice implementation of the algorithm to calculate the convolution of two ranges in C++ STL (or even boost)? i.e. something with prototype (convolution of two ranges a..b and c..d):

template< class Iterator >
void convolution(Iterator a, Iterator b, Iterator c, Iterator d);

which modifies a..b range

like image 537
Tomilov Anatoliy Avatar asked Nov 16 '12 04:11

Tomilov Anatoliy


2 Answers

Yes std::transform

std::transform(a, b, c, a, Op);

// a b is the the first input range
// c   is the start of the second range (which must be at least as large as (b-a)
// 
// We then use a as the output iterator as well.

// Op is a BinaryFunction

To answer the comment on how to perform accumulation of state in the comments:

struct Operator
{
    State& state;
    Operator(Sate& state) : state(state) {}
    Type operator()(TypeR1 const& r1Value, TypeR2 const& r2Value) const
    {
        Plop(state, r1Value, r2Value);
        return Convolute(state, r2Value, r2Value);
    }
};
State  theState  = 0;
Operator Op(theState);
like image 123
Martin York Avatar answered Oct 22 '22 12:10

Martin York


I'm not quite sure what a "convolution" from two sequences to one of these two sequences is supposed to be: It seems to be a different understanding than my understanding. Below is a version of convolution using a variable number of iterators. Because I'm actually just too lazy for now, I'll use a somewhat uncommon notion of passing the destination iterator as first argument rather than as last argument. Here is an implementation of a corresponding zip() algorithms:

#include <tuple>

namespace algo
{
    template <typename... T>
    void dummy(T...)
    {
    }

    template <typename To, typename InIt, typename... It>
    To zip(To to, InIt it, InIt end, It... its)
    {
        for (; it != end; ++it, ++to) {
            *to = std::make_tuple(*it, *its...);
            algo::dummy(++its...);
        }
        return to;
    }
}    

Below is a simple test program I used to verify that the above does what I intended it to do:

#include <deque>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>

enum class e { a = 'a', b = 'b', c = 'c' };

std::ostream& operator<< (std::ostream& out,
                          std::tuple<int, double, e> const& v)
{
    return out << "["
               << std::get<0>(v) << ", "
               << std::get<1>(v) << ", "
               << char(std::get<2>(v)) << "]";
}

int main()
{
    typedef std::tuple<int, double, e> tuple;
    std::vector<int>   v{ 1, 2, 3 };
    std::deque<double> d{ 1.1, 2.2, 3.3 };
    std::list<e>       l{ e::a, e::b, e::c };
    std::vector<tuple> r;

    algo::zip(std::back_inserter(r), v.begin(), v.end(), d.begin(), l.begin());

    std::copy(r.begin(), r.end(),
              std::ostream_iterator<tuple>(std::cout, "\n"));
}                                        
like image 41
Dietmar Kühl Avatar answered Oct 22 '22 13:10

Dietmar Kühl