-
Notifications
You must be signed in to change notification settings - Fork 112
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
Unitful linear algebra #46
Comments
Indeed the algorithm used in Akkinv = inv(A[k,k])
for i = k+1:m
A[i,k] *= Akkinv
end Other types for which |
Is there a plan to eventually resolve this issue or was this given up on? |
Depending on your use case, #191 might work? I don't know if I'll ever find the time to finish it, though. |
Thanks for the suggestion! Unfortunately it does not really help me because my use case involves large sparse LU factorizations ( |
The idea of stripping the units seems a bit limiting. For example this matrix has an inverse: julia> using Unitful: mm, s, kg
julia> A = [2mm^2 1mm*s; 1mm*s 2s^2]
2×2 Array{Quantity{Int64,D,U} where U where D,2}:
2 mm^2 1 mm s
1 mm s 2 s^2 but this one doesn't: julia> A = [2mm^2 1kg; 1kg 2s^2]
2×2 Array{Quantity{Int64,D,U} where U where D,2}:
2 mm^2 1 kg
1 kg 2 s^2 I think you'd want to find that out, by having the code throw an error when you tried to compute the factorization. I guess you could run a check at the beginning to see, and if it looks OK then you could trip units, compute the factorization, and assign the units retrospectively. But alternatively you could just write a unit-respecting implementation of LU factorization. Given that LU factorization is not a complicated algorithm, someone who wants this enough (@briochemc?) should just sit down and figure it out. The biggest problem, of course, is that it won't be inferrable if each entry has different units. So indeed you might want a special case for homogeneous arrays that leverages BLAS. Compared to computing the factorization, taking a copy or two is probably nothing ( |
Thanks for your comment. I think I understand and agree 😄 Although — and I may be wrong — I think the stripping is mandatory for many applications. In particular any case requiring sparse arrays will also require BLAS (and efficient sparse factorizations ala SuiteSparse) and have homogeneous units. For example, my most typical case is a discretized differential operator represented by a sparse matrix |
Yes, if you have homogeneous arrays then you will definitely get better performance using SuiteSparse and BLAS. In theory we're getting close to being able to write both libraries in Julia, with the same performance that the Fortran/C versions have, but I fear that's not a small project and might require more work on the compiler. |
Fishing for wisdom here: In your opinion, is it worth it to have a separate UnitfulSparse.jl package with Unitful sparse arrays in the vein of what Chris suggested? (I.e., that would strip and reattach units to allow sparse linear algebra operations) |
It might. Perhaps it would depend on how big of a deal it is. If it turns out to be quite short, perhaps adding it here would be better, but if it ends up being a big thing then I'd say a separate package makes a lot of sense. |
I believe it ought to be possible to design a
If the units |
I have another suggestion that probably is dumb, but here I go. When a matrix julia> using SparseArrays, LinearAlgebra, SuiteSparse
julia> using Unitful
julia> T = sprand(10, 10, 0.5) + I ;
julia> T = T * u"1/s" ;
julia> x = rand(10) * u"mmol/m^3" ;
julia> elunit(M::SparseMatrixCSC{U, Int}) where U = unit(U)
elunit (generic function with 1 method)
julia> elunit(x::AbstractVecOrMat{U}) where U = unit(U)
elunit (generic function with 2 methods)
julia> function LinearAlgebra.:\(M::SparseMatrixCSC{U, Int}, x::AbstractVecOrMat{V}) where {U<:Quantity, V<:Quantity}
if ~isconcretetype(U) || ~isconcretetype(V)
error("No mixed units for backslash")
else
return (ustrip.(M) \ ustrip(x)) * (elunit(M) / elunit(x))
end
end
julia> T \ x
10-element Array{Quantity{Float64,𝐋^3*𝐍^-1*𝐓^-1,Unitful.FreeUnits{(m^3, mmol^-1, s^-1),𝐋^3*𝐍^-1*𝐓^-1,nothing}},1}:
0.5218075428846516 m^3 mmol^-1 s^-1
-0.37126881733087075 m^3 mmol^-1 s^-1
-0.5717943786412751 m^3 mmol^-1 s^-1
0.6654072332256958 m^3 mmol^-1 s^-1
-0.489779363513709 m^3 mmol^-1 s^-1
-0.6341968692366408 m^3 mmol^-1 s^-1
0.8891121153540674 m^3 mmol^-1 s^-1
1.4828216212166003 m^3 mmol^-1 s^-1
0.24399317132721166 m^3 mmol^-1 s^-1
-0.1969247224331648 m^3 mmol^-1 s^-1 |
Actually maybe simpler would be to just let julia> using SparseArrays, LinearAlgebra, SuiteSparse
julia> using Unitful
julia> T = (sprand(10, 10, 0.5) + I) * u"1/s" ;
julia> x = rand(10) * u"mmol/m^3" ;
julia> elunit(M::SparseMatrixCSC{U, Int}) where U = unit(U)
elunit (generic function with 1 method)
julia> elunit(x::AbstractVecOrMat{U}) where U = unit(U)
elunit (generic function with 2 methods)
julia> LinearAlgebra.:\(M::SparseMatrixCSC{<:Quantity, Int}, x::AbstractVecOrMat{<:Quantity}) = (ustrip.(M) \ ustrip(x)) * (elunit(M) / elunit(x))
julia> T \ x
10-element Array{Quantity{Float64,𝐋^3*𝐍^-1*𝐓^-1,Unitful.FreeUnits{(m^3, mmol^-1, s^-1),𝐋^3*𝐍^-1*𝐓^-1,nothing}},1}:
-1.592883735567312 m^3 mmol^-1 s^-1
0.7810705179032268 m^3 mmol^-1 s^-1
0.506011915170795 m^3 mmol^-1 s^-1
0.9385158244984871 m^3 mmol^-1 s^-1
-0.7054928263619203 m^3 mmol^-1 s^-1
0.39630007844679466 m^3 mmol^-1 s^-1
-1.3477024041987156 m^3 mmol^-1 s^-1
1.0284718040639782 m^3 mmol^-1 s^-1
2.4997855862739455 m^3 mmol^-1 s^-1
-1.36216381582195 m^3 mmol^-1 s^-1 Please let me know if this sort of option is dumb or inefficient! |
BTW with all the movement I am unsure: should I keep discussing here or open another issue on the https://github.com/rigetti/Unitful.jl fork? |
For the time being I'd avoid splitting the discussion and continuing in rigetti/Unitful.jl, I believe the situation is still unclear |
I want to bring attention to my rough and partial attempt for Unitful linear algebra: https://github.com/goretkin/UnitfulLinearAlgebra.jl |
Maybe worth mentioning here that, at least for the simplest case in which you have dense arrays of homogeneous units, you can just reinterpret them: function LinearAlgebra.:\(A::Matrix{Q}, b::Vector{Q}) where {Q<:Quantity{Float64}}
A0, b0 = reinterpret(Float64, A), reinterpret(Float64, b)
A0 \ b0
end
@test A \ b isa StridedVector{Float64} This doesn't need to make a copy, nor define a (And clearly it could be done a bit more carefully, maybe for any |
Any idea when it will be solved? |
Need PainterQubits/Unitful.jl#46 to be solved
Here's a slight improvement on @mcabbott's answer, given that both the matrix and the vector have homogeneous, but not equal units. function LinearAlgebra.:\(A::Matrix{Q}, b::Vector{V}) where {Q<:Quantity{Float64}, V<:Quantity{Float64}}
ustrip(A)\ustrip(b) * (unit(b[1]) / unit(A[1,1]))
end
|
Some linear algebra operations like
\
have a hard time with unitful numbers. Take the following case:If you try
\
it gives a dimension error. If you try*
then it uses the generic*
fallback and not BLAS. The same is true if you use:I suggest trying something like, performing a dimensional analysis, strip the units, use the general
*
or\
, and then re-apply units.To do this properly, you might need a
UnitfulArray
instead of an array of Unitful values. I am not sure if stripping the units on an array of Unitful numbers can be done without making a temporary.The text was updated successfully, but these errors were encountered: