Skip to content
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

Vector valued constraints + funccache #8

Closed
sonntagdaniel opened this issue Nov 15, 2017 · 6 comments
Closed

Vector valued constraints + funccache #8

sonntagdaniel opened this issue Nov 15, 2017 · 6 comments

Comments

@sonntagdaniel
Copy link

sonntagdaniel commented Nov 15, 2017

Hi, I wanted to add a vector valued constraint, doesn't seem to work properly though. Basically it runs, but seems to ignore the constraints. Maybe related to that: what is the point of _funcCache? It seems, that it is never called or used? As this here requires an nlopt_mfunc, I had to change the dictionary type to <Delegate, Delegate>, would this cause the problem?

public void AddLessOrEqualZeroConstraints(Func<double[], double[]> constraint, uint m, double[] tolerances)
{
    CheckInequalityConstraintAvailability();
    nlopt_mfunc mfunc = (_m, result, _n, values, gradient, data) =>
        {
            if (gradient != null)
              throw new InvalidOperationException("Expected the constraint to handle the gradient.");
            result = constraint.Invoke(values);
         };
     _funcCache.Add(constraint, mfunc);
     var res = nlopt_add_inequality_mconstraint(_opt, m, mfunc, IntPtr.Zero, tolerances);
     if (res != NloptResult.SUCCESS)
                throw new ArgumentException("Unable to add the constraint. Result: " + res, "constraint");
}
@BrannonKing
Copy link
Owner

The _funcCache exists to keep the callbacks from getting garbage-collected. We pass them to non-managed functions, which means that the GC doesn't recognize that they are still referenced and need to be kept around. Changing the data type on the cache should be fine. It will still perform its necessary purpose. GC.KeepAlive serves a similar purpose, but it didn't seem to fit this particular form of encapsulation.

@sonntagdaniel
Copy link
Author

OK, thanks, that's what I thought more or less, as it only apears in the Dispose().

Any idea why the code posted above might not work properly?

@BrannonKing
Copy link
Owner

It gives an error or doesn't execute correctly? I might need to see your new method footprints as well.

@sonntagdaniel
Copy link
Author

No errors, it executes, but the result of the optimization ignores the constraints. My guess is somewhere they receive only 0.0 all the time as constraint value, having them generally active for all x, and I figured most likely somewhere in the solver code, as I am least familiar with that ;) I'll post the rest of the code tomorrow.
Also, do you happen to know if NLOpt calls the constraint before or after the function is called?

@sonntagdaniel
Copy link
Author

OK so as already defined:

private delegate void nlopt_mfunc(
    uint m,
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), In, Out] double[] result,
    uint n, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In] double[] x,
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In, Out] double[] gradient,
    IntPtr data);

Then from NLopt:

[DllImport("libnlopt-0.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern NloptResult nlopt_add_inequality_mconstraint(IntPtr opt, uint m, nlopt_mfunc fc, IntPtr data, double[] tolerances);

The signatures of my custom function:

private double[] computeConstraintValues(double[] x)

And the call / assignment of the constraint:

solver.AddLessOrEqualZeroConstraints(computeConstraintValues, nConstraints, Enumerable.Repeat<double>(0.001, (int)nConstraints).ToArray());

Did I miss anything?

@sonntagdaniel
Copy link
Author

sonntagdaniel commented Dec 12, 2017

Thanks to a colleague I finally figured it out, the mfunc definition actually needs to be:

nlopt_mfunc mfunc = (_m, result, _n, values, gradient, data) =>
{
  if (gradient != null)
    throw new InvalidOperationException("Expected the constraint to handle the gradient.");
    double[] returnData = constraint.Invoke(values);

    Array.Copy(returnData, result, result.Length);
};

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