Skip to content

Add basic vector transforms equivalent to existing scalar ones, along with vector transform composition #142

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

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dom-linkevicius
Copy link

Addresses #141, but not only for TVShift but others too, with the ultimate goal of adding vector transform composition.

Initial PR is to kick off discussions about API, as working off of something should be easier. Also, initial PR does not contain vector transform compositions yet.

@dom-linkevicius
Copy link
Author

dom-linkevicius commented Jun 30, 2025

I think we should spend a bit of time discussing the API first.
Do you want to shift vectors by vectors (in which case we can just make it accept vector arguments), or vectors by scalars?
What would you combine it with?

@tpapp thoughts on the current code in vector.jl?

Copy link
Collaborator

@devmotion devmotion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be better to define an alternative to ArrayTransformation that transforms each element with a possibly different transformation.

Comment on lines +11 to +16
struct VectorIdentity <: VectorTransform
d::Int
function VectorIdentity(d)
new(d)
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This transform already exists in a more general form: as(Real, dims...)

If there are performance improvements possible I think it would be better to implement them this existing array transformation.

Comment on lines +37 to +42
struct VecTVExp <: VectorTransform
d::Int
function VecTVExp(d)
new(d)
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, a more general version of this transform already exists.

Comment on lines +58 to +63
struct VecTVLogistic <: VectorTransform
d::Int
function VecTVLogistic(d)
new(d)
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, also this already exists.

Comment on lines +73 to +78
"""
$(TYPEDEF)

Shift transformation `x ↦ x + shift`.
"""
struct VecTVShift{T<:Real} <: VectorTransform
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One could exploit muladd when not decomposing shifting and scaling (which in my experience are usually both needed) in separate steps.


dimension(t::VecTVShift) = length(t.shift)
transform_with(flag::LogJacFlag, t::VecTVShift, x::AbstractVector{T}, index::Int) where {T} = x .+ t.shift, logjac_zero(flag, T), index + dimension(t)
inverse_eltype(t::VecTVShift, T::Type) = eltype(T)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must also take into account the element type of the shift. Moreover, currently the compiler won't specialize on T.

Suggested change
inverse_eltype(t::VecTVShift, T::Type) = eltype(T)
inverse_eltype(t::VecTVShift, ::Type{<:AbstractVector{T}}) where {T<:Real} = promote_type(eltype(t.shift), T)

Shift transformation `x ↦ x + shift`.
"""
struct VecTVShift{T<:Real} <: VectorTransform
shift::AbstractVector
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type should be a type parameter T<:AbstractVector{<:Real}.

Comment on lines +84 to +86
function VecTVShift(val::Real, dim::Integer)
return VecTVShift(repeat([val;], dim))
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should just be

Suggested change
function VecTVShift(val::Real, dim::Integer)
return VecTVShift(repeat([val;], dim))
end
function VecTVShift(val::Real, dim::Integer)
return VecTVShift(fill(val, dim))
end

Ideally, though, I think users might want to use FillArrays here. To avoid additional dependencies and keep it more flexible, I'd remove this definition:

Suggested change
function VecTVShift(val::Real, dim::Integer)
return VecTVShift(repeat([val;], dim))
end

@dom-linkevicius
Copy link
Author

This transform already exists in a more general form: as(Real, dims...)
If there are performance improvements possible I think it would be better to implement them this existing array transformation.

@devmotion yes, I'm aware some of those already existed, just that in terms of API, I thought that if I want to have a concise/easier way to write compositions of vector transformations then something like

t =  VecTVExp(n) ∘ VecTVShift(x) ∘ VecTVScale(y)

would be preferable to

t =  as(Real, dims...) ∘ VecTVShift(x) ∘ VecTVScale(y)

Haven't tested for performance differences, will check.

I wonder if it would be better to define an alternative to ArrayTransformation that transforms each element with a possibly different transformation.

That would be a more general approach, yes, but unsure how error prone composition of such transformation would be. If I have AlternativeArrayTransformation ∘ AlternativeArrayTransformation, I may have very little guarantees of what each of them are and whether they should compose. I don't think this is the case for VectorTransformations. But I'm up to giving it a shot, if you think that's a non-concern and at the end I'd still be able to get compositions of vector transformations.

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

Successfully merging this pull request may close these issues.

2 participants