Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ObjectMatrix.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
10
12{
16 public sealed class ObjectMatrix : RingElement, IMatrix
17 {
18 private IElement[,] values;
19 private ICollection<IElement> elements;
20 private string[] columnNames = null;
21 private readonly int rows;
22 private readonly int columns;
23
29 {
30 this.values = Values;
31 this.elements = null;
32 this.rows = Values.GetLength(0);
33 this.columns = Values.GetLength(1);
34 }
35
40 public ObjectMatrix(object[,] Values)
41 {
42 int i, j, c, d;
43 IElement[,] Values2 = new IElement[c = Values.GetLength(0), d = Values.GetLength(1)];
44
45 for (i = 0; i < c; i++)
46 {
47 for (j = 0; j < d; j++)
48 Values2[i, j] = Expression.Encapsulate(Values[i, j]);
49 }
50
51 this.values = Values2;
52 this.elements = null;
53 this.rows = Values.GetLength(0);
54 this.columns = Values.GetLength(1);
55 }
56
63 public ObjectMatrix(int Rows, int Columns, ICollection<IElement> Elements)
64 {
65 this.values = null;
66 this.elements = Elements;
67 this.rows = Rows;
68 this.columns = Columns;
69 }
70
74 public IElement[,] Values
75 {
76 get
77 {
78 if (this.values is null)
79 {
80 IElement[,] v = new IElement[this.rows, this.columns];
81 int x = 0;
82 int y = 0;
83
84 foreach (IElement Element in this.elements)
85 {
86 v[y, x++] = Element;
87 if (x >= this.columns)
88 {
89 y++;
90 x = 0;
91 }
92 }
93
94 this.values = v;
95 }
96
97 return this.values;
98 }
99 }
100
104 public IElement[,] MatrixElements => this.Values;
105
109 public ICollection<IElement> Elements
110 {
111 get
112 {
113 if (this.elements is null)
114 {
115 int x, y, i = 0;
116 IElement[] v = new IElement[this.rows * this.columns];
117
118 for (y = 0; y < this.rows; y++)
119 {
120 for (x = 0; x < this.columns; x++)
121 v[i++] = this.values[y, x];
122 }
123
124 this.elements = v;
125 }
126
127 return this.elements;
128 }
129 }
130
134 public int Rows => this.rows;
135
139 public int Columns => this.columns;
140
144 public string[] ColumnNames
145 {
146 get => this.columnNames;
147 set
148 {
149 if (!(value is null) && value.Length != this.columns)
150 throw new ArgumentException("Number of columns does not match actual number of columns.", nameof(value));
151
152 this.columnNames = value;
153 }
154 }
155
159 public bool HasColumnNames => !(this.columnNames is null);
160
167 public IElement this[string ColumnName]
168 {
169 get
170 {
171 if (!(this.columnNames is null))
172 {
173 int i, c = this.columnNames.Length;
174
175 for (i = 0; i < c; i++)
176 {
177 if (string.Compare(this.columnNames[i], ColumnName, true) == 0)
178 return this.GetColumn(i);
179 }
180 }
181
182 throw new ArgumentException("No column named " + ColumnName + " found.");
183 }
184 }
185
187 public override string ToString()
188 {
189 IElement[,] v = this.Values;
190 StringBuilder sb = null;
191 bool First;
192 int x, y;
193
194 for (y = 0; y < this.rows; y++)
195 {
196 if (sb is null)
197 sb = new StringBuilder("[[");
198 else
199 sb.Append(",\r\n [");
200
201 First = true;
202 for (x = 0; x < this.columns; x++)
203 {
204 if (First)
205 First = false;
206 else
207 sb.Append(", ");
208
209 sb.Append(Expression.ToString(v[y, x]));
210 }
211
212 sb.Append(']');
213 }
214
215 if (sb is null)
216 sb = new StringBuilder("[[]]");
217 else
218 sb.Append(']');
219
220 return sb.ToString();
221 }
222
226 public override IRing AssociatedRing
227 {
228 get
229 {
230 if (this.associatedMatrixSpace is null)
231 this.associatedMatrixSpace = new ObjectMatrices(this.rows, this.columns);
232
233 return this.associatedMatrixSpace;
234 }
235 }
236
237 private ObjectMatrices associatedMatrixSpace = null;
238
242 public override object AssociatedObjectValue => this;
243
250 {
251 IElement[,] Values = this.Values;
252 IElement[,] v;
253 IElement n;
254 int x, y, z;
255
256 if (Element.IsScalar)
257 {
258 v = new IElement[this.rows, this.columns];
259
260 for (y = 0; y < this.rows; y++)
261 {
262 for (x = 0; x < this.columns; x++)
263 v[y, x] = Multiply.EvaluateMultiplication(Element, Values[y, x], null);
264 }
265
266 return new ObjectMatrix(v);
267 }
268 else if (Element is IMatrix Matrix)
269 {
270 if (Matrix.Columns != this.rows)
271 return null;
272
273 IElement[,] Values2 = Matrix.MatrixElements;
274
275 v = new IElement[Matrix.Rows, this.columns];
276
277 for (y = 0; y < Matrix.Rows; y++)
278 {
279 for (x = 0; x < this.columns; x++)
280 {
281 n = null;
282
283 for (z = 0; z < this.rows; z++)
284 {
285 if (n is null)
286 n = Multiply.EvaluateMultiplication(Values2[y, z], Values[z, x], null);
287 else
288 {
289 n = Operators.Arithmetics.Add.EvaluateAddition(n,
290 Multiply.EvaluateMultiplication(Values2[y, z], Values[z, x], null), null);
291 }
292 }
293
294 v[y, x] = n;
295 }
296 }
297
298 return new ObjectMatrix(v);
299 }
300 else
301 return null;
302 }
303
310 {
311 IElement[,] Values = this.Values;
312 IElement[,] v;
313 IElement n;
314 int x, y, z;
315
316 if (Element.IsScalar)
317 {
318 v = new IElement[this.rows, this.columns];
319
320 for (y = 0; y < this.rows; y++)
321 {
322 for (x = 0; x < this.columns; x++)
323 v[y, x] = Multiply.EvaluateMultiplication(Element, Values[y, x], null);
324 }
325
326 return new ObjectMatrix(v);
327 }
328 else if (Element is IMatrix Matrix)
329 {
330 if (this.columns != Matrix.Rows)
331 return null;
332
333 IElement[,] Values2 = Matrix.MatrixElements;
334
335 v = new IElement[this.rows, Matrix.Columns];
336
337 for (y = 0; y < this.rows; y++)
338 {
339 for (x = 0; x < Matrix.Columns; x++)
340 {
341 n = null;
342
343 for (z = 0; z < this.columns; z++)
344 {
345 if (n is null)
346 n = Multiply.EvaluateMultiplication(Values[y, z], Values2[z, x], null);
347 else
348 {
349 n = Operators.Arithmetics.Add.EvaluateAddition(n,
350 Multiply.EvaluateMultiplication(Values[y, z], Values2[z, x], null), null);
351 }
352 }
353
354 v[y, x] = n;
355 }
356 }
357
358 return new ObjectMatrix(v);
359 }
360 else
361 return null;
362 }
363
368 public override IRingElement Invert()
369 {
370 if (this.rows != this.columns)
371 return null;
372
373 IElement[,] Values = this.Values;
374 int c2 = this.columns << 1;
375 IElement[,] v = new IElement[this.rows, c2];
376 IElement E;
377 int x, y;
378
379 for (y = 0; y < this.rows; y++)
380 {
381 for (x = 0; x < this.columns; x++)
382 {
383 v[y, x] = E = Values[y, x];
385 return null;
386
387 v[y, x + this.columns] = (x == y ? E2.One : E2.Zero);
388 }
389 }
390
391 if (Reduce(v, true, true, out _) < 0)
392 return null;
393
394 IElement[,] v2 = new IElement[this.rows, this.columns];
395
396 for (y = 0; y < this.rows; y++)
397 {
398 for (x = 0; x < this.columns; x++)
399 v2[y, x] = v[y, x + this.columns];
400 }
401
402 return new ObjectMatrix(v2);
403 }
404
416 public IMatrix Reduce(bool Eliminate, bool BreakIfZero, out int Rank, out ICommutativeRingWithIdentityElement Factor)
417 {
418 IElement[,] M = (IElement[,])this.Values.Clone();
419 Rank = Reduce(M, Eliminate, BreakIfZero, out Factor);
420 return new ObjectMatrix(M);
421 }
422
434 public static int Reduce(IElement[,] Matrix, bool Eliminate, bool BreakIfZero, out ICommutativeRingWithIdentityElement Factor)
435 {
436 int x, y, u, z;
437 int Rows = Matrix.GetLength(0);
438 int Columns = Matrix.GetLength(1);
439 int MinCount = Math.Min(Rows, Columns);
441 IElement w;
442 int Rank = 0;
443 bool Sign = false;
444
445 Factor = null;
446
447 for (x = 0; x < MinCount; x++)
448 {
449 a = Matrix[x, x] as ICommutativeRingWithIdentityElement;
450 if (a is null)
451 return -1;
452
453 if (a.Equals(a.Zero))
454 {
455 z = x;
456 for (y = x + 1; y < Rows; y++)
457 {
458 b = Matrix[y, x] as ICommutativeRingWithIdentityElement;
459 if (b is null)
460 return -1;
461
462 if (!b.Equals(b.Zero))
463 {
464 a = b;
465 z = y;
466 break;
467 }
468 }
469
470 if (z != x)
471 {
472 for (u = x; u < Columns; u++)
473 {
474 w = Matrix[x, u];
475 Matrix[x, u] = Matrix[z, u];
476 Matrix[z, u] = w;
477 }
478
479 Sign = !Sign;
480 }
481 else
482 {
483 if (BreakIfZero)
484 return -1;
485 else
486 continue;
487 }
488 }
489
490 Rank++;
491
492 if (a != a.One)
493 {
494 for (u = x; u < Columns; u++)
495 Matrix[x, u] = Divide.EvaluateDivision(Matrix[x, u], a, null);
496
497 if (Factor is null)
498 Factor = a;
499 else
500 {
502 if (Factor is null)
503 return -1;
504 }
505 }
506
507 for (y = Eliminate ? 0 : x + 1; y < Rows; y++)
508 {
509 if (y != x)
510 {
511 a = Matrix[y, x] as ICommutativeRingWithIdentityElement;
512 if (a is null)
513 return -1;
514
515 if (!a.Equals(a.Zero))
516 {
517 for (u = x; u < Columns; u++)
518 {
519 Matrix[y, u] = Subtract.EvaluateSubtraction(Matrix[y, u],
520 Multiply.EvaluateMultiplication(a, Matrix[x, u], null), null);
521 }
522 }
523 }
524 }
525 }
526
527 if (Factor is null)
528 Factor = new DoubleNumber(1);
529
530 if (Sign)
531 {
532 Factor = Factor.Negate() as ICommutativeRingWithIdentityElement;
533 if (Factor is null)
534 return -1;
535 }
536
537 return Rank;
538 }
539
546 {
547 IElement[,] Values = this.Values;
548 IElement[,] v;
549 int x, y;
550
551 if (Element.IsScalar)
552 {
553 v = new IElement[this.rows, this.columns];
554
555 for (y = 0; y < this.rows; y++)
556 {
557 for (x = 0; x < this.columns; x++)
558 v[y, x] = Operators.Arithmetics.Add.EvaluateAddition(Element, this.values[y, x], null);
559 }
560
561 return new ObjectMatrix(v);
562 }
563 else if (Element is IMatrix Matrix)
564 {
565 if (this.columns != Matrix.Columns || this.rows != Matrix.Rows)
566 return null;
567
568 IElement[,] Values2 = Matrix.MatrixElements;
569
570 v = new IElement[this.rows, this.columns];
571 for (y = 0; y < this.rows; y++)
572 {
573 for (x = 0; x < this.columns; x++)
574 v[y, x] = Operators.Arithmetics.Add.EvaluateAddition(Values[y, x], Values2[y, x], null);
575 }
576
577 return new ObjectMatrix(v);
578 }
579 else
580 return null;
581 }
582
587 public override IGroupElement Negate()
588 {
589 IElement[,] Values = this.Values;
590 IElement[,] v = new IElement[this.rows, this.columns];
591 int x, y;
592
593 for (y = 0; y < this.rows; y++)
594 {
595 for (x = 0; x < this.columns; x++)
596 v[y, x] = Operators.Arithmetics.Negate.EvaluateNegation(Values[y, x]);
597 }
598
599 return new ObjectMatrix(v);
600 }
601
607 public override bool Equals(object obj)
608 {
609 if (!(obj is IMatrix Matrix))
610 return false;
611
612 if (this.columns != Matrix.Columns || this.rows != Matrix.Rows)
613 return false;
614
615 IElement[,] V1 = this.Values;
616 IElement[,] V2 = Matrix.MatrixElements;
617 int x, y;
618
619 for (y = 0; y < this.rows; y++)
620 {
621 for (x = 0; x < this.columns; x++)
622 {
623 if (V1[y, x] != V2[y, x])
624 return false;
625 }
626 }
627
628 return true;
629 }
630
635 public override int GetHashCode()
636 {
637 int Result = 0;
638 int x, y;
639
640 for (y = 0; y < this.rows; y++)
641 {
642 for (x = 0; x < this.columns; x++)
643 Result ^= this.values[y, x].GetHashCode();
644 }
645
646 return Result;
647 }
648
652 public override bool IsScalar => false;
653
657 public override ICollection<IElement> ChildElements => this.Elements;
658
665 public override IElement Encapsulate(ICollection<IElement> Elements, ScriptNode Node)
666 {
667 return MatrixDefinition.Encapsulate(Elements, this.rows, this.columns, Node);
668 }
669
674 {
675 get { throw new ScriptException("Zero element not defined for generic object matrices."); }
676 }
677
681 public int Dimension => this.rows;
682
686 public ICollection<IElement> VectorElements
687 {
688 get
689 {
690 if (!(this.rowVectors is null))
691 return this.rowVectors;
692
693 LinkedList<IElement> Rows = new LinkedList<IElement>();
694 int x, y;
695
696 if (!(this.values is null))
697 {
698 for (y = 0; y < this.rows; y++)
699 {
700 LinkedList<IElement> Row = new LinkedList<IElement>();
701
702 for (x = 0; x < this.columns; x++)
703 Row.AddLast(this.values[y, x]);
704
705 Rows.AddLast(Operators.Vectors.VectorDefinition.Encapsulate(Row, false, null));
706 }
707 }
708 else
709 {
710 LinkedList<IElement> Row = null;
711
712 x = 0;
713 foreach (IElement Element in this.elements)
714 {
715 if (Row is null)
716 Row = new LinkedList<IElement>();
717
718 Row.AddLast(Element);
719 x++;
720 if (x >= this.columns)
721 {
722 Rows.AddLast(Operators.Vectors.VectorDefinition.Encapsulate(Row, false, null));
723 Row = null;
724 x = 0;
725 }
726 }
727
728 if (!(Row is null))
729 Rows.AddLast(Operators.Vectors.VectorDefinition.Encapsulate(Row, false, null));
730 }
731
732 this.rowVectors = Rows;
733 return Rows;
734 }
735 }
736
737 private LinkedList<IElement> rowVectors = null;
738
744 {
745 IElement[,] v = new IElement[this.columns, this.rows];
746 IElement[,] Values = this.Values;
747 int x, y;
748
749 for (y = 0; y < this.rows; y++)
750 {
751 for (x = 0; x < this.columns; x++)
752 v[x, y] = Values[y, x];
753 }
754
755 return new ObjectMatrix(v);
756 }
757
763 {
764 return this.Transpose();
765 }
766
772 public IElement GetElement(int Index)
773 {
774 if (Index < 0 || Index >= this.rows)
775 throw new ScriptException("Index out of bounds.");
776
777 IElement[,] M = this.Values;
778 IElement[] V = new IElement[this.columns];
779 int i;
780
781 for (i = 0; i < this.columns; i++)
782 V[i] = M[Index, i];
783
784 return Operators.Vectors.VectorDefinition.Encapsulate(V, false, null);
785 }
786
792 public void SetElement(int Index, IElement Value)
793 {
794 if (Index < 0 || Index >= this.rows)
795 throw new ScriptException("Index out of bounds.");
796
797 if (!(Value is IVector V))
798 throw new ScriptException("Invalid row vector.");
799
800 if (V.Dimension != this.columns)
801 throw new ScriptException("Dimension mismatch.");
802
803 IElement[,] M = this.Values;
804 this.elements = null;
805
806 int i = 0;
807
808 foreach (IElement E in V.ChildElements)
809 M[Index, i++] = E;
810 }
811
818 public IElement GetElement(int Column, int Row)
819 {
820 if (Column < 0 || Column >= this.columns || Row < 0 || Row >= this.rows)
821 throw new ScriptException("Index out of bounds.");
822
823 return this.Values[Row, Column];
824 }
825
832 public void SetElement(int Column, int Row, IElement Value)
833 {
834 if (Column < 0 || Column >= this.columns || Row < 0 || Row >= this.rows)
835 throw new ScriptException("Index out of bounds.");
836
837 IElement[,] M = this.Values;
838 this.elements = null;
839
840 M[Row, Column] = Value;
841 }
842
848 public IVector GetRow(int Row)
849 {
850 if (Row < 0 || Row >= this.rows)
851 throw new ScriptException("Index out of bounds.");
852
853 IElement[,] M = this.Values;
854 IElement[] V = new IElement[this.columns];
855 int i;
856
857 for (i = 0; i < this.columns; i++)
858 V[i] = M[Row, i];
859
860 return Operators.Vectors.VectorDefinition.Encapsulate(V, false, null);
861 }
862
868 public IVector GetColumn(int Column)
869 {
870 if (Column < 0 || Column >= this.columns)
871 throw new ScriptException("Index out of bounds.");
872
873 IElement[,] M = this.Values;
874 IElement[] V = new IElement[this.rows];
875 int i;
876
877 for (i = 0; i < this.rows; i++)
878 V[i] = M[i, Column];
879
880 return Operators.Vectors.VectorDefinition.Encapsulate(V, false, null);
881 }
882
888 public void SetRow(int Row, IVector Vector)
889 {
890 if (Row < 0 || Row >= this.rows)
891 throw new ScriptException("Index out of bounds.");
892
893 if (Vector.Dimension != this.columns)
894 throw new ScriptException("Vector dimension does not match number of columns");
895
896 IElement[,] M = this.Values;
897 this.elements = null;
898 int i = 0;
899
900 foreach (IElement E in Vector.VectorElements)
901 M[Row, i++] = E;
902 }
903
909 public void SetColumn(int Column, IVector Vector)
910 {
911 if (Column < 0 || Column >= this.columns)
912 throw new ScriptException("Index out of bounds.");
913
914 if (Vector.Dimension != this.rows)
915 throw new ScriptException("Vector dimension does not match number of rows");
916
917 IElement[,] M = this.Values;
918 this.elements = null;
919 int i = 0;
920
921 foreach (IElement E in Vector.VectorElements)
922 M[i++, Column] = E;
923 }
924 }
925}
Base class for all types of elements.
Definition: Element.cs:13
virtual bool IsScalar
If the element represents a scalar value.
Definition: Element.cs:54
Element()
Base class for all types of elements.
Definition: Element.cs:17
Base class for all types of ring elements.
Definition: RingElement.cs:10
Base class for script exceptions.
Class managing a script expression.
Definition: Expression.cs:39
static IElement Encapsulate(object Value)
Encapsulates an object.
Definition: Expression.cs:4955
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Definition: Expression.cs:4496
Base class for all nodes in a parsed script tree.
Definition: ScriptNode.cs:69
Pseudo-ring of Object-valued matrices.
IVector GetColumn(int Column)
Gets a column vector from the matrix.
IElement GetElement(int Index)
Gets an element of the vector.
IMatrix ConjugateTranspose()
Returns a conjugate transposed matrix.
void SetElement(int Column, int Row, IElement Value)
Sets an element in the matrix.
override IRing AssociatedRing
Associated Ring.
override IRingElement MultiplyRight(IRingElement Element)
Tries to multiply an element to the current element, from the right.
bool HasColumnNames
If the matrix has column names defined.
ObjectMatrix(IElement[,] Values)
Object-valued matrix.
Definition: ObjectMatrix.cs:28
override IAbelianGroupElement Add(IAbelianGroupElement Element)
Tries to add an element to the current element.
override IElement Encapsulate(ICollection< IElement > Elements, ScriptNode Node)
Encapsulates a set of elements into a similar structure as that provided by the current element.
IElement GetElement(int Column, int Row)
Gets an element of the matrix.
override object AssociatedObjectValue
Associated object value.
ICollection< IElement > Elements
Matrix elements.
void SetColumn(int Column, IVector Vector)
Gets a column vector from the matrix.
IMatrix Reduce(bool Eliminate, bool BreakIfZero, out int Rank, out ICommutativeRingWithIdentityElement Factor)
Reduces a matrix.
IVector GetRow(int Row)
Gets a row vector from the matrix.
static int Reduce(IElement[,] Matrix, bool Eliminate, bool BreakIfZero, out ICommutativeRingWithIdentityElement Factor)
Reduces a matrix.
ObjectMatrix(object[,] Values)
Object-valued matrix.
Definition: ObjectMatrix.cs:40
override IRingElement Invert()
Inverts the element, if possible.
IElement[,] MatrixElements
Matrix elements
override int GetHashCode()
Calculates a hash code of the element.
ObjectMatrix(int Rows, int Columns, ICollection< IElement > Elements)
Object-valued vector.
Definition: ObjectMatrix.cs:63
override IRingElement MultiplyLeft(IRingElement Element)
Tries to multiply an element to the current element, from the left.
override IAbelianGroupElement Zero
Returns the zero element of the group.
void SetElement(int Index, IElement Value)
Sets an element in the vector.
IElement[,] Values
Matrix element values.
Definition: ObjectMatrix.cs:75
ICollection< IElement > VectorElements
Vector of row vectors.
override bool Equals(object obj)
Compares the element to another.
override ICollection< IElement > ChildElements
An enumeration of child elements. If the element is a scalar, this property will return null.
string[] ColumnNames
Contains optional column names.
override IGroupElement Negate()
Negates the element.
override bool IsScalar
If the element represents a scalar value.
int Dimension
Dimension of matrix, if seen as a vector of row vectors.
IMatrix Transpose()
Returns a transposed matrix.
void SetRow(int Row, IVector Vector)
Gets a row vector from the matrix.
static IElement EvaluateDivision(IElement Left, IElement Right, ScriptNode Node)
Divides the right operand from the left one.
Definition: Divide.cs:65
static IElement EvaluateMultiplication(IElement Left, IElement Right, ScriptNode Node)
Multiplies two operands.
Definition: Multiply.cs:69
static IElement EvaluateSubtraction(IElement Left, IElement Right, ScriptNode Node)
Subtracts the right operand from the left one.
Definition: Subtract.cs:65
static IMatrix Encapsulate(ICollection< IElement > Rows, ScriptNode Node)
Encapsulates the elements of a matrix.
Basic interface for all types of abelian group elements.
IAbelianGroupElement Zero
Returns the zero element of the group.
Basic interface for all types of commutative ring with identity elements.
ICommutativeRingWithIdentityElement One
Returns the identity element of the commutative ring with identity.
Basic interface for all types of elements.
Definition: IElement.cs:20
ICollection< IElement > ChildElements
An enumeration of child elements. If the element is a scalar, this property will return null.
Definition: IElement.cs:49
IElement Encapsulate(ICollection< IElement > Elements, ScriptNode Node)
Encapsulates a set of elements into a similar structure as that provided by the current element.
Basic interface for all types of group elements.
Definition: IGroupElement.cs:9
Basic interface for matrices.
Definition: IMatrix.cs:9
Basic interface for all types of ring elements.
Definition: IRingElement.cs:10
Basic interface for vectors.
Definition: IVector.cs:9
int Dimension
Dimension of vector.
Definition: IVector.cs:14
Basic interface for all types of rings.
Definition: IRing.cs:10