Matrices in stdlib -- how to represent them? #3101
Replies: 6 comments 1 reply
|
I did put together a small PR many years ago using the vector of vectors appraoch and received some pushback on my design: #1525 Looking at it again now, whatever the representation of indices we choose I think we should probably try and go for tensors first, and have matrices as a special case of 2D tensor? |
|
Patrik Jansson (Chalmers) has done a lot of work in Agda on tensor algebra for (teaching) physics, including relating abstract representations and concrete / coordinatised forms . I'll try and find a good link: eg https://research.chalmers.se/en/publication/546169 As for fields, much as for matrices, various attempts have been made, but in a constructive setting, and without necessarily being able to decide the underlying equality, the natural notion is better that of local ring. #2219 |
|
Instead of having matrices, I am tempted to suggest defining a universe of finite types open import Data.Nat.Base using (ℕ)
data Shape : Set where
`Fin : ℕ → Shape
_`⊎_ : Shape → Shape → Shape
_`×_ : Shape → Shape → Shapeand then have a generic notion of Tensor indexed by such a open import Data.Fin.Base using (Fin)
open import Data.Sum.Base using (_⊎_)
open import Data.Product.Base using (_×_)
Index : Shape → Set
Index (`Fin n) = Fin n
Index (i₁ `⊎ i₂) = Index i₁ ⊎ Index i₂
Index (i₁ `× i₂) = Index i₁ × Index i₂
record Tensor {a} (sh : Shape) (A : Set a) : Set a where
constructor mkTensor
field runTensor : Index sh → AThere is of course an isomorphic flat representation as a big vector Matrix multiplication ought to be an instance of a more general operation |
|
There's another perspective on matrices, that they're (representations of) homomorphisms between certain modules. This provides a reason for the algebraic operations on them. |
|
We have an application where we need to extract code that actually multiplies matrices (the transition relation of weighted automata)
This is quite orthogonal to how you want to prove things. |
but when I use that memoized function, I pay the cost of indexing? so that must be O(1)
yes, if using |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I have a personal project where I have a construction of matrices over (commutative) (semi-) rings. I'd like to contribute some form of it to the standard library, but as I discussed with @JacquesCarette in this discussion in agda-categories, I have to do some design work and seek input from stdlib maintainers and Agda veterans. (I am a neophyte -- I hadn't heard of Agda until January. Love it.)
In my repo, I use something like this,
Fin nandFin mindexed function-based matrices.For matrix multiplication define e.g.
and you get the (semi)ring structure for
SqMat n = Mat n nalmost for free. You can of course define trace, determinant, inverse, and lots of other constructs of linear algebra.That said, there are definite pros and cons of representing matrices as (records wrapping) functions
Fin n → Fin m → R.carrier.As some pros: Finite ordinals are well-ordered, decidable, natural (sometimes literally defined as the natural numbers), and Data.Fin has lots of nice combinators like
splitAt,remQuot,join,punchOutthat make linear algebra convenient. Not to mentionData.Fin.{Subset,Properties,Permutation}etc which are also a goldmine. There is also only one "5" or any other n, we have UIP, and you can easily define submatrices, horizontal and vertical concatenation, and hence the Kronecker tensor product and direct sum.I also have an implementation of matrices as Vec n (Vec m) R.carrier (with round trips), which may be better for algorithms like Gaussian elimination and RREF construction.
That said, a lot of the things we want matrices to be don't require Fin n / Fin m, and also I don't know where on the spectrum of generality would be most useful. On one end, you could lift any commutative (additive) semigroup S to matrices of n x m elements that you can add and take trace of and nothing else (including scale). On the other end, you could define them over fields (although stdlib only has RealHeytingField, not a general Field type). I'm inclined to think the "sweet spot" would be over commutative rings, which give the determinant, subtraction, and lots of nice properties, perhaps generalized to commutative semirings which lose the determinant but retain most everything else. However, I think matrices over general (semi)rings are worth considering as long as we're okay losing some nice properties in the most general case. (In my repo, I actually do have matrices over not-necessarily commutative semirings, and commutative semirings, and rings, and commutative rings, but that is hard to follow architecturally.)
95%+ of the time, even in my math-heavy repo, I'm using matrices over commutative rings. You get trace cyclicity, the general linear group, Cramer's rule with a proof that det A is invertible, and lots more nice things.
What are some thoughts on how to best design this?
All reactions