G_do_hoelder: fix case with real x values which are not of type cl_R.
[ginac.git] / check / check_inifcns.cpp
1 /** @file check_inifcns.cpp
2  *
3  *  This test routine applies assorted tests on initially known higher level
4  *  functions. */
5
6 /*
7  *  GiNaC Copyright (C) 1999-2018 Johannes Gutenberg University Mainz, Germany
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23
24 #include "ginac.h"
25 using namespace GiNaC;
26
27 #include <cstdlib> // for rand()
28 #include <iostream>
29 using namespace std;
30
31 /* Some tests on the sine trigonometric function. */
32 static unsigned inifcns_check_sin()
33 {
34         unsigned result = 0;
35         bool errorflag = false;
36         
37         // sin(n*Pi) == 0?
38         errorflag = false;
39         for (int n=-10; n<=10; ++n) {
40                 if (sin(n*Pi).eval() != numeric(0) ||
41                         !sin(n*Pi).eval().info(info_flags::integer))
42                         errorflag = true;
43         }
44         if (errorflag) {
45                 // we don't count each of those errors
46                 clog << "sin(n*Pi) with integer n does not always return exact 0"
47                      << endl;
48                 ++result;
49         }
50         
51         // sin((n+1/2)*Pi) == {+|-}1?
52         errorflag = false;
53         for (int n=-10; n<=10; ++n) {
54                 if (!sin((n+numeric(1,2))*Pi).eval().info(info_flags::integer) ||
55                     !(sin((n+numeric(1,2))*Pi).eval() == numeric(1) ||
56                       sin((n+numeric(1,2))*Pi).eval() == numeric(-1)))
57                         errorflag = true;
58         }
59         if (errorflag) {
60                 clog << "sin((n+1/2)*Pi) with integer n does not always return exact {+|-}1"
61                      << endl;
62                 ++result;
63         }
64         
65         // compare sin((q*Pi).evalf()) with sin(q*Pi).eval().evalf() at various
66         // points.  E.g. if sin(Pi/10) returns something symbolic this should be
67         // equal to sqrt(5)/4-1/4.  This routine will spot programming mistakes
68         // of this kind:
69         errorflag = false;
70         ex argument;
71         numeric epsilon(double(1e-8));
72         for (int n=-340; n<=340; ++n) {
73                 argument = n*Pi/60;
74                 if (abs(sin(evalf(argument))-evalf(sin(argument)))>epsilon) {
75                         clog << "sin(" << argument << ") returns "
76                              << sin(argument) << endl;
77                         errorflag = true;
78                 }
79         }
80         if (errorflag)
81                 ++result;
82         
83         return result;
84 }
85
86 /* Simple tests on the cosine trigonometric function. */
87 static unsigned inifcns_check_cos()
88 {
89         unsigned result = 0;
90         bool errorflag;
91         
92         // cos((n+1/2)*Pi) == 0?
93         errorflag = false;
94         for (int n=-10; n<=10; ++n) {
95                 if (cos((n+numeric(1,2))*Pi).eval() != numeric(0) ||
96                     !cos((n+numeric(1,2))*Pi).eval().info(info_flags::integer))
97                         errorflag = true;
98         }
99         if (errorflag) {
100                 clog << "cos((n+1/2)*Pi) with integer n does not always return exact 0"
101                      << endl;
102                 ++result;
103         }
104         
105         // cos(n*Pi) == 0?
106         errorflag = false;
107         for (int n=-10; n<=10; ++n) {
108                 if (!cos(n*Pi).eval().info(info_flags::integer) ||
109                     !(cos(n*Pi).eval() == numeric(1) ||
110                       cos(n*Pi).eval() == numeric(-1)))
111                         errorflag = true;
112         }
113         if (errorflag) {
114                 clog << "cos(n*Pi) with integer n does not always return exact {+|-}1"
115                      << endl;
116                 ++result;
117         }
118         
119         // compare cos((q*Pi).evalf()) with cos(q*Pi).eval().evalf() at various
120         // points.  E.g. if cos(Pi/12) returns something symbolic this should be
121         // equal to 1/4*(1+1/3*sqrt(3))*sqrt(6).  This routine will spot
122         // programming mistakes of this kind:
123         errorflag = false;
124         ex argument;
125         numeric epsilon(double(1e-8));
126         for (int n=-340; n<=340; ++n) {
127                 argument = n*Pi/60;
128                 if (abs(cos(evalf(argument))-evalf(cos(argument)))>epsilon) {
129                         clog << "cos(" << argument << ") returns "
130                              << cos(argument) << endl;
131                         errorflag = true;
132                 }
133         }
134         if (errorflag)
135                 ++result;
136         
137         return result;
138 }
139
140 /* Simple tests on the tangent trigonometric function. */
141 static unsigned inifcns_check_tan()
142 {
143         unsigned result = 0;
144         bool errorflag;
145         
146         // compare tan((q*Pi).evalf()) with tan(q*Pi).eval().evalf() at various
147         // points.  E.g. if tan(Pi/12) returns something symbolic this should be
148         // equal to 2-sqrt(3).  This routine will spot programming mistakes of 
149         // this kind:
150         errorflag = false;
151         ex argument;
152         numeric epsilon(double(1e-8));
153         for (int n=-340; n<=340; ++n) {
154                 if (!(n%30) && (n%60))  // skip poles
155                         ++n;
156                 argument = n*Pi/60;
157                 if (abs(tan(evalf(argument))-evalf(tan(argument)))>epsilon) {
158                         clog << "tan(" << argument << ") returns "
159                              << tan(argument) << endl;
160                         errorflag = true;
161                 }
162         }
163         if (errorflag)
164                 ++result;
165         
166         return result;
167 }
168
169 /* Simple tests on the dilogarithm function. */
170 static unsigned inifcns_check_Li2()
171 {
172         // NOTE: this can safely be removed once CLN supports dilogarithms and
173         // checks them itself.
174         unsigned result = 0;
175         bool errorflag;
176         
177         // check the relation Li2(z^2) == 2 * (Li2(z) + Li2(-z)) numerically, which
178         // should hold in the entire complex plane:
179         errorflag = false;
180         ex argument;
181         numeric epsilon(double(1e-16));
182         for (int n=0; n<200; ++n) {
183                 argument = numeric(20.0*rand()/(RAND_MAX+1.0)-10.0)
184                          + numeric(20.0*rand()/(RAND_MAX+1.0)-10.0)*I;
185                 if (abs(Li2(pow(argument,2))-2*Li2(argument)-2*Li2(-argument)) > epsilon) {
186                         clog << "Li2(z) at z==" << argument
187                              << " failed to satisfy Li2(z^2)==2*(Li2(z)+Li2(-z))" << endl;
188                         errorflag = true;
189                 }
190         }
191         
192         if (errorflag)
193                 ++result;
194         
195         return result;
196 }
197
198 unsigned check_inifcns()
199 {
200         unsigned result = 0;
201
202         cout << "checking consistency of symbolic functions" << flush;
203         
204         result += inifcns_check_sin();  cout << '.' << flush;
205         result += inifcns_check_cos();  cout << '.' << flush;
206         result += inifcns_check_tan();  cout << '.' << flush;
207         result += inifcns_check_Li2();  cout << '.' << flush;
208         
209         return result;
210 }
211
212 int main(int argc, char** argv)
213 {
214         return check_inifcns();
215 }