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 FR_FUNCTION_2R(FUNC)	Number nr(vargs[1].number()); if(!nr.FUNC(vargs[0].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;}
37 #define NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(i)			NumberArgument *arg_non_complex##i = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false); arg_non_complex##i->setComplexAllowed(false); setArgumentDefinition(i, arg_non_complex##i);
38 
has_interval_unknowns(MathStructure & m)39 bool has_interval_unknowns(MathStructure &m) {
40 	if(m.isVariable() && !m.variable()->isKnown()) {
41 		Assumptions *ass = ((UnknownVariable*) m.variable())->assumptions();
42 		return !((UnknownVariable*) m.variable())->interval().isUndefined() || (ass && ((ass->sign() != ASSUMPTION_SIGN_UNKNOWN && ass->sign() != ASSUMPTION_SIGN_NONZERO) || ass->min() || ass->max()));
43 	}
44 	for(size_t i = 0; i < m.size(); i++) {
45 		if(has_interval_unknowns(m[i])) return true;
46 	}
47 	return false;
48 }
49 
bernoulli_poly(MathStructure & m,Number n,const MathStructure & mx,const EvaluationOptions & eo)50 bool bernoulli_poly(MathStructure &m, Number n, const MathStructure &mx, const EvaluationOptions &eo) {
51 	m.clear();
52 	Number bin, k, nmk(n), nrB;
53 	while(k <= n) {
54 		if(nmk.isEven() || nmk.isOne()) {
55 			nrB.set(nmk);
56 			if(!bin.binomial(n, k) || !nrB.bernoulli() || !nrB.multiply(bin)) return false;
57 			if(eo.approximation == APPROXIMATION_EXACT && nrB.isApproximate()) return false;
58 			m.add(nrB, true);
59 			m.last().multiply(mx);
60 			m.last().last().raise(k);
61 			m.childUpdated(m.size());
62 		}
63 		nmk--;
64 		k++;
65 	}
66 	if(m.isAddition()) m.delChild(1, true);
67 	return true;
68 }
69 
ZetaFunction()70 ZetaFunction::ZetaFunction() : MathFunction("zeta", 1, 2, SIGN_ZETA) {
71 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false);
72 	setArgumentDefinition(1, arg);
73 	arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false);
74 	setArgumentDefinition(2, arg);
75 	setDefaultValue(2, "1");
76 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)77 int ZetaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
78 	if(vargs.size() == 1 || vargs[1].isOne()) {
79 		if(vargs[0].number().isInteger()) {
80 			if(vargs[0].number().isZero()) {
81 				mstruct.set(-1, 2, 0);
82 				return 1;
83 			} else if(vargs[0].number().isMinusOne()) {
84 				mstruct.set(-1, 12, 0);
85 				return 1;
86 			} else if(vargs[0].number().isNegative() && vargs[0].number().isEven()) {
87 				mstruct.clear();
88 				return 1;
89 			} else if(vargs[0].number().isNegative() && vargs[0].number() >= -497) {
90 				Number nr(vargs[0].number());
91 				nr.negate();
92 				nr++;
93 				nr.bernoulli();
94 				nr.divide(vargs[0].number() - 1);
95 				if(vargs[0].number().isEven()) nr.negate();
96 				mstruct.set(nr);
97 				mstruct.mergePrecision(vargs[0]);
98 				return 1;
99 			} else if(vargs[0].number().isEven() && vargs[0].number() <= 498) {
100 				Number nr(vargs[0].number());
101 				nr.bernoulli();
102 				mstruct.set(nr);
103 				mstruct.multiply(CALCULATOR->getVariableById(VARIABLE_ID_PI));
104 				mstruct.last().multiply(nr_two);
105 				mstruct.last().raise(vargs[0]);
106 				mstruct.multiply(vargs[0]);
107 				mstruct.last().transformById(FUNCTION_ID_FACTORIAL);
108 				mstruct.last().inverse();
109 				if(vargs[0].number().isIntegerDivisible(4)) mstruct.multiply(Number(-1, 2));
110 				else mstruct.multiply(nr_half);
111 				mstruct.childrenUpdated(true);
112 				return 1;
113 			}
114 		}
115 		FR_FUNCTION(zeta)
116 	}
117 	if(vargs[0].number().isZero()) {
118 		mstruct.set(1, 2, 0);
119 		if(!vargs[1].isZero()) mstruct.subtract(vargs[1]);
120 		return 1;
121 	} else if(vargs[0].number().isInteger() && vargs[0].number().isNegative()) {
122 		Number nr(vargs[0].number());
123 		nr.negate();
124 		nr++;
125 		MathStructure m2(vargs[1]);
126 		replace_f_interval(m2, eo);
127 		replace_intervals_f(m2);
128 		if(bernoulli_poly(mstruct, nr, m2, eo)) {
129 			mstruct.divide(nr);
130 			mstruct.negate();
131 			return 1;
132 		}
133 	} else if(vargs[1].number().isInteger() && vargs[1].number() >= 2 && ((eo.approximation == APPROXIMATION_EXACT && vargs[1].number() <= 1000) || (vargs[1].number() <= 50 && vargs[0].number() >= -10 && vargs[0].number() <= 10))) {
134 		MathStructure m1(vargs[0]);
135 		replace_f_interval(m1, eo);
136 		replace_intervals_f(m1);
137 		mstruct = m1;
138 		m1.negate();
139 		mstruct.transform(this);
140 		mstruct.addChild(m_one);
141 		mstruct.add(m_minus_one);
142 		for(long int i = 2; vargs[1].number() > i; i++) {
143 			mstruct.add(Number(i, 1), true);
144 			mstruct.last().raise(m1);
145 			mstruct.last().negate();
146 		}
147 		return true;
148 	}
149 	FR_FUNCTION_2(zeta)
150 }
GammaFunction()151 GammaFunction::GammaFunction() : MathFunction("gamma", 1, 1, SIGN_CAPITAL_GAMMA) {
152 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1);
153 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)154 int GammaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
155 	if(vargs[0].number().isRational() && (eo.approximation == APPROXIMATION_EXACT || (eo.approximation == APPROXIMATION_TRY_EXACT && vargs[0].number().isLessThan(1000)))) {
156 		if(vargs[0].number().isInteger() && vargs[0].number().isPositive()) {
157 			mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_FACTORIAL), &vargs[0], NULL);
158 			mstruct[0] -= 1;
159 			return 1;
160 		} else if(vargs[0].number().denominatorIsTwo()) {
161 			Number nr(vargs[0].number());
162 			nr.floor();
163 			if(nr.isZero()) {
164 				MathStructure mtmp(CALCULATOR->getVariableById(VARIABLE_ID_PI));
165 				mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_SQRT), &mtmp, NULL);
166 				return 1;
167 			} else if(nr.isPositive()) {
168 				Number nr2(nr);
169 				nr2 *= 2;
170 				nr2 -= 1;
171 				nr2.doubleFactorial();
172 				Number nr3(2, 1, 0);
173 				nr3 ^= nr;
174 				nr2 /= nr3;
175 				mstruct = nr2;
176 				MathStructure mtmp1(CALCULATOR->getVariableById(VARIABLE_ID_PI));
177 				MathStructure mtmp2(CALCULATOR->getFunctionById(FUNCTION_ID_SQRT), &mtmp1, NULL);
178 				mstruct *= mtmp2;
179 				return 1;
180 			} else {
181 				nr.negate();
182 				Number nr2(nr);
183 				nr2 *= 2;
184 				nr2 -= 1;
185 				nr2.doubleFactorial();
186 				Number nr3(2, 1, 0);
187 				nr3 ^= nr;
188 				if(nr.isOdd()) nr3.negate();
189 				nr3 /= nr2;
190 				mstruct = nr3;
191 				MathStructure mtmp1(CALCULATOR->getVariableById(VARIABLE_ID_PI));
192 				MathStructure mtmp2(CALCULATOR->getFunctionById(FUNCTION_ID_SQRT), &mtmp1, NULL);
193 				mstruct *= mtmp2;
194 				return 1;
195 			}
196 		}
197 	}
198 	FR_FUNCTION(gamma)
199 }
DigammaFunction()200 DigammaFunction::DigammaFunction() : MathFunction("digamma", 1) {
201 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1);
202 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)203 int DigammaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
204 	if(vargs[0].number().isOne()) {
205 		mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_EULER));
206 		mstruct.negate();
207 		return 1;
208 	}
209 	FR_FUNCTION(digamma)
210 }
BetaFunction()211 BetaFunction::BetaFunction() : MathFunction("beta", 2, 2, SIGN_CAPITAL_BETA) {
212 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false));
213 	setArgumentDefinition(2, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false));
214 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)215 int BetaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
216 	mstruct = vargs[0];
217 	mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_GAMMA), &vargs[0], NULL);
218 	MathStructure mstruct2(CALCULATOR->getFunctionById(FUNCTION_ID_GAMMA), &vargs[1], NULL);
219 	mstruct *= mstruct2;
220 	mstruct2[0] += vargs[0];
221 	mstruct /= mstruct2;
222 	return 1;
223 }
AiryFunction()224 AiryFunction::AiryFunction() : MathFunction("airy", 1) {
225 	NumberArgument *arg = new NumberArgument();
226 	Number fr(-500, 1, 0);
227 	arg->setMin(&fr);
228 	fr.set(500, 1, 0);
229 	arg->setMax(&fr);
230 	setArgumentDefinition(1, arg);
231 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)232 int AiryFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
233 	FR_FUNCTION(airy)
234 }
BesseljFunction()235 BesseljFunction::BesseljFunction() : MathFunction("besselj", 2) {
236 	setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG));
237 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(2);
238 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)239 int BesseljFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
240 	FR_FUNCTION_2R(besselj)
241 }
BesselyFunction()242 BesselyFunction::BesselyFunction() : MathFunction("bessely", 2) {
243 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG);
244 	Number nmax(1000);
245 	iarg->setMax(&nmax);
246 	setArgumentDefinition(1, iarg);
247 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(2);
248 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)249 int BesselyFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
250 	FR_FUNCTION_2R(bessely)
251 }
ErfFunction()252 ErfFunction::ErfFunction() : MathFunction("erf", 1) {
253 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
254 }
representsPositive(const MathStructure & vargs,bool) const255 bool ErfFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNegative(const MathStructure & vargs,bool) const256 bool ErfFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNegative();}
representsNonNegative(const MathStructure & vargs,bool) const257 bool ErfFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const258 bool ErfFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonPositive();}
representsInteger(const MathStructure &,bool) const259 bool ErfFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool) const260 bool ErfFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure &,bool) const261 bool ErfFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const262 bool ErfFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsNonComplex(const MathStructure & vargs,bool) const263 bool ErfFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsComplex(const MathStructure & vargs,bool) const264 bool ErfFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsNonZero(const MathStructure & vargs,bool) const265 bool ErfFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonZero();}
representsEven(const MathStructure &,bool) const266 bool ErfFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const267 bool ErfFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const268 bool ErfFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)269 int ErfFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
270 	Number nr(vargs[0].number());
271 	if(!nr.erf() || (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())) {
272 		if(vargs[0].number().hasImaginaryPart() && !vargs[0].number().hasRealPart()) {
273 			mstruct = vargs[0].number().imaginaryPart();
274 			MathFunction *f = CALCULATOR->getFunctionById(FUNCTION_ID_ERFI);
275 			mstruct.transform(f);
276 			mstruct *= nr_one_i;
277 			return 1;
278 		}
279 		return 0;
280 	}
281 	mstruct.set(nr);
282 	return 1;
283 }
ErfiFunction()284 ErfiFunction::ErfiFunction() : MathFunction("erfi", 1) {
285 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
286 }
representsPositive(const MathStructure & vargs,bool) const287 bool ErfiFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsPositive();}
representsNegative(const MathStructure & vargs,bool) const288 bool ErfiFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNegative();}
representsNonNegative(const MathStructure & vargs,bool) const289 bool ErfiFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const290 bool ErfiFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonPositive();}
representsInteger(const MathStructure &,bool) const291 bool ErfiFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool) const292 bool ErfiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure &,bool) const293 bool ErfiFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const294 bool ErfiFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const295 bool ErfiFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsComplex(const MathStructure & vargs,bool) const296 bool ErfiFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsNonZero(const MathStructure & vargs,bool) const297 bool ErfiFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonZero();}
representsEven(const MathStructure &,bool) const298 bool ErfiFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const299 bool ErfiFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const300 bool ErfiFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)301 int ErfiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
302 	Number nr(vargs[0].number());
303 	if(!nr.erfi() || (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())) {
304 		if(vargs[0].number().hasImaginaryPart() && !vargs[0].number().hasRealPart()) {
305 			mstruct = vargs[0].number().imaginaryPart();
306 			mstruct.transformById(FUNCTION_ID_ERF);
307 			mstruct *= nr_one_i;
308 			return 1;
309 		}
310 		return 0;
311 	}
312 	mstruct.set(nr);
313 	return 1;
314 }
ErfcFunction()315 ErfcFunction::ErfcFunction() : MathFunction("erfc", 1) {
316 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
317 }
representsPositive(const MathStructure & vargs,bool) const318 bool ErfcFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNegative(const MathStructure &,bool) const319 bool ErfcFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const320 bool ErfcFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonPositive(const MathStructure &,bool) const321 bool ErfcFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure &,bool) const322 bool ErfcFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool) const323 bool ErfcFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure &,bool) const324 bool ErfcFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const325 bool ErfcFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsNonComplex(const MathStructure & vargs,bool) const326 bool ErfcFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
representsComplex(const MathStructure & vargs,bool) const327 bool ErfcFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsNonZero(const MathStructure & vargs,bool) const328 bool ErfcFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsEven(const MathStructure &,bool) const329 bool ErfcFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const330 bool ErfcFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const331 bool ErfcFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)332 int ErfcFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
333 	FR_FUNCTION(erfc)
334 }
335 
LiFunction()336 LiFunction::LiFunction() : MathFunction("Li", 2) {
337 	names[0].case_sensitive = true;
338 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false);
339 	arg->setHandleVector(true);
340 	setArgumentDefinition(1, arg);
341 	arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false);
342 	arg->setHandleVector(true);
343 	setArgumentDefinition(2, arg);
344 }
representsReal(const MathStructure & vargs,bool) const345 bool LiFunction::representsReal(const MathStructure &vargs, bool) const {
346 	return vargs.size() == 2 && vargs[0].representsInteger() && vargs[1].representsReal() && (vargs[1].representsNonPositive() || ((vargs[1].isNumber() && vargs[1].number().isLessThanOrEqualTo(1)) || (vargs[1].isVariable() && vargs[1].variable()->isKnown() && ((KnownVariable*) vargs[1].variable())->get().isNumber() && ((KnownVariable*) vargs[1].variable())->get().number().isLessThanOrEqualTo(1)))) && ((vargs[0].representsPositive() || ((vargs[1].isNumber() && COMPARISON_IS_NOT_EQUAL(vargs[1].number().compare(nr_one))) || (vargs[1].isVariable() && vargs[1].variable()->isKnown() && ((KnownVariable*) vargs[1].variable())->get().isNumber() && COMPARISON_IS_NOT_EQUAL(((KnownVariable*) vargs[1].variable())->get().number().compare(nr_one))))));
347 }
representsNonComplex(const MathStructure & vargs,bool) const348 bool LiFunction::representsNonComplex(const MathStructure &vargs, bool) const {
349 	return vargs.size() == 2 && vargs[0].representsInteger() && vargs[1].representsNonComplex() && (vargs[1].representsNonPositive() || ((vargs[1].isNumber() && vargs[1].number().isLessThanOrEqualTo(1)) || (vargs[1].isVariable() && vargs[1].variable()->isKnown() && ((KnownVariable*) vargs[1].variable())->get().isNumber() && ((KnownVariable*) vargs[1].variable())->get().number().isLessThanOrEqualTo(1))));
350 }
representsNumber(const MathStructure & vargs,bool) const351 bool LiFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 2 && vargs[0].representsInteger() && (vargs[0].representsPositive() || (vargs[1].representsNumber() && ((vargs[1].isNumber() && COMPARISON_IS_NOT_EQUAL(vargs[1].number().compare(nr_one))) || (vargs[1].isVariable() && vargs[1].variable()->isKnown() && ((KnownVariable*) vargs[1].variable())->get().isNumber() && COMPARISON_IS_NOT_EQUAL(((KnownVariable*) vargs[1].variable())->get().number().compare(nr_one))))));}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)352 int LiFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
353 	if(vargs[1].isVector()) return 0;
354 	if(vargs[0].isInteger()) {
355 		if(vargs[0].number().isOne()) {
356 			mstruct.set(1, 1, 0);
357 			mstruct -= vargs[1];
358 			mstruct.transformById(FUNCTION_ID_LOG);
359 			mstruct.negate();
360 			return true;
361 		} else if(vargs[0].number().isZero()) {
362 			mstruct.set(1, 1, 0);
363 			mstruct -= vargs[1];
364 			mstruct.inverse();
365 			mstruct += nr_minus_one;
366 			return true;
367 		} else if(vargs[0].number().isNegative()) {
368 			if(vargs[0].number().isMinusOne()) {
369 				mstruct.set(1, 1, 0);
370 				mstruct -= vargs[1];
371 				mstruct ^= Number(-2, 1);
372 				mstruct *= vargs[1];
373 				return true;
374 			} else if(vargs[0].number() == -2) {
375 				mstruct.set(1, 1, 0);
376 				mstruct -= vargs[1];
377 				mstruct ^= Number(-3, 1);
378 				mstruct *= vargs[1];
379 				mstruct.last() += m_one;
380 				mstruct.last() *= vargs[1];
381 				return true;
382 			} else if(vargs[0].number() == -3) {
383 				mstruct.set(1, 1, 0);
384 				mstruct -= vargs[1];
385 				mstruct ^= Number(-4, 1);
386 				mstruct *= vargs[1];
387 				mstruct.last() ^= nr_two;
388 				mstruct.last() += Number(4, 1);
389 				mstruct.last().last() *= vargs[1];
390 				mstruct.last() += m_one;
391 				mstruct.last() *= vargs[1];
392 				return true;
393 			} else if(vargs[0].number() == -4) {
394 				mstruct.set(1, 1, 0);
395 				mstruct -= vargs[1];
396 				mstruct ^= Number(-5, 1);
397 				mstruct *= vargs[1];
398 				mstruct.last() ^= nr_two;
399 				mstruct.last() += Number(10, 1);
400 				mstruct.last().last() *= vargs[1];
401 				mstruct.last() += m_one;
402 				mstruct.last() *= vargs[1];
403 				mstruct.last().last() += m_one;
404 				mstruct.last() *= vargs[1];
405 				return true;
406 			}
407 		}
408 	}
409 	mstruct = vargs[1];
410 	mstruct.eval(eo);
411 	if(mstruct.isVector()) return -2;
412 	if(vargs[0].number() >= 1 && mstruct.isOne()) {
413 		mstruct = vargs[0];
414 		mstruct.transformById(FUNCTION_ID_ZETA);
415 		return true;
416 	}
417 	if(mstruct.isNumber()) {
418 		Number nr(mstruct.number());
419 		if(nr.polylog(vargs[0].number()) && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate() || mstruct.isApproximate()) && (eo.allow_complex || !nr.isComplex() || vargs[0].number().isComplex() || mstruct.number().isComplex()) && (eo.allow_infinite || !nr.includesInfinity() || vargs[0].number().includesInfinity() || mstruct.number().includesInfinity())) {
420 			mstruct.set(nr); return 1;
421 		}
422 	}
423 	return -2;
424 }
425 
HeavisideFunction()426 HeavisideFunction::HeavisideFunction() : MathFunction("heaviside", 1) {
427 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
428 	arg->setHandleVector(true);
429 	arg->setComplexAllowed(false);
430 	setArgumentDefinition(1, arg);
431 }
representsPositive(const MathStructure & vargs,bool) const432 bool HeavisideFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative(true);}
representsNegative(const MathStructure &,bool) const433 bool HeavisideFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const434 bool HeavisideFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal(true);}
representsNonPositive(const MathStructure &,bool) const435 bool HeavisideFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure & vargs,bool) const436 bool HeavisideFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonZero() && vargs[0].representsReal(true);}
representsNumber(const MathStructure & vargs,bool) const437 bool HeavisideFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal(true);}
representsRational(const MathStructure & vargs,bool) const438 bool HeavisideFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal(true);}
representsNonComplex(const MathStructure & vargs,bool) const439 bool HeavisideFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
representsReal(const MathStructure & vargs,bool) const440 bool HeavisideFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal(true);}
representsComplex(const MathStructure &,bool) const441 bool HeavisideFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool) const442 bool HeavisideFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonNegative(true);}
representsEven(const MathStructure &,bool) const443 bool HeavisideFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const444 bool HeavisideFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure & vargs) const445 bool HeavisideFunction::representsUndefined(const MathStructure &vargs) const {return vargs.size() == 1 && vargs[0].representsUndefined();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)446 int HeavisideFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
447 	if(vargs[0].isVector()) return 0;
448 	mstruct = vargs[0];
449 	mstruct.eval(eo);
450 	if(mstruct.isVector()) return -1;
451 	if(!mstruct.representsNonComplex(true)) return false;
452 	if(mstruct.representsPositive(true)) {
453 		mstruct.set(1, 1, 0);
454 		return 1;
455 	}
456 	if(mstruct.representsNegative(true)) {
457 		mstruct.clear();
458 		return 1;
459 	}
460 	if(mstruct.isZero()) {
461 		mstruct = nr_half;
462 		return 1;
463 	}
464 	if(mstruct.isNumber() && mstruct.number().isInterval()) {
465 		if(!mstruct.number().isNonNegative()) {
466 			mstruct.number().setInterval(nr_half, nr_one);
467 		} else if(!mstruct.number().isNonPositive()) {
468 			mstruct.number().setInterval(nr_zero, nr_half);
469 		} else {
470 			mstruct.number().setInterval(nr_zero, nr_one);
471 		}
472 		return 1;
473 	}
474 	if(eo.approximation == APPROXIMATION_EXACT || has_interval_unknowns(mstruct)) {
475 		ComparisonResult cr = mstruct.compare(m_zero);
476 		if(cr == COMPARISON_RESULT_LESS) {
477 			mstruct.set(1, 1, 0);
478 			return 1;
479 		} else if(cr == COMPARISON_RESULT_GREATER) {
480 			mstruct.clear();
481 			return 1;
482 		}
483 	}
484 	return -1;
485 }
DiracFunction()486 DiracFunction::DiracFunction() : MathFunction("dirac", 1) {
487 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
488 	arg->setComplexAllowed(false);
489 	setArgumentDefinition(1, arg);
490 }
representsPositive(const MathStructure &,bool allow_units) const491 bool DiracFunction::representsPositive(const MathStructure&, bool allow_units) const {return false;}
representsNegative(const MathStructure &,bool) const492 bool DiracFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure &,bool) const493 bool DiracFunction::representsNonNegative(const MathStructure&, bool) const {return true;}
representsNonPositive(const MathStructure &,bool) const494 bool DiracFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure &,bool) const495 bool DiracFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure &,bool) const496 bool DiracFunction::representsNumber(const MathStructure&, bool) const {return false;}
representsRational(const MathStructure &,bool) const497 bool DiracFunction::representsRational(const MathStructure&, bool) const {return false;}
representsNonComplex(const MathStructure & vargs,bool) const498 bool DiracFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
representsReal(const MathStructure &,bool) const499 bool DiracFunction::representsReal(const MathStructure&, bool) const {return false;}
representsComplex(const MathStructure &,bool) const500 bool DiracFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure &,bool) const501 bool DiracFunction::representsNonZero(const MathStructure&, bool) const {return false;}
representsEven(const MathStructure &,bool) const502 bool DiracFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const503 bool DiracFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure & vargs) const504 bool DiracFunction::representsUndefined(const MathStructure &vargs) const {return vargs.size() == 1 && vargs[0].representsUndefined();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)505 int DiracFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
506 	mstruct = vargs[0];
507 	mstruct.eval(eo);
508 	if(!mstruct.representsNonComplex(true)) return false;
509 	if(mstruct.representsNonZero(true)) {
510 		mstruct.clear();
511 		return 1;
512 	}
513 	if(mstruct.isZero()) {
514 		mstruct = nr_plus_inf;
515 		return 1;
516 	}
517 	if(mstruct.isNumber() && mstruct.number().isInterval() && !mstruct.number().isNonZero()) {
518 		mstruct.number().setInterval(nr_zero, nr_plus_inf);
519 		return 1;
520 	}
521 	if(eo.approximation == APPROXIMATION_EXACT || has_interval_unknowns(mstruct)) {
522 		ComparisonResult cr = mstruct.compare(m_zero);
523 		if(COMPARISON_IS_NOT_EQUAL(cr)) {
524 			mstruct.clear();
525 			return 1;
526 		}
527 	}
528 	return -1;
529 }
530 
531