BYU-PRISM / GEKKO

GEKKO Python for Machine Learning and Dynamic Optimization
https://machinelearning.byu.edu
Other
595 stars 104 forks source link

Using a custom function in m.Equation #54

Closed ericman314 closed 3 years ago

ericman314 commented 5 years ago

GEKKO's solution for parsing expressions in m.Equation, m.Intermediate, and m.Obj is really slick. I understand that it simply uses operator overloading to construct a string version of the expression that is later parsed by APMonitor. Entering expressions into GEKKO this way is fast and intuitive.

However, there is currently no way to use a custom function:

def myComplicatedFunction(x):
  # ...Do work
  return result

m = GEKKO()
x = m.Var()
m.Obj( myComplicatedFunction(x) )

I understand that it would take a major architectural change to support this, as models are transmitted to APMonitor in string format. There appear to be some python libraries that can serialize functions, such as dill, but that might be a headache in itself, since if I'm not mistaken, APMonitor is not even written in python, so it would take some work to get the server to evaluate a custom function in this way. And having the server communicate over the wire to ask the client to evaluate an objective function probably wouldn't be fast enough unless the server was running locally.

Are there any plans to expose the powerful solvers of APMonitor in such a way that custom functions can be passed to them? I know it's possible to use the free solvers on their own, but then you lose all of the convenience that APMonitor provides. Here is another question I don't know the answer to: Does APMonitor examine the form of expressions symbolically to determine how to set up the problem, and which solver to use? Clearly, using the string expressions would be advantageous if this were the case.

APMonitor commented 5 years ago

This is a common request. Part of the reason that the solvers work efficiently is that they use exact 1st and 2nd derivatives. APMonitor parses and then compiles the equations into efficient byte-code, similar to Fortran speed, and provides the information to the solvers in sparse matrix form. A custom function would need to provide function evaluation and derivatives. There are very good AD tools so maybe this could be automated. If AD isn't available, a few judicious uses of finite differences may be possible but this could have a whole different set of problems and doesn't scale to large problems. GEKKO and APMonitor force users to create well-posed problems that have continuous first and second derivatives. See this simple absolute value example as a case of what happens with gradient-based solvers and functions that are not continuously differentiable: http://apmonitor.com/me575/index.php/Main/LogicalConditions Advanced users should be able to work around some of these issues.

I have a template that I use to create new custom objects such as these: http://apmonitor.com/wiki/index.php/Main/Objects Maybe we could use this template to provide an interface to an externally defined model where the user provides the model and derivatives. The GEKKO option m.options.DIAGLEVEL>=5 checks the 1st derivatives and m.options.DIAGLEVEL>=6 checks the 2nd derivatives. This could be applied to the custom model to verify that the user provided the correct derivatives.

ericman314 commented 5 years ago

I see. The problem isn't just with evaluating the function, but its derivatives as well. Unfortunately, the very types of functions that would require this feature probably have derivatives that are far more difficult to evaluate than the function itself, so making the user supply those could make the user experience daunting. Instead, requiring users to simplify the model to one that can be written in a single line may, in practical terms, lead to more efficient solutions and thus more added value for the user, even though the model may not be as accurate.

abe-mart commented 5 years ago

I know Casadi allows for custom user functions similar to what you are suggesting, but even they recommend avoiding it in most cases. (See section six of their documentation https://web.casadi.org/docs/). We've tossed the external function idea around several times because it would be very useful, but no one has come up with a great way to implement it yet. Has anyone ever looked into using complex step to supply the portions of the gradient that come from an external function?

On Fri, Feb 22, 2019, 8:23 PM Eric Mansfield notifications@github.com wrote:

I see. The problem isn't just with evaluating the function, but its derivatives as well. Unfortunately, the very types of functions that would require this feature probably have derivatives that are far more difficult to evaluate than the function itself, so making the user supply those could make the user experience daunting. Instead, requiring users to simplify the model to one that can be written in a single line may, in practical terms, lead to more efficient solutions and thus more added value for the user, even though the model may not be as accurate.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/BYU-PRISM/GEKKO/issues/54#issuecomment-466615243, or mute the thread https://github.com/notifications/unsubscribe-auth/ASiToRXu9J_wR3C1aqSJ69IWiyVNvlvpks5vQMIqgaJpZM4bMT1B .

billtubbs commented 5 years ago

I haven't really thought this through but is there any way that the simpy package could be integrated with GEKKO at the front end to help with the construction of equations maybe? Then the user or GEKKO could utilize sympy's diff method to find the derivatives algebraically.

APMonitor commented 3 years ago

No plans to add black-box models to Gekko. There is a new package in the works called Chameleon that may support these types of functions.