Matrix.st
author Claus Gittinger <cg@exept.de>
Sat, 02 May 2020 21:40:13 +0200
changeset 5476 7355a4b11cb6
parent 5375 4153fc1c5e80
permissions -rw-r--r--
#FEATURE by cg class: Socket class added: #newTCPclientToHost:port:domain:domainOrder:withTimeout: changed: #newTCPclientToHost:port:domain:withTimeout:

"{ Encoding: utf8 }"

"
 COPYRIGHT (c) 2018 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libbasic2' }"

"{ NameSpace: Smalltalk }"

AbstractMultidimensionalArray variableSubclass:#Matrix
	instanceVariableNames:'dimensions'
	classVariableNames:''
	poolDictionaries:''
	category:'Collections-MultiDimensional'
!

!Matrix class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2018 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

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:]
        MatrixAccessor
"
!

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 := MatrixAccessor 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 := MatrixAccessor 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 raiseRequestWith:aMatrix errorString:'argument matrix has different dimensions'
    ].

    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 raiseRequestWith:aMatrix errorString:'argument matrix has different dimensions'
    ].

    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
    IncompatibleMatrixError raiseRequestWith:self errorString: 'Matrix must be square'
! !

!Matrix methodsFor:'private'!

dimensions:dimensionsArg
    dimensionsArg isArray ifFalse:[
        dimensions := Array with:dimensionsArg y with:dimensionsArg x.
    ] ifTrue:[
        dimensions := dimensionsArg.
    ].
!

setDimensions:dimensionsArg
    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$'
! !