C++: piecewise function with loop initialization into a map - c++

Taking inspiration from: Defining a piecewise function (e.g. polynomial)
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
struct Point {
double x;
double y;
};
class LinearFunction {
public:
// Pre-calculate slope `m` and intercept `c`
LinearFunction(const Point &A, const Point &B){
double den = A.x-B.x;
m = (A.y-B.y)/den;
c = (A.x*B.y-A.y*B.x)/den;
}
// Evaluate at x
double operator()(double x){
return m*x+c;
}
private:
double m = 0;
double c = 0;
};
class PiecewiseFunction {
public:
// Initialize (m and c) for all segments of the piecewise
// function as a map of <lb,ub> -> function pointer
explicit PiecewiseFunction(std::vector<Point> &points){
for (int i = 0; i < points.size()-1; i++){
auto f = LinearFunction(points[i], points[i+1]);
fns.insert(std::make_pair(std::make_pair(points[i].x, points[i+1].x), &f));
}
}
double operator()( double x ) {
// Match segment lb <= x < ub and evaluate
auto iter = std::find_if(fns.cbegin(), fns.cend(),
[=](const auto &fn) {return x>=fn.first.first && x<fn.first.second;});
if (iter == fns.end()){
return 0;
} else {
return iter->second->operator()(x);
}
}
private:
std::map< std::pair<double,double>, LinearFunction*> fns;
};
int main() {
std::vector<Point> points {{0,0},{0.5,1},{1,0}};
PiecewiseFunction f{points};
std::cout << "x = 0.5; f(x) = " << f(0.5) << std::endl;
return 0;
}
which produces undefined behaviour:
x = 0.5; f(x) = 1.04297e-309
as the auto f = LinearFunction(points[i], points[i+1]); created in the loop goes out of scope.
I have been trying to find a solution that would let me create a piecewise function with e.g. 20 points

As suggested in the comments, I should store a copy not a dangling reference (as I am initializing in a loop).
The line in the inner loop goes from:
fns.insert(std::make_pair(std::make_pair(points[i].x, points[i+1].x), &f)); to
fns.insert(std::make_pair(std::make_pair(points[i].x, points[i+1].x), f));
and the variable declaration of fns, from:
std::map< std::pair<double,double>, LinearFunction *> fns; to:
std::map< std::pair<double,double>, LinearFunction> fns;
Finally,
return iter->second->operator()(x); to
return iter->second(x);

Related

Nonlinear least-squares fitting with two independent variables in C++: implementing GSL algorithm

