Numworks Epsilon  1.4.1
Graphing Calculator Operating System
integral.cpp
Go to the documentation of this file.
1 #include <poincare/integral.h>
2 #include <poincare/symbol.h>
3 #include <poincare/context.h>
4 #include <poincare/undefined.h>
5 #include <cmath>
6 extern "C" {
7 #include <assert.h>
8 #include <float.h>
9 #include <stdlib.h>
10 }
11 #include "layout/string_layout.h"
12 #include "layout/integral_layout.h"
14 
15 namespace Poincare {
16 
18  return Type::Integral;
19 }
20 
22  Integral * a = new Integral(m_operands, true);
23  return a;
24 }
25 
26 int Integral::polynomialDegree(char symbolName) const {
27  if (symbolName == 'x') {
28  int da = operand(1)->polynomialDegree(symbolName);
29  int db = operand(2)->polynomialDegree(symbolName);
30  if (da != 0 || db != 0) {
31  return -1;
32  }
33  return 0;
34  }
35  return Expression::polynomialDegree(symbolName);
36 }
37 
38 Expression * Integral::shallowReduce(Context& context, AngleUnit angleUnit) {
39  Expression * e = Expression::shallowReduce(context, angleUnit);
40  if (e != this) {
41  return e;
42  }
43 #if MATRIX_EXACT_REDUCING
44  if (operand(0)->type() == Type::Matrix || operand(1)->type() == Type::Matrix || operand(2)->type() == Type::Matrix) {
45  return replaceWith(new Undefined(), true);
46  }
47 #endif
48  return this;
49 }
50 
51 template<typename T>
52 Complex<T> * Integral::templatedApproximate(Context & context, AngleUnit angleUnit) const {
53  VariableContext<T> xContext = VariableContext<T>('x', &context);
54  Expression * aInput = operand(1)->approximate<T>(context, angleUnit);
55  T a = aInput->type() == Type::Complex ? static_cast<Complex<T> *>(aInput)->toScalar() : NAN;
56  delete aInput;
57  Expression * bInput = operand(2)->approximate<T>(context, angleUnit);
58  T b = bInput->type() == Type::Complex ? static_cast<Complex<T> *>(bInput)->toScalar() : NAN;
59  delete bInput;
60  if (std::isnan(a) || std::isnan(b)) {
61  return new Complex<T>(Complex<T>::Float(NAN));
62  }
63 #ifdef LAGRANGE_METHOD
64  T result = lagrangeGaussQuadrature<T>(a, b, xContext, angleUnit);
65 #else
66  T result = adaptiveQuadrature<T>(a, b, 0.1, k_maxNumberOfIterations, xContext, angleUnit);
67 #endif
68  return new Complex<T>(Complex<T>::Float(result));
69 }
70 
71 ExpressionLayout * Integral::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const {
72  assert(floatDisplayMode != PrintFloat::Mode::Default);
73  assert(complexFormat != ComplexFormat::Default);
74  ExpressionLayout * childrenLayouts[2];
75  childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat);
76  childrenLayouts[1] = new StringLayout("dx", 2);
77  return new IntegralLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), operand(2)->createLayout(floatDisplayMode, complexFormat), new HorizontalLayout(childrenLayouts, 2));
78 }
79 
80 template<typename T>
81 T Integral::functionValueAtAbscissa(T x, VariableContext<T> xContext, AngleUnit angleUnit) const {
82  Complex<T> e = Complex<T>::Float(x);
83  Symbol xSymbol('x');
84  xContext.setExpressionForSymbolName(&e, &xSymbol, xContext);
85  Expression * f = operand(0)->approximate<T>(xContext, angleUnit);
86  T result = f->type() == Type::Complex ? static_cast<Complex<T> *>(f)->toScalar() : NAN;
87  delete f;
88  return result;
89 }
90 
91 #ifdef LAGRANGE_METHOD
92 
93 template<typename T>
94 T Integral::lagrangeGaussQuadrature(T a, T b, VariableContext<T> xContext, AngleUnit angleUnit) const {
95  /* We here use Gauss-Legendre quadrature with n = 5
96  * Gauss-Legendre abscissae and weights can be found in
97  * C/C++ library source code. */
98  const static T x[10]={0.0765265211334973337546404, 0.2277858511416450780804962, 0.3737060887154195606725482, 0.5108670019508270980043641,
99  0.6360536807265150254528367, 0.7463319064601507926143051, 0.8391169718222188233945291, 0.9122344282513259058677524,
100  0.9639719272779137912676661, 0.9931285991850949247861224};
101  const static T w[10]={0.1527533871307258506980843, 0.1491729864726037467878287, 0.1420961093183820513292983, 0.1316886384491766268984945, 0.1181945319615184173123774,
102  0.1019301198172404350367501, 0.0832767415767047487247581, 0.0626720483341090635695065, 0.0406014298003869413310400, 0.0176140071391521183118620};
103  T xm = 0.5*(a+b);
104  T xr = 0.5*(b-a);
105  T result = 0;
106  for (int j = 0; j < 10; j++) {
107  T dx = xr * x[j];
108  result += w[j]*(functionValueAtAbscissa(xm+dx, xContext, angleUnit) + functionValueAtAbscissa(xm-dx, xContext, angleUnit));
109  }
110  result *= xr;
111  return result;
112 }
113 
114 #else
115 
116 template<typename T>
117 Integral::DetailedResult<T> Integral::kronrodGaussQuadrature(T a, T b, VariableContext<T> xContext, AngleUnit angleUnit) const {
118  static T epsilon = sizeof(T) == sizeof(double) ? DBL_EPSILON : FLT_EPSILON;
119  static T max = sizeof(T) == sizeof(double) ? DBL_MAX : FLT_MAX;
120  /* We here use Kronrod-Legendre quadrature with n = 21
121  * The abscissa and weights are taken from QUADPACK library. */
122  const static T wg[5]= {0.066671344308688137593568809893332, 0.149451349150580593145776339657697,
123  0.219086362515982043995534934228163, 0.269266719309996355091226921569469, 0.295524224714752870173892994651338};
124  const static T xgk[11]= {0.995657163025808080735527280689003, 0.973906528517171720077964012084452,
125  0.930157491355708226001207180059508, 0.865063366688984510732096688423493, 0.780817726586416897063717578345042,
126  0.679409568299024406234327365114874, 0.562757134668604683339000099272694, 0.433395394129247190799265943165784,
127  0.294392862701460198131126603103866, 0.148874338981631210884826001129720, 0.000000000000000000000000000000000};
128  const static T wgk[11]= {0.011694638867371874278064396062192, 0.032558162307964727478818972459390,
129  0.054755896574351996031381300244580, 0.075039674810919952767043140916190, 0.093125454583697605535065465083366,
130  0.109387158802297641899210590325805, 0.123491976262065851077958109831074, 0.134709217311473325928054001771707,
131  0.142775938577060080797094273138717, 0.147739104901338491374841515972068, 0.149445554002916905664936468389821};
132  T fv1[10];
133  T fv2[10];
134 
135  T centr = 0.5*(a+b);
136  T hlgth = 0.5*(b-a);
137  T dhlgth = std::fabs(hlgth);
138 
139  T resg = 0;
140  T fc = functionValueAtAbscissa(centr, xContext, angleUnit);
141  T resk = wgk[10]*fc;
142  T resabs = std::fabs(resk);
143  for (int j = 0; j < 5; j++) {
144  int jtw = 2*j+1;
145  T absc = hlgth*xgk[jtw];
146  T fval1 = functionValueAtAbscissa(centr-absc, xContext, angleUnit);
147  T fval2 = functionValueAtAbscissa(centr+absc, xContext, angleUnit);
148  fv1[jtw] = fval1;
149  fv2[jtw] = fval2;
150  T fsum = fval1+fval2;
151  resg += wg[j]*fsum;
152  resk += wgk[jtw]*fsum;
153  resabs += wgk[jtw]*(std::fabs(fval1)+std::fabs(fval2));
154  }
155  for (int j = 0; j < 5; j++) {
156  int jtwm1 = 2*j;
157  T absc = hlgth*xgk[jtwm1];
158  T fval1 = functionValueAtAbscissa(centr-absc, xContext, angleUnit);
159  T fval2 = functionValueAtAbscissa(centr+absc, xContext, angleUnit);
160  fv1[jtwm1] = fval1;
161  fv2[jtwm1] = fval2;
162  T fsum = fval1+fval2;
163  resk += wgk[jtwm1]*fsum;
164  resabs += wgk[jtwm1]*(std::fabs(fval1)+std::fabs(fval2));
165  }
166  T reskh = resk*0.5;
167  T resasc = wgk[10]*std::fabs(fc-reskh);
168  for (int j = 0; j < 10; j++) {
169  resasc += wgk[j]*(std::fabs(fv1[j]-reskh)+std::fabs(fv2[j]-reskh));
170  }
171  T integral = resk*hlgth;
172  resabs = resabs*dhlgth;
173  resasc = resasc*dhlgth;
174  T abserr = std::fabs((resk-resg)*hlgth);
175  if (resasc != 0 && abserr != 0) {
176  abserr = 1 > std::pow((T)(200*abserr/resasc), (T)1.5)? resasc*std::pow((T)(200*abserr/resasc), (T)1.5) : resasc;
177  }
178  if (resabs > max/(50.0*epsilon)) {
179  abserr = abserr > epsilon*50*resabs ? abserr : epsilon*50*resabs;
180  }
181  DetailedResult<T> result;
182  result.integral = integral;
183  result.absoluteError = abserr;
184  return result;
185 }
186 
187 template<typename T>
188 T Integral::adaptiveQuadrature(T a, T b, T eps, int numberOfIterations, VariableContext<T> xContext, AngleUnit angleUnit) const {
189  if (shouldStopProcessing()) {
190  return NAN;
191  }
192  DetailedResult<T> quadKG = kronrodGaussQuadrature(a, b, xContext, angleUnit);
193  T result = quadKG.integral;
194  if (quadKG.absoluteError <= eps) {
195  return result;
196  } else if (--numberOfIterations > 0) {
197  T m = (a+b)/2;
198  return adaptiveQuadrature<T>(a, m, eps/2, numberOfIterations, xContext, angleUnit) + adaptiveQuadrature<T>(m, b, eps/2, numberOfIterations, xContext, angleUnit);
199  } else {
200  return NAN;
201  }
202 }
203 #endif
204 
205 }
static bool shouldStopProcessing()
Definition: expression.cpp:65
#define NAN
Definition: math.h:30
int polynomialDegree(char symbolName) const override
Definition: integral.cpp:26
#define FLT_EPSILON
Definition: float.h:8
#define assert(e)
Definition: assert.h:9
Expression * replaceWith(Expression *newOperand, bool deleteAfterReplace=true)
Definition: expression.cpp:85
Expression * approximate(Context &context, AngleUnit angleUnit=AngleUnit::Default) const
Definition: expression.cpp:338
friend class Integral
Definition: expression.h:53
#define T(x)
Definition: events.cpp:26
friend class Symbol
Definition: expression.h:72
#define fabs(x)
Definition: math.h:178
#define DBL_EPSILON
Definition: float.h:11
#define DBL_MAX
Definition: float.h:9
#define FLT_MAX
Definition: float.h:6
Type type() const override
Definition: integral.cpp:17
#define pow(x, y)
Definition: math.h:190
const Expression * m_operands[T]
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode=PrintFloat::Mode::Default, ComplexFormat complexFormat=ComplexFormat::Default) const
Definition: expression.cpp:244
#define isnan(x)
Definition: math.h:43
static Complex< T > Float(T x)
Definition: complex.cpp:23
Expression * clone() const override
Definition: integral.cpp:21
const Expression * operand(int i) const
Definition: expression.cpp:78
virtual int polynomialDegree(char symbolName) const
Definition: expression.cpp:202
friend class Undefined
Definition: expression.h:17