matrix-lens
Optics for the matrix
package.
Thatβs how it is with people. Nobody cares how it works as long as it works.
- Councillor Hamann
Sparked by this reddit post.
Examples
The examples below make use of the following three matrices:
exampleInt :: Matrix Int
exampleInt = Matrix.fromLists
[ [1, 2, 3]
, [4, 5, 6]
, [7, 8, 9]
]
exampleInvertible :: Matrix (Ratio Int)
exampleInvertible = Matrix.fromLists
[ [ -3, 1 ]
, [ 5, 0 ]
]
exampleNotSquare :: Matrix Int
exampleNotSquare = Matrix.fromLists
[ [10, 20, 30]
, [40, 50, 60]
, [70, 80, 90]
, [100, 110, 120]
]
Accessing individual elements:
Ξ»> exampleNotSquare ^. elemAt (4, 3)
120
Ξ»> exampleInt & elemAt (2, 2) *~ 10
β β
β 1 2 3 β
β 4 50 6 β
β 7 8 9 β
β β
Accessing individual columns:
Ξ»> exampleInt ^. col 1
[1,4,7]
Ξ»> exampleInt & col 2 . each *~ 10
β β
β 1 20 3 β
β 4 50 6 β
β 7 80 9 β
β β
Accessing individual rows:
Ξ»> exampleInt ^. row 1
[1,2,3]
Ξ»> exampleInt & row 2 . each *~ 100
β β
β 1 2 3 β
β 400 500 600 β
β 7 8 9 β
β β
Manipulating all columns as a list:
Ξ»> exampleInt ^. cols
[[1,4,7],[2,5,8],[3,6,9]]
Ξ»> exampleInt & cols %~ reverse
β β
β 3 2 1 β
β 6 5 4 β
β 9 8 7 β
β β
Accessing all rows as a list:
Ξ»> exampleInt ^. rows
[[1,2,3],[4,5,6],[7,8,9]]
Ξ»> exampleInt & rows %~ map reverse
β β
β 3 2 1 β
β 6 5 4 β
β 9 8 7 β
β β
Ξ»> exampleInt & partsOf (dropping 1 (rows . each)) %~ reverse
β β
β 1 2 3 β
β 7 8 9 β
β 4 5 6 β
β β
In addition to the above there are also switching
and sliding
Isos for both
rows and columns which allow you to swap two arbitrary rows or columns or slide
a row or column through the matrix to a different row or column (moving all
intervening rows or columns over in the direction of the source row or column):
Ξ»> exampleNotSquare ^. switchingRows 1 4
β β
β 100 110 120 β
β 40 50 60 β
β 70 80 90 β
β 10 20 30 β
β β
Ξ»> exampleNotSquare ^. slidingRows 1 4
β β
β 40 50 60 β
β 70 80 90 β
β 100 110 120 β
β 10 20 30 β
β β
..and similary for switchingCols
and switchingRows
.
An Iso exists for accessing the matrix with a given row scaled:
Ξ»> exampleInt ^. scalingRow 1 10
β β
β 10 20 30 β
β 4 5 6 β
β 7 8 9 β
β β
Ξ»> exampleInt & scalingRow 1 10 . flattened *~ 2
β β
β -200 -400 -600 β
β 8 10 12 β
β 14 16 18 β
β β
Any valid sub matrix can be accessed via the sub
lens:
Ξ»> exampleNotSquare ^. sub (2, 1) (3, 2)
β β
β 40 50 β
β 70 80 β
β β
Ξ»> exampleNotSquare & sub (2, 1) (3, 2) . rows %~ reverse
β β
β 10 20 30 β
β 70 80 60 β
β 40 50 90 β
β 100 110 120 β
β β
The transposition of the matrix can be accessed via the transposed
Iso:
Ξ»> exampleInt ^. transposed
β β
β 1 4 7 β
β 2 5 8 β
β 3 6 9 β
β β
Ξ»> exampleInt & transposed . taking 4 flattened *~ 10
β β
β 10 20 3 β
β 40 5 6 β
β 70 8 9 β
β β
You can also traverse the flattened
matrix:
Ξ»> exampleInt ^.. flattened
[1,2,3,4,5,6,7,8,9]
which is more useful for making modifications:
Ξ»> exampleInt & flattened . filtered even *~ 10
β β
β 1 20 3 β
β 40 5 60 β
β 7 80 9 β
β β
Ξ»> exampleInt & dropping 4 flattened *~ 10
β β
β 1 2 3 β
β 4 50 60 β
β 70 80 90 β
β β
Accessing the diagonal:
Ξ»> exampleInt ^. diag
[1,5,9]
Ξ»> exampleInt & diag %~ reverse
β β
β 9 2 3 β
β 4 5 6 β
β 7 8 1 β
β β
Ξ»> exampleInt & diag . each *~ 10
β β
β 10 2 3 β
β 4 50 6 β
β 7 8 90 β
β β
Accessing inverse matrix is possible via the inverted
optic. Since not all
matrices have inverses inverted
is a prism:
Ξ»> exampleInvertible ^? inverted
Just β β
β 0 % 1 1 % 5 β
β 1 % 1 3 % 5 β
β β
Ξ»> exampleInvertible & inverted . flattened *~ 2
β β
β (-3) % 2 1 % 2 β
β 5 % 2 0 % 1 β
β β
Minor matrices can be accessed by specifying the (r, c) to be removed:
Ξ»> exampleInt ^. minor (1, 2)
β β
β 4 6 β
β 7 9 β
β β
Ξ»> exampleInt & minor (1, 2) . flattened *~ 10
β β
β 1 2 3 β
β 40 5 60 β
β 70 8 90 β
β β
An Iso exists for accessing a scaled version of a matrix:
Ξ»> exampleInt ^. scaled 10
β β
β 10 20 30 β
β 40 50 60 β
β 70 80 90 β
β β
Ξ»> exampleInt & minor (1, 1) . scaled 10 . flattened +~ 1
β β
β 1 2 3 β
β 4 -510 -610 β
β 7 -810 -910 β
β β
Getters for the matrix determinant and size are also provided:
Ξ»> exampleInt ^. determinant
Just 0
Ξ»> exampleInvertible ^. determinant
Just ((-5) % 1)
Ξ»> exampleNotSquare ^. determinant
Nothing
Ξ»> exampleInt ^. size
(3,3)
Ξ»> exampleInvertible ^. size
(2,2)
Ξ»> exampleNotSquare ^. size
(4,3)