Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c37b88f
Enhance CI workflow with MATLAB container cleanup
farid-zare Mar 6, 2026
6921cf9
Refactor Docker commands and add permissions fix step
farid-zare Mar 6, 2026
961248f
Fix formatting of optional input description
farid-zare Mar 6, 2026
760b8ad
Change CI environment check to use COBRA_CI variable
farid-zare Mar 6, 2026
58a898a
Refactor CI environment detection in test suite
farid-zare Mar 6, 2026
a0cfc5f
Refactor error handling for CI environment checks
farid-zare Mar 6, 2026
9535ed5
Update MATLAB Docker setup in CI workflow
farid-zare Mar 6, 2026
fa62207
Merge pull request #27 from farid-zare/testGurobi
farid-zare Mar 6, 2026
4d8fb2b
Fix comment formatting in compareModels.m
farid-zare Mar 6, 2026
611d98f
Fix workspace permissions for Docker execution
farid-zare Mar 6, 2026
3bc10b5
Merge pull request #28 from farid-zare/testGurobi
farid-zare Mar 6, 2026
b374f14
Fix permissions command and ensure newline at EOF
farid-zare Mar 11, 2026
2a20105
Configure git safe directory in CI workflow
farid-zare Mar 11, 2026
d32650e
Refactor changeObjective function documentation
farid-zare Mar 11, 2026
e7057da
Add requiredSoftwares parameter to prepareTest
farid-zare Mar 11, 2026
c1810bc
Fix workspace ownership and permissions for Docker
farid-zare Mar 12, 2026
f5c7cbc
Integrate EP solver and update related tests
farid-zare Mar 12, 2026
488b21e
Add EP solver to the test as a requirement
farid-zare Mar 12, 2026
a8ea00d
Improve assertions in testOptEnvelope.m
farid-zare Mar 12, 2026
312e393
Update testOptEnvelope.m
farid-zare Mar 12, 2026
adac0ee
Adjust tolerance in testOptEnvelope.m
farid-zare Mar 12, 2026
3851381
Merge pull request #2629 from opencobra/develop
rmtfleming Mar 16, 2026
63bb503
Merge branch 'opencobra:master' into master
farid-zare Mar 25, 2026
304af1c
Merge branch 'master' into testGurobi
farid-zare Mar 25, 2026
d7bc3a8
Enhance relax bounds handling in testCycleFreeFlux
farid-zare Mar 25, 2026
0bb91ac
Improve solution fallback logic in cycleFreeFlux
farid-zare Apr 1, 2026
33983e1
Update assertions for expected and actual results
farid-zare Apr 1, 2026
557b68d
Improve assertions for vertex equality in tests
farid-zare Apr 1, 2026
f045391
Merge pull request #32 from farid-zare/testGurobi
farid-zare Apr 1, 2026
5e8f254
Merge pull request #2636 from farid-zare/master
farid-zare Apr 1, 2026
b7531b6
Add normalization of CTRF test names
farid-zare Apr 1, 2026
62ef750
Update excluded solvers in testMOMA.m
farid-zare Apr 1, 2026
b0931cf
Add 'dqqMinos' to excluded solvers list
farid-zare Apr 1, 2026
009fb59
Update assertions to compare sorted vertex representations
farid-zare Apr 1, 2026
3102488
Improve test assertions and figure management
farid-zare Apr 2, 2026
81b38a9
Add OptArrow COBRA solver proof of concept
farid-zare Apr 2, 2026
a6d7e99
Merge pull request #33 from farid-zare/testGurobi
farid-zare Apr 2, 2026
9dd14a0
Merge pull request #2639 from farid-zare/master
farid-zare Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 72 additions & 24 deletions .github/workflows/testAllCI_step1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,120 @@ on:
- master
types: [opened, synchronize, reopened]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
runs-on: self-hosted
steps:
- name: Cleanup orphaned MATLAB containers
run: docker ps -q --filter ancestor=matlab | xargs -r docker rm -f
continue-on-error: true

- name: Check out merged PR code
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

- name: Install xvfb (skip if already installed)
- name: Fix workspace ownership and permissions for Docker
run: |
if ! command -v xvfb-run >/dev/null 2>&1; then
apt-get update -y
apt-get install -y xvfb
else
echo "xvfb already installed."
fi
sudo chown -R "$(id -u):$(id -g)" "${GITHUB_WORKSPACE}"
chmod -R o+rwx "${GITHUB_WORKSPACE}"

