Evolog - Support for actions and program modularization#364
Open
madmike200590 wants to merge 65 commits into
Open
Evolog - Support for actions and program modularization#364madmike200590 wants to merge 65 commits into
madmike200590 wants to merge 65 commits into
Conversation
…e StratifiedEvaluation
…st<Term>> rather than just Set<List<ConstantTerm>> so we can have module interpretations returning function terms
…s interpretations for module literals by wrapping calls to the ASP solver.
…n. Add very simple end2end test with module-based 3-coloring implementation.
…cluding unit tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Support for actions and program modularization
Detailed formal semantics for both actions and modules are described in Chapter 3 of [1].
Action Rules
Overview
Action rules allow for so-called side-effects in an ASP program, i.e. when an action rule fires, certain changes (such as opening or writing to files) can be applied to the environment. Consider the following Hello World-style example:
The rule on line 2 is an action rule:
hello_result(R) : @streamWrite[STDOUT, TEXT] = Ris an action head, wherehello_result(R)is a regular head atom, but@streamWrite[STDOUT, TEXT] = Rreferences an action function that has 2 input terms (variablesSTDOUTandTEXT) and yields the result termR.@streamWrite[STDOUT, TEXT]writes the stringTEXTto the file descriptorSTDOUT. VariableSTDOUTis bound by an external atom&stdout(STDOUT)which always supplies a reference to the standard output stream.Semantics and Restrictions
To stay in line with ASPs declarative semantics, action rules in Alpha
Hello World!is only written to the console once, regardless of the solver's actual evaluation strategy.Implementation
Rules with action heads are modelled as instances of
NormalRulewhose head is an instance ofActionHead:Interpretation of rules with action heads
Due to the restriction on program structure stated above, where actions may only occur in stratifiable programs, interpretation of action heads is implemented directly in
StratifiedEvaluation.Given a satisfying substitution for the body,
fireRulechecks whether the head of the rule in question is anActionHeadand, if so, callsinstantiateActionHead:Here, the actual action (i.e. the side-effect modifying the state of the outside world) is performed by calling an
ActionExecutionService. The result of this call is anActionWitnesswhich represents the information from a head atom of an action application rule as described in section 3.1 of [1]. The atom that is added to an answer set as a result of firing a rule with an action head, is obtained from theActionWitness:This atom is exactly what is described as the head atom of an action projection rule in section 3.1 of [1].
It's important to note that a distinct action is only ever executed once, i.e. even if the exact same rule is grounded and fired more than once, the resulting side-effect is only applied once. This is achieved through caching of action results in
ActionExecutionServiceImpl:Program Modularization
The second major part of this PR is program modularization. It adds
ModuleAtoms as possible form of a body atom. Conceptually, aModuleAtomworks like an external atom - based on some input terms, a (side-effect-free) function is evaluated and the function result is assigned to a list of output terms.In the case of a module atom, the function in question is the evaulation of an ASP program, where the atom's input terms are translated to facts that get added to said program. Each answer set of the module program is transformed into a list of terms that make up the output terms for one ground instance of the module atom.
A module atom yields one ground instance per answer set for each unique combination of input terms. The detailed formal syntax and semantics of Modules are described in Section 3.2 of [1].
Module definitons and usage in rules
An ASP-program that can be used as a module atom in other programs needs to be defined within a
#module ...-Section, e.g.:In the module declaration at the start of the section (i.e.
#module threecol(graph/2 => {col/2})),threecolis the name (i.e. unique identifier) of the module,graph/2is an input predicate, and{col/2}denotes the set of output predicates for the module. Note that there may be multiple input predicates as well as output predicates.A program using the above module definition to calculate 3-colorings of a graph could look as follows:
Looking at the module atom
#threecol{2}[VERTEX_LST, EDGE_LST](COL),threecoldenotes the name of the module{2}is the number of answer sets that should be calculated. This can be omitted, in which case all answer sets are calculatedVERTEX_LSTandEDGE_LSTare input termsCOLis an output termThe sole answer set of the program above is:
Note that each graph coloring calculated by the
threecol-module is represented as onecoloring-Atom. The term holding the actual coloring is structured as alist-term(see below) and holds the assigned color for each vertex.List Terms
Since module atoms can only accept and yield terms as inputs and outputs, list terms were intoduced as a means of grouping multiple terms into one.
A list term representing the list
[a, b, c]is writtenlst(a, lst(b, lst(a, lst_empty))), i.e. a list term is a binary function term with function symbollstwhose first argument is the head element of a list, and the second argument is the remainder (i.e. tail) of the list. The constantlst_emptyrepresents the empty list.The aggregate function
#listcan be used to group instances of a predicate into a term list, as demonstrated in the rule to construct a vertex list:vertex_list(VLST) :- VLST = #list{V : vertex(V)}.In the example above, the resulting atom isvertex_list(lst(a, lst(b, lst(c, lst_empty)))).If a program needs to pass in multiple terms into a module atom, this can be achieved suing list terms as demonstrated above. The module program then needs to unwrap the list term accordingly (see example above).
Since one ground instance of a module atom always corresponds to one answer set for a given substitution of input terms, atoms within that answer set are also represented as list terms, as can be seen in the above example, where one coloring is represented as
coloring(lst(col(a, red), lst(col(b, green), lst(col(c, blue), lst_empty)))).Interpretation of module atoms
In Alpha, module atoms are implemented as follows:
During parsing, module definitions (i.e. ASP subprograms constituting modules) are written into a list of modules that is attached to the main program:
Module atoms are represented as a specific kind of atom after parsing and cannot be directly grounded (i.e. evaluated) like external atoms:
The actual linking from module atoms to the corresponding module definitions happens in a
ProgramTransformationcalledModuleLinker. Here, for each module atom, an actualExternalAtomis constructed, which runs the program from the module definition:The actual translation step happens inside the method
translateModuleAtom:Here, we define the interpretation function for the newly-created external atom to be the result of calling
moduleRunner.solve(....)for the program resulting from adding facts corresponding to the input terms of the module atom to the program constituting the module definition.moduleRunneris an instance of the Alpha solver that is used to run the program. The resultingExternalAtomcan the be evaluated like any other external atom, i.e. modularization is completely invisible to the grounder and solver components.[1]: https://repositum.tuwien.at/handle/20.500.12708/220293 Michael Langowski. Evolog-Actions and Modularization in Lazy-Grounding Answer Set Programming. Master Thesis, Technische Universität Wien, 2025.