Reverse map a functional relation(c++) - c++

I am using a simple function (y(x)), and I want to generate an x value from a certain y value. While typically reverse mapping does not give a single x value, I am using the maximum from my y values. This means that there will be a unique x value for the y value I input(the maximum). I don't understand how to code this in c++

If you don't need interpolation, only exact reverse lookup, then it's relatively straighforward:
std::map<YType, XType> lookup;
// (code to read the file goes here)
// for each x {
YType y = f(x);
if ((lookup.count(y) == 0) || (lookup[y] < x)) {
lookup[y] = x;
}
// }
Then your reverse lookup is just lookup[y], which will return 0 (or a default-constructed value where applicable) if y in fact was missing from the data.
Be aware that my code is a bit inefficient, it looks up y several times in the map, up to 3. You can optimize using iterators, but I'm concerned that obscures what's going on if you're not already familiar with them:
typedef std::map<YType, XType> maptype;
typedef std::pair<maptype::iterator, bool> resulttype;
resulttype result = lookup.insert(std::make_pair(y, x));
if (!result.second) {
// key already existed, so value was not inserted. Check for max.
maptype::iterator pos = result.first;
if ((*pos).second < x) {
(*pos).second = x;
}
}

If I understand correctly, you are given a finite range of values x, say x[0], x[1], ..., x[N], and a function f, and you want to find the index k for which f(x[k]) is the largest possible. In that case, a simple search will do:
size_t k = 0;
T m = f(x[k]);
T tmp;
for (size_t i = 1; i <= N; ++i)
{
if ((tmp = f(x[i])) > m)
{
k = i;
m = tmp;
}
}
// Maximum is (x[k], m)
Here T is the type such that f is T f(T);

Related

Using std::set container for range items

