An automated reasoner for the Non-Monotonic Multi-Succedent (NMMS) sequent calculus from Hlobil & Brandom 2025, Ch. 3.
Project description
pyNMMS
An automated reasoner for the Non-Monotonic Multi-Succedent (NMMS) sequent calculus from Hlobil & Brandom 2025, Ch. 3.
Documentation | PyPI | GitHub
Installation
pip install pyNMMS
For development:
git clone https://github.com/bradleypallen/pyNMMS.git
cd pyNMMS
pip install -e ".[dev]"
Quick Start
from pynmms import MaterialBase, NMMSReasoner
# Create a material base with defeasible inferences
base = MaterialBase(
language={"A", "B", "C"},
consequences={
(frozenset({"A"}), frozenset({"B"})), # A |~ B
(frozenset({"B"}), frozenset({"C"})), # B |~ C
},
)
reasoner = NMMSReasoner(base)
# A derives B (base consequence)
result = reasoner.derives(frozenset({"A"}), frozenset({"B"}))
assert result.derivable # True
# A does NOT derive C (nontransitivity — no [Mixed-Cut])
result = reasoner.derives(frozenset({"A"}), frozenset({"C"}))
assert not result.derivable # False
# A, C does NOT derive B (nonmonotonicity — no [Weakening])
result = reasoner.derives(frozenset({"A", "C"}), frozenset({"B"}))
assert not result.derivable # False
# Classical tautologies still hold (supraclassicality)
result = reasoner.derives(frozenset(), frozenset({"A | ~A"}))
assert result.derivable # True
CLI
# Create a base and add consequences
pynmms tell -b base.json --create "A |~ B"
pynmms tell -b base.json "B |~ C"
# Query derivability
pynmms ask -b base.json "A => B" # DERIVABLE
pynmms ask -b base.json "A => C" # NOT DERIVABLE
pynmms ask -b base.json "A, C => B" # NOT DERIVABLE
# Interactive REPL
pynmms repl -b base.json
Ontology Extension
The pynmms.onto subpackage extends propositional NMMS with ontology axiom schemas (subClassOf, range, domain, subPropertyOf, disjointWith, disjointProperties), enabling ontology reasoning while preserving nonmonotonicity.
from pynmms.onto import OntoMaterialBase
from pynmms.reasoner import NMMSReasoner
base = OntoMaterialBase(language={"Man(socrates)", "hasChild(alice,bob)"})
# Register ontology axiom schemas
base.register_subclass("Man", "Mortal") # {Man(x)} |~ {Mortal(x)}
base.register_range("hasChild", "Person") # {hasChild(x,y)} |~ {Person(y)}
base.register_domain("hasChild", "Parent") # {hasChild(x,y)} |~ {Parent(x)}
base.register_disjoint("Mortal", "Immortal") # {Mortal(x), Immortal(x)} |~
r = NMMSReasoner(base, max_depth=15)
r.query(frozenset({"Man(socrates)"}), frozenset({"Mortal(socrates)"})) # True
r.query(frozenset({"hasChild(alice,bob)"}), frozenset({"Person(bob)"})) # True
# Nonmonotonic — extra premises defeat ontology inferences
r.query(
frozenset({"Man(socrates)", "Immortal(socrates)"}),
frozenset({"Mortal(socrates)"}),
) # False
# CLI with --onto flag
pynmms tell -b onto_base.json --create --onto "atom Man(socrates)"
pynmms tell -b onto_base.json --onto --batch schemas.txt # batch with schema lines
pynmms ask -b onto_base.json --onto "Man(socrates) => Mortal(socrates)"
pynmms repl --onto
Key Properties
- Nonmonotonicity: Adding premises can defeat inferences (no Weakening)
- Nontransitivity: Chaining good inferences can yield bad ones (no Mixed-Cut)
- Supraclassicality: All classically valid sequents are derivable
- Conservative Extension: Logical vocabulary doesn't change base-level relations
- Explicitation Conditions: DD, II, AA, SS biconditionals hold
Implementation
Proof search strategy
The reasoner uses root-first backward proof search with memoization and backtracking. This is related to but distinct from the deterministic proof-search procedure in Definition 20 of the Ch. 3 appendix. Definition 20 specifies a deterministic decomposition: find the first complex sentence (alphabetically, left side first), apply the corresponding rule, repeat until all leaves are atomic, then check axioms. Our implementation instead tries each complex sentence in sorted order with backtracking — if decomposing one sentence fails to produce a proof, it backtracks and tries the next. Both approaches are correct because all NMMS rules are invertible (Proposition 27): if a sequent is derivable, any order of rule application will find the proof. Our approach adds memoization and depth-limiting as practical safeguards.
- 8 Ketonen-style propositional rules with third top sequent (compensates for working with sets rather than multisets, per Proposition 21)
- Memoization keyed on
(frozenset, frozenset)pairs; cycle detection via pre-marking entries asFalsebefore recursion - Depth-limited (default 25) to guarantee termination
- Deterministic rule application order (sorted iteration) for reproducible results
Design decisions
- Propositional core with ontology axiom schemas in
pynmms.ontosubpackage - Sets (frozensets), not multisets — Contraction is built in (per Proposition 21)
- Sentences represented as strings, parsed on demand by a recursive descent parser producing frozen
Sentencedataclass AST nodes - Base consequences use exact syntactic match — no subset/superset matching, which is what enforces the no-Weakening property
- Containment (Γ ∩ Δ ≠ ∅) checked automatically as an axiom schema
- No runtime dependencies beyond the Python standard library
Known limitations
- Depth limit can cause false negatives for deeply nested valid sequents
- No incremental/persistent cache between queries
- Multi-premise rules ([L→], [L∨], [R∧]) each generate 3 subgoals, giving worst-case exponential branching
- Flat proof trace only — no structured proof tree or proof certificates
- Formula strings re-parsed at each proof step (no pre-compilation)
- Does not implement NMMS\ctr (contraction-free variant, Section 3.2.3), Monotonicity Box (□, Section 3.3.1), or classicality operator (⌈cl⌉, Section 3.3.2)
Test suite
483 tests across 20 test files:
- Propositional core (307 tests): Syntax parsing, MaterialBase construction/serialization, individual rule correctness, axiom derivability, structural properties (nonmonotonicity, nontransitivity, supraclassicality, DD/II/AA/SS), soundness audit, CLI integration, logging/tracing, Ch. 3 worked examples, Hypothesis property-based tests, cross-validation against ROLE.jl ground truth
- Ontology extension (176 tests): Ontology sentence parsing, OntoMaterialBase construction/validation, six ontology schema types (subClassOf, range, domain, subPropertyOf, disjointWith, disjointProperties), nonmonotonicity and non-transitivity of schemas, lazy evaluation, NMMSReasoner integration, CommitmentStore, CLI
--ontointegration, JSON output/exit codes, batch mode, annotations, legacy equivalence, logging
Theoretical Background
This implements the NMMS sequent calculus from:
- Hlobil, U., & Brandom, R. B. (2025). Reasons for logic, logic for reasons: Pragmatics, semantics, and conceptual roles. Routledge.
NMMS codifies open reason relations — consequence relations where Monotonicity and Transitivity can fail. The material base encodes defeasible material inferences among atomic sentences, and the Ketonen-style logical rules extend this to compound sentences while preserving nonmonotonicity.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pynmms-0.5.0.tar.gz.
File metadata
- Download URL: pynmms-0.5.0.tar.gz
- Upload date:
- Size: 79.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23daa2256282a4a8b807ae6fb0dde7ecc2fe51e22fa3386122fc5ba4be706056
|
|
| MD5 |
5e201f7e1cb218d2cb7f81796820c13c
|
|
| BLAKE2b-256 |
4516564c3b5c7ac908f3aeb34d9ba13e9fca55e098f78bda936037c4c39a7e48
|
File details
Details for the file pynmms-0.5.0-py3-none-any.whl.
File metadata
- Download URL: pynmms-0.5.0-py3-none-any.whl
- Upload date:
- Size: 30.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76924a5d8f67da6fb500d0df9b4e779b72d7ea673e738dc38dc3b460d451af78
|
|
| MD5 |
df2aab668c2d1fd1bc305f94e6259cce
|
|
| BLAKE2b-256 |
fd07d27873c37a81aa807b4ee3239b073d02d81c70119882a87aa52c378f9d42
|