Solver Backends: lang='java', lang='cpp'

The same Python model can be solved by any of LINE’s engines. Every solver constructor accepts a lang keyword that decides which codebase actually does the work. Nothing else in the model script changes:

from line_solver import *

MVA(model).avg_table()                 # native Python (default)
MVA(model, lang="java").avg_table()    # solved by the Java JAR (jline.jar)
MVA(model, lang="cpp").avg_table()     # solved by the C++ engine (line-cli)

This is what cross-checks a result without rewriting the model, and what makes another codebase’s faster or more precise engine reachable from a Python script.

Both delegated routes use the same transport: the model is serialized to model.json, the other codebase’s command-line front end solves it, and its JSON answer is read back into the usual result object, so avg_table() and the other getters behave exactly as they do natively. The banner a run prints names the engine that produced the numbers:

MVA analysis [method: default/mm1; type: exact, deterministic; lang: cpp; env: 3.14.6] completed in 5.253915s.

Setting the environment variable LINE_SOLVER_LANG to java or cpp changes the default for a whole session, without editing any script.

What each backend needs

lang='python' (default)

lang='java'

lang='cpp'

Engine

native Python

jline.jar

line-cli

Requires

nothing

a Java runtime

the line-cli binary

Solvers

all

all

MVA, NC, CTMC, MAM, FLD, SSA, BA, AG, AUTO, JMT, plus LN (steady state) and ENV

lang='java'

The JAR is located in $LINE_JLINE_JAR, then inside the installed package, then in a source checkout’s common/ directory; when none of these carries it, it is downloaded from SourceForge on first use. In practice the route works out of the box wherever java is on the path. It serves every solver, the LDES and LQNS wrappers included, and is the fastest option for large-scale and layered models.

The JAR can also be built from a checkout:

cd jar && mvn clean package -P b

lang='cpp'

The binary is located through $LINE_CLI_BINARY, then a checkout’s common/, then cpp/build/, then PATH. Build it from the source tree with:

cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Release
cmake --build cpp/build --target line-cli

LDES is deliberately absent from the solver list above: the Python LDES wrapper is already a subprocess client of that same C++ engine, so lang='cpp' there would only name the backend it is running on. LQNS wraps an external tool the C++ front end does not carry.

This backend additionally accepts an arith option, which has no meaning for the others, since MATLAB, the JAR and native Python are IEEE double throughout:

MVA(model, lang="cpp", arith="exact")        # exact rational arithmetic
MVA(model, lang="cpp", arith="real:64")      # 64-digit floating point

An analyzer that needs transcendental functions refuses arith="exact" by name and takes arith="real:<digits>" instead: NC, for one, forms throughputs as exp(lG(N-1) - lG(N)), which exact rational arithmetic cannot evaluate.

What falls back, and what does not

A missing or unrunnable binary (no build for this platform, a stale artifact, a missing shared library) is the one failure that falls back to native Python, with a warning. Every other failure – a construct the delegated analyzer refuses, a non-zero exit, unparseable output – is raised, because lang is an assertion about what produced the numbers: silently answering with a different engine would hide precisely the class of defect that cross-engine comparison exists to find.

See Also