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

Feature request: SetIpoptProblemScaling for FORTRAN interface #577

Closed
Steven-R-Hall opened this issue Jun 4, 2022 · 6 comments
Closed

Comments

@Steven-R-Hall
Copy link

Steven-R-Hall commented Jun 4, 2022

The Ipopt Fortran interface has all but one of the routines available in the C interface. The mapping between the two is:

IpStdCInterface             IpStdFInterface
------------------------    ------------------------------
CreateIpoptProblem          IPCREATE
FreeIpoptProblem            IPFREE
AddIpoptStrOption           IPADDSTROPTION
AddIpoptNumOption           IPADDNUMOPTION
AddIpoptIntOption           IPADDINTOPTION
OpenIpoptOutputFile         IPOPENOUTPUTFILE
SetIntermediateCallback     IPSETCALLBACK, IPUNSETCALLBACK
IpoptSolve                  IPSOLVE
GetIpoptCurrentIterate      IPGETCURRITERATE
GetIpoptCurrentViolations   IPGETCURRVIOLATIONS
SetIpoptProblemScaling

Would it be possible to add an additional routine, IPSETPROBLEMSCALING, to the Fortran interface? For our problems, scaling is important, and we're finding it difficult to work around the fact that it's not available. We have tried using a Fortran interface without much success.

Thanks!

@Steven-R-Hall
Copy link
Author

Steven-R-Hall commented Jun 5, 2022

Following up on the above, we were able to modify IpStdFInterface by adding the function:

IPOPTLIB_EXPORT ipindex F77_FUNC(ipsetproblemscaling, IPSETPROBLEMSCALING)(
    fptr*      FProblem,
    ipnumber*  obj_scaling,
    ipnumber*  x_scaling,
    ipnumber*  g_scaling
)
{
    ipindex retval;

    FUserData* fuser_data = (FUserData*) *FProblem;
    retval =  SetIpoptProblemScaling(fuser_data->Problem, *obj_scaling, x_scaling, g_scaling);

    return retval ? OKRetVal : NotOKRetVal;
}

Everything seems to work as expected when applied to a modified hs071_f.f in the examples. We compared the results to those obtained with cyipopt in python and the results agreed.

Also, if no x_scaling is desired, one can either pass an array populated with all 1s, or make x_scaling allocatable, and then don't allocate any memory to it, so that a null pointer is passed. In both cases it behaves as expected.

So while we have a workaround, it would be helpful still if this were added to the Ipopt package.

Thanks!

Edit: Fixed the return value passed by the function.

@svigerske
Copy link
Member

Sorry for the late reply.
I see no reason why one shouldn't allow setting a user scaling via the Fortran interface, too. Will have a look at this soon.

@svigerske
Copy link
Member

I'm adding ipsetproblemscaling in branch 577-fscaling: https://github.com/coin-or/Ipopt/compare/577-fscaling

I don't know much about Fortran, however. Can you let me know how to "make x_scaling allocatable"?
For instance, how would the example need to be modified so that, say, G_SCALING is received as NULL pointer on the C side?

@Steven-R-Hall
Copy link
Author

If a user knows that they are going to do (for example) x scaling, they don't need the array to be allocatable, so they can just do

  double precision X_SCALING(N)
  data X_SCALING / 1d0, 2d0, 3d0, 4d0 /

If they know they aren't going to do g_scaling, they could do

   double precision, allocatable, dimension(:)  :: G_SCALING

and nothing more. Then G_SCALING will have a null pointer. If they might do either (depending on some conditions such as program input), they can declare as allocatable as above, and then if they want to do g scaling, they would do

  allocate(G_SCALING(M))
  G_SCALING = (/ 1d0, 2d0 /)

and then of course G_SCALING will not have a null pointer. If they later want to not use g scaling, they can

  deallocate(G_SCALING)

and it will again have a null pointer.

For your example, I might suggest this:

  double precision X_SCALING(N)
  double precision, allocatable, dimension(:) :: G_SCALING
  ...
  data X_SCALING / 1d0, 2d0, 3d0, 4d0 /

as an example with one scaling used and the other not.

The allocate attribute is not available in F77, so to use the feature a user would have to declare and populate both the g scaling and x scaling arrays.

svigerske added a commit that referenced this issue Jun 24, 2022
- as suggested in #577
- requires Fortran > 77
@svigerske
Copy link
Member

I see. Thank you very much. I thought this may not work with F77.
I've added some comments to the example how to do this.

The IPSETPROBLEMSCALING will be available with the next release.

@Steven-R-Hall
Copy link
Author

Thanks so much for this addition!

One small problem in the documentation. The example works as is, but to work without g scaling, one has to change the two lines indicated in the comments, and in addition comment out the line

  data G_SCALING / 1d0, 1d0 /

since of course the variable G_SCALING isn't allocated.

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