#ifndef IMATHLIB_H_MATH_EXPRESSION_TEMPLATE_HPP
#define IMATHLIB_H_MATH_EXPRESSION_TEMPLATE_HPP
#include "IMathLib/math/expression_template/control_syntax.hpp"
#include "IMathLib/math/expression_template/expr_wrapper.hpp"
#include "IMathLib/math/expression_template/return.hpp"
//数式で数学関数を扱うためのもの
#include "IMathLib/math/expression_template/math/associative.hpp"
#include "IMathLib/math/expression_template/math/cos.hpp"
#include "IMathLib/math/expression_template/math/differential.hpp"
#include "IMathLib/math/expression_template/math/distributive.hpp"
#include "IMathLib/math/expression_template/math/math.hpp"
#include "IMathLib/math/expression_template/math/sin.hpp"
namespace iml {
namespace op {
//expr_wrapperのための数式の文字列生成
template <class T>
struct Estring {
using expr_type = T;
static auto estring(const expr_type& expr) {
std::stringstream ss;
ss << expr;
return ss.str();
}
};
template <class T>
struct Estring<expr_wrapper<none_tag, type_tuple<T>>> {
using expr_type = expr_wrapper<none_tag, type_tuple<T>>;
static auto estring(const expr_type& expr) {
std::stringstream ss;
ss << expr.name_m;
return ss.str();
}
};
//単項演算
template <class Expr>
struct Estring<expr_wrapper<add_tag, type_tuple<Expr>>> {
using expr_type = expr_wrapper<add_tag, type_tuple<Expr>>;
static auto estring(const expr_type& expr) {
std::stringstream ss;
if constexpr (operator_precedence<Expr>::value >= operator_precedence<expr_type>::value) {
ss << "+(" << Estring<Expr>::estring(expr.terms_m) << ')';
}
else {
ss << '+' << Estring<Expr>::estring(expr.terms_m);
}
return ss.str();
}
};
template <class Expr>
struct Estring<expr_wrapper<sub_tag, type_tuple<Expr>>> {
using expr_type = expr_wrapper<sub_tag, type_tuple<Expr>>;
static auto estring(const expr_type& expr) {
std::stringstream ss;
if constexpr (operator_precedence<Expr>::value >= operator_precedence<expr_type>::value) {
ss << "-(" << Estring<Expr>::estring(expr.terms_m) << ')';
}
else {
ss << '-' << Estring<Expr>::estring(expr.terms_m);
}
return ss.str();
}
};
//2項演算
template <class, class T>
struct Estring_tuple {
static constexpr auto estring(const T& x, index_tuple<size_t>) { return Estring<T>::estring(x); }
};
#define ESTRIGN_BINARY_OPERATION(NAME, OP)\
template <class First, class... Types>\
struct Estring_tuple<NAME##_tag, tuple<First, Types...>> {\
template <class T>\
static constexpr auto estring_impl(const T& x) {\
std::stringstream ss;\
if constexpr (is_tuple_v<T> || (operator_precedence<T>::value >= operator_precedence<expr_wrapper<NAME##_tag, type_tuple<First, Types...>>>::value)) {\
ss << "(" << Estring_tuple<NAME##_tag, T>::estring(x, index_range_t<size_t, 1, tuple_size_v<T>>()) << ')';\
}\
else {\
ss << Estring_tuple<NAME##_tag, T>::estring(x, index_range_t<size_t, 1, tuple_size_v<T>>());\
}\
return ss.str();\
}\
template <size_t... Indices>\
static constexpr auto estring(const tuple<First, Types...>& x, index_tuple<size_t, Indices...>) {\
std::stringstream ss;\
ss << Estring_tuple<NAME##_tag, First>::estring(x.get<0>(), index_range_t<size_t, 1, tuple_size_v<First>>());\
(ss << ... << ((#OP) + estring_impl(x.get<Indices>())));\
return ss.str();\
}\
};
ESTRIGN_BINARY_OPERATION(add, +);
ESTRIGN_BINARY_OPERATION(sub, -);
ESTRIGN_BINARY_OPERATION(mul, *);
ESTRIGN_BINARY_OPERATION(div, / );
#undef ESTRIGN_BINARY_OPERATION
template <class Op, class First, class Second, class... Types>
struct Estring<expr_wrapper<Op, type_tuple<First, Second, Types...>>> {
static constexpr auto estring(const expr_wrapper<Op, type_tuple<First, Second, Types...>>& expr) {
return Estring_tuple<Op, tuple<First, Second, Types...>>::estring(expr.terms_m
, index_range_t<size_t, 1, 2 + sizeof...(Types)>());
}
};
template <class Expr1, class Expr2>
struct Estring<expr_wrapper<subscript_tag, type_tuple<Expr1, Expr2>>> {
using expr_type = expr_wrapper<subscript_tag, type_tuple<Expr1, Expr2>>;
static auto estring(const expr_wrapper<subscript_tag, type_tuple<Expr1, Expr2>>& expr) {
std::stringstream ss;
if constexpr (operator_precedence<Expr1>::value > operator_precedence<expr_type>::value) {
ss << "(" << Estring<Expr1>::estring(expr.terms_m.get<0>()) << ')';
}
else {
ss << Estring<Expr1>::estring(expr.get<0>());
}
ss << '[' << Estring<Expr2>::estring(expr.get<1>()) << ']';
return ss.str();
}
};
template <class T>
auto estring(const T& expr) { return Estring<T>::estring(expr); }
template <class T, class = std::enable_if_t<is_expr_wrapper<T>::value>>
std::ostream& operator<<(std::ostream& os, const T& expr) {
os << estring(expr);
return os;
}
}
}
namespace iml {
namespace op {
//std::coutを識別子として登録
using cout_tag = ident_tag<100>;
//std::coutがコピー不可オブジェクトのためそのホルダのようなもの(intは型推論を機能させるためのダミー)
template <>
struct expr_wrapper<cout_tag, type_tuple<int, int>> {
template <class Expr>
expr_wrapper<cout_tag, type_tuple<Expr>> operator<<(const Expr& expr) {
return expr_wrapper<cout_tag, type_tuple<Expr>>(expr);
}
};
expr_wrapper<cout_tag, type_tuple<int, int>> ch;
template <class Expr>
struct Eval<expr_wrapper<cout_tag, type_tuple<Expr>>> {
template <class Result, class Tuple>
static constexpr void eval(Result& result, const expr_wrapper<cout_tag, type_tuple<Expr>>& expr, Tuple&& t) {
std::cout << Eval<Expr>::eval(result, expr.x_m, std::forward<Tuple>(t));
}
template <class Tuple>
static constexpr void eval(const expr_wrapper<cout_tag, type_tuple<Expr>>& expr, Tuple&& t) {
std::cout << Eval<Expr>::eval(expr.x_m, std::forward<Tuple>(t));
}
};
template <class Expr>
struct Estring<expr_wrapper<math_function_tag, type_tuple<iml::Sin<Expr>, tuple<Expr>, index_tuple<size_t, 0>>>> {
using expr_type = expr_wrapper<math_function_tag, type_tuple<iml::Sin<Expr>, tuple<Expr>, index_tuple<size_t, 0>>>;
static auto estring(const expr_type& expr) {
std::stringstream ss;
ss << "sin(" << Estring<Expr>::estring(expr.args_m.get<0>()) << ")";
return ss.str();
}
};
template <class Expr>
struct Estring<expr_wrapper<math_function_tag, type_tuple<iml::Cos<Expr>, tuple<Expr>, index_tuple<size_t, 0>>>> {
using expr_type = expr_wrapper<math_function_tag, type_tuple<iml::Cos<Expr>, tuple<Expr>, index_tuple<size_t, 0>>>;
static auto estring(const expr_type& expr) {
std::stringstream ss;
ss << "cos(" << Estring<Expr>::estring(expr.args_m.get<0>()) << ")";
return ss.str();
}
};
}
}
#endif