- name: Run MATLAB Tests (xvfb headless)
# MATLAB runs inside Docker
- name: Run MATLAB Tests in Docker (licensed MAC, xvfb headless)
env:
QT_QPA_PLATFORM: offscreen
JAVA_AWT_HEADLESS: "1"
run: |
xvfb-run -a -s "-screen 0 1280x1024x24" \
matlab -noFigureWindows -batch "try; run('initCobraToolbox.m'); set(0,'DefaultFigureVisible','off'); run('test/testAll.m'); catch ME; disp(getReport(ME,'extended')); exit(1); end; exit(0);"
set -euo pipefail
# Confirm MATLAB image exists
docker image inspect matlab >/dev/null
docker run --rm \
--mac-address="02:42:ac:11:00:02" \
--platform linux/amd64 \
-e HOME=/tmp \
-e USER=matlab \
-e LOGNAME=matlab \
-e COBRA_CI=1 \
-e QT_QPA_PLATFORM="${QT_QPA_PLATFORM}" \
-e JAVA_AWT_HEADLESS="${JAVA_AWT_HEADLESS}" \
-v "${GITHUB_WORKSPACE}:/work" \
-w /work \
--entrypoint bash \
matlab \
-lc '
set -euo pipefail
echo "Running inside container as:"
id
echo "HOME=$HOME"
echo "USER=$USER"
mkdir -p /tmp/.matlab /tmp/.MathWorks
echo "Configuring git safe directory..."
git config --global --add safe.directory /work
git config --global --add safe.directory "*"
echo "Starting MATLAB tests..."
xvfb-run -a -s "-screen 0 1280x1024x24" \
matlab -noFigureWindows -batch "try; \
run(\"initCobraToolbox.m\"); \
changeCobraSolver(\"gurobi\",\"all\",0); \
set(0,\"DefaultFigureVisible\",\"off\"); \
run(\"test/testAll.m\"); \
catch ME; \
disp(getReport(ME,\"extended\")); \
exit(1); \
end; \
exit(0);"
'

- name: Fix workspace permissions after Docker run
run: sudo chown -R "$(id -u):$(id -g)" "${GITHUB_WORKSPACE}"
continue-on-error: true

# New: ensure Node.js is present
- name: Set up Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Convert JUnit to CTRF
run: |
# Check Node.js version (optional guard)
MAJOR="$(node -p "process.versions.node.split('.')[0]")"
if [ "$MAJOR" -lt 20 ]; then
echo "❌ Node.js version too old: $(node -v). Please install Node 20 or newer."
echo "❌ Node.js version too old: $(node -v)"
exit 1
fi

# Print versions for debugging clarity
echo "✅ Node version: $(node -v)"
echo "✅ npm version: $(npm -v)"

# Ensure output directory exists
echo "✅ npm version: $(npm -v)"
mkdir -p ./ctrf

# Run conversion
echo "Converting JUnit XML to CTRF JSON..."
npx --yes junit-to-ctrf@0.0.12 ./testReport.junit.xml -o ./ctrf/ctrf-report.json

- name: Normalize CTRF Test Names
run: |
node -e '
const fs = require("fs");
const path = "./ctrf/ctrf-report.json";
const report = JSON.parse(fs.readFileSync(path, "utf8"));
for (const test of report.results?.tests || []) {
if (typeof test.name === "string") {
test.name = test.name.split(": ").pop();
}
}
fs.writeFileSync(path, JSON.stringify(report, null, 2) + "\n");
'

- name: Upload CTRF Artifact
uses: actions/upload-artifact@v4
with:
name: testReport
path: ./ctrf/ctrf-report.json

- name: Save PR Number
run: echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV

- name: Upload PR Number as Artifact
run: echo $PR_NUMBER > pr_number.txt
shell: bash

- name: Upload PR Number Artifact
uses: actions/upload-artifact@v4
Expand Down
3 changes: 2 additions & 1 deletion src/analysis/FBA/changeObjective.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
% Changes the objective function of a constraint-based model
%
% USAGE:
%
%
% model = changeObjective(model, rxns, objectiveCoeff)
%
% INPUTS:
Expand Down Expand Up @@ -41,3 +41,4 @@
else
model.c(rxnID) = objectiveCoeff;
end

4 changes: 2 additions & 2 deletions src/analysis/FBA/minimizeModelFlux.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
% model: COBRA model structure
%
% OPTIONAL INPUTS:
% osenseStr: Maximize ('max')/minimize ('min') (opt, default = 'min')
% osenseStr: Maximize ('max')/minimize ('min') (opt, default = 'min')
% minNorm: {(0), 'one', 'zero', > 0 , `n x 1` vector}, where `[m,n]=size(S)`;
% 0 - Default, normal LP,
% 'one' Minimise the Taxicab Norm using LP.
Expand Down Expand Up @@ -108,4 +108,4 @@

