Numworks Epsilon  1.4.1
Graphing Calculator Operating System
matrix.cpp
Go to the documentation of this file.
1 extern "C" {
2 #include <assert.h>
3 #include <stdlib.h>
4 }
5 #include <poincare/matrix.h>
6 #include <poincare/complex.h>
7 #include <poincare/addition.h>
8 #include <poincare/decimal.h>
9 #include <poincare/undefined.h>
10 #include "layout/grid_layout.h"
11 #include "layout/bracket_layout.h"
12 #include <cmath>
13 #include <float.h>
14 #include <string.h>
15 
16 namespace Poincare {
17 
18 Matrix::Matrix(MatrixData * matrixData) :
20 {
21  assert(matrixData != nullptr);
22  m_numberOfOperands = matrixData->numberOfRows()*matrixData->numberOfColumns();
23  m_numberOfRows = matrixData->numberOfRows();
24  matrixData->pilferOperands(&m_operands);
25  for (int i = 0; i < m_numberOfOperands; i++) {
26  const_cast<Expression *>(m_operands[i])->setParent(this);
27  }
28 }
29 
30 Matrix::Matrix(const Expression * const * operands, int numberOfRows, int numberOfColumns, bool cloneOperands) :
31  DynamicHierarchy(operands, numberOfRows*numberOfColumns, cloneOperands),
32  m_numberOfRows(numberOfRows)
33 {
34 }
35 
36 int Matrix::numberOfRows() const {
37  return m_numberOfRows;
38 }
39 
41  return numberOfOperands()/m_numberOfRows;
42 }
43 
45  return Type::Matrix;
46 }
47 
49  return new Matrix(m_operands, numberOfRows(), numberOfColumns(), true);
50 }
51 
52 int Matrix::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
53  if (bufferSize == 0) {
54  return -1;
55  }
56  buffer[bufferSize-1] = 0;
57  int currentChar = 0;
58  if (currentChar >= bufferSize-1) {
59  return 0;
60  }
61  buffer[currentChar++] = '[';
62  if (currentChar >= bufferSize-1) {
63  return currentChar;
64  }
65  for (int i = 0; i < numberOfRows(); i++) {
66  buffer[currentChar++] = '[';
67  if (currentChar >= bufferSize-1) {
68  return currentChar;
69  }
70  currentChar += operand(i*numberOfColumns())->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, numberOfSignificantDigits);
71  if (currentChar >= bufferSize-1) {
72  return currentChar;
73  }
74  for (int j = 1; j < numberOfColumns(); j++) {
75  buffer[currentChar++] = ',';
76  if (currentChar >= bufferSize-1) {
77  return currentChar;
78  }
79  currentChar += operand(i*numberOfColumns()+j)->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, numberOfSignificantDigits);
80  if (currentChar >= bufferSize-1) {
81  return currentChar;
82  }
83  }
84  currentChar = strlen(buffer);
85  if (currentChar >= bufferSize-1) {
86  return currentChar;
87  }
88  buffer[currentChar++] = ']';
89  if (currentChar >= bufferSize-1) {
90  return currentChar;
91  }
92  }
93  buffer[currentChar++] = ']';
94  buffer[currentChar] = 0;
95  return currentChar;
96 }
97 
98 int Matrix::polynomialDegree(char symbolName) const {
99  return -1;
100 }
101 
102 ExpressionLayout * Matrix::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const {
103  assert(floatDisplayMode != PrintFloat::Mode::Default);
104  assert(complexFormat != ComplexFormat::Default);
105  ExpressionLayout ** childrenLayouts = new ExpressionLayout * [numberOfOperands()];
106  for (int i = 0; i < numberOfOperands(); i++) {
107  childrenLayouts[i] = operand(i)->createLayout(floatDisplayMode, complexFormat);
108  }
109  ExpressionLayout * layout = new BracketLayout(new GridLayout(childrenLayouts, numberOfRows(), numberOfColumns()));
110  delete [] childrenLayouts;
111  return layout;
112 }
113 
114 template<typename T>
116  if (numberOfRows() != numberOfColumns()) {
117  return new Complex<T>(Complex<T>::Float(NAN));
118  }
119  int dim = numberOfRows();
121  for (int i = 0; i < dim; i++) {
122  assert(operand(i*dim+i)->type() == Type::Complex);
123  c = Addition::compute(c, *(static_cast<const Complex<T> *>(operand(i*dim+i))));
124  }
125  return new Complex<T>(c);
126 }
127 
128 // TODO: 1. implement determinant/inverse for complex matrix
129 // TODO: 2. implement determinant/inverse for any expression (do not evaluate first)
130 template<typename T>
132  if (numberOfRows() != numberOfColumns()) {
133  return new Complex<T>(Complex<T>::Float(NAN));
134  }
135  int dim = numberOfRows();
136  T ** tempMat = new T*[dim];
137  for (int i = 0; i < dim; i++) {
138  tempMat[i] = new T[dim];
139  }
140  T det = 1;
141  /* Copy the matrix */
142  for (int i = 0; i < dim; i++) {
143  for (int j = 0; j < dim; j++) {
144  const Expression * op = operand(i*dim+j);
145  assert(op->type() == Type::Complex);
146  tempMat[i][j] = static_cast<const Complex<T> *>(op)->toScalar(); // TODO: keep complex
147  }
148  }
149 
150  /* Main Loop: Gauss pivot */
151  for (int i = 0; i < dim-1; i++) {
152  /* Search for pivot */
153  int rowWithPivot = i;
154  for (int row = i+1; row < dim; row++) {
155  if (std::fabs(tempMat[rowWithPivot][i]) < std::fabs(tempMat[row][i])) {
156  rowWithPivot = row;
157  }
158  }
159  T valuePivot = tempMat[rowWithPivot][i];
160  /* if the pivot is null, det = 0. */
161  if (std::fabs(valuePivot) <= (sizeof(T) == sizeof(float) ? FLT_EPSILON : DBL_EPSILON)) {
162  for (int i = 0; i < dim; i++) {
163  delete[] tempMat[i];
164  }
165  delete[] tempMat;
166  return new Complex<T>(Complex<T>::Float(0.0));
167  }
168  /* Switch rows to have the pivot row as first row */
169  if (rowWithPivot != i) {
170  for (int col = i; col < dim; col++) {
171  T temp = tempMat[i][col];
172  tempMat[i][col] = tempMat[rowWithPivot][col];
173  tempMat[rowWithPivot][col] = temp;
174  }
175  det *= -1;
176  }
177  det *= valuePivot;
178  /* Set to 0 all A[][i] by linear combination */
179  for (int row = i+1; row < dim; row++) {
180  T factor = tempMat[row][i]/valuePivot;
181  for (int col = i; col < dim; col++) {
182  tempMat[row][col] -= factor*tempMat[i][col];
183  }
184  }
185  }
186  det *= tempMat[dim-1][dim-1];
187  for (int i = 0; i < dim; i++) {
188  delete[] tempMat[i];
189  }
190  delete[] tempMat;
191  return new Complex<T>(Complex<T>::Float(det));
192 }
193 
194 template<typename T>
196  if (numberOfRows() != numberOfColumns()) {
197  return nullptr;
198  }
199  int dim = numberOfRows();
200  /* Create the matrix inv = (A|I) with A the input matrix and I the dim identity matrix */
201  T ** inv = new T*[dim];
202  for (int i = 0; i < dim; i++) {
203  inv[i] = new T [2*dim];
204  }
205  for (int i = 0; i < dim; i++) {
206  for (int j = 0; j < dim; j++) {
207  const Expression * op = operand(i*dim+j);
208  assert(op->type() == Type::Complex);
209  inv[i][j] = static_cast<const Complex<T> *>(op)->toScalar(); // TODO: keep complex
210  }
211  for (int j = dim; j < 2*dim; j++) {
212  inv[i][j] = (i+dim == j);
213  }
214  }
215  /* Main Loop: Gauss pivot */
216  for (int i = 0; i < dim; i++) {
217  /* Search for pivot */
218  int rowWithPivot = i;
219  for (int row = i+1; row < dim; row++) {
220  if (std::fabs(inv[rowWithPivot][i]) < std::fabs(inv[row][i])) {
221  rowWithPivot = row;
222  }
223  }
224  T valuePivot = inv[rowWithPivot][i];
225  /* if the pivot is null, the matrix in not invertible. */
226  if (std::fabs(valuePivot) <= (sizeof(T) == sizeof(float) ? FLT_EPSILON : DBL_EPSILON)) {
227  for (int i = 0; i < dim; i++) {
228  delete[] inv[i];
229  }
230  delete[] inv;
231  return nullptr;
232  }
233  /* Switch rows to have the pivot row as first row */
234  if (rowWithPivot != i) {
235  for (int col = i; col < 2*dim; col++) {
236  T temp = inv[i][col];
237  inv[i][col] = inv[rowWithPivot][col];
238  inv[rowWithPivot][col] = temp;
239  }
240  }
241  /* A[pivot][] = A[pivot][]/valuePivot */
242  for (int col = 0; col < 2*dim; col++) {
243  inv[i][col] /= valuePivot;
244  }
245  /* Set to 0 all A[][row] by linear combination */
246  for (int row = 0; row < dim; row++) {
247  if (row == i) {
248  continue;
249  }
250  T factor = inv[row][i];
251  for (int col = 0; col < 2*dim; col++) {
252  inv[row][col] -= factor*inv[i][col];
253  }
254  }
255  }
256  const Expression ** operands = new const Expression * [numberOfOperands()];
257  for (int i = 0; i < dim; i++) {
258  for (int j = 0; j < dim; j++) {
259  operands[i*dim+j] = new Complex<T>(Complex<T>::Float(inv[i][j+dim]));
260  }
261  }
262  for (int i = 0; i < dim; i++) {
263  delete[] inv[i];
264  }
265  delete[] inv;
266  // Intentionally swapping dimensions for inverse, although it doesn't make a difference because it is square
267  Matrix * matrix = new Matrix(operands, numberOfColumns(), numberOfRows(), false);
268  delete[] operands;
269  return matrix;
270 }
271 
273  const Expression ** operands = new const Expression * [numberOfOperands()];
274  for (int i = 0; i < numberOfRows(); i++) {
275  for (int j = 0; j < numberOfColumns(); j++) {
277  }
278  }
279  // Intentionally swapping dimensions for transpose
280  Matrix * matrix = new Matrix(operands, numberOfColumns(), numberOfRows(), true);
281  delete[] operands;
282  return matrix;
283 }
284 
286  Expression ** operands = new Expression * [dim*dim];
287  for (int i = 0; i < dim; i++) {
288  for (int j = 0; j < dim; j++) {
289  if (i == j) {
290  operands[i*dim+j] = new Rational(1);
291  } else {
292  operands[i*dim+j] = new Rational(0);
293  }
294  }
295  }
296  Matrix * matrix = new Matrix(operands, dim, dim, false);
297  delete [] operands;
298  return matrix;
299 }
300 
301 template<typename T>
303  Expression ** operands = new Expression * [dim*dim];
304  for (int i = 0; i < dim; i++) {
305  for (int j = 0; j < dim; j++) {
306  if (i == j) {
307  operands[i*dim+j] = new Complex<T>(Complex<T>::Float(1));
308  } else {
309  operands[i*dim+j] = new Complex<T>(Complex<T>::Float(0));
310  }
311  }
312  }
313  Matrix * matrix = new Matrix(operands, dim, dim, false);
314  delete [] operands;
315  return matrix;
316 }
317 
318 template<typename T>
319 Expression * Matrix::templatedApproximate(Context& context, AngleUnit angleUnit) const {
321  for (int i = 0; i < numberOfOperands(); i++) {
322  Expression * operandEvaluation = operand(i)->approximate<T>(context, angleUnit);
323  if (operandEvaluation->type() != Type::Complex) {
325  delete operandEvaluation;
326  } else {
327  operands[i] = operandEvaluation;
328  }
329  }
330  Expression * matrix = new Matrix(operands, numberOfRows(), numberOfColumns(), false);
331  delete[] operands;
332  return matrix;
333 }
334 
335 template Matrix* Matrix::createApproximateIdentity<float>(int);
336 template Matrix* Matrix::createApproximateIdentity<double>(int);
337 template Complex<float>* Matrix::createTrace<float>() const;
338 template Complex<double>* Matrix::createTrace<double>() const;
339 template Matrix* Matrix::createInverse<float>() const;
340 template Matrix* Matrix::createInverse<double>() const;
341 template Complex<float>* Matrix::createDeterminant<float>() const;
342 template Complex<double>* Matrix::createDeterminant<double>() const;
343 }
int numberOfColumns() const
Definition: matrix.cpp:40
Matrix * createInverse() const
Definition: matrix.cpp:195
#define NAN
Definition: math.h:30
int polynomialDegree(char symbolName) const override
Definition: matrix.cpp:98
#define FLT_EPSILON
Definition: float.h:8
#define assert(e)
Definition: assert.h:9
Expression * approximate(Context &context, AngleUnit angleUnit=AngleUnit::Default) const
Definition: expression.cpp:338
int writeTextInBuffer(char *buffer, int bufferSize, int numberOfSignificantDigits=PrintFloat::k_numberOfStoredSignificantDigits) const override
Definition: matrix.cpp:52
static Matrix * createIdentity(int dim)
Definition: matrix.cpp:285
Matrix * createTranspose() const
Definition: matrix.cpp:272
#define T(x)
Definition: events.cpp:26
Matrix(MatrixData *matrixData)
Definition: matrix.cpp:18
Complex< T > * createDeterminant() const
Definition: matrix.cpp:131
Expression * clone() const override
Definition: matrix.cpp:48
const Expression ** m_operands
#define fabs(x)
Definition: math.h:178
static Complex< T > compute(const Complex< T > c, const Complex< T > d)
Definition: addition.cpp:331
#define DBL_EPSILON
Definition: float.h:11
c(generic_all_nodes)
friend class Rational
Definition: expression.h:18
size_t strlen(const char *s)
Definition: strlen.c:3
const Expression *const * operands() const override
constexpr uint8_t numberOfColumns
Definition: keyboard.h:39
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode=PrintFloat::Mode::Default, ComplexFormat complexFormat=ComplexFormat::Default) const
Definition: expression.cpp:244
int numberOfRows() const
Definition: matrix.cpp:36
static Complex< T > Float(T x)
Definition: complex.cpp:23
void setParent(Expression *parent)
Definition: expression.h:186
void pilferOperands(const Expression ***newStorageAddress)
Definition: matrix_data.cpp:61
Type type() const override
Definition: matrix.cpp:44
constexpr uint8_t numberOfRows
Definition: keyboard.h:35
int numberOfOperands() const override
Complex< T > * createTrace() const
Definition: matrix.cpp:115
const Expression * operand(int i) const
Definition: expression.cpp:78
virtual Type type() const =0
static Matrix * createApproximateIdentity(int dim)
Definition: matrix.cpp:302
virtual int writeTextInBuffer(char *buffer, int bufferSize, int numberOfSignificantDigits=PrintFloat::k_numberOfStoredSignificantDigits) const =0