--- /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$'
+! !
+