Reaktoro  v2.11.0
A unified framework for modeling chemically reactive systems
Roots.hpp
1 // Reaktoro is a unified framework for modeling chemically reactive systems.
2 //
3 // Copyright © 2014-2024 Allan Leal
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library. If not, see <http://www.gnu.org/licenses/>.
17 
18 #pragma once
19 
20 // C++ includes
21 #include <array>
22 #include <complex>
23 #include <functional>
24 
25 namespace Reaktoro {
26 
28 template<typename T>
29 using CubicRoots = std::array<std::complex<T>, 3>;
30 
43 template<typename T>
44 auto cardano(const T& b, const T& c, const T& d) -> CubicRoots<T>
45 {
46  using std::abs;
47  using std::acos;
48  using std::cbrt;
49  using std::cos;
50  using std::sqrt;
51  using std::complex;
52 
53  const auto xn = -b/3;
54  const auto yn = d + xn*(c + xn*(b + xn));
55 
56  const auto delta2 = (b*b - 3*c)/9;
57 
58  const auto u = yn*yn;
59  const auto v = 4*delta2*delta2*delta2;
60 
61  const auto discr = u - v;
62 
63  const auto eps = 100*std::numeric_limits<T>::epsilon();
64 
65  if(discr > eps) {
66  const auto sqrtdiscr = sqrt(discr);
67  const auto aux1 = cbrt( 0.5*(-yn + sqrtdiscr) );
68  const auto aux2 = cbrt( 0.5*(-yn - sqrtdiscr) );
69  const auto alpha = xn + aux1 + aux2;
70  const auto z1 = alpha - xn;
71  const auto aux3 = 0.5*sqrt(3*(z1*z1 - 4*delta2));
72  const auto aux4 = xn - 0.5*z1;
73  const auto beta = complex{aux4, -aux3};
74  const auto gamma = complex{aux4, aux3};
75  return {alpha, beta, gamma};
76  }
77  else if(discr < -eps) {
78  const auto pi = 3.14159265358979323846;
79  const auto delta = sqrt(delta2);
80  const auto h = 2*delta2*delta;
81  const auto theta = acos(-yn/h) / 3.0;
82  const auto alpha = xn + 2*delta*cos(theta);
83  const auto beta = xn + 2*delta*cos(2*pi/3 - theta);
84  const auto gamma = xn + 2*delta*cos(2*pi/3 + theta);
85  return {gamma, beta, alpha};
86  }
87  else {
88  const auto delta = cbrt( 0.5*yn );
89  const auto alpha = xn + delta;
90  const auto gamma = xn - 2*delta;
91  if(alpha < gamma) return {alpha, alpha, gamma};
92  else return {gamma, alpha, alpha};
93  }
94 }
95 
102 template<typename T>
103 auto newton(const std::function<std::tuple<T, T>(const T&)>& f, const T& x0, const T& epsilon, std::size_t maxiter) -> std::tuple<T, std::size_t, bool>
104 {
105  using std::abs;
106  assert(epsilon > 0.0);
107  assert(maxiter > 0);
108  T x = x0;
109  for(auto i = 0; i < maxiter; ++i)
110  {
111  const auto [fx, dfx] = f(x);
112  assert(dfx != 0.0);
113  x -= fx/dfx;
114  if(abs(fx) < epsilon)
115  return { x, i, true };
116  }
117  return { x, maxiter, false };
118 }
119 
123 template<typename T>
124 auto realRoots(const CubicRoots<T>& roots) -> std::vector<T>
125 {
126  std::vector<T> real_roots;
127  if(std::get<0>(roots).imag() == 0.0)
128  real_roots.push_back(std::get<0>(roots).real());
129  if(std::get<1>(roots).imag() == 0.0)
130  real_roots.push_back(std::get<1>(roots).real());
131  if(std::get<2>(roots).imag() == 0.0)
132  real_roots.push_back(std::get<2>(roots).real());
133 
134  return real_roots;
135 }
136 
137 } // namespace Reaktoro
The namespace containing all components of the Reaktoro library.
Definition: Algorithms.hpp:29
std::array< std::complex< T >, 3 > CubicRoots
Define a type that describes the roots of a cubic equation.
Definition: Roots.hpp:29
auto abs(const Eigen::MatrixBase< Derived > &mat) -> decltype(mat.cwiseAbs())
Return the component-wise absolute entries of a matrix.
Definition: Matrix.hpp:798
auto cardano(const T &b, const T &c, const T &d) -> CubicRoots< T >
Calculate the roots of a cubic equation using Cardano's method.
Definition: Roots.hpp:44
autodiff::real real
The number type used throughout the library.
Definition: Real.hpp:26
auto realRoots(const CubicRoots< T > &roots) -> std::vector< T >
Return all real roots of a group of roots.
Definition: Roots.hpp:124
constexpr auto epsilon
The value of machine precision epsilon.
Definition: Constants.hpp:68
auto sqrt(const Eigen::MatrixBase< Derived > &mat) -> decltype(mat.cwiseSqrt())
Return the component-wise square root of a matrix.
Definition: Matrix.hpp:804
auto newton(const std::function< std::tuple< T, T >(const T &)> &f, const T &x0, const T &epsilon, std::size_t maxiter) -> std::tuple< T, std::size_t, bool >
Calculate the root of a non-linear function using Newton's method.
Definition: Roots.hpp:103