BYU-PRISM / GEKKO

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

Feature request: web app integration #175

Open MuTsunTsai opened 11 months ago

MuTsunTsai commented 11 months ago

My web app is looking for a MINLP solver, and I came across GEKKO which works perfectly for my use case when running locally. I was hoping to run GEKKO through Pyodide, but that seems impossible at this point, for:

I would really love to see a solution to this. This can be done by creating a Pyodide-compatible build of GEKKO, or by directly compiling APMonitor into WebAssembly and call it from JavaScript.

APMonitor commented 11 months ago

Thanks for the suggestion and for highlighting the challenge for running MINLP solutions in Pyodide. The Pyodide project looks very interesting with bringing Python functionality to the web-browser. I've added this as a feature request. I'm not sure if the mixed Fortran90 / C++ code will compile into WebAssembly with cpython-emscripten, but we'll look at it.

MuTsunTsai commented 5 months ago

@APMonitor I wonder if this project might help? https://github.com/StarGate01/Full-Stack-Fortran

APMonitor commented 5 months ago

Thanks for the link. Another way to tackle this is to set up a Flask server that can handle your MINLP request with a JavaScript version of a Gekko. Here's an example setup:

HTML + JavaScript:

This code creates a simple form in HTML to input the initial value for the variable y and sends it to the server to solve the equation (y^2 = 1) using Gekko.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gekko Optimization via JavaScript</title>
</head>
<body>
    <h1>Simple Gekko Solver</h1>
    <form id="gekkoForm">
        <label for="initialY">Initial y value:</label>
        <input type="text" id="initialY" name="initialY" value="2">
        <button type="button" onclick="sendData()">Solve</button>
    </form>
    <div id="result"></div>

    <script>
        function sendData() {
            var initialY = document.getElementById('initialY').value;
            fetch('http://your-server-address/solve', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({initialY: initialY})
            })
            .then(response => response.json())
            .then(data => {
                document.getElementById('result').innerText = 'Solution y: ' + data.result;
            })
            .catch((error) => {
                console.error('Error:', error);
            });
        }
    </script>
</body>
</html>

Python Server Code:

This is a simple Flask server application that receives the initial value, solves the optimization problem using Gekko, and sends back the result.

from flask import Flask, request, jsonify
from gekko import GEKKO

app = Flask(__name__)

@app.route('/solve', methods=['POST'])
def solve():
    data = request.get_json()
    initial_y = float(data['initialY'])

    m = GEKKO()            # Create GEKKO model
    y = m.Var(value=initial_y)  # Define variable, initial value from JS
    m.Equation(y**2 == 1)  # Define equation
    m.solve(disp=False)    # Solve

    return jsonify(result=y.value[0])

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Deployment:

This setup assumes that the server hosting the Python code is accessible through http://your-server-address. Adjust the URL in the JavaScript code to match your server's actual address.

The other option is to use the public server and have your pyiodide application create a gk0_model.apm file that can be transmitted to the server for solution. That way, you wouldn't need to host your own Flask server.

MuTsunTsai commented 5 months ago

@APMonitor Unfortunately, establishing such a backend is beyond the scope of my project. My main goal is to provide offline capability to my web app, so WASM solutions will be the top choices, and if I really need to do this with remote APIs, I might as well just use one from the NEOS server.