initial checkin
authorClaus Gittinger <cg@exept.de>
Tue, 20 Aug 2019 15:00:25 +0200
changeset 5082 dd1fa34053ea
parent 5081 06c4888598d2
child 5083 79a19e80bebc
initial checkin
Matrix.st
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Matrix.st	Tue Aug 20 15:00:25 2019 +0200
@@ -0,0 +1,444 @@
+"{ Package: 'stx:libbasic2' }"
+
+"{ NameSpace: Smalltalk }"
+
+AbstractMultidimensionalArray variableSubclass:#Matrix
+	instanceVariableNames:'dimensions'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Collections-MultiDimensional'
+!
+
+!Matrix class methodsFor:'documentation'!
+
+documentation
+"
+    Generic Matrix with arbitrary number of dimensions.
+    Especially useful with the ArrayIndexing-Parser extension.
+
+    [author:]
+        Claus Gittinger (cg@sinir)
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+        MultiDimensionalArrayAccessor
+"
+!
+
+examples
+"
+
+  You have to enable the Parsers arrayIndexingExtension support
+  in order to be able to execute the examples below.
+
+  Parser allowArrayIndexSyntaxExtension:true
+
+                                                                [exBegin]
+    |m|
+
+    m := Matrix[3,3].
+    m[2,1] := 11.
+    m[2,2] := 12.
+    m[2,3] := 13.
+    m     
+                                                                [exEnd]
+
+                                                                [exBegin]
+    |m|
+
+    m := Matrix3_3 new.
+    m[2,1] := 11.
+    m[2,2] := 12.
+    m[2,3] := 13.
+    m       
+                                                                [exEnd]
+
+                                                                [exBegin]
+    |m1 m2|
+
+    m1 := Matrix3_3 new.
+    m1 atAllPut:1.
+
+    m2 := Matrix3_3 new.
+    m2 atAllPut:2.
+
+    m1 - m2    
+                                                                [exEnd]
+
+                                                                [exBegin]
+    |m1 m2|
+
+    m1 := Matrix3_3 new.
+    m1 atAllPut:1.
+
+    m2 := Matrix3_3 new.
+    m2 atAllPut:2.
+
+    m1 + m2    
+                                                                [exEnd]
+"
+! !
+
+!Matrix class methodsFor:'instance creation'!
+
+_at:nIndices
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        Matrix[n]
+     generates
+        Matrix _at: n
+    "
+
+    ^ Array new:nIndices
+!
+
+_at:dim1 at:dim2
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        Matrix[n,m]
+     generates
+        Matrix _at:n at:m
+    "
+
+    ^ self newForRows:dim1 cols:dim2
+!
+
+_at:dim1 at:dim2 at:dim3
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        Matrix[n,m,o]
+     generates
+        Matrix _at:n at:m at:o
+    "
+
+    ^ (self basicNew:(dim1 * dim2 * dim3))
+        dimensions:(Array with:dim1 with:dim2 with:dim3)
+!
+
+identity: anInteger
+    "Answer an identity matrix of order 'anInteger@anInteger'."
+
+    | mat |
+
+    mat := self newForRows:anInteger cols:anInteger.
+    mat atAllPut:0.
+    1 to: anInteger do: [ :i | mat _at: i at: i put: 1 ].
+    ^ mat
+
+    "
+     self identity:3
+     self identity:2
+     self identity:5
+    "
+!
+
+newForRows:nRows cols:nCols
+    |mClass|
+
+    nRows == nCols ifTrue:[
+        nCols == 2 ifTrue:[
+            ^ Matrix2_2 new dimensions:#(2 2)
+        ].
+        nCols == 3 ifTrue:[
+            ^ Matrix3_3 new dimensions:#(3 3)
+        ].
+        mClass := SquareMatrix
+    ] ifFalse:[
+        mClass := self
+    ].
+
+    ^ (mClass basicNew:(nRows * nCols))
+        dimensions:(Array with:nRows with:nCols)
+!
+
+ones: aPoint
+    "Answer a matrix of order 'aPoint' filled with ones"
+
+    |mat|
+
+    mat := self newForRows:aPoint y cols:aPoint x.
+    mat atAllPut: 1.
+    ^ mat
+
+    "
+     self ones:(3 @ 3)
+     self ones:(3 @ 2)
+     self ones:(5 @ 5)
+    "
+!
+
+zero: aPoint
+    "Answer a matrix of order 'aPoint' filled with zeros"
+
+    |mat|
+
+    mat := self newForRows:aPoint y cols:aPoint x.
+    mat atAllPut: 0.
+    ^ mat
+
+    "
+     self zero:(3 @ 3)
+     self zero:(3 @ 2)
+     self zero:(5 @ 5)
+    "
+! !
+
+!Matrix methodsFor:'accessing'!
+
+_at:index
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        foo[n]
+     generates
+        foo _at: n
+    "
+    dimensions size ~~ 1 ifTrue:[self dimensionError].
+    ^ self basicAt:index.
+!
+
+_at:index1 at:index2
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        foo[n,m]
+     generates
+        foo _at:n at:m
+    "
+    |idx|
+
+    dimensions size ~~ 2 ifTrue:[self dimensionError].
+    (index1 between:1 and:(dimensions at:1)) ifFalse:[self subscriptBoundsError:index1].
+    (index2 between:1 and:(dimensions at:2)) ifFalse:[self subscriptBoundsError:index2].
+
+    idx := ((index1-1) * (dimensions at:2)).
+    idx := idx + index2.
+    ^ self basicAt:idx.
+
+    "
+     |m|
+     m := MultiDimensionalArrayAccessor new
+              collection:
+                #(
+                   11 12 13 14
+                   21 22 23 24
+                   31 32 33 34
+                 )
+              dimensions:
+                #(3 4).
+
+     m[1,4]          
+    "
+!
+
+_at:index1 at:index2 at:index3
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] is parsed.
+     I.e. 
+        foo[n,m,o]
+     generates
+        foo _at:n at:m at:o
+    "
+    |idx|
+
+    dimensions size ~~ 3 ifTrue:[self dimensionError].
+    (index1 between:1 and:(dimensions at:1)) ifFalse:[self subscriptBoundsError:index1].
+    (index2 between:1 and:(dimensions at:2)) ifFalse:[self subscriptBoundsError:index2].
+    (index3 between:1 and:(dimensions at:3)) ifFalse:[self subscriptBoundsError:index3].
+
+    idx := ((((index1-1) * (dimensions at:2)) + (index2-1)) * (dimensions at:3)).
+    idx := idx + index3.
+    ^ self basicAt:idx.
+
+    "
+     |m|
+     m := MultiDimensionalArrayAccessor new
+              collection:
+                #(
+                   111 112 113 114
+                   121 122 123 124
+                   131 132 133 134
+
+                   211 212 213 214
+                   221 222 223 224
+                   231 232 233 234 )
+              dimensions:
+                #(2 3 4).
+
+     m[2,1,4]          
+    "
+!
+
+_at:index1 at:index2 at:index3 put:val
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] := val is parsed.
+     I.e. 
+        foo[n,m,o] := val
+     generates
+        foo _at:n at:m at:o put:val
+    "
+    |idx|
+
+    dimensions size ~~ 3 ifTrue:[self dimensionError].
+    (index1 between:1 and:(dimensions at:1)) ifFalse:[self subscriptBoundsError:index1].
+    (index2 between:1 and:(dimensions at:2)) ifFalse:[self subscriptBoundsError:index2].
+    (index3 between:1 and:(dimensions at:3)) ifFalse:[self subscriptBoundsError:index3].
+
+    idx := ((((index1-1) * (dimensions at:2)) + (index2-1)) * (dimensions at:3)).
+    idx := idx + index3.
+    ^ self basicAt:idx put:val.
+!
+
+_at:index1 at:index2 put:val
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] := val is parsed.
+     I.e. 
+        foo[n,m] := val
+     generates
+        foo _at:n at:m put:val
+    "
+    |idx|
+
+    dimensions size ~~ 2 ifTrue:[self dimensionError].
+    (index1 between:1 and:(dimensions at:1)) ifFalse:[self subscriptBoundsError:index1].
+    (index2 between:1 and:(dimensions at:2)) ifFalse:[self subscriptBoundsError:index2].
+
+    idx := ((index1-1) * (dimensions at:2)).
+    idx := idx + index2.
+    ^ self basicAt:idx put:val.
+!
+
+_at:index put:val
+    "this is a synthetic selector, generated by the compiler,
+     if a construct of the form expr[idx...] := val is parsed.
+     I.e. 
+        foo[n] := val
+     generates
+        foo _at:n put:val
+    "
+    dimensions size ~~ 1 ifTrue:[self dimensionError].
+    ^ self basicAt:index put:val.
+!
+
+at:index
+    "/ dimensions size ~~ 1 ifTrue:[self dimensionError].
+    ^ self basicAt:index.
+!
+
+at:index put:val
+    "/ dimensions size ~~ 1 ifTrue:[self dimensionError].
+    ^ self basicAt:index put:val.
+!
+
+dimensions
+    ^ dimensions
+!
+
+size
+    ^ self basicSize
+! !
+
+!Matrix methodsFor:'arithmetic'!
+
++ aMatrix
+    "Answer the result of adding 'aMatrix' to this matrix."
+
+    ^ aMatrix sumFromMatrix:self
+!
+
+- aMatrix
+    "Answer the result of subtracting 'aMatrix' from this matrix."
+
+    ^ aMatrix differenceFromMatrix:self
+!
+
+= aMatrix
+    "Answer true, if the argument represents the same matrix"
+
+    self species == aMatrix species ifFalse: [ ^ false ].
+    dimensions = aMatrix dimensions ifFalse: [ ^ false ].
+
+    1 to: self basicSize do:[ :idx | 
+        (aMatrix basicAt: idx) == (self basicAt: idx) ifFalse:[^ false].
+    ].
+    ^ true
+!
+
+differenceFromMatrix: aMatrix
+    "Answer the result of subtracting the receiver from 'aMatrix'."
+
+    | result |
+
+    dimensions = aMatrix dimensions ifFalse: [ IncompatibleMatrixError signal ].
+
+    result := (self class new:(self basicSize)) dimensions:dimensions.
+
+    1 to: self basicSize do:[ :idx | 
+        result basicAt: idx put: (aMatrix basicAt: idx) - (self basicAt: idx).
+    ].
+    ^ result
+!
+
+sumFromMatrix: aMatrix
+    "Answer the result of adding 'aMatrix' to this matrix."
+
+    | result |
+
+    dimensions = aMatrix dimensions ifFalse: [ IncompatibleMatrixError signal ].
+
+    result := (self class new:(self basicSize)) dimensions:dimensions.
+
+    1 to: self basicSize do:[ :idx | 
+        result basicAt: idx put: (self basicAt: idx) + (aMatrix basicAt: idx).
+    ].
+    ^ result
+! !
+
+!Matrix methodsFor:'matrix operations'!
+
+determinant
+    MatrixError signal: 'Matrix must be square'
+! !
+
+!Matrix methodsFor:'private'!
+
+dimensions:dimensionsArg
+    dimensionsArg isArray ifFalse:[
+        dimensions := Array with:dimensionsArg y with:dimensionsArg x.
+    ] ifTrue:[
+        dimensions := dimensionsArg.
+    ].
+! !
+
+!Matrix methodsFor:'queries'!
+
+columns
+    ^ dimensions at:2
+!
+
+isSquare
+    ^ false
+
+    "
+     (self zero:(3 @ 3)) isSquare
+     (self zero:(2 @ 2)) isSquare
+     (self zero:(3 @ 2)) isSquare 
+    "
+!
+
+rows
+    ^ dimensions at:1
+! !
+
+!Matrix class methodsFor:'documentation'!
+
+version_CVS
+    ^ '$Header$'
+! !
+