Following up to a previous question I asked in Fixing parameters of a fitting function in Nonlinear Least-Square GSL (successfully answered by #zkoza), I would like to implement an algorithm that can fit data to a non-linear function, by fixing some of its parameters while leaving other parameters to change for finding the best fit to the data. The difference to my previous question is that I want to have two independent variables instead of one independent variable.
Non-linear function used to fit the data
double gaussian(double x, double b, double a, double c)
{
const double z = (x - b) / c;
return a * std::exp(-0.5 * z * z);
}
In my previous question I was considering that x was the only independent variable. Now I would like to consider two independent variables, x and b.
The original algorithm used to fit a non-linear function using only one independent variable (while fixing variable a) is a C++ wrapper of the GSL nonlinear least-squares algorithm (borrowed from https://github.com/Eleobert/gsl-curve-fit/blob/master/example.cpp):
template <typename F, size_t... Is>
auto gen_tuple_impl(F func, std::index_sequence<Is...> )
{
return std::make_tuple(func(Is)...);
}
template <size_t N, typename F>
auto gen_tuple(F func)
{
return gen_tuple_impl(func, std::make_index_sequence<N>{} );
}
template <class R, class... ARGS>
struct function_ripper {
static constexpr size_t n_args = sizeof...(ARGS);
};
template <class R, class... ARGS>
auto constexpr n_params(R (ARGS...) )
{
return function_ripper<R, ARGS...>();
}
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>
{
// This specifies a trust region method
const gsl_multifit_nlinear_type *T = gsl_multifit_nlinear_trust;
const size_t max_iter = 200;
const double xtol = 1.0e-8;
const double gtol = 1.0e-8;
const double ftol = 1.0e-8;
auto *work = gsl_multifit_nlinear_alloc(T, params, fdf->n, fdf->p);
int info;
// initialize solver
gsl_multifit_nlinear_init(initial_params, fdf, work);
//iterate until convergence
gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol, nullptr, nullptr, &info, work);
// result will be stored here
gsl_vector * y = gsl_multifit_nlinear_position(work);
auto result = std::vector<double>(initial_params->size);
for(int i = 0; i < result.size(); i++)
{
result[i] = gsl_vector_get(y, i);
}
auto niter = gsl_multifit_nlinear_niter(work);
auto nfev = fdf->nevalf;
auto njev = fdf->nevaldf;
auto naev = fdf->nevalfvv;
// nfev - number of function evaluations
// njev - number of Jacobian evaluations
// naev - number of f_vv evaluations
//logger::debug("curve fitted after ", niter, " iterations {nfev = ", nfev, "} {njev = ", njev, "} {naev = ", naev, "}");
gsl_multifit_nlinear_free(work);
gsl_vector_free(initial_params);
return result;
}
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*
{
auto* result = gsl_vector_alloc(vec.size());
int i = 0;
for(const auto e: vec)
{
gsl_vector_set(result, i, e);
i++;
}
return result;
}
template<typename C1>
struct fit_data
{
const std::vector<double>& t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
template<typename FitData, int n_params>
int internal_f(const gsl_vector* x, void* params, gsl_vector *f)
{
auto* d = static_cast<FitData*>(params);
// Convert the parameter values from gsl_vector (in x) into std::tuple
auto init_args = [x](int index)
{
return gsl_vector_get(x, index);
};
auto parameters = gen_tuple<n_params>(init_args);
// Calculate the error for each...
for (size_t i = 0; i < d->t.size(); ++i)
{
double ti = d->t[i];
double yi = d->y[i];
auto func = [ti, &d](auto ...xs)
{
// call the actual function to be fitted
return d->f(ti, xs...);
};
auto y = std::apply(func, parameters);
gsl_vector_set(f, i, yi - y);
}
return GSL_SUCCESS;
}
using func_f_type = int (*) (const gsl_vector*, void*, gsl_vector*);
using func_df_type = int (*) (const gsl_vector*, void*, gsl_matrix*);
using func_fvv_type = int (*) (const gsl_vector*, const gsl_vector *, void *, gsl_vector *);
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*;
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>;
template<typename C1>
auto curve_fit_impl(func_f_type f, func_df_type df, func_fvv_type fvv, gsl_vector* initial_params, fit_data<C1>& fd) -> std::vector<double>
{
assert(fd.t.size() == fd.y.size());
auto fdf = gsl_multifit_nlinear_fdf();
auto fdf_params = gsl_multifit_nlinear_default_parameters();
fdf.f = f;
fdf.df = df;
fdf.fvv = fvv;
fdf.n = fd.t.size();
fdf.p = initial_params->size;
fdf.params = &fd;
// "This selects the Levenberg-Marquardt algorithm with geodesic acceleration."
fdf_params.trs = gsl_multifit_nlinear_trs_lmaccel;
return internal_solve_system(initial_params, &fdf, &fdf_params);
}
template <typename Callable, auto n>
auto curve_fit(Callable f, const std::array<double, n>& initial_params, const std::vector<double>& x, const std::vector<double>& y) -> std::vector<double>
{
// We can't pass lambdas without convert to std::function.
//constexpr auto n = 3;//decltype(n_params(f))::n_args - 5;
//constexpr auto n = 2;
assert(initial_params.size() == n);
auto params = internal_make_gsl_vector_ptr(initial_params);
auto fd = fit_data<Callable>{x, y, f};
return curve_fit_impl(internal_f<decltype(fd), n>, nullptr, nullptr, params, fd);
}
In order to fix one of the parameters of the gaussian function, #zkoza proposed to use functors:
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(double x, double b, double c) const { return gaussian(x, b, a, c); }
};
And these last lines show how I would create a fake dataset of observed data (with some noise which is normally distributed) and test the fitting curve function with two independent variables, given by the vectors xs and bs.
int main()
{
auto device = std::random_device();
auto gen = std::mt19937(device());
auto xs = linspace<std::vector<double>>(0.0, 1.0, 300);
auto bs = linspace<std::vector<double>>(0.4, 1.4, 300);
auto ys = std::vector<double>(xs.size());
double a = 5.0, c = 0.15;
for(size_t i = 0; i < xs.size(); i++)
{
auto y = gaussian(xs[i], a, bs[i], c);
auto dist = std::normal_distribution(0.0, 0.1 * y);
ys[i] = y + dist(gen);
}
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{0.11}, xs, bs, ys);
std::cout << "result: " << r[0] << ' ' << '\n';
std::cout << "error : " << r[0] - c << '\n';
}
Do you have any idea on how I could implement the two-independent variables non-linear fitting?
The solution, as suggested in the comments by #BenVoigt, is to replace the x and b independent variables in the gaussian function with 'one independent variable' given as a vector, whose first element is x and the second element is b.
Also the backbone of the nonlinear fitting needs to be slightly edited. The edits consist:
Replace the fit_data functor with:
struct fit_data
{
const std::vector< vector<double> > &t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
Such that, the independent variable is no longer a vector but rather a vector of a vector (aka a matrix).
Replace within the function internal_f.
a) double ti = d->t[i] with std::vector<double> ti = d->t[i]
b) auto func = [ti, &d](auto ...xs) with auto func = [ti, &d](auto ...xs_matrix)
c) return d->f(ti, xs...) with return d->f(ti, xs_matrix...)
Replace within curve_fit function:
a) const std::vector<double>& x with const std::vector< vector<double> > &xs_matrix
b) auto fd = fit_data<Callable>{x, y, f} with auto fd = fit_data<Callable>{xs_matrix, y, f}
Whereas the gaussian function, gaussian_fixed_a functor and the fitting function looks like:
double gaussian(std::vector<double> x_vector, double a, double c)
{
const double z = (x_vector[0] - x_vector[1]) / c;
return a * std::exp(-0.5 * z * z);
}
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(std::vector<double> x_vector, double c) const { return gaussian(x_vector, a, c); }
};
double fittingTest(const std::vector< vector<double> > &xs_matrix, const std::vector<double> ys, const double a){
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{3.0}, xs_matrix, ys);
return r[0]);
}

