# Syntax of LPS [TOC] lps.swi is the LPS implementation based on SWI-Prolog. The surface syntax used in lps.js is slightly different. The current syntax of LPS is essentially a superset of @SWI-Prolog](http://www.swi-prolog.org), adding a flexible mixture of explicit and implicit time and some additional rules and declarations. ### Comments ``` % written either in this form /* or in this form, which is convenient if they occupy several lines. */ ``` ### Declarations: ``` maxTime(_). fluents … . events … . actions … . ``` ### Inputs ``` initially … . observe … . ``` ### Reactive rules ``` if … then … . ``` ### Clauses for time-dependent predicates ``` … if … . ``` ### Clauses for timeless predicates (e.g. Prolog) ``` … :- … . ``` ### Causal laws ``` … initiates … if … . … terminates … if … . ``` ### Constraints ``` false … . ``` In more detail: ## Declarations. ``` #! maxTime(_). ``` This is an optional declaration of the maximum number of states. If the declaration is not present, the maximum is currently set at 20 by default. ``` #! fluents fluent1, fluent2, …, fluentn. % n >= 1 ``` Fluents are time-dependent atomic sentences. Here they are specified by giving the name of the fluent followed by its arguments. For example, a two-argument fluent named location could be specified by any one of location/2, location(_,_), or location(_object, _place), where _, _object, and _place are “anonymous variables”. Fluents can be “extensional” if they are represented by “facts” and updated by events or “intensional” if they are represented by clauses that mirror changes of the extensional fluents. ``` #! events event1, event2, … , eventn. % n >= 1. ``` Events can be external, given by observations, or generated by the system. They can be “atomic”, taking place instantaneously from one state to the next, or “composite”, taking place over a series of zero or more states. For example, say/2, say(_,_) or say(_agent, _expression). ``` #! actions action1, action2, …, actionn. % n >= 1. ``` Actions are “atomic”, taking place instantaneously, and are generated by the system. They have the same syntax as events, and can also be declared as events, which may be external. ## Inputs. ``` #! initially fluent1, fluent2, … , fluentn. % n >= 1. ``` This specifies the extensional fluents that are true in the initial state at time 0. ``` #! observe event1, event2, … , eventn from time1 to time2. % n >= 1. ``` time1 and time2 should be successive positive integers, e.g. from 2 to 3. The program can have multiple observe statements with different times. ## Reactive rules. ``` #! if literal1, … , literaln then literaln+1, … , literaln+m. % n >= 1 and m >= 1. ``` Each literal is a timed or untimed atomic formula or the negation of an atomic formula. (See below.) Implicitly all times after "then" are later than or equal to the latest time before "then". Also, no time after a comma is earlier than any time before the same comma. ## Clauses for time-dependent predicates. ``` #! atomic formula if literal1, … , literaln. % n > 1. ``` ``` #! atomic formula. % n = 0. ``` These clauses are used to define: * 1) intensional predicates, which change as a consequence of changes to extensional predicates. For example (with explicit time) ``` #! location(Object, Place) at T if holding(Agent, Object) at T, location(Agent, Place) at T. ``` These can also be written without explicit time: ``` #! location(Object, Place) if holding(Agent, Object), location(Agent, Place). ``` * 2) composite actions and events, which can take place over zero or more state transitions. For example (with explicit time): ``` #! makeAt(Agent, Place) from T to T if location(Agent, Place) at T. makeAt(Agent, Place) from T1 to T2 if not location(Agent, Place) at T1,move(Agent, Place) from T1 to T2. ``` Traditional clauses in Prolog are also allowed: ``` #!prolog atomic formula :- literal1, … , literaln. % n > 0. ``` These clauses can be used to define time-independent predicates directly in Prolog. For example, ``` #!prolog parent(X,Y) :- mother(X,Y). parent(X,Y) :- father(X,Y). ``` The implementation does not support the logical connective for disjunction. So the following definition of parent does not work. ``` #!prolog parent(X,Y) :- mother(X,Y);father(X,Y). ``` Prolog predicates includes all time-independent predicates, including temporal inequalities, e.g. philosopher(hume) and T1 < T2. ## Causal laws ``` #! event initiates fluent if literal1, … , literaln. % n > 0. ``` Here event is an external event or an atomic (non-composite) action. event, fluent and literals can all be written without explicit time. Implicitly, if the event takes place from T to T+1 then fluent is true at time T+1 if all the literals are true at time T. Do we allow the literals be events? (to be answered). ``` #! event terminates fluent if literal1, … , literal. % n > 0. ``` Like initiates, implicitly, if the event takes place from T to T+1 then the fluent at time T is terminated. It is possible for a fluent to be initiated and terminated at the same time, but by different events, as for example, when a subscription runs out, but is renewed at the same time. ## Constraints. ``` #! false literal1, literal2, … , literaln. % n > 1 ``` These are used to constrain candidate actions, say from T to T+1. So one of the literals must be an action. Other literals can be actions or external events that also occur from T to T+1. They can also be fluents that are true at time T. Because of these restrictions on time, these constraints can be written without explicit time. Fluent literals in constraints can be negative literals, but action and other event literals can not be negated. ## Literals ``` #!prolog predicate(term1, term2, … , termn) % n > 0 ``` Such literals are also called (untimed) atomic formulas, or simply atoms, and can be fluents, events, or time-independent. The predicate must start with a lower case letter. The terms can be variables, constants (numbers or strings starting with a lower case letter), numbers, or any expression allowed by Prolog. Variables follow the Prolog convention of starting with an upper case letter, or with _ if their name does not matter because it does not occur elsewhere in the same sentence. ``` #!prolog not atom ``` atom can be an atomic fluent. Other uses of negation are under investigation. ``` #!prolog fluent at T ``` Here T is a time variable. However, the possibility that T may be a constant time has not been excluded. ``` #!prolog event from T1 to T2 event from T1 event to T2 ``` These all have their obvious intended meanings. ## Notes * 1) Most of the components listed above are optional. To be meaningful an LPS program needs only reactive rules and actions, for example, the program: ``` #! actions rain. if true then rain. if rain then rain. ``` generates a sequence of 19 actions: ``` #! rain, rain, …, rain. ``` * 2) Literals in reactive rules and clauses are processed Prolog-like, in the order in which they are written. Processing is suspended if the time of a fluent or the start time of an event is later than the current time, or if the time is a variable and the literal cannot be made true at the current time, but might become true later. * 3) Times can be omitted from fluents and events. However, for this to work, composite events and actions need to be declared as events, and intensional fluents need to be declared as fluents. This feature is currently under development, and is subject to change. Implicit and explicit times can be mixed in the same sentence. Currently, the interpreter interprets implicit times according to the following rules: The expression: ``` #! fluent1, fluent2 ``` means ``` #!prolog fluent1 at T1, fluent2 at T2, T1 =< T2. ``` The expression: ``` #! fluent, event ``` means ``` #!prolog fluent at T1, event from T2 to T3, T1 =< T2. ``` The expression: ``` #! event1, event2 ``` means ``` #!prolog event1 from T1 to T2, event2 from T3 to T4, T2 =< T3. ``` The expression: ``` #! event, fluent ``` means ``` #!prolog event from T1 to T2, fluent at T3, T2 =< T3. ``` The expression: ``` #! event if conditions ``` means ``` #!prolog event from T1 to Tn if conditions ``` where T1 is the earliest time in conditions and Tn is the latest time in conditions. The expression: ``` #! fluent if conditions ``` means ``` #!prolog fluent at T if conditions ``` where all the time variables in conditions are identical to T. * * * ## LPS syntax (tentative) summary ## Files have the .lps extension and (more or less) the following structure. Please, beware, this is just a rough approximation: ``` #! spec ::= statement statement ::= settings rules settings ::= max_time actions fluents initial_state observations rules ::= if_then_rules if_rules initiate_rules terminate_rules constraints if_rules ::= if_rule | if_rule if_rules if_rule ::= literal "." | literal "if" conjunction "." | literal ":-" conjunction "." if_then_rules ::= if_then_rule | if_then_rule if_then_rules if_then_rule ::= "if" conjunction "then" conjunction "." constraints ::= constraint | constraint constraints constraint ::= "false" conjunction "." conjunction ::= "true" | literal | literal "," conjunction ``` * * * ## Internal syntax ## NOTE: to see your program in this syntax, use ```dump.```in the SWISH query panel. Files have the .lpsw extension and (more or less) the following structure: ``` #! spec ::= statement statement ::= settings rules settings ::= max_time actions fluents initial_state observations events rules ::= if_rules reactive_rules initiate_rules terminate_rules constraints if_rules ::= if_rule | if_rule if_rules if_rule ::= timeless_rule | event_rule | prolog_clause timeless_rule ::= "l_timeless(" literal "," conjunction ")." event_rule ::= "l_events(" happens_literal "," hold_conjunction_list ")." reactive_rules ::= if_then_rule | if_then_rule if_then_rules if_then_rule ::= "reactive_rule(" conjunction "," conjunction ")." constraints ::= constraint | constraint constraints constraint ::= "d_pre(" conjunction ")." conjunction ::= "true" | literal | literal "," conjunction ```