Metadata-Version: 1.1
Name: clyngor
Version: 0.3.5
Summary: Python wrapper around Clingo/Answer Set Programming
Home-page: https://github.com/aluriak/clyngor
Author: Lucas Bourneuf
Author-email: lucas.bourneuf@laposte.net
License: GPL
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, parsing error handling
        
        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.
        
        
        ### 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.
        
        
        
        ## Alternatives
        [pyasp](https://github.com/sthiele/pyasp) comes into mind, but does not supports clingo alone.
        
        
        
        ## 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).
        
        
        ### `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))
        
        
        ## Changelog
        
        - 0.4.0
            - 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
        ```
        
Keywords: Answer Set Programming,wrapper,clingo
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: ASP
