1 /*
2     Qalculate (library)
3 
4     Copyright (C) 2003-2007, 2008, 2016-2019  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 "MathStructure.h"
15 #include "Calculator.h"
16 #include "BuiltinFunctions.h"
17 #include "Number.h"
18 #include "Function.h"
19 #include "Variable.h"
20 #include "Unit.h"
21 #include "Prefix.h"
22 #include "MathStructure-support.h"
23 
24 using std::string;
25 using std::cout;
26 using std::vector;
27 using std::endl;
28 
gatherInformation(const MathStructure & mstruct,vector<Unit * > & base_units,vector<AliasUnit * > & alias_units,bool check_variables=false)29 void gatherInformation(const MathStructure &mstruct, vector<Unit*> &base_units, vector<AliasUnit*> &alias_units, bool check_variables = false) {
30 	switch(mstruct.type()) {
31 		case STRUCT_UNIT: {
32 			switch(mstruct.unit()->subtype()) {
33 				case SUBTYPE_BASE_UNIT: {
34 					for(size_t i = 0; i < base_units.size(); i++) {
35 						if(base_units[i] == mstruct.unit()) {
36 							return;
37 						}
38 					}
39 					base_units.push_back(mstruct.unit());
40 					break;
41 				}
42 				case SUBTYPE_ALIAS_UNIT: {
43 					for(size_t i = 0; i < alias_units.size(); i++) {
44 						if(alias_units[i] == mstruct.unit()) {
45 							return;
46 						}
47 					}
48 					alias_units.push_back((AliasUnit*) (mstruct.unit()));
49 					break;
50 				}
51 				case SUBTYPE_COMPOSITE_UNIT: {
52 					gatherInformation(((CompositeUnit*) (mstruct.unit()))->generateMathStructure(), base_units, alias_units, check_variables);
53 					break;
54 				}
55 			}
56 			break;
57 		}
58 		case STRUCT_VARIABLE: {
59 			if(check_variables && mstruct.variable()->isKnown()) gatherInformation(((KnownVariable*) mstruct.variable())->get(), base_units, alias_units, check_variables);
60 			break;
61 		}
62 		case STRUCT_FUNCTION: {
63 			if(mstruct.function()->id() == FUNCTION_ID_STRIP_UNITS) break;
64 			for(size_t i = 0; i < mstruct.size(); i++) {
65 				if(!mstruct.function()->getArgumentDefinition(i + 1) || mstruct.function()->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) {
66 					gatherInformation(mstruct[i], base_units, alias_units, check_variables);
67 				}
68 			}
69 			break;
70 		}
71 		default: {
72 			for(size_t i = 0; i < mstruct.size(); i++) {
73 				gatherInformation(mstruct[i], base_units, alias_units, check_variables);
74 			}
75 			break;
76 		}
77 	}
78 
79 }
80 
isUnitCompatible(const MathStructure & mstruct) const81 int MathStructure::isUnitCompatible(const MathStructure &mstruct) const {
82 	if(!isMultiplication() && mstruct.isMultiplication()) return mstruct.isUnitCompatible(*this);
83 	int b1 = mstruct.containsRepresentativeOfType(STRUCT_UNIT, true, true);
84 	int b2 = containsRepresentativeOfType(STRUCT_UNIT, true, true);
85 	if(b1 < 0 || b2 < 0) return -1;
86 	if(b1 != b2) return false;
87 	if(!b1) return true;
88 	if(isMultiplication()) {
89 		size_t unit_count1 = 0, unit_count2 = 0;
90 		for(size_t i = 0; i < SIZE; i++) {
91 			if(CHILD(i).isUnit_exp()) unit_count1++;
92 			else if(CHILD(i).containsRepresentativeOfType(STRUCT_UNIT, true, true) != 0) return -1;
93 		}
94 		if(mstruct.isMultiplication()) {
95 			for(size_t i = 0; i < mstruct.size(); i++) {
96 				if(mstruct[i].isUnit_exp()) unit_count2++;
97 				else if(mstruct[i].containsRepresentativeOfType(STRUCT_UNIT, true, true) != 0) return -1;
98 			}
99 		} else if(mstruct.isUnit_exp()) {
100 			if(unit_count1 > 1) return false;
101 			for(size_t i = 0; i < SIZE; i++) {
102 				if(CHILD(i).isUnit_exp()) return CHILD(1) == mstruct;
103 			}
104 		} else {
105 			return -1;
106 		}
107 		if(unit_count1 != unit_count2) return false;
108 		size_t i2 = 0;
109 		for(size_t i = 0; i < SIZE; i++) {
110 			if(CHILD(i).isUnit_exp()) {
111 				for(; i2 < mstruct.size(); i2++) {
112 					if(mstruct[i2].isUnit_exp()) {
113 						if(CHILD(i) != mstruct[i2]) return false;
114 						i2++;
115 						break;
116 					}
117 				}
118 			}
119 		}
120 	} else if(isUnit_exp()) {
121 		if(mstruct.isUnit_exp()) return equals(mstruct);
122 	}
123 	return -1;
124 }
125 
syncUnits(bool sync_nonlinear_relations,bool * found_nonlinear_relations,bool calculate_new_functions,const EvaluationOptions & feo)126 bool MathStructure::syncUnits(bool sync_nonlinear_relations, bool *found_nonlinear_relations, bool calculate_new_functions, const EvaluationOptions &feo) {
127 	if(SIZE == 0) return false;
128 	vector<Unit*> base_units;
129 	vector<AliasUnit*> alias_units;
130 	vector<CompositeUnit*> composite_units;
131 	gatherInformation(*this, base_units, alias_units);
132 	if(alias_units.empty() || base_units.size() + alias_units.size() == 1) return false;
133 	CompositeUnit *cu;
134 	bool b = false, do_erase = false;
135 	for(size_t i = 0; i < alias_units.size(); ) {
136 		do_erase = false;
137 		if(alias_units[i]->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
138 			b = false;
139 			cu = (CompositeUnit*) alias_units[i]->baseUnit();
140 			for(size_t i2 = 0; i2 < base_units.size(); i2++) {
141 				if(cu->containsRelativeTo(base_units[i2])) {
142 					for(size_t i3 = 0; i3 < composite_units.size(); i3++) {
143 						if(composite_units[i3] == cu) {
144 							b = true;
145 							break;
146 						}
147 					}
148 					if(!b) composite_units.push_back(cu);
149 					do_erase = true;
150 					break;
151 				}
152 			}
153 			for(size_t i2 = 0; !do_erase && i2 < alias_units.size(); i2++) {
154 				if(i != i2 && alias_units[i2]->baseUnit() != cu && cu->containsRelativeTo(alias_units[i2])) {
155 					for(size_t i3 = 0; i3 < composite_units.size(); i3++) {
156 						if(composite_units[i3] == cu) {
157 							b = true;
158 							break;
159 						}
160 					}
161 					if(!b) composite_units.push_back(cu);
162 					do_erase = true;
163 					break;
164 				}
165 			}
166 		}
167 		if(do_erase) {
168 			alias_units.erase(alias_units.begin() + i);
169 			for(int i2 = 1; i2 <= (int) cu->countUnits(); i2++) {
170 				b = false;
171 				Unit *cub = cu->get(i2);
172 				switch(cub->subtype()) {
173 					case SUBTYPE_BASE_UNIT: {
174 						for(size_t i3 = 0; i3 < base_units.size(); i3++) {
175 							if(base_units[i3] == cub) {
176 								b = true;
177 								break;
178 							}
179 						}
180 						if(!b) base_units.push_back(cub);
181 						break;
182 					}
183 					case SUBTYPE_ALIAS_UNIT: {
184 						for(size_t i3 = 0; i3 < alias_units.size(); i3++) {
185 							if(alias_units[i3] == cub) {
186 								b = true;
187 								break;
188 							}
189 						}
190 						if(!b) alias_units.push_back((AliasUnit*) cub);
191 						break;
192 					}
193 					case SUBTYPE_COMPOSITE_UNIT: {
194 						gatherInformation(((CompositeUnit*) cub)->generateMathStructure(), base_units, alias_units);
195 						break;
196 					}
197 				}
198 			}
199 			i = 0;
200 		} else {
201 			i++;
202 		}
203 	}
204 
205 	for(size_t i = 0; i < alias_units.size();) {
206 		do_erase = false;
207 		for(size_t i2 = 0; i2 < alias_units.size(); i2++) {
208 			if(i != i2 && alias_units[i]->baseUnit() == alias_units[i2]->baseUnit()) {
209 				if(alias_units[i2]->isParentOf(alias_units[i])) {
210 					do_erase = true;
211 					break;
212 				} else if(!alias_units[i]->isParentOf(alias_units[i2])) {
213 					b = false;
214 					for(size_t i3 = 0; i3 < base_units.size(); i3++) {
215 						if(base_units[i3] == alias_units[i2]->firstBaseUnit()) {
216 							b = true;
217 							break;
218 						}
219 					}
220 					if(!b) base_units.push_back((Unit*) alias_units[i]->baseUnit());
221 					do_erase = true;
222 					break;
223 				}
224 			}
225 		}
226 		if(do_erase) {
227 			alias_units.erase(alias_units.begin() + i);
228 			i = 0;
229 		} else {
230 			i++;
231 		}
232 	}
233 	for(size_t i = 0; i < alias_units.size();) {
234 		do_erase = false;
235 		if(alias_units[i]->baseUnit()->subtype() == SUBTYPE_BASE_UNIT) {
236 			for(size_t i2 = 0; i2 < base_units.size(); i2++) {
237 				if(alias_units[i]->baseUnit() == base_units[i2]) {
238 					do_erase = true;
239 					break;
240 				}
241 			}
242 		}
243 		if(do_erase) {
244 			alias_units.erase(alias_units.begin() + i);
245 			i = 0;
246 		} else {
247 			i++;
248 		}
249 	}
250 	b = false;
251 	bool fcr = false;
252 	for(size_t i = 0; i < composite_units.size(); i++) {
253 		if(convert(composite_units[i], sync_nonlinear_relations, (found_nonlinear_relations || sync_nonlinear_relations) ? &fcr : NULL, calculate_new_functions, feo)) b = true;
254 	}
255 	if(dissolveAllCompositeUnits()) b = true;
256 	for(size_t i = 0; i < base_units.size(); i++) {
257 		if(convert(base_units[i], sync_nonlinear_relations, (found_nonlinear_relations || sync_nonlinear_relations) ? &fcr : NULL, calculate_new_functions, feo)) b = true;
258 	}
259 	for(size_t i = 0; i < alias_units.size(); i++) {
260 		if(convert(alias_units[i], sync_nonlinear_relations, (found_nonlinear_relations || sync_nonlinear_relations) ? &fcr : NULL, calculate_new_functions, feo)) b = true;
261 	}
262 	if(b && sync_nonlinear_relations && fcr) CALCULATOR->error(false, _("Calculations involving conversion of units without proportional linear relationship might give unexpected results and is not recommended."), NULL);
263 	if(fcr && found_nonlinear_relations) *found_nonlinear_relations = fcr;
264 	return b;
265 }
266 
has_approximate_relation_to_base(Unit * u,bool do_intervals)267 bool has_approximate_relation_to_base(Unit *u, bool do_intervals) {
268 	if(u->subtype() == SUBTYPE_ALIAS_UNIT) {
269 		if(((AliasUnit*) u)->isApproximate()) return do_intervals;
270 		if(((AliasUnit*) u)->expression().find_first_not_of(NUMBER_ELEMENTS EXPS) != string::npos && !((AliasUnit*) u)->hasNonlinearExpression()) return true;
271 		return has_approximate_relation_to_base(((AliasUnit*) u)->firstBaseUnit());
272 	} else if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
273 		for(size_t i = 1; i <= ((CompositeUnit*) u)->countUnits(); i++) {
274 			if(has_approximate_relation_to_base(((CompositeUnit*) u)->get(i))) return true;
275 		}
276 	}
277 	return false;
278 }
279 
testDissolveCompositeUnit(Unit * u)280 bool MathStructure::testDissolveCompositeUnit(Unit *u) {
281 	if(m_type == STRUCT_UNIT) {
282 		if(o_unit->subtype() == SUBTYPE_COMPOSITE_UNIT) {
283 			if(((CompositeUnit*) o_unit)->containsRelativeTo(u)) {
284 				set(((CompositeUnit*) o_unit)->generateMathStructure());
285 				return true;
286 			}
287 		} else if(o_unit->subtype() == SUBTYPE_ALIAS_UNIT && o_unit->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
288 			if(((CompositeUnit*) (o_unit->baseUnit()))->containsRelativeTo(u)) {
289 				if(convert(o_unit->baseUnit())) {
290 					convert(u);
291 					return true;
292 				}
293 			}
294 		}
295 	}
296 	return false;
297 }
test_dissolve_cu(MathStructure & mstruct,Unit * u,bool convert_nonlinear_relations,bool * found_nonlinear_relations,bool calculate_new_functions,const EvaluationOptions & feo,Prefix * new_prefix=NULL)298 bool test_dissolve_cu(MathStructure &mstruct, Unit *u, bool convert_nonlinear_relations, bool *found_nonlinear_relations, bool calculate_new_functions, const EvaluationOptions &feo, Prefix *new_prefix = NULL) {
299 	if(mstruct.isUnit()) {
300 		if(mstruct.unit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
301 			if(((CompositeUnit*) mstruct.unit())->containsRelativeTo(u)) {
302 				mstruct.set(((CompositeUnit*) mstruct.unit())->generateMathStructure());
303 				return true;
304 			}
305 		} else if(mstruct.unit()->subtype() == SUBTYPE_ALIAS_UNIT && mstruct.unit()->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
306 			if(((CompositeUnit*) (mstruct.unit()->baseUnit()))->containsRelativeTo(u)) {
307 				if(mstruct.convert(mstruct.unit()->baseUnit(), convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo)) {
308 					mstruct.convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
309 					return true;
310 				}
311 			}
312 		}
313 	}
314 	return false;
315 }
testCompositeUnit(Unit * u)316 bool MathStructure::testCompositeUnit(Unit *u) {
317 	if(m_type == STRUCT_UNIT) {
318 		if(o_unit->subtype() == SUBTYPE_COMPOSITE_UNIT) {
319 			if(((CompositeUnit*) o_unit)->containsRelativeTo(u)) {
320 				return true;
321 			}
322 		} else if(o_unit->subtype() == SUBTYPE_ALIAS_UNIT && o_unit->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
323 			if(((CompositeUnit*) (o_unit->baseUnit()))->containsRelativeTo(u)) {
324 				return true;
325 			}
326 		}
327 	}
328 	return false;
329 }
dissolveAllCompositeUnits()330 bool MathStructure::dissolveAllCompositeUnits() {
331 	switch(m_type) {
332 		case STRUCT_UNIT: {
333 			if(o_unit->subtype() == SUBTYPE_COMPOSITE_UNIT) {
334 				set(((CompositeUnit*) o_unit)->generateMathStructure());
335 				return true;
336 			}
337 			break;
338 		}
339 		default: {
340 			bool b = false;
341 			for(size_t i = 0; i < SIZE; i++) {
342 				if(CHILD(i).dissolveAllCompositeUnits()) {
343 					CHILD_UPDATED(i);
344 					b = true;
345 				}
346 			}
347 			return b;
348 		}
349 	}
350 	return false;
351 }
setPrefixForUnit(Unit * u,Prefix * new_prefix)352 bool MathStructure::setPrefixForUnit(Unit *u, Prefix *new_prefix) {
353 	if(m_type == STRUCT_UNIT && o_unit == u) {
354 		if(o_prefix != new_prefix) {
355 			Number new_value(1, 1);
356 			if(o_prefix) new_value = o_prefix->value();
357 			if(new_prefix) new_value.divide(new_prefix->value());
358 			o_prefix = new_prefix;
359 			multiply(new_value);
360 			return true;
361 		}
362 		return false;
363 	}
364 	bool b = false;
365 	for(size_t i = 0; i < SIZE; i++) {
366 		if(CHILD(i).setPrefixForUnit(u, new_prefix)) {
367 			CHILD_UPDATED(i);
368 			b = true;
369 		}
370 	}
371 	return b;
372 }
373 
searchSubMultiplicationsForComplexRelations(Unit * u,const MathStructure & mstruct)374 bool searchSubMultiplicationsForComplexRelations(Unit *u, const MathStructure &mstruct) {
375 	int b_c = -1;
376 	for(size_t i = 0; i < mstruct.size(); i++) {
377 		if(mstruct[i].isUnit_exp()) {
378 			if((mstruct[i].isUnit() && u->hasNonlinearRelationTo(mstruct[i].unit())) || (mstruct[i].isPower() && u->hasNonlinearRelationTo(mstruct[i][0].unit()))) {
379 				return true;
380 			}
381 		} else if(b_c == -1 && mstruct[i].isMultiplication()) {
382 			b_c = -3;
383 		}
384 	}
385 	if(b_c == -3) {
386 		for(size_t i = 0; i < mstruct.size(); i++) {
387 			if(mstruct[i].isMultiplication() && searchSubMultiplicationsForComplexRelations(u, mstruct[i])) return true;
388 		}
389 	}
390 	return false;
391 }
convertToBaseUnits(bool convert_nonlinear_relations,bool * found_nonlinear_relations,bool calculate_new_functions,const EvaluationOptions & feo,bool avoid_approximate_variables)392 bool MathStructure::convertToBaseUnits(bool convert_nonlinear_relations, bool *found_nonlinear_relations, bool calculate_new_functions, const EvaluationOptions &feo, bool avoid_approximate_variables) {
393 	if(m_type == STRUCT_UNIT) {
394 		if(o_unit->subtype() == SUBTYPE_COMPOSITE_UNIT) {
395 			set(((CompositeUnit*) o_unit)->generateMathStructure());
396 			convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables);
397 			return true;
398 		} else if(o_unit->subtype() == SUBTYPE_ALIAS_UNIT) {
399 			AliasUnit *au = (AliasUnit*) o_unit;
400 			if(au->hasNonlinearRelationTo(au->baseUnit())) {
401 				if(found_nonlinear_relations) *found_nonlinear_relations = true;
402 				if(!convert_nonlinear_relations) {
403 					if(!au->hasNonlinearExpression() && ((feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES) || !au->hasApproximateExpression(avoid_approximate_variables, false))) {
404 						MathStructure mstruct_old(*this);
405 						if(convert(au->firstBaseUnit(), false, NULL, calculate_new_functions, feo) && !equals(mstruct_old)) {
406 							convertToBaseUnits(false, NULL, calculate_new_functions, feo, avoid_approximate_variables);
407 							return true;
408 						}
409 					}
410 					return false;
411 				}
412 			}
413 			if((feo.approximation == APPROXIMATION_EXACT || feo.approximation == APPROXIMATION_EXACT_VARIABLES) && au->hasApproximateRelationTo(au->baseUnit(), avoid_approximate_variables, false)) {
414 				MathStructure mstruct_old(*this);
415 				if(convert(au->firstBaseUnit(), false, NULL, calculate_new_functions, feo) && !equals(mstruct_old)) {
416 					convertToBaseUnits(false, NULL, calculate_new_functions, feo, avoid_approximate_variables);
417 					return true;
418 				}
419 				return false;
420 			}
421 			if(convert(au->baseUnit(), convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo)) {
422 				convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables);
423 				return true;
424 			}
425 		}
426 		return false;
427 	} else if(m_type == STRUCT_MULTIPLICATION && (convert_nonlinear_relations || found_nonlinear_relations)) {
428 		AliasUnit *complex_au = NULL;
429 		if(convert_nonlinear_relations && convertToBaseUnits(false, NULL, calculate_new_functions, feo, avoid_approximate_variables)) {
430 			convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables);
431 			return true;
432 		}
433 		for(size_t i = 0; i < SIZE; i++) {
434 			if(CALCULATOR->aborted()) return false;
435 			if(CHILD(i).isUnit_exp() && CHILD(i).unit_exp_unit()->subtype() == SUBTYPE_ALIAS_UNIT) {
436 				AliasUnit *au = (AliasUnit*) CHILD(i).unit_exp_unit();
437 				if(au && au->hasNonlinearRelationTo(au->baseUnit())) {
438 					if(found_nonlinear_relations) {
439 						*found_nonlinear_relations = true;
440 					}
441 					if(convert_nonlinear_relations) {
442 						if(complex_au) {
443 							complex_au = NULL;
444 							convert_nonlinear_relations = false;
445 							break;
446 						} else {
447 							complex_au = au;
448 						}
449 					} else {
450 						break;
451 					}
452 				}
453 			}
454 		}
455 		if(convert_nonlinear_relations && complex_au && ((feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES) || !complex_au->hasApproximateExpression(avoid_approximate_variables, false))) {
456 			MathStructure mstruct_old(*this);
457 			if(convert(complex_au->firstBaseUnit(), true, NULL, calculate_new_functions, feo) && !equals(mstruct_old)) {
458 				convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables);
459 				return true;
460 			}
461 		}
462 	} else if(m_type == STRUCT_FUNCTION) {
463 		if(o_function->id() == FUNCTION_ID_STRIP_UNITS) return false;
464 		bool b = false;
465 		for(size_t i = 0; i < SIZE; i++) {
466 			if(CALCULATOR->aborted()) return b;
467 			if((!o_function->getArgumentDefinition(i + 1) || o_function->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) && CHILD(i).convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables)) {
468 				CHILD_UPDATED(i);
469 				b = true;
470 			}
471 		}
472 		return b;
473 	}
474 	bool b = false;
475 	for(size_t i = 0; i < SIZE; i++) {
476 		if(CALCULATOR->aborted()) return b;
477 		if(CHILD(i).convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, avoid_approximate_variables)) {
478 			CHILD_UPDATED(i);
479 			b = true;
480 		}
481 	}
482 	return b;
483 }
484 bool convert_approximate(MathStructure &m, Unit *u, const EvaluationOptions &feo, vector<KnownVariable*> *vars, vector<MathStructure> *uncs, vector<Unit*> *units, bool do_intervals);
convert_approximate(MathStructure & m,const MathStructure unit_mstruct,const EvaluationOptions & feo,vector<KnownVariable * > * vars,vector<MathStructure> * uncs,vector<Unit * > * units,bool do_intervals)485 bool convert_approximate(MathStructure &m, const MathStructure unit_mstruct, const EvaluationOptions &feo, vector<KnownVariable*> *vars, vector<MathStructure> *uncs, vector<Unit*> *units, bool do_intervals) {
486 	bool b = false;
487 	if(unit_mstruct.type() == STRUCT_UNIT) {
488 		if(convert_approximate(m, unit_mstruct.unit(), feo, vars, uncs, units, do_intervals)) b = true;
489 	} else {
490 		for(size_t i = 0; i < unit_mstruct.size(); i++) {
491 			if(convert_approximate(m, unit_mstruct[i], feo, vars, uncs, units, do_intervals)) b = true;
492 		}
493 	}
494 	return b;
495 }
test_dissolve_cu_approximate(MathStructure & mstruct,Unit * u,const EvaluationOptions & feo,vector<KnownVariable * > * vars,vector<MathStructure> * uncs,vector<Unit * > * units,bool do_intervals)496 bool test_dissolve_cu_approximate(MathStructure &mstruct, Unit *u, const EvaluationOptions &feo, vector<KnownVariable*> *vars, vector<MathStructure> *uncs, vector<Unit*> *units, bool do_intervals) {
497 	if(mstruct.isUnit()) {
498 		if(mstruct.unit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
499 			if(((CompositeUnit*) mstruct.unit())->containsRelativeTo(u)) {
500 				mstruct.set(((CompositeUnit*) mstruct.unit())->generateMathStructure());
501 				return true;
502 			}
503 		} else if(mstruct.unit()->subtype() == SUBTYPE_ALIAS_UNIT && mstruct.unit()->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
504 			if(((CompositeUnit*) (mstruct.unit()->baseUnit()))->containsRelativeTo(u)) {
505 				if(convert_approximate(mstruct, mstruct.unit()->baseUnit(), feo, vars, uncs, units, do_intervals)) {
506 					convert_approximate(mstruct, u, feo, vars, uncs, units, do_intervals);
507 					return true;
508 				}
509 			}
510 		}
511 	}
512 	return false;
513 }
convert_approximate(MathStructure & m,Unit * u,const EvaluationOptions & feo,vector<KnownVariable * > * vars,vector<MathStructure> * uncs,vector<Unit * > * units,bool do_intervals)514 bool convert_approximate(MathStructure &m, Unit *u, const EvaluationOptions &feo, vector<KnownVariable*> *vars, vector<MathStructure> *uncs, vector<Unit*> *units, bool do_intervals) {
515 	bool b = false;
516 	if(m.type() == STRUCT_UNIT && (m.unit() == u || m.prefix())) {
517 		return false;
518 	}
519 	if(u->subtype() == SUBTYPE_COMPOSITE_UNIT && !(m.type() == STRUCT_UNIT && m.unit()->baseUnit() == u)) {
520 		return convert_approximate(m, ((CompositeUnit*) u)->generateMathStructure(false, true), feo, vars, uncs, units, do_intervals);
521 	}
522 	if(m.type() == STRUCT_UNIT) {
523 		if(u->hasApproximateRelationTo(m.unit(), feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES, true) || u->hasNonlinearRelationTo(m.unit())) {
524 			return false;
525 		}
526 		if(!vars) return true;
527 		if(m.unit()->baseUnit() != u->baseUnit() && test_dissolve_cu_approximate(m, u, feo, vars, uncs, units, do_intervals)) {
528 			convert_approximate(m, u, feo, vars, uncs, units, do_intervals);
529 			return true;
530 		}
531 		MathStructure *exp = new MathStructure(1, 1, 0);
532 		MathStructure *mstruct = new MathStructure(1, 1, 0);
533 		Unit *u_m = m.unit();
534 		if(u_m->subtype() == SUBTYPE_ALIAS_UNIT && do_intervals) {
535 			for(size_t i = 0; i < units->size(); i++) {
536 				if((*units)[i] == u_m) {
537 					mstruct->set((*vars)[i]);
538 					u_m = ((AliasUnit*) u_m)->firstBaseUnit();
539 				}
540 			}
541 			if(u_m == m.unit()) {
542 				((AliasUnit*) u_m)->convertToFirstBaseUnit(*mstruct, *exp);
543 				if(mstruct->isNumber() && mstruct->number().isInterval()) {
544 					uncs->push_back(mstruct->number().uncertainty());
545 					units->push_back(u_m);
546 					Number nmid(mstruct->number());
547 					nmid.intervalToMidValue();
548 					nmid.setApproximate(false);
549 					KnownVariable *v = new KnownVariable("", string("(") + format_and_print(nmid) + ")", nmid);
550 					mstruct->set(v);
551 					vars->push_back(v);
552 					v->destroy();
553 					u_m = ((AliasUnit*) u_m)->firstBaseUnit();
554 				} else {
555 					mstruct->set(1, 1, 0);
556 					exp->set(1, 1, 0);
557 				}
558 			}
559 		}
560 		if(u->convert(u_m, *mstruct, *exp) && (do_intervals || (!mstruct->containsInterval(true, false, false, 1, true) && !exp->containsInterval(true, false, false, 1, true)))) {
561 			m.setUnit(u);
562 			if(!exp->isOne()) {
563 				if(feo.calculate_functions) {
564 					calculate_nondifferentiable_functions(*exp, feo, true, true, feo.interval_calculation != INTERVAL_CALCULATION_VARIANCE_FORMULA ? 0 : ((feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES) ? 2 : 1));
565 				}
566 				if(do_intervals) exp->calculatesub(feo, feo, true);
567 				m.raise_nocopy(exp);
568 			} else {
569 				exp->unref();
570 			}
571 			if(!mstruct->isOne()) {
572 				if(feo.calculate_functions) {
573 					calculate_nondifferentiable_functions(*mstruct, feo, true, true, feo.interval_calculation != INTERVAL_CALCULATION_VARIANCE_FORMULA ? 0 : ((feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES) ? 2 : 1));
574 				}
575 				if(do_intervals) mstruct->calculatesub(feo, feo, true);
576 				m.multiply_nocopy(mstruct);
577 			} else {
578 				mstruct->unref();
579 			}
580 			return true;
581 		} else {
582 			exp->unref();
583 			mstruct->unref();
584 			return false;
585 		}
586 	} else {
587 		if(m.type() == STRUCT_FUNCTION) {
588 			if(m.function()->id() == FUNCTION_ID_STRIP_UNITS) return b;
589 			for(size_t i = 0; i < m.size(); i++) {
590 				if(m.size() > 100 && CALCULATOR->aborted()) return b;
591 				if((!m.function()->getArgumentDefinition(i + 1) || m.function()->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) && convert_approximate(m[i], u, feo, vars, uncs, units, do_intervals)) {
592 					m.childUpdated(i + 1);
593 					b = true;
594 				}
595 			}
596 			return b;
597 		}
598 		for(size_t i = 0; i < m.size(); i++) {
599 			if(m.size() > 100 && CALCULATOR->aborted()) return b;
600 			if(convert_approximate(m[i], u, feo, vars, uncs, units, do_intervals)) {
601 				m.childUpdated(i + 1);
602 				b = true;
603 			}
604 		}
605 		return b;
606 	}
607 	return b;
608 }
609 
contains_approximate_relation_to_base(const MathStructure & m,bool do_intervals)610 bool contains_approximate_relation_to_base(const MathStructure &m, bool do_intervals) {
611 	if(m.isUnit()) {
612 		return has_approximate_relation_to_base(m.unit(), do_intervals);
613 	} else if(m.isFunction() && m.function()->id() == FUNCTION_ID_STRIP_UNITS) {
614 		return false;
615 	}
616 	for(size_t i = 0; i < m.size(); i++) {
617 		if(contains_approximate_relation_to_base(m[i], do_intervals)) return true;
618 	}
619 	return false;
620 }
621 
sync_approximate_units(MathStructure & m,const EvaluationOptions & feo,vector<KnownVariable * > * vars,vector<MathStructure> * uncs,bool do_intervals)622 bool sync_approximate_units(MathStructure &m, const EvaluationOptions &feo, vector<KnownVariable*> *vars, vector<MathStructure> *uncs, bool do_intervals) {
623 	if(m.size() == 0) return false;
624 	if(!contains_approximate_relation_to_base(m, do_intervals)) return false;
625 	bool check_variables = (feo.approximation != APPROXIMATION_EXACT && feo.approximation != APPROXIMATION_EXACT_VARIABLES);
626 	vector<Unit*> base_units;
627 	vector<AliasUnit*> alias_units;
628 	vector<CompositeUnit*> composite_units;
629 	gatherInformation(m, base_units, alias_units, check_variables);
630 	if(alias_units.empty() || base_units.size() + alias_units.size() == 1) return false;
631 	CompositeUnit *cu;
632 	bool b = false, do_erase = false;
633 	for(size_t i = 0; i < alias_units.size(); ) {
634 		do_erase = false;
635 		if(alias_units[i]->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
636 			b = false;
637 			cu = (CompositeUnit*) alias_units[i]->baseUnit();
638 			for(size_t i2 = 0; i2 < base_units.size(); i2++) {
639 				if(cu->containsRelativeTo(base_units[i2])) {
640 					for(size_t i3 = 0; i3 < composite_units.size(); i3++) {
641 						if(composite_units[i3] == cu) {
642 							b = true;
643 							break;
644 						}
645 					}
646 					if(!b) composite_units.push_back(cu);
647 					do_erase = true;
648 					break;
649 				}
650 			}
651 			for(size_t i2 = 0; !do_erase && i2 < alias_units.size(); i2++) {
652 				if(i != i2 && alias_units[i2]->baseUnit() != cu && cu->containsRelativeTo(alias_units[i2])) {
653 					for(size_t i3 = 0; i3 < composite_units.size(); i3++) {
654 						if(composite_units[i3] == cu) {
655 							b = true;
656 							break;
657 						}
658 					}
659 					if(!b) composite_units.push_back(cu);
660 					do_erase = true;
661 					break;
662 				}
663 			}
664 		}
665 		if(do_erase) {
666 			alias_units.erase(alias_units.begin() + i);
667 			for(int i2 = 1; i2 <= (int) cu->countUnits(); i2++) {
668 				b = false;
669 				Unit *cub = cu->get(i2);
670 				switch(cub->subtype()) {
671 					case SUBTYPE_BASE_UNIT: {
672 						for(size_t i3 = 0; i3 < base_units.size(); i3++) {
673 							if(base_units[i3] == cub) {
674 								b = true;
675 								break;
676 							}
677 						}
678 						if(!b) base_units.push_back(cub);
679 						break;
680 					}
681 					case SUBTYPE_ALIAS_UNIT: {
682 						for(size_t i3 = 0; i3 < alias_units.size(); i3++) {
683 							if(alias_units[i3] == cub) {
684 								b = true;
685 								break;
686 							}
687 						}
688 						if(!b) alias_units.push_back((AliasUnit*) cub);
689 						break;
690 					}
691 					case SUBTYPE_COMPOSITE_UNIT: {
692 						gatherInformation(((CompositeUnit*) cub)->generateMathStructure(), base_units, alias_units, check_variables);
693 						break;
694 					}
695 				}
696 			}
697 			i = 0;
698 		} else {
699 			i++;
700 		}
701 	}
702 
703 	for(size_t i = 0; i < alias_units.size();) {
704 		do_erase = false;
705 		for(size_t i2 = 0; i2 < alias_units.size(); i2++) {
706 			if(i != i2 && alias_units[i]->baseUnit() == alias_units[i2]->baseUnit()) {
707 				if(alias_units[i2]->isParentOf(alias_units[i])) {
708 					do_erase = true;
709 					break;
710 				} else if(!alias_units[i]->isParentOf(alias_units[i2])) {
711 					b = false;
712 					for(size_t i3 = 0; i3 < base_units.size(); i3++) {
713 						if(base_units[i3] == alias_units[i2]->firstBaseUnit()) {
714 							b = true;
715 							break;
716 						}
717 					}
718 					if(!b) base_units.push_back((Unit*) alias_units[i]->baseUnit());
719 					do_erase = true;
720 					break;
721 				}
722 			}
723 		}
724 		if(do_erase) {
725 			alias_units.erase(alias_units.begin() + i);
726 			i = 0;
727 		} else {
728 			i++;
729 		}
730 	}
731 	for(size_t i = 0; i < alias_units.size();) {
732 		do_erase = false;
733 		if(alias_units[i]->baseUnit()->subtype() == SUBTYPE_BASE_UNIT) {
734 			for(size_t i2 = 0; i2 < base_units.size(); i2++) {
735 				if(alias_units[i]->baseUnit() == base_units[i2]) {
736 					do_erase = true;
737 					break;
738 				}
739 			}
740 		}
741 		if(do_erase) {
742 			alias_units.erase(alias_units.begin() + i);
743 			i = 0;
744 		} else {
745 			i++;
746 		}
747 	}
748 	b = false;
749 	vector<Unit*> units;
750 	for(size_t i = 0; i < composite_units.size(); i++) {
751 		if(convert_approximate(m, composite_units[i], feo, vars, uncs, &units, do_intervals)) b = true;
752 	}
753 	if(m.dissolveAllCompositeUnits()) b = true;
754 	for(size_t i = 0; i < base_units.size(); i++) {
755 		if(convert_approximate(m, base_units[i], feo, vars, uncs, &units, do_intervals)) b = true;
756 	}
757 	for(size_t i = 0; i < alias_units.size(); i++) {
758 		if(convert_approximate(m, alias_units[i], feo, vars, uncs, &units, do_intervals)) b = true;
759 	}
760 	return b;
761 }
762 
763 
convert(Unit * u,bool convert_nonlinear_relations,bool * found_nonlinear_relations,bool calculate_new_functions,const EvaluationOptions & feo,Prefix * new_prefix)764 bool MathStructure::convert(Unit *u, bool convert_nonlinear_relations, bool *found_nonlinear_relations, bool calculate_new_functions, const EvaluationOptions &feo, Prefix *new_prefix) {
765 	if(m_type == STRUCT_ADDITION && containsType(STRUCT_DATETIME, false, true, false) > 0) return false;
766 	bool b = false;
767 	if(m_type == STRUCT_UNIT && o_unit == u) {
768 		if((new_prefix || o_prefix) && o_prefix != new_prefix) {
769 			Number new_value(1, 1);
770 			if(o_prefix) new_value = o_prefix->value();
771 			if(new_prefix) new_value.divide(new_prefix->value());
772 			o_prefix = new_prefix;
773 			multiply(new_value);
774 			return true;
775 		}
776 		return false;
777 	}
778 	if(u->subtype() == SUBTYPE_COMPOSITE_UNIT && !(m_type == STRUCT_UNIT && o_unit->baseUnit() == u)) {
779 		return convert(((CompositeUnit*) u)->generateMathStructure(false, true), convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo);
780 	}
781 	if(m_type == STRUCT_UNIT) {
782 		if(u->hasNonlinearRelationTo(o_unit)) {
783 			if(found_nonlinear_relations) *found_nonlinear_relations = true;
784 			if(!convert_nonlinear_relations) return false;
785 		}
786 		if(o_unit->baseUnit() != u->baseUnit() && test_dissolve_cu(*this, u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix)) {
787 			convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
788 			return true;
789 		}
790 		MathStructure *exp = new MathStructure(1, 1, 0);
791 		MathStructure *mstruct = new MathStructure(1, 1, 0);
792 		if(o_prefix) {
793 			mstruct->set(o_prefix->value());
794 		}
795 		if(u->convert(o_unit, *mstruct, *exp) && (feo.approximation != APPROXIMATION_EXACT || (!mstruct->isApproximate() && !exp->isApproximate()))) {
796 			setUnit(u);
797 			o_prefix = new_prefix;
798 			if(new_prefix) {
799 				divide(new_prefix->value());
800 			}
801 			if(!exp->isOne()) {
802 				if(calculate_new_functions) exp->calculateFunctions(feo, true, false);
803 				raise_nocopy(exp);
804 			} else {
805 				exp->unref();
806 			}
807 			if(!mstruct->isOne()) {
808 				if(calculate_new_functions) mstruct->calculateFunctions(feo, true, false);
809 				multiply_nocopy(mstruct);
810 			} else {
811 				mstruct->unref();
812 			}
813 			return true;
814 		} else {
815 			exp->unref();
816 			mstruct->unref();
817 			return false;
818 		}
819 	} else {
820 		if(convert_nonlinear_relations || found_nonlinear_relations) {
821 			if(m_type == STRUCT_MULTIPLICATION) {
822 				long int b_c = -1;
823 				for(size_t i = 0; i < SIZE; i++) {
824 					if(CHILD(i).isUnit_exp()) {
825 						Unit *u2 = CHILD(i).isPower() ? CHILD(i)[0].unit() : CHILD(i).unit();
826 						if(u->hasNonlinearRelationTo(u2)) {
827 							if(found_nonlinear_relations) *found_nonlinear_relations = true;
828 
829 							b_c = i;
830 							break;
831 						}
832 					} else if(CHILD(i).isMultiplication() && (CALCULATOR->getTemperatureCalculationMode() == TEMPERATURE_CALCULATION_RELATIVE || u->baseUnit() != CALCULATOR->getUnitById(UNIT_ID_KELVIN))) {
833 						b_c = -3;
834 					}
835 				}
836 				if(b_c == -3) {
837 					for(size_t i = 0; i < SIZE; i++) {
838 						if(CHILD(i).isMultiplication()) {
839 							if(searchSubMultiplicationsForComplexRelations(u, CHILD(i))) {
840 								if(!convert_nonlinear_relations) {
841 									*found_nonlinear_relations = true;
842 									break;
843 								}
844 								flattenMultiplication(*this);
845 								return convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
846 							}
847 						}
848 					}
849 				}
850 				if(convert_nonlinear_relations && b_c >= 0) {
851 					if((CALCULATOR->getTemperatureCalculationMode() == TEMPERATURE_CALCULATION_RELATIVE || u->baseUnit() != CALCULATOR->getUnitById(UNIT_ID_KELVIN)) && flattenMultiplication(*this)) return convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
852 					MathStructure mstruct(1, 1);
853 					MathStructure mstruct2(1, 1);
854 					if(SIZE == 2) {
855 						if(b_c == 0) mstruct = CHILD(1);
856 						else mstruct = CHILD(0);
857 						if(mstruct.containsType(STRUCT_UNIT, false, true, true) > 0) {
858 							mstruct2 = mstruct;
859 							mstruct.set(1, 1, 0);
860 						}
861 					} else if(SIZE > 2) {
862 						mstruct = *this;
863 						size_t nr_of_del = 0;
864 						for(size_t i = 0; i < SIZE; i++) {
865 							if(CHILD(i).containsType(STRUCT_UNIT, false, true, true) > 0) {
866 								mstruct.delChild(i + 1 - nr_of_del);
867 								nr_of_del++;
868 								if((long int) i != b_c) {
869 									if(mstruct2.isOne()) mstruct2 = CHILD(i);
870 									else mstruct2.multiply(CHILD(i), true);
871 								}
872 							}
873 						}
874 						if(mstruct.size() == 1) mstruct.setToChild(1);
875 						else if(mstruct.size() == 0) mstruct.set(1, 1, 0);
876 					}
877 					MathStructure exp(1, 1);
878 					Unit *u2;
879 					bool b_p = false;
880 					if(CHILD(b_c).isPower()) {
881 						if(CHILD(b_c)[0].unit()->baseUnit() != u->baseUnit()) {
882 							if(CHILD(b_c)[0].unit()->subtype() != SUBTYPE_BASE_UNIT && (CHILD(b_c)[0].unit()->subtype() != SUBTYPE_ALIAS_UNIT || ((AliasUnit*) CHILD(b_c)[0].unit())->firstBaseUnit()->subtype() != SUBTYPE_COMPOSITE_UNIT)) {
883 								convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo);
884 							} else {
885 								return false;
886 							}
887 							convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
888 							return true;
889 						}
890 						exp = CHILD(b_c)[1];
891 						u2 = CHILD(b_c)[0].unit();
892 						if(CHILD(b_c)[0].prefix() && CHILD(b_c)[0].prefix() != CALCULATOR->getDecimalNullPrefix() && CHILD(b_c)[0].prefix() != CALCULATOR->getBinaryNullPrefix()) b_p = true;
893 					} else {
894 						if(CHILD(b_c).unit()->baseUnit() != u->baseUnit()) {
895 							if(CHILD(b_c).unit()->subtype() != SUBTYPE_BASE_UNIT && (CHILD(b_c).unit()->subtype() != SUBTYPE_ALIAS_UNIT || ((AliasUnit*) CHILD(b_c).unit())->firstBaseUnit()->subtype() != SUBTYPE_COMPOSITE_UNIT)) {
896 								convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo);
897 							} else {
898 								return false;
899 							}
900 							convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
901 							return true;
902 						}
903 						u2 = CHILD(b_c).unit();
904 						if(CHILD(b_c).prefix() && CHILD(b_c).prefix() != CALCULATOR->getDecimalNullPrefix() && CHILD(b_c).prefix() != CALCULATOR->getBinaryNullPrefix()) b_p = true;
905 					}
906 					size_t efc = 0, mfc = 0;
907 					if(calculate_new_functions) {
908 						efc = exp.countFunctions();
909 						mfc = mstruct.countFunctions();
910 					}
911 					Unit *u1 = u;
912 					if((!mstruct2.isOne() || !exp.isOne()) && (CALCULATOR->getTemperatureCalculationMode() == TEMPERATURE_CALCULATION_RELATIVE && u->baseUnit() == CALCULATOR->getUnitById(UNIT_ID_KELVIN))) {
913 						if(u2 == CALCULATOR->getUnitById(UNIT_ID_CELSIUS)) u2 = CALCULATOR->getUnitById(UNIT_ID_KELVIN);
914 						else if(u2 == CALCULATOR->getUnitById(UNIT_ID_FAHRENHEIT) && CALCULATOR->getUnitById(UNIT_ID_RANKINE)) u2 = CALCULATOR->getUnitById(UNIT_ID_RANKINE);
915 						if(u1 == CALCULATOR->getUnitById(UNIT_ID_CELSIUS)) u1 = CALCULATOR->getUnitById(UNIT_ID_KELVIN);
916 						else if(u1 == CALCULATOR->getUnitById(UNIT_ID_FAHRENHEIT) && CALCULATOR->getUnitById(UNIT_ID_RANKINE)) u1 = CALCULATOR->getUnitById(UNIT_ID_RANKINE);
917 					}
918 					if(u1->convert(u2, mstruct, exp)) {
919 						if(feo.approximation == APPROXIMATION_EXACT && !isApproximate() && (mstruct.isApproximate() || exp.isApproximate())) return false;
920 						if(b_p) {
921 							EvaluationOptions eo = feo;
922 							eo.keep_prefixes = false;
923 							unformat(eo);
924 							return convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
925 						}
926 						set(u);
927 						if(!exp.isOne()) {
928 							if(calculate_new_functions && exp.countFunctions() > efc) exp.calculateFunctions(feo, true, false);
929 							raise(exp);
930 						}
931 						if(!mstruct2.isOne()) {
932 							multiply(mstruct2);
933 						}
934 						if(!mstruct.isOne()) {
935 							if(calculate_new_functions && mstruct.countFunctions() > mfc) mstruct.calculateFunctions(feo, true, false);
936 							multiply(mstruct);
937 						}
938 						if(u->baseUnit() != CALCULATOR->getUnitById(UNIT_ID_KELVIN)) convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
939 						return true;
940 					}
941 					return false;
942 				}
943 			} else if(m_type == STRUCT_POWER) {
944 				if(CHILD(0).isUnit() && u->hasNonlinearRelationTo(CHILD(0).unit())) {
945 					if(found_nonlinear_relations) *found_nonlinear_relations = true;
946 					if(convert_nonlinear_relations) {
947 						if(CHILD(0).unit()->baseUnit() != u->baseUnit()) {
948 							if(CHILD(0).unit()->subtype() != SUBTYPE_BASE_UNIT && (CHILD(0).unit()->subtype() != SUBTYPE_ALIAS_UNIT || ((AliasUnit*) CHILD(0).unit())->firstBaseUnit()->subtype() != SUBTYPE_COMPOSITE_UNIT)) {
949 								convertToBaseUnits(convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo);
950 							} else {
951 								return false;
952 							}
953 							convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix);
954 							return true;
955 						}
956 						MathStructure exp(CHILD(1));
957 						MathStructure mstruct(1, 1);
958 						if(CHILD(0).prefix()) {
959 							mstruct.set(CHILD(0).prefix()->value());
960 							mstruct.raise(exp);
961 						}
962 						size_t efc = 0;
963 						if(calculate_new_functions) {
964 							efc = exp.countFunctions();
965 						}
966 						if(u->convert(CHILD(0).unit(), mstruct, exp)) {
967 							if(feo.approximation == APPROXIMATION_EXACT && !isApproximate() && (mstruct.isApproximate() || exp.isApproximate())) return false;
968 							set(u);
969 							if(!exp.isOne()) {
970 								if(calculate_new_functions && exp.countFunctions() > efc) exp.calculateFunctions(feo, true, false);
971 								raise(exp);
972 							}
973 							if(!mstruct.isOne()) {
974 								if(calculate_new_functions) mstruct.calculateFunctions(feo, true, false);
975 								multiply(mstruct);
976 							}
977 							return true;
978 						}
979 						return false;
980 					}
981 				}
982 			}
983 		}
984 		if(m_type == STRUCT_FUNCTION) {
985 			if(o_function->id() == FUNCTION_ID_STRIP_UNITS) return b;
986 			for(size_t i = 0; i < SIZE; i++) {
987 				if(CALCULATOR->aborted()) return b;
988 				if((!o_function->getArgumentDefinition(i + 1) || o_function->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) && CHILD(i).convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix)) {
989 					CHILD_UPDATED(i);
990 					b = true;
991 				}
992 			}
993 			return b;
994 		}
995 		for(size_t i = 0; i < SIZE; i++) {
996 			if(CALCULATOR->aborted()) return b;
997 			if(CHILD(i).convert(u, convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, new_prefix)) {
998 				CHILD_UPDATED(i);
999 				b = true;
1000 			}
1001 		}
1002 		return b;
1003 	}
1004 	return b;
1005 }
convert(const MathStructure unit_mstruct,bool convert_nonlinear_relations,bool * found_nonlinear_relations,bool calculate_new_functions,const EvaluationOptions & feo)1006 bool MathStructure::convert(const MathStructure unit_mstruct, bool convert_nonlinear_relations, bool *found_nonlinear_relations, bool calculate_new_functions, const EvaluationOptions &feo) {
1007 	bool b = false;
1008 	if(unit_mstruct.type() == STRUCT_UNIT) {
1009 		if(convert(unit_mstruct.unit(), convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo, feo.keep_prefixes ? unit_mstruct.prefix() : NULL)) b = true;
1010 	} else {
1011 		for(size_t i = 0; i < unit_mstruct.size(); i++) {
1012 			if(convert(unit_mstruct[i], convert_nonlinear_relations, found_nonlinear_relations, calculate_new_functions, feo)) b = true;
1013 		}
1014 	}
1015 	return b;
1016 }
1017 
1018