MATLAB Interface for OptArrow
OptArrow includes a general MATLAB client for sending optimization models to the OptArrow Gateway.
The preferred MATLAB transport is Apache Arrow IPC:
MATLAB builds a plain model struct for an LP or QP problem.
Sparse matrices are serialized as COO arrays:
row,col,val, andshape.optarrow.computeconverts the request to a flat Arrow IPC stream.The request is posted to the Gateway endpoint.
The Arrow IPC response is decoded back into a MATLAB struct.
No Python interpreter is involved on the MATLAB client side. Python and Julia are still used by the OptArrow services behind the Gateway.
When the Apache Arrow MATLAB interface is not installed, the
client can fall back to the Gateway’s JSON route, /computeJSON. JSON
fallback is intended for setup verification and compatibility. Arrow IPC
remains the recommended path for large sparse models.
Files
The MATLAB client source is under src/matlab:
File |
Purpose |
|---|---|
|
Set global OptArrow runtime config |
|
Read global OptArrow runtime config |
|
Verify Gateway reachability and Arrow backend availability |
|
Generic Arrow IPC or JSON request/response call |
|
LP convenience wrapper |
|
QP convenience wrapper |
|
Optional bundled Apache Arrow MATLAB builds |
The MATLAB functions use the optarrow.* package namespace. Add the
src/matlab directory to the MATLAB path — MATLAB will automatically
discover the +optarrow package folder inside it.
Downstream integrations, such as COBRA Toolbox adapters, should keep toolbox-specific conversion and solver-dispatch logic outside this general MATLAB client.
Requirements
MATLAB R2023b or later.
A running OptArrow Gateway, usually at
http://127.0.0.1:8000/compute.Apache Arrow MATLAB interface for the preferred Arrow IPC path.
If Arrow is unavailable and transport is set to auto or json, the
client posts the same logical request to /computeJSON using MATLAB’s native
JSON support.
Set Up Apache Arrow for MATLAB
The Apache Arrow MATLAB interface provides native Arrow IPC serialization in MATLAB. OptArrow includes helper scripts to install it quickly on common platforms.
These steps assume you are working from the OptArrow repository:
git clone https://github.com/optArrow/optArrow.git
cd optArrow
Try the Bundled Linux Build
On Linux x86_64, OptArrow includes an experimental bundled Apache Arrow MATLAB build under:
src/matlab/vendor/apache-arrow/linux-x86_64/arrow_matlab
From MATLAB, run:
run scripts/setupMATLABArrow.m
The setup script first looks for the bundled Linux build. If it is found, it adds it to the MATLAB path, verifies it by constructing an Arrow record batch, and then saves the MATLAB path.
Verify manually with:
arrow.recordBatch(table(["A"; "B"], [1; 2]))
If MATLAB prints a RecordBatch, Arrow is ready.
Build Arrow If Needed
If setupMATLABArrow cannot find a usable build, or if MATLAB reports a
GLIBCXX_* runtime error while loading the bundled MEX file, build the
Apache Arrow MATLAB interface locally.
Install build prerequisites:
# Debian/Ubuntu
sudo apt install -y cmake build-essential
# macOS
xcode-select --install
brew install cmake
Then run:
./scripts/buildMATLABArrow.sh
The script clones Apache Arrow if needed, builds Arrow C++, builds the MATLAB bindings, and installs them by default to:
$HOME/arrow_no_s3
$HOME/arrow_matlab
After the build finishes, rerun the setup script from MATLAB:
run scripts/setupMATLABArrow.m
Or add the source-built interface manually:
addpath(fullfile(getenv('HOME'), 'arrow_matlab', 'arrow_matlab'));
savepath;
arrow.recordBatch(table(["A"; "B"], [1; 2]))
Optional S3-enabled build:
./scripts/buildMATLABArrow.sh --with-s3
The build paths can be customized with ARROW_REPO_DIR,
ARROW_CPP_INSTALL, and ARROW_MATLAB_INSTALL.
Why Models Must Be Serialized
The Gateway accepts Arrow IPC bytes on /compute. MATLAB structs, sparse
matrices, and cell arrays cannot be sent directly over HTTP as MATLAB objects.
Before posting a request, the MATLAB client serializes the optimization model
into Arrow-friendly columns.
For sparse matrices, the interface uses COO form:
[row, col, val] = find(A);
model.A = struct( ...
'row', row(:)' - 1, ...
'col', col(:)' - 1, ...
'val', val(:)', ...
'shape', [size(A, 1), size(A, 2)]);
Rows and columns are zero-based because the Gateway and Python/Julia engine
side expect zero-based matrix coordinates. Vector fields such as b, c,
lb, ub, and csense are packed as Arrow list columns. Solver options
are packed as parallel key/value string lists.
Most users should call optarrow.solveLP or optarrow.solveQP; these
wrappers build the serialized model payload. Use optarrow.compute directly
only when you already have an OptArrow payload struct.
Check Gateway Setup
Before solving, verify the Gateway is reachable and that the correct Arrow backend is selected:
report = optarrow.checkSetup();
disp(report)
Or with an explicit endpoint and a hard error on failure:
report = optarrow.checkSetup( ...
'http://127.0.0.1:8000/cobra/compute', ...
struct('throwOnError', true));
The returned report struct includes:
Field |
Meaning |
|---|---|
|
|
|
Resolved Gateway URL |
|
HTTP status code returned by the Gateway (0 if unreachable) |
|
|
|
Cell array of error messages (empty when |
Configure The MATLAB Client
Start the OptArrow Gateway first. From the repository root, one common local path is:
sh scripts/startAll.sh
Then configure MATLAB:
cfg = struct( ...
'engine', 'python', ...
'backendSolver', 'HiGHS', ...
'backendSolverType', 'LP', ...
'backendOptions', struct(), ...
'endpoint', 'http://127.0.0.1:8000/compute', ...
'timeoutSec', 120, ...
'transport', 'auto');
optarrow.setOptArrowConfig(cfg);
Supported MATLAB transports:
Transport |
Behavior |
|---|---|
|
Use Arrow IPC when Apache Arrow MATLAB is installed; otherwise use JSON |
|
Require Arrow IPC and fail if Apache Arrow MATLAB is unavailable |
|
Always use |
For JSON fallback, optarrow.compute rewrites a configured /compute or
/cobra/compute endpoint to /computeJSON.
Solve an LP
Maximise 3x + 2y subject to two inequality constraints:
lp = struct();
lp.A = sparse([1 1; 1 3]);
lp.b = [4; 6];
lp.c = [3; 2];
lp.lb = [0; 0];
lp.csense = ['L'; 'L']; % L = <=, E = =, G = >=
lp.osense = 'max'; % 'max' or 'min' (ub defaults to 1e30 when omitted)
result = optarrow.solveLP(lp);
disp(result)
Expected output:
success: 1
status: 'optimal'
stat: 1
obj_val: 11
solution: [3 1]
Solve a QP
Minimise x² + y² - 2x - 5y subject to x + y = 3. The ub
field is optional; optarrow.solveQP defaults it to 1e30.
QPproblem = struct();
QPproblem.F = sparse([2 0; 0 2]);
QPproblem.c = [-2; -5];
QPproblem.A = sparse([1 1]);
QPproblem.b = 3;
QPproblem.lb = [0; 0];
QPproblem.csense = 'E';
QPproblem.osense = 1; % minimise
result = optarrow.solveQP(QPproblem, struct('modelName', 'matlab_qp'));
disp(result)
Expected output:
success: 1
status: 'optimal'
stat: 1
obj_val: -7.125
solution: [0.75 2.25]
Submit a Generic Payload
A direct optarrow.compute payload should include:
problem_type:LPorQP.engine: backend engine name, for examplepythonorjulia.solver_name: backend solver name, for exampleHiGHSorGurobi.model_name: label used by the backend for logging/debugging.time_limit: solver time limit in seconds.solver_params: backend option struct.model: serialized LP/QP model struct.
Example:
payload = struct();
payload.problem_type = 'LP';
payload.engine = 'python';
payload.solver_name = 'HiGHS';
payload.model_name = 'my_lp';
payload.time_limit = 300;
payload.solver_params = struct();
payload.model.A = struct( ...
'row', int64([0; 1]), ...
'col', int64([0; 1]), ...
'val', [1.0; 1.0], ...
'shape', int64([2, 2]));
payload.model.b = [1.0; 1.0];
payload.model.c = [2.0; 3.0];
payload.model.lb = [0.0; 0.0];
payload.model.ub = [10.0; 10.0];
payload.model.csense = {'L'; 'L'};
payload.model.osense = 'max';
result = optarrow.compute(payload);
disp(result)
Response Struct
The decoded response is a MATLAB struct. Common fields include:
Field |
Meaning |
|---|---|
|
Logical success flag |
|
Backend status text |
|
Normalized numeric status: |
|
Objective value |
|
Primal solution vector |
|
Constraint duals, when available |
|
Reduced costs, when available |
|
Constraint slack, when available |
|
Backend method label, when available |
|
Backend solve time, when available |
Troubleshooting
If MATLAB cannot find
arrow.recordBatch, runscripts/setupMATLABArrow.m.If the bundled Arrow build fails with
GLIBCXX_*, build Arrow locally with./scripts/buildMATLABArrow.sh.If Arrow is not available and you only need a compatibility path, configure
transportasautoorjson.If HTTP requests fail, confirm the Gateway is running and the configured
endpointmatches the server route.If a sparse model gives incorrect dimensions, include
shapein the COO matrix struct or useoptarrow.solveLP/optarrow.solveQPto build it.If
optarrow.*functions are not found, confirm the installed MATLAB client is on the path as a+optarrowpackage.