% Minimize the flux measuring demand (netFlux)
MinimizedFlux = optimizeCbModel(modelIrrev, osenseStr, minNorm);
end
end
24 changes: 22 additions & 2 deletions src/analysis/thermo/thermoFBA/cycleFreeFlux.m
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,28 @@
else
fprintf('%s','cycleFreeFlux: No quadratically regularised solution found. Relaxing LP version...');
qp = rmfield(qp,'F');
paramRelax.relaxedPrintLevel=1;
[solutionRelaxed, relaxedqp] = relaxedFBA(qp,paramRelax);
solutionLP = solveCobraLP(qp);
if solutionLP.stat==1 || solutionLP.stat==3
solution = solutionLP;
else
paramRelax.relaxedPrintLevel = 1;
try
[solutionRelaxed, relaxedqp] = relaxedFBA(qp,paramRelax);
if isfield(solutionRelaxed,'v') && ~isempty(solutionRelaxed.v) && all(isfinite(solutionRelaxed.v))
solution.stat = solutionRelaxed.stat;
solution.full = solutionRelaxed.v;
else
solutionRelaxedLP = solveCobraLP(relaxedqp);
if solutionRelaxedLP.stat==1 || solutionRelaxedLP.stat==3
solution = solutionRelaxedLP;
end
end
catch ME
if param.printLevel>0
fprintf('%s %s\n','cycleFreeFlux: relaxedFBA fallback failed:',ME.message);
end
end
end

end
case 'lp0'
Expand Down
82 changes: 82 additions & 0 deletions src/base/solvers/optarrow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# COBRA x OptArrow Proof Of Concept

This directory contains a minimal proof of concept for routing COBRA-style
`LPproblem` and `QPproblem` structs through OptArrow without using MATLAB's
native solver interfaces.

The current design deliberately keeps the integration thin:

- Convert a COBRA-style LP/QP struct into the OptArrow model schema.
- Call OptArrow's Python solver stack directly in-process.
- Map the result back into a COBRA-like solution struct.

This is a downstream adapter, not a patch to OptArrow itself. That keeps the
first proof small and avoids coupling COBRA to OptArrow's current MATLAB
client, which depends on MATLAB's Python bridge.

## Files

- `cobra_lp_adapter.py`: COBRA-style LP adapter for OptArrow.
- `cobra_lp_arrow_ipc.py`: Arrow IPC request/response helpers for the LP proof.
- `cobra_qp_adapter.py`: COBRA-style QP adapter for OptArrow.
- `run_optarrow_lp_poc.py`: Runnable end-to-end proof using a toy LP.
- `run_optarrow_lp_status_cases.py`: Runnable status sweep for optimal,
infeasible, and unbounded LPs.
- `run_optarrow_lp_arrow_ipc_poc.py`: Runnable file-based Arrow IPC LP proof.
- `run_optarrow_qp_poc.py`: Runnable end-to-end proof using a toy QP.
- `solveCobraLPOptArrow.m`: Thin MATLAB wrapper for the LP CLI bridge.
- `solveCobraQPOptArrow.m`: Thin MATLAB wrapper for the QP CLI bridge.

## Todo

- [x] Define a minimal COBRA LP to OptArrow model mapping.
- [x] Implement a thin, non-MATLAB-specific adapter.
- [x] Validate the path on a toy LP with a real solver backend.
- [ ] Add COBRA-compatible dual and reduced-cost extraction.
- [x] Extend the adapter to `QP`.
- [x] Define an Arrow IPC contract for the LP proof.
- [ ] Add support for `MILP` and `MIQP` once OptArrow exposes them cleanly.
- [x] Prototype MATLAB wrappers that call the thin adapter instead of `py.*`.

## Running The Proof

Create and populate the local proof virtualenv from the repository root:

```bash
python3 -m venv .venv_optarrow_poc
.venv_optarrow_poc/bin/python -m pip install pyarrow pyomo highspy scipy
```

Then run:

```bash
.venv_optarrow_poc/bin/python src/base/solvers/optarrow/run_optarrow_lp_poc.py
.venv_optarrow_poc/bin/python src/base/solvers/optarrow/run_optarrow_lp_status_cases.py
.venv_optarrow_poc/bin/python src/base/solvers/optarrow/run_optarrow_lp_arrow_ipc_poc.py
.venv_optarrow_poc/bin/python src/base/solvers/optarrow/run_optarrow_qp_poc.py
```

The scripts print:

- the COBRA-style problem
- the raw OptArrow solver result
- the mapped COBRA-like solution struct

The status sweep additionally verifies normalized COBRA-style statuses for:

- optimal (`stat = 1`)
- infeasible (`stat = 0`)
- unbounded (`stat = 2`)

and asserts the expected optimal objective value for the toy LP.

## Current State

- LP uses a direct HiGHS contract path and returns primal values, duals,
reduced costs, objective, and normalized statuses.
- LP now also has a file-based Arrow IPC proof so the solver boundary is not
tied to JSON.
- QP uses the current OptArrow Pyomo solver path and confirms objective,
primal values, and normalized statuses.
- The MATLAB wrappers are thin shims that keep COBRA-specific adaptation in
the COBRA Toolbox rather than in OptArrow itself.
Loading
Loading