bertini.records

The casual face of the structured output directory: solve, save, load.

Every solve writes durable, plain-text records of what was computed (the directory explains itself: see its README.txt), and consults them before computing – so rerunning a script is always safe: instant if done, resuming if crashed, fresh if new. The records directory is ambient (BERTINI_RECORDS_DIR, else ./bertini_output); nobody is required to name it.

import bertini as pb sols = pb.solve(my_system, seed=42) # records + resumes automatically pb.save(sols) # or pb.save(“my favorites”, sols) pb.load(“my favorites”) # back, in any later session

Reading the records never requires bertini: JSON lines throughout – history/ (what was asked, when), results/ (one file per run: the computed paths and their metadata), definitions/ (the exact inputs, content-addressed). Power users keep the full solver-object API; these three verbs are sugar over it.

bertini.records.solve(system, seed=None, directory=None, precision='adaptive', endgame='cauchy', homotopy=None, start=None)[source]

Solve a polynomial system, recording and resuming automatically.

Ensure-answered semantics: the solve consults the ambient records directory first; paths already recorded for this exact ask (system + settings + seed) are taken from the records, and only the rest are computed. Rerun a crashed script and it finishes; rerun a finished one and it is instant.

Parameters:
  • system (System) – The target system (no path variable).

  • seed (int, optional) – The reproducibility seed. solve(sys, seed=42) means the same homotopy – the same gamma, start points, and patch – forever, on every machine. Omitted: an EFFECTIVE seed is derived for this solve and the solve runs under it, so the seed recorded in the run’s ask reproduces that run standalone – a mid-session solve does not silently depend on the session’s earlier draw history. (Consecutive seedless solves get distinct seeds, chained deterministically from set_random_seed’s master when one was set.)

  • directory (str, optional) – Records directory override; default is ambient (see records_dir).

  • homotopy (System, optional) – A homotopy you built (e.g. bertini.nag_algorithm.blend_homotopy()), for a CHAINED solve: its paths run from your start points at t=1 to system’s solutions at t=0. Requires start.

  • start (SolveResult or iterable of points, optional) – Where the paths start. A prior SolveResult (or its solutions) chains with full provenance – the records link every new endpoint back through the prior run, all the way to the beginning. Raw points (arrays) are archived as a given: provenance bottoms out honestly at data you supplied.

  • precision (str) – Passed through to bertini.nag_algorithm.ZeroDimSolver() (mptype / endgame).

  • endgame (str) – Passed through to bertini.nag_algorithm.ZeroDimSolver() (mptype / endgame).

Returns:

The finite solutions (as Solution points that remember their run) plus the run id – a claim ticket, safe to drop.

Return type:

SolveResult

bertini.records.save(*args, description='', directory=None)[source]

Save almost anything under a name: save(thing) or save(name, thing).

A SolveResult (or anything with .run_id and .solutions) is declared as results with full provenance; any JSON-able value (dict, list, number, string) is recorded inline. The declaration lands in history/ (the points themselves live in results/, referred to by {run, index}). A nameless save(thing) is auto-named by timestamp; re-saving a name replaces it (newest wins).

bertini.records.load(name=None, directory=None)[source]

Load saved results by name – the other half of save().

load("my favorites") returns that result (its points, annotations, provenance, or its inline value); load() returns the whole dict of everything saved, by name. Reads the plain records – declarations and annotations from history/, the referenced points from results/ – so this works in any later session, on any producer’s directory, and the same files are readable without bertini at all.

bertini.records.records_dir(path=None)[source]

Get (or set, by passing a path) the ambient records directory for this process.

Resolution when unset: the BERTINI_RECORDS_DIR environment variable, else ./bertini_output. Created on demand. Returns the resolved path as a string.

Ambient recording is ON BY DEFAULT for every solver in the process – ZeroDimSolver and HomotopySolver record here just like solve, with no code at all. Setting a path chooses WHERE: it is exported to BERTINI_RECORDS_DIR, which the solver classes read for their ambient attach. recording(False) is the off switch: while recording is off, nothing is exported and the off sentinel survives.

class bertini.records.Solution(coordinates, provenance=None, annotations=None)[source]

Bases: ndarray

A solution point: coordinates that remember where they came from.

Behaves exactly like the numpy array you expect (index it, print it, feed it to a solver), while carrying .provenance ({'run': ..., 'index': ...} – the recorded path that produced it) and .annotations invisibly. Arithmetic produces plain derived points: a computed combination is a new thing, and its provenance is honestly absent.

class bertini.records.SolveResult(solutions, run_id, directory, num_recalled, solver)[source]

Bases: object

What solve returns: the solutions plus a claim ticket on the recorded run.

Forgetting to capture it loses nothing – the records hold the truth; another solve of the same ask re-mints an equivalent result (recalled, not recomputed).

__init__(solutions, run_id, directory, num_recalled, solver)[source]
solutions

the finite solutions, user coordinates

Type:

list[Solution]

run_id

the recorded run’s id ({run, index} is a point reference)

Type:

str

directory

the records directory this run lives in

Type:

str

num_recalled

paths taken from the records instead of computed

Type:

int

property solver

The underlying solver object (all_solutions, solution_metadata, …).