Skip to content

Eager vs lazy composition, and transform_deriv_params #5

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

Closed
c42f opened this issue Jul 4, 2016 · 6 comments
Closed

Eager vs lazy composition, and transform_deriv_params #5

c42f opened this issue Jul 4, 2016 · 6 comments

Comments

@c42f
Copy link
Member

c42f commented Jul 4, 2016

I started implementing AffineTransformation which is pretty easy, except for one tricky design decision: should composition of specific AffineTransformation types eagerly compose into a composite AffineTransformation, or should they remain apart?

For most uses, I'm guessing eager composition is better since it'll be more efficient if you're just applying the transformation to many points. However, it's not a good idea if you want to optimize the parameters of one part of the transformation chain.

My current thought is that composition should be eager by default, but we could add a wrapper type for transformations to mark them as lazy. Come to think of it, maybe the wrapper type should be the signal that we're going to want derivative information in transform_deriv_params()? Currently there's no way to indicate which parts of a transformation chain should be differentiated...

Usage musings...

V = Translation(1.0, 2.0, 3.0)
R = ParameterizedTransform->RotationXY(θ))

# R1 = apply_params(R, 1.0) # RotationXY(1.0) ?

T = R  V

dTdθ = transform_deriv_params(trans, 1.0) # Evaluates derivative of T at θ = 1.0 ?
@andyferris
Copy link
Contributor

I'm also struggling with this decision. Here's one case that confounded me:

RotationXY(a) ∘ RotationYZ(b) ∘ RotationZX(c)

It's a toss-up if this is less efficient, and it's clear that it's a Euler rotation where you can easily read the order, so I've let them stay separate so far.

Additionally for Affine transformations, I can get confused about what order you add the displacement and multiply the matrix when I'm doing both forward and reverse transforms, so I've let that stay a composition. Then it's clear that

affine = rotation ∘ offfset

and

inv(affine) == inv(offset) ∘ inv(rotation)

I don't know - it stays clear in my head! And you don't have to change the displacement vector for the inverse!

Going the other way in design space, we could define more constructors. Have no greedy compositions, and let us define e.g.

function AffineTransformation(trans::ComposedTransformation)
    AffineTransformation(AffineTransformation(trans.trans1), AffineTransformation(trans.trans2))
end

AffineTransformation(t1::AffineTransformation, t2::AffineTransformation) = ... # pretty obvious

AffineTransformation(rot::Rotation) = AffineTransformation(rotmatrix(rot), Vec(0, 0, 0))

AffineTransformation(t::Translation) = AffineTransformation(identity, t.dx)

# etc...

Going further, AffineTransformation could simply be a typealias of a certain kind of ComposedTransformation...

@c42f
Copy link
Member Author

c42f commented Jul 5, 2016

Interesting point about the inverse and the two ways to represent an affine transformation. On the other hand, I think this problem could be addressed by providing a couple of well documented utility functions to recover the linear and translation parts of a given affine transformation:

trans = B  C  D  E

R, T = rotation_and_translation(trans) # Ugh, naming?
T, R = translation_and_rotation(trans)

In the branch I started working on, I already have those utility constructors for AffineTransformation since they're rather useful regardless of whether compose is eager or not.

@c42f c42f closed this as completed Jul 5, 2016
@c42f
Copy link
Member Author

c42f commented Jul 5, 2016

Argh, wrong button.

@c42f c42f reopened this Jul 5, 2016
@c42f
Copy link
Member Author

c42f commented Jul 20, 2016

A lot of this has been done now in #9, and it's become clear I think that eager composition is the right thing. In particular, eager composition of an arbitrary affine transformation chain produces the same type regardless of the number of affine transformations in the chain. So storing collections of composition chains is much more efficient if the composition is eager since all the transformation types are the same.

@andyferris
Copy link
Contributor

Agreed. I think this will turn out nicely.

We will still need a replacement for transform_deriv_params...

@c42f
Copy link
Member Author

c42f commented Aug 22, 2016

Remaining issues here are probably better covered by #6

@c42f c42f closed this as completed Aug 22, 2016
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

No branches or pull requests

2 participants