@@ -7,9 +7,9 @@ The type `T` is meant to encode the largest acceptable space, so usually
77this enforces `p(dx)::T`. But some subspaces which aren't subtypes of `T` may
88be allowed, and in particular `dx::AbstractZero` always passes through.
99
10- Usually `T` is the "outermost" part of the type, and `p` stores additional
10+ Usually `T` is the "outermost" part of the type, and `p` stores additional
1111properties such as projectors for each constituent field.
12- Arrays have either one projector `p.element` expressing the element type for
12+ Arrays have either one projector `p.element` expressing the element type for
1313an array of numbers, or else an array of projectors `p.elements`.
1414These properties can be supplied as keyword arguments on construction,
1515`p = ProjectTo{T}(; field=data, element=Projector(x))`. For each `T` in use,
@@ -21,7 +21,19 @@ struct ProjectTo{P,D<:NamedTuple}
2121 info:: D
2222end
2323ProjectTo {P} (info:: D ) where {P,D<: NamedTuple } = ProjectTo {P,D} (info)
24- ProjectTo {P} (; kwargs... ) where {P} = ProjectTo {P} (NamedTuple (kwargs))
24+
25+ # We'd like to write
26+ # ProjectTo{P}(; kwargs...) where {P} = ProjectTo{P}(NamedTuple(kwargs))
27+ #
28+ # but the kwarg dispatcher has non-trivial complexity. See rules.jl for an
29+ # explanation of this trick.
30+ const EMPTY_NT = NamedTuple ()
31+ ProjectTo {P} () where {P} = ProjectTo {P} (EMPTY_NT)
32+
33+ const Type_kwfunc = Core. kwftype (Type). instance
34+ function (:: typeof (Type_kwfunc))(kws:: Any , :: Type{ProjectTo{P}} ) where {P}
35+ ProjectTo {P} (NamedTuple (kws))
36+ end
2537
2638Base. getproperty (p:: ProjectTo , name:: Symbol ) = getproperty (backing (p), name)
2739Base. propertynames (p:: ProjectTo ) = propertynames (backing (p))
@@ -41,13 +53,13 @@ function Base.show(io::IO, project::ProjectTo{T}) where {T}
4153end
4254
4355# Structs
44- # Generic method is to recursively make `ProjectTo`s for all their fields. Not actually
56+ # Generic method is to recursively make `ProjectTo`s for all their fields. Not actually
4557# used on unknown structs, but useful for handling many known ones in the same manner.
4658function generic_projector (x:: T ; kw... ) where {T}
4759 fields_nt:: NamedTuple = backing (x)
4860 fields_proj = map (_maybe_projector, fields_nt)
4961 # We can't use `T` because if we have `Foo{Matrix{E}}` it should be allowed to make a
50- # `Foo{Diagaonal{E}}` etc. We assume it has a default constructor that has all fields
62+ # `Foo{Diagaonal{E}}` etc. We assume it has a default constructor that has all fields
5163 # but if it doesn't `construct` will give a good error message.
5264 wrapT = T. name. wrapper
5365 # Official API for this? https://github.com/JuliaLang/julia/issues/35543
100112
101113julia> unthunk(pd(th))
1021143×3 Diagonal{Float64, Vector{Float64}}:
103- 1.0 ⋅ ⋅
104- ⋅ 5.0 ⋅
115+ 1.0 ⋅ ⋅
116+ ⋅ 5.0 ⋅
105117 ⋅ ⋅ 9.0
106118
107119julia> ProjectTo([1 2; 3 4]') # no special structure, integers are promoted to float(x)
156168# We assume (lacking evidence to the contrary) that it is the right subspace of numebers
157169# The (::ProjectTo{T})(::T) method doesn't work because we are allowing a different
158170# Number type that might not be a subtype of the `project_type`.
159- (:: ProjectTo{<:Number} )(dx:: Number ) = dx
171+ (:: ProjectTo{<:Number} )(dx:: Number ) = dx
160172
161173(project:: ProjectTo{<:Real} )(dx:: Complex ) = project (real (dx))
162174(project:: ProjectTo{<:Complex} )(dx:: Real ) = project (complex (dx))
@@ -407,7 +419,7 @@ function (project::ProjectTo{SparseVector})(dx::SparseVector)
407419 # When sparsity pattern is unchanged, all the time is in checking this,
408420 # perhaps some simple hash/checksum might be good enough?
409421 samepattern = project. nzind == dx. nzind
410- # samepattern = length(project.nzind) == length(dx.nzind)
422+ # samepattern = length(project.nzind) == length(dx.nzind)
411423 if eltype (dx) <: project_type (project. element) && samepattern
412424 return dx
413425 elseif samepattern
0 commit comments