How to find point of intersection in qcustomplot?

I have an app based on qt (qcustomplot) that prints two different graphs. They have one point of intersection. How to find x and y coordinates of this point?
This doesn't have much to do with plotting, since you'd be investigating the underlying data. Let's say that we can interpolate between data points using lines, and the data sets are single-valued (i.e. for any x or key coordinate, there's only one value).
Online demo of the code below
Let's sketch a solution. First, some preliminaries, and we detect whether QCustomPlot was included so that the code can be tested without it - the necessary classes are mocked:
#define _USE_MATH_DEFINES
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <optional>
#include <type_traits>
#include <vector>
//#include "qcustomplot.h"
constexpr bool debugOutput = false;
#ifndef QCP_PLOTTABLE_GRAPH_H
struct QCPGraphData {
double key, value;
QCPGraphData() = default;
QCPGraphData(double x, double y) : key(x), value(y) {}
};
#endif
auto keyLess(const QCPGraphData &l, const QCPGraphData &r) { return l.key < r.key; }
#ifndef QCP_PLOTTABLE_GRAPH_H
template <typename T> struct QCPDataContainer : public std::vector<T> {
using std::vector<T>::vector;
void sort() { std::sort(this->begin(), this->end(), keyLess); }
};
using QCPGraphDataContainer = QCPDataContainer<QCPGraphData>;
#endif
using Point = QCPGraphData;
using Container = QCPGraphDataContainer;
static_assert(std::is_copy_constructible_v<Point>, "Point must be copy-constructible");
Some helper functions:
std::ostream &operator<<(std::ostream &os, const Point &p) {
return os << "(" << p.key << ", " << p.value << ")";
}
template <class T> bool has_unique_keys(const T &v) {
constexpr auto keyEqual = [](const Point &l, const Point &r) { return l.key == r.key; };
return std::adjacent_find(std::begin(v), std::end(v), keyEqual) == std::end(v);
}
template <class T> bool has_valid_points(const T& v) {
constexpr auto isValid = [](const Point &p) { return std::isfinite(p.key) && std::isfinite(p.value); };
return std::all_of(std::begin(v), std::end(v), isValid);
}
The line segment intersection finder:
// intersection of two line segments
std::optional<Point> intersection(const Point &a1, const Point &a2, const Point &b1, const Point &b2)
{
auto p1 = a1, p2 = a2, p3 = b1, p4 = b2;
assert(p1.key <= p2.key);
assert(p3.key <= p4.key);
if (debugOutput) std::cout << p1 << "-" << p2 << ", " << p3 << "-" << p4;
auto const denom = (p1.key - p2.key)*(p3.value - p4.value)
- (p1.value - p2.value)*(p3.key - p4.key);
if (fabs(denom) > 1e-6*(p2.key - p1.key)) {
// the lines are not parallel
auto const scale = 1.0/denom;
auto const q = p1.key*p2.value - p1.value*p2.key;
auto const r = p3.key*p4.value - p3.value*p4.key;
auto const x = (q*(p3.key-p4.key) - (p1.key-p2.key)*r) * scale;
if (debugOutput) std::cout << " x=" << x << "\n";
if (p1.key <= x && x <= p2.key && p3.key <= x && x <= p4.key) {
auto const y = (q*(p3.value-p4.value) - (p1.value-p2.value)*r) * scale;
return std::optional<Point>(std::in_place, x, y);
}
}
else if (debugOutput) std::cout << "\n";
return std::nullopt;
}
An algorithm that walks down two lists of points sorted in ascending key (x) order, and finds all intersections of line segments spanning consecutive point pairs from these two lists:
std::vector<Point> findIntersections(const Container &a_, const Container &b_)
{
if (a_.size() < 2 || b_.size() < 2) return {};
static constexpr auto check = [](const auto &c){
assert(has_valid_points(c));
assert(std::is_sorted(c.begin(), c.end(), keyLess));
assert(has_unique_keys(c));
};
check(a_);
check(b_);
bool aFirst = a_.front().key <= b_.front().key;
const auto &a = aFirst ? a_ : b_, &b = aFirst ? b_ : a_;
assert(a.front().key <= b.front().key);
if (a.back().key < b.front().key) return {}; // the key spans don't overlap
std::vector<Point> intersections;
auto ia = a.begin(), ib = b.begin();
Point a1 = *ia++, b1 = *ib++;
while (ia->key < b1.key) a1=*ia++; // advance a until the key spans overlap
for (Point a2 = *ia, b2 = *ib;;) {
auto const ipt = intersection(a1, a2, b1, b2);
if (ipt)
intersections.push_back(*ipt);
bool advanceA = a2.key <= b2.key, advanceB = b2.key <= a2.key;
if (advanceA) {
if (++ia == a.end()) break;
a1 = a2, a2 = *ia;
}
if (advanceB) {
if (++ib == b.end()) break;
b1 = b2, b2 = *ib;
}
}
return intersections;
}
And a more generic version that can also sort the points in ascending key order:
auto findIntersections(Container &d1, Container &d2, bool presorted)
{
if (!presorted) {
d1.sort();
d2.sort();
}
return findIntersections(d1, d2);
}
And now some simple demonstration:
template <typename Fun>
Container makeGraph(double start, double step, double end, Fun &&fun) {
Container result;
int i = 0;
for (auto x = start; x <= end; x = ++i * step)
result.emplace_back(x, fun(x));
return result;
}
int main()
{
for (auto step2: {0.1, 0.1151484584}) {
auto sinPlot = makeGraph(-2*M_PI, 0.1, 3*M_PI, sin);
auto cosPlot = makeGraph(0., step2, 2*M_PI, cos);
auto intersections = findIntersections(sinPlot, cosPlot);
std::cout << "Intersections:\n";
for (auto &ip : intersections)
std::cout << " at " << ip << "\n";
}
}
Demo output:
Intersections:
at (0.785613, 0.706509)
at (3.92674, -0.706604)
Intersections:
at (0.785431, 0.706378)
at (3.92693, -0.706732)

