Skip to main content

msolveio

Strict Python I/O for msolve: canonical input, mode-required output. Gröbner mode (-g) and characteristic-0 rational-parametrization mode (-P). Bytes from any other msolve mode are rejected, not interpreted.

msolveio writes .ms files that msolve 0.10.x will parse the way you meant, and reads back only the one output language it can identify with certainty. It is not a CAS and not a Gröbner engine.

Install

pip install msolveio

You also need a system msolve 0.10.x binary on PATH (or pass binary=). msolveio has no runtime dependencies.

Usage

from msolveio import emit_system, parse_groebner, run_groebner, MsolveAmbiguous

source = emit_system(
    ["x^2+y", "x*y-1"],
    variables=["x", "y"],
    characteristic=0,
)

result = run_groebner(source, gb=2, timeout=60)

print(result.output.unit_ideal)  # False
print(result.output.basis)       # ('y^2+x', 'x*y-1', 'x^2+y')
print(result.msolve_version)     # '0.10.1'

emit_system raises MsolveInputError rather than rewriting input: parentheses, post-monomial division (x/2), repeated monomials, unknown identifiers, and coefficients that would overflow msolve's 64-bit read are all refused. Leading rationals (1/2*x) are allowed over Q only.

parse_groebner requires msolve's # comment header. That header is the only thing in the bytes that says which mode produced them, so it is load-bearing. Feeding it solver output raises MsolveAmbiguous instead of returning a basis:

parse_groebner("[-1]:")  # MsolveAmbiguous

This matters because the two languages invert each other. In solver mode [-1]: means no solutions; in Gröbner mode the unit ideal — the same fact — prints as [1]:. A parser that guesses gets the answer exactly backwards.

Rational parametrization (-P)

run_param runs msolve -P 2 and parses the rational univariate representation exactly. Every returned coefficient is a Python integer; nothing is a float, and nothing is eval'd. The result is one of three types — match on it, none is ever a silent empty list:

from fractions import Fraction
from msolveio import emit_system, run_param
from msolveio import RationalParametrization, EmptySolutionSet, PositiveDimensional

source = emit_system(["2*x-1", "3*y-1"], variables=["x", "y"], characteristic=0)
result = run_param(source, timeout=60)

assert isinstance(result.output, RationalParametrization)
result.output.w_ascending           # (-1, 3)      w(t) = 3t - 1, ascending, content kept
result.output.wprime_ascending      # (3,)         the denominator; checked to equal w'(t)
result.output.numerators_printed    # (ParamNumerator(v_ascending=(-3,), denominator_scale=2),)

result.chart.point_at(Fraction(1, 3))   # (Fraction(1, 2), Fraction(1, 3))

Read that worked example closely, because the conventions are load-bearing. The parameter t is the last printed variable (here y, so t = 1/3 at the point). Every earlier printed variable is recovered as

variable = -v(t) / (denominator_scale * w'(t))

so x = -(-3) / (2 * 3) = 1/2. The leading minus sign, the integer scale, the ascending coefficient order, and the kept integer content of w are all msolve's printed conventions, pinned as named dataclass fields and verified by the parser; a misread scale or sign would yield wrong witness points that still pass casual arithmetic, which is exactly the class of silent inversion this library exists to refuse.

msolve fixes non-generic systems silently: it may permute your variables, and may append an auxiliary variable tied to a linear form (always printed as A, even when that collides with one of yours). result.chart resolves all of that back onto your input chart — printed_index, added_variable, linear_form_input (t = -(c_1*x_1 + ...)), and one numerator per input variable under the uniform convention above. Consume the chart, not the printed order.

[-1]: parses to EmptySolutionSet and [1, nvars, -1, []]: to PositiveDimensional — typed results, not errors and not lists. Gröbner-shaped or solver-shaped bytes raise MsolveAmbiguous. A parametrization over a prime field raises MsolveCharPParamUnsupported: msolve's characteristic-p -P grammar differs, and half-parsing it with characteristic-0 conventions is the footgun, not the feature.

Passing precision=<bits> switches to msolve -P 1 -p <bits> and additionally returns real-root isolation boxes as exact Fraction pairs (msolve prints dyadic rationals, not floats), un-permuted to input order on the chart. Note that msolve parametrizes the radical: quotient_degree may exceed deg w, and multiplicity is not recoverable here.

ParamResult carries the same custody fields as RunResult: msolve_version, argv, wall_seconds, returncode, stderr, input_sha256, output_sha256.

Not supported in v0.2

  • Solver mode (real-root isolation without -P) — raises, and is never interpreted as a basis or a parametrization.
  • Parametrizations over prime fields — a typed raise, see above.
  • JSON output, Macaulay2 format, or any other msolve serialization.
  • sympy / flint / numpy interop. Gröbner basis elements are strings exactly as msolve printed them; parametrization coefficients are plain Python integers. One canonical representation, zero dependencies; convert downstream where your algebra lives.

A note on characteristic

msolve 0.10.1 labels some unlifted rational Gröbner bases as characteristic 0 regardless of whether a lift to Q actually happened. GroebnerOutput.characteristic reports what msolve printed and nothing more; msolveio does not pretend to know better.

License

MIT © 2026 DC Posch — https://github.com/dcposch/msolveio

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

msolveio-0.2.1.tar.gz (35.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

msolveio-0.2.1-py3-none-any.whl (27.8 kB view details)

Uploaded Python 3

File details

Details for the file msolveio-0.2.1.tar.gz.

File metadata

  • Download URL: msolveio-0.2.1.tar.gz
  • Upload date:
  • Size: 35.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for msolveio-0.2.1.tar.gz
Algorithm Hash digest
SHA256 6fe3957bae69a0d819faf8f0aec93fa84f44fa8dfc4b43033e3430d42ee52ee9
MD5 0bf0b9a129cb258316ff8948475cfbe1
BLAKE2b-256 2cfc9db9841842b6b12b32613ed4c3a71e84f1241688d5d1837f4eec3ddbbd84

See more details on using hashes here.

Provenance

The following attestation bundles were made for msolveio-0.2.1.tar.gz:

Publisher: publish.yml on dcposch/msolveio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msolveio-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: msolveio-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 27.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for msolveio-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b0e96ccdaca4fc16c1039b303d28ca2357705137b367a73b5abda62c6a865441
MD5 90591e8f6f39a67a275a87688f9940ad
BLAKE2b-256 7798239342ae73b01440e6f4ed34a8d5e7c5557c2b0fb6869c8faeeab74e17c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for msolveio-0.2.1-py3-none-any.whl:

Publisher: publish.yml on dcposch/msolveio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page