Happy new year!
[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-2008 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 <iostream>
25 #include <cstdlib> // rand()
26 #include "ginac.h"
27 using namespace std;
28 using namespace GiNaC;
29
30 /* Some tests on the sine trigonometric function. */
31 static unsigned inifcns_check_sin()
32 {
33         unsigned result = 0;
34         bool errorflag = false;
35         
36         // sin(n*Pi) == 0?
37         errorflag = false;
38         for (int n=-10; n<=10; ++n) {
39                 if (sin(n*Pi).eval() != numeric(0) ||
40                         !sin(n*Pi).eval().info(info_flags::integer))
41                         errorflag = true;
42         }
43         if (errorflag) {
44                 // we don't count each of those errors
45                 clog << "sin(n*Pi) with integer n does not always return exact 0"
46                      << endl;
47                 ++result;
48         }
49         
50         // sin((n+1/2)*Pi) == {+|-}1?
51         errorflag = false;
52         for (int n=-10; n<=10; ++n) {
53                 if (!sin((n+numeric(1,2))*Pi).eval().info(info_flags::integer) ||
54                     !(sin((n+numeric(1,2))*Pi).eval() == numeric(1) ||
55                       sin((n+numeric(1,2))*Pi).eval() == numeric(-1)))
56                         errorflag = true;
57         }
58         if (errorflag) {
59                 clog << "sin((n+1/2)*Pi) with integer n does not always return exact {+|-}1"
60                      << endl;
61                 ++result;
62         }
63         
64         // compare sin((q*Pi).evalf()) with sin(q*Pi).eval().evalf() at various
65         // points.  E.g. if sin(Pi/10) returns something symbolic this should be
66         // equal to sqrt(5)/4-1/4.  This routine will spot programming mistakes
67         // of this kind:
68         errorflag = false;
69         ex argument;
70         numeric epsilon(double(1e-8));
71         for (int n=-340; n<=340; ++n) {
72                 argument = n*Pi/60;
73                 if (abs(sin(evalf(argument))-evalf(sin(argument)))>epsilon) {
74                         clog << "sin(" << argument << ") returns "
75                              << sin(argument) << endl;
76                         errorflag = true;
77                 }
78         }
79         if (errorflag)
80                 ++result;
81         
82         return result;
83 }
84
85 /* Simple tests on the cosine trigonometric function. */
86 static unsigned inifcns_check_cos()
87 {
88         unsigned result = 0;
89         bool errorflag;
90         
91         // cos((n+1/2)*Pi) == 0?
92         errorflag = false;
93         for (int n=-10; n<=10; ++n) {
94                 if (cos((n+numeric(1,2))*Pi).eval() != numeric(0) ||
95                     !cos((n+numeric(1,2))*Pi).eval().info(info_flags::integer))
96                         errorflag = true;
97         }
98         if (errorflag) {
99                 clog << "cos((n+1/2)*Pi) with integer n does not always return exact 0"
100                      << endl;
101                 ++result;
102         }
103         
104         // cos(n*Pi) == 0?
105         errorflag = false;
106         for (int n=-10; n<=10; ++n) {
107                 if (!cos(n*Pi).eval().info(info_flags::integer) ||
108                     !(cos(n*Pi).eval() == numeric(1) ||
109                       cos(n*Pi).eval() == numeric(-1)))
110                         errorflag = true;
111         }
112         if (errorflag) {
113                 clog << "cos(n*Pi) with integer n does not always return exact {+|-}1"
114                      << endl;
115                 ++result;
116         }
117         
118         // compare cos((q*Pi).evalf()) with cos(q*Pi).eval().evalf() at various
119         // points.  E.g. if cos(Pi/12) returns something symbolic this should be
120         // equal to 1/4*(1+1/3*sqrt(3))*sqrt(6).  This routine will spot
121         // programming mistakes of this kind:
122         errorflag = false;
123         ex argument;
124         numeric epsilon(double(1e-8));
125         for (int n=-340; n<=340; ++n) {
126                 argument = n*Pi/60;
127                 if (abs(cos(evalf(argument))-evalf(cos(argument)))>epsilon) {
128                         clog << "cos(" << argument << ") returns "
129                              << cos(argument) << endl;
130                         errorflag = true;
131                 }
132         }
133         if (errorflag)
134                 ++result;
135         
136         return result;
137 }
138
139 /* Simple tests on the tangent trigonometric function. */
140 static unsigned inifcns_check_tan()
141 {
142         unsigned result = 0;
143         bool errorflag;
144         
145         // compare tan((q*Pi).evalf()) with tan(q*Pi).eval().evalf() at various
146         // points.  E.g. if tan(Pi/12) returns something symbolic this should be
147         // equal to 2-sqrt(3).  This routine will spot programming mistakes of 
148         // this kind:
149         errorflag = false;
150         ex argument;
151         numeric epsilon(double(1e-8));
152         for (int n=-340; n<=340; ++n) {
153                 if (!(n%30) && (n%60))  // skip poles
154                         ++n;
155                 argument = n*Pi/60;
156                 if (abs(tan(evalf(argument))-evalf(tan(argument)))>epsilon) {
157                         clog << "tan(" << argument << ") returns "
158                              << tan(argument) << endl;
159                         errorflag = true;
160                 }
161         }
162         if (errorflag)
163                 ++result;
164         
165         return result;
166 }
167
168 /* Simple tests on the dilogarithm function. */
169 static unsigned inifcns_check_Li2()
170 {
171         // NOTE: this can safely be removed once CLN supports dilogarithms and
172         // checks them itself.
173         unsigned result = 0;
174         bool errorflag;
175         
176         // check the relation Li2(z^2) == 2 * (Li2(z) + Li2(-z)) numerically, which
177         // should hold in the entire complex plane:
178         errorflag = false;
179         ex argument;
180         numeric epsilon(double(1e-16));
181         for (int n=0; n<200; ++n) {
182                 argument = numeric(20.0*rand()/(RAND_MAX+1.0)-10.0)
183                          + numeric(20.0*rand()/(RAND_MAX+1.0)-10.0)*I;
184                 if (abs(Li2(pow(argument,2))-2*Li2(argument)-2*Li2(-argument)) > epsilon) {
185                         clog << "Li2(z) at z==" << argument
186                              << " failed to satisfy Li2(z^2)==2*(Li2(z)+Li2(-z))" << endl;
187                         errorflag = true;
188                 }
189         }
190         
191         if (errorflag)
192                 ++result;
193         
194         return result;
195 }
196
197 unsigned check_inifcns()
198 {
199         unsigned result = 0;
200
201         cout << "checking consistency of symbolic functions" << flush;
202         
203         result += inifcns_check_sin();  cout << '.' << flush;
204         result += inifcns_check_cos();  cout << '.' << flush;
205         result += inifcns_check_tan();  cout << '.' << flush;
206         result += inifcns_check_Li2();  cout << '.' << flush;
207         
208         return result;
209 }
210
211 int main(int argc, char** argv)
212 {
213         return check_inifcns();
214 }