Skip to content

Commit

Permalink
Merge pull request #1097 from xor2k/master
Browse files Browse the repository at this point in the history
Add integrated Webdemo
  • Loading branch information
jajhall authored Feb 20, 2023
2 parents 8a11444 + aaa7b9c commit ce35101
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 1 deletion.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,7 @@ adlittle.lp
qjh.mps

*.whl
bazel*
bazel*

# webdemo
build_webdemo
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ option(PYTHON "Build Python interface" OFF)
option(FORTRAN "Build Fortran interface" OFF)
option(CSHARP "Build CSharp interface" OFF)

# emscripten
option(EMSCRIPTEN_HTML "Emscripten HTML output" OFF)

# set the correct rpath for OS X
set(CMAKE_MACOSX_RPATH ON)

Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,24 @@ Javascript

HiGHS can be used from javascript directly inside a web browser thanks to [highs-js](https://github.com/lovasoa/highs-js). See the [demo](https://lovasoa.github.io/highs-js/) and the [npm package](https://www.npmjs.com/package/highs).

Alternatively, HiGHS can directly be compiled into a single HTML file and used
in a browser. This requires `emscripten` to be installed from their website
(unfortunately, e.g. `sudo apt install emscripten` in Ubuntu Linux is broken):

https://emscripten.org/docs/getting_started/downloads.html

Then, run

sh build_webdemo.sh

This will create the file `build_webdemo/bin/highs.html`. For fast edit
iterations run

find src app | entr -rs 'make -C build_webdemo highs; echo'

This will rebuild `highs.html` every time a source file is modified (e.g.
from Visual Studio Code).

Python
------

Expand Down
5 changes: 5 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ endif()

target_link_libraries(highs libhighs)

if(EMSCRIPTEN AND EMSCRIPTEN_HTML)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
set_target_properties(highs PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/highs_webdemo_shell.html)
endif()

target_include_directories(highs PRIVATE
$<BUILD_INTERFACE:${HIGHS_SOURCE_DIR}/app>
)
Expand Down
73 changes: 73 additions & 0 deletions app/highs_webdemo_shell.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!doctype html>
<!-- compare https://github.com/emscripten-core/emscripten/blob/main/src/shell_minimal.html -->
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>HiGHS</title>
</head>
<body>
<div style="display: grid; grid-template-columns: 1fr 1fr">
<textarea id="input" style="height: 700px">
</textarea>
<textarea id="output"></textarea>
<button id="run">Optimize!</button>
</div>
{{{ SCRIPT }}}
<script type='text/javascript'>
main = async () => {
const printInTextarea = function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
// console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
}

const highs = await HiGHS({
print: printInTextarea,
printErr: printInTextarea
})

const inputTextarea = document.getElementById('input');
inputTextarea.value = `Maximize
obj: x1 + 2 x2 + 3 x3 + x4
Subject To
c1: - x1 + x2 + x3 + 10 x4 <= 20
c2: x1 - 3 x2 + x3 <= 30
c3: x2 - 3.5 x4 = 0
Bounds
0 <= x1 <= 40
2 <= x4 <= 3
General
x4
End`;

const element = document.getElementById('output');
const clearOutput = (v) => {
element.value = v || '';
}

clearOutput('Click on "Optimize!"') // clear browser cache

const runButton = document.getElementById('run');
runButton.addEventListener("click", () => {
clearOutput()
const inputFilename = 'inputFile.lp'
highs.FS.writeFile(inputFilename, inputTextarea.value)
highs.callMain([inputFilename])
})

}

main()

</script>
</body>
</html>
25 changes: 25 additions & 0 deletions build_webdemo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
script_path=$(realpath $(dirname $0))
build_dir="build_webdemo"

# interesting for Node.js: -sNODERAWFS=1, allows direct os filesystem access
LDFLAGS=$(echo $(cat << EOF
-sINVOKE_RUN=0
-sMODULARIZE=1
-sEXPORTED_RUNTIME_METHODS=['FS','callMain']
-sEXPORT_NAME='HiGHS'
-sSINGLE_FILE
-sALLOW_MEMORY_GROWTH=1
--shell-file ${script_path}/app/highs_webdemo_shell.html
EOF
))

# compare https://stackoverflow.com/a/6481016
physical_cores=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}')

cd ${script_path} &&
rm -rf ${build_dir} &&
mkdir ${build_dir} &&
cd ${build_dir} &&
LDFLAGS=$LDFLAGS emcmake cmake .. \
-DCMAKE_BUILD_TYPE=Release -DEMSCRIPTEN_HTML=on &&
emmake make -j ${physical_cores}

0 comments on commit ce35101

Please sign in to comment.