-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add elementary matrices constructors #21
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @rlschuller for the updated PR. It is very organized. I think we can do something more clever regarding the dimension of the matrices. Let's use I
from LinearAlgebra as an example again:
julia> using LinearAlgebra
julia> I * [1,2,3]
3-element Vector{Int64}:
1
2
3
It works even though we did not specify the dimension (=3). If you read their source you will see that they create a functor object that is dimensionless, and then when users type I(3)
this creates a Diagonal
instance. We can do something similar for our matrices so that when we use them in complicated expressions we don't need to type d
everywhere.
Take a look at equations 4.26 -- 4.30 after the table in the book and imagine these expressions full of d
, not very pleasant to read. We will use these equations to convert between the various types of covariance structure.
How to implement something similar to I
without reinventing the wheel? Take a look at FillArrays.jl and BlockArrays.jl. For example I would export the functor J = JMatrix()
and would write (J::JMatrix{T})(d) where {T} = Fill(one(T), d, d)
.
After we have this working with general dimension, we can check if the BlockArrays.jl approach introduces performance issues.
src/CoDa.jl
Outdated
@@ -26,6 +27,13 @@ export | |||
norm, dot, ⋅, | |||
distance, | |||
|
|||
# matrices | |||
JColumn, | |||
JMatrix, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why you didn't export J and j as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of the conflicting styles - structures should start w/ upper case letters according to the manual.
There're is also the problem of j
beeing a common indexation variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any suggestions for j
alternatives? Maybe Jc
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe for Julia
this doesn't apply, but the variables I use most frequently in nested for
loops are i
, j
and k
. Wouldn't j
for the column vector create confusion?
test/matrices.jl
Outdated
@test JColumn(d) == ones(d) | ||
@test JMatrix(d) == ones(d, d) | ||
@test F(d) == [I(d) -ones(d)] | ||
@test maximum(abs.(G(D) - I(D) + JMatrix(D)/ D)) < 1e-5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about norm(G(D) - I(D) + J(D) / D, Inf) < 1e-5
? The function norm
is available in LinearAlgebra.
test/runtests.jl
Outdated
@@ -3,6 +3,7 @@ using DataDeps | |||
using RData | |||
using CSV | |||
using Test | |||
import LinearAlgebra: I |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import LinearAlgebra: I | |
using LinearAlgebra |
test/matrices.jl
Outdated
@test JColumn(d) == ones(d) | ||
@test JMatrix(d) == ones(d, d) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rewrite these in terms of the shortcuts J
and j
after exporting these names.
src/matrices.jl
Outdated
Base.IndexStyle(::Type{<:JColumn}) = IndexLinear() | ||
Base.getindex(A::JColumn{T}, i::Integer) where {T} = one(T) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/matrices.jl
Outdated
struct FMatrix{T} <: AbstractMatrix{T} | ||
d::Int | ||
end | ||
FMatrix(d::Int) = FMatrix{Int}(d) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice that you are not consistent regarding the parameter type. For the Jmatrix you used Bool and here you used Int.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The elements in FMatrix
can assume negative values.
The elements in GMatrix
are fractional, so Float64
was chosen as the default. According to the Performance Tips section of the manual, the use of Real
types should be avoided in containers, but for in my tests Real
defaulted to Float64
and performed w/ the same speed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thank you for clarifying it 💯
src/matrices.jl
Outdated
end | ||
FMatrix(d::Int) = FMatrix{Int}(d) | ||
F(d::Int) = FMatrix(d) | ||
Base.size(A::FMatrix) = (A.d, A.d+1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base.size(A::FMatrix) = (A.d, A.d+1) | |
Base.size(F::FMatrix) = (F.d, F.d + 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unsure about how Julia would handle conflicts of names, if the arguments of the functions always overwrite the other variables w/ that name I agree that using F looks much more readable.
src/matrices.jl
Outdated
F(d::Int) = FMatrix(d) | ||
Base.size(A::FMatrix) = (A.d, A.d+1) | ||
Base.IndexStyle(::Type{<:FMatrix}) = IndexCartesian() | ||
Base.getindex(A::FMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*((i==j) - (j==(A.d+1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base.getindex(A::FMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*((i==j) - (j==(A.d+1))) | |
Base.getindex(F::FMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*((i == j) - (j == (F.d + 1))) |
src/matrices.jl
Outdated
end | ||
HMatrix(d::Int) = HMatrix{Int}(d) | ||
H(d::Int) = HMatrix(d) | ||
Base.size(A::HMatrix) = (A.d, A.d) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base.size(A::HMatrix) = (A.d, A.d) | |
Base.size(H::HMatrix) = (H.d, H.d) |
src/matrices.jl
Outdated
H(d::Int) = HMatrix(d) | ||
Base.size(A::HMatrix) = (A.d, A.d) | ||
Base.IndexStyle(::Type{<:HMatrix}) = IndexCartesian() | ||
Base.getindex(A::HMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*(i==j) + one(T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base.getindex(A::HMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*(i==j) + one(T) | |
Base.getindex(::HMatrix{T}, i::Integer, j::Integer) where {T} = one(T)*(i == j) + one(T) |
I didn't realize that |
Yes, it is a nice side effect of multiple-dispatch in the language. The product |
Codecov Report
@@ Coverage Diff @@
## master #21 +/- ##
==========================================
+ Coverage 82.10% 84.25% +2.15%
==========================================
Files 3 4 +1
Lines 95 108 +13
==========================================
+ Hits 78 91 +13
Misses 17 17
Continue to review full report at Codecov.
|
I guess we could eliminate JColumn from the list temporarily. My impression
is that most algebraic manipulations we will do can be expressed with just
the matrices.
…On Sun, Sep 12, 2021, 11:51 Rodrigo Schuller ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/CoDa.jl
<#21 (comment)>:
> @@ -26,6 +27,13 @@ export
norm, dot, ⋅,
distance,
+ # matrices
+ JColumn,
+ JMatrix,
Maybe for Julia this doesn't apply, but the variables I use more
frequently in nested for loops are i, j and k. Wouldn't j for the column
vector create confusion?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#21 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAZQW3NZP2YTRQFSTZXQYPTUBS46DANCNFSM5D3YICZA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
f0092ef
to
6cb339d
Compare
As defined by Aitchison 1986.
6cb339d
to
4389bfa
Compare
@rlschuller why you are closing the PRs instead of updating them in place? That way we loose all the suggestions in multiple places. |
As defined by Aitchison 1986.
A couple of observations regarding the choices of types:
Integer
fori
andj
, following LinearAlgebra.jl conventionsInt
for the variable inside the structure to avoid (re)allocation problems: it is used inF
andG
for the methodgetindex
The documentation was simplified to make it cleaner, but we can put the examples back.