cureos / csipopt

.NET interface to Ipopt non-linear optimizer
http://code.google.com/p/csipopt/
Eclipse Public License 1.0
19 stars 11 forks source link

Running example with Mono yields NullReferenceException #2

Closed cureos closed 12 years ago

cureos commented 12 years ago

It is not sufficient to use the "classic" csipopt API with Mono any more. In the first call to a function delegate, the following exception is thrown:

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object at string.memcpy4 (byte*,byte*,int) <0x00018> at string.memcpy (byte*,byte*,int) <0x000b7> at (wrapper native-to-managed) Cureos.Numerics.IpoptProblem/JacobianEvaluator.Ev aluate (int,intptr,Cureos.Numerics.IpoptBoolType,int,int,intptr,intptr,intptr,in tptr) <0x00087> at (wrapper managed-to-native) Cureos.Numerics.IpoptAdapter.IpoptSolve (intptr,d ouble[],double[],double&,double[],double[],double[],intptr) <0x00003> at Cureos.Numerics.IpoptProblem.SolveProblem (double[],double&,double[],double[] ,double[],double[]) <0x0004f> at hs071_cs.Program.Main (string[]) <0x002af>

This happens regardless of which executable is being run with the Mono runtime, mcs or Visual C# compiled. On the other hand, when running an mcs compiled executable using the regular .NET runtime, the optimization problem is successfully solved.

cureos commented 12 years ago

Further examinations indicate that the problem might be due to the modification of the native delegate signatures. The same problem occurs when running Mono 2.6.7 (originally found the problem on Mono 2.10.6), so it does not seem to be related to Mono version at least. Keeping this issue open for the moment.

cureos commented 12 years ago

After further investigating this issue, I have some suspicion of what is going wrong. I have not yet been able to unambiguously confirm it, though.

The P/Invoke signature of the Eval_Jac_G_CB callback function is as follows:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IpoptBoolType Eval_Jac_G_CB(int n, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] x,
IpoptBoolType new_x, int m, int nele_jac,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] int[] iRow,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] int[] jCol,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] double[] values, IntPtr user_data);

Upon first call of this callback function from the Ipopt DLL, values is equal to null, indicating that iRow and jCol shall be defined. I suspect that the Mono runtime implicitly assumes that values is always initialized and tries to copy the contents based on the SizeParamIndex specification. In a strict sense this is probably correct, but the .NET runtime seems to be more forgiving in this sense.

I have enforced the Ipopt DLL to call the eval_f, eval_g and eval_grad_f callback functions prior to calling eval_jac_g by enabling the derivative checker, and these callback functions are sufficiently called when running via the Mono runtime. The exception is only thrown for the eval_jac_g function (and most likely for the eval_hcallback function, which uses the same initialization principle).

I will investigate further and try to come up with a workaround based on these findings. For the time being Mono uses are recommended to apply the csipopt 0.9 release, which do not have these marshaling issues.

cureos commented 12 years ago

I have now managed to solve this issue by changing the native callback signature when compiling for the Mono runtime. In the Eval_Jac_G_CB and Eval_H_CB delegates I now use IntPtr instead of arrays. In the evaluation wrapper methods for the managed delegates I perform the necessary copying from and to unmanaged memory.

The managed callback function signatures have not changed, so when running csipopt on the Mono runtime, the user is strongly recommended to only implement managed callback functions. When using the Mono adapted native callback functions, the user is required to implement the necessary copying between unmanaged pointers and managed arrays him/herself.