Optics for the "matrix" package.
See README at https://github.com/interosinc/matrix-lens#readme
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)