Can I use std::lower_bound on function calls instead iterators? - c++

Simple use case: I want to find with binary search the minimal index i for which f(i)>=t, where t is some threshold and f is a monotonically increasing function over integer values.
A simple way to go would be to just call this function on every possible input, save it to a container and then use lower_bound, this would be useful in a scenario where I want to do multiple searches on the same function with different thresholds.
However, in my scenario, function evaluations are runtime expensive and I have multiple different functions/lambdas on which I only perform a single binary search.
So I guess, what I need, is either a lower_bound function taking a function and a value range instead of start and end iterators, or I need a mechanism to hide the function calls inside an iterator structure. I know the first solution is easy to implement, but I hoped for a solution that would avoid implementing binary search from scratch.
To me, this seemed like a common use case but somehow I failed to find anything on this particular problem on the web. I'd appreciate any tips, tricks, and links.
EDIT
I found the two first provided solutions very intriguing. The given solution using the comp argument is very elegant, however I forget to mention a reason why this approach does not work for me. In addition to long runtimes for a single function evaluation I also have the problem of having a large search space (e.g. over 10**15 integers) which makes it impractical to allocate a dummy vector for this purpose. I do not know how it would work with the boost increment iterators but I need something to work with std only anyway.
The second solution using a custom iterator is quite verbose though. I tested it with the large number I mentioned (and changing the ints to long longs) but this seems to be also to slow. It seems that lower_bound actually calls the operator++ several times to go from one location to the other, so the implementation of the std::lower_bound might already be the killer for my approach here (see below modified code example and output) and there is no way around a custom implementation (which I already have, no need here).
Thanks, however, for the insights, both answers showed me something new. And maybe someone can shine some more light on the points mentioned above, as I am definitely no expert on iterators or the implementation of lower_bound, maybe I used it wrong or it is something about the code example given by #idclev that makes it iterate this inefficiently through the numbers which I did not recognize.
Modified code example
#include <iostream>
#include <unordered_map>
#include <algorithm>
long long foo(long long i){ std::cout << "function evaluation:\t" << i << std::endl; return i;}
using function_type = long long(*)(long long);
template <function_type F>
struct fun_iterator {
using difference_type = size_t;
using value_type = long long;
using pointer = int*;
using reference = int&;
using iterator_category = std::forward_iterator_tag;
static std::unordered_map<long long,long long> m;
long long index;
fun_iterator(long long index) : index(index) {}
fun_iterator& operator++() {
std::cout << "operator++:\t" << index << std::endl;
++index;
return *this;
}
fun_iterator operator++(int x) {
fun_iterator it = *this;
++index;
return it;
}
int operator*() {
auto it = m.find(index);
if (it != m.end()) return it->second;
auto res = F(index);
m[index] = res;
return res;
}
bool operator!=(const fun_iterator& other){
return index != other.index;
}
bool operator==(const fun_iterator& other){
return index == other.index;
}
bool operator<(const fun_iterator& other){
return index < other.index;
}
};
template <function_type F>
std::unordered_map<long long,long long> fun_iterator<F>::m;
template <function_type F>
std::pair<fun_iterator<F>,fun_iterator<F>> make_begin_and_end(long long begin,long long end){
return {{begin},{end}};
}
int main() {
auto x = make_begin_and_end<foo>(0,10L);
auto it = std::lower_bound(x.first,x.second,4L);
// auto x = make_begin_and_end<foo>(0,1000000000000L);
// auto it = std::lower_bound(x.first,x.second,400000000000L);
std::cout << it.index << std::endl;
}
and the output:
operator++: 0
operator++: 1
operator++: 2
operator++: 3
operator++: 4
operator++: 5
operator++: 6
operator++: 7
operator++: 8
operator++: 9
operator++: 0
operator++: 1
operator++: 2
operator++: 3
operator++: 4
function evaluation: 5
operator++: 0
operator++: 1
function evaluation: 2
operator++: 2
operator++: 3
function evaluation: 4
function evaluation: 3
operator++: 3
4

