Arxiv:2103.01395V3 [Cs.LO] 19 May 2021 Ueaei Oiae Nprsb Xlrn O a H Embed the Far How Benefit
Total Page:16
File Type:pdf, Size:1020Kb
The Fusemate Logic Programming System (System Description) Peter Baumgartner[0000−0002−6559−9654] Data61/CSIRO and The Australian National University, Canberra, Australia [email protected] Abstract. Fusemate is a logic programming system that implements the possible model semantics for disjunctive logic programs. Its input language is centered around a weak notion of stratification with comprehension and aggregation oper- ators on top of it. Fusemate is implemented as a shallow embedding in the Scala programming language. This enables using Scala data types natively as terms, a tight interface with external systems, and it makes model computation available as an ordinary container data structure constructor. The paper describes the above features and demonstrates them with a non-trivial use-case, the embedding of the description logic ALCIF into Fusemate’s input language. This version of the paper corrects an error in the published version, which used an unsuitable version of “blocking” in the ALCIF embedding. 1 Introduction Fusemate1 is a logic programming system for computing possible models of disjunctive logic programs [23,24]. A Fusemate logic program consists of (typically) non-ground if-then rules with stratified default negation in the body [21]. Stratification entails that a true default-negated body literal remains true in the course of deriving new conclusions. Fusemate was introduced in [7] for modelling systems that evolve over time and for analysing their current state based on the events so far. Such tasks are often sub- sumed under the terms of stream processing, complex event recognition, and situational awareness, and have been addressed (also) with logic-based approaches [2,9,4,5]. To my knowledge,Fusemate is unique among all these and other logic programming systems [12,1,13,26,16] (and theorem provers) in the way it is implemented. Fusemate is arXiv:2103.01395v3 [cs.LO] 19 May 2021 implementedby shallow embeddingin a full-fledgedprogramminglanguage,Scala [25]. Essentially, the user writes a syntactically sugared Scala program utilizing familiar logic programming notation, and the program’s execution returns models. This has advantages and disadvantages. The main disadvantages is that it is more difficult to implement performance boosting measures like term indexing. The main advantage is that interfacing with data structure libraries and with external systems is easy, an aspect whose importance has been emphasized for virtually all of the above systems. In fact, Fusemate is motivated in parts by exploring how far the embedding approach can be pushed and to what benefit. 1 Fusemate is available at https://bitbucket.csiro.au/users/bau050/repos/fusemate/. 2 P. Baumgartner The earlier Fusemate paper [7] focused on the model computation calculus with a belief revision operator as the main novelty. It utilized a certain notion of stratification by time (SBT) for making the calculus effective and useful in the intended application areas. This system description focuses on the advantages of the shallow embedding approach as boosted by new language features introduced here. These new language features are (a) non-standard comprehension and aggregation operators, among others, and (b) a weaker notion of stratification by time and predicates (SBTP). In brief, SBTP is a lexicographic combination of stratification by time and the standard stratification in terms of the call-graph of the program. Section 5 has an example that demonstrates the need for (a) and (b) in combination, and Section 4 discusses the shallow embedding approach and its advantages on a more general level. Here is an excerpt from a Fusemate programthat previews some of the new features: 1 type Time = java.time.LocalDateTime 2 val allIds = 1to10 3 case class Change(time:Time, id:Int, color:String) extends Atom 4 case class State(time:Time, id:Int, color:String) extends Atom 5 case class FullState(time:Time, drive:Set[Int], stop:Set[Int]) extends Atom 6 State(time, id, color) :- Now(time), CHOOSE(id:Int, allIds), Change(t <= time, id, color) 7 FullState(time, drive.toSet, stop.toSet) :- State(time,_,_), 8 COLLECT(drive:List[Int], id STH State(time, id, "green")), 9 COLLECT(stop:List[Int], id STH (State(time, id, color), color=="red" || color=="yellow")) 10 MovingState(time) :- FullState(time, drive, stop), stop.size < drive.size 11 Faulty(time, id, since) :- State(time, id, "red"), Change(since < time, id, "green"), 12 NOT (Change(t, id, "yellow"), since < t, t< time) The scenario comprises traffic lights identified by numbers 1 to 10 (line 2). In the course of time the traffic lights change their colors, and each such event is recorded as a corresponding Change atom (line 3). The rule on line 6 computes a State at a current time Now(time) as a snapshot of the current colors of all traffic lights. For that, the comprehension Change(t <=time,id,color) on line 6 finds the latest Change event before or at time for a fixed id chosen from allIds, and binds that time to the (unused) variable t.A FullState aggregates the separate State facts at a time partitioned as (Scala) sets of ids of “drive” and “stop” colors. In that, the COLLECT special form collects in a Scala List-typed variable the specified terms that satisfy the body behind STH. Notice that all atoms in FullState refer to the same time, yet the program is SBTP because State comes before FullState in predicate stratification. (Predicate stratification is computed automatically by Fusemate with Tarjan’s algorithm.) The rule on line 10 demonstrates the use of the Scala Set method size in the body. Line 11 demonstrates the use of default negation in combination with comprehension. When applied to a given sequence of Change events, Fusemate computes models, one-at-a-time, each as Scala set of atoms. 2 Fusemate Programs For the purpose of this paper, a brief summary of the syntactic notions underlying Fusemate programsis sufficient; see [7] for details. Termsand atomsof a given signature The Fusemate Logic Programming System (System Description) 3 are defined as usual. Let var(I) denote the set of variables occurring in an expression I. We say that I is ground if var(I) = ∅. We write If for applying a substitution f to I. The domain of f is denoted by dom(f). A substitution W is a grounding substitution for I iff dom(W) = var(I) and IW is ground. In this case we simply say that W is for I. Let T be a countably infinite discrete set of time points equipped with a total strict ordering < (“earlier than”), e.g., the integers. Assume that the time points, comparison operators = and ≤, and a successor time function +1 are part of the signature and interpreted in the intended way. A time term is a (possibly non-ground) term over the sub-signature T ∪ {+1}. The signature may contain other “built-in” predicate and function symbols for pre- defined types such as strings, arithmetic data types, sets, etc. We only informally assume that all terms are built in a well-sorted way and that built-in operators over ground terms can be evaluated effectively. An ordinary atom (with time term C) is of the form ?(C, C1,...,C=) where ? is an ordinary predicate (i.e., neither a time predicate nor built-in), C is a time term and C1,...,C= terms. A (Fusemate) rule is an implication written in Prolog-like syntax as :- 11,...,1: , not 1ì:+1,..., not 1ì= . (1) In (1), a rule head is either (a) a disjunction ℎ1 ∨···∨ ℎ< of ordinary atoms, for some < ≥ 1, or (b) the expression fail.2 In case (a) the rule is ordinary and in case (b) it is a fail rule. A rule body , the part to the right of :-, is defined by mutual recursion as follows. A positive body literal is one of the following: (a) an ordinary atom, (b) a comprehension atom (with time term G) of the form ?(G ◦ C, C1,...,C=) sth , where G is a variable, ◦ ∈ {<, ≤,>, ≥} and is a body, (c) a built-in call , i.e., an atom with a built-in predicate symbol, or (d) a special form let(G, C), choose(G, ts), match(C, B) or collect(G, C sth ) where G is a variable, B, C are terms, ts is a list of terms, and is a body. A positive body is a list 1ì = 11,...,1: of positive body literals with : ≥ 0. If : = 0 then 1ì is empty otherwise it is non-empty.A negative body literal is an expression of the form not 1ì, where 1ì is a non-empty positive body. A body is a list = 11,...,1: , not 1ì:+1,..., not 1ì= comprised of a (possibly empty) positive body and (possibly zero) negative body literals. It is variable free if var(11,...,1: ) = ∅. Let A be a rule (1). We say that A is range-restricted iff var() ⊆ var(1ì). Compared to the usual notion of range-restrictedness [18], Fusemate rules may contain extra variables in negative body literals. For example, p(C,G) :- q(C,G), not(B < C, r(B,G,H)) is range-restricted in our sense with extra variables B and H. The extra variables are implicitly existentially quantified within the not expression. The example correspondsto the formula q(C,G)∧¬∃B, H.(B < C∧r(B,G,H)) → p(C,G). Semantically and operationally this will cause no problems thanks to stratification, introduced next. Fusemate programs– sets of rules – need to be “stratified by time and by predicates” (SBTP). The standard notion of stratification by predicates means that the call graph of the program contains no cycles going through negative body literals. The edges of this call graph are the “depends on” relation between predicate symbols such that ? 2 This definition of head is actually simplified as Fusemate offers an additional head operator for belief revision, see [7].