summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-clyngor.spec1285
-rw-r--r--sources1
3 files changed, 1287 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..d59432d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/clyngor-0.4.3.tar.gz
diff --git a/python-clyngor.spec b/python-clyngor.spec
new file mode 100644
index 0000000..f4112e6
--- /dev/null
+++ b/python-clyngor.spec
@@ -0,0 +1,1285 @@
+%global _empty_manifest_terminate_build 0
+Name: python-clyngor
+Version: 0.4.3
+Release: 1
+Summary: Python wrapper around Clingo/Answer Set Programming
+License: GPLv3
+URL: https://github.com/aluriak/clyngor
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/5c/7d/6f6634114f1b13e1875fc21c87caee724927b118e5ca2515e1e21dc2b640/clyngor-0.4.3.tar.gz
+BuildArch: noarch
+
+Requires: python3-Arpeggio
+Requires: python3-pyPEG2
+Requires: python3-pytest
+Requires: python3-clingo
+
+%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))
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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)`)
+
+
+
+
+
+## Official Python API
+If the used version of clingo is compiled with python, you can put python code into your ASP code as usual.
+But if you also have the [clingo package](https://potassco.org/clingo/python-api/current/clingo.html)
+installed and importable, clyngor can use it for various tasks.
+
+Using the official API leads to the following changes :
+
+- both robust and quick parsing, instead of the simple vs slow method
+- some options are not supported : constants, [time-limit](clyngor/test/test_time_limit.py), parsing error handling, [decoupled grounding/solving](clyngor/test/test_grounding.py)
+
+You can activate the use of the clingo module by calling once `clyngor.activate_clingo_module()`
+or calling `clyngor.solve` with argument `use_clingo_module` set to `True`.
+
+
+## Python embedding
+For users putting some python in their ASP, clyngor may help.
+The only condition is to have clingo compiled with python support,
+and having clyngor installed for the python used by clingo.
+
+
+### Easy ASP functors
+Clyngor provides `converted_types` function,
+allowing one to avoid boilerplate code based on type annotation when
+calling python from inside ASP code.
+
+Example (see [tests](clyngor/test/test_upapi.py) for more):
+
+```python
+#script(python)
+from clyngor.upapi import converted_types
+@converted_types
+def f(a:str, b:int):
+ yield a * b
+ yield len(a) * b
+#end.
+
+p(X):- (X)=@f("hello",2).
+p(X):- (X)=@f(1,2). % ignored, because types do not match
+```
+
+Without `converted_types`, user have to ensure that `f` is a function returning a list,
+and that arguments are of the expected type.
+
+Note that the [incoming clingo version](https://github.com/potassco/clingo/issues/147)
+is leading to that flexibility regarding returned values.
+
+
+### Generalist propagators
+Propagators are presented in [this paper](http://drops.dagstuhl.de/opus/volltexte/2016/6733/). They are basically active
+observers of the solving process, able for instance to modify truth assignment
+and invalidate models.
+
+As shown in [clyngor/test/test_propagator_class.py](clyngor/test/test_propagator_class.py),
+a high-level propagator class built on top of the official API is available, useful in many typical use-cases.
+
+
+### Python constraint propagators
+As shown in [examples/pyconstraint.lp](examples/pyconstraint.lp),
+clyngor also exposes some helpers for users wanting to create propagators
+that implement an ASP constraint, but written in Python:
+
+```python
+#script(python)
+from clyngor import Constraint, Variable as V, Main
+
+# Build the constraint on atom b
+def formula(inputs) -> bool:
+ return inputs['b', (2,)]
+
+constraint = Constraint(formula, {('b', (V,))})
+
+# regular main function that register given propagator.
+main = Main(propagators=constraint)
+
+#end.
+
+% ASP part, computing 3 models, b(1), b(2) and b(3).
+1{b(1..3)}1.
+```
+
+## Decoders
+An idea coming from the [JSON decoders](https://docs.python.org/3/library/json.html#encoders-and-decoders), allowing user to specify how to decode/encode custom objects in JSON.
+With clyngor, you can do something alike for ASP (though very basic and only from ASP to Python):
+
+```python
+import clyngor, itertools
+
+ASP_LIST_CONCEPTS = """ % one model contains all concepts
+concept(0).
+extent(0,(a;b)). intent(0,(c;d)).
+concept(1).
+extent(1,(b;e)). intent(1,(f;g)).
+concept(2).
+extent(2,b). intent(2,(c;d;f;g)).
+"""
+
+class Concept:
+ "Decoder of concepts in ASP output"
+ def __init__(self, concept:1, extent:all, intent:all):
+ self.id = int(concept[0])
+ self.extent = frozenset(arg for nb, arg in extent if nb == self.id)
+ self.intent = frozenset(arg for nb, arg in intent if nb == self.id)
+ def __str__(self):
+ return f"<{self.id}: {{{','.join(sorted(self.extent))}}} × {{{','.join(sorted(self.intent))}}}>"
+
+objects = clyngor.decode(inline=ASP_LIST_CONCEPTS, decoders=[Concept])
+print('\t'.join(map(str, objects)))
+```
+
+This code will print something like:
+
+ <2: {b} × {c,d,f,g}> <0: {a,b} × {c,d}> <1: {b,e} × {f,g}>
+
+Note the use of annotations to declare that each `concept` must be associated to one instance,
+and that all `extent` and `intent` must be sent to constructor for each object.
+
+See [tests](clyngor/test/test_decoder.py) for complete API example.
+
+Remaining features for a good decoder support:
+
+- encoding: try to more-or-less automatically build the python to ASP compiler
+- more available annotations, for instance `(3, 5)` (to ask for between 3 and 5 atoms to be associated with the instance), or `any` (exact meaning has to be found)
+- allow to raise an InvalidDecoder exception during decoder instanciation to get the instance discarded
+
+
+## Alternatives
+Clyngor is basically the total rewriting of [pyasp](https://github.com/sthiele/pyasp), which is now abandoned.
+
+For an ORM approach, give a try to [clorm](https://github.com/daveraja/clorm).
+
+
+
+## Installation
+
+ pip install clyngor
+
+You must have [`clingo`](https://potassco.org/doc/start/) in your path. Depending on your OS, it might be done with a system installation,
+or through [downloading](https://github.com/potassco/clingo/releases) and (compilation and) manual installation.
+
+You may also want to install the [python clingo module](https://potassco.org/clingo/python-api/current/clingo.html),
+which is [an optional dependancy](#official-api-embedding).
+
+
+## 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
+
+```python
+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).
+The `solve` function also support the `clingo_bin_path` parameter.
+
+The third solution is to use the decorator `with_clingo_bin`, which modify the global variable
+during the execution of a specific function:
+
+```python
+import clyngor
+
+@clyngor.with_clingo_bin('clingo454')
+def sequence():
+ ...
+ clyngor.solve(...) # will use clingo454, not clingo, unless clingo_bin_path is given
+ ...
+```
+
+
+### `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:
+
+```python
+solve('file.lp', nb_model=n)
+solve('file.lp', options='-n ' + str(n))
+```
+
+
+
+## FAQ
+
+### Dinopython support ?
+No.
+
+### Contributions ?
+Yes.
+
+### Why clyngor ?
+No, it's pronounced [*clyngor*](https://www.youtube.com/watch?v=RyU99BCNRuU#t=50s).
+
+### Explain me again the thing with the official module
+Clyngor was designed to not require the official module, because it required a manual compilation and installation of clingo.
+However, because of the obvious interest in features and performances,
+the official module can be used by clyngor if it is available.
+
+
+## Further ideas
+- [timeout](https://stackoverflow.com/a/12698328/3077939) in addition to time-limit
+- ASP source code debugging generator (started in [clyngor-parser](clyngor-parser))
+
+
+## What is clyngor used for ?
+
+- bioinformatics, to encode biological pathway logic in [pathmodel](https://github.com/pathmodel/pathmodel) and [Menetools](https://github.com/cfrioux/MeneTools), and for [community detection](https://github.com/cfrioux/miscoto).
+- mathematics, to encode some [FCA]()-related task such as [AOC-poset generation](https://github.com/Aluriak/AOC-poset-generation) or [concept search](https://github.com/Aluriak/concept-generation), and [graph compression](https://github.com/Aluriak/PowerGrASP) or [graph manipulation](https://github.com/Aluriak/phasme) in the context of graph theory.
+- visualization, with [Draco](https://github.com/uwdata/draco), a formalization of visualization design knowledge as constraints, and [biseau](https://gitlab.inria.fr/lbourneu/biseau), an ASP-to-graph compiler.
+- web applications, for [a sudoku solver made with ASP](https://github.com/llaisdy/phoenix_live_view_sudoku/).
+
+
+## Changelog
+
+- 0.4.0 (todo)
+ - see [further ideas](#Further-ideas)
+- 0.3.28
+ - [706747045](https://github.com/aluriak/clyngor/commit/706747045cb96abcb9de1e2d729cd43c084cb36f): handle default negation on atoms, by keeping the prefixed dash
+ - [d4830ad52](https://github.com/aluriak/clyngor/commit/d4830ad521a6dcf9024f2c70f2f50e6b19f8c7a2): fix an import error
+- 0.3.25
+ - [80245b2a7](https://github.com/aluriak/clyngor/commit/80245b2a72b8d76639b44a2315622f6743a7bc17): remove f-strings for 3.4 and 3.5 compat.
+ - [6efdb6ab0](https://github.com/aluriak/clyngor/commit/6efdb6ab0f0304b28b35d6ceb16545226b2f9e3e): fix combination of .as_pyasp and .parse_args, where atoms in args were not transformed as pyasp Atom objects.
+ - [fe4107573](https://github.com/aluriak/clyngor/commit/fe410757386e2c3e0881ecc90d7f18ee97672194): correctly parse atoms starting with underscores.
+ - [d6507f17d](https://github.com/aluriak/clyngor/commit/d6507f17dbf27c6c309e3e4009a234b9d63134ba): careful parsing is automatically set when answer set [obviously needs it](clyngor/parsing.py#L266).
+ - [f2c65e8ae](https://github.com/aluriak/clyngor/commit/f2c65e8ae018b9d3589a058a09f9de87e1f3fdf3): fixed bug when using clingo module and `.int_not_parsed`.
+- 0.3.24
+ - [f92248e91](https://github.com/aluriak/clyngor/commit/f92248e91def2c979fd2f8f8af3755b86485becf): `#show 3.` and `#show "hello !".` are now handled
+ - [31375774c](https://github.com/aluriak/clyngor/commit/31375774c437403e8a05f5fe8d0346caba0f43e4): when using clingo module, the models contains only the output atoms, not everything (thank you Arnaud)
+ - [cc6021797](https://github.com/aluriak/clyngor/commit/cc60217975de123a5ef0d083fb10971e0d89c03e): support for `.with_answer_number`, giving model, optimization, optimality and answer number
+ - [c0c090c34](https://github.com/aluriak/clyngor/commit/c0c090c34a7028ba34c49815f0197c67c76e7bfb): parsing and string reproduction of nested atoms such as `a((a("g(2,3)",(2)),))` is now correctly handled and tested
+ - [1840c36e3](https://github.com/aluriak/clyngor/commit/1840c36e3f57c926a565fef7352cd1b083194e58): fix the `models.command` output when clingo module is used
+ - [2679d26a9](https://github.com/aluriak/clyngor/commit/2679d26a91720ab507fb7c2ffc41c064e8ca9cb9): optimize memory usage of `opt_models_from_clyngor_answers` by using yield and answer number, but is now a generator and loses (the useless) `repeated_optimal` option
+- 0.3.20
+ - fix [#7](https://github.com/Aluriak/clyngor/issues/7)
+ - improve testing cover, fix warning in recent versions of pytest
+ - more robust options parsing when solving with clingo module
+- 0.3.19
+ - fix [#16](https://github.com/Aluriak/clyngor/issues/16)
+- 0.3.18
+ - TermSet bugfix
+ - `TermSet.add` to add atoms to the TermSet
+ - `TermSet.union` to generate the union of multiple TermSet instances
+- 0.3.17
+ - support for decoupled grounding and solving, as shown in [dedicated example](examples/decoupled-grounding.py)
+ - new parameter `return_raw_output` for clyngor.solve, allowing to get stdout/stderr without treatments
+ - [new example](examples/enum-optN.py) showing how to retrieve all optimal models using clyngor, and…
+ - … the defined function `opt_models_from_clyngor_answers` is now embedded in clyngor API
+- 0.3.16
+ - support for `.by_arity`, equivalent to `.by_predicate` but with predicate and arity
+ - decorator `with_clingo_bin`, changing clingo binary path for encapsulated function
+ - support for `.with_optimality`, giving optimization and optimality along with the model
+- 0.3.14
+ - decoders support, see [`clyngor.decoder`](clyngor/decoder.py) and [doc](#decoders)
+- 0.3.10
+ - support for `.discard_quotes` option (thanks to ArnaudBelcour)
+ - bugfix: `.atom_as_string` and `.first_arg_only` collision
+ - bugfix: more robust tempfile deletion and closing management
+ - [demonstration](examples/pyconstraint-is-not-working.lp) of the non-working Constraint type implementation
+- before
+ - predicat to know if python/lua are available with used clingo binary
+ - easy interface for most use cases using type hint for embedded python
+ - easy python constraints in ASP with Constraint type
+ - add support for propagators
+ - add support for clingo official python module
+
+
+## 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:
+
+```python
+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:
+
+```python
+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
+```
+
+
+## Thanks
+To [Arnaud Belcour](https://github.com/ArnaudBelcour) for his works and frequent feedbacks.
+
+To [Domoritz](https://github.com/domoritz) for his questions and feedbacks.
+
+
+
+
+%package -n python3-clyngor
+Summary: Python wrapper around Clingo/Answer Set Programming
+Provides: python-clyngor
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-clyngor
+<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))
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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)`)
+
+
+
+
+
+## Official Python API
+If the used version of clingo is compiled with python, you can put python code into your ASP code as usual.
+But if you also have the [clingo package](https://potassco.org/clingo/python-api/current/clingo.html)
+installed and importable, clyngor can use it for various tasks.
+
+Using the official API leads to the following changes :
+
+- both robust and quick parsing, instead of the simple vs slow method
+- some options are not supported : constants, [time-limit](clyngor/test/test_time_limit.py), parsing error handling, [decoupled grounding/solving](clyngor/test/test_grounding.py)
+
+You can activate the use of the clingo module by calling once `clyngor.activate_clingo_module()`
+or calling `clyngor.solve` with argument `use_clingo_module` set to `True`.
+
+
+## Python embedding
+For users putting some python in their ASP, clyngor may help.
+The only condition is to have clingo compiled with python support,
+and having clyngor installed for the python used by clingo.
+
+
+### Easy ASP functors
+Clyngor provides `converted_types` function,
+allowing one to avoid boilerplate code based on type annotation when
+calling python from inside ASP code.
+
+Example (see [tests](clyngor/test/test_upapi.py) for more):
+
+```python
+#script(python)
+from clyngor.upapi import converted_types
+@converted_types
+def f(a:str, b:int):
+ yield a * b
+ yield len(a) * b
+#end.
+
+p(X):- (X)=@f("hello",2).
+p(X):- (X)=@f(1,2). % ignored, because types do not match
+```
+
+Without `converted_types`, user have to ensure that `f` is a function returning a list,
+and that arguments are of the expected type.
+
+Note that the [incoming clingo version](https://github.com/potassco/clingo/issues/147)
+is leading to that flexibility regarding returned values.
+
+
+### Generalist propagators
+Propagators are presented in [this paper](http://drops.dagstuhl.de/opus/volltexte/2016/6733/). They are basically active
+observers of the solving process, able for instance to modify truth assignment
+and invalidate models.
+
+As shown in [clyngor/test/test_propagator_class.py](clyngor/test/test_propagator_class.py),
+a high-level propagator class built on top of the official API is available, useful in many typical use-cases.
+
+
+### Python constraint propagators
+As shown in [examples/pyconstraint.lp](examples/pyconstraint.lp),
+clyngor also exposes some helpers for users wanting to create propagators
+that implement an ASP constraint, but written in Python:
+
+```python
+#script(python)
+from clyngor import Constraint, Variable as V, Main
+
+# Build the constraint on atom b
+def formula(inputs) -> bool:
+ return inputs['b', (2,)]
+
+constraint = Constraint(formula, {('b', (V,))})
+
+# regular main function that register given propagator.
+main = Main(propagators=constraint)
+
+#end.
+
+% ASP part, computing 3 models, b(1), b(2) and b(3).
+1{b(1..3)}1.
+```
+
+## Decoders
+An idea coming from the [JSON decoders](https://docs.python.org/3/library/json.html#encoders-and-decoders), allowing user to specify how to decode/encode custom objects in JSON.
+With clyngor, you can do something alike for ASP (though very basic and only from ASP to Python):
+
+```python
+import clyngor, itertools
+
+ASP_LIST_CONCEPTS = """ % one model contains all concepts
+concept(0).
+extent(0,(a;b)). intent(0,(c;d)).
+concept(1).
+extent(1,(b;e)). intent(1,(f;g)).
+concept(2).
+extent(2,b). intent(2,(c;d;f;g)).
+"""
+
+class Concept:
+ "Decoder of concepts in ASP output"
+ def __init__(self, concept:1, extent:all, intent:all):
+ self.id = int(concept[0])
+ self.extent = frozenset(arg for nb, arg in extent if nb == self.id)
+ self.intent = frozenset(arg for nb, arg in intent if nb == self.id)
+ def __str__(self):
+ return f"<{self.id}: {{{','.join(sorted(self.extent))}}} × {{{','.join(sorted(self.intent))}}}>"
+
+objects = clyngor.decode(inline=ASP_LIST_CONCEPTS, decoders=[Concept])
+print('\t'.join(map(str, objects)))
+```
+
+This code will print something like:
+
+ <2: {b} × {c,d,f,g}> <0: {a,b} × {c,d}> <1: {b,e} × {f,g}>
+
+Note the use of annotations to declare that each `concept` must be associated to one instance,
+and that all `extent` and `intent` must be sent to constructor for each object.
+
+See [tests](clyngor/test/test_decoder.py) for complete API example.
+
+Remaining features for a good decoder support:
+
+- encoding: try to more-or-less automatically build the python to ASP compiler
+- more available annotations, for instance `(3, 5)` (to ask for between 3 and 5 atoms to be associated with the instance), or `any` (exact meaning has to be found)
+- allow to raise an InvalidDecoder exception during decoder instanciation to get the instance discarded
+
+
+## Alternatives
+Clyngor is basically the total rewriting of [pyasp](https://github.com/sthiele/pyasp), which is now abandoned.
+
+For an ORM approach, give a try to [clorm](https://github.com/daveraja/clorm).
+
+
+
+## Installation
+
+ pip install clyngor
+
+You must have [`clingo`](https://potassco.org/doc/start/) in your path. Depending on your OS, it might be done with a system installation,
+or through [downloading](https://github.com/potassco/clingo/releases) and (compilation and) manual installation.
+
+You may also want to install the [python clingo module](https://potassco.org/clingo/python-api/current/clingo.html),
+which is [an optional dependancy](#official-api-embedding).
+
+
+## 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
+
+```python
+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).
+The `solve` function also support the `clingo_bin_path` parameter.
+
+The third solution is to use the decorator `with_clingo_bin`, which modify the global variable
+during the execution of a specific function:
+
+```python
+import clyngor
+
+@clyngor.with_clingo_bin('clingo454')
+def sequence():
+ ...
+ clyngor.solve(...) # will use clingo454, not clingo, unless clingo_bin_path is given
+ ...
+```
+
+
+### `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:
+
+```python
+solve('file.lp', nb_model=n)
+solve('file.lp', options='-n ' + str(n))
+```
+
+
+
+## FAQ
+
+### Dinopython support ?
+No.
+
+### Contributions ?
+Yes.
+
+### Why clyngor ?
+No, it's pronounced [*clyngor*](https://www.youtube.com/watch?v=RyU99BCNRuU#t=50s).
+
+### Explain me again the thing with the official module
+Clyngor was designed to not require the official module, because it required a manual compilation and installation of clingo.
+However, because of the obvious interest in features and performances,
+the official module can be used by clyngor if it is available.
+
+
+## Further ideas
+- [timeout](https://stackoverflow.com/a/12698328/3077939) in addition to time-limit
+- ASP source code debugging generator (started in [clyngor-parser](clyngor-parser))
+
+
+## What is clyngor used for ?
+
+- bioinformatics, to encode biological pathway logic in [pathmodel](https://github.com/pathmodel/pathmodel) and [Menetools](https://github.com/cfrioux/MeneTools), and for [community detection](https://github.com/cfrioux/miscoto).
+- mathematics, to encode some [FCA]()-related task such as [AOC-poset generation](https://github.com/Aluriak/AOC-poset-generation) or [concept search](https://github.com/Aluriak/concept-generation), and [graph compression](https://github.com/Aluriak/PowerGrASP) or [graph manipulation](https://github.com/Aluriak/phasme) in the context of graph theory.
+- visualization, with [Draco](https://github.com/uwdata/draco), a formalization of visualization design knowledge as constraints, and [biseau](https://gitlab.inria.fr/lbourneu/biseau), an ASP-to-graph compiler.
+- web applications, for [a sudoku solver made with ASP](https://github.com/llaisdy/phoenix_live_view_sudoku/).
+
+
+## Changelog
+
+- 0.4.0 (todo)
+ - see [further ideas](#Further-ideas)
+- 0.3.28
+ - [706747045](https://github.com/aluriak/clyngor/commit/706747045cb96abcb9de1e2d729cd43c084cb36f): handle default negation on atoms, by keeping the prefixed dash
+ - [d4830ad52](https://github.com/aluriak/clyngor/commit/d4830ad521a6dcf9024f2c70f2f50e6b19f8c7a2): fix an import error
+- 0.3.25
+ - [80245b2a7](https://github.com/aluriak/clyngor/commit/80245b2a72b8d76639b44a2315622f6743a7bc17): remove f-strings for 3.4 and 3.5 compat.
+ - [6efdb6ab0](https://github.com/aluriak/clyngor/commit/6efdb6ab0f0304b28b35d6ceb16545226b2f9e3e): fix combination of .as_pyasp and .parse_args, where atoms in args were not transformed as pyasp Atom objects.
+ - [fe4107573](https://github.com/aluriak/clyngor/commit/fe410757386e2c3e0881ecc90d7f18ee97672194): correctly parse atoms starting with underscores.
+ - [d6507f17d](https://github.com/aluriak/clyngor/commit/d6507f17dbf27c6c309e3e4009a234b9d63134ba): careful parsing is automatically set when answer set [obviously needs it](clyngor/parsing.py#L266).
+ - [f2c65e8ae](https://github.com/aluriak/clyngor/commit/f2c65e8ae018b9d3589a058a09f9de87e1f3fdf3): fixed bug when using clingo module and `.int_not_parsed`.
+- 0.3.24
+ - [f92248e91](https://github.com/aluriak/clyngor/commit/f92248e91def2c979fd2f8f8af3755b86485becf): `#show 3.` and `#show "hello !".` are now handled
+ - [31375774c](https://github.com/aluriak/clyngor/commit/31375774c437403e8a05f5fe8d0346caba0f43e4): when using clingo module, the models contains only the output atoms, not everything (thank you Arnaud)
+ - [cc6021797](https://github.com/aluriak/clyngor/commit/cc60217975de123a5ef0d083fb10971e0d89c03e): support for `.with_answer_number`, giving model, optimization, optimality and answer number
+ - [c0c090c34](https://github.com/aluriak/clyngor/commit/c0c090c34a7028ba34c49815f0197c67c76e7bfb): parsing and string reproduction of nested atoms such as `a((a("g(2,3)",(2)),))` is now correctly handled and tested
+ - [1840c36e3](https://github.com/aluriak/clyngor/commit/1840c36e3f57c926a565fef7352cd1b083194e58): fix the `models.command` output when clingo module is used
+ - [2679d26a9](https://github.com/aluriak/clyngor/commit/2679d26a91720ab507fb7c2ffc41c064e8ca9cb9): optimize memory usage of `opt_models_from_clyngor_answers` by using yield and answer number, but is now a generator and loses (the useless) `repeated_optimal` option
+- 0.3.20
+ - fix [#7](https://github.com/Aluriak/clyngor/issues/7)
+ - improve testing cover, fix warning in recent versions of pytest
+ - more robust options parsing when solving with clingo module
+- 0.3.19
+ - fix [#16](https://github.com/Aluriak/clyngor/issues/16)
+- 0.3.18
+ - TermSet bugfix
+ - `TermSet.add` to add atoms to the TermSet
+ - `TermSet.union` to generate the union of multiple TermSet instances
+- 0.3.17
+ - support for decoupled grounding and solving, as shown in [dedicated example](examples/decoupled-grounding.py)
+ - new parameter `return_raw_output` for clyngor.solve, allowing to get stdout/stderr without treatments
+ - [new example](examples/enum-optN.py) showing how to retrieve all optimal models using clyngor, and…
+ - … the defined function `opt_models_from_clyngor_answers` is now embedded in clyngor API
+- 0.3.16
+ - support for `.by_arity`, equivalent to `.by_predicate` but with predicate and arity
+ - decorator `with_clingo_bin`, changing clingo binary path for encapsulated function
+ - support for `.with_optimality`, giving optimization and optimality along with the model
+- 0.3.14
+ - decoders support, see [`clyngor.decoder`](clyngor/decoder.py) and [doc](#decoders)
+- 0.3.10
+ - support for `.discard_quotes` option (thanks to ArnaudBelcour)
+ - bugfix: `.atom_as_string` and `.first_arg_only` collision
+ - bugfix: more robust tempfile deletion and closing management
+ - [demonstration](examples/pyconstraint-is-not-working.lp) of the non-working Constraint type implementation
+- before
+ - predicat to know if python/lua are available with used clingo binary
+ - easy interface for most use cases using type hint for embedded python
+ - easy python constraints in ASP with Constraint type
+ - add support for propagators
+ - add support for clingo official python module
+
+
+## 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:
+
+```python
+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:
+
+```python
+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
+```
+
+
+## Thanks
+To [Arnaud Belcour](https://github.com/ArnaudBelcour) for his works and frequent feedbacks.
+
+To [Domoritz](https://github.com/domoritz) for his questions and feedbacks.
+
+
+
+
+%package help
+Summary: Development documents and examples for clyngor
+Provides: python3-clyngor-doc
+%description help
+<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))
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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:
+
+```python
+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)`)
+
+
+
+
+
+## Official Python API
+If the used version of clingo is compiled with python, you can put python code into your ASP code as usual.
+But if you also have the [clingo package](https://potassco.org/clingo/python-api/current/clingo.html)
+installed and importable, clyngor can use it for various tasks.
+
+Using the official API leads to the following changes :
+
+- both robust and quick parsing, instead of the simple vs slow method
+- some options are not supported : constants, [time-limit](clyngor/test/test_time_limit.py), parsing error handling, [decoupled grounding/solving](clyngor/test/test_grounding.py)
+
+You can activate the use of the clingo module by calling once `clyngor.activate_clingo_module()`
+or calling `clyngor.solve` with argument `use_clingo_module` set to `True`.
+
+
+## Python embedding
+For users putting some python in their ASP, clyngor may help.
+The only condition is to have clingo compiled with python support,
+and having clyngor installed for the python used by clingo.
+
+
+### Easy ASP functors
+Clyngor provides `converted_types` function,
+allowing one to avoid boilerplate code based on type annotation when
+calling python from inside ASP code.
+
+Example (see [tests](clyngor/test/test_upapi.py) for more):
+
+```python
+#script(python)
+from clyngor.upapi import converted_types
+@converted_types
+def f(a:str, b:int):
+ yield a * b
+ yield len(a) * b
+#end.
+
+p(X):- (X)=@f("hello",2).
+p(X):- (X)=@f(1,2). % ignored, because types do not match
+```
+
+Without `converted_types`, user have to ensure that `f` is a function returning a list,
+and that arguments are of the expected type.
+
+Note that the [incoming clingo version](https://github.com/potassco/clingo/issues/147)
+is leading to that flexibility regarding returned values.
+
+
+### Generalist propagators
+Propagators are presented in [this paper](http://drops.dagstuhl.de/opus/volltexte/2016/6733/). They are basically active
+observers of the solving process, able for instance to modify truth assignment
+and invalidate models.
+
+As shown in [clyngor/test/test_propagator_class.py](clyngor/test/test_propagator_class.py),
+a high-level propagator class built on top of the official API is available, useful in many typical use-cases.
+
+
+### Python constraint propagators
+As shown in [examples/pyconstraint.lp](examples/pyconstraint.lp),
+clyngor also exposes some helpers for users wanting to create propagators
+that implement an ASP constraint, but written in Python:
+
+```python
+#script(python)
+from clyngor import Constraint, Variable as V, Main
+
+# Build the constraint on atom b
+def formula(inputs) -> bool:
+ return inputs['b', (2,)]
+
+constraint = Constraint(formula, {('b', (V,))})
+
+# regular main function that register given propagator.
+main = Main(propagators=constraint)
+
+#end.
+
+% ASP part, computing 3 models, b(1), b(2) and b(3).
+1{b(1..3)}1.
+```
+
+## Decoders
+An idea coming from the [JSON decoders](https://docs.python.org/3/library/json.html#encoders-and-decoders), allowing user to specify how to decode/encode custom objects in JSON.
+With clyngor, you can do something alike for ASP (though very basic and only from ASP to Python):
+
+```python
+import clyngor, itertools
+
+ASP_LIST_CONCEPTS = """ % one model contains all concepts
+concept(0).
+extent(0,(a;b)). intent(0,(c;d)).
+concept(1).
+extent(1,(b;e)). intent(1,(f;g)).
+concept(2).
+extent(2,b). intent(2,(c;d;f;g)).
+"""
+
+class Concept:
+ "Decoder of concepts in ASP output"
+ def __init__(self, concept:1, extent:all, intent:all):
+ self.id = int(concept[0])
+ self.extent = frozenset(arg for nb, arg in extent if nb == self.id)
+ self.intent = frozenset(arg for nb, arg in intent if nb == self.id)
+ def __str__(self):
+ return f"<{self.id}: {{{','.join(sorted(self.extent))}}} × {{{','.join(sorted(self.intent))}}}>"
+
+objects = clyngor.decode(inline=ASP_LIST_CONCEPTS, decoders=[Concept])
+print('\t'.join(map(str, objects)))
+```
+
+This code will print something like:
+
+ <2: {b} × {c,d,f,g}> <0: {a,b} × {c,d}> <1: {b,e} × {f,g}>
+
+Note the use of annotations to declare that each `concept` must be associated to one instance,
+and that all `extent` and `intent` must be sent to constructor for each object.
+
+See [tests](clyngor/test/test_decoder.py) for complete API example.
+
+Remaining features for a good decoder support:
+
+- encoding: try to more-or-less automatically build the python to ASP compiler
+- more available annotations, for instance `(3, 5)` (to ask for between 3 and 5 atoms to be associated with the instance), or `any` (exact meaning has to be found)
+- allow to raise an InvalidDecoder exception during decoder instanciation to get the instance discarded
+
+
+## Alternatives
+Clyngor is basically the total rewriting of [pyasp](https://github.com/sthiele/pyasp), which is now abandoned.
+
+For an ORM approach, give a try to [clorm](https://github.com/daveraja/clorm).
+
+
+
+## Installation
+
+ pip install clyngor
+
+You must have [`clingo`](https://potassco.org/doc/start/) in your path. Depending on your OS, it might be done with a system installation,
+or through [downloading](https://github.com/potassco/clingo/releases) and (compilation and) manual installation.
+
+You may also want to install the [python clingo module](https://potassco.org/clingo/python-api/current/clingo.html),
+which is [an optional dependancy](#official-api-embedding).
+
+
+## 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
+
+```python
+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).
+The `solve` function also support the `clingo_bin_path` parameter.
+
+The third solution is to use the decorator `with_clingo_bin`, which modify the global variable
+during the execution of a specific function:
+
+```python
+import clyngor
+
+@clyngor.with_clingo_bin('clingo454')
+def sequence():
+ ...
+ clyngor.solve(...) # will use clingo454, not clingo, unless clingo_bin_path is given
+ ...
+```
+
+
+### `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:
+
+```python
+solve('file.lp', nb_model=n)
+solve('file.lp', options='-n ' + str(n))
+```
+
+
+
+## FAQ
+
+### Dinopython support ?
+No.
+
+### Contributions ?
+Yes.
+
+### Why clyngor ?
+No, it's pronounced [*clyngor*](https://www.youtube.com/watch?v=RyU99BCNRuU#t=50s).
+
+### Explain me again the thing with the official module
+Clyngor was designed to not require the official module, because it required a manual compilation and installation of clingo.
+However, because of the obvious interest in features and performances,
+the official module can be used by clyngor if it is available.
+
+
+## Further ideas
+- [timeout](https://stackoverflow.com/a/12698328/3077939) in addition to time-limit
+- ASP source code debugging generator (started in [clyngor-parser](clyngor-parser))
+
+
+## What is clyngor used for ?
+
+- bioinformatics, to encode biological pathway logic in [pathmodel](https://github.com/pathmodel/pathmodel) and [Menetools](https://github.com/cfrioux/MeneTools), and for [community detection](https://github.com/cfrioux/miscoto).
+- mathematics, to encode some [FCA]()-related task such as [AOC-poset generation](https://github.com/Aluriak/AOC-poset-generation) or [concept search](https://github.com/Aluriak/concept-generation), and [graph compression](https://github.com/Aluriak/PowerGrASP) or [graph manipulation](https://github.com/Aluriak/phasme) in the context of graph theory.
+- visualization, with [Draco](https://github.com/uwdata/draco), a formalization of visualization design knowledge as constraints, and [biseau](https://gitlab.inria.fr/lbourneu/biseau), an ASP-to-graph compiler.
+- web applications, for [a sudoku solver made with ASP](https://github.com/llaisdy/phoenix_live_view_sudoku/).
+
+
+## Changelog
+
+- 0.4.0 (todo)
+ - see [further ideas](#Further-ideas)
+- 0.3.28
+ - [706747045](https://github.com/aluriak/clyngor/commit/706747045cb96abcb9de1e2d729cd43c084cb36f): handle default negation on atoms, by keeping the prefixed dash
+ - [d4830ad52](https://github.com/aluriak/clyngor/commit/d4830ad521a6dcf9024f2c70f2f50e6b19f8c7a2): fix an import error
+- 0.3.25
+ - [80245b2a7](https://github.com/aluriak/clyngor/commit/80245b2a72b8d76639b44a2315622f6743a7bc17): remove f-strings for 3.4 and 3.5 compat.
+ - [6efdb6ab0](https://github.com/aluriak/clyngor/commit/6efdb6ab0f0304b28b35d6ceb16545226b2f9e3e): fix combination of .as_pyasp and .parse_args, where atoms in args were not transformed as pyasp Atom objects.
+ - [fe4107573](https://github.com/aluriak/clyngor/commit/fe410757386e2c3e0881ecc90d7f18ee97672194): correctly parse atoms starting with underscores.
+ - [d6507f17d](https://github.com/aluriak/clyngor/commit/d6507f17dbf27c6c309e3e4009a234b9d63134ba): careful parsing is automatically set when answer set [obviously needs it](clyngor/parsing.py#L266).
+ - [f2c65e8ae](https://github.com/aluriak/clyngor/commit/f2c65e8ae018b9d3589a058a09f9de87e1f3fdf3): fixed bug when using clingo module and `.int_not_parsed`.
+- 0.3.24
+ - [f92248e91](https://github.com/aluriak/clyngor/commit/f92248e91def2c979fd2f8f8af3755b86485becf): `#show 3.` and `#show "hello !".` are now handled
+ - [31375774c](https://github.com/aluriak/clyngor/commit/31375774c437403e8a05f5fe8d0346caba0f43e4): when using clingo module, the models contains only the output atoms, not everything (thank you Arnaud)
+ - [cc6021797](https://github.com/aluriak/clyngor/commit/cc60217975de123a5ef0d083fb10971e0d89c03e): support for `.with_answer_number`, giving model, optimization, optimality and answer number
+ - [c0c090c34](https://github.com/aluriak/clyngor/commit/c0c090c34a7028ba34c49815f0197c67c76e7bfb): parsing and string reproduction of nested atoms such as `a((a("g(2,3)",(2)),))` is now correctly handled and tested
+ - [1840c36e3](https://github.com/aluriak/clyngor/commit/1840c36e3f57c926a565fef7352cd1b083194e58): fix the `models.command` output when clingo module is used
+ - [2679d26a9](https://github.com/aluriak/clyngor/commit/2679d26a91720ab507fb7c2ffc41c064e8ca9cb9): optimize memory usage of `opt_models_from_clyngor_answers` by using yield and answer number, but is now a generator and loses (the useless) `repeated_optimal` option
+- 0.3.20
+ - fix [#7](https://github.com/Aluriak/clyngor/issues/7)
+ - improve testing cover, fix warning in recent versions of pytest
+ - more robust options parsing when solving with clingo module
+- 0.3.19
+ - fix [#16](https://github.com/Aluriak/clyngor/issues/16)
+- 0.3.18
+ - TermSet bugfix
+ - `TermSet.add` to add atoms to the TermSet
+ - `TermSet.union` to generate the union of multiple TermSet instances
+- 0.3.17
+ - support for decoupled grounding and solving, as shown in [dedicated example](examples/decoupled-grounding.py)
+ - new parameter `return_raw_output` for clyngor.solve, allowing to get stdout/stderr without treatments
+ - [new example](examples/enum-optN.py) showing how to retrieve all optimal models using clyngor, and…
+ - … the defined function `opt_models_from_clyngor_answers` is now embedded in clyngor API
+- 0.3.16
+ - support for `.by_arity`, equivalent to `.by_predicate` but with predicate and arity
+ - decorator `with_clingo_bin`, changing clingo binary path for encapsulated function
+ - support for `.with_optimality`, giving optimization and optimality along with the model
+- 0.3.14
+ - decoders support, see [`clyngor.decoder`](clyngor/decoder.py) and [doc](#decoders)
+- 0.3.10
+ - support for `.discard_quotes` option (thanks to ArnaudBelcour)
+ - bugfix: `.atom_as_string` and `.first_arg_only` collision
+ - bugfix: more robust tempfile deletion and closing management
+ - [demonstration](examples/pyconstraint-is-not-working.lp) of the non-working Constraint type implementation
+- before
+ - predicat to know if python/lua are available with used clingo binary
+ - easy interface for most use cases using type hint for embedded python
+ - easy python constraints in ASP with Constraint type
+ - add support for propagators
+ - add support for clingo official python module
+
+
+## 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:
+
+```python
+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:
+
+```python
+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
+```
+
+
+## Thanks
+To [Arnaud Belcour](https://github.com/ArnaudBelcour) for his works and frequent feedbacks.
+
+To [Domoritz](https://github.com/domoritz) for his questions and feedbacks.
+
+
+
+
+%prep
+%autosetup -n clyngor-0.4.3
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-clyngor -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Mon May 29 2023 Python_Bot <Python_Bot@openeuler.org> - 0.4.3-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..49f9257
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+dc2d6e7d044892fc659edee31564547d clyngor-0.4.3.tar.gz