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 
test_eval(MathStructure & mtest,const EvaluationOptions & eo)34 bool test_eval(MathStructure &mtest, const EvaluationOptions &eo) {
35 	EvaluationOptions eo2 = eo;
36 	eo2.assume_denominators_nonzero = false;
37 	eo2.approximation = APPROXIMATION_APPROXIMATE;
38 	CALCULATOR->beginTemporaryEnableIntervalArithmetic();
39 	if(!CALCULATOR->usesIntervalArithmetic()) {CALCULATOR->endTemporaryEnableIntervalArithmetic(); return false;}
40 	CALCULATOR->beginTemporaryStopMessages();
41 	mtest.calculateFunctions(eo2);
42 	mtest.calculatesub(eo2, eo2, true);
43 	CALCULATOR->endTemporaryEnableIntervalArithmetic();
44 	if(CALCULATOR->endTemporaryStopMessages()) return false;
45 	return true;
46 }
47 
calculate_arg(MathStructure & mstruct,const EvaluationOptions & eo)48 bool calculate_arg(MathStructure &mstruct, const EvaluationOptions &eo) {
49 
50 	MathStructure msave;
51 
52 	if(!mstruct.isNumber()) {
53 		if(mstruct.isPower() && mstruct[0] == CALCULATOR->getVariableById(VARIABLE_ID_E) && mstruct[1].isNumber() && mstruct[1].number().hasImaginaryPart() && !mstruct[1].number().hasRealPart()) {
54 			CALCULATOR->beginTemporaryEnableIntervalArithmetic();
55 			if(CALCULATOR->usesIntervalArithmetic()) {
56 				CALCULATOR->beginTemporaryStopMessages();
57 				Number nr(*mstruct[1].number().internalImaginary());
58 				Number nrpi; nrpi.pi();
59 				nr.add(nrpi);
60 				nr.divide(nrpi);
61 				nr.divide(2);
62 				Number nr_u(nr.upperEndPoint());
63 				nr = nr.lowerEndPoint();
64 				nr_u.floor();
65 				nr.floor();
66 				if(!CALCULATOR->endTemporaryStopMessages() && nr == nr_u) {
67 					CALCULATOR->endTemporaryEnableIntervalArithmetic();
68 					nr.setApproximate(false);
69 					nr *= 2;
70 					nr.negate();
71 					mstruct = mstruct[1].number().imaginaryPart();
72 					if(!nr.isZero()) {
73 						mstruct += nr;
74 						mstruct.last() *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
75 					}
76 					return true;
77 				}
78 			}
79 			CALCULATOR->endTemporaryEnableIntervalArithmetic();
80 		}
81 		if(eo.approximation == APPROXIMATION_EXACT) {
82 			msave = mstruct;
83 			if(!test_eval(mstruct, eo)) {
84 				mstruct = msave;
85 				return false;
86 			}
87 		}
88 	}
89 	if(mstruct.isNumber()) {
90 		if(!mstruct.number().hasImaginaryPart()) {
91 			return false;
92 		} else if(!mstruct.number().hasRealPart() && mstruct.number().imaginaryPartIsNonZero()) {
93 			bool b_neg = mstruct.number().imaginaryPartIsNegative();
94 			mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half);
95 			if(b_neg) mstruct.negate();
96 		} else if(!msave.isZero()) {
97 			mstruct = msave;
98 			return false;
99 		} else if(!mstruct.number().realPartIsNonZero()) {
100 			return false;
101 		} else {
102 			MathStructure new_nr(mstruct.number().imaginaryPart());
103 			if(!new_nr.number().divide(mstruct.number().realPart())) return false;
104 			if(mstruct.number().realPartIsNegative()) {
105 				if(mstruct.number().imaginaryPartIsNegative()) {
106 					mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
107 					switch(eo.parse_options.angle_unit) {
108 						case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
109 						case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
110 						case ANGLE_UNIT_RADIANS: {break;}
111 						default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
112 					}
113 					mstruct.subtract(CALCULATOR->getVariableById(VARIABLE_ID_PI));
114 				} else if(mstruct.number().imaginaryPartIsNonNegative()) {
115 					mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
116 					switch(eo.parse_options.angle_unit) {
117 						case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
118 						case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
119 						case ANGLE_UNIT_RADIANS: {break;}
120 						default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
121 					}
122 					mstruct.add(CALCULATOR->getVariableById(VARIABLE_ID_PI));
123 				} else {
124 					return false;
125 				}
126 			} else {
127 				mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
128 				switch(eo.parse_options.angle_unit) {
129 					case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
130 					case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
131 					case ANGLE_UNIT_RADIANS: {break;}
132 					default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
133 				}
134 			}
135 		}
136 		return true;
137 	}
138 	if(!msave.isZero()) {
139 		mstruct = msave;
140 	}
141 	return false;
142 
143 }
144 
SqrtFunction()145 SqrtFunction::SqrtFunction() : MathFunction("sqrt", 1) {
146 	Argument *arg = new Argument("", false, false);
147 	arg->setHandleVector(true);
148 	setArgumentDefinition(1, arg);
149 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)150 int SqrtFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
151 	if(vargs[0].isVector()) return 0;
152 	mstruct = vargs[0];
153 	if(!vargs[0].representsScalar()) {
154 		mstruct.eval(eo);
155 		if(mstruct.isVector()) return -1;
156 	}
157 	mstruct.raise(nr_half);
158 	return 1;
159 }
representsPositive(const MathStructure & vargs,bool allow_units) const160 bool SqrtFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsPositive(allow_units);}
representsNegative(const MathStructure &,bool) const161 bool SqrtFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool allow_units) const162 bool SqrtFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonNegative(allow_units);}
representsNonPositive(const MathStructure &,bool) const163 bool SqrtFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure &,bool) const164 bool SqrtFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const165 bool SqrtFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure &,bool) const166 bool SqrtFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool allow_units) const167 bool SqrtFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonNegative(allow_units);}
representsNonComplex(const MathStructure & vargs,bool allow_units) const168 bool SqrtFunction::representsNonComplex(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units);}
representsComplex(const MathStructure & vargs,bool allow_units) const169 bool SqrtFunction::representsComplex(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNegative(allow_units);}
representsNonZero(const MathStructure & vargs,bool allow_units) const170 bool SqrtFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonZero(allow_units);}
representsEven(const MathStructure &,bool) const171 bool SqrtFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const172 bool SqrtFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const173 bool SqrtFunction::representsUndefined(const MathStructure&) const {return false;}
CbrtFunction()174 CbrtFunction::CbrtFunction() : MathFunction("cbrt", 1) {
175 	Argument *arg = new Argument("", false, false);
176 	arg->setHandleVector(true);
177 	setArgumentDefinition(1, arg);
178 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)179 int CbrtFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
180 	if(vargs[0].isVector()) return 0;
181 	if(vargs[0].representsNegative(true)) {
182 		mstruct = vargs[0];
183 		mstruct.negate();
184 		mstruct.raise(Number(1, 3, 0));
185 		mstruct.negate();
186 	} else if(vargs[0].representsNonNegative(true)) {
187 		mstruct = vargs[0];
188 		mstruct.raise(Number(1, 3, 0));
189 	} else {
190 		MathStructure mroot(3, 1, 0);
191 		mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ROOT), &vargs[0], &mroot, NULL);
192 	}
193 	return 1;
194 }
RootFunction()195 RootFunction::RootFunction() : MathFunction("root", 2) {
196 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
197 	arg->setComplexAllowed(false);
198 	arg->setHandleVector(true);
199 	setArgumentDefinition(1, arg);
200 	NumberArgument *arg2 = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
201 	arg2->setComplexAllowed(false);
202 	arg2->setRationalNumber(true);
203 	arg2->setHandleVector(true);
204 	setArgumentDefinition(2, arg2);
205 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)206 int RootFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
207 	if(vargs[0].isVector()) return 0;
208 	if(vargs[1].number().isOne()) {
209 		mstruct = vargs[0];
210 		return 1;
211 	}
212 	if(!vargs[1].number().isInteger() || !vargs[1].number().isPositive()) {
213 		mstruct = vargs[0];
214 		if(!vargs[0].representsScalar()) {
215 			mstruct.eval(eo);
216 		}
217 		if(mstruct.isVector()) return -1;
218 		Number nr_root(vargs[1].number().numerator());
219 		nr_root.setPrecisionAndApproximateFrom(vargs[1].number());
220 		Number nr_pow(vargs[1].number().denominator());
221 		nr_pow.setPrecisionAndApproximateFrom(vargs[1].number());
222 		if(nr_root.isNegative()) {
223 			nr_root.negate();
224 			nr_pow.negate();
225 		}
226 		if(nr_root.isOne()) {
227 			mstruct ^= nr_pow;
228 		} else if(nr_root.isZero()) {
229 			mstruct ^= nr_zero;
230 		} else {
231 			mstruct ^= nr_pow;
232 			mstruct.transform(this);
233 			mstruct.addChild(nr_root);
234 		}
235 		return 1;
236 	}
237 	if(vargs[0].representsNonNegative(true)) {
238 		mstruct = vargs[0];
239 		Number nr_exp(vargs[1].number());
240 		nr_exp.recip();
241 		mstruct.raise(nr_exp);
242 		return 1;
243 	} else if(vargs[1].number().isOdd() && vargs[0].representsNegative(true)) {
244 		mstruct = vargs[0];
245 		mstruct.negate();
246 		Number nr_exp(vargs[1].number());
247 		nr_exp.recip();
248 		mstruct.raise(nr_exp);
249 		mstruct.negate();
250 		return 1;
251 	}
252 	bool eval_mstruct = !vargs[0].isNumber();
253 	Number nr;
254 	if(eval_mstruct) {
255 		mstruct = vargs[0];
256 		if(eo.approximation == APPROXIMATION_TRY_EXACT && mstruct.representsScalar()) {
257 			EvaluationOptions eo2 = eo;
258 			eo2.approximation = APPROXIMATION_EXACT;
259 			mstruct.eval(eo2);
260 		} else {
261 			mstruct.eval(eo);
262 		}
263 		if(mstruct.isVector()) {
264 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
265 			return -1;
266 		}
267 		if(mstruct.representsNonNegative(true)) {
268 			Number nr_exp(vargs[1].number());
269 			nr_exp.recip();
270 			mstruct.raise(nr_exp);
271 			return 1;
272 		} else if(vargs[1].number().isOdd() && mstruct.representsNegative(true)) {
273 			mstruct.negate();
274 			Number nr_exp(vargs[1].number());
275 			nr_exp.recip();
276 			mstruct.raise(nr_exp);
277 			mstruct.negate();
278 			return 1;
279 		}
280 		if(!mstruct.isNumber()) {
281 			if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().isInteger()) {
282 				if(mstruct[1] == vargs[1]) {
283 					if(mstruct[1].number().isEven()) {
284 						if(!mstruct[0].representsReal(true)) return -1;
285 						mstruct.delChild(2);
286 						mstruct.setType(STRUCT_FUNCTION);
287 						mstruct.setFunctionId(FUNCTION_ID_ABS);
288 					} else {
289 						mstruct.setToChild(1);
290 					}
291 					return 1;
292 				} else if(mstruct[1].number().isIntegerDivisible(vargs[1].number())) {
293 					if(mstruct[1].number().isEven()) {
294 						if(!mstruct[0].representsReal(true)) return -1;
295 						mstruct[0].transform(STRUCT_FUNCTION);
296 						mstruct[0].setFunctionId(FUNCTION_ID_ABS);
297 					}
298 					mstruct[1].divide(vargs[1].number());
299 					return 1;
300 				} else if(!mstruct[1].number().isMinusOne() && vargs[1].number().isIntegerDivisible(mstruct[1].number())) {
301 					if(mstruct[1].number().isEven()) {
302 						if(!mstruct[0].representsReal(true)) return -1;
303 						mstruct[0].transform(STRUCT_FUNCTION);
304 						mstruct[0].setFunctionId(FUNCTION_ID_ABS);
305 					}
306 					Number new_root(vargs[1].number());
307 					new_root.divide(mstruct[1].number());
308 					bool bdiv = new_root.isNegative();
309 					if(bdiv) new_root.negate();
310 					mstruct[1] = new_root;
311 					mstruct.setType(STRUCT_FUNCTION);
312 					mstruct.setFunction(this);
313 					if(bdiv) mstruct.raise(nr_minus_one);
314 					return 1;
315 				} else if(mstruct[1].number().isMinusOne()) {
316 					mstruct[0].transform(STRUCT_FUNCTION, vargs[1]);
317 					mstruct[0].setFunction(this);
318 					return 1;
319 				} else if(mstruct[1].number().isNegative()) {
320 					mstruct[1].number().negate();
321 					mstruct.transform(STRUCT_FUNCTION, vargs[1]);
322 					mstruct.setFunction(this);
323 					mstruct.raise(nr_minus_one);
324 					return 1;
325 				}
326 			} else if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().isRational() && mstruct[1].number().denominatorIsTwo()) {
327 				Number new_root(vargs[1].number());
328 				new_root.multiply(Number(2, 1, 0));
329 				if(mstruct[1].number().numeratorIsOne()) {
330 					mstruct[1].number().set(new_root, true);
331 					mstruct.setType(STRUCT_FUNCTION);
332 					mstruct.setFunction(this);
333 				} else {
334 					mstruct[1].number().set(mstruct[1].number().numerator(), true);
335 					mstruct.transform(STRUCT_FUNCTION);
336 					mstruct.addChild(new_root);
337 					mstruct.setFunction(this);
338 				}
339 				return 1;
340 			} else if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_SQRT && mstruct.size() == 1) {
341 				Number new_root(vargs[1].number());
342 				new_root.multiply(Number(2, 1, 0));
343 				mstruct.addChild(new_root);
344 				mstruct.setFunction(this);
345 				return 1;
346 			} else if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_ROOT && mstruct.size() == 2 && mstruct[1].isNumber() && mstruct[1].number().isInteger() && mstruct[1].number().isPositive()) {
347 				Number new_root(vargs[1].number());
348 				new_root.multiply(mstruct[1].number());
349 				mstruct[1] = new_root;
350 				return 1;
351 			} else if(mstruct.isMultiplication()) {
352 				bool b = true;
353 				for(size_t i = 0; i < mstruct.size(); i++) {
354 					if(!mstruct[i].representsReal(true)) {
355 						b = false;
356 						break;
357 					}
358 				}
359 				if(b) {
360 					if(vargs[1].number().isOdd()) {
361 						bool b_neg = false;
362 						for(size_t i = 0; i < mstruct.size(); i++) {
363 							if(mstruct[i].isNumber() && mstruct[i].number().isNegative() && !mstruct[i].isMinusOne()) {
364 								mstruct[i].negate();
365 								b_neg = !b_neg;
366 							}
367 							mstruct[i].transform(STRUCT_FUNCTION, vargs[1]);
368 							mstruct[i].setFunction(this);
369 						}
370 						if(b_neg) mstruct.insertChild_nocopy(new MathStructure(-1, 1, 0), 1);
371 						return 1;
372 					} else {
373 						for(size_t i = 0; i < mstruct.size(); i++) {
374 							if(mstruct[i].isNumber() && mstruct[i].number().isNegative() && !mstruct[i].isMinusOne()) {
375 								MathStructure *mmul = new MathStructure(this, &mstruct[i], &vargs[1], NULL);
376 								(*mmul)[0].negate();
377 								mstruct[i] = nr_minus_one;
378 								mstruct.transform(STRUCT_FUNCTION, vargs[1]);
379 								mstruct.setFunction(this);
380 								mstruct.multiply_nocopy(mmul);
381 								return true;
382 							} else if(mstruct[i].representsPositive()) {
383 								mstruct[i].transform(STRUCT_FUNCTION, vargs[1]);
384 								mstruct[i].setFunction(this);
385 								mstruct[i].ref();
386 								MathStructure *mmul = &mstruct[i];
387 								mstruct.delChild(i + 1, true);
388 								mstruct.transform(STRUCT_FUNCTION, vargs[1]);
389 								mstruct.setFunction(this);
390 								mstruct.multiply_nocopy(mmul);
391 								return true;
392 							}
393 						}
394 					}
395 				}
396 			}
397 			return -1;
398 		}
399 		nr = mstruct.number();
400 	} else {
401 		nr = vargs[0].number();
402 	}
403 	if(!nr.root(vargs[1].number()) || (eo.approximation < APPROXIMATION_APPROXIMATE && nr.isApproximate() && !vargs[0].isApproximate() && !mstruct.isApproximate() && !vargs[1].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {
404 		if(!eval_mstruct) {
405 			if(vargs[0].number().isNegative() && vargs[1].number().isOdd()) {
406 				mstruct.set(this, &vargs[0], &vargs[1], NULL);
407 				mstruct[0].number().negate();
408 				mstruct.negate();
409 				return 1;
410 			}
411 			return 0;
412 		} else if(mstruct.number().isNegative() && vargs[1].number().isOdd()) {
413 			mstruct.number().negate();
414 			mstruct.transform(STRUCT_FUNCTION, vargs[1]);
415 			mstruct.setFunction(this);
416 			mstruct.negate();
417 			return 1;
418 		}
419 	} else {
420 		mstruct.set(nr);
421 		return 1;
422 	}
423 	return -1;
424 }
representsPositive(const MathStructure & vargs,bool allow_units) const425 bool RootFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsPositive(allow_units);}
representsNegative(const MathStructure & vargs,bool allow_units) const426 bool RootFunction::representsNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsOdd() && vargs[1].representsPositive() && vargs[0].representsNegative(allow_units);}
representsNonNegative(const MathStructure & vargs,bool allow_units) const427 bool RootFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNonNegative(allow_units);}
representsNonPositive(const MathStructure & vargs,bool allow_units) const428 bool RootFunction::representsNonPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsOdd() && vargs[1].representsPositive() && vargs[0].representsNonPositive(allow_units);}
representsInteger(const MathStructure &,bool) const429 bool RootFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const430 bool RootFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure &,bool) const431 bool RootFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool allow_units) const432 bool RootFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsReal(allow_units) && (vargs[0].representsNonNegative(allow_units) || vargs[1].representsOdd());}
representsNonComplex(const MathStructure & vargs,bool allow_units) const433 bool RootFunction::representsNonComplex(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units);}
representsComplex(const MathStructure & vargs,bool allow_units) const434 bool RootFunction::representsComplex(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && (vargs[0].representsComplex(allow_units) || (vargs[1].representsEven() && vargs[0].representsNegative(allow_units)));}
representsNonZero(const MathStructure & vargs,bool allow_units) const435 bool RootFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNonZero(allow_units);}
representsEven(const MathStructure &,bool) const436 bool RootFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const437 bool RootFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const438 bool RootFunction::representsUndefined(const MathStructure&) const {return false;}
439 
SquareFunction()440 SquareFunction::SquareFunction() : MathFunction("sq", 1) {
441 	Argument *arg = new Argument("", false, false);
442 	arg->setHandleVector(true);
443 	setArgumentDefinition(1, arg);
444 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)445 int SquareFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
446 	mstruct = vargs[0];
447 	mstruct ^= 2;
448 	return 1;
449 }
450 
ExpFunction()451 ExpFunction::ExpFunction() : MathFunction("exp", 1) {
452 	Argument *arg = new Argument("", false, false);
453 	arg->setHandleVector(true);
454 	setArgumentDefinition(1, arg);
455 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)456 int ExpFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
457 	mstruct = CALCULATOR->getVariableById(VARIABLE_ID_E);
458 	mstruct ^= vargs[0];
459 	return 1;
460 }
461 
LogFunction()462 LogFunction::LogFunction() : MathFunction("ln", 1) {
463 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
464 	arg->setHandleVector(true);
465 	setArgumentDefinition(1, arg);
466 }
representsPositive(const MathStructure & vargs,bool) const467 bool LogFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive() && ((vargs[0].isNumber() && vargs[0].number().isGreaterThan(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isGreaterThan(nr_one)));}
representsNegative(const MathStructure & vargs,bool) const468 bool LogFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative() && ((vargs[0].isNumber() && vargs[0].number().isLessThan(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isLessThan(nr_one)));}
representsNonNegative(const MathStructure & vargs,bool) const469 bool LogFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive() && ((vargs[0].isNumber() && vargs[0].number().isGreaterThanOrEqualTo(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isGreaterThanOrEqualTo(nr_one)));}
representsNonPositive(const MathStructure & vargs,bool) const470 bool LogFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative() && ((vargs[0].isNumber() && vargs[0].number().isLessThanOrEqualTo(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isLessThanOrEqualTo(nr_one)));}
representsInteger(const MathStructure &,bool) const471 bool LogFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const472 bool LogFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units) && vargs[0].representsNonZero(allow_units);}
representsRational(const MathStructure &,bool) const473 bool LogFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const474 bool LogFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive();}
representsNonComplex(const MathStructure & vargs,bool) const475 bool LogFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsComplex(const MathStructure & vargs,bool) const476 bool LogFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNegative();}
representsNonZero(const MathStructure & vargs,bool) const477 bool LogFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (vargs[0].representsNonPositive() || (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))));}
representsEven(const MathStructure &,bool) const478 bool LogFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const479 bool LogFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const480 bool LogFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)481 int LogFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
482 	if(vargs[0].isVector()) return 0;
483 
484 	mstruct = vargs[0];
485 
486 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
487 		mstruct.set(m_one);
488 		return true;
489 	} else if(mstruct.isPower()) {
490 		if(mstruct[0].isVariable() && mstruct[0].variable()->id() == VARIABLE_ID_E) {
491 			if(mstruct[1].representsReal()) {
492 				mstruct.setToChild(2, true);
493 				return true;
494 			}
495 		} else if(eo.approximation != APPROXIMATION_APPROXIMATE && ((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction()))) {
496 			MathStructure mstruct2;
497 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
498 			mstruct2 *= mstruct[1];
499 			mstruct = mstruct2;
500 			return true;
501 		}
502 	}
503 
504 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
505 		EvaluationOptions eo2 = eo;
506 		eo2.approximation = APPROXIMATION_EXACT;
507 		CALCULATOR->beginTemporaryStopMessages();
508 		mstruct.eval(eo2);
509 		if(mstruct.isVector()) {CALCULATOR->endTemporaryStopMessages(true); return -1;}
510 	} else {
511 		mstruct.eval(eo);
512 		if(mstruct.isVector()) return -1;
513 	}
514 
515 	bool b = false;
516 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
517 		mstruct.set(m_one);
518 		b = true;
519 	} else if(mstruct.isPower()) {
520 		if(mstruct[0].isVariable() && mstruct[0].variable()->id() == VARIABLE_ID_E) {
521 			if(mstruct[1].representsReal()) {
522 				mstruct.setToChild(2, true);
523 				b = true;
524 			}
525 		} else if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
526 			MathStructure mstruct2;
527 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
528 			mstruct2 *= mstruct[1];
529 			mstruct = mstruct2;
530 			b = true;
531 		}
532 	} else if(mstruct.isMultiplication()) {
533 		b = true;
534 		for(size_t i = 0; i < mstruct.size(); i++) {
535 			if(!mstruct[i].representsPositive()) {
536 				b = false;
537 				break;
538 			}
539 		}
540 		if(b) {
541 			MathStructure mstruct2;
542 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
543 			for(size_t i = 1; i < mstruct.size(); i++) {
544 				mstruct2.add(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[i], NULL), i > 1);
545 			}
546 			mstruct = mstruct2;
547 		}
548 	}
549 	if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
550 	if(b) return 1;
551 	if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
552 		EvaluationOptions eo2 = eo;
553 		eo2.approximation = APPROXIMATION_APPROXIMATE;
554 		mstruct = vargs[0];
555 		mstruct.eval(eo2);
556 	}
557 
558 	if(mstruct.isNumber()) {
559 		if(eo.allow_complex && mstruct.number().isMinusOne()) {
560 			mstruct = nr_one_i;
561 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
562 			return 1;
563 		} else if(mstruct.number().isI()) {
564 			mstruct.set(1, 2, 0);
565 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
566 			mstruct *= nr_one_i;
567 			return 1;
568 		} else if(mstruct.number().isMinusI()) {
569 			mstruct.set(-1, 2, 0);
570 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
571 			mstruct *= nr_one_i;
572 			return 1;
573 		} else if(eo.allow_complex && eo.allow_infinite && mstruct.number().isMinusInfinity()) {
574 			mstruct = CALCULATOR->getVariableById(VARIABLE_ID_PI);
575 			mstruct *= nr_one_i;
576 			Number nr; nr.setPlusInfinity();
577 			mstruct += nr;
578 			return 1;
579 		}
580 		Number nr(mstruct.number());
581 		if(nr.ln() && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
582 			mstruct.set(nr, true);
583 			return 1;
584 		}
585 		if(mstruct.number().isRational() && mstruct.number().isPositive()) {
586 			if(mstruct.number().isInteger()) {
587 				if(mstruct.number().isLessThanOrEqualTo(PRIMES[NR_OF_PRIMES - 1])) {
588 					vector<Number> factors;
589 					mstruct.number().factorize(factors);
590 					if(factors.size() > 1) {
591 						mstruct.clear(true);
592 						mstruct.setType(STRUCT_ADDITION);
593 						for(size_t i = 0; i < factors.size(); i++) {
594 							if(i > 0 && factors[i] == factors[i - 1]) {
595 								if(mstruct.last().isMultiplication()) mstruct.last().last().number()++;
596 								else mstruct.last() *= nr_two;
597 							} else {
598 								mstruct.addChild(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), NULL));
599 								mstruct.last().addChild(factors[i]);
600 							}
601 						}
602 						if(mstruct.size() == 1) mstruct.setToChild(1, true);
603 						return 1;
604 					}
605 				}
606 			} else {
607 				MathStructure mstruct2(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), NULL);
608 				mstruct2.addChild(mstruct.number().denominator());
609 				mstruct.number().set(mstruct.number().numerator());
610 				mstruct.transformById(FUNCTION_ID_LOG);
611 				mstruct -= mstruct2;
612 				return 1;
613 			}
614 		} else if(mstruct.number().hasImaginaryPart()) {
615 			if(mstruct.number().hasRealPart()) {
616 				MathStructure *marg = new MathStructure(mstruct);
617 				if(calculate_arg(*marg, eo)) {
618 					mstruct.transformById(FUNCTION_ID_ABS);
619 					mstruct.transformById(FUNCTION_ID_LOG);
620 					marg->multiply(nr_one_i);
621 					mstruct.add_nocopy(marg);
622 					return 1;
623 				}
624 				marg->unref();
625 			} else {
626 				bool b_neg = mstruct.number().imaginaryPartIsNegative();
627 				if(mstruct.number().abs()) {
628 					mstruct.transform(this);
629 					mstruct += b_neg ? nr_minus_half : nr_half;
630 					mstruct.last() *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
631 					mstruct.last().multiply(nr_one_i, true);
632 				}
633 				return 1;
634 			}
635 		}
636 	} else if(mstruct.isPower()) {
637 		if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
638 			MathStructure mstruct2;
639 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
640 			mstruct2 *= mstruct[1];
641 			mstruct = mstruct2;
642 			return 1;
643 		}
644 		if(mstruct[1].isNumber() && mstruct[1].number().isTwo() && mstruct[0].representsPositive()) {
645 			mstruct.setToChild(1, true);
646 			mstruct.transform(this);
647 			mstruct *= nr_two;
648 			return 1;
649 		}
650 		if(eo.approximation == APPROXIMATION_EXACT && !mstruct[1].isNumber()) {
651 			CALCULATOR->beginTemporaryStopMessages();
652 			MathStructure mtest(mstruct[1]);
653 			EvaluationOptions eo2 = eo;
654 			eo2.approximation = APPROXIMATION_APPROXIMATE;
655 			mtest.eval(eo2);
656 			if(!CALCULATOR->endTemporaryStopMessages() && mtest.isNumber() && mtest.number().isFraction()) {
657 				MathStructure mstruct2;
658 				mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
659 				mstruct2 *= mstruct[1];
660 				mstruct = mstruct2;
661 				return 1;
662 			}
663 		}
664 	}
665 	if(eo.allow_complex && mstruct.representsNegative()) {
666 		mstruct.negate();
667 		mstruct.transformById(FUNCTION_ID_LOG);
668 		mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
669 		mstruct.last() *= nr_one_i;
670 		return 1;
671 	}
672 	if(!mstruct.representsReal()) {
673 		MathStructure *marg = new MathStructure(mstruct);
674 		if(calculate_arg(*marg, eo)) {
675 			mstruct.transformById(FUNCTION_ID_ABS);
676 			mstruct.transformById(FUNCTION_ID_LOG);
677 			marg->multiply(nr_one_i);
678 			mstruct.add_nocopy(marg);
679 			return 1;
680 		}
681 		marg->unref();
682 	}
683 
684 	return -1;
685 
686 }
LognFunction()687 LognFunction::LognFunction() : MathFunction("log", 1, 2) {
688 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
689 	arg->setHandleVector(true);
690 	setArgumentDefinition(1, arg);
691 	arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
692 	arg->setHandleVector(true);
693 	setArgumentDefinition(2, arg);
694 	setDefaultValue(2, "e");
695 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)696 int LognFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
697 	if(vargs[0].isVector() || vargs[1].isVector()) return 0;
698 	if(vargs[1].isVariable() && vargs[1].variable()->id() == VARIABLE_ID_E) {
699 		mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[0], NULL);
700 		return 1;
701 	}
702 	mstruct = vargs[0];
703 	mstruct.eval(eo);
704 	if(mstruct.isVector()) return -1;
705 	MathStructure mstructv2 = vargs[1];
706 	mstructv2.eval(eo);
707 	if(mstructv2.isVector()) return -2;
708 	if(mstruct.isPower()) {
709 		if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
710 			MathStructure mstruct2;
711 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[0], &mstructv2, NULL);
712 			mstruct2 *= mstruct[1];
713 			mstruct = mstruct2;
714 			return 1;
715 		}
716 	} else if(mstruct.isMultiplication()) {
717 		bool b = true;
718 		for(size_t i = 0; i < mstruct.size(); i++) {
719 			if(!mstruct[i].representsPositive()) {
720 				b = false;
721 				break;
722 			}
723 		}
724 		if(b) {
725 			MathStructure mstruct2;
726 			mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[0], &mstructv2, NULL);
727 			for(size_t i = 1; i < mstruct.size(); i++) {
728 				mstruct2.add(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[i], &mstructv2, NULL), i > 1);
729 			}
730 			mstruct = mstruct2;
731 			return 1;
732 		}
733 	} else if(mstruct.isNumber() && mstructv2.isNumber()) {
734 		Number nr(mstruct.number());
735 		if(nr.log(mstructv2.number()) && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
736 			mstruct.set(nr, true);
737 			return 1;
738 		}
739 	}
740 	mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[0], NULL);
741 	mstruct.divide_nocopy(new MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[1], NULL));
742 	return 1;
743 }
CisFunction()744 CisFunction::CisFunction() : MathFunction("cis", 1) {
745 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
746 	arg->setHandleVector(true);
747 	setArgumentDefinition(1, arg);
748 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)749 int CisFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
750 
751 	if(vargs[0].isVector()) return 0;
752 	if(contains_angle_unit(vargs[0], eo.parse_options)) {
753 		if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getRadUnit()) {
754 			mstruct = vargs[0][0];
755 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getRadUnit()) {
756 			mstruct = vargs[0][1];
757 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getDegUnit()) {
758 			mstruct = vargs[0][0];
759 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
760 			mstruct.multiply(Number(1, 180), true);
761 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getDegUnit()) {
762 			mstruct = vargs[0][1];
763 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
764 			mstruct.multiply(Number(1, 180), true);
765 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getGraUnit()) {
766 			mstruct = vargs[0][0];
767 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
768 			mstruct.multiply(Number(1, 200), true);
769 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getGraUnit()) {
770 			mstruct = vargs[0][1];
771 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
772 			mstruct.multiply(Number(1, 200), true);
773 		} else {
774 			mstruct = vargs[0];
775 			mstruct.convert(CALCULATOR->getRadUnit());
776 			mstruct /= CALCULATOR->getRadUnit();
777 		}
778 	} else {
779 		mstruct = vargs[0];
780 	}
781 
782 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_PI) {
783 		mstruct.set(-1, 1, 0, true);
784 		return 1;
785 	} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isInteger() && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI) {
786 		if(mstruct[0].number().isEven()) {
787 			mstruct.set(1, 1, 0, true);
788 			return 1;
789 		} else if(mstruct[0].number().isOdd()) {
790 			mstruct.set(-1, 1, 0, true);
791 			return 1;
792 		}
793 	}
794 
795 	mstruct *= nr_one_i;
796 	mstruct ^= CALCULATOR->getVariableById(VARIABLE_ID_E);
797 	mstruct.swapChildren(1, 2);
798 
799 	return 1;
800 
801 }
LambertWFunction()802 LambertWFunction::LambertWFunction() : MathFunction("lambertw", 1, 2) {
803 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
804 	arg->setComplexAllowed(false);
805 	arg->setHandleVector(true);
806 	setArgumentDefinition(1, arg);
807 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
808 	setDefaultValue(2, "0");
809 }
representsNumber(const MathStructure & vargs,bool) const810 bool LambertWFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].representsNumber() && (vargs[1].isZero() || vargs[0].representsNonZero()));}
representsReal(const MathStructure & vargs,bool) const811 bool LambertWFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].isZero() && vargs[0].representsNonNegative());}
representsNonComplex(const MathStructure & vargs,bool) const812 bool LambertWFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].isZero() || (vargs[1].isZero() && vargs[0].representsNonNegative()));}
representsComplex(const MathStructure & vargs,bool) const813 bool LambertWFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].representsComplex() || (vargs[0].representsNonZero() && (vargs[1].isInteger() && (!vargs[1].isMinusOne() || vargs[0].representsPositive()) && !vargs[1].isZero())));}
representsNonZero(const MathStructure & vargs,bool) const814 bool LambertWFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].representsNonZero() || vargs[0].representsNonZero());}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)815 int LambertWFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
816 
817 	if(vargs[0].isVector()) return 0;
818 	mstruct = vargs[0];
819 
820 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
821 		EvaluationOptions eo2 = eo;
822 		eo2.approximation = APPROXIMATION_EXACT;
823 		CALCULATOR->beginTemporaryStopMessages();
824 		mstruct.eval(eo2);
825 		if(mstruct.isVector()) {CALCULATOR->endTemporaryStopMessages(true); return -1;}
826 	} else {
827 		mstruct.eval(eo);
828 		if(mstruct.isVector()) return -1;
829 	}
830 
831 	bool b = false;
832 	if(!vargs[1].isZero()) {
833 		if(mstruct.isZero()) {
834 			mstruct.set(nr_minus_inf, true);
835 			b = true;
836 		} else if(vargs[1].isMinusOne()) {
837 			if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isPower() && mstruct[1][0].isVariable() && mstruct[1][0].variable()->id() == VARIABLE_ID_E && mstruct[0].number() <= nr_minus_one && mstruct[1][1] == mstruct[0]) {
838 				mstruct.setToChild(1, true);
839 				b = true;
840 			}
841 		}
842 
843 	} else {
844 		if(mstruct.isZero()) {
845 			b = true;
846 		} else if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
847 			mstruct.set(1, 1, 0, true);
848 			b = true;
849 		} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isMinusOne() && mstruct[1].isPower() && mstruct[1][0].isVariable() && mstruct[1][0].variable()->id() == VARIABLE_ID_E && mstruct[1][1].isMinusOne()) {
850 			mstruct.set(-1, 1, 0, true);
851 			b = true;
852 		}
853 	}
854 	if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
855 	if(b) return 1;
856 	if(eo.approximation == APPROXIMATION_EXACT) return -1;
857 	if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
858 		EvaluationOptions eo2 = eo;
859 		eo2.approximation = APPROXIMATION_APPROXIMATE;
860 		mstruct = vargs[0];
861 		mstruct.eval(eo2);
862 	}
863 	if(mstruct.isNumber()) {
864 		Number nr(mstruct.number());
865 		if(nr.lambertW(vargs[1].number()) && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
866 			mstruct.set(nr, true);
867 			return 1;
868 		}
869 	}
870 	return -1;
871 }
872 
873