Skip to content

Instantly share code, notes, and snippets.

@2bbb
Last active September 14, 2015 21:46
Show Gist options
  • Select an option

  • Save 2bbb/aea74128484a5b220fe8 to your computer and use it in GitHub Desktop.

Select an option

Save 2bbb/aea74128484a5b220fe8 to your computer and use it in GitHub Desktop.
symbolic
#include <functional>
#include <tuple>
#include <memory>
namespace symbolic {
template <typename T>
using ref = std::shared_ptr<T>;
template <typename type>
struct value {
value()
: v(std::make_shared<type>()) {};
value(type v)
: v(std::make_shared<type>(v)) {};
virtual type get() const { return *v; }
virtual const value &operator=(const value &x) {
v = x.v;
return *this;
}
const operator type() const {
return get();
}
private:
ref<const type> v;
};
template <typename type>
struct variable : value<type> {
variable()
: x(std::make_shared<type>()) {};
variable(type v)
: x(std::make_shared<type>(v)) {};
virtual void set(type x) { *(this->x) = x; }
virtual type get() const { return *x; }
virtual const variable &operator=(const value<type> &x) {
*(this->x) = x.get();
return *this;
}
virtual const variable &operator=(const variable &x) {
this->x = x.x;
return *this;
}
private:
ref<type> x;
};
namespace {
template <typename res, typename ... args>
std::function<variable<res>(variable<args> ...)> convert_to_algebraic(const std::function<res(args ...)> &f) {
return [=](variable<args> ... arguments) {
return f(arguments.get() ...);
};
}
template<int ...>
struct sequence { };
template<int n, int ... seq>
struct generator : generator<n - 1, n - 1, seq ...> { };
template<int ...seq>
struct generator<0, seq ...> {
typedef sequence<seq ...> type;
};
template <typename res, typename ... args>
res apply(std::function<res(args ...)> &f, const std::tuple<args ...> &arguments) {
return apply_impl(typename generator<sizeof...(args)>::type(), f, arguments);
};
template<int ... seq, typename res, typename ... args>
res apply_impl(sequence<seq ...>, std::function<res(args ...)> &f, const std::tuple<args ...> &arguments) {
return f(std::get<seq>(arguments) ...);
};
};
template <typename res, typename ... args>
struct result_value : value<res> {
using function_type = std::function<variable<res>(variable<args> ...)>;
result_value(ref<function_type> f, variable<args> ... arguments)
: f(f)
, arguments(arguments ...) {}
virtual res get() const {
return apply(*f, arguments).get();
}
ref<function_type> f;
std::tuple<variable<args> ...> arguments;
};
template <typename res, typename ... args>
struct function {
function() {}
function(const std::function<res(args ...)> &f)
: f(std::make_shared<decltype(f)>(f))
, f_(std::make_shared<decltype(f_)>(convert_to_algebraic(f))) {};
void set(const std::function<res(args ...)> &f) {
this->f = std::make_shared<std::function<res(args ...)>>(f);
this->f_ = std::make_shared<std::function<variable<res>(variable<args> ...)>>(convert_to_algebraic(f));
}
const std::function<res(args ...)> &get() const { return *f; }
result_value<res, args ...> operator()(variable<args> ... arguments) { return result_value<res, args ...>(f_, arguments ...); }
ref<std::function<res(args ...)>> f;
ref<std::function<variable<res>(variable<args> ...)>> f_;
};
};
#include <iostream>
int main(int argc, char *argv[]) {
symbolic::variable<double> x = 4.0;
symbolic::function<double, double> f;
f.set([](double x) { return x * x; });
std::cout << x << std::endl;
auto y = f(x);
std::cout << y << std::endl;
x.set(5.0);
std::cout << y << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment