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 
SumFunction()34 SumFunction::SumFunction() : MathFunction("sum", 3, 4) {
35 	Argument *arg = new IntegerArgument();
36 	arg->setHandleVector(false);
37 	setArgumentDefinition(2, arg);
38 	arg = new IntegerArgument();
39 	arg->setHandleVector(false);
40 	setArgumentDefinition(3, arg);
41 	setArgumentDefinition(4, new SymbolicArgument());
42 	setDefaultValue(4, "undefined");
43 	setCondition("\\z >= \\y");
44 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)45 int SumFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
46 
47 	MathStructure m1(vargs[0]);
48 	EvaluationOptions eo2 = eo;
49 	eo2.calculate_functions = false;
50 	eo2.expand = false;
51 	Number i_nr(vargs[1].number());
52 	if(eo2.approximation == APPROXIMATION_TRY_EXACT) {
53 		Number nr(vargs[2].number());
54 		nr.subtract(i_nr);
55 		if(nr.isGreaterThan(100)) eo2.approximation = APPROXIMATION_APPROXIMATE;
56 	}
57 	CALCULATOR->beginTemporaryStopMessages();
58 	m1.eval(eo2);
59 	int im = 0;
60 	if(CALCULATOR->endTemporaryStopMessages(NULL, &im) > 0 || im > 0) m1 = vargs[0];
61 	eo2.calculate_functions = eo.calculate_functions;
62 	eo2.expand = eo.expand;
63 	mstruct.clear();
64 	MathStructure mstruct_calc;
65 	bool started = false;
66 	while(i_nr.isLessThanOrEqualTo(vargs[2].number())) {
67 		if(CALCULATOR->aborted()) {
68 			if(!started) {
69 				return 0;
70 			} else if(i_nr != vargs[2].number()) {
71 				MathStructure mmin(i_nr);
72 				mstruct.add(MathStructure(this, &vargs[0], &mmin, &vargs[2], &vargs[3], NULL), true);
73 				return 1;
74 			}
75 		}
76 		mstruct_calc.set(m1);
77 		mstruct_calc.replace(vargs[3], i_nr);
78 		mstruct_calc.eval(eo2);
79 		if(started) {
80 			mstruct.calculateAdd(mstruct_calc, eo2);
81 		} else {
82 			mstruct = mstruct_calc;
83 			mstruct.calculatesub(eo2, eo2);
84 			started = true;
85 		}
86 		i_nr += 1;
87 	}
88 	return 1;
89 
90 }
ProductFunction()91 ProductFunction::ProductFunction() : MathFunction("product", 3, 4) {
92 	Argument *arg = new IntegerArgument();
93 	arg->setHandleVector(false);
94 	setArgumentDefinition(2, arg);
95 	arg = new IntegerArgument();
96 	arg->setHandleVector(false);
97 	setArgumentDefinition(3, arg);
98 	setArgumentDefinition(4, new SymbolicArgument());
99 	setDefaultValue(4, "undefined");
100 	setCondition("\\z >= \\y");
101 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)102 int ProductFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
103 
104 	MathStructure m1(vargs[0]);
105 	EvaluationOptions eo2 = eo;
106 	eo2.calculate_functions = false;
107 	eo2.expand = false;
108 	Number i_nr(vargs[1].number());
109 	if(eo2.approximation == APPROXIMATION_TRY_EXACT) {
110 		Number nr(vargs[2].number());
111 		nr.subtract(i_nr);
112 		if(nr.isGreaterThan(100)) eo2.approximation = APPROXIMATION_APPROXIMATE;
113 	}
114 	CALCULATOR->beginTemporaryStopMessages();
115 	m1.eval(eo2);
116 	int im = 0;
117 	if(CALCULATOR->endTemporaryStopMessages(NULL, &im) || im > 0) m1 = vargs[0];
118 	eo2.calculate_functions = eo.calculate_functions;
119 	eo2.expand = eo.expand;
120 	mstruct.clear();
121 	MathStructure mstruct_calc;
122 	bool started = false;
123 	while(i_nr.isLessThanOrEqualTo(vargs[2].number())) {
124 		if(CALCULATOR->aborted()) {
125 			if(!started) {
126 				return 0;
127 			} else if(i_nr != vargs[2].number()) {
128 				MathStructure mmin(i_nr);
129 				mstruct.multiply(MathStructure(this, &vargs[0], &mmin, &vargs[2], &vargs[3], NULL), true);
130 				return 1;
131 			}
132 		}
133 		mstruct_calc.set(m1);
134 		mstruct_calc.replace(vargs[3], i_nr);
135 		mstruct_calc.eval(eo2);
136 		if(started) {
137 			mstruct.calculateMultiply(mstruct_calc, eo2);
138 		} else {
139 			mstruct = mstruct_calc;
140 			mstruct.calculatesub(eo2, eo2);
141 			started = true;
142 		}
143 		i_nr += 1;
144 	}
145 	return 1;
146 
147 }
148 
SolveFunction()149 SolveFunction::SolveFunction() : MathFunction("solve", 1, 2) {
150 	setArgumentDefinition(2, new SymbolicArgument());
151 	setDefaultValue(2, "undefined");
152 }
153 bool is_comparison_structure(const MathStructure &mstruct, const MathStructure &xvar, bool *bce = NULL, bool do_bce_or = false);
is_comparison_structure(const MathStructure & mstruct,const MathStructure & xvar,bool * bce,bool do_bce_or)154 bool is_comparison_structure(const MathStructure &mstruct, const MathStructure &xvar, bool *bce, bool do_bce_or) {
155 	if(mstruct.isComparison()) {
156 		if(bce) *bce = mstruct.comparisonType() == COMPARISON_EQUALS && mstruct[0] == xvar;
157 		return true;
158 	}
159 	if(bce && do_bce_or && mstruct.isLogicalOr()) {
160 		*bce = true;
161 		for(size_t i = 0; i < mstruct.size(); i++) {
162 			bool bcei = false;
163 			if(!is_comparison_structure(mstruct[i], xvar, &bcei, false)) return false;
164 			if(!bcei) *bce = false;
165 		}
166 		return true;
167 	}
168 	if(bce) *bce = false;
169 	if(mstruct.isLogicalAnd()) {
170 		for(size_t i = 0; i < mstruct.size(); i++) {
171 			if(is_comparison_structure(mstruct[i], xvar)) return true;
172 		}
173 		return true;
174 	} else if(mstruct.isLogicalOr()) {
175 		for(size_t i = 0; i < mstruct.size(); i++) {
176 			if(!is_comparison_structure(mstruct[i], xvar)) return false;
177 		}
178 		return true;
179 	}
180 	return false;
181 }
182 
solve_handle_logical_and(MathStructure & mstruct,MathStructure ** mtruefor,ComparisonType ct,bool & b_partial,const MathStructure & x_var)183 MathStructure *solve_handle_logical_and(MathStructure &mstruct, MathStructure **mtruefor, ComparisonType ct, bool &b_partial, const MathStructure &x_var) {
184 	MathStructure *mcondition = NULL;
185 	for(size_t i2 = 0; i2 < mstruct.size(); ) {
186 		if(ct == COMPARISON_EQUALS) {
187 			if(mstruct[i2].isComparison() && ct == mstruct[i2].comparisonType() && mstruct[i2][0].contains(x_var)) {
188 				if(mstruct[i2][0] == x_var) {
189 					if(mstruct.size() == 2) {
190 						if(i2 == 0) {
191 							mstruct[1].ref();
192 							mcondition = &mstruct[1];
193 						} else {
194 							mstruct[0].ref();
195 							mcondition = &mstruct[0];
196 						}
197 					} else {
198 						mcondition = new MathStructure();
199 						mcondition->set_nocopy(mstruct);
200 						mcondition->delChild(i2 + 1);
201 					}
202 					mstruct.setToChild(i2 + 1, true);
203 					break;
204 				} else {
205 					b_partial = true;
206 					i2++;
207 				}
208 			} else {
209 				i2++;
210 			}
211 		} else {
212 			if(mstruct[i2].isComparison() && mstruct[i2][0].contains(x_var)) {
213 				i2++;
214 			} else {
215 				mstruct[i2].ref();
216 				if(mcondition) {
217 					mcondition->add_nocopy(&mstruct[i2], OPERATION_LOGICAL_AND, true);
218 				} else {
219 					mcondition = &mstruct[i2];
220 				}
221 				mstruct.delChild(i2 + 1);
222 			}
223 		}
224 	}
225 	if(ct == COMPARISON_EQUALS) {
226 		if(mstruct.isLogicalAnd()) {
227 			MathStructure *mtmp = new MathStructure();
228 			mtmp->set_nocopy(mstruct);
229 			if(!(*mtruefor)) {
230 				*mtruefor = mtmp;
231 			} else {
232 				(*mtruefor)->add_nocopy(mtmp, OPERATION_LOGICAL_OR, true);
233 			}
234 			mstruct.clear(true);
235 		}
236 	} else {
237 		if(mstruct.size() == 1) {
238 			mstruct.setToChild(1, true);
239 			if(ct != COMPARISON_EQUALS) mstruct.setProtected();
240 		} else if(mstruct.size() == 0) {
241 			mstruct.clear(true);
242 			if(!(*mtruefor)) {
243 				*mtruefor = mcondition;
244 			} else {
245 				(*mtruefor)->add_nocopy(mcondition, OPERATION_LOGICAL_OR, true);
246 			}
247 			mcondition = NULL;
248 		} else if(ct != COMPARISON_EQUALS) {
249 			for(size_t i = 0; i < mstruct.size(); i++) {
250 				mstruct[i].setProtected();
251 			}
252 		}
253 	}
254 	return mcondition;
255 }
256 
257 void simplify_constant(MathStructure &mstruct, const MathStructure &x_var, const MathStructure &y_var, const MathStructure &c_var, bool in_comparison = false, bool in_or = false, bool in_and = false);
simplify_constant(MathStructure & mstruct,const MathStructure & x_var,const MathStructure & y_var,const MathStructure & c_var,bool in_comparison,bool in_or,bool in_and)258 void simplify_constant(MathStructure &mstruct, const MathStructure &x_var, const MathStructure &y_var, const MathStructure &c_var, bool in_comparison, bool in_or, bool in_and) {
259 	if(!in_comparison && mstruct.isComparison()) {
260 		if(mstruct[0] == c_var) {
261 			if(in_or) mstruct.clear(true);
262 			else mstruct.set(1, 1, 0);
263 		} else if(mstruct[0] == y_var) {
264 			if(mstruct[1].contains(y_var, true) <= 0) simplify_constant(mstruct[1], x_var, y_var, c_var, true);
265 		} else if(mstruct[0].contains(y_var, true) <= 0 && mstruct.contains(c_var, true) > 0) {
266 			if(in_or) mstruct.clear(true);
267 			else mstruct.set(1, 1, 0);
268 		}
269 	}
270 	if(in_comparison) {
271 		if(mstruct.contains(y_var, true) <= 0 && mstruct.contains(x_var, true) <= 0 && mstruct.contains(c_var, true) > 0) {
272 			mstruct = c_var;
273 			return;
274 		}
275 	}
276 	if(in_comparison) {
277 		int n_c = 0, b_cx = false;
278 		size_t i_c = 0;
279 		for(size_t i = 0; i < mstruct.size(); i++) {
280 			if(mstruct[i].contains(c_var, true) > 0) {
281 				n_c++;
282 				i_c = i;
283 				if(!b_cx && mstruct[i].contains(x_var, true) > 0) {
284 					b_cx = true;
285 				}
286 			}
287 		}
288 		if(!b_cx && n_c >= 1 && (mstruct.isAddition() || mstruct.isMultiplication())) {
289 			bool b_c = false;
290 			for(size_t i = 0; i < mstruct.size();) {
291 				if(mstruct[i].contains(c_var, true) > 0) {
292 					if(b_c) {
293 						mstruct.delChild(i + 1);
294 					} else {
295 						b_c = true;
296 						mstruct[i] = c_var;
297 						i++;
298 					}
299 				} else if(mstruct[i].contains(x_var, true) <= 0) {
300 					mstruct.delChild(i + 1);
301 				} else {
302 					i++;
303 				}
304 			}
305 			if(mstruct.size() == 1) mstruct.setToChild(1, true);
306 		} else if(n_c == 1) {
307 			if(b_cx) simplify_constant(mstruct[i_c], x_var, y_var, c_var, true);
308 			else mstruct[i_c] = c_var;
309 		}
310 	} else {
311 		for(size_t i = 0; i < mstruct.size(); i++) {
312 			simplify_constant(mstruct[i], x_var, y_var, c_var, false, mstruct.isLogicalOr(), mstruct.isLogicalAnd());
313 		}
314 	}
315 }
316 
test_equation(MathStructure & mstruct,const EvaluationOptions & eo,const MathStructure & x_var,const MathStructure & y_var,const MathStructure & x_value,const MathStructure & y_value)317 int test_equation(MathStructure &mstruct, const EvaluationOptions &eo, const MathStructure &x_var, const MathStructure &y_var, const MathStructure &x_value, const MathStructure &y_value) {
318 	if(mstruct.isComparison() && mstruct.comparisonType() == COMPARISON_EQUALS && mstruct[0] == y_var) {
319 		MathStructure mtest(mstruct);
320 		mtest.replace(x_var, x_value);
321 		MathStructure mtest2(y_var);
322 		mtest2.transform(COMPARISON_EQUALS, y_value);
323 		CALCULATOR->beginTemporaryStopMessages();
324 		EvaluationOptions eo2 = eo;
325 		eo2.approximation = APPROXIMATION_APPROXIMATE;
326 		mtest.calculateFunctions(eo2);
327 		mtest2.calculateFunctions(eo2);
328 		int b = test_comparisons(mtest, mtest2, y_var, eo);
329 		CALCULATOR->endTemporaryStopMessages();
330 		if(!b) mstruct.clear(true);
331 		return b;
332 	}
333 	bool b_ret = 0;
334 	for(size_t i = 0; i < mstruct.size(); i++) {
335 		int b = test_equation(mstruct[i], eo, x_var, y_var, x_value, y_value);
336 		if(b < 0) return b;
337 		else if(b > 0) b_ret = 1;
338 	}
339 	return b_ret;
340 }
341 
solve_equation(MathStructure & mstruct,const MathStructure & m_eqn,const MathStructure & y_var,const EvaluationOptions & eo,bool dsolve=false,const MathStructure & x_var=m_undefined,const MathStructure & c_var=m_undefined,const MathStructure & x_value=m_undefined,const MathStructure & y_value=m_undefined)342 int solve_equation(MathStructure &mstruct, const MathStructure &m_eqn, const MathStructure &y_var, const EvaluationOptions &eo, bool dsolve = false, const MathStructure &x_var = m_undefined, const MathStructure &c_var = m_undefined, const MathStructure &x_value = m_undefined, const MathStructure &y_value = m_undefined) {
343 
344 	int itry = 0;
345 	int ierror = 0;
346 	int first_error = 0;
347 
348 	Assumptions *assumptions = NULL;
349 	bool assumptions_added = false;
350 	AssumptionSign as = ASSUMPTION_SIGN_UNKNOWN;
351 	AssumptionType at = ASSUMPTION_TYPE_NUMBER;
352 	MathStructure msave;
353 	string strueforall;
354 
355 	while(true) {
356 
357 		if(itry == 1) {
358 			if(ierror == 1) {
359 				if(!dsolve) CALCULATOR->error(true, _("No equality or inequality to solve. The entered expression to solve is not correct (e.g. \"x + 5 = 3\" is correct)"), NULL);
360 				return -1;
361 			} else {
362 				first_error = ierror;
363 				msave = mstruct;
364 			}
365 		}
366 
367 		itry++;
368 
369 		if(itry == 2) {
370 			if(y_var.isVariable() && y_var.variable()->subtype() == SUBTYPE_UNKNOWN_VARIABLE) {
371 				assumptions = ((UnknownVariable*) y_var.variable())->assumptions();
372 				if(!assumptions) {
373 					assumptions = new Assumptions();
374 					assumptions->setSign(CALCULATOR->defaultAssumptions()->sign());
375 					assumptions->setType(CALCULATOR->defaultAssumptions()->type());
376 					((UnknownVariable*) y_var.variable())->setAssumptions(assumptions);
377 					assumptions_added = true;
378 				}
379 			} else {
380 				assumptions = CALCULATOR->defaultAssumptions();
381 			}
382 			if(assumptions->sign() != ASSUMPTION_SIGN_UNKNOWN) {
383 				as = assumptions->sign();
384 				assumptions->setSign(ASSUMPTION_SIGN_UNKNOWN);
385 			} else {
386 				itry++;
387 			}
388 		}
389 		if(itry == 3) {
390 			if(assumptions->type() > ASSUMPTION_TYPE_NUMBER) {
391 				at = assumptions->type();
392 				assumptions->setType(ASSUMPTION_TYPE_NUMBER);
393 				as = assumptions->sign();
394 				assumptions->setSign(ASSUMPTION_SIGN_UNKNOWN);
395 			} else {
396 				itry++;
397 			}
398 		}
399 
400 		if(itry > 3) {
401 			if(as != ASSUMPTION_SIGN_UNKNOWN) assumptions->setSign(as);
402 			if(at > ASSUMPTION_TYPE_NUMBER) assumptions->setType(at);
403 			if(assumptions_added) ((UnknownVariable*) y_var.variable())->setAssumptions(NULL);
404 			switch(first_error) {
405 				case 2: {
406 					CALCULATOR->error(true, _("The comparison is true for all %s (with current assumptions)."), format_and_print(y_var).c_str(), NULL);
407 					break;
408 				}
409 				case 3: {
410 					CALCULATOR->error(true, _("No possible solution was found (with current assumptions)."), NULL);
411 					break;
412 				}
413 				case 4: {
414 					CALCULATOR->error(true, _("Was unable to completely isolate %s."), format_and_print(y_var).c_str(), NULL);
415 					break;
416 				}
417 				case 7: {
418 					CALCULATOR->error(false, _("The comparison is true for all %s if %s."), format_and_print(y_var).c_str(), strueforall.c_str(), NULL);
419 					break;
420 				}
421 				default: {
422 					CALCULATOR->error(true, _("Was unable to isolate %s."), format_and_print(y_var).c_str(), NULL);
423 					break;
424 				}
425 			}
426 			mstruct = msave;
427 			return -1;
428 		}
429 
430 		ComparisonType ct = COMPARISON_EQUALS;
431 
432 		bool b = false;
433 		bool b_partial = false;
434 
435 		if(m_eqn.isComparison()) {
436 			ct = m_eqn.comparisonType();
437 			mstruct = m_eqn;
438 			b = true;
439 		} else if(m_eqn.isLogicalAnd() && m_eqn.size() > 0 && m_eqn[0].isComparison()) {
440 			ct = m_eqn[0].comparisonType();
441 			for(size_t i = 0; i < m_eqn.size(); i++) {
442 				if(m_eqn[i].isComparison() && m_eqn[i].contains(y_var, true) > 0) {
443 					ct = m_eqn[i].comparisonType();
444 					break;
445 				}
446 			}
447 			mstruct = m_eqn;
448 			b = true;
449 		} else if(m_eqn.isLogicalOr() && m_eqn.size() > 0 && m_eqn[0].isComparison()) {
450 			ct = m_eqn[0].comparisonType();
451 			mstruct = m_eqn;
452 			b = true;
453 		} else if(m_eqn.isLogicalOr() && m_eqn.size() > 0 && m_eqn[0].isLogicalAnd() && m_eqn[0].size() > 0 && m_eqn[0][0].isComparison()) {
454 			ct = m_eqn[0][0].comparisonType();
455 			for(size_t i = 0; i < m_eqn[0].size(); i++) {
456 				if(m_eqn[0][i].isComparison() && m_eqn[0][i].contains(y_var, true) > 0) {
457 					ct = m_eqn[0][i].comparisonType();
458 					break;
459 				}
460 			}
461 			mstruct = m_eqn;
462 			b = true;
463 		} else if(m_eqn.isVariable() && m_eqn.variable()->isKnown() && (eo.approximation != APPROXIMATION_EXACT || !m_eqn.variable()->isApproximate()) && ((KnownVariable*) m_eqn.variable())->get().isComparison()) {
464 			mstruct = ((KnownVariable*) m_eqn.variable())->get();
465 			mstruct.unformat();
466 			ct = m_eqn.comparisonType();
467 			b = true;
468 		} else {
469 			EvaluationOptions eo2 = eo;
470 			eo2.test_comparisons = false;
471 			eo2.assume_denominators_nonzero = false;
472 			eo2.isolate_x = false;
473 			mstruct = m_eqn;
474 			mstruct.eval(eo2);
475 			if(mstruct.isComparison()) {
476 				ct = mstruct.comparisonType();
477 				b = true;
478 			} else if(mstruct.isLogicalAnd() && mstruct.size() > 0 && mstruct[0].isComparison()) {
479 				ct = mstruct[0].comparisonType();
480 				b = true;
481 			} else if(mstruct.isLogicalOr() && mstruct.size() > 0 && mstruct[0].isComparison()) {
482 				ct = mstruct[0].comparisonType();
483 				b = true;
484 			} else if(mstruct.isLogicalOr() && mstruct.size() > 0 && mstruct[0].isLogicalAnd() && mstruct[0].size() > 0 && mstruct[0][0].isComparison()) {
485 				ct = mstruct[0][0].comparisonType();
486 				b = true;
487 			}
488 		}
489 
490 		if(!b) {
491 			ierror = 1;
492 			continue;
493 		}
494 
495 		EvaluationOptions eo2 = eo;
496 		eo2.isolate_var = &y_var;
497 		eo2.isolate_x = true;
498 		eo2.test_comparisons = true;
499 		mstruct.eval(eo2);
500 		if(dsolve) {
501 			if(x_value.isUndefined() || y_value.isUndefined()) {
502 				simplify_constant(mstruct, x_var, y_var, c_var);
503 				mstruct.eval(eo2);
504 			} else {
505 				int test_r = test_equation(mstruct, eo2, x_var, y_var, x_value, y_value);
506 				if(test_r < 0) {
507 					ierror = 8;
508 					continue;
509 				} else if(test_r > 0) {
510 					mstruct.eval(eo2);
511 				}
512 			}
513 		}
514 
515 		if(mstruct.isOne()) {
516 			ierror = 2;
517 			continue;
518 		} else if(mstruct.isZero()) {
519 			ierror = 3;
520 			continue;
521 		}
522 
523 		if(mstruct.isComparison()) {
524 			if((ct == COMPARISON_EQUALS && mstruct.comparisonType() != COMPARISON_EQUALS) || !mstruct.contains(y_var)) {
525 				if(itry == 1) {
526 					strueforall = format_and_print(mstruct);
527 				}
528 				ierror = 7;
529 				continue;
530 			} else if(ct == COMPARISON_EQUALS && mstruct[0] != y_var) {
531 				ierror = 4;
532 				continue;
533 			}
534 			if(ct == COMPARISON_EQUALS) {
535 				mstruct.setToChild(2, true);
536 			} else {
537 				mstruct.setProtected();
538 			}
539 			if(itry > 1) {
540 				assumptions->setSign(as);
541 				if(itry == 2) {
542 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
543 				} else if(itry == 3) {
544 					assumptions->setType(at);
545 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed type and sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
546 				}
547 				if(assumptions_added) ((UnknownVariable*) y_var.variable())->setAssumptions(NULL);
548 			}
549 			return 1;
550 		} else if(mstruct.isLogicalAnd()) {
551 			MathStructure *mtruefor = NULL;
552 			bool b_partial;
553 			MathStructure mcopy(mstruct);
554 			MathStructure *mcondition = solve_handle_logical_and(mstruct, &mtruefor, ct, b_partial, y_var);
555 			if((!mstruct.isComparison() && !mstruct.isLogicalAnd()) || (ct == COMPARISON_EQUALS && (!mstruct.isComparison() || mstruct.comparisonType() != COMPARISON_EQUALS || mstruct[0] != y_var)) || !mstruct.contains(y_var)) {
556 				if(mtruefor) delete mtruefor;
557 				if(mcondition) delete mcondition;
558 				if(b_partial) {
559 					ierror = 4;
560 				} else {
561 					ierror = 5;
562 				}
563 				mstruct = mcopy;
564 				continue;
565 			}
566 			if(itry > 1) {
567 				assumptions->setSign(as);
568 				if(itry == 2) {
569 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
570 				} else if(itry == 3) {
571 					assumptions->setType(at);
572 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed type and sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
573 				}
574 				if(assumptions_added) ((UnknownVariable*) y_var.variable())->setAssumptions(NULL);
575 			}
576 			if(mcondition) {
577 				CALCULATOR->error(false, _("The solution requires that %s."), format_and_print(*mcondition).c_str(), NULL);
578 				delete mcondition;
579 			}
580 			if(mtruefor) {
581 				CALCULATOR->error(false, _("The comparison is true for all %s if %s."), format_and_print(y_var).c_str(), format_and_print(*mtruefor).c_str(), NULL);
582 				delete mtruefor;
583 			}
584 			if(ct == COMPARISON_EQUALS) mstruct.setToChild(2, true);
585 			return 1;
586 		} else if(mstruct.isLogicalOr()) {
587 			MathStructure mcopy(mstruct);
588 			MathStructure *mtruefor = NULL;
589 			vector<MathStructure*> mconditions;
590 			for(size_t i = 0; i < mstruct.size(); ) {
591 				MathStructure *mcondition = NULL;
592 				bool b_and = false;
593 				if(mstruct[i].isLogicalAnd()) {
594 					mcondition = solve_handle_logical_and(mstruct[i], &mtruefor, ct, b_partial, y_var);
595 					b_and = true;
596 				}
597 				if(!mstruct[i].isZero()) {
598 					for(size_t i2 = 0; i2 < i; i2++) {
599 						if(mstruct[i2] == mstruct[i]) {
600 							mstruct[i].clear();
601 							if(mcondition && mconditions[i2]) {
602 								mconditions[i2]->add_nocopy(mcondition, OPERATION_LOGICAL_OR, true);
603 							}
604 							break;
605 						}
606 					}
607 				}
608 				bool b_del = false;
609 				if((!mstruct[i].isComparison() && !mstruct[i].isLogicalAnd()) || (ct == COMPARISON_EQUALS && (!mstruct[i].isComparison() || mstruct[i].comparisonType() != COMPARISON_EQUALS)) || !mstruct[i].contains(y_var)) {
610 					b_del = true;
611 				} else if(ct == COMPARISON_EQUALS && mstruct[i][0] != y_var) {
612 					b_partial = true;
613 					b_del = true;
614 				}
615 				if(b_del) {
616 					if(!mstruct[i].isZero()) {
617 						mstruct[i].ref();
618 						if(!mtruefor) {
619 							mtruefor = &mstruct[i];
620 						} else {
621 							mtruefor->add_nocopy(&mstruct[i], OPERATION_LOGICAL_OR, true);
622 						}
623 					}
624 					mstruct.delChild(i + 1);
625 				} else {
626 					mconditions.push_back(mcondition);
627 					if(!b_and && ct != COMPARISON_EQUALS) mstruct[i].setProtected();
628 					i++;
629 				}
630 			}
631 			if(ct == COMPARISON_EQUALS) {
632 				for(size_t i = 0; i < mstruct.size(); i++) {
633 					if(mstruct[i].isComparison() && mstruct[i].comparisonType() == ct) mstruct[i].setToChild(2, true);
634 				}
635 			}
636 			if(mstruct.size() == 1) {
637 				mstruct.setToChild(1, true);
638 			} else if(mstruct.size() == 0) {
639 				if(mtruefor) delete mtruefor;
640 				if(b_partial) ierror = 4;
641 				else ierror = 5;
642 				mstruct = mcopy;
643 				continue;
644 			} else {
645 				mstruct.setType(STRUCT_VECTOR);
646 			}
647 			if(itry > 1) {
648 				assumptions->setSign(as);
649 				if(itry == 2) {
650 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
651 				} else if(itry == 3) {
652 					assumptions->setType(at);
653 					CALCULATOR->error(false, _("Was unable to isolate %s with the current assumptions. The assumed type and sign was therefore temporarily set as unknown."), format_and_print(y_var).c_str(), NULL);
654 				}
655 				if(assumptions_added) ((UnknownVariable*) y_var.variable())->setAssumptions(NULL);
656 			}
657 
658 			if(mconditions.size() == 1) {
659 				if(mconditions[0]) {
660 					CALCULATOR->error(false, _("The solution requires that %s."), format_and_print(*mconditions[0]).c_str(), NULL);
661 					delete mconditions[0];
662 				}
663 			} else {
664 				string sconditions;
665 				for(size_t i = 0; i < mconditions.size(); i++) {
666 					if(mconditions[i]) {
667 						CALCULATOR->error(false, _("Solution %s requires that %s."), i2s(i + 1).c_str(), format_and_print(*mconditions[i]).c_str(), NULL);
668 						delete mconditions[i];
669 					}
670 				}
671 			}
672 			if(mtruefor) {
673 				CALCULATOR->error(false, _("The comparison is true for all %s if %s."), format_and_print(y_var).c_str(), format_and_print(*mtruefor).c_str(), NULL);
674 				delete mtruefor;
675 			}
676 			return 1;
677 		} else {
678 			ierror = 6;
679 		}
680 	}
681 	return -1;
682 
683 }
684 
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)685 int SolveFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
686 	return solve_equation(mstruct, vargs[0], vargs[1], eo);
687 }
688 
SolveMultipleFunction()689 SolveMultipleFunction::SolveMultipleFunction() : MathFunction("multisolve", 2) {
690 	setArgumentDefinition(1, new VectorArgument());
691 	VectorArgument *arg = new VectorArgument();
692 	arg->addArgument(new SymbolicArgument());
693 	arg->setReoccuringArguments(true);
694 	setArgumentDefinition(2, arg);
695 	setCondition("dimension(\\x) = dimension(\\y)");
696 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)697 int SolveMultipleFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
698 
699 	mstruct.clearVector();
700 
701 	if(vargs[1].size() < 1) return 1;
702 
703 	vector<bool> eleft;
704 	eleft.resize(vargs[0].size(), true);
705 	vector<size_t> eorder;
706 	bool b = false;
707 	for(size_t i = 0; i < vargs[1].size(); i++) {
708 		b = false;
709 		for(size_t i2 = 0; i2 < vargs[0].size(); i2++) {
710 			if(eleft[i2] && vargs[0][i2].contains(vargs[1][i], true)) {
711 				eorder.push_back(i2);
712 				eleft[i2] = false;
713 				b = true;
714 				break;
715 			}
716 		}
717 		if(!b) {
718 			eorder.clear();
719 			for(size_t i2 = 0; i2 < vargs[0].size(); i2++) {
720 				eorder.push_back(i2);
721 			}
722 			break;
723 		}
724 	}
725 
726 	for(size_t i = 0; i < eorder.size(); i++) {
727 		MathStructure msolve(vargs[0][eorder[i]]);
728 		EvaluationOptions eo2 = eo;
729 		eo2.isolate_var = &vargs[1][i];
730 		for(size_t i2 = 0; i2 < i; i2++) {
731 			msolve.replace(vargs[1][i2], mstruct[i2]);
732 		}
733 		msolve.eval(eo2);
734 
735 		if(msolve.isComparison()) {
736 			if(msolve[0] != vargs[1][i]) {
737 				if(!b) {
738 					CALCULATOR->error(true, _("Unable to isolate %s.\n\nYou might need to place the equations and variables in an appropriate order so that each equation at least contains the corresponding variable (if automatic reordering failed)."), format_and_print(vargs[1][i]).c_str(), NULL);
739 				} else {
740 					CALCULATOR->error(true, _("Unable to isolate %s."), format_and_print(vargs[1][i]).c_str(), NULL);
741 				}
742 				return 0;
743 			} else {
744 				if(msolve.comparisonType() == COMPARISON_EQUALS) {
745 					mstruct.addChild(msolve[1]);
746 				} else {
747 					CALCULATOR->error(true, _("Inequalities is not allowed in %s()."), preferredName().name.c_str(), NULL);
748 					return 0;
749 				}
750 			}
751 		} else if(msolve.isLogicalOr()) {
752 			for(size_t i2 = 0; i2 < msolve.size(); i2++) {
753 				if(!msolve[i2].isComparison() || msolve[i2].comparisonType() != COMPARISON_EQUALS || msolve[i2][0] != vargs[1][i]) {
754 					CALCULATOR->error(true, _("Unable to isolate %s."), format_and_print(vargs[1][i]).c_str(), NULL);
755 					return 0;
756 				} else {
757 					msolve[i2].setToChild(2, true);
758 				}
759 			}
760 			msolve.setType(STRUCT_VECTOR);
761 			mstruct.addChild(msolve);
762 		} else {
763 			CALCULATOR->error(true, _("Unable to isolate %s."), format_and_print(vargs[1][i]).c_str(), NULL);
764 			return 0;
765 		}
766 		for(size_t i2 = 0; i2 < i; i2++) {
767 			for(size_t i3 = 0; i3 <= i; i3++) {
768 				if(i2 != i3) {
769 					mstruct[i2].replace(vargs[1][i3], mstruct[i3]);
770 				}
771 			}
772 		}
773 	}
774 
775 	return 1;
776 
777 }
778 
779 MathStructure *find_deqn(MathStructure &mstruct);
find_deqn(MathStructure & mstruct)780 MathStructure *find_deqn(MathStructure &mstruct) {
781 	if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_DIFFERENTIATE) return &mstruct;
782 	for(size_t i = 0; i < mstruct.size(); i++) {
783 		MathStructure *m = find_deqn(mstruct[i]);
784 		if(m) return m;
785 	}
786 	return NULL;
787 }
788 
789 bool contains_ignore_diff(const MathStructure &m, const MathStructure &mstruct, const MathStructure &mdiff);
contains_ignore_diff(const MathStructure & m,const MathStructure & mstruct,const MathStructure & mdiff)790 bool contains_ignore_diff(const MathStructure &m, const MathStructure &mstruct, const MathStructure &mdiff) {
791 	if(m.equals(mstruct)) return true;
792 	if(m.equals(mdiff)) return false;
793 	for(size_t i = 0; i < m.size(); i++) {
794 		if(contains_ignore_diff(m[i], mstruct, mdiff)) return true;
795 	}
796 	if(m.isVariable() && m.variable()->isKnown()) {
797 		return contains_ignore_diff(((KnownVariable*) m.variable())->get(), mstruct, mdiff);
798 	} else if(m.isVariable()) {
799 		if(mstruct.isNumber() || !m.representsNumber()) return true;
800 	} else if(m.isAborted()) {
801 		return true;
802 	}
803 	return false;
804 }
805 
add_C(MathStructure & m_eqn,const MathStructure & m_x,const MathStructure & m_y,const MathStructure & x_value,const MathStructure & y_value)806 void add_C(MathStructure &m_eqn, const MathStructure &m_x, const MathStructure &m_y, const MathStructure &x_value, const MathStructure &y_value) {
807 	if(!y_value.isUndefined() && !x_value.isUndefined()) {
808 		MathStructure m_c(m_eqn);
809 		m_c.replace(m_x, x_value);
810 		m_c.replace(m_y, y_value);
811 		m_c.setType(STRUCT_ADDITION);
812 		m_c[1].negate();
813 		m_c.childUpdated(2);
814 		m_eqn[1] += m_c;
815 	} else {
816 		m_eqn[1] += CALCULATOR->getVariableById(VARIABLE_ID_C);
817 	}
818 	m_eqn.childrenUpdated();
819 }
820 
dsolve(MathStructure & m_eqn,const EvaluationOptions & eo,const MathStructure & m_diff,const MathStructure & y_value,const MathStructure & x_value)821 bool dsolve(MathStructure &m_eqn, const EvaluationOptions &eo, const MathStructure &m_diff, const MathStructure &y_value, const MathStructure &x_value) {
822 	MathStructure m_y(m_diff[0]), m_x(m_diff[1]);
823 	bool b = false;
824 	if(m_eqn[0] == m_diff) {
825 		if(m_eqn[1].containsRepresentativeOf(m_y, true, true) == 0) {
826 			// y'=f(x)
827 			MathStructure m_fx(m_eqn[1]);
828 			if(m_fx.integrate(m_x, eo, true, false) > 0) {
829 				m_eqn[0] = m_y;
830 				m_eqn[1] = m_fx;
831 				b = true;
832 			}
833 		} else if(m_eqn[1].containsRepresentativeOf(m_x, true, true) == 0) {
834 			MathStructure m_fy(m_eqn[1]);
835 			m_fy.inverse();
836 			if(m_fy.integrate(m_y, eo, true, false) > 0) {
837 				m_eqn[0] = m_fy;
838 				m_eqn[1] = m_x;
839 				b = true;
840 			}
841 		} else if(m_eqn[1].isMultiplication() && m_eqn[1].size() >= 2) {
842 			b = true;
843 			MathStructure m_fx(1, 1, 0), m_fy(1, 1, 0);
844 			for(size_t i = 0; i < m_eqn[1].size(); i++) {
845 				if(m_eqn[1][i].containsRepresentativeOf(m_y, true, true) != 0) {
846 					if(m_eqn[1][i].containsRepresentativeOf(m_x, true, true) != 0) {
847 						b = false;
848 						break;
849 					}
850 					if(m_fy.isOne()) m_fy = m_eqn[1][i];
851 					else m_fy.multiply(m_eqn[1][i], true);
852 				} else {
853 					if(m_fx.isOne()) m_fx = m_eqn[1][i];
854 					else m_fx.multiply(m_eqn[1][i], true);
855 				}
856 			}
857 			if(b) {
858 				// y'=f(x)*f(y)
859 				m_fy.inverse();
860 				if(m_fy.integrate(m_y, eo, true, false)  > 0 && m_fx.integrate(m_x, eo, true, false) > 0) {
861 					m_eqn[0] = m_fy;
862 					m_eqn[1] = m_fx;
863 				} else {
864 					b = false;
865 				}
866 			}
867 		} else {
868 			MathStructure mfactor(m_eqn);
869 			mfactor[1].factorize(eo, false, 0, 0, false, false, NULL, m_x);
870 			if(mfactor[1].isMultiplication() && mfactor[1].size() >= 2) {
871 				mfactor.childUpdated(2);
872 				if(dsolve(mfactor, eo, m_diff, y_value, x_value)) {
873 					m_eqn = mfactor;
874 					return 1;
875 				}
876 			}
877 			if(m_eqn[1].isAddition()) {
878 				MathStructure m_left;
879 				MathStructure m_muly;
880 				MathStructure m_mul_exp;
881 				MathStructure m_exp;
882 				b = true;
883 				for(size_t i = 0; i < m_eqn[1].size(); i++) {
884 					if(m_eqn[1][i] == m_y) {
885 						if(m_muly.isZero()) m_muly = m_one;
886 						else m_muly.add(m_one, true);
887 					} else if(m_eqn[1][i].containsRepresentativeOf(m_y, true, true) != 0) {
888 						if(m_left.isZero() && m_eqn[1][i].isPower() && m_eqn[1][i][0] == m_y && (m_mul_exp.isZero() || m_eqn[1][i][1] == m_exp)) {
889 							if(m_mul_exp.isZero()) {
890 								m_exp = m_eqn[1][i][1];
891 								m_mul_exp = m_one;
892 							} else {
893 								m_mul_exp.add(m_one, true);
894 							}
895 						} else if(m_eqn[1][i].isMultiplication()) {
896 							size_t i_my = 0;
897 							bool b2 = false, b2_exp = false;
898 							for(size_t i2 = 0; i2 < m_eqn[1][i].size(); i2++) {
899 									if(!b2 && m_eqn[1][i][i2] == m_y) {
900 									i_my = i2;
901 									b2 = true;
902 								} else if(!b2 && m_left.isZero() && m_eqn[1][i][i2].isPower() && m_eqn[1][i][i2][0] == m_y && (m_mul_exp.isZero() || m_eqn[1][i][i2][1] == m_exp)) {
903 									i_my = i2;
904 									b2 = true;
905 									b2_exp = true;
906 								} else if(m_eqn[1][i][i2].containsRepresentativeOf(m_y, true, true) != 0) {
907 									b2 = false;
908 									break;
909 								}
910 							}
911 							if(b2) {
912 								MathStructure m_a(m_eqn[1][i]);
913 								m_a.delChild(i_my + 1, true);
914 								if(b2_exp) {
915 									if(m_mul_exp.isZero()) {
916 										m_exp = m_eqn[1][i][i_my][1];
917 										m_mul_exp = m_a;
918 									} else {
919 										m_mul_exp.add(m_a, true);
920 									}
921 								} else {
922 									if(m_muly.isZero()) m_muly = m_a;
923 									else m_muly.add(m_a, true);
924 								}
925 							} else {
926 								b = false;
927 								break;
928 							}
929 						} else {
930 							b = false;
931 							break;
932 						}
933 					} else {
934 						if(!m_mul_exp.isZero()) {
935 							b = false;
936 							break;
937 						}
938 						if(m_left.isZero()) m_left = m_eqn[1][i];
939 						else m_left.add(m_eqn[1][i], true);
940 					}
941 				}
942 				if(b && !m_muly.isZero()) {
943 					if(!m_mul_exp.isZero()) {
944 						if(m_exp.isOne() || !m_left.isZero()) return false;
945 						// y' = f(x)*y+g(x)*y^c
946 						b = false;
947 						m_muly.calculateNegate(eo);
948 						MathStructure m_y1_integ(m_muly);
949 						if(m_y1_integ.integrate(m_x, eo, true, false) > 0) {
950 							m_exp.negate();
951 							m_exp += m_one;
952 							MathStructure m_y1_exp(m_exp);
953 							m_y1_exp *= m_y1_integ;
954 							m_y1_exp.transform(STRUCT_POWER, CALCULATOR->getVariableById(VARIABLE_ID_E));
955 							m_y1_exp.swapChildren(1, 2);
956 							MathStructure m_y1_exp_integ(m_y1_exp);
957 							m_y1_exp_integ *= m_mul_exp;
958 							if(m_y1_exp_integ.integrate(m_x, eo, true, false) > 0) {
959 								m_eqn[1] = m_exp;
960 								m_eqn[1] *= m_y1_exp_integ;
961 								m_eqn[0] = m_y;
962 								m_eqn[0] ^= m_exp;
963 								m_eqn[0] *= m_y1_exp;
964 								add_C(m_eqn, m_x, m_y, x_value, y_value);
965 								m_eqn[0].delChild(m_eqn[0].size());
966 								m_eqn[1] /= m_y1_exp;
967 								m_eqn.childrenUpdated();
968 								return 1;
969 							}
970 						}
971 					} else if(m_left.isZero()) {
972 						// y'=f(x)*y+g(x)*y
973 						MathStructure mtest(m_eqn);
974 						MathStructure m_fy(m_y);
975 						m_fy.inverse();
976 						MathStructure m_fx(m_muly);
977 						if(m_fy.integrate(m_y, eo, true, false) > 0 && m_fx.integrate(m_x, eo, true, false) > 0) {
978 							m_eqn[0] = m_fy;
979 							m_eqn[1] = m_fx;
980 							b = true;
981 						}
982 					} else {
983 						// y'=f(x)*y+g(x)
984 						MathStructure integ_fac(m_muly);
985 						integ_fac.negate();
986 						if(integ_fac.integrate(m_x, eo, true, false) > 0) {
987 							UnknownVariable *var = new UnknownVariable("", "u");
988 							Assumptions *ass = new Assumptions();
989 							if(false) {
990 								ass->setType(ASSUMPTION_TYPE_REAL);
991 							}
992 							var->setAssumptions(ass);
993 							MathStructure m_u(var);
994 							m_u.inverse();
995 							if(m_u.integrate(var, eo, false, false) > 0) {
996 								MathStructure m_eqn2(integ_fac);
997 								m_eqn2.transform(COMPARISON_EQUALS, m_u);
998 								m_eqn2.isolate_x(eo, var);
999 								if(m_eqn2.isComparison() && m_eqn2.comparisonType() == COMPARISON_EQUALS && m_eqn2[0] == var) {
1000 									integ_fac = m_eqn2[1];
1001 									MathStructure m_fx(m_left);
1002 									m_fx *= integ_fac;
1003 									if(m_fx.integrate(m_x, eo, true, false) > 0) {
1004 										m_eqn[0] = m_y;
1005 										m_eqn[0] *= integ_fac;
1006 										m_eqn[1] = m_fx;
1007 										add_C(m_eqn, m_x, m_y, x_value, y_value);
1008 										m_eqn[0] = m_y;
1009 										m_eqn[1] /= integ_fac;
1010 										m_eqn.childrenUpdated();
1011 										return 1;
1012 									}
1013 								} else if(m_eqn2.isLogicalOr() && m_eqn2.size() >= 2) {
1014 									b = true;
1015 									for(size_t i = 0; i < m_eqn2.size(); i++) {
1016 										if(!m_eqn2[i].isComparison() || m_eqn2[i].comparisonType() != COMPARISON_EQUALS || m_eqn2[i][0] != var) {
1017 											b = false;
1018 											break;
1019 										}
1020 									}
1021 									if(b) {
1022 										MathStructure m_eqn_new;
1023 										m_eqn_new.setType(STRUCT_LOGICAL_OR);
1024 										for(size_t i = 0; i < m_eqn2.size(); i++) {
1025 											integ_fac = m_eqn2[i][1];
1026 											MathStructure m_fx(m_left);
1027 											m_fx *= integ_fac;
1028 											if(m_fx.integrate(m_x, eo, true, false) > 0) {
1029 												MathStructure m_fy(m_y);
1030 												m_fy *= integ_fac;
1031 												m_eqn_new.addChild(m_fy);
1032 												m_eqn_new.last().transform(COMPARISON_EQUALS, m_fx);
1033 												add_C(m_eqn_new.last(), m_x, m_y, x_value, y_value);
1034 												m_eqn_new.last()[0] = m_y;
1035 												m_eqn_new.last()[1] /= integ_fac;
1036 												m_eqn_new.last().childrenUpdated();
1037 												m_eqn_new.childUpdated(m_eqn_new.size());
1038 											} else {
1039 												b = false;
1040 												break;
1041 											}
1042 										}
1043 										if(b) {
1044 											m_eqn_new.childrenUpdated();
1045 											m_eqn = m_eqn_new;
1046 											return 1;
1047 										}
1048 									}
1049 								}
1050 							}
1051 							var->destroy();
1052 						}
1053 					}
1054 				} else {
1055 					b = false;
1056 				}
1057 			}
1058 		}
1059 		if(b) {
1060 			add_C(m_eqn, m_x, m_y, x_value, y_value);
1061 			return 1;
1062 		}
1063 	}
1064 	return false;
1065 }
1066 
DSolveFunction()1067 DSolveFunction::DSolveFunction() : MathFunction("dsolve", 1, 3) {
1068 	setDefaultValue(2, "undefined");
1069 	setDefaultValue(3, "0");
1070 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1071 int DSolveFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1072 	MathStructure m_eqn(vargs[0]);
1073 	EvaluationOptions eo2 = eo;
1074 	eo2.isolate_x = false;
1075 	eo2.protected_function = CALCULATOR->getFunctionById(FUNCTION_ID_DIFFERENTIATE);
1076 	m_eqn.eval(eo2);
1077 	MathStructure *m_diff_p = NULL;
1078 	if(m_eqn.isLogicalAnd()) {
1079 		for(size_t i = 0; i < m_eqn.size(); i++) {
1080 			if(m_eqn[i].isComparison() && m_eqn.comparisonType() == COMPARISON_EQUALS) {
1081 				m_diff_p = find_deqn(m_eqn[i]);
1082 				if(m_diff_p) break;
1083 			}
1084 		}
1085 	} else if(m_eqn.isComparison() && m_eqn.comparisonType() == COMPARISON_EQUALS) {
1086 		m_diff_p = find_deqn(m_eqn);
1087 	}
1088 	if(!m_diff_p) {
1089 		CALCULATOR->error(true, _("No differential equation found."), NULL);
1090 		mstruct = m_eqn; return -1;
1091 	}
1092 	MathStructure m_diff(*m_diff_p);
1093 	if(m_diff.size() < 3 || (!m_diff[0].isSymbolic() && !m_diff[0].isVariable()) || (!m_diff[1].isSymbolic() && !m_diff[1].isVariable()) || !m_diff[2].isInteger() || !m_diff[2].number().isPositive() || !m_diff[2].number().isLessThanOrEqualTo(10)) {
1094 		CALCULATOR->error(true, _("No differential equation found."), NULL);
1095 		mstruct = m_eqn; return -1;
1096 	}
1097 	if(m_diff[2].number().intValue() != 1) {
1098 		CALCULATOR->error(true, _("Unable to solve differential equation."), NULL);
1099 		mstruct = m_eqn;
1100 		return -1;
1101 	}
1102 	m_eqn.isolate_x(eo2, m_diff);
1103 	mstruct = m_eqn;
1104 	if(eo.approximation == APPROXIMATION_TRY_EXACT) eo2.approximation = APPROXIMATION_EXACT;
1105 	if(m_eqn.isLogicalAnd()) {
1106 		for(size_t i = 0; i < m_eqn.size(); i++) {
1107 			if(m_eqn[i].isComparison() && m_eqn[i].comparisonType() == COMPARISON_EQUALS && m_eqn[i][0] == m_diff) {
1108 				dsolve(m_eqn[i], eo2, m_diff, vargs[1], vargs[2]);
1109 			}
1110 		}
1111 	} else if(m_eqn.isLogicalOr()) {
1112 		for(size_t i = 0; i < m_eqn.size(); i++) {
1113 			if(m_eqn[i].isComparison() && m_eqn[i].comparisonType() == COMPARISON_EQUALS && m_eqn[i][0] == m_diff) {
1114 				dsolve(m_eqn[i], eo2, m_diff, vargs[1], vargs[2]);
1115 			} else if(m_eqn[i].isLogicalAnd()) {
1116 				for(size_t i2 = 0; i2 < m_eqn[i].size(); i2++) {
1117 					if(m_eqn[i][i2].isComparison() && m_eqn[i][i2].comparisonType() == COMPARISON_EQUALS && m_eqn[i][i2][0] == m_diff) {
1118 						dsolve(m_eqn[i][i2], eo2, m_diff, vargs[1], vargs[2]);
1119 					}
1120 				}
1121 			}
1122 		}
1123 	} else if(m_eqn.isComparison() && m_eqn.comparisonType() == COMPARISON_EQUALS && m_eqn[0] == m_diff) {
1124 		dsolve(m_eqn, eo2, m_diff, vargs[1], vargs[2]);
1125 	}
1126 	if(m_eqn.contains(m_diff)) {
1127 		CALCULATOR->error(true, _("Unable to solve differential equation."), NULL);
1128 		return -1;
1129 	}
1130 	m_eqn.calculatesub(eo2, eo2, true);
1131 	MathStructure msolve(m_eqn);
1132 	if(solve_equation(msolve, m_eqn, m_diff[0], eo, true, m_diff[1], MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_C)), vargs[2], vargs[1]) <= 0) {
1133 		CALCULATOR->error(true, _("Unable to solve differential equation."), NULL);
1134 		return -1;
1135 	}
1136 	mstruct = msolve;
1137 	return 1;
1138 }
1139 
1140