matt-weinstein / adigator

Matlab Algorithmic Differentiation Toolbox
22 stars 5 forks source link

"Conversion to double from cada is not possible " - Problems with for loops #6

Open VishnuDevA7 opened 4 years ago

VishnuDevA7 commented 4 years ago

Hi, Quite often with robots, the dynamics calculations involve three dimensional matrices, the third dimensions usually being the length of the time vector. For example, n-DoF robot has a (n x n) mass matrix and is expanded to nxnxt with time dimension. When I tried to use Adigator with 3 dimensional matrices, it did not allow me to have arrays greater than two dimensions. Therefore, I changed my dynamics file and converted 3 dimensional matrices to 2 dimensional matrices by stacking every time slice of the same along the 2nd dimension. Now my mass matrix is as (n x n*t). However, I cannot avoid using for loops. Now when I call adigator again, I get the error "Conversion to double from cada is not possible" exactly at the point where a for loop is employed. Is there a fix for this issue ?

matt-weinstein commented 4 years ago

Can you replicate the issue with some simple example code and provide matlab version? Loops have always been finicky, but something may have broken with a matlab update.

VishnuDevA7 commented 4 years ago

I was able to get around this problem by using cell arrays and manually break up matrices into vectors. Therefore nnt matrix had to be broken into n cell arrays of n*t dimensions. However, for systems of large dimensioanality this cannot be a solution.

VishnuDevA7 commented 4 years ago

I am trying to use Adigator for vectorized dynamics functions. Any for or while loops break the process. Can you give us an example of using a for loop in a dynamics function and then generating its AutoDiff code ?

To explain the context with clarity, at times, the computation of dynamics vector dq (size:n x 1) involves intermediate matrix (n x n) computation and inversion steps. In such a case, when using AdiGATOR along with direct collocation problems, the number of points m at which the dynamics function needs to be evaluated would be unknown beforehand (due to mesh refinement steps, etc.). Computing the dynamics in vectorized form would then involve arrays of three dimensions or arrays of stacked matrices. For both the approaches, one would have to query the size m of the input vector q (n x m) for which the dynamics is computed. Now when I determine m and use for/while loops to perform m matrix computations and inversions, I get the following error : ----------------------in the case of while loop-------------------------- Conversion to logical from cada is not possible. Error in robot_dyn>calc_J (line 127)

----------------------in the case of for loop-------------------------- Conversion to double from cada is not possible. Error in robot_dyn>calc_J (line 127)

Both the errors occur at the entry point in the loops. Therefore, can you show how to overcome this issue.

Even when I a double variable is used to store the size of an input variable inside the dynamics function, I can see that the double variable has become a cada variable and I am unable to use the double value that was stored.

VishnuDevA7 commented 4 years ago

I managed to vectorize most of the code and restrict the function to handle known size inputs. Adigtor was able to generate code for the derivative file. I use ICLOCS library (https://github.com/ImperialCollegeLondon/ICLOCS) which provides an interface to adigator. Strangely enough in the derivative file that is being generated there are unnecessary spaces or parse errors being generated in the variable names (eg. 'cada1f10 dY' instead of 'cada1f10dY'). There might be a possible bug, I have attached the generated file (its huge), the error first appears at line 11485., could you please check?

Func_Y_eLeg_Dynamics_Internal_Phase1.zip

matt-weinstein commented 4 years ago

That's an interesting one.. So it looks like it is failing from this line: %User Line: [dynF_org,gConst]=f(X,U,P,T,vdat); where the tool doesn't realize that f(X,U,P,T,vdat) is a function and is effectively unwrapping it. It is writing out computations for dynF_org okay, but breaking as it writes out the steps to compute gConst.

The naming of intermediate variables is set based off of the number of intermediate operations to evaluate a line of user code - something in that book-keeping process is breaking down. I will take a look when I get some spare cycles to allow for this behavior (I think it should be easy enough to replicate).

Also note: If you are attempting to put flow control (conditionals, loops), inside of the function f, that will most definitely break as the tool does not recognize f as being source code. This is probably the real challenge of getting it to work cleanly with this ICLOCS implementation..

What I have typically done in these scenarios is that you apply adigator directly to the user function, and then just have a wrapper that completes the chain rule for the scaling, etc. This would also (I think) only require ICLOCS to call adigator once per solution (from this file I am assuming that, if they are using mesh refinement, they are calling adigator once per NLP solve). This is probably the better answer, but I honestly haven't looked at the ICLOCS implementation in detail.

VishnuDevA7 commented 4 years ago

Thanks for the detailed reply. I have noticed that this breaking typically occurs when zeros are assigned to a variable after its initialization. For instance, if I initially declare a variable to be zeros of a particular size, adigator does not later allow me to perform assign any values to it, throwing the error : "conversion from double to cada not possible" So a workaround I tried was to assign some cada variable while intialization but later multiply it with a zero. Adigator generates the code but with parsing errors.

Another instance where the same errors occur is when the second output from a function uses variable(s) that are associated with the first output after the first output is computed. In [dynF_org,gConst]=f(X,U,P,T,vdat), for some reason, if gConst was computed after dynF_org and if it involved some variable that was used in the computation of dynF_org, then the same parsing errors were printed in the derivative file. To avoid this I had to always compute gConst before dynF_org. The same errors persist when I use separate subfunction to compute gConst and dynF_org. Yes, they could aa be related to the adigator function call in the ICLOCS implementation, however, its quite hard to debug these code generation errors at the moment.

matt-weinstein commented 4 years ago

The zero-initialization thing is a classical operator overloading issue - adigator typically doesn't have an issue with this because it is pre-parsing the source code and converting those zero-initialization matrices. Again, that isn't working here because the function implementation is hiding the source code contained in f.

I will take a look when I get some time - I was able to recreate the issue with some very simple code, but tracing through and debugging indeed takes time (particularly given that it has been quite some time since I've dug through the relevant code).