A Python ORM interface for building and solving clingo ASP programs
Project description
ASPAlchemy
ASPAlchemy is a Python library for building clingo ASP (Answer Set Programming) programs with a clean, object-oriented interface.
Term Hierarchy
The library is built around a rich hierarchy of term types that represent different ASP constructs:
Term(abstract base class)ComparableTerm(abstract: usable in comparisons; provides==,!=,<,<=,>,>=)Value(abstract, for basic values — also aBasicTerm)Variable(e.g.,X,Y)ConstantBase(abstract)Number(numeric constants, e.g.,42)String(string literals, e.g.,"hello")DefinedConstant(#const-defined constants, e.g.,max_size)Supremum/Infimum(#sup/#inf, the ordering's end markers;SUPandINFare the singletons)
Expression(arithmetic expressions, e.g.,X+Y*2)AggregateBase(abstract marker so core can recognize aggregates)Aggregate(abstract)Count,Sum,SumPlus,Min,Max
BasicTerm(abstract, can be direct predicate arguments:Value,Predicate,Pool)Predicate(e.g.,person(john, 42))Pool(abstract)RangePool(e.g.,1..5)ExplicitPool(e.g.,(1;3;5))
Negatable(abstract mixin:~buildsnot termon atoms; on plain comparisons it builds the complement — seeNot)Comparison(comparisons, e.g.,X < Y)DefaultNegation(default negation, e.g.,not p(X))
ConditionalLiteral(e.g.,p(X) : q(X))Choice(e.g.,{ p(X) : q(X) })
Core Concepts
Values
Values represent basic elements in an ASP program. Plain Python literals coerce
automatically wherever terms are expected — an int becomes an ASP number, a str
becomes a quoted ASP string. Variables you construct by hand, and bare atoms
(the n in direction(n)) are zero-arity predicates:
from aspalchemy import Predicate, Variable
X = Variable("X") # an ASP variable
n = Predicate.define("n", [], show=False)() # a bare atom: n, distinct from the string "n"
Predicates
Declare predicates as classes; fields are statically checked, so typos and missing arguments are type errors, and instances autocomplete:
from aspalchemy import Predicate, PredicateField
class Person(Predicate):
name: PredicateField
age: PredicateField
john = Person(name="john", age=30)
mary = Person(name="mary", age=25)
The ASP name defaults to the class name, snake-cased (HasSymbol becomes
has_symbol); class kwargs override it and set namespacing and visibility (class Pipe(Predicate, name="pipe_seg", show=False)). When the schema is only known at runtime, build the same thing
dynamically:
Edge = Predicate.define("edge", ["a", "b"])
For fully typed fields, annotate them as Field[int], Field[str], or
Field[SomePredicate]. Writes accept rule terms (Variables, Expressions) as
well as ground values, and are validated per field; reads are plain Python
values, statically typed — so solution atoms come back as real ints and strs:
from aspalchemy import ASPProgram, Field, Predicate
class Score(Predicate):
player: Field[str]
points: Field[int]
program = ASPProgram()
program.fact(Score(player="ada", points=3), Score(player="ben", points=5))
model = program.solve().first() # raises UnsatisfiableError if there is no model
total = sum(score.points for score in model.atoms(Score)) # plain ints
assert total == 8
Rules
Build rules with clear syntax:
from aspalchemy import ANY, ASPProgram, Variable
program = ASPProgram()
X, Y = Variable("X"), Variable("Y")
Adult = Predicate.define("adult", ["name"])
# Facts
program.fact(john)
program.fact(mary)
# Rules
program.when(Person(name=X, age=Y), Y >= 18).derive(Adult(name=X))
# Constraints
program.forbid(Person(name=ANY, age=Y), Y < 0)
Comparisons
Compare terms:
X < Y # Creates a comparison X < Y
Aggregates
Use aggregates for advanced computations:
from aspalchemy import ANY, Count, Variable
X = Variable("X")
count = Count(X, Person(name=X, age=ANY)) > 5
Solving
Solve your ASP program:
# Generate ASP code
asp_code = program.render()
print(asp_code)
# Solve
result = program.solve() # a lazy stream: consume the models you want
for model in result:
print("Solution found:")
for adult in model.atoms(Adult):
print(f" {adult}")
print(f"Satisfiable: {result.satisfiable}")
Diagnostics point at your code
Every statement remembers the Python line that authored it. A when() left
unclosed reports where it was opened; grounding diagnostics from clingo carry
a "generated by file:line" note back to your source;
program.render(annotate=True) appends a trailing % file:line comment to
each rule — without changing line numbers, so the annotated text doubles as
a map from raw-clingo error lines back to your source; and when a grounding
is slow or huge, program.ground().analyze_grounding() reports ground-atom
counts per signature, largest first, each joined back to the lines that
derive it. Frameworks built on
aspalchemy call register_skip_package() (whole package, or per-module dotted
prefixes) so locations point at their caller's code; mark a single helper
with @attribute_to_caller to attribute its statements to its call sites.
Switch capture off with ASPProgram(source_locations=False) when
generating rules in bulk.
Requirements
- Python 3.14+
- clingo 5.8+
License
MIT License
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 aspalchemy-1.0.0.tar.gz.
File metadata
- Download URL: aspalchemy-1.0.0.tar.gz
- Upload date:
- Size: 111.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6469efc6a51e9bb14017b4bc4f76237bfb46126e99a67214d083b93762736cb8
|
|
| MD5 |
5bea4bd9d7e959b677db95e82f1554f8
|
|
| BLAKE2b-256 |
68730537b40c51b4cdeed3ce657011a90baf01a464044683cac0a1f863443439
|
File details
Details for the file aspalchemy-1.0.0-py3-none-any.whl.
File metadata
- Download URL: aspalchemy-1.0.0-py3-none-any.whl
- Upload date:
- Size: 123.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8615954a9ec3ffb4c9cbdfafc4575d5a0313855a519d96e4bb6cc3c6fc264be
|
|
| MD5 |
5ce482bbdf3fc2fb0fac5df341dcf44d
|
|
| BLAKE2b-256 |
de38fe67050b975f2e1244f9016fa158258d58fc1348ba009d26af62093eff2b
|