-
Notifications
You must be signed in to change notification settings - Fork 63
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
Change similar
, zero_matrix
, ones_matrix
to use UndefInitializer
constructors
#1909
base: master
Are you sure you want to change the base?
Conversation
This is incompatible with older Nemo versions.
b66d72c
to
ffa3842
Compare
similar
, zero_matrix
, ones_matrix
to use UndefInitializer
constructors
src/Matrix.jl
Outdated
z = Generic.MatSpaceElem{elem_type(R)}(R, arr) | ||
return z | ||
end | ||
zero_matrix(R::NCRing, r::Int, c::Int) = zero!(dense_matrix_type(R)(R, undef, r, c)) |
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.
Nice. This will allow some code deduplication in Nemo, where something like this is currently implemented for every Matrix type
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.
Well, not quite: there we often will want to omit the zero!
because the "undef" matrices are actually already zero initialized. E.g. for ZZMatrix
.
So they'd still have to have a method like
zero_matrix(R::ZZRing, r::Int, c::Int) = (dense_matrix_type(R)(R, undef, r, c))
or maybe rather
zero_matrix(R::ZZRing, r::Int, c::Int) = ZZMatrix(r, c)
However this made me realize a problem: we don't require the UndefInitializer
constructors to perform a sanity check on r
and c
(i.e. that they are >= 0
). And we probably don't want to (it is not needed when called from similar
).
So this method here should actually have such a check. But that's fine. And then we'd keep the existing zero_matrix
method for ZZRing
as it is. However, we could most or all of these methods from `fmpz_mat.jl:
function (a::ZZMatrixSpace)()
z = ZZMatrix(nrows(a), ncols(a))
return z
end
function (a::ZZMatrixSpace)(arr::AbstractMatrix{T}) where {T <: IntegerUnion}
_check_dim(nrows(a), ncols(a), arr)
z = ZZMatrix(nrows(a), ncols(a), arr)
return z
end
function (a::ZZMatrixSpace)(arr::AbstractVector{T}) where {T <: IntegerUnion}
_check_dim(nrows(a), ncols(a), arr)
z = ZZMatrix(nrows(a), ncols(a), arr)
return z
end
function (a::ZZMatrixSpace)(d::ZZRingElem)
z = ZZMatrix(nrows(a), ncols(a), d)
return z
end
function (a::ZZMatrixSpace)(d::Integer)
z = ZZMatrix(nrows(a), ncols(a), flintify(d))
return z
end
Well maybe the last one should be kept as it is a very minor optimization (as it avoids allocating to "convert" d
to a ZZRingElem
if it is a bit integer). Though as I said, very few people would go through that interface anyway, so maybe nothing to worry about too much...
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1909 +/- ##
=======================================
Coverage 88.17% 88.17%
=======================================
Files 120 120
Lines 30298 30266 -32
=======================================
- Hits 26715 26688 -27
+ Misses 3583 3578 -5 ☔ View full report in Codecov by Sentry. 🚨 Try these New Features:
|
There is still some unfortunate code duplication left, which currently forces matrix implementations to produce more code than idea. For example, there are two ways to construct a scalar matrix with a value
Currently the default implementations for these and similar methods are mostly independent, meaning matrix types need to overload both if they have optimized versions. In contrast, So we could follow that model and delegate this way. However, note that function (a::ZZMatrixSpace)()
z = ZZMatrix(nrows(a), ncols(a))
return z
end
function (a::ZZMatrixSpace)(d::ZZRingElem)
z = ZZMatrix(nrows(a), ncols(a), d)
return z
end versus function zero_matrix(R::ZZRing, r::Int, c::Int)
if r < 0 || c < 0
error("dimensions must not be negative")
end
z = ZZMatrix(r, c)
return z
end
# no custom diagonal_mat method in Nemo, but it might look like this:
function diagonal_matrix(d::ZZRingElem, r::Int, c::Int)
if r < 0 || c < 0
error("dimensions must not be negative")
end
z = ZZMatrix(r, c, d)
return z
end But overall I say we should not worry about this very minor inefficiency because, (a) it is negligible compared to the actual cost for allocating a matrix, and (b) hardly anyone will go through the matrix space API anyway. Here are some measurements to support my performance claim:
Here the mean time without the check even seems to 5 nanoseconds higher than that with the check. Of course that's just a fluke and if I repeat this several times it shifts around which one looks "faster". But that's kinda my point (and yeah of course I tested on my work laptop which means a bunch of stuff is running in the background; serious benchmarking needs a dedicated benchmark machine. But that seems irrelevant). Based on this I've now changed |
The NemoCI failures really confused me until I realized they are still with 0.47.3 not 0.47.4 -- turns out while Nemocas/Nemo.jl#1945 was merged last week, which marked Nemo 0.47.4, we never registered it. Oops! So I just triggered that and then the tests can re-run afterwards (and hopefully pass). Of course this is still breaking for Nemo <= 0.47.3, but I'd like to really be sure it works with newer versions (seems to be the case when I run the tests locally) |
This is incompatible with older Nemo versions which did not provide
UndefInitializer
constructors for their matrices. Thus I've added the "breaking" label.Note quite done yet, I'd like to convert more places to use theShould be OK to review now.undef
constructors.