JuliaGeometry / CoordinateTransformations.jl

A fresh approach to coordinate transformations...
Other
180 stars 24 forks source link

Are transformations active or passive? #29

Open andyferris opened 7 years ago

andyferris commented 7 years ago

I foreseen this for a while, but I think this ambiguity is finally biting somewhere. See https://github.com/JuliaImages/ImageTransformations.jl/issues/25 for context.

The problem is that when you have a transformation, it isn't clear whether it is active or passive.

While the difference might seem pretty inane/abstract, I think the distinction can have important consequences. In ImageTransformations.jl the difference matters when your warp an image - are you moving the pixels to a new location, or is the "canvas" being warped (i.e. mapping a new canvas to pixels on the old canvas)? Note that the two transformations are inverses of one another (and further note that not all transformations are invertible, or otherwise that creating the inverse may be a slow/inaccurate operation).

I'm not yet certain what the solution is, but I feel that if it were clear whether a given transformation were to be interpretted as active or passive then these kinds of ambiguities would not occur downstream.

andyferris commented 7 years ago

I'll make suggestions separate to the OP. Here's my first. Feedback welcome/desired.

Note that many transformations (like those in Geodesy) are clearly passive, while other transformations like LinearMap, AffineMap and Translation are more likely to be seen as active (though I think this is ambiguous/arguable). I think one possible solution is to apply a trait to each transformation. We could use the type tree, e.g. abstract ActiveTransformation <: Transformation, but perhaps this could become less flexible for certain users (that might want this to be a type parameter or even data).

We can then apply the "active" trait to LinearMap and make a new, passive LinearTransformation, say. Things which are ...Map would generally be viewed as active.

c42f commented 7 years ago

Great summary. Particularly the point that we already have prototypical examples in Geodesy which are clearly passive and where a trait would work.

OTOH, I'm quite sure that generic pieces like AffineMap can't have a trait for this, without an extra type tag (ie, AffineMap{Active} vs AffineMap{Passive}) or distinct types AffineMapA vs AffineMapP. For example, consider AffineMap in two contexts:

These two uses will clearly be needed together, so it should be easy to convert between them.

andyferris commented 7 years ago

I was suggesting AffineMap (active) and AffineTransformation (passive).

Converting from one to the other should definitely be considered.

c42f commented 7 years ago

Right, makes sense.

What confuses me about this whole issue is I don't understand the practical benefit tagging as active vs passive will achieve. We could easily end up increasing the conceptual difficulties of active vs passive if we force people to think about them all the time, where in many cases it's a non-issue.

andyferris commented 7 years ago

Yeah, that's why it never made it in here so far.

One question here is this: is the composition of active and passive transformations considered to be active or passive? There's no reason to forbid them from being composed (the composition makes sense).

Anyway, I can't think of any solution that doesn't make life harder, on average.

timholy commented 7 years ago

I'm in favor of documenting that all transformations are passive.

andyferris commented 7 years ago

Hmm... is this right? Currently AffineMap, LinearMap and Translation are specified in the active sense (the inputs are the vector/matrix to apply to the points, not the axes).

While rotations are easily invertible, not all linear/affine maps are. How do I interpret a rectangular or singular LinearMap?

Evizero commented 7 years ago

Stupid question: What would be the difference implementation-wise between an active LinearMap and a passive LinearMap? To me as an domain outsider it looks like the only difference is how one "thinks" about what the transformation represents. Am I wrong in this?

timholy commented 7 years ago

Currently AffineMap, LinearMap and Translation are specified in the active sense (the inputs are the vector/matrix to apply to the points, not the axes).

As far as ImageTransformations goes, the points are the coordinates, so an active transformation on the coordinates is a passive transformation with respect to the image. This is why I'm not sure that adding this terminology would be all that helpful. In the end these are just functions that map one SVector to another, and I think we should keep it that way.

c42f commented 7 years ago

I'm in favor of documenting that all transformations are passive.

@timholy that doesn't really make sense to me. Then what about applications where an active interpretation is the natural one?

I'm actually quite happy with the way we currently define AffineMap, which is a purely algebraic operational definition based on the components:

help?> AffineMap
...
  A concrete affine transformation. To construct the mapping x -> M*x + v, use

  AffineMap(M, v)

  where M is a matrix and v a vector.
...

@Evizero that's right, it's an interpretation issue.

c42f commented 7 years ago

Oh, we overlapped there Tim. My comment was in relation to your previous one about just documenting everything is passive.

timholy commented 7 years ago

My fault, I was rushing through a week's worth of Julia email backlog...

singularitti commented 1 year ago

Is there any update on this issue? I am looking forward to a package that has passive transformations.

andyferris commented 1 year ago

Is there any update on this issue?

Well - not really.

As Tim alludes to above, such an interpretation really plays out when the user applies the transformation to do something. (E.g. in a ray tracer, you could either apply a transforms to the rays, or to the geometry the rays intersect with, and you'd get the same result either way perhaps with performance and/or rounding differences).

Further, users can use inv for inverses, and could overload pinv as necessary, so all the basic functionality to do either already exists.