how to return function pointer of compound function in c++?

for example, how to turn below code in matlab to a c++ equivalence?
function g = Transform(funct, y)
h = #(x) funct(x) +y;
g = #(x) sign(h(x));
end
the above code takes in a function named "funct" and a input value "y". It outputs a new (transformed) function named g.
a usage of this in matlab would be
function main()
for i = 1:5
y = rand();
funct = Tranform(funct,y);
end
disp(funct(1.27)); % after transformed 5 times
end
function z = funct(x)
z = x;
end
You can, but it looks a little more messy. For this you can use lambda functions together with std::function like so
#include <iostream>
#include <string>
#include <functional>
template <typename T> int sgn(T val)
{
return (T(0) < val) - (val < T(0));
}
std::function<int(double)> transform(std::function<double(double)> funct, double y )
{
std::function<int(double)> h = [=](double x) -> int
{
return sgn(funct(x) + y);
};
return h;
}
int main()
{
auto f = [](double x) -> double { return x + 5.; };
auto res = transform(f, 5.);
std::cout << res(-15.) << std::endl;
}
Which outputs:
res(-10) -> 0
res(> -10) -> 1
res(< -10) -> -1

C++ -- How write a function, that return the derivative of a real valued function, not the value of the derivative

This function calculates the value of the Derivation of the Function Foo at X
double Deriv( double(* Foo)(double x), double X )
{
const double mtDx = 1.0e-6;
double x1 = Foo(X+mtDx);
double x0 = Foo(X);
return ( x1 - x0 ) / mtDx;
}
I would like to write a Funktion, which returned not the value of the derivation at X, but a new function which IS the derivation of the function Foo.
xxxx Deriv( double(* Foo)(double x) )
{
return Derivation of Foo;
}
Then it would be possible to write
SecondDeriv = Deriv( Deriv( Foo ))
Is it possible in C++ according to new standard to write such a function ?
I think with old standard it was impossible.
Once you can compute the value of a function at one point, you can use that to implement your general function. Lambda expressions allow you to generate those derived functions easily:
auto MakeDerivative(double (&f)(double)) {
return [=](double x) { return Deriv(f, x); };
}
If you want to be able to use stateful functions, you may need to update your Deriv to be a function template whose first parameter type is a template parameter. This is true in particular if you want to apply MakeDerivative repeatedly (since its return types are stateful closures):
template <typename F>
double Deriv(F f, double x) {
// your code here
}
template <typename F>
auto MakeDerivative(F f) {
return [=](double x) { return Deriv(f, x); };
}
However, you may be interested in techniques like "automatic differentiation" which allow you to express the derivative directly in terms of the definition of the original function, at the cost of working on an enlarged domain (an infinitesimal neighbourhood, essentially).
Here's one way to do it.
#include <iostream>
#include <functional>
std::function<double(double)> Deriv( double(*Foo)(double x) )
{
auto f = [Foo](double x) -> double
{
const double mtDx = 1.0e-6;
double x1 = Foo(x+mtDx);
double x0 = Foo(x);
return ( x1 - x0 ) / mtDx;
};
return f;
}
double Foo(double x)
{
return x*x;
}
double Bar(double x)
{
return x*x*x;
}
int main()
{
std::cout << Deriv(Foo)(10) << std::endl;
std::cout << Deriv(Bar)(10) << std::endl;
}
Output:
20
300
Using generic lambda, implementing a toy derivative is simple. In the following code, derivative is a derivative operator in the math sense. It accepts a function double -> double, produces its derivative double -> double.
#include <iostream>
double delta = 0.001;
auto derivative = [] ( auto foo ) {
return [foo] (double x) {
// the simplest formula for numeric derivative
return (foo(x + delta) - foo(x)) / delta;
};
};
// test
int main() {
auto quar = [] ( double x ) { return x * x; };
auto dev_quar = derivative(quar);
auto dev_dev_quar = derivative(dev_quar);
for ( double s = 0.0; s < 10.0; ++s ) {
std::cout << "(" << quar(s) << "," << dev_quar(s) << "," << dev_dev_quar(s) << ")\n";
}
}

