C ++ boost or STL `y + = f (x)` algorithm

I know I can do this y[i] += f(x[i])

with a conversion with two input iterators. however, it seems to be somewhat controversial and more complex than the loop.

Is there a more natural way to do this using the existing algorithm in boost or Stl. I couldn't find a clean equivalent.

here's the transformation (y = y + a * x):

using boost::lambda;
transform(y.begin(), y.end(), x.begin(), y.begin(), (_1 + scale*_2);
//  I thought something may exist:
transform2(x.begin(), x.end(), y.begin(), (_2 + scale*_1);
// it does not, so no biggie. I will write wrapper

      

thanks

+2


a source to share


4 answers


There are several ways to do this.

As you noted, you can use transform

with a number of predicates, several more or less automatically generated:

std::vector<X> x = /**/;
std::vector<Y> y = /**/;

assert(x.size() == y.size());

//
// STL-way
//
struct Predicate: std::binary_function<X,Y,Y>
{
  Y operator()(X lhs, Y rhs) const { return rhs + f(lhs); }
};

std::transform(x.begin(), x.end(), y.begin(), y.begin(), Predicate());

//
// C++0x way
//
std::transform(x.begin(), x.end(), y.begin(), y.begin(),
               [](X lhs, Y rhs) { return rhs += f(lhs); });

      



Now, if we had vector

a range of indices, we could do it in a more "pythony" way:

std::vector<size_t> indices = /**/;


//
// STL-way
//
class Predicate: public std::unary_function<size_t, void>
{
public:
  Predicate(const std::vector<X>& x, std::vector<Y>& y): mX(x), mY(y) {}
  void operator()(size_t i) const { y.at(i) += f(x.at(i)); }
private:
  const std::vector<X>& mX;
  std::vector<Y>& mY;
};

std::foreach(indices.begin(), indices.end(), Predicate(x,y));

//
// C++0x way
//
std::foreach(indices.begin(), indices.end(), [&](size_t i) { y.at(i) += f(x.at(i)); });

//
// Boost way
//
BOOST_FOREACH(size_t i, indices) y.at(i) += f(x.at(i));

      

I don't know if there can be anything to do with views, they usually allow for some pretty syntax. Of course it's a little tricky, I think, due to self-modification y

.

+7


a source


Disclaimer . I have no practical experience with valarray, so please don't take this answer as "advice", but rather as "request for comments". In particular, I don't know how effective it would be. But I'm curious that the notation seems pretty intuitive to me:

If x and y are valarray<int>

and with a function int f(int)

, it will be:



y += x.apply(&f);

      

do what you want?

+3


a source


What's wrong with a simple loop?

for (size_t i = 0; i < n; ++i)
  y[i] += f(x[i]); 

      

In general, even in Fortran it will be:

forall(i=0:n) y(i) += f(x(i))

      

Although restrictions on f

, x

, y

it can be written as:

y += f(x)

      

transform()

the variant is more general and detailed:

std::transform(boost::begin(y), boost::end(y), boost::begin(x), 
               boost::begin(y), _1 += bind(f, _2)); 

      

Can be written zip()

with boost::zip_iterator

:

foreach (auto v, zip(y, z)) 
  v.get<0>() += f(v.get<1>());

      

where foreach

- BOOST_FOREACH

.

Here's an option similar to @Matthieu M. indices :

foreach (size_t i, range(n)) // useless compared to simple loop
  y[i] += f(x[i]); 

      

Possible range()

Implementation

template<class T, class T2>
std::pair<boost::counting_iterator<T>, 
          boost::counting_iterator<T> > 
range(T first, T2 last) {
  return std::make_pair(boost::counting_iterator<T>(first), 
                        boost::counting_iterator<T>(last));
}

template<class T>
std::pair<boost::counting_iterator<T>, 
          boost::counting_iterator<T> > 
range(T last) {
  return range<T>(0, last);
}

      

Draft (broken) zip()

Implementation

template<class Range1, class Range2>
struct zip_return_type {
  typedef boost::tuple<
    typename boost::range_iterator<Range1>::type,
    typename boost::range_iterator<Range2>::type> tuple_t;

  typedef std::pair<
    boost::zip_iterator<tuple_t>,
    boost::zip_iterator<tuple_t> > type;
};

template<class Range1, class Range2>
typename zip_return_type<Range1, Range2>::type
zip(Range1 r1, Range2 r2) {
  return std::make_pair(
    boost::make_zip_iterator(
      boost::make_tuple(boost::begin(r1), boost::begin(r2))),
    boost::make_zip_iterator(
      boost::make_tuple(boost::end(r1), boost::end(r2))));
}

      

+1


a source


You have two options. I suppose it y

is a kind of container following the idea iterator

.

The first way is to write another procedure that takes y

, x

and some functor as a parameter. Typically, it will do the same y[i] += f(x[i])

, but if you name it correctly, it will make your code clearer and easier to understand.

Another way is operator overloading +=

(or +

better together), so (let it y

have a type container

) it would look like this:

container& operator+ (functor_type& functor)

      

Here, your functor should be declared as struct / class like this:

class functor {
private:
   container c;
public:
   functor (container& c) : c(c) { }
   container operator() (void) { (...) - your actions on container here }
};

      

This way you can write y += f(x)

and everything will be fine. However, I would not recommend this way of manipulating the code, because all these operator overloads on your own data types usually make the code harder to understand.

0


a source







All Articles