Closed cureos closed 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.
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_h
callback 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.
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.
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.