Last active
September 14, 2015 21:46
-
-
Save 2bbb/aea74128484a5b220fe8 to your computer and use it in GitHub Desktop.
symbolic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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