Weitere ähnliche Inhalte Ähnlich wie C++ Expression Templateを使って式をコンパイル時に微分 (20) Kürzlich hochgeladen (20) C++ Expression Templateを使って式をコンパイル時に微分2. : y x
!!
double x = 1.0;
double y = 3.0 * x + 2.0;
double dydx = derivative(y) // ?
4 2 y
4 (Expression Template)
4. : <operator, 1, 2>
struct add_op {}; struct sub_op {}; struct mul_op {}; struct div_op {};
template<typename OP, typename E1, typename E2>
class binary_expression {
public:
binary_expression(const E1& e1, const E2& e2)
: _e1(e1), _e2(e2){
}
const E1& e1() const {return _e1;}
const E2& e2() const {return _e2;}
private:
const E1 _e1;
const E2 _e2;
};
class Variable {
public:
Variable(const double x): _x(x) {}
double get() const {return _x;}
private:
const double _x;
};
5. :
template<typename E1, typename E2>
auto operator +(const E1& x, const E2& y) {
return binary_expression<add_op, E1, E2>(x, y);
};
template<typename E1, typename E2>
auto operator -(const E1& x, const E2& y) {
return binary_expression<sub_op, E1, E2>(x, y);
};
template<typename E1, typename E2>
auto operator *(const E1& x, const E2& y) {
return binary_expression<mul_op, E1, E2>(x, y);
};
template<typename E1, typename E2>
auto operator /(const E1& x, const E2& y) {
return binary_expression<div_op, E1, E2>(x, y);
};
6. int main() {
auto x = Variable(1.0);
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
auto y2 = y1 * y0;
std::cout << typeid(y0).name() << std::endl;
std::cout << typeid(y1).name() << std::endl;
std::cout << typeid(y2).name() << std::endl;
}
4
7. code
auto y0 = x + 2.0;
std::cout << typeid(y0).name() << std::endl;
output
binary_expression<add_op, Variable, double>
8. code
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
std::cout << typeid(y1).name() << std::endl;
output
binary_expression<
add_op,
binary_expression<
mul_op, double, binary_expression<add_op, Variable, double>
>,
double
>
9. code
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
auto y2 = y1 * y0;
std::cout << typeid(y2).name() << std::endl;
output
binary_expression<
mul_op,
binary_expression<
add_op,
binary_expression<mul_op, double, binary_expression<add_op, Variable, double> >,
double
>,
binary_expression<add_op, Variable, double>
>
10. : !
auto eval(const Variable& e) {return e.get();}
auto eval(const double e) {return e;}
template<typename E1, typename E2>
auto eval(const binary_expression<add_op, E1, E2>& e) {
return eval(e.e1()) + eval(e.e2());
}
template<typename E1, typename E2>
auto eval(const binary_expression<mul_op, E1, E2>& e) {
return eval(e.e1()) * eval(e.e2());
}
11. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
auto y2 = y1 * y0;
std::cout << eval(y2) << std::endl;
output
42
12. : eval
auto diff(const double e) {return 0;}
auto diff(const Variable& e) {return 1;}
template<typename E1, typename E2>
auto diff(const binary_expression<add_op, E1, E2>& e) {
// x + y -> dx + dy
return diff(e.e1()) + diff(e.e2());
}
template<typename E1, typename E2>
auto diff(const binary_expression<mul_op, E1, E2>& e) {
// x * y -> dx * y + x * dy
return diff(e.e1()) * eval(e.e2()) + eval(e.e1()) * diff(e.e2());
}
13. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
auto y2 = y1 * y0;
std::cout << diff(y0) << std::endl;
std::cout << diff(y1) << std::endl;
std::cout << diff(y2) << std::endl;
output
1
3
23
15. auto x = Variable(1.0);
auto y = 3.0 * x * x + 2.0 * x;
auto dydx = derivative(y)
std::cout << typeid(dydx).name() << std::endl;
y
// 6.0 * x + 2.0
binary_expression<
add_op,
binary_expression<mul_op, double, Variable>,
double
>
16. class one {};
class zero {};
auto derivative(const double e) {return zero();}
auto derivative(const Variable& e) {return one();}
template<typename E1, typename E2>
auto derivative(const binary_expression<add_op, E1, E2>& e) {
return derivative(e.e1()) + derivative(e.e2());
}
template<typename E1, typename E2>
auto derivative(const binary_expression<mul_op, E1, E2>& e) {
return e.e1() * derivative(e.e2()) + derivative(e.e1()) * e.e2();
}
17. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
std::cout << typeid(y0).name() << std::endl;
output
binary_expression<add_op, one, zero>
18. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
std::cout << typeid(y1).name() << std::endl;
output
binary_expression<
add_op,
binary_expression<
add_op,
binary_expression<
mul_op,
double,
binary_expression<add_op, one, zero>
>,
binary_expression<
mul_op,
zero,
binary_expression<add_op, Variable, double>
>
>,
zero
>
20. : !
4 a + 0 = a
template <typename E>
auto operator +(const E& e, const zero&) {return e;}
template <typename E>
auto operator +(const zero&, const E& e) {return e;}
template <typename E>
auto operator *(const E& e, const zero&) {return zero();}
template <typename E>
auto operator *(const zero&, const E& e) {return zero();}
template <typename E>
auto operator *(const E& e, const one&) {return e;}
template <typename E>
auto operator *(const one&, const E& e) {return e;}
21. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
std::cout << typeid(y0).name() << std::endl;
output! one !
one
22. code
auto x = Variable(1.0);
auto y0 = x + 2.0;
auto y1 = 3.0 * y0 + 5.0;
std::cout << typeid(y1).name() << std::endl;
output!! double !!
double