Welcome to valasp’s documentation!

ValAsp is validation framework for Answer Set Programming developed by Mario Alviano and Carmine Dodaro.

The idea of valasp is to inject validation without cluttering the ASP encoding. It can be done by decorating Python classes, or by processing a YAML file. Below is an example usage of the Python layer.

import datetime

from clingo import Control
from valasp.core import Context
from valasp.domain.primitive_types import Fun, String

def main():
    context = Context()

    @context.valasp(validate_predicate=False, with_fun=Fun.IMPLICIT)
    class Date:
        year: int
        month: int
        day: int

        def __post_init__(self):
            datetime.datetime(self.year, self.month, self.day)

    @context.valasp()
    class Birthday:
        name: String
        date: Date

    res = None

    def on_model(model):
        nonlocal res
        res = []
        for atom in model.symbols(atoms=True):
            res.append(atom)

    context.valasp_run(Control(), on_model, ['birthday("sofia",date(2019,6,25)). birthday("leonardo",date(2018,2,1)).'])
    print(res)  # [birthday("sofia",date(2019,6,25)), birthday("leonardo",date(2018,2,1))]

    context.valasp_run(Control(), aux_program=['birthday("no one",date(2019,2,29)).'])
    # a RuntimeException is raised because the date is not valid

if __name__ == '__main__':
    main()

Attributes can be declared also using int and str, or the clingo types. If you use @-terms, pass them to the wrap arguments of the constructor, as in the following example.

from clingo import Control
from valasp.core import Context


def prec(x):
    return x.number - 1


def succ(x):
    return x.number + 1


def main():
    context = Context(wrap=[prec, succ])  # or wrap=globals().values() to add all function

    @context.valasp()
    class Num:
        value: int


    res = None

    def on_model(model):
        nonlocal res
        res = []
        for atom in model.symbols(atoms=True):
            res.append(atom)

    context.valasp_run(Control(), on_model, ['num(@prec(0)). num(@succ(0)).'])
    print(res)  # [num(1), num(-1)]


if __name__ == '__main__':
    main()

Even if you opted for putting @-terms in a class, you can still wrap an instance of that class, as done below.

from clingo import Control
from valasp.core import Context


class AtTerms:
    def prec(self, x):
        return x.number - 1


    def succ(self, x):
        return x.number + 1


def main():
    context = Context(wrap=[AtTerms()])

    @context.valasp()
    class Num:
        value: int


    res = None

    def on_model(model):
        nonlocal res
        res = []
        for atom in model.symbols(atoms=True):
            res.append(atom)

    context.valasp_run(Control(), on_model, ['num(@prec(0)). num(@succ(0)).'])
    print(res)  # [num(1), num(-1)]


if __name__ == '__main__':
    main()

Another option is to run clingo with validation:

#script(python).

from clingo import Control
from valasp.core import Context


def prec(x):
    return x.number - 1


def succ(x):
    return x.number + 1


def main(prg):
    context = Context(wrap=[prec, succ])

    @context.valasp()
    class Num:
        value: int

    prg.add("valasp", [], context.valasp_validators())
    prg.ground([('base', []), ('valasp', [])], context=context)
    prg.solve()

#end.

num(@prec(0)). num(@succ(0)).

Indices and tables