Python wrapper around Clingo/Answer Set Programming
Project description
<p align="center">
<img src="clyngor.png"/><br>
</p>
Handy python wrapper around [Potassco's Clingo](https://potassco.org/) [ASP solver](https://en.wikipedia.org/wiki/Answer%20set%20programming).
## Example
Clyngor offers multiple interfaces. The followings are all equivalent.
(they search for [formal concepts](https://en.wikipedia.org/wiki/Formal_concept_analysis))
from clyngor import ASP, solve
answers = ASP("""
rel(a,(c;d)). rel(b,(d;e)).
obj(X):- rel(X,_) ; rel(X,Y): att(Y).
att(Y):- rel(_,Y) ; rel(X,Y): obj(X).
:- not obj(X):obj(X).
:- not att(Y):att(Y).
""")
for answer in answers:
print(answer)
The same, but with the lower level function expecting files:
answers = solve(inline="""
rel(a,(c;d)). rel(b,(d;e)).
obj(X):- rel(X,_) ; rel(X,Y): att(Y).
att(Y):- rel(_,Y) ; rel(X,Y): obj(X).
:- not obj(X):obj(X).
:- not att(Y):att(Y).
""")
More traditional interface, using file containing the ASP source code:
answers = solve('concepts.lp'): # also accepts an iterable of file
More examples are available in [the unit tests](clyngor/test/).
## Chaining
Once you get your answers, clyngor allows you to specify
the answer sets format using builtin methods:
for answer in answers.by_predicate.first_arg_only:
print('{' + ','.join(answer['obj']) + '} × {' + ','.join(answer['att']) + '}')
And if you need a [*pyasp-like*](https://github.com/sthiele/pyasp) interface:
for answer in answers.as_pyasp:
print('{' + ','.join(a.args()[0] for a in answer if a.predicate == 'obj')
+ '} × {' + ','.join(a.args()[0] for a in answer if a.predicate == 'att') + '}')
Currently, there is only one way to see all chaining operator available:
[the source code of the Answers object](clyngor/answers.py).
(or `help(clyngor.Answers)`)
## Debugging
TODO: Clyngor is also able to parse an ASP program to generate debugging help.
## Solver scripting
TODO: Clyngor is able to manage python inside ASP source code, allowing user to fully control the solving.
## Alternatives
[pyasp](https://github.com/sthiele/pyasp) comes into mind, but do not (yet) supports clingo alone.
## Installation
pip install clyngor
You must have `clingo` in your path. Depending on your OS, it might be done with a system installation,
or through downloading and (compilation and) manual installation.
[See the doc](https://potassco.org/doc/start/).
## Tips
### Careful parsing
By default, clyngor uses a very simple parser (yeah, `str.split`) in order to achieve time efficiency in most time.
However, when asked to compute a particular output format (like `parse_args`) or an explicitely *careful parsing*,
clyngor will use a much more robust parser (made with an [arpeggio](http://www.igordejanovic.net/Arpeggio/) grammar).
### Import/export
See the [`utils` module](clyngor/utils.py) and its [tests](clyngor/test/test_utils.py),
which provides high level routines to save and load answer sets.
### Define the path to clingo binary
import clyngor
clyngor.CLINGO_BIN_PATH = 'path/to/clingo'
Note that it will be the very first parameter to [`subprocess.Popen`](https://docs.python.org/3/library/subprocess.html#popen-constructor).
### `clyngor.solve` parameters
The `solve` functions allow to pass explicitely some parameters to clingo
(including number of models to yield, time-limit, and constants).
Using the `options` parameter is just fine, but with the explicit parameters some verifications
are made against data (mostly about type).
Therefore, the two followings are equivalent ; but the first is more readable and will crash earlier with a better error message if `n` is not valid:
solve('file.lp', nb_model=n)
solve('file.lp', options='-n ' + str(n))
### Dinopython support
No.
### Contributions
Yes.
### Why clyngor ?
No, it's pronounced [*clyngor*](https://www.youtube.com/watch?v=RyU99BCNRuU#t=50s).
## Further ideas
- [timeout](https://stackoverflow.com/a/12698328/3077939) in addition to time-limit
- ASP source code debugging generator
## from pyasp to clyngor
If you have a project that makes use of pyasp, but need clingo instead of gringo+clasp, one way to go is to use clyngor instead.
Here was my old code:
from pyasp import asp
def solving(comp, graph):
programs = [comp, graph]
clasp_options = ['--opt-mode=optN', '--parallel-mode=4', '--project']
solver = asp.Gringo4Clasp(clasp_options=clasp_options)
print("solver run as: `clingo {} {}`".format(' '.join(programs), clasp_options))
at_least_one_solution = False
for answerset in solver.run(programs, collapseAtoms=False):
yield answerset
def find_direct_inclusions(model) -> dict:
programs = [ASP_SRC_INCLUSION]
solver = asp.Gringo4Clasp()
add_atoms = ''.join(str(atom) + '.' for atom in model)
answers = tuple(solver.run(programs, collapseAtoms=False,
additionalProgramText=add_atoms))
return answers
And here is the version using clyngor, that pass the exact same unit tests:
import clyngor
def solving(comp, graph):
programs = [comp, graph]
clasp_options = '--opt-mode=optN', '--parallel-mode=4', '--project'
answers = clyngor.solve(programs, options=clasp_options)
print("solver run as: `{}`".format(answers.command))
for answerset in answers.as_pyasp.parse_args.int_not_parsed:
yield answerset
def find_direct_inclusions(model) -> dict:
programs = [ASP_SRC_INCLUSION]
add_atoms = ''.join(str(atom) + '.' for atom in model)
answers = tuple(clyngor.solve(programs, inline=add_atoms).as_pyasp.parse_args)
return answers
<img src="clyngor.png"/><br>
</p>
Handy python wrapper around [Potassco's Clingo](https://potassco.org/) [ASP solver](https://en.wikipedia.org/wiki/Answer%20set%20programming).
## Example
Clyngor offers multiple interfaces. The followings are all equivalent.
(they search for [formal concepts](https://en.wikipedia.org/wiki/Formal_concept_analysis))
from clyngor import ASP, solve
answers = ASP("""
rel(a,(c;d)). rel(b,(d;e)).
obj(X):- rel(X,_) ; rel(X,Y): att(Y).
att(Y):- rel(_,Y) ; rel(X,Y): obj(X).
:- not obj(X):obj(X).
:- not att(Y):att(Y).
""")
for answer in answers:
print(answer)
The same, but with the lower level function expecting files:
answers = solve(inline="""
rel(a,(c;d)). rel(b,(d;e)).
obj(X):- rel(X,_) ; rel(X,Y): att(Y).
att(Y):- rel(_,Y) ; rel(X,Y): obj(X).
:- not obj(X):obj(X).
:- not att(Y):att(Y).
""")
More traditional interface, using file containing the ASP source code:
answers = solve('concepts.lp'): # also accepts an iterable of file
More examples are available in [the unit tests](clyngor/test/).
## Chaining
Once you get your answers, clyngor allows you to specify
the answer sets format using builtin methods:
for answer in answers.by_predicate.first_arg_only:
print('{' + ','.join(answer['obj']) + '} × {' + ','.join(answer['att']) + '}')
And if you need a [*pyasp-like*](https://github.com/sthiele/pyasp) interface:
for answer in answers.as_pyasp:
print('{' + ','.join(a.args()[0] for a in answer if a.predicate == 'obj')
+ '} × {' + ','.join(a.args()[0] for a in answer if a.predicate == 'att') + '}')
Currently, there is only one way to see all chaining operator available:
[the source code of the Answers object](clyngor/answers.py).
(or `help(clyngor.Answers)`)
## Debugging
TODO: Clyngor is also able to parse an ASP program to generate debugging help.
## Solver scripting
TODO: Clyngor is able to manage python inside ASP source code, allowing user to fully control the solving.
## Alternatives
[pyasp](https://github.com/sthiele/pyasp) comes into mind, but do not (yet) supports clingo alone.
## Installation
pip install clyngor
You must have `clingo` in your path. Depending on your OS, it might be done with a system installation,
or through downloading and (compilation and) manual installation.
[See the doc](https://potassco.org/doc/start/).
## Tips
### Careful parsing
By default, clyngor uses a very simple parser (yeah, `str.split`) in order to achieve time efficiency in most time.
However, when asked to compute a particular output format (like `parse_args`) or an explicitely *careful parsing*,
clyngor will use a much more robust parser (made with an [arpeggio](http://www.igordejanovic.net/Arpeggio/) grammar).
### Import/export
See the [`utils` module](clyngor/utils.py) and its [tests](clyngor/test/test_utils.py),
which provides high level routines to save and load answer sets.
### Define the path to clingo binary
import clyngor
clyngor.CLINGO_BIN_PATH = 'path/to/clingo'
Note that it will be the very first parameter to [`subprocess.Popen`](https://docs.python.org/3/library/subprocess.html#popen-constructor).
### `clyngor.solve` parameters
The `solve` functions allow to pass explicitely some parameters to clingo
(including number of models to yield, time-limit, and constants).
Using the `options` parameter is just fine, but with the explicit parameters some verifications
are made against data (mostly about type).
Therefore, the two followings are equivalent ; but the first is more readable and will crash earlier with a better error message if `n` is not valid:
solve('file.lp', nb_model=n)
solve('file.lp', options='-n ' + str(n))
### Dinopython support
No.
### Contributions
Yes.
### Why clyngor ?
No, it's pronounced [*clyngor*](https://www.youtube.com/watch?v=RyU99BCNRuU#t=50s).
## Further ideas
- [timeout](https://stackoverflow.com/a/12698328/3077939) in addition to time-limit
- ASP source code debugging generator
## from pyasp to clyngor
If you have a project that makes use of pyasp, but need clingo instead of gringo+clasp, one way to go is to use clyngor instead.
Here was my old code:
from pyasp import asp
def solving(comp, graph):
programs = [comp, graph]
clasp_options = ['--opt-mode=optN', '--parallel-mode=4', '--project']
solver = asp.Gringo4Clasp(clasp_options=clasp_options)
print("solver run as: `clingo {} {}`".format(' '.join(programs), clasp_options))
at_least_one_solution = False
for answerset in solver.run(programs, collapseAtoms=False):
yield answerset
def find_direct_inclusions(model) -> dict:
programs = [ASP_SRC_INCLUSION]
solver = asp.Gringo4Clasp()
add_atoms = ''.join(str(atom) + '.' for atom in model)
answers = tuple(solver.run(programs, collapseAtoms=False,
additionalProgramText=add_atoms))
return answers
And here is the version using clyngor, that pass the exact same unit tests:
import clyngor
def solving(comp, graph):
programs = [comp, graph]
clasp_options = '--opt-mode=optN', '--parallel-mode=4', '--project'
answers = clyngor.solve(programs, options=clasp_options)
print("solver run as: `{}`".format(answers.command))
for answerset in answers.as_pyasp.parse_args.int_not_parsed:
yield answerset
def find_direct_inclusions(model) -> dict:
programs = [ASP_SRC_INCLUSION]
add_atoms = ''.join(str(atom) + '.' for atom in model)
answers = tuple(clyngor.solve(programs, inline=add_atoms).as_pyasp.parse_args)
return answers
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
clyngor-0.0.16.tar.gz
(29.7 kB
view details)
File details
Details for the file clyngor-0.0.16.tar.gz
.
File metadata
- Download URL: clyngor-0.0.16.tar.gz
- Upload date:
- Size: 29.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9420271141471c0c86460322dce438d087aa330431b9284aa5624e47d114daef |
|
MD5 | 0edee1dad832efb79f0b44fef41f6c9b |
|
BLAKE2b-256 | ce38ab6d6f7824459fb7ccaf63c8c38c7d7e7908eeb1c862e6bc83a27a0f19d8 |