Python API¶
The public pyfracessa package calls the native C++ analyzer in-process. Inputs are small dataclasses and every result is an
ordinary Python dictionary; no conversion from a result class is required.
Execution contract¶
Every execution function requires "safe" or "fast". safe is the complete exact route.
fast can miss candidates during its binary64 prefilter, although every surviving candidate and final stability decision is
exact. See Getting Started for method selection and matrix text formats.
run() and run_multiprocessing() have the same return modes:
Input |
Sink |
Return value |
|---|---|---|
One |
None |
One result dictionary. |
Iterable of matrices |
None |
A lazy iterator of result dictionaries. |
One matrix or an iterable |
Provided |
The number of result dictionaries written eagerly. |
Result dictionary¶
Every result contains the following fields:
Field |
Meaning |
|---|---|
|
Identifier supplied by the caller or generated for the complete wrapper call. |
|
Signed 64-bit identifier copied from the input matrix. |
|
Integer |
|
Number of exact equilibrium candidates retained by the ESS search, including circular multipliers. |
|
Number of ESS found by the selected method, including circular multipliers. The count is complete with |
|
Dictionary mapping support size to candidate count at that size. |
|
Dictionary mapping support size to ESS count at that size. |
|
Native analyzer duration in nanoseconds, measured with a monotonic clock; Python scheduling and file output are excluded. |
|
Whole-matrix |
|
Empty on success; otherwise the parser, execution, or worker diagnostic. |
|
Stored representative rows when |
|
The caller’s original matrix metadata dictionary, or |
The possible non-null whole-matrix fallback reasons are "precision_span", "equilibration_invalid", and
"equilibration_non_convergence".
Candidate counts are not a census of every algebraic Nash equilibrium. The complete safe ESS search can discard a singular
support immediately and, after finding an exact equilibrium support, skip its strict supersets because they cannot add another ESS.
full_support=True tests the full support before this ordinary search and can therefore retain a non-ESS full-support candidate
that the normal order would later skip. See Algorithm Overview for the precise search semantics.
Candidate dictionary¶
Each stored candidate contains:
Field |
Meaning |
|---|---|
|
One-based identifier of the stored representative in deterministic search order. |
|
Exact full-dimensional probability vector as comma-separated rational text; entries outside the support are zero. |
|
Arbitrary-precision integer bit mask for |
|
Bit mask for |
|
Number of distinct circular rotations/reflections represented by the row, or |
|
Whether exact stability checking accepted the candidate as an ESS. |
|
Machine-readable reason code for the stability decision. |
|
Exact rational payoff as text. |
|
Lossy binary64 approximation provided only for convenience. |
Counts and structures include every candidate found by the selected method even when representative rows are disabled. For large searches, leave candidates disabled unless their individual vectors are needed; candidate payloads can dominate memory and output volume.
Stability reason codes¶
Every candidate reason records the exact path that completed its stability decision:
Code |
ESS |
Meaning |
|---|---|---|
|
Yes |
A pure candidate has no other tied best reply. |
|
No |
The support-only reduced Hessian is not negative definite. |
|
Yes |
The reduced Hessian is negative definite and no outside best reply ties the payoff. |
|
Yes |
The remaining reduced Bomze matrix is strictly copositive. |
|
No |
The remaining reduced Bomze matrix is not strictly copositive. |
Core types¶
- class pyfracessa.StatusCode(*values)¶
Status values returned in every result dictionary.
- OK¶
Analysis completed successfully.
- PARSE_ERROR¶
The native parser rejected the matrix text.
- EXEC_ERROR¶
Analysis failed after parsing.
- INTERNAL_ERROR¶
The Python worker or native boundary caught an unexpected failure.
- class pyfracessa.Matrix(matrix_id, matrix, metadata=None)¶
Describe one matrix submitted for analysis.
- Parameters:
matrix_id (int)
matrix (str)
metadata (dict[str, Any] | None)
- matrix_id¶
Signed 64-bit identifier preserved in every output row.
- Type:
int
- matrix¶
Exact matrix text in
dimension#valuesor Matrix Market form. Values-only text is also accepted whenmetadatacontains an integerdimension.- Type:
str
- metadata¶
Optional user dictionary copied unchanged to the result and, when used, the sink’s metadata output.
- Type:
dict[str, Any] | None
matrixaccepts the full upper triangle of a symmetric matrix, the compact circular-symmetric layout described in Getting Started, or a complete Matrix Market document. Entries may be integers, fractions, exact decimals, or exact scientific notation.
- class pyfracessa.RunConfig(full_support=False, include_candidates=False, enable_logging=False)¶
Configure native analysis for sequential or multiprocessing execution.
- Parameters:
full_support (bool)
include_candidates (bool)
enable_logging (bool)
- full_support¶
Check the full support first. If the selected candidate route finds it and exact stability accepts it as an ESS, stop; otherwise continue the ordinary search without checking that support twice.
- Type:
bool
- include_candidates¶
Include individual representative dictionaries in
result["candidates"]. Counts and support-size structures for the selected method are returned regardless of this setting.- Type:
bool
- enable_logging¶
Write the native diagnostic trace for sequential execution. Multiprocessing rejects this option because workers cannot safely share the rotating log file.
- Type:
bool
- class pyfracessa.MPConfig(workers=4, prefetch_per_worker=128, queue_maxsize=4096, start_method='spawn')¶
Configure process scheduling for
run_multiprocessing().- Parameters:
workers (int)
prefetch_per_worker (int)
queue_maxsize (int)
start_method (Literal['spawn', 'forkserver', 'fork'])
- workers¶
Number of worker processes. The default is the CPUs available to the Python process; each worker analyzes one matrix at a time.
- Type:
int
- prefetch_per_worker¶
Pending-matrix allowance per worker. Together with
queue_maxsize, this bounds submitted work.- Type:
int
- queue_maxsize¶
Maximum serialized-result queue size and upper bound on the pending-matrix window.
- Type:
int
- start_method¶
Python multiprocessing start method. The portable default,
"spawn", requires the calling script to use anif __name__ == "__main__":guard.- Type:
Literal[‘spawn’, ‘forkserver’, ‘fork’]
Analyzer¶
- pyfracessa.new_run_id(prefix='run')¶
Return
prefixplus the current UTC timestamp to second precision.The result is convenient for output file names but is not a globally unique identifier when several calls use the same prefix during one second.
- Parameters:
prefix (str)
- Return type:
str
- pyfracessa.compute_matrix(method, matrix, config, run_id)¶
Compute one matrix with the native extension and return its canonical Python result.
This is the low-level public adapter used by
run()andrun_multiprocessing(). Candidate rows are augmented withrun_idandmatrix_id. Parser and analyzer failures are returned as nonzero status codes witherror_messagerather than raised by the native boundary.- Parameters:
method (Literal['fast', 'safe']) – Required candidate-search method.
"safe"is complete and exact;"fast"uses a potentially incomplete binary64 candidate filter before exact verification.matrix (Matrix) – Validated matrix input.
config (RunConfig) – Native analysis options.
run_id (str) – Identifier attached to the result and candidate rows.
- Returns:
The canonical result dictionary consumed by every sink. It contains
run_id,matrix_id,status, candidate and ESS counts and support-size structures, nativeelapsed_ns,safe_fallback,error_message, optional representativecandidates, and the originalmetadata.- Raises:
TypeError – If
methodor values-only dimension metadata has the wrong type.ValueError – If
methodis unknown or values-only matrix text has no dimension metadata.ModuleNotFoundError – If the native
fracessa_coreextension cannot be imported.
- Return type:
dict
- pyfracessa.run(method, matrices, config=None, run_id=None, sink=None)¶
Run matrix analysis sequentially.
A single
Matrixreturns one result dictionary immediately. An iterable returns a lazy iterator unlesssinkis provided; with a sink, all results are written eagerly and the number written is returned. Every matrix uses the same run ID and is completed before the next matrix begins. FracESSA imposes no per-matrix computation timeout.- Parameters:
method (Literal['fast', 'safe']) – Required candidate-search method.
"safe"is complete and exact;"fast"can miss candidates during its binary64 prefilter.matrices (Matrix | Iterable[Matrix]) – One matrix or an iterable of matrices.
config (RunConfig | None) – Analysis options; defaults to
RunConfig.run_id (str | None) – Output identifier; a timestamp-based ID is generated when omitted.
sink – Optional object providing
write_result(),close(), and optionallyabort().
- Returns:
One result dictionary, a lazy result iterator, or a written-result count.
- Raises:
TypeError – If
methodis not a string.ValueError – If
methodis unknown.
- Return type:
dict | Iterator[dict] | int
- pyfracessa.run_multiprocessing(method, matrices, config=None, run_id=None, sink=None, mp_config=None)¶
Run matrix analysis across worker processes.
A single
Matrixblocks and returns one result dictionary. An iterable returns a lazy completion-order iterator unlesssinkis provided; with a sink, all results are written eagerly and the number written is returned. Each worker analyzes one matrix at a time, so parallelism is across matrices rather than within one matrix. FracESSA imposes no per-matrix computation timeout.Submission is bounded by
min(queue_maxsize, workers * prefetch_per_worker). Closing the iterator before completion terminates its workers. An unexpected exception inside a worker becomes anINTERNAL_ERRORresult so one bad matrix cannot break the queue protocol. Scripts using the default"spawn"start method require anif __name__ == "__main__":guard.- Parameters:
method (Literal['fast', 'safe']) – Required candidate-search method.
"safe"is complete and exact;"fast"can miss candidates during its binary64 prefilter.matrices (Matrix | Iterable[Matrix]) – One matrix or an iterable of matrices.
config (RunConfig | None) – Analysis options; defaults to
RunConfig.run_id (str | None) – Output identifier; a timestamp-based ID is generated when omitted.
sink – Optional object providing
write_result(),close(), and optionallyabort().mp_config (MPConfig | None) – Process scheduling options; defaults to
MPConfig.
- Returns:
One result dictionary, a lazy result iterator, or a written-result count.
- Raises:
ValueError – If
config.enable_loggingis true.RuntimeError – If workers exit before returning every submitted result.
- Return type:
dict | Iterator[dict] | int
Multiprocessing notes¶
One worker analyzes one matrix at a time; parallelism is across matrices, and results are yielded in completion order. Submission is
bounded by min(queue_maxsize, workers * prefetch_per_worker). Closing an unfinished iterator terminates its workers. Scripts using
the default spawn method must protect their entry point with if __name__ == "__main__":. Native logging is sequential-only;
enabling it for a multiprocessing call raises ValueError before workers are started.
Input and output¶
- pyfracessa.load_matrices_from_json(path, matrices_key='matrices', id_key='id', matrix_key='matrix', dimension_key='dimension')¶
Load, validate, and sort matrices from a JSON file.
Supported input shapes:
{"matrices": [...]}[...]
Field names can be remapped with the key arguments. Extra row fields are preserved as metadata. Complete
dimension#valuesand Matrix Market strings are preserved after trimming; values-only matrix strings require an integer dimension field and are prefixed withdimension#.- Parameters:
path (str | Path) – JSON file to read.
matrices_key (str) – Top-level key containing rows when the document is an object.
id_key (str) – Row key containing the signed 64-bit matrix identifier.
matrix_key (str) – Row key containing the matrix string.
dimension_key (str) – Row key used to prefix values-only matrix strings.
- Returns:
Validated matrices sorted by
matrix_id.- Raises:
ValueError – If the JSON shape or any matrix row is invalid.
- Return type:
list[Matrix]
- pyfracessa.create_sink(kind, output_dir, run_id)¶
Create a CSV, JSON, or Parquet sink with run-specific file names.
The output directory is created when needed. Each sink writes separate summary, candidate, and metadata files and refuses to overwrite any of them.
- Parameters:
kind (str) – Case-insensitive
"csv","json", or"parquet".output_dir (str | Path) – Directory that will contain the output triplet.
run_id (str) – Identifier used in all three file names.
- Returns:
A new
CsvSink,JsonSink, orParquetSink.- Raises:
ValueError – If
kindis unsupported.FileExistsError – If any target output already exists.
- class pyfracessa.CsvSink(summary_path, candidates_path, metadata_path=None)¶
Write summary and candidate CSV files plus a metadata JSON sidecar.
Files are opened exclusively. A successful
close()preserves the output triplet;abort()closes and removes all three files.- Parameters:
summary_path (str | Path)
candidates_path (str | Path)
metadata_path (str | Path | None)
- abort()¶
Close and remove incomplete outputs; repeated calls are safe.
- Return type:
None
- close()¶
Finalize and preserve every output; repeated calls do nothing.
- Return type:
None
- write_result(result)¶
Write one canonical result and all of its candidate and metadata rows.
- Parameters:
result (dict)
- Return type:
None
- class pyfracessa.JsonSink(summary_path, candidates_path, metadata_path=None)¶
Write summary, candidate, and metadata arrays without retaining rows.
Files are opened exclusively. A successful
close()preserves the output triplet;abort()closes and removes all three files.- Parameters:
summary_path (str | Path)
candidates_path (str | Path)
metadata_path (str | Path | None)
- abort()¶
Close and remove incomplete outputs; repeated calls are safe.
- Return type:
None
- close()¶
Finalize and preserve every JSON array; repeated calls do nothing.
- Return type:
None
- write_result(result)¶
Write one canonical result and all of its candidate and metadata rows.
- Parameters:
result (dict)
- Return type:
None
- class pyfracessa.ParquetSink(summary_path, candidates_path, metadata_path=None)¶
Write batched summary and candidate Parquet files plus metadata JSON.
Rows are buffered in fixed-size batches before being passed to PyArrow. Files are opened exclusively and removed by
abort()after any failure.- Parameters:
summary_path (str | Path)
candidates_path (str | Path)
metadata_path (str | Path | None)
- abort()¶
Close and remove incomplete outputs; repeated calls are safe.
- Return type:
None
- close()¶
Flush, finalize, and preserve outputs; repeated calls do nothing.
- Return type:
None
- write_result(result)¶
Buffer one canonical result and its candidate and metadata rows.
- Parameters:
result (dict)
- Return type:
None
The JSON loader accepts either a top-level list or an object with a matrices list. By default each row uses id and matrix;
all other fields become metadata. A matrix row may contain complete dimension#values or Matrix Market text. Values-only text
requires an integer dimension field:
[
{"id": 1, "matrix": "3#-1,0,0,-2,0,-3", "source": "example"},
{"id": 2, "dimension": 3, "matrix": "4,13/2,1/2,5,11/2,3"}
]
For streamed output, create one sink and pass it directly to run() or run_multiprocessing(). The call then consumes all
matrices eagerly, closes the sink, and returns the number of written summaries:
from pyfracessa import RunConfig, create_sink, load_matrices_from_json, run
run_id = "example"
matrices = load_matrices_from_json("matrices.json")
sink = create_sink("json", "results", run_id)
written = run(
"safe",
matrices,
config=RunConfig(include_candidates=True),
run_id=run_id,
sink=sink,
)
All sinks create separate summary, candidate, and metadata outputs without overwriting existing paths. A failed construction, run,
write, or finalization removes only files created by that attempt and re-raises the original error. CSV and JSON preserve
arbitrary-width support integers. The current Parquet candidate schema is uint64 and rejects supports above 2^64 - 1 rather
than truncating them.