As #KamilCuk suggested, write your own iterator, or alternatively
You can take any container of natural numbers (if you don't have ranges at hand, simply create an std::vector<int> and populate it with monotonically growing numbers — provided you at least know the boundaries of expected interval your expected value lies within). Next, std::lower_bound accepts a comp argument:
std::vector<int> args(1000);
std::iota(args.begin(), args.end(), 0);
root = std::lower_bound(args.cbegin(), args.cend(), t,
[](int x, int t){ return f(x) < t; });
(As a sanity check, check if root is args's begin — then 0 can be higher than your desired root — or is args's end — then the root is higher than the estimated right boundary.)

You can write your own iterator and to avoid unnessesary evaluations of the function, you can use memoization. The iterator can have a static map to cache results of function calls. To make iterators for different functions a different type, I parametrized the iterator on a function pointer:
#include <iostream>
#include <unordered_map>
#include <algorithm>
double foo(int i){ return i;}
using function_type = double(*)(int);
template <function_type F>
struct fun_iterator {
using difference_type = size_t;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::forward_iterator_tag;
static std::unordered_map<int,double> m;
int index;
fun_iterator(int index) : index(index) {}
fun_iterator& operator++() {
++index;
return *this;
}
fun_iterator operator++(int x) {
fun_iterator it = *this;
++index;
return it;
}
int operator*() {
auto it = m.find(index);
if (it != m.end()) return it->second;
auto res = F(index);
m[index] = res;
return res;
}
bool operator!=(const fun_iterator& other){
return index != other.index;
}
bool operator==(const fun_iterator& other){
return index == other.index;
}
bool operator<(const fun_iterator& other){
return index < other.index;
}
};
template <function_type F>
std::unordered_map<int,double> fun_iterator<F>::m;
template <function_type F>
std::pair<fun_iterator<F>,fun_iterator<F>> make_begin_and_end(int begin,int end){
return {{begin},{end}};
}
int main() {
auto x = make_begin_and_end<foo>(0,100);
auto it = std::lower_bound(x.first,x.second,50);
std::cout << it.index;
}
The map will be reused also for later instances of fun_iterator for the same function. And because it is parametrized on the function pointer, a fun_iterator for a different function uses a different map to store the results.

Related

How to write an infinite sequence compatible with std::ranges?

I would like to write a struct which will generate an infinite sequence of fibonacci numbers in a way compatible with std::ranges and range adaptors.
So if I wanted the first 5 even fibonacci numbers, I would write something like this:
#include <iostream>
#include <ranges>
using namespace std;
int main() {
auto is_even = [](auto a) { return a % 2 == 0; };
for (auto v :
something | ranges::views::filter(is_even) | ranges::views::take(5))
std::cout << v << std::endl;
return 0;
}
What "something" needs to be ?
It seems to me that it has to be a class with a forward iterator, but I can't find any example.
Edit: As it was pointed out by 康桓瑋 in the comments, there has been a better, cleaner solution presented at Cppcon, link, by Tristan Brindle.
I think this could serve as a quick reference to make custom iterator-based generators.
By your requirements, something must be a std::ranges::view, meaning it must be a moveable std::ranges::range deriving from std::ranges::view_interface<something>.
We can tackle all three with the following:
#include <ranges>
template<typename T>
class fib : public std::ranges::view_interface<fib<T>>{
public:
struct iterator;
auto begin() const { return iterator{}; }
auto end() const { return std::unreachable_sentinel; }
};
Notice std::unreachable_sentinel which makes creating sequences without end really simple.
We still have to define the iterator which does the actual work. In your case we want fib to be "the source" of the values, so our iterator should actually be std::input_iterator. There's some boiler plate code needed for that but it's basically just a type which can be incremented and dereferenced to yield its current value.
Something like this will do:
#include <iterator>
template<typename T>
struct fib<T>::iterator {
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T;
constexpr iterator() noexcept = default;
iterator& operator++() {
auto old_next = next;
next = next + current;
current = old_next;
return *this;
}
iterator operator++(int) {
iterator current{*this};
++(*this);
return current;
}
value_type operator*() const {
return current;
}
bool operator==(const iterator& other) const { return current == other.current && next==other.next; }
private:
T current= {};
T next = T{} + 1; // Could perhaps be fancier.
};
The increment operator does the computation itself, it's the simple iterating algorithm.
That's it, here's a working example:
#include <cstdint>
#include <iostream>
int main() {
auto is_even = [](auto a) { return a % 2 == 0; };
for (auto v :
fib<std::uint64_t>{} | std::ranges::views::filter(is_even) | std::ranges::views::take(10))
std::cout << v << std::endl;
return 0;
}
which outputs:
0
2
8
34
144
610
2584
10946
46368
196418
Of course you won't get very far even with std::uint64_t. But T can be anything numeric enough.
One can easily generalize the iterator to hold a stateful functor, likely passed from the range itself, call it during each increment and store the yielded value for dereferencing later. This would be very crude, but simple, way how to at least simulate "yield-based" generators.

Struct, Iterate over, C++ [duplicate]

I want to create a range-like construct in c++, that will be used like this:
for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8
for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
Handling the integer case is relatively easy:
template<typename T>
struct range
{
T from, to;
range(T from, T to) : from(from), to(to) {}
struct iterator
{
T current;
T operator*() { return current; }
iterator& operator++()
{
++current;
return *this;
}
bool operator==(const iterator& other) { return current == other.current; }
bool operator!=(const iterator& other) { return current != other.current; }
};
iterator begin() const { return iterator{ from }; }
iterator end() const { return iterator{ to }; }
};
However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end and not whether iter <= end as you would do in a for a loop.
Is there a simple way to create an iterable object that will behave like a correct range based for-loop on floats?
Here is my attempt which does not impair the semantics of iterators. Now, each iterator knows its stopping value. The iterator will set itself to this value upon exceeding it. All end iterators of a range with equal to therefore compare equal.
template <typename T>
struct range {
T from, to;
range(T from, T to): from(from), to(to) {}
struct iterator {
const T to; // iterator knows its bounds
T current;
T operator*() { return current; }
iterator& operator++() {
++current;
if(current > to)
// make it an end iterator
// (current being exactly equal to 'current' of other end iterators)
current = to;
return *this;
}
bool operator==(const iterator& other) const // OT: note the const
{ return current == other.current; }
// OT: this is how we do !=
bool operator!=(const iterator& other) const { return !(*this == other); }
};
iterator begin() const { return iterator{to, from}; }
iterator end() const { return iterator{to, to}; }
};
Why is this better?
The solution by #JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.
Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:
template <typename T>
struct range {
T from, to;
range(T from, T to): from(from), to(to) {}
struct iterator {
range const* range;
T current;
iterator& operator++() {
++current;
if(current > range->to)
current = range->to;
return *this;
}
...
};
iterator begin() const { return iterator{this, from}; }
iterator end() const { return iterator{this, to}; }
};
Or it could be T const* const pointing directly to that value, it is up to you.
OT: Do not forget to make the internals private for both classes.
Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.
See: https://en.cppreference.com/w/cpp/language/coroutines
With MSVC it would be:
#include <iostream>
#include <experimental/generator>
std::experimental::generator<double> rangeGenerator(double from, double to) {
for (double x=from;x <= to;x++)
{
co_yield x;
}
}
int main()
{
for (auto i : rangeGenerator(5.1, 9.2))
std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
}
Is there a simple way to create an iterable object that will behave
like a correct for loop on floats?
The simplest hack† would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.
(See Live)
#include <type_traits>
bool operator!=(const iterator& other)
{
if constexpr (std::is_floating_point_v<T>) return current <= other.current;
return !(*this == other);
}
†Warning: Even though that does the job, it breaks the meaning of operator!= overload.
Alternative Solution
The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
in the standard container std::vector.
Use SFINE, to restrict the use of the function for only the valid types.
This way, you can rely on standard implementations and forget about the reinventions.
(See Live)
#include <iostream>
#include <type_traits>
#include <vector> // std::vector
#include <numeric> // std::iota
#include <cstddef> // std::size_t
#include <cmath> // std::modf
// traits for valid template types(integers and floating points)
template<typename Type>
using is_integers_and_floats = std::conjunction<
std::is_arithmetic<Type>,
std::negation<std::is_same<Type, bool>>,
std::negation<std::is_same<Type, char>>,
std::negation<std::is_same<Type, char16_t>>,
std::negation<std::is_same<Type, char32_t>>,
std::negation<std::is_same<Type, wchar_t>>
/*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
>;
template <typename T>
auto ragesof(const T begin, const T end)
-> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>
{
if (begin >= end) return std::vector<T>{}; // edge case to be considered
// find the number of elements between the range
const std::size_t size = [begin, end]() -> std::size_t
{
const std::size_t diffWhole
= static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
if constexpr (std::is_floating_point_v<T>) {
double whole; // get the decimal parts of begin and end
const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
const double decimalEnd = std::modf(static_cast<double>(end), &whole);
return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;
}
return diffWhole;
}();
// construct and initialize the `std::vector` with size
std::vector<T> vec(size);
// populates the range from [first, end)
std::iota(std::begin(vec), std::end(vec), begin);
return vec;
}
int main()
{
for (auto i : ragesof( 5, 9 ))
std::cout << i << ' '; // prints 5 6 7 8
std::cout << '\n';
for (auto i : ragesof(5.1, 9.2))
std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
}
A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.
For example:
for (int i=-10; i<=10; i++)
{
double x = i/10.0; // Substituting i*0.1 would be faster but less accurate
}
or
for (int i=0; i<=16; i++)
{
double x = ((startValue*(16-i))+(endValue*i))*(1/16);
}
Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.
Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.

How to create a `range`-like iterable object of floats?

I want to create a range-like construct in c++, that will be used like this:
for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8
for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
Handling the integer case is relatively easy:
template<typename T>
struct range
{
T from, to;
range(T from, T to) : from(from), to(to) {}
struct iterator
{
T current;
T operator*() { return current; }
iterator& operator++()
{
++current;
return *this;
}
bool operator==(const iterator& other) { return current == other.current; }
bool operator!=(const iterator& other) { return current != other.current; }
};
iterator begin() const { return iterator{ from }; }
iterator end() const { return iterator{ to }; }
};
However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end and not whether iter <= end as you would do in a for a loop.
Is there a simple way to create an iterable object that will behave like a correct range based for-loop on floats?
Here is my attempt which does not impair the semantics of iterators. Now, each iterator knows its stopping value. The iterator will set itself to this value upon exceeding it. All end iterators of a range with equal to therefore compare equal.
template <typename T>
struct range {
T from, to;
range(T from, T to): from(from), to(to) {}
struct iterator {
const T to; // iterator knows its bounds
T current;
T operator*() { return current; }
iterator& operator++() {
++current;
if(current > to)
// make it an end iterator
// (current being exactly equal to 'current' of other end iterators)
current = to;
return *this;
}
bool operator==(const iterator& other) const // OT: note the const
{ return current == other.current; }
// OT: this is how we do !=
bool operator!=(const iterator& other) const { return !(*this == other); }
};
iterator begin() const { return iterator{to, from}; }
iterator end() const { return iterator{to, to}; }
};
Why is this better?
The solution by #JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.
Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:
template <typename T>
struct range {
T from, to;
range(T from, T to): from(from), to(to) {}
struct iterator {
range const* range;
T current;
iterator& operator++() {
++current;
if(current > range->to)
current = range->to;
return *this;
}
...
};
iterator begin() const { return iterator{this, from}; }
iterator end() const { return iterator{this, to}; }
};
Or it could be T const* const pointing directly to that value, it is up to you.
OT: Do not forget to make the internals private for both classes.
Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.
See: https://en.cppreference.com/w/cpp/language/coroutines
With MSVC it would be:
#include <iostream>
#include <experimental/generator>
std::experimental::generator<double> rangeGenerator(double from, double to) {
for (double x=from;x <= to;x++)
{
co_yield x;
}
}
int main()
{
for (auto i : rangeGenerator(5.1, 9.2))
std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
}
Is there a simple way to create an iterable object that will behave
like a correct for loop on floats?
The simplest hack† would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.
(See Live)
#include <type_traits>
bool operator!=(const iterator& other)
{
if constexpr (std::is_floating_point_v<T>) return current <= other.current;
return !(*this == other);
}
†Warning: Even though that does the job, it breaks the meaning of operator!= overload.
Alternative Solution
The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
in the standard container std::vector.
Use SFINE, to restrict the use of the function for only the valid types.
This way, you can rely on standard implementations and forget about the reinventions.
(See Live)
#include <iostream>
#include <type_traits>
#include <vector> // std::vector
#include <numeric> // std::iota
#include <cstddef> // std::size_t
#include <cmath> // std::modf
// traits for valid template types(integers and floating points)
template<typename Type>
using is_integers_and_floats = std::conjunction<
std::is_arithmetic<Type>,
std::negation<std::is_same<Type, bool>>,
std::negation<std::is_same<Type, char>>,
std::negation<std::is_same<Type, char16_t>>,
std::negation<std::is_same<Type, char32_t>>,
std::negation<std::is_same<Type, wchar_t>>
/*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
>;
template <typename T>
auto ragesof(const T begin, const T end)
-> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>
{
if (begin >= end) return std::vector<T>{}; // edge case to be considered
// find the number of elements between the range
const std::size_t size = [begin, end]() -> std::size_t
{
const std::size_t diffWhole
= static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
if constexpr (std::is_floating_point_v<T>) {
double whole; // get the decimal parts of begin and end
const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
const double decimalEnd = std::modf(static_cast<double>(end), &whole);
return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;
}
return diffWhole;
}();
// construct and initialize the `std::vector` with size
std::vector<T> vec(size);
// populates the range from [first, end)
std::iota(std::begin(vec), std::end(vec), begin);
return vec;
}
int main()
{
for (auto i : ragesof( 5, 9 ))
std::cout << i << ' '; // prints 5 6 7 8
std::cout << '\n';
for (auto i : ragesof(5.1, 9.2))
std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1
}
A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.
For example:
for (int i=-10; i<=10; i++)
{
double x = i/10.0; // Substituting i*0.1 would be faster but less accurate
}
or
for (int i=0; i<=16; i++)
{
double x = ((startValue*(16-i))+(endValue*i))*(1/16);
}
Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.
Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.

Finding minimum element based on a transformed value

Here is the task came to me from a code review. I want to select a minimum value from a set, based on a special kind of compare predicate. Like this:
struct Complex { ... };
float calcReduction(Complex elem);
Complex findMinValueWithPredicates(const std::vector<Complex>& values)
{
auto it = std::min_element(values.begin(), values.end(),
[](const Complex& a, const Complex& b) {
return calcReduction(a) < calcReduction(b);
});
if (it == values.end()) throw std::runtime_error("");
return *it;
}
Here I find the minimum element based on a predicate. This predicate computes a reduction of both values to float and then compares those floats. Works fine, looks neat.
Can you see the problem? Yes, for a set of N elements calcReduction() is called 2N times, while it is enough to compute it only N times - once for each element.
One way to solve this problem is to write explicit computations:
Complex findMinValueExplicit(const std::vector<Complex>& values)
{
float minReduction = std::numeric_limits<float>::max();
Complex minValue;
for (Complex value : values)
{
float reduction = calcReduction(value);
if (reduction < minReduction)
{
minReduction = reduction;
minValue = value;
}
}
if (minReduction == std::numeric_limits<float>::max()) throw std::runtime_error("");
return minValue;
}
It works fine and we only have N calls to calcReduction(). However, it looks too verbose and the intent is not such clear, as compared to explicit call of min_element. Because when you call min_element it is really easy to guess you are going to find a minimum element, you know.
The only idea I have for now is to create my own algorithm like min_element_with_reduction, accepting a range and a reduction function. Sounds reasonable, but I wonder whether there are any ready solutions.
Any ideas on how to solve this task with clear intent and some ready solutions? Boost is welcomed. C++17 and ranges are interesting to see.
You could use boost::range library.
auto reductionLambda = [](const Complex& a) { return calcReduction(a); };
auto it = boost::range::min_element(values | boost::adaptors::transformed(
std::ref(reductionLambda));
Ranges themselves should be coming to the standard C++ with C++17 as well.
Edit
As we figured out in comments, this would also make the conversion twice.
So here's something fun:
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/assign.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
template <class Iterator, class UnaryFunction>
class memoizing_transform_iterator
: public boost::iterator_adaptor<
memoizing_transform_iterator<Iterator, UnaryFunction> // Derived
, Iterator // Base
, std::decay_t<decltype(std::declval<UnaryFunction>()(std::declval<typename Iterator::value_type>()))> // Value
, boost::forward_traversal_tag // CategoryOrTraversal
>
{
public:
memoizing_transform_iterator() {}
explicit memoizing_transform_iterator(Iterator iter, UnaryFunction f)
: memoizing_transform_iterator::iterator_adaptor_(iter), fun(f) {}
static int total;
private:
friend class boost::iterator_core_access;
void increment() { ++this->base_reference(); memoized = false; }
using MemoType = std::decay_t<decltype(std::declval<UnaryFunction>()(std::declval<typename Iterator::value_type>()))>;
MemoType& dereference() const
{
if (!memoized) {
++total;
memoized = true;
memo = fun(*this->base());
}
return memo;
}
UnaryFunction fun;
mutable bool memoized = false;
mutable MemoType memo;
};
template <class Iterator, class UnaryFunction>
auto make_memoizing_transform_iterator(Iterator i, UnaryFunction&& f)
{
return memoizing_transform_iterator<Iterator, UnaryFunction>(i, f);
}
template<class I, class U>
int memoizing_transform_iterator<I, U>::total = 0;
// THIS IS COPIED FROM LIBSTDC++
template<typename _ForwardIterator>
_ForwardIterator
min_el(_ForwardIterator __first, _ForwardIterator __last)
{
if (__first == __last)
return __first;
_ForwardIterator __result = __first;
while (++__first != __last)
if (*__first < *__result)
__result = __first;
return __result;
}
int main(int argc, const char* argv[])
{
using namespace boost::assign;
std::vector<int> input;
input += 2,3,4,1,5,6,7,8,9,10;
auto transformLambda = [](const int& a) { return a*2; };
auto begin_it = make_memoizing_transform_iterator(input.begin(), std::ref(transformLambda));
auto end_it = make_memoizing_transform_iterator(input.end(), std::ref(transformLambda));
std::cout << *min_el(begin_it, end_it).base() << "\n";
std::cout <<begin_it.total;
return 0;
}
Basically I implemented an iterator that memoizes the result of calling the transformation functor. The weird part though is that at least in online compilers, the iterators are copied before their dereferenced values are compared (thus defeating the purpose of memoizing). However when I simply copied the implementation from libstdc++, it works as expected. Perhaps you could try it out on a real machine? The live example is here.
Small edit:
I tested on VS2015 and it works as expected with std::min_element.
Here's a solution using (already works with the range-v3 library, the implementation by the author of the upcoming Ranges TS)
#include <range/v3/all.hpp>
#include <iostream>
#include <limits>
using namespace ranges::v3;
int main()
{
auto const expensive = [](auto x) { static int n; std::cout << n++ << " "; return x; };
auto const v = view::closed_iota(1,10) | view::transform(expensive);
auto const m1 = *min_element(v);
std::cout << "\n" << m1 << "\n";
auto const inf = std::numeric_limits<int>::max();
auto const min = [](auto x, auto y) { return std::min(x, y); };
auto const m2 = accumulate(v, inf, min);
std::cout << "\n" << m2 << "\n";
}
Live On Coliru with output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
1
19 20 21 22 23 24 25 26 27 28
1
As you can see, using min_element takes 2N comparisons, but using accumulate only N.
The only thing missing is the meta-iterator.
A meta-iterator takes an iterator, and creates an iterator that contains a copy of it. It passes all operations through to the contained iterator, except when dereferenced returns a copy of the contained iterator instead.
With any care, the code used for this also works to create an iterator over size_t or int or similar torsor-likes.
template<class It, class R>
struct reduced_t {
It it;
R r;
friend bool operator<( reduced_t const& lhs, reduced_t const& rhs ) {
return lhs.r < rhs.r;
}
};
template<class It, class F>
reduced_t<It, std::result_of_t<F(typename std::iterator_traits<It>::reference)>>
reducer( It it, F&& f ) {
return {it, std::forward<F>(f)(*it)};
}
template<class It, class F>
It reduce( It begin, It end, F&& f ) {
if (begin==end)
return begin;
return std::accumulate(
meta_iterator(std::next(begin)), meta_iterator(end),
reducer(begin, f),
[&](
auto&& reduced, // reduced_t<blah...> in C++11
It i
) {
auto r2 = reducer( i, f );
return (std::min)(reduced, r2);
}
).it;
};
f(*it) is called exactly once per iterator.
I wouldn't call this ... obvious. The trick is that we use accumulate and meta-iterators to implement min_element, then we can have accumulate operate on transformed elements (which gets called once, and returned).
You could rewrite it in stack-based programming style using primitives, but there are lots of primitives to write. Maybe post ranges-v3.
At this point, I'm imagining having some high-powered compositional programming library. If I did, we could do the following:
reducer( X, f ) can be rewritten graph( deref |then| f )(X) using order_by( get_n_t<1> ) for ordering.
The accumulate call could read accumulate( skip_first(range), g(begin(range)), get_least( order_by( get_n_t<1> ) ) ).
Not sure if that is any clearer.
If you take a minElem as a lambda parameter you could use min_element
Complex findMinValueWithPredicates(const std::vector<Complex>& values)
{
float minElem = std::numeric_limits<float>::max();
auto it = std::min_element(values.begin(), values.end(),
[&minElem](const Complex& a, const Complex& b) {
float tmp = calcReduction(a);
if (tmp < minElem) {
minElem = tmp;
return true;
}
return false;
});
if (it == values.end()) throw std::runtime_error("");
return *it;
}
Edit:
Why does this work when bis not used?
25.4.7.21 min_element
21 Returns: The first iterator i in the range [first,last) such that
for every iterator j in the range [first,last) the following
corresponding conditions hold: !(*j < *i) or comp(*j, *i) == false.
Returns last if first == last.
because b should have been named smallestYet (code from cplusplus.com)
template <class ForwardIterator>
ForwardIterator min_element ( ForwardIterator first, ForwardIterator last )
{
if (first==last) return last;
ForwardIterator smallest = first;
while (++first!=last)
if (*first<*smallest) // or: if (comp(*first,*smallest)) for version (2)
smallest=first;
return smallest;
}
Which lead me to a new favourite quote:
"There are only 10 hard problems in Computer Science:
cache invalidation, naming things and off-by-one errors."
one commented on that we might be off-by-one as we don't use b.
I worried that the minElem cached might not be correct.
And I realized that the name b should have been more meaningful as it is "dereferenced iterator to smallest element yet" or smallestYet.
Finally that not all understand binary when its not written with a ´b´ at the end.
Here is another option, but it is still effectively your second solution. To be honest it doesn't look clear, but someone might like it. (I use std::pair<float, Complex> to store reduction result and the value that was reduced.)
std::pair<float, Complex> result{std::numeric_limits<float>::max(), {}};
auto output_function = [&result](std::pair<float, Complex> candidate) {
if (candidate.first < result.first)
result = candidate;
};
std::transform(values.begin(), values.end(),
boost::make_function_output_iterator(output_function),
[](Complex x) { return std::make_pair(calcReduction(x), x); });
P.S. If your calcReduction costs a lot, have you considered caching results in Complex objects? It will lead to a slightly more complicated implementation, but you'll be able to use plain std::min_element which makes your intentions clear.

Sorting just two elements using STL

Quite often I have two variables foo1 and foo2 which are numeric types. They represent the bounds of something.
A user supplies values for them, but like a recalcitrant musician, not necessarily in the correct order!
So my code is littered with code like
if (foo2 < foo1){
std::swap(foo2, foo1);
}
Of course, this is an idiomatic sort with two elements not necessarily contiguous in memory. Which makes me wonder: is there a STL one-liner for this?
I suggest to take a step back and let the type system do the job for you: introduce a type like Bounds (or Interval) which takes care of the issue. Something like
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
This not only centralizes the swap-to-sort code, it also helps asserting the correct order very early on so that you don't pass around two elements all the time, which means that you don't even need to check the order so often in the first place.
An alternative approach to avoid the issue is to express the boundaries as a pair of 'start value' and 'length' where the 'length' is an unsigned value.
No, but when you notice you wrote the same code twice it's time to write a function for it:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
 
std::minmax returns pair of smallest and largest element. Which you can use with std::tie.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
Note that this isn't the same as the if(a < b) std::swap(a,b); version. For example this doesn't work with move-only elements.
if the data type of your value that you're going to compare is not already in c++. You need to overload the comparison operators.
For example, if you want to compare foo1 and foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
If your value is some type of int, or double. Then you can use the std::list<>::sort member function.
For example:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}