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 
VectorFunction()34 VectorFunction::VectorFunction() : MathFunction("vector", -1) {
35 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)36 int VectorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
37 	mstruct = vargs;
38 	mstruct.setType(STRUCT_VECTOR);
39 	return 1;
40 }
MatrixFunction()41 MatrixFunction::MatrixFunction() : MathFunction("matrix", 3) {
42 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
43 	arg->setHandleVector(false);
44 	setArgumentDefinition(1, arg);
45 	arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
46 	arg->setHandleVector(false);
47 	setArgumentDefinition(2, arg);
48 	setArgumentDefinition(3, new VectorArgument());
49 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)50 int MatrixFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
51 	size_t rows = (size_t) vargs[0].number().uintValue();
52 	size_t columns = (size_t) vargs[1].number().uintValue();
53 	mstruct.clearMatrix(); mstruct.resizeMatrix(rows, columns, m_zero);
54 	size_t r = 1, c = 1;
55 	for(size_t i = 0; i < vargs[2].size(); i++) {
56 		if(r > rows || c > columns) {
57 			CALCULATOR->error(false, _("Too many elements (%s) for the dimensions (%sx%s) of the matrix."), i2s(vargs[2].size()).c_str(), i2s(rows).c_str(), i2s(columns).c_str(), NULL);
58 			break;
59 		}
60 		mstruct[r - 1][c - 1] = vargs[2][i];
61 		if(c == columns) {
62 			c = 1;
63 			r++;
64 		} else {
65 			c++;
66 		}
67 	}
68 	return 1;
69 }
RankFunction()70 RankFunction::RankFunction() : MathFunction("rank", 1, 2) {
71 	setArgumentDefinition(1, new VectorArgument(""));
72 	setArgumentDefinition(2, new BooleanArgument(""));
73 	setDefaultValue(2, "1");
74 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)75 int RankFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
76 	if(vargs[0].isMatrix()) {
77 		MathStructure mvector;
78 		mvector.clearVector();
79 		size_t rows = vargs[0].size(), cols = vargs[0][0].size();
80 		for(size_t i = 0; i < rows; i++) {
81 			for(size_t i2 = 0; i2 < cols; i2++) {
82 				mvector.addChild(vargs[0][i][i2]);
83 			}
84 		}
85 		if(!mvector.rankVector(vargs[1].number().getBoolean())) return 0;
86 		mstruct.clearMatrix();
87 		mstruct.resizeMatrix(rows, cols, m_zero);
88 		for(size_t i = 0; i < mvector.size(); i++) {
89 			mstruct[i / cols][i % cols] = mvector[i];
90 		}
91 		return 1;
92 	}
93 	mstruct = vargs[0];
94 	return mstruct.rankVector(vargs[1].number().getBoolean());
95 }
SortFunction()96 SortFunction::SortFunction() : MathFunction("sort", 1, 2) {
97 	setArgumentDefinition(1, new VectorArgument(""));
98 	setArgumentDefinition(2, new BooleanArgument(""));
99 	setDefaultValue(2, "1");
100 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)101 int SortFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
102 	mstruct = vargs[0];
103 	return mstruct.sortVector(vargs[1].number().getBoolean());
104 }
MergeVectorsFunction()105 MergeVectorsFunction::MergeVectorsFunction() : MathFunction("mergevectors", 1, -1) {
106 	setArgumentDefinition(1, new VectorArgument(""));
107 	setArgumentDefinition(2, new VectorArgument(""));
108 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)109 int MergeVectorsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
110 	mstruct.clearVector();
111 	for(size_t i = 0; i < vargs.size(); i++) {
112 		if(CALCULATOR->aborted()) return 0;
113 		if(vargs[i].isVector()) {
114 			for(size_t i2 = 0; i2 < vargs[i].size(); i2++) {
115 				mstruct.addChild(vargs[i][i2]);
116 			}
117 		} else {
118 			mstruct.addChild(vargs[i]);
119 		}
120 	}
121 	return 1;
122 }
MatrixToVectorFunction()123 MatrixToVectorFunction::MatrixToVectorFunction() : MathFunction("matrix2vector", 1) {
124 	setArgumentDefinition(1, new MatrixArgument());
125 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)126 int MatrixToVectorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
127 	vargs[0].matrixToVector(mstruct);
128 	return 1;
129 }
RowFunction()130 RowFunction::RowFunction() : MathFunction("row", 2) {
131 	setArgumentDefinition(1, new MatrixArgument());
132 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
133 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)134 int RowFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
135 	size_t row = (size_t) vargs[1].number().uintValue();
136 	if(row > vargs[0].rows()) {
137 		CALCULATOR->error(true, _("Row %s does not exist in matrix."), format_and_print(vargs[1]).c_str(), NULL);
138 		return 0;
139 	}
140 	vargs[0].rowToVector(row, mstruct);
141 	return 1;
142 }
ColumnFunction()143 ColumnFunction::ColumnFunction() : MathFunction("column", 2) {
144 	setArgumentDefinition(1, new MatrixArgument());
145 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
146 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)147 int ColumnFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
148 	size_t col = (size_t) vargs[1].number().uintValue();
149 	if(col > vargs[0].columns()) {
150 		CALCULATOR->error(true, _("Column %s does not exist in matrix."), format_and_print(vargs[1]).c_str(), NULL);
151 		return 0;
152 	}
153 	vargs[0].columnToVector(col, mstruct);
154 	return 1;
155 }
RowsFunction()156 RowsFunction::RowsFunction() : MathFunction("rows", 1) {
157 	setArgumentDefinition(1, new VectorArgument(""));
158 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)159 int RowsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
160 	if(!vargs[0].isMatrix()) mstruct = m_one;
161 	else mstruct = (int) vargs[0].rows();
162 	return 1;
163 }
ColumnsFunction()164 ColumnsFunction::ColumnsFunction() : MathFunction("columns", 1) {
165 	setArgumentDefinition(1, new VectorArgument(""));
166 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)167 int ColumnsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
168 	if(!vargs[0].isMatrix()) mstruct = (int) vargs[0].countChildren();
169 	else mstruct = (int) vargs[0].columns();
170 	return 1;
171 }
ElementsFunction()172 ElementsFunction::ElementsFunction() : MathFunction("elements", 1) {
173 	setArgumentDefinition(1, new VectorArgument(""));
174 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)175 int ElementsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
176 	if(vargs[0].isMatrix()) {
177 		mstruct = (int) (vargs[0].rows() * vargs[0].columns());
178 	} else {
179 		mstruct = (int) vargs[0].countChildren();
180 	}
181 	return 1;
182 }
ElementFunction()183 ElementFunction::ElementFunction() : MathFunction("element", 2, 3) {
184 	setArgumentDefinition(1, new VectorArgument(""));
185 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
186 	setArgumentDefinition(3, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SIZE));
187 	setDefaultValue(3, "0");
188 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)189 int ElementFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
190 	if(vargs[2].number().isPositive() && vargs[0].isMatrix()) {
191 		size_t row = (size_t) vargs[1].number().uintValue();
192 		size_t col = (size_t) vargs[2].number().uintValue();
193 		bool b = true;
194 		if(col > vargs[0].columns()) {
195 			CALCULATOR->error(true, _("Column %s does not exist in matrix."), format_and_print(vargs[2]).c_str(), NULL);
196 			b = false;
197 		}
198 		if(row > vargs[0].rows()) {
199 			CALCULATOR->error(true, _("Row %s does not exist in matrix."), format_and_print(vargs[1]).c_str(), NULL);
200 			b = false;
201 		}
202 		if(b) {
203 			const MathStructure *em = vargs[0].getElement(row, col);
204 			if(em) mstruct = *em;
205 			else b = false;
206 		}
207 		return b;
208 	} else {
209 		if(vargs[2].number().isGreaterThan(1)) {
210 			CALCULATOR->error(false, _("Argument 3, %s, is ignored for vectors."), getArgumentDefinition(3)->name().c_str(), NULL);
211 		}
212 		size_t row = (size_t) vargs[1].number().uintValue();
213 		if(row > vargs[0].countChildren()) {
214 			CALCULATOR->error(true, _("Element %s does not exist in vector."), format_and_print(vargs[1]).c_str(), NULL);
215 			return 0;
216 		}
217 		mstruct = *vargs[0].getChild(row);
218 		return 1;
219 	}
220 }
DimensionFunction()221 DimensionFunction::DimensionFunction() : MathFunction("dimension", 1) {
222 	setArgumentDefinition(1, new VectorArgument(""));
223 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)224 int DimensionFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
225 	mstruct = (int) vargs[0].countChildren();
226 	return 1;
227 }
ComponentFunction()228 ComponentFunction::ComponentFunction() : MathFunction("component", 2) {
229 	setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
230 	setArgumentDefinition(2, new VectorArgument(""));
231 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)232 int ComponentFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
233 	size_t i = (size_t) vargs[0].number().uintValue();
234 	if(i > vargs[1].countChildren()) {
235 		CALCULATOR->error(true, _("Element %s does not exist in vector."), format_and_print(vargs[0]).c_str(), NULL);
236 		return 0;
237 	}
238 	mstruct = *vargs[1].getChild(i);
239 	return 1;
240 }
LimitsFunction()241 LimitsFunction::LimitsFunction() : MathFunction("limits", 3) {
242 	setArgumentDefinition(1, new VectorArgument(""));
243 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SINT);
244 	arg->setHandleVector(false);
245 	setArgumentDefinition(2, arg);
246 	arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SINT);
247 	arg->setHandleVector(false);
248 	setArgumentDefinition(3, arg);
249 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)250 int LimitsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
251 	vargs[0].getRange(vargs[1].number().intValue(), vargs[2].number().intValue(), mstruct);
252 	return 1;
253 }
AreaFunction()254 AreaFunction::AreaFunction() : MathFunction("area", 5) {
255 	setArgumentDefinition(1, new MatrixArgument(""));
256 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
257 	arg->setHandleVector(false);
258 	setArgumentDefinition(2, arg);
259 	arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
260 	arg->setHandleVector(false);
261 	setArgumentDefinition(3, arg);
262 	arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
263 	arg->setHandleVector(false);
264 	setArgumentDefinition(4, arg);
265 	arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE);
266 	arg->setHandleVector(false);
267 	setArgumentDefinition(5, arg);
268 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)269 int AreaFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
270 	vargs[0].getArea(vargs[1].number().uintValue(), vargs[2].number().uintValue(), vargs[3].number().uintValue(), vargs[4].number().uintValue(), mstruct);
271 	return 1;
272 }
TransposeFunction()273 TransposeFunction::TransposeFunction() : MathFunction("transpose", 1) {
274 	setArgumentDefinition(1, new MatrixArgument());
275 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)276 int TransposeFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
277 	mstruct = vargs[0];
278 	return mstruct.transposeMatrix();
279 }
IdentityMatrixFunction()280 IdentityMatrixFunction::IdentityMatrixFunction() : MathFunction("identity", 1) {
281 	ArgumentSet *arg = new ArgumentSet();
282 	arg->addArgument(new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
283 	MatrixArgument *marg = new MatrixArgument();
284 	marg->setSquareDemanded(true);
285 	arg->addArgument(marg);
286 	setArgumentDefinition(1, arg);
287 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)288 int IdentityMatrixFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
289 	if(vargs[0].isMatrix()) {
290 		if(vargs[0].rows() != vargs[0].columns()) {
291 			return 0;
292 		}
293 		mstruct.setToIdentityMatrix(vargs[0].size());
294 	} else {
295 		mstruct.setToIdentityMatrix((size_t) vargs[0].number().uintValue());
296 	}
297 	return 1;
298 }
DeterminantFunction()299 DeterminantFunction::DeterminantFunction() : MathFunction("det", 1) {
300 	MatrixArgument *marg = new MatrixArgument();
301 	marg->setSquareDemanded(true);
302 	setArgumentDefinition(1, marg);
303 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)304 int DeterminantFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
305 	vargs[0].determinant(mstruct, eo);
306 	return !mstruct.isUndefined();
307 }
PermanentFunction()308 PermanentFunction::PermanentFunction() : MathFunction("permanent", 1) {
309 	MatrixArgument *marg = new MatrixArgument();
310 	marg->setSquareDemanded(true);
311 	setArgumentDefinition(1, marg);
312 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)313 int PermanentFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
314 	vargs[0].permanent(mstruct, eo);
315 	return !mstruct.isUndefined();
316 }
CofactorFunction()317 CofactorFunction::CofactorFunction() : MathFunction("cofactor", 3) {
318 	setArgumentDefinition(1, new MatrixArgument());
319 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
320 	setArgumentDefinition(3, new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SIZE));
321 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)322 int CofactorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
323 	vargs[0].cofactor((size_t) vargs[1].number().uintValue(), (size_t) vargs[2].number().uintValue(), mstruct, eo);
324 	return !mstruct.isUndefined();
325 }
AdjointFunction()326 AdjointFunction::AdjointFunction() : MathFunction("adj", 1) {
327 	MatrixArgument *marg = new MatrixArgument();
328 	marg->setSquareDemanded(true);
329 	setArgumentDefinition(1, marg);
330 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)331 int AdjointFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
332 	mstruct = vargs[0];
333 	if(!mstruct.adjointMatrix(eo)) return 0;
334 	return !mstruct.isUndefined();
335 }
InverseFunction()336 InverseFunction::InverseFunction() : MathFunction("inverse", 1) {
337 	MatrixArgument *marg = new MatrixArgument();
338 	marg->setSquareDemanded(true);
339 	setArgumentDefinition(1, marg);
340 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)341 int InverseFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
342 	mstruct = vargs[0];
343 	return mstruct.invertMatrix(eo);
344 }
MagnitudeFunction()345 MagnitudeFunction::MagnitudeFunction() : MathFunction("magnitude", 1) {
346 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)347 int MagnitudeFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
348 	mstruct = vargs[0];
349 	if(mstruct.isVector()) {
350 		mstruct ^= nr_two;
351 		mstruct.raise(nr_half);
352 		return 1;
353 	} else if(mstruct.representsScalar()) {
354 		mstruct.transformById(FUNCTION_ID_ABS);
355 		return 1;
356 	}
357 	mstruct.eval(eo);
358 	if(mstruct.isVector()) {
359 		mstruct ^= nr_two;
360 		mstruct.raise(nr_half);
361 		return 1;
362 	}
363 	mstruct = vargs[0];
364 	mstruct.transformById(FUNCTION_ID_ABS);
365 	return 1;
366 }
HadamardFunction()367 HadamardFunction::HadamardFunction() : MathFunction("hadamard", 1, -1) {
368 	setArgumentDefinition(1, new VectorArgument());
369 	setArgumentDefinition(2, new VectorArgument());
370 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)371 int HadamardFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
372 	bool b_matrix = vargs[0].isMatrix();
373 	for(size_t i3 = 1; i3 < vargs.size(); i3++) {
374 		if(b_matrix) {
375 			if(!vargs[i3].isMatrix() || vargs[i3].columns() != vargs[0].columns() || vargs[i3].rows() != vargs[0].rows()) {
376 				CALCULATOR->error(true, _("%s() requires that all matrices/vectors have the same dimensions."), preferredDisplayName().name.c_str(), NULL);
377 				return 0;
378 			}
379 		} else if(vargs[i3].size() != vargs[0].size()) {
380 			CALCULATOR->error(true, _("%s() requires that all matrices/vectors have the same dimensions."), preferredDisplayName().name.c_str(), NULL);
381 			return 0;
382 		}
383 	}
384 	mstruct = vargs[0];
385 	for(size_t i = 0; i < mstruct.size(); i++) {
386 		if(b_matrix) {
387 			for(size_t i2 = 0; i2 < mstruct[i].size(); i2++) {
388 				for(size_t i3 = 1; i3 < vargs.size(); i3++) mstruct[i][i2] *= vargs[i3][i][i2];
389 			}
390 		} else {
391 			for(size_t i3 = 1; i3 < vargs.size(); i3++) mstruct[i] *= vargs[i3][i];
392 		}
393 	}
394 	return 1;
395 }
matrix_to_rref(MathStructure & m,const EvaluationOptions & eo)396 bool matrix_to_rref(MathStructure &m, const EvaluationOptions &eo) {
397 	size_t rows = m.rows();
398 	size_t cols = m.columns();
399 	size_t cur_row = 0;
400 	for(size_t c = 0; c < cols; ) {
401 		bool b = false;
402 		for(size_t r = cur_row; r < rows; r++) {
403 			if(m[r][c].representsNonZero()) {
404 				if(r != cur_row) {
405 					MathStructure *mrow = &m[r];
406 					mrow->ref();
407 					m.delChild(r + 1);
408 					m.insertChild_nocopy(mrow, cur_row + 1);
409 				}
410 				for(r = 0; r < rows; r++) {
411 					if(r != cur_row) {
412 						if(m[r][c].representsNonZero()) {
413 							MathStructure mmul(m[r][c]);
414 							mmul.calculateDivide(m[cur_row][c], eo);
415 							mmul.calculateNegate(eo);
416 							for(size_t c2 = 0; c2 < cols; c2++) {
417 								if(c2 == c) {
418 									m[r][c2].clear(true);
419 								} else {
420 									MathStructure madd(m[cur_row][c2]);
421 									madd.calculateMultiply(mmul, eo);
422 									m[r][c2].calculateAdd(madd, eo);
423 								}
424 							}
425 						} else if(!m[r][c].isZero()) {
426 							return false;
427 						}
428 					}
429 				}
430 				for(size_t c2 = 0; c2 < cols; c2++) {
431 					if(c2 != c) {
432 						m[cur_row][c2].calculateDivide(m[cur_row][c], eo);
433 					}
434 				}
435 				m[cur_row][c].set(1, 1, 0, true);
436 				cur_row++;
437 				b = true;
438 				break;
439 			} else if(!m[r][c].isZero()) {
440 				return false;
441 			}
442 		}
443 		if(cur_row == rows) break;
444 		if(!b) c++;
445 	}
446 	return true;
447 }
RRefFunction()448 RRefFunction::RRefFunction() : MathFunction("rref", 1) {
449 	setArgumentDefinition(1, new MatrixArgument());
450 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)451 int RRefFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
452 	// echelon matrix
453 	MathStructure m(vargs[0]);
454 	if(!matrix_to_rref(m, eo)) return false;
455 	mstruct = m;
456 	return 1;
457 }
MatrixRankFunction()458 MatrixRankFunction::MatrixRankFunction() : MathFunction("rk", 1) {
459 	setArgumentDefinition(1, new MatrixArgument());
460 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)461 int MatrixRankFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
462 	MathStructure m(vargs[0]);
463 	if(!matrix_to_rref(m, eo)) return false;
464 	size_t rows = m.rows();
465 	size_t cols = m.columns();
466 	Number nr;
467 	// count zero rows
468 	for(size_t r = 0; r < rows; r++) {
469 		bool b = false;
470 		for(size_t c = 0; c < cols; c++) {
471 			if(m[r][c].representsNonZero()) {
472 				b = true;
473 				break;
474 			} else if(!m[r][c].isZero()) {
475 				return false;
476 			}
477 		}
478 		if(!b) break;
479 		nr++;
480 	}
481 	mstruct = nr;
482 	return 1;
483 }
EntrywiseFunction()484 EntrywiseFunction::EntrywiseFunction() : MathFunction("entrywise", 2) {
485 	VectorArgument *arg = new VectorArgument();
486 	arg->addArgument(new VectorArgument());
487 	arg->addArgument(new SymbolicArgument());
488 	arg->setReoccuringArguments(true);
489 	setArgumentDefinition(2, arg);
490 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)491 int EntrywiseFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
492 	if(vargs[1].size() == 0) {
493 		mstruct = vargs[0];
494 		return 1;
495 	}
496 	bool b_matrix = vargs[1][0].isMatrix();
497 	for(size_t i3 = 2; i3 < vargs[1].size(); i3 += 2) {
498 		if(b_matrix) {
499 			if(!vargs[1][i3].isMatrix() || vargs[1][i3].columns() != vargs[1][0].columns() || vargs[1][i3].rows() != vargs[1][0].rows()) {
500 				CALCULATOR->error(true, _("%s() requires that all matrices/vectors have the same dimensions."), preferredDisplayName().name.c_str(), NULL);
501 				return 0;
502 			}
503 		} else if(vargs[1][i3].size() != vargs[1][0].size()) {
504 			CALCULATOR->error(true, _("%s() requires that all matrices/vectors have the same dimensions."), preferredDisplayName().name.c_str(), NULL);
505 			return 0;
506 		}
507 	}
508 	MathStructure mexpr(vargs[0]);
509 	EvaluationOptions eo2 = eo;
510 	eo2.calculate_functions = false;
511 	mexpr.eval(eo2);
512 	mstruct = vargs[1][0];
513 	for(size_t i = 0; i < mstruct.size(); i++) {
514 		if(b_matrix) {
515 			for(size_t i2 = 0; i2 < mstruct[i].size(); i2++) {
516 				mstruct[i][i2] = mexpr;
517 				for(size_t i3 = 1; i3 < vargs[1].size(); i3 += 2) {
518 					mstruct[i][i2].replace(vargs[1][i3], vargs[1][i3 - 1][i][i2]);
519 				}
520 			}
521 		} else {
522 			mstruct[i] = mexpr;
523 			for(size_t i3 = 1; i3 < vargs[1].size(); i3 += 2) {
524 				mstruct[i].replace(vargs[1][i3], vargs[1][i3 - 1][i]);
525 			}
526 		}
527 	}
528 	return 1;
529 }
530 
531 bool process_replace(MathStructure &mprocess, const MathStructure &mstruct, const MathStructure &vargs, size_t index);
process_replace(MathStructure & mprocess,const MathStructure & mstruct,const MathStructure & vargs,size_t index)532 bool process_replace(MathStructure &mprocess, const MathStructure &mstruct, const MathStructure &vargs, size_t index) {
533 	if(mprocess == vargs[1]) {
534 		mprocess = mstruct[index];
535 		return true;
536 	}
537 	if(!vargs[3].isEmptySymbol() && mprocess == vargs[3]) {
538 		mprocess = (int) index + 1;
539 		return true;
540 	}
541 	if(!vargs[4].isEmptySymbol() && mprocess == vargs[4]) {
542 		mprocess = vargs[2];
543 		return true;
544 	}
545 	bool b = false;
546 	for(size_t i = 0; i < mprocess.size(); i++) {
547 		if(process_replace(mprocess[i], mstruct, vargs, index)) {
548 			mprocess.childUpdated(i + 1);
549 			b = true;
550 		}
551 	}
552 	return b;
553 }
554 
ProcessFunction()555 ProcessFunction::ProcessFunction() : MathFunction("process", 3, 5) {
556 	setArgumentDefinition(2, new SymbolicArgument());
557 	setArgumentDefinition(3, new VectorArgument());
558 	setArgumentDefinition(4, new SymbolicArgument());
559 	setDefaultValue(4, "\"\"");
560 	setArgumentDefinition(5, new SymbolicArgument());
561 	setDefaultValue(5, "\"\"");
562 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)563 int ProcessFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
564 
565 	mstruct = vargs[2];
566 	MathStructure mprocess;
567 	for(size_t index = 0; index < mstruct.size(); index++) {
568 		mprocess = vargs[0];
569 		process_replace(mprocess, mstruct, vargs, index);
570 		mstruct[index] = mprocess;
571 	}
572 	return 1;
573 
574 }
575 
576 
577 bool process_matrix_replace(MathStructure &mprocess, const MathStructure &mstruct, const MathStructure &vargs, size_t rindex, size_t cindex);
process_matrix_replace(MathStructure & mprocess,const MathStructure & mstruct,const MathStructure & vargs,size_t rindex,size_t cindex)578 bool process_matrix_replace(MathStructure &mprocess, const MathStructure &mstruct, const MathStructure &vargs, size_t rindex, size_t cindex) {
579 	if(mprocess == vargs[1]) {
580 		mprocess = mstruct[rindex][cindex];
581 		return true;
582 	}
583 	if(!vargs[3].isEmptySymbol() && mprocess == vargs[3]) {
584 		mprocess = (int) rindex + 1;
585 		return true;
586 	}
587 	if(!vargs[4].isEmptySymbol() && mprocess == vargs[4]) {
588 		mprocess = (int) cindex + 1;
589 		return true;
590 	}
591 	if(!vargs[5].isEmptySymbol() && mprocess == vargs[5]) {
592 		mprocess = vargs[2];
593 		return true;
594 	}
595 	bool b = false;
596 	for(size_t i = 0; i < mprocess.size(); i++) {
597 		if(process_matrix_replace(mprocess[i], mstruct, vargs, rindex, cindex)) {
598 			mprocess.childUpdated(i + 1);
599 			b = true;
600 		}
601 	}
602 	return b;
603 }
604 
ProcessMatrixFunction()605 ProcessMatrixFunction::ProcessMatrixFunction() : MathFunction("processm", 3, 6) {
606 	setArgumentDefinition(2, new SymbolicArgument());
607 	setArgumentDefinition(3, new MatrixArgument());
608 	setArgumentDefinition(4, new SymbolicArgument());
609 	setDefaultValue(4, "\"\"");
610 	setArgumentDefinition(5, new SymbolicArgument());
611 	setDefaultValue(5, "\"\"");
612 	setArgumentDefinition(6, new SymbolicArgument());
613 	setDefaultValue(6, "\"\"");
614 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)615 int ProcessMatrixFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
616 
617 	mstruct = vargs[2];
618 	MathStructure mprocess;
619 	for(size_t rindex = 0; rindex < mstruct.size(); rindex++) {
620 		for(size_t cindex = 0; cindex < mstruct[rindex].size(); cindex++) {
621 			if(CALCULATOR->aborted()) return 0;
622 			mprocess = vargs[0];
623 			process_matrix_replace(mprocess, mstruct, vargs, rindex, cindex);
624 			mstruct[rindex][cindex] = mprocess;
625 		}
626 	}
627 	return 1;
628 
629 }
GenerateVectorFunction()630 GenerateVectorFunction::GenerateVectorFunction() : MathFunction("genvector", 4, 6) {
631 	setArgumentDefinition(5, new SymbolicArgument());
632 	setDefaultValue(5, "undefined");
633 	setArgumentDefinition(6, new BooleanArgument());
634 	setDefaultValue(6, "0");
635 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)636 int GenerateVectorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
637 	if(CALCULATOR->aborted()) return 0;
638 	if(vargs[5].number().getBoolean()) {
639 		mstruct = vargs[0].generateVector(vargs[4], vargs[1], vargs[2], vargs[3], NULL, eo);
640 	} else {
641 		bool overflow = false;
642 		int steps = vargs[3].number().intValue(&overflow);
643 		if(!vargs[3].isNumber() || overflow || steps < 1) {
644 			CALCULATOR->error(true, _("The number of requested elements in generate vector function must be a positive integer."), NULL);
645 			return 0;
646 		}
647 		mstruct = vargs[0].generateVector(vargs[4], vargs[1], vargs[2], steps, NULL, eo);
648 	}
649 	if(CALCULATOR->aborted()) return 0;
650 	return 1;
651 }
SelectFunction()652 SelectFunction::SelectFunction() : MathFunction("select", 2, 4) {
653 	setArgumentDefinition(3, new SymbolicArgument());
654 	setDefaultValue(3, "undefined");
655 	setArgumentDefinition(4, new BooleanArgument());
656 	setDefaultValue(4, "0");
657 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)658 int SelectFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
659 	MathStructure mtest;
660 	mstruct = vargs[0];
661 	mstruct.eval(eo);
662 	if(!mstruct.isVector()) {
663 		mtest = vargs[1];
664 		mtest.replace(vargs[2], mstruct);
665 		mtest.eval(eo);
666 		if(!mtest.isNumber() || mtest.number().getBoolean() < 0) {
667 			CALCULATOR->error(true, _("Comparison failed."), NULL);
668 			return -1;
669 		}
670 		if(mtest.number().getBoolean() == 0) {
671 			if(vargs[3].number().getBoolean() > 0) {
672 				CALCULATOR->error(true, _("No matching item found."), NULL);
673 				return -1;
674 			}
675 			mstruct.clearVector();
676 		}
677 		return 1;
678 	}
679 	for(size_t i = 0; i < mstruct.size();) {
680 		mtest = vargs[1];
681 		mtest.replace(vargs[2], mstruct[i]);
682 		mtest.eval(eo);
683 		if(!mtest.isNumber() || mtest.number().getBoolean() < 0) {
684 			CALCULATOR->error(true, _("Comparison failed."), NULL);
685 			return -1;
686 		}
687 		if(mtest.number().getBoolean() == 0) {
688 			if(vargs[3].number().getBoolean() == 0) {
689 				mstruct.delChild(i + 1);
690 			} else {
691 				i++;
692 			}
693 		} else if(vargs[3].number().getBoolean() > 0) {
694 			MathStructure msave(mstruct[i]);
695 			mstruct = msave;
696 			return 1;
697 		} else {
698 			i++;
699 		}
700 	}
701 	if(vargs[3].number().getBoolean() > 0) {
702 		CALCULATOR->error(true, _("No matching item found."), NULL);
703 		return -1;
704 	}
705 	return 1;
706 }
LoadFunction()707 LoadFunction::LoadFunction() : MathFunction("load", 1, 3) {
708 	setArgumentDefinition(1, new FileArgument());
709 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE, true, true, INTEGER_TYPE_SINT);
710 	arg->setHandleVector(false);
711 	setArgumentDefinition(2, arg);
712 	setDefaultValue(2, "1");
713 	setArgumentDefinition(3, new TextArgument());
714 	setDefaultValue(3, "\",\"");
715 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)716 int LoadFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
717 	string delim = vargs[2].symbol();
718 	if(delim == "tab") {
719 		delim = "\t";
720 	}
721 	if(!CALCULATOR->importCSV(mstruct, vargs[0].symbol().c_str(), vargs[1].number().intValue(), delim)) {
722 		CALCULATOR->error(true, "Failed to load %s.", vargs[0].symbol().c_str(), NULL);
723 		return 0;
724 	}
725 	return 1;
726 }
ExportFunction()727 ExportFunction::ExportFunction() : MathFunction("export", 2, 3) {
728 	setArgumentDefinition(1, new VectorArgument());
729 	setArgumentDefinition(2, new FileArgument());
730 	setArgumentDefinition(3, new TextArgument());
731 	setDefaultValue(3, "\",\"");
732 }
calculate(MathStructure &,const MathStructure & vargs,const EvaluationOptions &)733 int ExportFunction::calculate(MathStructure&, const MathStructure &vargs, const EvaluationOptions&) {
734 	string delim = vargs[2].symbol();
735 	if(delim == "tab") {
736 		delim = "\t";
737 	}
738 	if(!CALCULATOR->exportCSV(vargs[0], vargs[1].symbol().c_str(), delim)) {
739 		CALCULATOR->error(true, "Failed to export to %s.", vargs[1].symbol().c_str(), NULL);
740 		return 0;
741 	}
742 	return 1;
743 }
744 
745