c++ error C2064 for nested bind in C++ template

If I compile the code below, I get an:
microsoft visual studio 12.0\vc\include\xrefwrap(58): error C2064: term does not evaluate to a function taking 2 arguments
In the call to accumulate algorithm, if I change the code to function<double(double, Position const&) > f = bind(sum, placeholders::_1, bind(mem_fn(&Position::getBalance), placeholders::_2));double sum = accumulate(balances.begin(), balances.end(), 0., f); everything compiles fine. I also tried to use a non member function, but it doesn't work neither.
class Position
{
private:
double m_balance;
public:
Position(double balance) :
m_balance(balance)
{}
double getBalance() const
{
return m_balance;
}
};
static double sum(double v1, double v2)
{
return v1 + v2;
}
int main(int argc, char ** argv)
{
std::vector< Position > balances;
for (size_t i = 0; i < 10; i++)
{
balances.push_back(Position(i));
}
double sum = accumulate(balances.begin(), balances.end(), 0., bind(sum, placeholders::_1, bind(mem_fn(&Position::getBalance), placeholders::_2)));
cout << sum << endl;
return 0;
}
This will fix it:
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
std::bind(std::plus<>(),
placeholders::_1,
std::bind(&Position::getBalance, placeholders::_2)));
or we could be kind to our fellow programmers:
auto add_balance = [](auto x, auto& position) {
return x + position.getBalance();
};
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
add_balance);
Or of course we can inline the lambda. There's no performance difference. Which one seems clearer will be a matter of personal preference.
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
[](auto x, auto& position)
{
return x + position.getBalance();
});
Or we can write a complex functor to do a similar job. This was the pre-lambda way:
template<class Op>
struct PositionOp
{
using mfp_type = double (Position::*)() const;
PositionOp(Op op, mfp_type mfp) : op(op), mfp(mfp) {}
template<class T>
auto operator()(T x, const Position& pos) const {
return op(x, (pos.*mfp)());
}
Op op;
mfp_type mfp;
};
template<class Op>
auto position_op(Op op, double (Position::*mfp)() const)
{
return PositionOp<Op>(op, mfp);
}
...
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
position_op(std::plus<>(), &Position::getBalance));
... but I hope you'll agree that this is ghastly.