-
Notifications
You must be signed in to change notification settings - Fork 127
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
[WIP][SetParameters] Generalize to work for any type, rename to TypeParameterAccessors
#1331
Conversation
Also switch out SetParameter functions with ones provided by `Base`
…actor/rename_setparameters
@mtfishman Right now the new code compiles but I have not verified that tests pass. I will be working on this more today. I did some timing and see that the new code you wrote is roughly the same speed or faster than the previous implementation and uses slightly fewer allocations. |
TypeParameterAccessors
keep track
functions to `parameter.jl`
So far I have the |
…T/ITensors.jl into kmp5/refactor/rename_setparameters
`TypeParameterAccessor`
NDTensors/src/lib/TypeParameterAccessor/src/TypeParameterAccessor.jl
Outdated
Show resolved
Hide resolved
and add nparameters function
end | ||
|
||
Base.ndims(type::Type{<:BlockSparse}) = parameter(type, Base.ndims) |
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.ndims(type::Type{<:BlockSparse}) = parameter(type, Base.ndims) | |
Base.ndims(type::Type{<:BlockSparse}) = parameter(type, ndims) |
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't this just be a generic definition:
Base.ndims(type::Type) = parameter(type, ndims)
for any 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.
I don't think this is possible because BlockSparse
is a AbstractArray
so if we don't define Base.ndims(type::Type{<:BlockSparse)
then it will use the AbstractArray
version.
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.
Oh right, never mind. I was forgetting that would be type piracy, since Julia already defines Base.ndims(::Type{<:AbstractArray})
.
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.
See my comment above, we may want to define a TypeParameterAccessors.ndims
function.
arraytype_specified = specify_parameters( | ||
arraytype, parameter_names(arraytype), parameters(xs) | ||
) |
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'm still confused by this function call. What if parameter_names(arraytype)
doesn't correspond with the output of parameters(xs)
? For example, xs
could just have an element type parameter, in which case it just outputs something like (Float64,)
, but parameter_names(arraytype)
outputs (eltype, ndims, storagemode)
.
It seems like this should be:
arraytype_specified = specify_parameters(
arraytype, parameter_names(xs), parameters(xs)
)
instead.
@mtfishman So I think I need to go through all of the code and find where |
…ny functions that need to be assessed/removed
@mtfishman The changes from today address the |
Sounds like a good summary, thanks. |
NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl
Outdated
Show resolved
Hide resolved
NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl
Outdated
Show resolved
Hide resolved
@kmp5VT regarding the comment Miles made about how it is a bit strange for users to get For example, it could be defined like this: is_specified_parameter(param::TypeVar) = false
# Handles both `DataType`, or an `isbits` type parameter.
is_specified_parameter(param::Any) = true
function get_parameter(type::Type, pos)
param = parameter(type, pos)
!is_specified_parameter(param) && error("The requested type parameter isn't specified.")
return param
end With that kind of design, if we ever decided to change our design or convention for what is_parameter_specifed(type::Type, pos) = is_specified_parameter(parameter(type, pos)) which I think would be generally useful. Then, we should make definitions like |
default_parameter(::Type{<:AbstractArray}, ::Position{1}) = Float64 | ||
default_parameter(::Type{<:AbstractArray}, ::Position{2}) = 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.
What's the reasoning behind this change?
function get_parameter(type::Type, pos) | ||
param = parameter(type, pos) | ||
return _get_parameter(SpecifiedParameter(param), param) | ||
end | ||
|
||
function _get_parameter(::SpecifiedParameter{true}, parameter) | ||
return parameter | ||
end | ||
|
||
function _get_parameter(::SpecifiedParameter{false}, parameter) | ||
return error("The requested type parameter isn't specified.") | ||
end |
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'm not sure we really need the SpecifiedParameter
trait, I found it was sufficient for type stability just to do a runtime check of is_parameter_specified
, see https://gist.github.com/mtfishman/c3859d89f0d0c710f5a4cb11a782ae0c, and would be a lot simpler.
struct TypeParameter{P} end | ||
TypeParameter(x) = TypeParameter{x}() | ||
|
||
Base.Int(p::Position) = parameter(p) |
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.Int(p::Position) = parameter(p) | |
Base.Int(p::Position) = Int(parameter(p)) |
to make sure it really outputs Int
.
UnspecifiedFunction() = nothing | ||
|
||
function parameter_name(type::Type, p::Position) | ||
return error("There does not yet exist a name for the type $(type) at position $(int(p))") |
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.
return error("There does not yet exist a name for the type $(type) at position $(int(p))") | |
return error("There does not yet exist a name for the type $(type) at position $(Int(p))") |
return error("The default parameter of $(name) is not defined for type $(type)") | ||
end | ||
|
||
UnspecifiedFunction() = nothing |
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'm guessing this should be removed.
@test nparameters(Array) == 2 | ||
@test nparameters(Base.SubArray) == 5 | ||
end | ||
if VERSION ≥ v"1.8" |
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.
Here's a suggestion for avoiding this code duplication across tests. We can define our own macro:
using Test
macro inferred_above(version, expr)
quote
if VERSION ≥ $(version)
@inferred $(expr)
else
$(expr)
end
end
end
f(x) = x > 0.5 ? Int : Float64
@inferred_above v"1.7" f(0.2)
@inferred_above v"1.10" f(0.2)
which only tests inference if the version is at or above a certain value. So then we can use all of the same tests, and adjust the version as needed if we know inference fails on older versions but we don't care if that's the case.
Description
Rename the SetParameters package and utilize the type information provided by
DataType
and modify the package to use Base functions to change/access the parameters.Checklist:
SetParameters
toTypeParameterAccessors
#1327