I'd like to store a bunch of range items in std::set container.
This data structure should provide fast decision whether a specific input range contained by one of the ranges that the set currently holds, by overloading the comparison of std::set in order use the set::find method to check one of the items in set contain the input range argument.
It should also support range item that represents a single point (start_range == end_range).
Here's my implementation :
#include <iostream>
#include <map>
#include <set>
using std::set;
using std::map;
class range : public std::pair<int,int>
{
public:
range(int lower, int upper)
{
if (upper < lower)
{
first = upper;
second = lower;
}
else
{
first = lower;
second = upper;
}
}
range(int val)
{
first = second = val;
}
bool operator<(range const & b) const
{
if (second < b.first)
{
return true;
}
return false;
}
};
And here's how I test my data structure:
int main(int argc, const char * argv[])
{
std::map<int, std::set<range>> n;
n[1].insert(range(-50,-40));
n[1].insert(range(40,50));
n[2].insert(range(-30,-20));
n[2].insert(range(20,30));
n[3].insert(range(-20,-10));
n[3].insert(range(10,20));
range v[] = {range(-50,-41), range(30,45), range(-45,-45), range(25,25)};
int j[] = {1,2,3};
for (int l : j)
{
for (range i : v)
{
if (n[l].find(i) != n[l].end())
{
std::cout << l << "," << i.first << "," << i.second << " : "
<< n[l].find(range(i))->first << " "
<< n[l].find(range(i))->second << std::endl;
}
}
}
}
and here are the results I get:
1,-50,-41 : -50 -40 --> good
1,30,45 : 40 50 --> bad
1,-45,-45 : -50 -40 --> good
2,30,45 : 20 30 --> bad
2,25,25 : 20 30 --> good
So as you can see, my code does support perfectly well single point range (-45 is contained by range (-50,-40) and 25 is contained by by range (20,30))
However, as for wider ranges, my current operator < is capable of finding the contained relationship which is equal for the set terminology (meaning that for ranges a and b a<b && a<b.
Is there anyway to change this operator to make it work ?
Sounds like a perfect match for using Boost Interval Container Library. In short, you can
#include <boost/icl/interval_set.hpp>
// Helper function template to reduce explicit typing:
template <class T>
auto closed(T&& lower, T&& upper)
{
return boost::icl::discrete_interval<T>::closed(std::forward<T>(lower),
std::forward<T>(upper));
}
boost::icl::interval_set<int> ranges;
ranges.insert(closed(1, 2));
ranges.insert(closed(42, 50));
std::cout << contains(ranges, closed(43, 46)) << "\n"; // true
std::cout << contains(ranges, closed(42, 54)) << "\n"; // false
This should easily be pluggable into your std::map and be usable without further adjustments.
Your operator < defines partial order:
(30,45) < (40, 50) == false and simultaneously (40, 50) < (30, 45) == false so in terms of std::set and std::map they are equal. That is why you got these results.
There is a paper about partial order: https://en.wikipedia.org/wiki/Partially_ordered_set
You might want use std::unordered_map or define somehow total order for your ranges.
I suggest operator < that compares the arithmetical mean of range bounds, i.e.
(a, b) < (c, d) if and only if (a+b)/2 < (c+d)/2 for total order. Note that you might want use float for arithmetical mean.
For testing I suggest the following code draft (I write here from scratch and didn't tested it). -1 meanst that are no range that contains this
int range::firstContainsMe(const std::vector<range> rangesVec)
{
for (size_t i = 0; i < rangesVec; i++) {
if (lower >= rangesVec[i].lower && upper <= rangesVec[i].upper) {
return i;
}
}
return -1;
}
Your comparison operator is unsuitable.
If you wish to use any container or algorithm based on ordering in C++, the ordering relation needs to be a Strict Weak Ordering Relation. The definition can be found on Wikipedia, in short the following rules must be respected:
Irreflexivity: For all x in S, it is not the case that x < x.
Asymmetry: For all x, y in S, if x < y then it is not the case that y < x.
Transitivity: For all x, y, z in S, if x < y and y < z then x < z.
Transitivity of Incomparability: For all x, y, z in S, if x is incomparable with y (neither x < y nor y < x hold), and y is incomparable with z, then x is incomparable with z.
Your comparison operator fails, and therefore is unsuitable. In general, a quick way of obtaining a good comparison operator is to do what tuples do:
bool operator<(range const & b) const
{
return std::tie(first, second) < std::tie(b.first, b.second);
}
You want a map, not a set.
In order to solve your problem, you want a map, not a set.
For disjoint intervals, a map from lower-bound to upper-bound is sufficient:
std::map<int, int> intervals;
The .lower_bound and .upper_bound operations allow finding the closest key in O(log N) time, and from there containment is quickly asserted.
For non-disjoint intervals, things get trickier I fear, and you'll want to start looking into specialized data-structures (Interval Trees for example).

Lambda function type creep

Let's have a look at the following code:
tbb::blocked_range<int> range(0, a.rows);
uint64_t positive = tbb::parallel_reduce(range, 0, // <- initial value
[&](const tbb::blocked_range<int>& r, uint64_t v)->uint64_t {
for (int y = r.begin(); y < r.end(); ++y) {
auto rA = a[y], rB = b[y];
for (int x = 0; x < a.cols; ++x) {
auto A = rA[x], B = rB[x];
for (int l = y; l < a.rows; ++l) {
auto rAA = a[l], rBB = b[l];
for (int m = x; m < a.cols; ++m) {
if (l == y && m == x)
continue;
auto AA = rAA[m], BB = rBB[m];
if ((A == AA) && (B == BB))
v++; // <- value is changed
if ((A != AA) && (B != BB))
v++; // <- value is changed
}
}
}
}
return v;
}, [](uint64_t first, uint64_t second)->uint64_t {
std::cerr << first << ' + ' << second; // <- wrong values occur
return first+second;
}
);
This is a parallel reduce operation where the initial value is 0. Then, in each parallel computation, based on the initial value, we count up (local variable v in the first lambda function). The second lambda function aggregates the results from parallel workers.
Interestingly enough, this code does not work as expected. The output of the second lambda function will show enormous figures that result from integer overflows.
The code works correctly when replacing the second line with:
uint64_t positive = tbb::parallel_reduce(range, (uint64_t)0, // <- initial value
Now I wonder. Wouldn't the definition of the first lambda (uint64_t v) enforce this cast and how can a function that is supposed to operate on uint64_t operate on int instead?
The compiler is GCC 6.
It doesn't matter what argument the lambda takes. According to the docs, everything is based on the type of the 2nd argument:
template<typename Range, typename Value,
typename Func, typename Reduction>
Value parallel_reduce( const Range& range, const Value& identity,
const Func& func, const Reduction& reduction,
[, partitioner[, task_group_context& group]] );
with pseudo-signatures of:
Value Func::operator()(const Range& range, const Value& x)
Value Reduction::operator()(const Value& x, const Value& y)
So a Value is passed into Func and into Reduction and returned. If you want uint64_ts everywhere, you'll need to ensure that Value is uint64_t. Which is why your (uint64_t)0 works but your 0 doesn't (and is actually undefined behavior to boot).
Note that this is the same problem that you would get with just normal accumulate:
std::vector<uint64_t> vs{0x7fffffff, 0x7fffffff, 0x7fffffff};
uint64_t sum = std::accumulate(vs.begin(), vs.end(), 0, std::plus<uint64_t>{});
// ^^^ oops, int 0!
// even though I'm using plus<uint64_t>!
assert(sum == 0x17ffffffd); // fails because actually sum is truncated
// and is just 0x7ffffffd

C++ STL std::random_shuffle cannot pass custom random number generator

I want to random_shuffle a vector (I know that random_shuffle is depreciated), but I get a compile error when I pass my custom random function which I copied from another thread on here. Can someone show me how to call random_shuffle using the random number generator posted below?
random_shuffle(defects.begin(), defects.end(), xorshf96);
static unsigned int x=123456789, y=362436069, z=521288629;
unsigned int xorshf96(void) { //period 2^96-1
unsigned int t;
x ^= x << 16;
x ^= x >> 5;
x ^= x << 1;
t = x;
x = y;
y = z;
z = t ^ x ^ y;
return z;
}
xorshf96 does not meet the requirements of the RandomFunc argument to std::random_shuffle:
r - function object returning a randomly chosen value of type convertible to std::iterator_traits<RandomIt>::difference_type in the interval [0,n) if invoked as r(n)
It must take an argument and return a random number less than it. The function is in implementation of the Knuth Shuffle and that is how that algorithm works.
As a sample fix, you could provide:
unsigned int xorshf96_fixed(int n)
{
return xorshf96() % n;
}
random_shuffle(defects.begin(), defects.end(), xorshf96_fixed);

Returning the actual value of maximum of absolutes of variables

I want to find the maximum of the absolute of two variables, and return the actual value of that variable, rather than the absolute value of that variable.
For example:
int x = 3;
int y = -5;
int z = max(abs(x), abs(y))
Will just set z to 5, whereas I want it to return -5. Is there a C++ function to perform this?
If you're using C++11, with the STL you could use a vector of int, max_element and a lambda Compare
std::vector<int> values = {3, -5};
int largest_abs = *std::max_element(values.begin(), values.end(), [](const int& a, const int& b)
{
return abs(a) < abs(b);
});
This returns the iterator between the start and end of values, whose absolute value is the largest. (this is found through the comparator) The * is then used to convert the iterator (returned by std::max_element) to an int
It's not a commonly used function, but writing your own function is trivial.
int max_abs(int x, int y)
{
if (x == INT_MIN || y == INT_MIN)
return INT_MIN;
return (abs(x) > abs(y)) ? x : y;
}
int z = (max(abs(x), abs(y)) == abs(x)) ? x : y;
This is like an if-condition. Its equivalent to
int z = x;
if(max(abs(x), abs(y)) != abs(z))
z = y;
But much shorter.
There is no function in the STL to fit into your needs directly, so you need to make your own and this one could be one version.
A more handy one can be int z = (abs(y) < abs(x)) ? x : y thought.

How to set configuration parameters using an array table?

Following situation: I have an array with some constant values, which represent ranges.
A range is always between two values in the array, e.g.: 10 - 20 = range1
20-30 = range2 and so on...
const int arr[] = {10, 20, 30, 40, 50, 60};
With a Search function, I search for the number(val) between those ranges in arr[] and return the range index where val was found.
For example: if val = 15 → return value would be 1
if val = 33 → return value would be 3
int Search(const int arr[], int n, int val)
{
int i = 0;
while (i < n) {
if (val > arr[i])
++i;
else
return i;
}
return -1;
}
OK, this works out so far...
Now following problem:
I have some parameters let's call them x, y, z which are simple integers and they depend on the value of val.
The parameter values for x, y, z I know already before compilation, of course they are different for every range.
How can I now set x, y and z using the range index?
How can I make an array for example with the constant parameter values for x, y, z and set them depending on the returned range index? Or should it be a struct?
How would that look like...?
Thx
You could hold the parameters for each range in a struct:
struct range_parameters {
int x;
int y;
// etc
}
And keep all these structs in a std::vector:
std::vector<range_parameters> params;
Adding the data would be done like this:
range_parameters params_for_range_1;
params_for_range_1.x = 1;
params_for_range_1.y = 2;
params[0] = params_for_range_1;
So finally you can access the parameters for range n as params[n-1].