Skip to content

Projection for x:: AbstractRange #437

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

Open
mcabbott opened this issue Aug 16, 2021 · 1 comment
Open

Projection for x:: AbstractRange #437

mcabbott opened this issue Aug 16, 2021 · 1 comment
Labels
ProjectTo related to the projection functionality

Comments

@mcabbott
Copy link
Member

mcabbott commented Aug 16, 2021

If we want something like JuliaArrays/FillArrays.jl#153 to project the gradient of a Fill onto a one-dimensional subspace, then I think we probably want something similar for the gradient of a range, but projecting onto a two-dimensional space, parameterised by the endpoints. Before I lose the bit of scrap paper I wrote this on, I think this would look as follows:

ProjectTo(x::AbstractRange) = ProjectTo{AbstractRange}()

function (project::ProjectTo{AbstractRange})(dx::AbstractVector)
    L = length(dx)
    μ = mean(dx)
    # δ = -sum(diff(dx))/2
    δ = sum(Base.splat(-), zip(dx, @view dx[2:end]))/2
    return LinRange(μ + δ, μ - δ, L)
end

(project::ProjectTo{AbstractRange})(dx::AbstractRange) = dx

Using LinRange allows for zero slope (e.g. for constant dx) and skips the high-precision machinery which StepRangeLen uses to hit endpoints exactly, as I don't think we're concerned about the last digit here. This isn't yet careful about element types etc.

@mcabbott mcabbott added the ProjectTo related to the projection functionality label Aug 16, 2021
@mcabbott
Copy link
Member Author

mcabbott commented Nov 8, 2021

The above formula is wrong. Correct versions are here: https://github.com/mcabbott/OddArrays.jl/blob/6c3ef3ab5ebf05c8aa6aa030590456200715be0f/src/OddArrays.jl#L814-L838

And the motivation is things like this:

julia> gradient(x -> (2 .* x)[1], 0:0.2:1)  # natural
([2.0, 0.0, 0.0, 0.0, 0.0, 0.0],)

julia> gradient(first, LinRange(0,1,5))  # structural
((start = 1.0, stop = nothing, len = nothing, lendiv = nothing),)

julia> gradient(x -> first(2 .* x), LinRange(0,1,5))
ERROR: DimensionMismatch("x and y are of different lengths!")
Stacktrace:
  [1] dot(x::Tangent{Any, NamedTuple{(:start, :stop, :len, :lendiv), Tuple{Float64, ZeroTangent, ZeroTangent, ZeroTangent}}}, y::LinRange{Float64, Int64})

julia> gradient(x -> first(LinRange(x,1,5)), 0)
(1.0,)

julia> gradient(x -> (2 .* LinRange(x,1,5))[1], 0)
ERROR: Need an adjoint for constructor LinRange{Float64, Int64}. Gradient is of type Vector{Float64}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ProjectTo related to the projection functionality
Projects
None yet
Development

No branches or pull requests

1 participant