diff --git a/include/expolit/differentiation.hh b/include/expolit/differentiation.hh index 94e8e4b..a1a496c 100644 --- a/include/expolit/differentiation.hh +++ b/include/expolit/differentiation.hh @@ -1,143 +1,143 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef DIFFERENTIATION_HH #define DIFFERENTIATION_HH #include "exponential.hh" #include "litteral.hh" #include "operations.hh" #include "polynomial.hh" #include "types.hh" #include namespace expolit { namespace detail { template struct for_diff { template constexpr static void diff(std::array& res, const std::array& a) { std::get(res) = a[i + 1] * static_cast(i + 1); for_diff::diff(res, a); } }; template <> struct for_diff<0> { template constexpr static void diff(std::array& res, const std::array& a) { std::get<0>(res) = a[1] * static_cast(1); } }; } // namespace detail /// Differentiate polynomial template constexpr auto differentiate(const Polynomial& p) { Polynomial dp; detail::for_diff::diff(dp.coeffs, p.coeffs); return dp; } /// Differentiate constant template constexpr auto differentiate(const Constant& /*p*/) { return Constant({0}); } /// Differentiate litteral template constexpr auto differentiate(const Litteral& /*p*/) { return 0; } /// Differentiate exponential template constexpr auto differentiate(const Exponential& e) { return differentiate(e.expression) * e; } /// Differentiate generic product template constexpr auto differentiate(const Product& p) { auto&& o = p.operands; return differentiate(o.first) * o.second + o.first * differentiate(o.second); } /// Differentiate constant + expression template constexpr auto differentiate(const Sum, U>& p) { return differentiate(p.operands.second); } /// Differentiate expression + constant template constexpr auto differentiate(const Sum>& p) { return differentiate(p.commute()); } /// Differentiate litteral + expression template constexpr auto differentiate(const Sum, U>& p) { return differentiate(p.operands.second); } /// Differentiate expression + litteral template constexpr auto differentiate(const Sum>& p) { return differentiate(p.commute()); } /// Differentiate constant * expression template constexpr auto differentiate(const Product, U>& p) { return p.operands.first * differentiate(p.operands.second); } /// Differentiate expression * constant template constexpr auto differentiate(const Product>& p) { return differentiate(p.commute()); } /// Differentiate litteral * expression template constexpr auto differentiate(const Product, U>& p) { return p.operands.first * differentiate(p.operands.second); } /// Differentiate expression * litteral template constexpr auto differentiate(const Product>& p) { return differentiate(p.commute()); } } // namespace expolit #endif diff --git a/include/expolit/expolit b/include/expolit/expolit index 1e7cb15..d9511bd 100644 --- a/include/expolit/expolit +++ b/include/expolit/expolit @@ -1,38 +1,38 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef EXPOLIT_HEADER #define EXPOLIT_HEADER #include "types.hh" #include "operations.hh" #include "polynomial.hh" #include "exponential.hh" #include "litteral.hh" #include "differentiation.hh" #include "integration.hh" #endif diff --git a/include/expolit/exponential.hh b/include/expolit/exponential.hh index 3047a72..b600ac5 100644 --- a/include/expolit/exponential.hh +++ b/include/expolit/exponential.hh @@ -1,74 +1,74 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef EXPONENTIAL_HH #define EXPONENTIAL_HH #include "types.hh" #include "operations.hh" #include #include #include namespace expolit { namespace detail { // Necessary for proper dispatch using std::exp; struct ExponentialFunctor { template constexpr auto operator()(Val&& v) const { return exp(v); // Should dispatch in case expression is passed } }; } /** * @brief Exponential expression * * Handles exponential of arbitrary expression */ template using Exponential = UnaryOperation; template constexpr auto exp(const Expression& e) { return Exponential>(e.downcast()); } /* -------------------------------------------------------------------------- */ /* Output */ /* -------------------------------------------------------------------------- */ template std::ostream& operator<<(std::ostream& os, const Exponential& e) { os << "exp(" << e.expression << ")"; return os; } } // namespace expolit #endif diff --git a/include/expolit/integration.hh b/include/expolit/integration.hh index 04ad777..ba61b4f 100644 --- a/include/expolit/integration.hh +++ b/include/expolit/integration.hh @@ -1,155 +1,155 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef INTEGRATION_HH #define INTEGRATION_HH #include "differentiation.hh" #include "exponential.hh" #include "litteral.hh" #include "polynomial.hh" #include "types.hh" namespace expolit { namespace detail { template struct for_integ { template static constexpr void integ(std::array& res, const std::array& a) { std::get(res) = a[i-1] / static_cast(i); for_integ::integ(res, a); } }; template <> struct for_integ<1> { template static constexpr void integ(std::array& res, const std::array& a) { std::get<1>(res) = a[0]; } }; } // namespace detail /// Integrate polynomial template constexpr auto integrate(const Polynomial& p) { Polynomial ip; detail::for_integ::integ(ip.coeffs, p.coeffs); return ip; } /// Integrate litteral template constexpr auto integrate(const Litteral& q) { constexpr Polynomial id({0, 1}); return q * id; } /// Integrate constant * expression template constexpr auto integrate(const Product, Derived>& p) { return p.operands.first * integrate(p.operands.second); } /// Integrate expression * constant template constexpr auto integrate(const Product>& p) { return integrate(p.commute()); } /// Integrate litteral * expression template constexpr auto integrate(const Product, Derived>& p) { return p.operands.first * integrate(p.operands.second); } /// Integrate expression * litteral template constexpr auto integrate(const Product>& p) { return integrate(p.commute()); } /// Integrate litteral / expression template constexpr auto integrate(const Division>& p) { return integrate(p.operands.first) / p.operands.second; } /// Integrate exponential of order 1 polynomial template constexpr auto integrate(const Exponential>& e) { return Constant({1 / e.expression.coeffs.back()}) * e; } /// Integrate exponential of litteral * order 1 polynomial template constexpr auto integrate(const Exponential, Polynomial>>& e) { return e * Constant({1 / e.expression.operands.second.coeffs.back()}) / e.expression.operands.first; } /// Integrate exponential of order 1 polynomial * litteral template constexpr auto integrate(const Exponential, Litteral>>& e) { return integrate(e.op(e.expression.commute())); } /// Integration by parts of expression * polynomial template constexpr auto integrate(const Product>& p) { auto u = integrate(p.operands.first); return u * p.operands.second - integrate(u * differentiate(p.operands.second)); } /// Integration by parts of polynomial * expression template constexpr auto integrate(const Product, Derived>& p) { return integrate(p.commute()); } /// Integration of sum template constexpr auto integrate(const Sum& s) { return integrate(s.operands.first) + integrate(s.operands.second); } /// Compute definite integral template constexpr auto definite_integral(const std::pair& bounds, const Expression& exp) { auto integ = integrate(exp.downcast()); return integ(bounds.second) - integ(bounds.first); } } // namespace expolit #endif diff --git a/include/expolit/litteral.hh b/include/expolit/litteral.hh index 67073b0..096c02c 100644 --- a/include/expolit/litteral.hh +++ b/include/expolit/litteral.hh @@ -1,80 +1,80 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef LITTERAL_HH #define LITTERAL_HH #include "operations.hh" #include "polynomial.hh" #include "types.hh" namespace expolit { template struct Litteral : Expression> { using tag = Tag; Litteral() = default; }; /// Substitue litteral template constexpr auto substitute(const Expression& val, const Litteral& /*t*/) { return val.downcast(); } /// Substitute litteral in binary operation template constexpr auto substitute(const Expression& val, const BinaryOperation& op) { return op.op(substitute(val, op.operands.first), substitute(val, op.operands.second)); } /// Substitute litteral in polynomial (aka do nothing) template constexpr auto substitute(const Expression& /*val*/, const Polynomial& p) { return p; } /// Substitute litteral in polynomial (aka do nothing) template constexpr auto substitute(const Expression& val, const UnaryOperation& p) { return p.op(substitute(val, p.expression)); } /// Substitute generic expression by downcast // template // constexpr auto substitute(const Expression& val, // const Expression& e) { // return substitute(val, e.downcast()); // } } // namespace expolit #endif diff --git a/include/expolit/operations.hh b/include/expolit/operations.hh index 38954d3..78d005e 100644 --- a/include/expolit/operations.hh +++ b/include/expolit/operations.hh @@ -1,189 +1,189 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef OPERATIONS_HH #define OPERATIONS_HH #include "types.hh" #include #include #include namespace expolit { /** * @brief Type for unary operation */ template struct UnaryOperation : Expression> { /// Construct from an expression constexpr UnaryOperation(const Expression& t) : expression(t.downcast()) {} /// Evaluate operation template constexpr auto operator()(Val&& v) const { return op(expression(v)); } const T expression; const Op op = Op(); }; /** * @brief Type for binary operation * * Handles binary operations between two arbitrary expressions */ template struct BinaryOperation : Expression> { /// Construct from two expressions constexpr BinaryOperation(const Expression& t, const Expression& u) : operands(t.downcast(), u.downcast()) {} /// Evaluate operation template constexpr auto operator()(Val&& v) const { return op(operands.first(v), operands.second(v)); } constexpr auto commute() const { return BinaryOperation(operands.second, operands.first); } /// Product operarands const std::pair operands; const Op op = Op(); }; /// Symmetric of T, U template using SBinaryOperation = BinaryOperation; /// Product expression template using Product = BinaryOperation>; /// Sum expression template using Sum = BinaryOperation>; /// Difference expression template using Difference = BinaryOperation>; /// Division expression template using Division = BinaryOperation>; /* -------------------------------------------------------------------------- */ /* Algebraic rules */ /* -------------------------------------------------------------------------- */ /// Product operator template constexpr auto operator*(const Expression& e1, const Expression& e2) { return Product(e1, e2); } /// Sum operator template constexpr auto operator+(const Expression& e1, const Expression& e2) { return Sum(e1, e2); } /// Difference operator template constexpr auto operator-(const Expression& e1, const Expression& e2) { return Difference(e1, e2); } /// Division operator template constexpr auto operator/(const Expression& e1, const Expression& e2) { return Division(e1, e2); } namespace detail { template struct power_acc { template static constexpr auto accumulate(const Expression& acc, const Expression& e) { return power_acc::accumulate(acc.downcast() * e.downcast(), e); } }; template <> struct power_acc<1> { template static constexpr auto accumulate(const Expression& acc, const Expression&) { return acc.downcast(); } }; } // namespace detail template constexpr auto pow(const Expression& e) { return detail::power_acc::accumulate(e, e); } /* -------------------------------------------------------------------------- */ /* Output */ /* -------------------------------------------------------------------------- */ template std::ostream& operator<<(std::ostream& os, const Product& p) { os << "(" << p.operands.first << ")" << " * " << "(" << p.operands.second << ")"; return os; } template std::ostream& operator<<(std::ostream& os, const Division& p) { os << "(" << p.operands.first << ")" << " / " << "(" << p.operands.second << ")"; return os; } template std::ostream& operator<<(std::ostream& os, const Difference& p) { os << p.operands.first << " - " << p.operands.second; return os; } template std::ostream& operator<<(std::ostream& os, const Sum& p) { os << p.operands.first << " + " << p.operands.second; return os; } } // namespace expolit #endif diff --git a/include/expolit/polynomial.hh b/include/expolit/polynomial.hh index c42525c..fd002b9 100644 --- a/include/expolit/polynomial.hh +++ b/include/expolit/polynomial.hh @@ -1,327 +1,327 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef POLYNOMIALS_HH #define POLYNOMIALS_HH #include "operations.hh" #include "types.hh" #include #include #include #include namespace expolit { template using compatible = std::enable_if_t::value>; /** * @brief Polynomial type * * Type for polynomial expressions of arbitrary order, variable type and * coefficient type */ template struct Polynomial : Expression> { /// Number of terms constexpr static std::size_t terms = order + 1; constexpr Polynomial() = default; constexpr explicit Polynomial(const std::array& coeffs) : coeffs(coeffs) {} /// Evaluating polynomial template > constexpr auto operator()(Val z) const { using Res = decltype(std::declval() * z); Res res(coeffs.front()); Val power(z); for (UInt i = 1; i < terms; ++i) { res += coeffs[i] * power; power *= z; } return res; } /// Storing coefficients std::array coeffs = {0}; }; template using Constant = Polynomial; namespace detail { template struct get_terms : std::integral_constant< std::size_t, std::remove_reference_t>::terms> { }; } // namespace detail /* -------------------------------------------------------------------------- */ /* Algebraic rules */ /* -------------------------------------------------------------------------- */ /// Sum with scalar template > constexpr auto operator+(DT x, const Polynomial& p) { Polynomial() + x), order> res(p); std::get<0>(res.coeffs) += x; return res; } /// Sum with scalar template > constexpr auto operator+(const Polynomial& p, DT x) { return x + p; } namespace detail { template struct for_scalar { template constexpr static void prod(std::array& res, DT x) { std::get(res) *= x; for_scalar::prod(res, x); } template constexpr static void div(std::array& res, DT x) { std::get(res) /= x; for_scalar::prod(res, x); } }; template <> struct for_scalar<0> { template constexpr static void prod(std::array& res, DT x) { std::get<0>(res) *= x; } template constexpr static void div(std::array& res, DT x) { std::get<0>(res) /= x; } }; } // namespace detail /// Product with scalar template > constexpr auto operator*(DT x, const Polynomial& p) { Polynomial() * x), order> res(p); detail::for_scalar::prod(res.coeffs, x); return res; } /// Product with scalar template > constexpr auto operator*(const Polynomial& p, DT x) { return x * p; } /// Division with scalar template > constexpr auto operator/(const Polynomial& p, DT x) { Polynomial() / x), order> res(p); detail::for_scalar::div(res.coeffs, x); return res; } /// Division with constant template > constexpr auto operator/(const Polynomial& p, const Constant& x) { Polynomial() / x.coeffs.front()), order> res(p); detail::for_scalar::div(res.coeffs, std::get<0>(x.coeffs)); return res; } namespace detail { template struct coeff_product { template static constexpr void prod(std::array& res, const std::array& a, const std::array& b) { std::get(res) += a[i] * b[j]; coeff_product::prod(res, a, b); } }; template struct coeff_product { template static constexpr void prod(std::array& res, const std::array& a, const std::array& b) { std::get(res) += a[i] * b[0]; coeff_product::prod(res, a, b); } }; template <> struct coeff_product<0, 0> { template static constexpr void prod(std::array& res, const std::array& a, const std::array& b) { std::get<0>(res) += a[0] * b[0]; } }; } // namespace detail /// Product of polynomials template constexpr auto operator*(const Polynomial& p1, const Polynomial& p2) { Polynomial() * std::declval()), o1 + o2> res; detail::coeff_product::value - 1, detail::get_terms::value - 1>::prod(res.coeffs, p1.coeffs, p2.coeffs); return res; } namespace detail { template struct coeff_sum { template static constexpr void sum(std::array& res, const std::array& a, const std::array& b) { std::get(res) += ((i < m) ? a[i] : 0) + ((i < l) ? b[i] : 0); coeff_sum::sum(res, a, b); } }; template <> struct coeff_sum<0> { template static constexpr void sum(std::array& res, const std::array& a, const std::array& b) { std::get<0>(res) += a[0] + b[0]; } }; } // namespace detail /// Sum of polynomials template constexpr auto operator+(const Polynomial& p1, const Polynomial& p2) { Polynomial() + std::declval()), std::max(o1, o2)> res; detail::coeff_sum::sum(res.coeffs, p1.coeffs, p2.coeffs); return res; } /* -------------------------------------------------------------------------- */ /* Simplification rules */ /* -------------------------------------------------------------------------- */ #define POLY_SIMPLIFICATION(opsign, std_op) \ template \ constexpr auto operator opsign( \ const Polynomial& p1, \ const BinaryOperation, Derived, std_op>& p2) { \ return p2.op(p2.op(p1, p2.operands.first), p2.operands.second); \ } \ \ template \ constexpr auto operator opsign( \ const BinaryOperation, Derived, std_op>& p2, \ const Polynomial& p1) { \ return p2.op(p1, p2); \ } \ \ template \ constexpr auto operator opsign( \ const Polynomial& p1, \ const SBinaryOperation, Derived, std_op>& p2) { \ return p2.op(p1, p2.commute()); \ } \ \ template \ constexpr auto operator opsign( \ const SBinaryOperation, Derived, std_op>& p2, \ const Polynomial& p1) { \ return p2.op(p1, p2.commute()); \ } POLY_SIMPLIFICATION(+, std::plus<>) POLY_SIMPLIFICATION(*, std::multiplies<>) #undef POLY_SIMPLIFICATION template constexpr auto operator/(const Product, Derived>& p, const Constant& c) { return p.operands.second * (p.operands.first / c); } template constexpr auto operator/(const Product>& p, const Constant& c) { return p.operands.second * (p.operands.first / c); } template constexpr auto operator*(const Polynomial& p, const Division>& d) { return (p / d.operands.second) * d.operands.first; } template constexpr auto operator*(const Division>& d, const Polynomial& p) { return (p / d.operands.second) * d.operands.first; } /* -------------------------------------------------------------------------- */ /* Output */ /* -------------------------------------------------------------------------- */ template std::ostream& operator<<(std::ostream& os, const Polynomial& p) { os << p.coeffs[0]; if (p.terms >= 2) { os << " + " << p.coeffs[1] << "*z"; for (UInt i = 2; i < p.terms; ++i) os << " + " << p.coeffs[i] << "*z^" << i; } return os; } } // namespace expolit #endif diff --git a/include/expolit/types.hh b/include/expolit/types.hh index 68b998a..729d0f3 100644 --- a/include/expolit/types.hh +++ b/include/expolit/types.hh @@ -1,52 +1,52 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #ifndef TYPES_HH #define TYPES_HH #include #include #include #include namespace expolit { using Int = int; using UInt = unsigned int; /// Expression class for expression templates template struct Expression { constexpr const Derived& downcast() const { return static_cast(*this); } constexpr Derived& downcast() { return static_cast(*this); } }; template std::ostream& operator<<(std::ostream& os, const Expression& e) { os << e.downcast(); return os; } } // namespace expolit #endif diff --git a/tests/tests_gtest.cc b/tests/tests_gtest.cc index b7eb93b..a603731 100644 --- a/tests/tests_gtest.cc +++ b/tests/tests_gtest.cc @@ -1,175 +1,175 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * - * Copyright (©) 2018-2020 EPFL (Ecole Polytechnique Fédérale de + * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Expolit is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Expolit is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Expolit. If not, see . * */ #include #include #include using namespace expolit; using Real = double; static constexpr Polynomial Zi({0, 1}); static constexpr Polynomial, 1> Zc({0, 1}); static constexpr Polynomial Zr({0, 1}); using lin = std::remove_cv_t; template constexpr void compare(const Polynomial& p1, const Polynomial& p2) { for (UInt i = 0; i < p1.terms; ++i) ASSERT_NEAR(std::abs(p1.coeffs[i] - p2.coeffs[i]), 0, 1e-14) << "Polynomials are not equal (i = " << i << ")"; } template constexpr void compare(const Polynomial& p1, const Polynomial& p2) { for (UInt i = 0; i < p1.terms; ++i) ASSERT_EQ(p1.coeffs[i], p2.coeffs[i]) << "Polynomials are not equal (i = " << i << ")"; } TEST(Polynomial, initialization) { constexpr auto p = 1 + 2 * pow<2>(Zi) + pow<3>(Zi); constexpr Int z = 3; constexpr Int sol = 1 + 2 * z * z + z * z * z; constexpr Int res = p(z); static_assert(sol == res, "Bad coefficients"); // This guy cannot be consexpr because std::complex is stupid auto p2 = 1. + Zc * Zc; std::complex z2(0, 1); ASSERT_NEAR(std::abs(p2(z2)), 0, 1e-14) << "Bad coefficents (complex)"; } TEST(Polynomial, sum) { constexpr auto p = 1 + 2 * pow<2>(Zi) + pow<3>(Zi); constexpr auto p2 = Zi + 2 * Zi * Zi; constexpr auto res = 1 + Zi + 4 * Zi * Zi + Zi * Zi * Zi; compare(p + p2, res); } TEST(Polynomial, product) { constexpr auto p = 1 + 2 * pow<2>(Zi) + pow<3>(Zi); constexpr auto p2 = Zi + 2 * pow<2>(Zi); constexpr auto res = Zi + 2 * pow<2>(Zi) + 2 * pow<3>(Zi) + 5 * pow<4>(Zi) + 2 * pow<5>(Zi); compare(p * p2, res); } TEST(Polynomial, derivative) { constexpr auto p = 1 + 2 * pow<2>(Zi) + pow<3>(Zi); constexpr auto res = 4 * Zi + 3 * Zi * Zi; compare(differentiate(p), res); } TEST(Polynomial, integration) { constexpr auto p = 1. + 2. * pow<2>(Zr) + pow<3>(Zr); constexpr auto res = Zr + 2 / 3. * pow<3>(Zr) + 1 / 4. * pow<4>(Zr); compare(integrate(p), res); } TEST(Exponential, evaluation) { constexpr auto e = exp(2. * Zr); constexpr Real z = 3.4; const Real res = e(z); // cannot be constexpr because of exponential ASSERT_NEAR(std::exp(2 * z), res, 1e-14) << "Exponential evaluation fail"; } TEST(Exponential, derivative) { constexpr auto e = exp(2. * Zr); constexpr auto diff = differentiate(e); constexpr auto res = Constant({2}) * e; compare(res.operands.first, diff.operands.first); compare(e.expression, diff.operands.second.expression); } TEST(Exponential, integration) { constexpr auto e = exp(2. * Zr); constexpr auto integ = integrate(e); constexpr auto res = Constant({1 / 2.}) * e; compare(res.operands.first, integ.operands.first); compare(e.expression, integ.operands.second.expression); } TEST(Integration, parts) { constexpr auto e = exp(2. * Zr); constexpr auto expr = e * (2. * Zr); constexpr auto res = Zr * e - Constant({1 / 2.}) * e; constexpr auto integ = integrate(expr); compare(integ.operands.first.operands.first, res.operands.first.operands.first); compare(integ.operands.second.operands.first, res.operands.second.operands.first); } TEST(Integration, definite_integral) { constexpr auto p = Zr; constexpr std::pair bounds(0, 1); constexpr auto res = definite_integral(bounds, p); ASSERT_NEAR(0.5, res, 1e-14) << "Definite integral fail"; constexpr auto pi = 2 * Zi; static_assert(definite_integral(std::make_pair(0, 1), pi) == 1, "Definite integral fail"); } using Q = Litteral; TEST(Litteral, substitution) { constexpr Q q; constexpr auto p = q * Zi; constexpr auto c = Constant({2}); constexpr auto p_sub = substitute(c, p); compare(2 * Zi, p_sub); constexpr auto expo = exp(q * Zr); constexpr auto x_sub = substitute(c, expo); compare(2. * Zr, x_sub.expression); } TEST(Litteral, differentiation) { constexpr Q q; constexpr auto c = Constant({2}); constexpr auto expo = exp(q * Zr); constexpr auto dexpo = differentiate(expo); constexpr auto res = substitute(c, dexpo); compare(c, res.operands.first); compare(2. * Zr, res.operands.second.expression); } TEST(Litteral, integration) { constexpr Q q; constexpr auto c = Constant({2}); constexpr auto res = substitute(c, integrate(2 * Zr * exp(q * Zr))); constexpr auto sol = Zr * exp(2. * Zr) - Constant({1 / 2.}) * exp(2. * Zr); compare(sol.operands.first.operands.first, res.operands.first.operands.first); compare(sol.operands.second.operands.first, res.operands.second.operands.first); }