matrix-lens: Optics for the "matrix" package

[ bsd3, library, math ] [ Propose Tags ]

Versions [faq] 0.1.0.0 ChangeLog.md base (>=4.7 && <5), lens (>=4.19.2 && <4.20), matrix (>=0.3.6 && <0.4), vector (>=0.12.1 && <0.13) [details] BSD-3-Clause 2020 Interos, Inc. Interos, Inc. jevans@interos.ai Math https://github.com/interosinc/matrix-lens#readme https://github.com/interosinc/matrix-lens/issues head: git clone https://github.com/interosinc/matrix-lens by lgastako at 2020-07-07T06:39:57Z NixOS:0.1.0.0 38 total (4 in the last 30 days) (no votes yet) [estimated by Bayesian average] λ λ λ Docs available Last success reported on 2020-07-07

Modules

[Index] [Quick Jump]

Flags

NameDescriptionDefaultType
developer

Developer mode -- stricter handling of compiler warnings.

DisabledManual

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Maintainer's Corner

For package maintainers and hackage trustees

[back to package description]

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)