patr-schm / TinyAD

Automatic Differentiation in Geometry Processing Made Simple
MIT License
371 stars 17 forks source link

Question regarding defining an objective on one-ring (element valence is not constant) #8

Closed jockyuiz closed 1 year ago

jockyuiz commented 1 year ago

Hi, I'm trying to define an objective that involves the shape operator, which evaluates the data on one-ring around each vertex. However, I only find objectives connected with constant variables in all the examples. I can't do something like func::add_element <valence> in a loop since it requires a const value inside<>. Is there any solution to this kind of objective? Thank you so much in advance!

patr-schm commented 1 year ago

Hi, this is currently the main limitation of TinyAD. It is only fast because elements have a small and constant size.

Here are two workarounds:

Workaround A Statically choose a maximum allowed vertex valence and use func.add_elements<max_valence>(..). You can then dynamically query the subset of variables that you actually want to use per vertex via element.variables(..). This means that per-element derivatives will just carry around a bunch of zeros when not all variables are used.

Run time performance will slow down a lot depending on max_valence. Another trick would then be to create element types for a number of common valences, like func.add_elements<5>(..), func.add_elements<6>(..), func.add_elements<7>(..), and use func.add_elements<max_valence>(..) only for all other vertices. This compiles slower but runs faster. I'd recommend this workaround.

Workaround B Use dynamic mode via TinyAD::Double<Eigen::Dynamic> for each element (not supported in the scalar_function interface) and assemble the global derivatives manually. But I don't really recommend that, because dynamic mode is much more limited, see #6.