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.0.tar.gz (35.7 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.0-py3-none-any.whl (27.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: msolveio-0.2.0.tar.gz
  • Upload date:
  • Size: 35.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for msolveio-0.2.0.tar.gz
Algorithm Hash digest
SHA256 255b9e229d96088e1b87806007b2bc67ad6febffac30a263c5ec7ed4bf45e0e7
MD5 fa6e5045562e5289c7e42a3decf40d62
BLAKE2b-256 b44aaecf00031a4fcc32b3e8a8e677aa86eb7ad6b16729186799abf7657b7009

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for msolveio-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb01ca1a4084e2efa4495548bb53baa0ebceb74859552de485e1dfe4f39f9fa6
MD5 6411eabaefdf3367b9c33a9fd5899ee3
BLAKE2b-256 f5ecc40f110e8972a8e2088262a54602fe97f9e7efef2c07ba4d6a2925282d15

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

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