[GOODIE] Matrix-raok

Richard A. O'Keefe ok at cs.otago.ac.nz
Mon Nov 25 00:06:16 UTC 2002


Bert Freudenberg <bert at isg.cs.uni-magdeburg.de>
asked how my Matrix class (described by me as basically a minor cleanup
of Array2D) compares with Croquet's Matrix class.

I couldn't even print the Croquet manual (the first page came out;
what Acrobat Reader did with the rest I cannot imagine) and so have
not looked at Croquet.  I can only reply based on the specific
examples in Bert Freudenberg's message.

		"Create a new array"
		a := Matrix[3, 3] fill: #(1 2 3 4 5 6 7 8 9). 
	
Not possible in plain Squeak syntax.
It is not clear whether filling goes by rows or columns,
so I rejected such an ambiguous operation from my design.

    a := Matrix rows: 3 columns: 3 tabulate: [:r :c | (r-1)*3+c]

if filling goes by rows, or

    a := Matrix rows: 3 columns: 3 tabulate: [:r :c | (c-1)*3+r]

if filling goes by columns.

		"Access individual elements"
		a[1,2].
		a[2,1].
	
Not possible in plain Squeak syntax.

    a at: 1 at: 2
    a at: 2 at: 1

		"Assign individual elements"
		a[3,1] := 42.
		a[1,3] := 21.
	
Not possible in plain Squeak syntax.

    a at: 3 at: 1 put: 42
    a at: 1 at: 3 put: 21

		"Access vectors"
		a[1]. 
		a[1,#all]. 
		a[#all,1]. 
	
I surmise that these mean "row 1", "row 1", and "column 1" respectively.

    a atRow: 1
    a atColumn: 1

Names "rowAt:" "columnAt:" were considered, but to me
"a atRow: i put: v" reads better than "a rowAt: i put: v".

		"Assign vectors"
		a[1] := #(-1 -2 -3). a.
		a[1,#all] := #(-3 -4 -5). a.
		a[#all,1] := #(-6 -7 -8). a.
	
Not possible in plain Squeak syntax.

    a atRow: 1 put: #(-1 -2 -3). a.
    a atRow: 1 put: #(-3 -4 -5). a.
    a atColumn: 1 put: #(-6 -7 -8). a.

I am in some doubt whether they should use ... put: or ... putAll: .

		"Access sub-arrays"
		a[(1 to: 2),(1 to: 2)]. 
		a[(2 to: 3),(2 to: 3)].
	
This I had not bothered to implement, not having had a need for it.
A new version will be on its way soon supporting

    a atRows: 1 to: 2 atColumns: 1 to: 2
    a atRows: 2 to: 3 atColumns: 2 to: 3
    a atRows: (1 to: 2) columns: (1 to: 2)
    a atRows: (2 to: 3) columns: (2 to: 3)

		"Assign sub-arrays"
		a[(1 to: 2),(1 to: 2)] := Matrix[2, 2] fill: 1.
		a[(2 to: 3),(2 to: 3)] := Matrix[2, 2] fill: 2.
	
Again, I had not bothered to implement this, not having had a need for it.
The new version will have

    a atRows: 1 to: 2 columns: 1 to: 2 put:
	(Matrix rows: 2 columns: 2 element: 1)
    a atRows: 2 to: 3 columns: 2 to: 3 put:
	(Matrix rows: 2 columns: 2 element: 2)
    a atRows: (1 to: 2) columns: (1 to: 2) put:
	(Matrix rows: 2 columns: 2 element: 1)
    a atRows: (2 to: 3) columns: (2 to: 3) put:
	(Matrix rows: 2 columns: 2 element: 2)

Again, I am in some doubt whether these should be ...put: or ...putAll: .
(Matrix>>rows:columns:element: is also new.)

		a[#all,#all]. 
		a[#all].
	
If these mean the same as

    a copy

then that works, otherwise I don't understand the question.

	"**** Dave''s examples ***"
	
		"Matrix addition"
		m1 := Matrix[3, 3] fill: #(1 2 3 4).
		m2 := Matrix[3, 3] fill: #(10 20 30).
		m3 := Matrix[3, 3] define: [:i1 :i2 | m1[i1, i2] + m2[i1, i2]].
	
I don't know what it means to fill a 3x3 matrix with a 4 element vector.

    m1 := Matrix new: 3 tabulate: [:r :c | c].    " 1  2  3;  1  2  3;  1  2  3"
    m2 := Matrix new: 3 tabulate: {:r :c | r*10]. "10 10 10; 20 20 20; 30 30 30"
    m1 + m2

or if you really insist on the long-winded version:

    m3 := Matrix new: tabulate [:r :c | (m1 at: r at: c) + (m2 at: r at: c)]

		"Matrix Transpose"
		Matrix shape: (m3 matrixShape reverse) define:[:i1 :i2 | m3[i2, i1]].
	
It doesn't get much simpler than

    m3 transposed

		"Matrix Multiplication (matrix product):"
		m1 := Matrix[4, 3] fill: #(1 2 3 4 5 6 7).
		m2 := Matrix[3, 2] fill: #(10 20 30 40).
		m3 := Matrix[4, 2] define:[ :i1 : i2 | m1[i1,#all ] dot: m2[#all, i2]]. 
	
Again, I don't know what filling a matrix with a vector whose size is
different from all of {number of rows, number of columns, total number
of elements} is supposed to do, so I will concentrate on the last step.

    m3 := m1 +* m2

	    "Laplace filter"
	    lap := Matrix[3,3] fill: #(1 4 1 4 -20 4 1 4 1).

    lap := Matrix new: 3 tabulate: [:r :c |
	    (#((1 4 1) (4 -20 4) (1 4 1)) at: r) at: c]

	    image := Matrix[50,50] fill: 1.

    image := Matrix new: 50 element: 1.  "in new version."

	    fImage := Matrix[50,50] define:[:i1 :i2|
		    (image[(i1-1 to: i1+1), (i2-1 to: i2+1)] * lap) sum sum].

    fImage := Matrix rows: 50 columns: 50 tabulate: [:r :c |
	((image atRows: r-1 to: r+1 columns: c-1 to: c+1) +* lap) sum]

Beware: this does NOT work at the edges.
We need a new message which fills missing elements in.
The new version adds this:

    fImage := Matrix rows: 50 columns: 50 tabulate: [:r :c |
	((image atRows: r-1 to: r+1 columns: c-1 to: c+1 ifInvalid: 0)
	  +* lap) sum]


	    image := Matrix[53,53] fill: 1.
	    fImage := Matrix[50,50] define:[:i1 :i2|
		    (i1 at i2) printString displayAt: 0 at 0.
		    (image[(i1 to: i1+2), (i2 to: i2+2)] * lap) sum sum].

    image := Matrix new: 53: fill: 1.
    fImage := Matrix new: 50 tabulate: [:r :c |
	(r at c) printString displayAt: 0 at 0.
	((image atRows: r to: r+2 columns: c to: c+2) +* lap) sum]

For consistency with #(1 2 3) * #(4 5 6), it is important that the
symbol for matrix multiplication should NOT be *.

The examples above have been tested, but where retyped by hand, so may
contain typos.



More information about the Squeak-dev mailing list