1 /*
2     Qalculate (library)
3 
4     Copyright (C) 2003-2007, 2008, 2016, 2018  Hanna Knutsson (hanna.knutsson@protonmail.com)
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 */
11 
12 #include "support.h"
13 
14 #include "BuiltinFunctions.h"
15 #include "util.h"
16 #include "MathStructure.h"
17 #include "Number.h"
18 #include "Calculator.h"
19 #include "Variable.h"
20 #include "Unit.h"
21 
22 #include <sstream>
23 #include <time.h>
24 #include <limits>
25 #include <algorithm>
26 
27 #include "MathStructure-support.h"
28 
29 using std::string;
30 using std::cout;
31 using std::vector;
32 using std::endl;
33 
34 #define FR_FUNCTION(FUNC)	Number nr(vargs[0].number()); if(!nr.FUNC() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {return 0;} else {mstruct.set(nr); return 1;}
35 #define FR_FUNCTION_2(FUNC)	Number nr(vargs[0].number()); if(!nr.FUNC(vargs[1].number()) || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate() && !vargs[1].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex() && !vargs[1].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity() && !vargs[1].number().includesInfinity())) {return 0;} else {mstruct.set(nr); return 1;}
36 #define NON_COMPLEX_NUMBER_ARGUMENT(i)				NumberArgument *arg_non_complex##i = new NumberArgument(); arg_non_complex##i->setComplexAllowed(false); setArgumentDefinition(i, arg_non_complex##i);
37 
liFunction()38 liFunction::liFunction() : MathFunction("li", 1) {
39 	names[0].case_sensitive = true;
40 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
41 }
representsReal(const MathStructure & vargs,bool) const42 bool liFunction::representsReal(const MathStructure &vargs, bool) const {
43 	return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative() && ((vargs[0].isNumber() && !COMPARISON_IS_NOT_EQUAL(vargs[0].number().compare(nr_one))) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && COMPARISON_IS_NOT_EQUAL(((KnownVariable*) vargs[0].variable())->get().number().compare(nr_one))));
44 }
representsNonComplex(const MathStructure & vargs,bool) const45 bool liFunction::representsNonComplex(const MathStructure &vargs, bool) const {
46 	return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();
47 }
representsNumber(const MathStructure & vargs,bool) const48 bool liFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber() && ((vargs[0].isNumber() && COMPARISON_IS_NOT_EQUAL(vargs[0].number().compare(nr_one))) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && COMPARISON_IS_NOT_EQUAL(((KnownVariable*) vargs[0].variable())->get().number().compare(nr_one))));}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)49 int liFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
50 	FR_FUNCTION(logint)
51 }
EiFunction()52 EiFunction::EiFunction() : MathFunction("Ei", 1) {
53 	names[0].case_sensitive = true;
54 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
55 }
representsReal(const MathStructure & vargs,bool) const56 bool EiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonZero();}
representsNonComplex(const MathStructure & vargs,bool) const57 bool EiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsNumber(const MathStructure & vargs,bool) const58 bool EiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber() && vargs[0].representsNonZero();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)59 int EiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
60 	FR_FUNCTION(expint)
61 }
FresnelSFunction()62 FresnelSFunction::FresnelSFunction() : MathFunction("fresnels", 1) {
63 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
64 	Number fr(-6, 1);
65 	arg->setMin(&fr);
66 	fr = 6;
67 	arg->setMax(&fr);
68 	setArgumentDefinition(1, arg);
69 }
representsPositive(const MathStructure & vargs,bool) const70 bool FresnelSFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNegative(const MathStructure & vargs,bool) const71 bool FresnelSFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNegative();}
representsNonNegative(const MathStructure & vargs,bool) const72 bool FresnelSFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const73 bool FresnelSFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonPositive();}
representsInteger(const MathStructure &,bool) const74 bool FresnelSFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool) const75 bool FresnelSFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure &,bool) const76 bool FresnelSFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const77 bool FresnelSFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsNonComplex(const MathStructure & vargs,bool) const78 bool FresnelSFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsComplex(const MathStructure & vargs,bool) const79 bool FresnelSFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsNonZero(const MathStructure & vargs,bool) const80 bool FresnelSFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonZero();}
representsEven(const MathStructure &,bool) const81 bool FresnelSFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const82 bool FresnelSFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const83 bool FresnelSFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)84 int FresnelSFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
85 	mstruct = vargs[0];
86 	mstruct.eval(eo);
87 	if(contains_angle_unit(mstruct, eo.parse_options)) {mstruct /= CALCULATOR->getRadUnit(); mstruct.eval(eo);}
88 	if(!mstruct.isNumber()) return -1;
89 	Number nr(mstruct.number()); if(!nr.fresnels() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {
90 		return -1;
91 	}
92 	mstruct.set(nr);
93 	return 1;
94 }
FresnelCFunction()95 FresnelCFunction::FresnelCFunction() : MathFunction("fresnelc", 1) {
96 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
97 	Number fr(-6, 1);
98 	arg->setMin(&fr);
99 	fr = 6;
100 	arg->setMax(&fr);
101 	setArgumentDefinition(1, arg);
102 }
representsPositive(const MathStructure & vargs,bool) const103 bool FresnelCFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNegative(const MathStructure & vargs,bool) const104 bool FresnelCFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNegative();}
representsNonNegative(const MathStructure & vargs,bool) const105 bool FresnelCFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const106 bool FresnelCFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonPositive();}
representsInteger(const MathStructure &,bool) const107 bool FresnelCFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool) const108 bool FresnelCFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure &,bool) const109 bool FresnelCFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const110 bool FresnelCFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsNonComplex(const MathStructure & vargs,bool) const111 bool FresnelCFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsComplex(const MathStructure & vargs,bool) const112 bool FresnelCFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsNonZero(const MathStructure & vargs,bool) const113 bool FresnelCFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonZero();}
representsEven(const MathStructure &,bool) const114 bool FresnelCFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const115 bool FresnelCFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const116 bool FresnelCFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)117 int FresnelCFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
118 	mstruct = vargs[0];
119 	mstruct.eval(eo);
120 	if(contains_angle_unit(mstruct, eo.parse_options)) {mstruct /= CALCULATOR->getRadUnit(); mstruct.eval(eo);}
121 	if(!mstruct.isNumber()) return -1;
122 	Number nr(mstruct.number()); if(!nr.fresnelc() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {
123 		return -1;
124 	}
125 	mstruct.set(nr);
126 	return 1;
127 }
SiFunction()128 SiFunction::SiFunction() : MathFunction("Si", 1) {
129 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
130 }
representsNumber(const MathStructure & vargs,bool) const131 bool SiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsReal(const MathStructure & vargs,bool) const132 bool SiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const133 bool SiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)134 int SiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
135 	if(vargs[0].isVector()) return 0;
136 	mstruct = vargs[0];
137 	mstruct.eval(eo);
138 	if(mstruct.isVector()) return -1;
139 	if(contains_angle_unit(mstruct, eo.parse_options)) {mstruct /= CALCULATOR->getRadUnit(); mstruct.eval(eo);}
140 	if(mstruct.isNumber()) {
141 		Number nr(mstruct.number());
142 		if(nr.isPlusInfinity()) {
143 			mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI), true);
144 			mstruct *= nr_half;
145 			return 1;
146 		}
147 		if(nr.isMinusInfinity()) {
148 			mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI), true);
149 			mstruct *= nr_minus_half;
150 			return 1;
151 		}
152 		if(nr.hasImaginaryPart() && !nr.hasRealPart()) {
153 			mstruct.set(nr.imaginaryPart());
154 			mstruct.transformById(FUNCTION_ID_SINHINT);
155 			mstruct *= nr_one_i;
156 			return 1;
157 		}
158 		if(nr.sinint() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || mstruct.isApproximate()) && (eo.allow_complex || !nr.isComplex() || mstruct.number().isComplex()) && (eo.allow_infinite || !nr.includesInfinity() || mstruct.number().includesInfinity())) {
159 			mstruct.set(nr);
160 			return 1;
161 		}
162 	}
163 	if(has_predominately_negative_sign(mstruct)) {
164 		negate_struct(mstruct);
165 		mstruct.transform(this);
166 		mstruct.negate();
167 		return 1;
168 	}
169 	return -1;
170 }
CiFunction()171 CiFunction::CiFunction() : MathFunction("Ci", 1) {
172 	names[0].case_sensitive = true;
173 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
174 }
representsReal(const MathStructure & vargs,bool) const175 bool CiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNumber(const MathStructure & vargs,bool) const176 bool CiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsNonComplex(const MathStructure & vargs,bool) const177 bool CiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)178 int CiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
179 	if(vargs[0].isVector()) return 0;
180 	mstruct = vargs[0];
181 	mstruct.eval(eo);
182 	if(mstruct.isVector()) return -1;
183 	if(contains_angle_unit(mstruct, eo.parse_options)) {mstruct /= CALCULATOR->getRadUnit(); mstruct.eval(eo);}
184 	if(mstruct.isNumber()) {
185 		if(mstruct.number().isNegative()) {
186 			if(!eo.allow_complex) return -1;
187 			mstruct.negate();
188 			mstruct.transform(this);
189 			mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
190 			mstruct.last() *= nr_one_i;
191 			return 1;
192 		}
193 		Number nr(mstruct.number());
194 		if(nr.isComplex() && nr.hasImaginaryPart() && !nr.hasRealPart()) {
195 			mstruct.set(nr.imaginaryPart());
196 			if(nr.imaginaryPartIsNegative()) mstruct.negate();
197 			mstruct.transformById(FUNCTION_ID_COSHINT);
198 			mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
199 			mstruct.last() *= nr_half;
200 			if(nr.imaginaryPartIsPositive()) mstruct.last() *= nr_one_i;
201 			else mstruct.last() *= nr_minus_i;
202 			return 1;
203 		}
204 		if(nr.cosint() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || mstruct.isApproximate()) && (eo.allow_complex || !nr.isComplex() || mstruct.number().isComplex()) && (eo.allow_infinite || !nr.includesInfinity() || mstruct.number().includesInfinity())) {
205 			mstruct.set(nr);
206 			return 1;
207 		}
208 	}
209 	return -1;
210 }
ShiFunction()211 ShiFunction::ShiFunction() : MathFunction("Shi", 1) {
212 	names[0].case_sensitive = true;
213 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
214 }
representsReal(const MathStructure & vargs,bool) const215 bool ShiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNumber(const MathStructure & vargs,bool) const216 bool ShiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsNonComplex(const MathStructure & vargs,bool) const217 bool ShiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)218 int ShiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
219 	if(vargs[0].isVector()) return 0;
220 	mstruct = vargs[0];
221 	mstruct.eval(eo);
222 	if(mstruct.isVector()) return -1;
223 	if(mstruct.isNumber()) {
224 		Number nr(mstruct.number());
225 		if(nr.hasImaginaryPart() && !nr.hasRealPart()) {
226 			mstruct.set(nr.imaginaryPart());
227 			mstruct.transformById(FUNCTION_ID_SININT);
228 			mstruct *= nr_one_i;
229 			return 1;
230 		}
231 		if(nr.sinhint() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || mstruct.isApproximate()) && (eo.allow_complex || !nr.isComplex() || mstruct.number().isComplex()) && (eo.allow_infinite || !nr.includesInfinity() || mstruct.number().includesInfinity())) {
232 			mstruct.set(nr);
233 			return 1;
234 		}
235 	}
236 	if(has_predominately_negative_sign(mstruct)) {
237 		negate_struct(mstruct);
238 		mstruct.transform(this);
239 		mstruct.negate();
240 		return 1;
241 	}
242 	return -1;
243 }
ChiFunction()244 ChiFunction::ChiFunction() : MathFunction("Chi", 1) {
245 	names[0].case_sensitive = true;
246 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
247 }
representsReal(const MathStructure & vargs,bool) const248 bool ChiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNonComplex(const MathStructure & vargs,bool) const249 bool ChiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative();}
representsNumber(const MathStructure & vargs,bool) const250 bool ChiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)251 int ChiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
252 	if(vargs[0].isVector()) return 0;
253 	mstruct = vargs[0];
254 	mstruct.eval(eo);
255 	if(mstruct.isVector()) return -1;
256 	if(mstruct.isNumber()) {
257 		if(eo.allow_complex && mstruct.number().isNegative()) {
258 			if(!eo.allow_complex) return -1;
259 			mstruct.negate();
260 			mstruct.transform(this);
261 			mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
262 			mstruct.last() *= nr_one_i;
263 			return 1;
264 		}
265 		Number nr(mstruct.number());
266 		if(nr.isComplex() && nr.hasImaginaryPart() && !nr.hasRealPart()) {
267 			mstruct.set(nr.imaginaryPart());
268 			if(nr.imaginaryPartIsNegative()) mstruct.negate();
269 			mstruct.transformById(FUNCTION_ID_COSINT);
270 			mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
271 			mstruct.last() *= nr_half;
272 			if(nr.imaginaryPartIsPositive()) mstruct.last() *= nr_one_i;
273 			else mstruct.last() *= nr_minus_i;
274 			return 1;
275 		}
276 		if(nr.coshint() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || mstruct.isApproximate()) && (eo.allow_complex || !nr.isComplex() || mstruct.number().isComplex()) && (eo.allow_infinite || !nr.includesInfinity() || mstruct.number().includesInfinity())) {
277 			mstruct.set(nr);
278 			return 1;
279 		}
280 	}
281 	return -1;
282 }
283 
IGammaFunction()284 IGammaFunction::IGammaFunction() : MathFunction("igamma", 2) {
285 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
286 	setArgumentDefinition(2, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
287 }
representsReal(const MathStructure & vargs,bool) const288 bool IGammaFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].representsPositive() || (vargs[0].representsInteger() && vargs[0].representsPositive()));}
representsNonComplex(const MathStructure & vargs,bool) const289 bool IGammaFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].representsNonNegative() || (vargs[0].representsInteger() && vargs[0].representsNonNegative()));}
representsNumber(const MathStructure & vargs,bool) const290 bool IGammaFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].representsNonZero() || vargs[0].representsPositive());}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)291 int IGammaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
292 	FR_FUNCTION_2(igamma)
293 }
294 
LimitFunction()295 LimitFunction::LimitFunction() : MathFunction("limit", 2, 4) {
296 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
297 	arg->setComplexAllowed(false);
298 	arg->setHandleVector(true);
299 	setArgumentDefinition(2, arg);
300 	setArgumentDefinition(3, new SymbolicArgument());
301 	setDefaultValue(3, "x");
302 	IntegerArgument *iarg = new IntegerArgument();
303 	iarg->setMin(&nr_minus_one);
304 	iarg->setMax(&nr_one);
305 	setArgumentDefinition(4, iarg);
306 	setDefaultValue(4, "0");
307 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)308 int LimitFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
309 	if(vargs[1].isVector()) return 0;
310 	mstruct = vargs[0];
311 	EvaluationOptions eo2 = eo;
312 	eo2.approximation = APPROXIMATION_EXACT;
313 	if(mstruct.calculateLimit(vargs[2], vargs[1], eo2, vargs[3].number().intValue())) return 1;
314 	CALCULATOR->error(true, _("Unable to find limit."), NULL);
315 	return -1;
316 }
replace_diff_x(MathStructure & m,const MathStructure & mfrom,const MathStructure & mto)317 bool replace_diff_x(MathStructure &m, const MathStructure &mfrom, const MathStructure &mto) {
318 	if(m.equals(mfrom, true, true)) {
319 		m = mto;
320 		return true;
321 	}
322 	if(m.type() == STRUCT_FUNCTION && m.function()->id() == FUNCTION_ID_DIFFERENTIATE) {
323 		if(m.size() >= 4 && m[1] == mfrom && m[3].isUndefined()) {
324 			m[3] = mto;
325 			return true;
326 		}
327 		return false;
328 	}
329 	bool b = false;
330 	for(size_t i = 0; i < m.size(); i++) {
331 		if(replace_diff_x(m[i], mfrom, mto)) {
332 			b = true;
333 			m.childUpdated(i + 1);
334 		}
335 	}
336 	return b;
337 }
338 
DeriveFunction()339 DeriveFunction::DeriveFunction() : MathFunction("diff", 1, 4) {
340 	setArgumentDefinition(2, new SymbolicArgument());
341 	setDefaultValue(2, "undefined");
342 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SINT);
343 	arg->setHandleVector(false);
344 	setArgumentDefinition(3, arg);
345 	setDefaultValue(3, "1");
346 	setDefaultValue(4, "undefined");
347 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)348 int DeriveFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
349 	int i = vargs[2].number().intValue();
350 	mstruct = vargs[0];
351 	bool b = false;
352 	while(i) {
353 		if(CALCULATOR->aborted()) return 0;
354 		if(!mstruct.differentiate(vargs[1], eo) && !b) {
355 			return 0;
356 		}
357 		b = true;
358 		i--;
359 		if(i > 0) {
360 			EvaluationOptions eo2 = eo;
361 			eo2.approximation = APPROXIMATION_EXACT;
362 			eo2.calculate_functions = false;
363 			mstruct.eval(eo2);
364 		}
365 	}
366 	if(!vargs[3].isUndefined()) replace_diff_x(mstruct, vargs[1], vargs[3]);
367 	return 1;
368 }
369 
RombergFunction()370 RombergFunction::RombergFunction() : MathFunction("romberg", 3, 6) {
371 	Argument *arg = new Argument("", false, false);
372 	arg->setHandleVector(true);
373 	setArgumentDefinition(1, arg);
374 	NON_COMPLEX_NUMBER_ARGUMENT(2)
375 	NON_COMPLEX_NUMBER_ARGUMENT(3)
376 	setCondition("\\z > \\y");
377 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG);
378 	Number nr(2, 1);
379 	iarg->setMin(&nr);
380 	setArgumentDefinition(4, iarg);
381 	setDefaultValue(4, "6");
382 	setArgumentDefinition(5, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG));
383 	setDefaultValue(5, "20");
384 	setArgumentDefinition(6, new SymbolicArgument());
385 	setDefaultValue(6, "undefined");
386 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)387 int RombergFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
388 	MathStructure minteg(vargs[0]);
389 	EvaluationOptions eo2 = eo;
390 	eo2.approximation = APPROXIMATION_APPROXIMATE;
391 	Number nr_interval;
392 	nr_interval.setInterval(vargs[1].number(), vargs[2].number());
393 	UnknownVariable *var = new UnknownVariable("", format_and_print(vargs[5]));
394 	var->setInterval(nr_interval);
395 	MathStructure x_var(var);
396 	minteg.replace(vargs[5], x_var);
397 	var->destroy();
398 	minteg.eval(eo2);
399 	Number nr;
400 	eo2.interval_calculation = INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC;
401 	eo2.warn_about_denominators_assumed_nonzero = false;
402 	CALCULATOR->beginTemporaryStopMessages();
403 	if(romberg(minteg, nr, x_var, eo2, vargs[1].number(), vargs[2].number(), vargs[4].number().lintValue(), vargs[3].number().lintValue(), false)) {
404 		CALCULATOR->endTemporaryStopMessages();
405 		mstruct = nr;
406 		return 1;
407 	}
408 	CALCULATOR->endTemporaryStopMessages();
409 	CALCULATOR->error(false, _("Unable to integrate the expression."), NULL);
410 	return 0;
411 }
MonteCarloFunction()412 MonteCarloFunction::MonteCarloFunction() : MathFunction("montecarlo", 4, 5) {
413 	Argument *arg = new Argument("", false, false);
414 	arg->setHandleVector(true);
415 	setArgumentDefinition(1, arg);
416 	NON_COMPLEX_NUMBER_ARGUMENT(2)
417 	NON_COMPLEX_NUMBER_ARGUMENT(3)
418 	setCondition("\\z > \\y");
419 	setArgumentDefinition(4, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE));
420 	setArgumentDefinition(5, new SymbolicArgument());
421 	setDefaultValue(5, "undefined");
422 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)423 int MonteCarloFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
424 	MathStructure minteg(vargs[0]);
425 	EvaluationOptions eo2 = eo;
426 	eo2.approximation = APPROXIMATION_APPROXIMATE;
427 	Number nr_interval;
428 	nr_interval.setInterval(vargs[1].number(), vargs[2].number());
429 	UnknownVariable *var = new UnknownVariable("", format_and_print(vargs[4]));
430 	var->setInterval(nr_interval);
431 	MathStructure x_var(var);
432 	minteg.replace(vargs[4], x_var);
433 	var->destroy();
434 	minteg.eval(eo2);
435 	Number nr;
436 	eo2.interval_calculation = INTERVAL_CALCULATION_NONE;
437 	if(montecarlo(minteg, nr, x_var, eo2, vargs[1].number(), vargs[2].number(), vargs[3].number())) {
438 		mstruct = nr;
439 		return 1;
440 	}
441 	CALCULATOR->error(false, _("Unable to integrate the expression."), NULL);
442 	return 0;
443 }
444 
IntegrateFunction()445 IntegrateFunction::IntegrateFunction() : MathFunction("integrate", 1, 5) {
446 	Argument *arg = new Argument("", false, false);
447 	arg->setHandleVector(true);
448 	setArgumentDefinition(1, arg);
449 	setDefaultValue(2, "undefined");
450 	arg = new Argument("", false, false);
451 	arg->setHandleVector(true);
452 	setArgumentDefinition(2, arg);
453 	setDefaultValue(3, "undefined");
454 	arg = new Argument("", false, false);
455 	arg->setHandleVector(true);
456 	setArgumentDefinition(3, arg);
457 	setArgumentDefinition(4, new SymbolicArgument());
458 	setDefaultValue(4, "undefined");
459 	setArgumentDefinition(5, new BooleanArgument());
460 	setDefaultValue(5, "0");
461 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)462 int IntegrateFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
463 	mstruct = vargs[0];
464 	if(vargs.size() >= 2 && (vargs.size() == 2 || vargs[2].isUndefined()) && (vargs[1].isSymbolic() || (vargs[1].isVariable() && !vargs[1].variable()->isKnown()))) {
465 		if(mstruct.integrate(vargs.size() < 3 ? m_undefined : vargs[2], vargs.size() < 4 ? m_undefined : vargs[3], vargs[1], eo, vargs.size() >= 4 && vargs[4].number().getBoolean(), true)) return 1;
466 	} else {
467 		if(mstruct.integrate(vargs.size() < 2 ? m_undefined : vargs[1], vargs.size() < 3 ? m_undefined : vargs[2], vargs.size() < 3 ? CALCULATOR->getVariableById(VARIABLE_ID_X) : vargs[3], eo, vargs.size() >= 4 && vargs[4].number().getBoolean(), true)) return 1;
468 	}
469 	return -1;
470 }
471 
472