UNPKG

@casadi/casadi-wasm

Version:

CasADi — symbolic framework for algorithmic differentiation and numerical optimization, compiled to WebAssembly. Runs in Node.js with on-demand solver plugins (ipopt, fatrop, sundials, ...).

104 lines (93 loc) 4.46 kB
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>CasADi in the browser — @casadi/casadi-wasm via unpkg</title> <style> body { font: 14px/1.6 ui-monospace, Menlo, Consolas, monospace; margin: 2rem; max-width: 60rem; color: #222; } h1 { font-size: 1.2rem; } a { color: #1565c0; } #out { background: #f5f5f5; border: 1px solid #ddd; padding: 1rem; white-space: pre-wrap; min-height: 6rem; } button { font: inherit; padding: .35rem .9rem; margin-bottom: .6rem; } .err { color: #c62828; } small { color: #666; } </style> </head> <body> <h1>CasADi running in your browser 🐫</h1> <p><small>Loaded straight from <a href="https://unpkg.com/@casadi/casadi-wasm@3.8.0-beta.1/">unpkg</a> — no install, no server-side compute. Symbolic AD + an IPOPT solve, all WebAssembly.</small></p> <button id="run" disabled>Run again</button> <div id="out">Loading casadi.wasm from unpkg…</div> <script> "use strict"; // Pin the published prerelease. Use "@beta" to always track the latest beta. const BASE = "https://unpkg.com/@casadi/casadi-wasm@3.8.0-beta.1/"; // --- Self-contained browser loader ------------------------------------- // casadi.js is generated as CommonJS for Node (require('./casadi_wasm.js'), // require('path'), __dirname). We fetch it from unpkg and evaluate it in a // tiny CJS sandbox that supplies exactly those, so the unmodified file runs // in the browser. (Mirrors the package's own examples/_casadi_browser.js.) async function loadCasadi(base) { const evalCjs = async (file, requireFn) => { const resp = await fetch(base + file); if (!resp.ok) throw new Error(`${base + file}: ${resp.status} ${resp.statusText}`); const src = await resp.text(); const factory = new Function("module", "exports", "require", "__dirname", "__filename", src + "\n;return module.exports;"); const m = { exports: {} }; return factory(m, m.exports, requireFn, base.replace(/\/$/, ""), base + file); }; const createWasm = await evalCjs("casadi_wasm.js", (p) => { throw new Error("casadi_wasm.js: unexpected require " + p); }); const createcasadi = await evalCjs("casadi.js", (p) => { if (p.endsWith("casadi_wasm.js")) return createWasm; if (p === "path") return { join: (...a) => a.filter(Boolean).join("/").replace(/\/{2,}/g, "/") }; throw new Error("casadi.js: unexpected require " + p); }); return await createcasadi(); } // Plugin .so's are fetched lazily by name; redirect those bare requests to // unpkg so on-demand solver loading works cross-origin from a static page. const _fetch = window.fetch.bind(window); window.fetch = (u, o) => _fetch(typeof u === "string" && /^libcasadi_[\w]+\.so$/.test(u) ? BASE + u : u, o); // --- The demo ---------------------------------------------------------- async function demo(ca, log) { // JavaScript has no operator overloading: use ca.plus/minus/times, etc. const x = ca.SX.sym("x", 2); const [x0, x1] = ca.vertsplit(x); const f = ca.plus(ca.times(x0, x0), ca.times(x1, x1)); // f = x0^2 + x1^2 log("symbolic f = " + String(f)); // Algorithmic differentiation: exact Jacobian, evaluated numerically. const F = ca.Function("F", [x], [f]); const J = ca.Function("J", [x], [ca.jacobian(f, x)]); const xv = ca.DM([1.5, -2.0]); log("f([1.5, -2]) = " + String(F(xv))); log("∂f/∂x at that x = " + String(J(xv))); // Constrained optimization with IPOPT (loaded on demand from unpkg). log("\nloading ipopt…"); await ca.load_nlpsol("ipopt"); const nlp = { x: x, f: f, g: ca.minus(ca.plus(x0, x1), ca.SX(10)) }; // x0 + x1 - 10 const solver = ca.nlpsol("solver", "ipopt", nlp); const sol = solver.call({ lbg: ca.DM(0) }); // subject to g >= 0 log("argmin x0^2+x1^2 s.t. x0+x1 >= 10"); log(" x* = " + String(sol["x"])); log(" f* = " + String(sol["f"])); } // --- Wire up the page -------------------------------------------------- const out = document.getElementById("out"); const btn = document.getElementById("run"); const log = (...a) => { out.textContent += a.join(" ") + "\n"; }; const run = (ca) => { out.textContent = ""; return demo(ca, log); }; loadCasadi(BASE).then((ca) => { btn.disabled = false; btn.onclick = () => run(ca).catch((e) => log("FATAL: " + (e.message || e))); return run(ca); }).catch((e) => { out.textContent = "Failed to load casadi: " + (e.message || e); out.className = "err"; }); </script> </body> </html>