I need to concatenate multiple instances of boost::iterator_range.
My initial idea was to use boost::join, but it looks like it takes only two ranges as parameters.
On another question I found that the most voted answer was "well, just call join again", but that is not working in my case.
I realized the reason might be that I do not know at compile time the exact number of ranges I am going to join, resulting in boost::join not knowing its return type.
To make it more clear, I need to use it in a ranged for loop, such as the following:
SomeRangeType result;
for ( const auto& a_range : some_list_of_ranges )
{
result = boost::join( result, a_range );
}
return result;
Does another join-like operation like the one I need exist in boost?
range-v3 has concat and join views, it seems you want join view here:
std::vector<std::vector<int>> v{{1, 2, 3}, {4}, {5, 6}};
for (auto e : v | ranges::view::join) {
std::cout << e << " "; // 1 2 3 4 5 6
}
Demo
C++ does not have run-time dynamic templates, so the idea does not work with boost::range.
We can have 2 ranges r1 and r2 with types R1 and R2 and when we join those then we get result (lets name it r12) of type boost::joined_range<R1,R2>.
We can have third range (say r3 of type R3) and joining it with r12 we would get result of type boost::joined_range<boost::joined_range<R1,R2>,R3>.
The ranges r1, r2, r3 etc. can be passed to variadic template function as arguments and from list of arguments we can make compiler to figure what is the resulting type. Same is when we have the ranges in fixed length collection (like std::tuple or std::array), we can make compiler to figure what is the resulting type of joining those.
However if we don't have fixed amount of ranges but run-time dynamic amount (like from std::vector) then we don't know what will be the type of joining these and also compiler can't figure it out compile time. Every type however must be known compile time in C++.
So you have either to find a way to fix the amount of ranges you join compile time or you have to use that dynamic, not joined collection (like vector) of ranges as your data type or you have to use some third thing like range-v3.
Related
Consider the following code using the ranges library (from c++20)
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> inputs{1, 2, 3, 4, 5, 6};
auto square_it = [](auto i) {
std::cout << i << std::endl;
return i * 2; };
auto results = inputs | std::views::transform(square_it) | std::views::filter([](auto i){ return i % 3 == 0; });
for(auto r : results) {
// std::cout << r << std::endl;
}
}
The cout in the square function is to log when the square function is called by the ranges library. This code prints
1
2
3
3
4
5
6
6
The question is, why are values that match the filter's predicated are printed twice?
I have seem this code in a presentation in CppCon 2020, where the presenter explains why this happens. According to him, filter iterates until its predicate is satisfied (and of course if needs to call transform each time). Then filter stops and it is ready to be iterated on. After that the actual iteration is started and a value is read from filter, which then calls transform again a second time for the same input.
It is not clear to me why this is necessary. Since ranges::views compute values lazily and every view operation pulls data from the one before it, why can't filter just pass the value to whoever is after it in the pipeline as soon as it finds a match?
why can't filter just pass the value to whoever is after it in the pipeline as soon as it finds a match?
Because in the iterator model, positioning and accessing are distinct operations. You position an iterator with ++; you access an iterator with *. These are two distinct expressions, which are evaluated at two distinct times, resulting in two distinct function calls that yield two distinct values (++ yields an iterator, * yields a reference).
A filtering iterator, in order to perform its iteration operation, must access the values of its underlying iterator. But that access cannot be communicated to the caller of ++ because that caller only asked to position the iterator, not to get its value. The result of positioning an iterator is a new iterator value, not the value stored in that iterated position.
So there's nobody to return it to.
You can't really delay positioning until after accessing because a user might reposition the iterator multiple times. I mean, you could implement it that way in theory by storing the number of such increments/decrements. But this increases the complexity of the iterator's implementation. Especially since resolving such delayed positioning can happen through something as simple as testing against another iterator or sentinel, which is supposed to be an O(1) operation.
This is simply a limitation of the model of iterators as having both position and value. The iterator model was designed as an abstraction of pointers, where iteration and access are distinct operations, so it inherited this mechanism. Alternative models exist where iteration and access are bundled together, but they're not how standard library iteration works.
I am looking at the following snippet:
std::vector<int> elements{ 1,2,3 };
// this won't compile:
elements
| std::views::filter([](auto i) { return i % 2 == 0; })
| std::ranges::for_each([](auto e) {std::cout << e << std::endl; });
// but this compiles:
auto view =
elements
| std::views::filter([](auto i) { return i % 2 == 0; });
std::ranges::for_each(view, [](auto e) {std::cout << e << std::endl; });
and I can't see the reason why the combination of the range adaptor (view) and the range algorithm via the pipe operator does not compile. I suppose it has something to do with the type std::ranges::dangling that for_each seems to be returning as my compiler (msvc 19.29) reports, but I am not sure ...
There isn't really any inherent design reason why some sets of algorithms do have pipe support (views, actions, and to - although C++20 only has views so far) and others don't (everything else in <algorithm>). Piping into for_each makes just as much sense as piping into filter, it's just that range-v3 (and, consequently, C++20 Ranges) only did so for some things and not others.
As of now, there is no opt-in mechanism to make something "pipeable" in the Ranges sense (see P2387 to change that). But once that paper, or some variant of it, gets approved, it would become easy to write an algorithm adapter that simply makes algorithms pipeable. So that you could do, for instance, this:
elements
| std::views::filter([](auto i) { return i % 2 == 0; })
| adaptor(std::ranges::for_each)([](auto e) {std::cout << e << std::endl; });
Demo (note that this depends on libstdc++ internals at the moment).
One issue with the library machinery approach to this problem is ambiguity - this relies on deciding that if f(x, y) is invokable that the intent is to make it a full call rather than a partial one. It's certainly possible for some algorithms that you may not be able to distinguish between a partial and full call in this sense (which itself may be one motivation for not having them be implicitly pipeable). This is certainly a known problem with some views already (zip, concat, and join taking a delimiter are examples) and is itself one of the motivations for having a language solution to this problem (e.g. P2011).
Of course that only affects whether you could write | some_algo(args...), the opt-in mechanism that I'm describing here could just as easily have been spelled | partial(ranges::for_each, args...) instead of | adaptor(ranges::for_each)(args...), and then there'd be no ambiguity. It's just a weirder spelling in my opinion, which is why I showed it the way I did.
Why can't range adaptors and ranges be combined in one expression?
They can be. You just did combine them. You used elements as a range, and combined it with the range adaptor std::views::filter.
std::ranges::for_each however is neither a range, nor is it a range adaptor. It is a function (template) that accepts range as an argument. You can keep it in one expression if you really want to, although at the cost of readability in my opinion:
std::ranges::for_each(
elements
| std::views::filter([](auto i) { return i % 2 == 0; }),
[](auto e) {std::cout << e << std::endl; }
);
filter is a range adaptor: it takes a range of values and converts it into a different range of values.
for_each is an operation. It takes a range of values and does something with it. That "something" does not led to the production of a range of values. So it's not adapting anything; it is consuming the range.
And range adaptor composition is about building ranges, not consuming them. The product of a range composition is always a range.
What you're asking is no different from wondering why you can add one std::string to another, but you can't add a std::string to an std::ifstream to open a file. Opening a file doesn't produce a string; it produces a file. Same goes here: performing an arbitrary operation over a range doesn't produce a range.
This is why ranges::transform has a range adaptor views::transform version: because transform conceptually produces a new range of values. for_each doesn't produce anything; it merely consumes a range.
Consider the following code using the ranges library (from c++20)
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> inputs{1, 2, 3, 4, 5, 6};
auto square_it = [](auto i) {
std::cout << i << std::endl;
return i * 2; };
auto results = inputs | std::views::transform(square_it) | std::views::filter([](auto i){ return i % 3 == 0; });
for(auto r : results) {
// std::cout << r << std::endl;
}
}
The cout in the square function is to log when the square function is called by the ranges library. This code prints
1
2
3
3
4
5
6
6
The question is, why are values that match the filter's predicated are printed twice?
I have seem this code in a presentation in CppCon 2020, where the presenter explains why this happens. According to him, filter iterates until its predicate is satisfied (and of course if needs to call transform each time). Then filter stops and it is ready to be iterated on. After that the actual iteration is started and a value is read from filter, which then calls transform again a second time for the same input.
It is not clear to me why this is necessary. Since ranges::views compute values lazily and every view operation pulls data from the one before it, why can't filter just pass the value to whoever is after it in the pipeline as soon as it finds a match?
why can't filter just pass the value to whoever is after it in the pipeline as soon as it finds a match?
Because in the iterator model, positioning and accessing are distinct operations. You position an iterator with ++; you access an iterator with *. These are two distinct expressions, which are evaluated at two distinct times, resulting in two distinct function calls that yield two distinct values (++ yields an iterator, * yields a reference).
A filtering iterator, in order to perform its iteration operation, must access the values of its underlying iterator. But that access cannot be communicated to the caller of ++ because that caller only asked to position the iterator, not to get its value. The result of positioning an iterator is a new iterator value, not the value stored in that iterated position.
So there's nobody to return it to.
You can't really delay positioning until after accessing because a user might reposition the iterator multiple times. I mean, you could implement it that way in theory by storing the number of such increments/decrements. But this increases the complexity of the iterator's implementation. Especially since resolving such delayed positioning can happen through something as simple as testing against another iterator or sentinel, which is supposed to be an O(1) operation.
This is simply a limitation of the model of iterators as having both position and value. The iterator model was designed as an abstraction of pointers, where iteration and access are distinct operations, so it inherited this mechanism. Alternative models exist where iteration and access are bundled together, but they're not how standard library iteration works.
I have two Eigen::Array which have the same number of columns. One of them, a, has one row, and the other, b, has two rows.
What I want to do, is to multiply every column of b with the entry in the respective column in a, so that it behaves like this:
ArrayXXd result;
result.resizeLike(b);
for (int i=0; i<a.cols(); ++i)
result.col(i) = a.col(i)[0] * b.col(i);
However, it's part of a rather long expression with several of such multiplications, and I don't want to have to evaluate intermediate results in temporaries. Therefore, I'd rather get an Eigen expression of the above, like
auto expr = a * b;
This, of course, triggers an assertion, because a.rows() != b.rows().
What I tried, which works, is:
auto expr = a.replicate(2,1) * b;
However, the resulting code is very slow, so I hope there's a better option.
Possibly related.
Eigen provides the possibility to use broadcasting for such cases. However, the one-dimensional array should first be converted into a Vector:
broadcasting operations can only be applied with an object of type Vector
This will work in your case:
RowVectorXd av = a;
ArrayXXd expr = b.rowwise() * av.array();
Edit
To avoid a copy of the data into a new vector one can use Map:
ArrayXXd expr = b.rowwise() * RowVectorXd::Map(&a(0), a.cols()).array();
I have posted the same solution to your previous question but here is my answer again:
Define your arrays with fixed number of rows but dynamic number of columns whereas ArrayXXd type yields an array with both dynamic number of rows and columns.
Use fixed-size version of operations. This should typically give faster code.
I was multiplying each container against another number so I did the following:
local_it begin = magnitudesBegin;
std::advance(begin , 2);
local_it end = magnitudesBegin;
std::advance(end, 14);
std::transform(begin, end, firstHalf.begin(),
std::bind1st(std::multiplies<double>(),100));
It worked wonders, problem is when doing the same to divide between another container. Here is a working example of my problem:
const std::size_t stabilitySize = 13;
boost::array<double,stabilitySize> secondHalf;
double fundamental = 707;
boost::array<double, stabilitySize> indexes = {{3,4,5,6,7,8,9,10,11,12,13,14,15}};
std::transform(indexes.begin(), indexes.end(), secondHalf.begin(),
std::bind1st(std::divides<double>(),fundamental));
It does divide the container. But instead of dividing each element in the array against 707 it divides 707 between each element in the array.
std::bind1st(std::divides<double>(),fundamental)
The code above takes a functor std::divides<double> that takes two arguments and fixes the value of the first argument to be fundamental. That is it fixes the numerator of the operation and you get the expected result. If you want to bind fundamental to be the denominator, use std::bind2nd.
you can try the following , divide has a completely different operation than multiply, it just divides a constant number by all your elements
std::bind1st(std::multiplies<double>(),1.0/707.0));
If the number 707.0 is something like a fundamental constant, and a division can be seen as a "conversion", let's call it "x to y" (I don't know what your numbers are representing, so replace this by meaningful words). It would be nice to wrap this "x to y" conversion in a free-standing function for re-usability. Then, use this function on std::transform.
double x_to_y(double x) {
return x / 707.0;
}
...
std::transform(..., x_to_y);
If you had C++11 available, or want to use another lambda-library, another option is to write this in-line where being used. You might find this syntax more readable like parameter binding using bind2nd:
std::transform(..., _1 / 707.0); // when using boost::lambda