=Paper=
{{Paper
|id=None
|storemode=property
|title=Temporal
Meta-Axioms in Logical Agents
|pdfUrl=https://ceur-ws.org/Vol-857/paper_f05.pdf
|volume=Vol-857
|dblpUrl=https://dblp.org/rec/conf/cilc/CostantiniT12
}}
==Temporal
Meta-Axioms in Logical Agents==
Temporal Meta-Axioms in Logical Agents Stefania Costantini1 and Panagiota Tsintza1 Dip. di Ingegneria e Scienze dell’Informazione (DISIM), Università di L’Aquila, Coppito 67100, L’Aquila, Italy stefania.costantini@univaq.it, panagiota.tsintza@univaq.it Abstract. This paper deals with run-time detection and possible correction of erroneous and/or anomalous behavior in agents defined in datalog- or prolog- based logic languages. In particular, we augment our previous approaches by allowing an agent to explicitly observe and record its past behavior so as to be able to decide its best actions, detect anomalous behavior and try to dynamically correct detected problems. 1 Introduction Agents, in their interaction with the environment, are subject to modify themselves and evolve according to both external and internal stimuli, the latter due to the proactive and deliberative capabilities of the agent themselves. In previous work, we defined semantic frameworks for datalog-based and prolog- based logical agents that account for: (i) the kind of evolution of reactive and proactive agents due to directly dealing with stimuli, that are to be coped with, recorded and possibly removed [1,2]; and (ii) the kind of evolution related to adding/removing rules from the agent knowledge base. These frameworks have been integrated into an overall framework for logical evolving agents (cf. [3,4]), where every agent is seen as the com- position of a base-level (or object-level) program and one or more meta-levels. In this model, updates related to recoding stimuli are performed in a standard way, while up- dates involving the addition/deletion of sets of rules, related to learning, belief revision, etc. are a consequence of meta-level decisions. As agent systems are more widely used in real-world applications, the issue of ver- ification is becoming increasingly important (see [5] and the many references therein). The motivation of the work presented in this paper is that, though agents behavior is affected by their interaction with the external world, in most practical cases the actual arrival order of events is unforeseeable. Often, the set of possible events is so large that computing all combinations would result in a combinatorial explosion, thus making “a priori” (static) verification techniques somewhat unpractical. Properties that one wants to verify often depend upon which events have been ob- served by an agent up to a certain point, and which others are supposed to occur later. We believe that static verification should be integrated with dynamic self-checking aimed at detecting properties violation and trying to restore an acceptable or desired state of affairs. The definition of frameworks such as the one that we propose here, for checking agent behavior during its life based on its experience, has not been widely treated up to now. In the quest quest for agent platforms whose component entities would be capable of exhibiting a correct and rigorous behavior with respect to expectations, developers have frequently applied model-checking techniques (cf. [6] and Section 4 for a discus- sion of applications in the agent realm) that are based upon abstract models of an agent system. On the one hand however, not all properties can be statically verified. On the other hand, it would be useful to devise methods for reinstating a correct behavior at run-time in case unwanted situations should occur. Thus, we believe that the introduc- tion of forms of dynamic (self-)checking are necessary and can be useful. In this paper, we propose a method for checking the agent behavior correctness dur- ing the agent activity, based on maintaining information on its past “experiences” and behavior. If augmented by time stamps, these records (that we call past events) consti- tute in a way the history of the agent activity. The set of past events evolves in time, and past events constitute the ground upon which the agent can check its own behavior with respect to what has happened in the external environment (more precisely, with respect to what the agent has perceived about what has happened). To perform such checks, we introduce a new kind of constraints, that we call Evolutionary LTL Expressions, that according to what has happened and to what is supposed to happen in the future define properties that should hold and what should be done if they are violated. Evolutionary LTL Expressions are based upon specifying: (i) a sequence of events that are supposed to have happened; by using a notation obtained from regular expressions, one does not need to completely specify a finite sequence, but is allowed to define partially specified sequences of unlimited length; (ii) a temporal-logic-like expression defining a property that should hold; (iii) a sequence of events that are supposed to happen in the future, without affecting the property; (iv) a sequence of events that are supposed to happen in the future; (v) optionally, “repair” actions to be undertaken if the property is violated. The interval temporal logic adopted for defining properties has been introduced in pre- vious work. Evolutionary LTL Expressions are a novel feature that we introduce in this paper, and that we have (prototypically) implemented and experimented. Our approach can be adopted in any logic agent-oriented framework, and we be- lieve that, more generally, evolutionary LTL expressions can be adopted as a program- ming construct in event-based extensions to datalog and prolog. In particular, one such language is DALI [7,8], which is an agent-oriented extension to prolog. We have im- plemented the proposed approach in DALI, where we have performed the experiments presented below. The paper is structured as follows. In Section 2 we provide the reader with some background, concerning our declarative semantics of evolving agents, and temporal logic (extended to interval temporal logic). In Section 3 we introduce Evolutionary LTL Expressions, that define properties that are supposed to hold, given events that are supposed to have occurred in the past, and events that are supposed to occur or not to occur in the future. These expressions are actually constraints to be verified at run-time. We compare the proposed approach with other approaches to verification in Section 4. We introduce and discuss the problem of the experimental evaluation of the approach in Section 5. Finally, in Section 6 we conclude. 2 Background In this paper we will refer to the declarative semantics introduced in [1], aimed at declar- atively modeling changes inside an agent which are determined both by changes in the environment, that we call external events, and by the agent’s own self-modifications, that we call internal events. The key idea is to understand these changes as the result of the application of program-transformation functions. As a typical situation, perception of an external event will have an effect on the program which represents the agent: for instance, the event will be stored as a new fact. This transforms the program into a new program, that will procedurally behave differently than before, e.g., by possibly reacting to the event. Or, the internal event cor- responding to the decision of the agent to undertake an activity triggers a more complex program transformation, resulting in a version of the program where the corresponding intention is “loaded” so as to become executable. We abstractly formalize an agent as the tuple Ag = < PAg , E, I, A > where Ag is the agent name and PAg (that we call “agent program”) describes the agent behav- ioral rules. E is the set of the external events, i.e, events that the agent is capable to perceive and recognize: let E = {E1 , . . . , En } for some n. I is the internal events set (distinguished internal conclusions): let I = {I1 , . . . , Im } for some m. A is the set of actions that the agent can possibly perform: let A = {A1 , . . . , Ak } for some k. Let Y = (E ∪ I ∪ A). According to this semantic account, one will have an initial program P0 = PAg which, according to events that happen and actions which are performed, passes through corresponding program-transformation steps (each one transforming Pi into Pi+1 , cf. [1]), and thus gives rise to a Program Evolution Sequence P E = [P0 , ..., Pn , ...]. The program evolution sequence will imply a corresponding Semantic Evolution Sequence M E = [M0 , ..., Mn , ...] where Mi is the semantic account of Pi . The different languages and different formalisms in which an agent can possibly be expressed will influence the following key points: (i) when a transition from Pi to Pi+1 takes place, i.e., which are the external and internal factors that determine a change in the agent; (ii) which kind of transformations are performed; (iii) which semantic approach is adopted, i.e., how Mi is obtained from Pi . We also believe it useful to perform an Initialization step, where the program PAg written by the programmer is transformed into a corresponding program P0 by means of some sort of knowledge compilation. This initialization step can be understood as a rewriting of the program in an intermediate language and/or as the loading of a “virtual machine” that supports language features. This stage can on one extreme do nothing, on the other extreme it can perform complex transformations by producing “code” that implements language features in the underlying logical formalism. P0 can be simply a program (logical theory) or can have additional information associated to it. Let H be the history of an agent, that is, a set of events that happened and actions performed by the agent, each one time-stamped so as to indicate when they occurred. In particular, we introduce a set P of current “valid” past events that describe the state of the world as perceived by the agent1 , and a set PNV where we store all previous ones. Thus, the history H is the tuple hP, P N V i. In practice, H is dynamically augmented with new events that happen. Given set Y of events, if one is interested in identifying the kind of event, a postfix (to be omitted if irrelevant) can provide this indication. I.e., XE is an external event, XA is an action and XI an internal event. As soon as X is perceived by the agent, it is recorded in P in the form XP Y : Ti , Y ∈ {E, A, I}. In [2] we have defined Past Constraints, which allow one to define when and upon which conditions (apart from arrival of more recent ones) past events should be moved into PNV. Definition 1 (Evolutionary semantics). Let Ag be an agent. The evolutionary seman- tics εAg of Ag is a tuple hH, P E, M Ei, where H is the history of Ag, and P E and M E are its program and semantic evolution sequence. The next definition introduces the notion of instant view of εAg , at a certain stage of the evolution (which is in principle of unlimited length). Definition 2 (Evolutionary semantics snapshot). Let Ag be an agent, with evolu- tionary semantics εAg = hH, P E, M Ei. The snaphot at stage i of εAg i is the tuple hHi , Pi , Mi i, where Hi is the history up to the events that have determined the transi- tion from Pi−1 to Pi . For defining properties that are supposed to be respected by an evolving system, a well-established approach is that of Temporal Logic (introduced in Computer Science by Pnueli [9], for a survey the reader can refer to [10]), and in particular Linear-time Temporal Logic (LTL), that implicitly quantifies universally upon all possible paths. LTL logics are called linear because, in contrast to branching time logics, they evaluate each formula with respect to a vertex-labeled infinite path s0 s1 . . . where each vertex si in the path corresponds to a point in time (or “time instant” or “state”). LTL enriches an underlying propositional logic language with a set of temporal con- nectives composed of a number of unary and binary connectives referring to future-time and past-time. In prior work (see e.g., [11]), we introduced an extension to temporal logic based on intervals, where states in which a temporal formula is supposed to hold are explicitly stated. E.g., Gm,n (always in time interval) states that formula ϕ should become true at most at state sm and then hold at least until state sn . 3 Checking the behavior of Evolving Agents In this section we introduce Evolutionary LTL Expressions, which are aimed at check- ing an agent’s behavior at run-time under partially specified sequences of past and future events. This extends our past work [11] where we defined meta-axioms with repair to be undergone upon violation of given conditions, but without reference to event sequences. These expressions are based upon specifying: (i) a sequence of events that are supposed to have happened; by using a notation obtained from regular expressions, one does not 1 The agent is aware of the world through perceptions, that necessarily report a past (though hopefully recent) state. need to completely specify a finite sequence, but is allowed to define partially specified infinite sequences; (ii) a temporal-logic-like expression defining a property that should hold; (iii) a sequence of events that are supposed to happen in the future, without af- fecting the property; (iv) a sequence of events that are supposed not to happen in the future, otherwise the property will not hold any longer; (v) optionally, “repair” actions to be undertaken if the property is violated. According to the evolutionary semantics summarized above, time instants s0 s1 . . . concerning an agent’s “life” can be understood in terms of the events that happen. In fact, at the i-th evolution step we have an history Hi , an agent program Pi and its in- tended semantics Mi , determined by events E1 , . . . , Ei occurred so far. The next evo- lution step will take place in accordance to the perception of next event Ei+1 . Then, any property ϕ which holds w.r.t. εAgi , i.e. w.r.t. the agent evolutionary semantics up to step i, will keep holding until next event will determine a transition to the next snap- shot. In other words, the agent understands the world only in terms of the events that it perceives. Therefore we can define a state si as si = εAg i = hHi , Pi , Mi i. that is, a state is taken to be the snapshot at stage i of the evolutionary semantics of the agent. In model-checking, the aim is to establish if some LTL formula Op ϕ or ϕ Op ψ (where Op can be, for instance, N for “never”, E for “eventually”, etc.) can be es- tablished to be true, given a description of the system at hand from which the system evolution can be somehow elicited. In order to cope with the many cases where this evolution cannot be fully foreseen, we propose to exploit temporal logic operators in a different way than before, so as to take into account the events that have happened already and those that are expected to happen or not to happen in the future and that are relevant to the property that we intend to check. Definition 3 (Evolutionary LTL Expressions). Let τ be a temporal logic expression of the form Op ϕ if operator Op is unary or ϕ Op ψ if operator Op is binary, where Op can be an interval operator Opz,x . The evolutionary version of τ , that we will call Evolutionary LTL Expression, is of the form {EP1 , . . . , EPl } : τ :: {F1 , . . . , Fm } ::: {J1 , . . . , Jr } with l > 1 and m, r ≥ 0 where: – {EP1 , . . . , EPl } denote the relevant events which are supposed to have happened (without assumption about their order); i.e., these events act as preconditions: whenever they happen, τ will be checked; – {F1 , . . . , Fm } denote the events that are expected to happen in the future (without assumption about their order) without affecting τ ; – {J1 , . . . , Jr } denote the events that are expected not to happen in the future; i.e., whenever any of them should happen, τ is not required to hold any longer. The state until which τ is required to hold depends upon the current state sn and the operator Op occurring in τ with the following special cases. – τ contains an interval operator Opz,x : in this case, x is the state until which τ is required to hold; – one of the Ji ’s happens at state sw , w < x: then, τ is not required to hold after sw . Notice that both the Fi ’s and the Ji ’s are optional Notice also that, in general, we cannot foresee when (and in which order) the expected relevant events Fi ’s will happen. In many practical cases, we are unable to provide a full sequence of the expected events, and in particular to be aware of how many times they will occur. Sometimes, we will be interested in specifying the (partial) order in which they should occur. Thus, in the above definition, to be able to indicate the sets of past and future events in a more flexible way we admit in part the syntax of regular expressions [12]. We also extend this syntax, in order to specify a partial order among events. Definition 4. If E is an event, as customary in regular expressions E ∗ will indicate zero or more occurrences of E, and E + one or more occurrences. Given events E1 and E2 , by E1 • E2 we mean that E1 must occur before E2 and by E1 • •E2 we mean that E1 must occur immediately before E2 (i.e., the two events must be consecutive). Wild-card X, standing for any event, can be used. For instance, E1+ • X ∗ • E2 , E3 • •X • •E4 means that, after a certain (non-zero) number of occurrences of E1 and, possibly, of some unknown event X, E2 and E3 can occur in any order, immediately followed by some unknown event X and, immediately afterwards, by E4 . Notice that, for an agent, an event “occurs” when the agent perceives it. This is only partially related to when events actually happen in the environment where the agent is situated. In fact, the order of perceptions can be influenced by many factors. However, either events are somehow time-stamped (in a reliable way) whenever they happen so as to certify the exact time of their origin (as sometimes it may be the case), or an agent must rely on its own subjective experience. Evolutionary LTL Expressions are easily given a semantics in the context of the Evolutionary Semantics of an agent. Therefore, a given Evolutionary LTL Expression can be evaluated w.r.t. a state, i.e. (as seen above), a snapshot εAg i and will hold when- ever Hi encompasses the sequence of events that have been supposed to have occurred (i.e., they occur in Hi in the given order) and τ holds (i.e., i belongs to the given in- terval and the formula is true w.r.t. i). According to agent’s activities the agent will evolve to a new snapshot, in particular when a new event happens, either expected or unwanted. In the new snapshot, the given expression can be re-evaluated. This consti- tutes a “punctual” evaluation of the expression. An expression involving Opz,x can be finally deemed to hold whenever either the interval has expired and τ has been true in all points, or an unwanted event (one of the Ji s) has occurred. Instead, an expression can be deemed not to hold (or, as we often say, to be violated as far as it expresses a wished-for property) whenever τ is false in some point. In Definition 3 we do not require the EPi ’s, the Fi ’s and the Ji ’s to be ground terms. Instead, we admit each of them to contain variables if we are not interested in precisely specifying some of their parameters. For instance, the expression consumeA + (r, Q) (where postfix A as specified before indicates an action) stands for a sequence of events where the action of consuming (some resource r) occurs at least once. Each action will refer to an unspecified quantity Q. All variables occurring in evolutionary LTL expressions are implicitly universally quantified, as customary in datalog- and prolog- like logic languages. An evolutionary LTL expression could be for instance (where N stands for the LTL operator “never”): supplyP + (r, s) : N (quantity(r, V ), V < th) :: consumeA + (r, Q) stating that, after having provided a supply of resource r for a certain total quantity, the agent is expected to consume unknown quantities of the resource itself. The expression defines a constraint requiring that the available quantity of resource r must remain over a certain threshold th. Evolutionary LTL expressions are in fact supposed to act as constraints to be verified at run-time whenever new events are perceived. Notice in fact that the “supply” event is supposed to occur at least once, possibly an unlimited number of times. Interval-LTL formula τ = N (quantity(r, V ), V < th) will be (re-)evaluated after each occurrence. A violation will happen whenever τ does not hold. As another example, consider the following expression stating that, after a car has been submitted to a checkup, it is assumed to work properly for (at least) six months, even in case of (repeated) long trips, unless an accident occurs. checkupP (Car) : t1 : Gt1 ,t1+6months work ok(Car) :: long trip + (Car) ::: accident(Car) In the above example we have used the operator Gt1 ,t2 , t2 = t1 + 6months which is an interval LTL operator, G standing for “always”. We may notice the similarity between evolutionary LTL expressions and event- calculus formulations. The Event Calculus has been proposed by Kowalski and Sergot [13] as a system for reasoning about time and actions in the framework of Logic Programming. The essential idea is to have terms, called fluents, which are names of time-dependent relations. Kowalski and Sergot write holds(r(x, y), t) which is understood as “fluent r(x, y) is true at time t”. Take for instance the default inertia law, stating when fluent f holds, formulated in the event calculus as follows: holds(f, t) ← happens(e), initiates(e, f ), date(e, ts ), ts < t, not clipped(ts , f, t) The analogy consists in the fact that, in the above LTL expression, past event checkupP (Car) : t1 initiates a fluent which is actually an interval LTL expression, namely Gt1 ,t1+6months work ok(Car), which would be “clipped” by accident(Car), where a fluent which is clipped does not hold any longer. The evolutionary LTL expres- sion contains an element which constitutes an addition w.r.t. the event calculus formu- lation: in fact, long trip + (Car) represents a sequence of events that is expected, but by which the fluent should not be clipped if everything works as expected. In our opinion, evolutionary LTL expressions might in perspective be considered as a useful programming construct in datalog and prolog (and their extensions). In fact, also by means of interval LTL operators, propositions holding over intervals in a dy- namic setting can be expressed in a direct and compact way. Below we state when an evolutionary LTL expression is defined to hold. Definition 5. An evolutionary LTL expression E, of the form {EP1 , . . . , EPl } : τ :: {F1 , . . . , Fm } ::: {J1 , . . . , Jr } holds in state si whenever (i) some of the EP1 , . . . , EPl has happened, some (or none) of the F1 , . . . , Fm has happened, none of the J1 , . . . , Jr has happened, and τ holds or (ii) some of the J1 , . . . , Jr has happened. As said before, whenever an unwanted event (one of the Ji s) should happen, τ is not required to hold any longer (though it might). The proposition below formally allows for dynamic run-time checking of evolutionary LTL expressions. In fact, it states that, if a given expression holds in a certain state and is supposed to keep holding after the first expected event has happened, then checking this expression amounts to checking the modified expression where: (i) the occurred event has become a past event, and (ii) subsequent events are still expected. Proposition 1. Given evolutionary LTL expression E = {EP1 , . . . , EPl } : τ :: F ::: J , where F = {F1 , . . . , Fm } and J is the list of unexpected events, assume that E holds at state sn and that it still holds after the occurrence of event Fi ∈ F at state sv (v ≥ n), and that none of the events in J has happened. Let F1 = F \ Fi . Given EFi = {EP1 , . . . , EPl , FiP } : τ :: F1 ::: J we have that for every state sw with (w ≥ v) E holds iff EFi holds. In prior work (see e.g., [4,11]), we introduced temporal logic rules with repair, where actions could be specified in order to cope with unwanted situations. We extend this approach to the present work. We distinguish between two cases: in the former, none of the unwanted events has happened, and nevertheless the inner interval LTL formula τ does not hold; the latter, where τ does not hold because some of the unwanted events has occurred (in this case however, according to previous definitions the overall expression still holds). Definition 6. An evolutionary LTL expression E, of the form {EP1 , . . . , EPl } : τ :: {F1 , . . . , Fm } ::: {J1 , . . . , Jr } is violated in state si whenever some of the EP1 , . . . , EPl has happened, some (or none) of the F1 , . . . , Fm has happened, none of the J1 , . . . , Jr has happened, and τ does not hold. Definition 7. An evolutionary LTL expression E, of the form {EP1 , . . . , EPl } : τ :: {F1 , . . . , Fm } ::: {J1 , . . . , Jr } is broken in state si whenever some of the EP1 , . . . , EPl has happened, some (or none) of the F1 , . . . , Fm has happened, some of the J1 , . . . , Jr has happened, and τ does not hold. Whenever an evolutionary LTL expression is either violated or broken, a repair can be attempted with the aim of recovering the agent’s state. LTL expressions will be “hosted” in some logic agent-oriented programming language L. The repairs will be program fragments written in L to be executed upon violations. Definition 8. An evolutionary LTL expression with repair E R is of the form: E|R1 ||R2 where E is an evolutionary LTL expression adopted in a language L, and R1 , R2 are program fragments written in L. R1 will be executed whenever F R is violated, and R2 will be executed whenever F R is broken. Going back to the example of the car, let us assume that, if before six months after a checkup we have a malfunctioning, then one is entitled to get free assistance; in case of an accident instead, one has (say) to call the police. Again, let’s assume that postfix ’A’ indicates actions. checkupP (Car) : t1 : Gt1 ,t1+6months work ok(Car) :: long trip + (Car) ::: accident(Car) | call f ree assistanceA(Car, Address) || call policeA(Address) Let us now assume that language L provides distinguished preconditions to actions, i.e., distinguished predicates defining preconditions that are implicitly added to every action. Let us assume that prevent(Action), whenever true, prevents an action from being performed, and allow (Action, Condition) allows an action to be performed only if the specified condition holds2 . Then, we assume that an action can be performed only if not prevented and allowed. The evolutionary LTL expression with improvement listed below states that no more consumption can take place if the available quantity of resource r is scarce. supplyP + (r, s) : N (quantity(r, V ), V < th) :: consumeA + (r, Q) | prevent(consumeA (r, Q)) We might instead adopt another (softer) constraint, that forces the agent to limit con- sumption to small quantities (say less than quantity q) if it is approaching the threshold (say that the remaining quantity is th + f , for some f ). supplyP + (r, s) : N (quantity(r, V ), V < th + f ) :: consumeA + (r, Q) | allow (consumeA (r, Q), Q < q) 4 Related Work Verification of agent programs can to some extent be performed statically (i.e., prior to agent activation), by checking the system against any possible input configura- tion, sequence of external events, etc., Static verification can be accomplished through model-checking techniques [6], abstract interpretation [14] or theorem proving (the lat- ter two not commented here). Although model-checking techniques have been origi- nally adopted for testing hardware devices, their application to software systems and 2 These are supposed to be embedded procedures implemented within the interpreter of the language at hand to achieve the desired behavior of allowing/disallowing action execution. protocols is constantly growing [15,16], and there have been a number of attempts to overcome some known limitations of this approach. The application of such techniques to the verification of agents is still limited by two fundamental problems. The first prob- lem arises from the marked differences between the languages used for the definition of agents and those needed by verifiers (usually ad-hoc, tool-specific languages). Indeed, to apply static verification, currently an agent has to be remodeled in another language: this task is usually performed manually, thus it requires an advanced expertise and gives no guarantee on the correctness and coherence of the new model. In many cases (e.g., [16,17]) the current research in this field is still focused on the problem of defining a suitable language that can be used to easily and/or automatically reformulate an agent in order to verify it through general model-checking algorithms. However, the literature reports fully-implemented promising static verification frameworks (e.g., [18,19,20]). [20] is an extension of the SCIFF proof procedure to prove system properties at design time. [18] describes a technique to model-check agents defined by means of a subset of the AgentSpeak language, which can be auto- matically translated into PROMELA and Java and then verified by the model-checkers SPIN [15] and Java PathFinder [21], respectively, against a set of constraints which, in turn, are translated into LTL from a source language which is a simplified version of the BDI logic. [19] describes an approach that exploits bounded symbolic model- checking, in particular the tool MCMAS, to check agents and MAS (Multi-Agent Sys- tems) against formulas expressed in the CTLK temporal logic. The second obstacle to the application of model-checking to agents and MAS is represented by the dynamic nature of agents, which are able to learn and self-modify over their life cycle, and by the extreme variability of the environment in which agents move. These aspects make it difficult modeling agents through finite-state languages, which are typical of many model-checkers (e.g., [15,22]), and dramatically increase the resources (time, space) required for their verification (state explosion). This can be seen as a motivation for our approach, which defers at least part of the verification activity (namely, the part more dependent upon agent evolution) to run-time. The issue of run-time verification has been considered in recent work. The SCIFF proof procedure, based on abduction, allows for checking the compliance of a narrative of events w.r.t. a specification, by matching events w.r.t. expectations, ie., by performing a form of run-time monitoring (see, e.g., [23] and the references therein). [24] proposes a reactive event calculus to check social commitments, i.e., commitments made from an agent to another agent to bring about a certain property. 5 Experimental Evaluation and Discussion We have implemented and we have been experimenting the proposed approach within the DALI multi-agent system (the DALI interpreter is freely available at http://www.di.univaq.it/stefcost/Sito-Web-DALI/WEB-DALI/). In this system, a fre- quency can be associated to each constraint by means of directives (a default frequency is otherwise provided). One can also establish since when and until when a constraint has to be checked. An important aspect to be experimentally verified is whether constraints actually empower the agent ability to cope with events without introducing too much over- head, that would lead an agent to that “brittleness” that it is so important to avoid. For performing dynamic checking without specific constructs, one has build, within an agent program, a suitable cyclic structure to perform the needed checks. Our solution therefore, by exploiting the underlying basic cycle of the interpreter, avoids adding this further layer. In this sense, the overhead is in any case alleviated. Nonetheless, a cru- cial point to consider is that one, when adding new constraints and/or increasing the frequency of checks, has to experimentally verify that the addition/increment is “sus- tainable” by the interpreter. The experimental evaluation is in fact mandatory under this respect. In the Appendix we present a basic experiment. Namely, we have implemented an agent that manages a FIFO queue, thus accepting requests of pushing and popping ele- ments on/from the queue. This example is in our opinion significant because it models in an abstract way the very general and widely used architecture where an agent pro- vides a service to a number of consumer. The instance size of our experiments (set by the user) coincides with the number of elements that are pushed/popped (at most 500). We establish the constraint, represented below in our formalism, that the queue must not contain any duplicated elements e1 and e2 . The possible actions are pushA (V, Q) that inserts a generic value V in the queue (as the e-th elements) and popA (Q) that extracts the oldest element from the queue (pushP (V, Q) is the past event recording this action having been performed). The constraint considers an unknown number of pushing actions happened in the past (and thus now recorded as past events) and can foresee an unknown number of popping actions. pushP + (V, Q) : N (in queue(e1 , V ), in queue(e2 , V ), e1 6= e2 ) :: popA + (Q) In particular, in the Appendix we present in Section A the pure prolog code, and in Section B the DALI code. Then, in Figure 1 and Figure ?? we show the execution time of the two solutions at the growth of the instance size. In Figure ?? we show the difference in percentage between the execution times. It is possible to identify an initial “unstable” stage and then a trend that further consolidates with the growth of the instance size. In fact, what we can conclude beyond any doubt is that, when the number of events that we consider is small, the two solutions are more or less equivalent, the prolog one a bit better as it involves no overhead (while the DALI implementation of events management necessarily involves some). But, as soon as the instance size grows, the DALI solution becomes better and better in a very significant way, despite the overhead of the implementation. 6 Concluding Remarks In this paper, we have presented an approach to detection and correction of run-time behavioral anomalies by using dynamic constraints. The runtime observation of actual anomalous behavior with dynamic possible correction of detected problems, as opposed to full prior classical program verification and validation on all inputs, can be a key to bringing down the well-known computational burden of the agent behavior assur- ance problem. Suitable experiments, performed in the DALI language, have shown that the proposed approach is computationally effective, and constitutes and improvement also in terms of efficiency. However, as it happens in all the environments where static and dynamic checks are equally applicable, none of the two forms of verification may substitute the other: indeed, the only possible solution is given by a synergy aimed at creating an integrated, reliable and lightweight verification environment. References 1. Costantini, S., Tocchio, A.: About declarative semantics of logic-based agent languages. In Baldoni, M., Torroni, P., eds.: Declarative Agent Languages and Technologies. LNAI 3904. Springer-Verlag (2006) 106–123 2. Costantini, S.: Defining and maintaining agent’s experience in logical agents. In: In- formal Proc. of the LPMAS (Logic Programming for Multi-Agent Systems) Workshop at ICLP 2011, and CORR Proceedings of LANMR 2011, Latin-American Conference on Non- Monotonic Reasoning. (2011) 3. Costantini, S., Tocchio, A., Toni, F., Tsintza, P.: A multi-layered general agent model. In: AI*IA 2007: Artificial Intelligence and Human-Oriented Computing, 10th Congress of the Italian Association for Artificial Intelligence. LNCS 4733, Springer-Verlag, Berlin (2007) 4. Costantini, S., Dell’Acqua, P., Pereira, L.M.: A multi-layer framework for evolving and learning agents. In M. T. Cox, A.R., ed.: Proceedings of Metareasoning: Thinking about thinking workshop at AAAI 2008, Chicago, USA. (2008) 5. Fisher, M., Bordini, R.H., Hirsch, B., Torroni, P.: Computational logics and agents: a road map of current technologies and future trends. Computational Intelligence Journal 23(1) (2007) 61–91 6. Clarke, E.M., Lerda, F.: Model checking: Software and beyond. Journal of Universal Com- puter Science 13(5) (2007) 639–649 7. Costantini, S., Tocchio, A.: A logic programming language for multi-agent systems. In: Logics in Artificial Intelligence, Proc. of the 8th Europ. Conf.,JELIA 2002. LNAI 2424, Springer-Verlag, Berlin (2002) 8. Costantini, S., Tocchio, A.: The DALI logic programming agent-oriented language. In: Logics in Artificial Intelligence, Proc. of the 9th European Conference, Jelia 2004. LNAI 3229, Springer-Verlag, Berlin (2004) 9. Pnueli, A.: The temporal logic of programs. In: Proc. of FOCS, 18th Annual Symposium on Foundations of Computer Science, IEEE (1977) 46–57 10. Emerson, E.A.: Temporal and modal logic. In van Leeuwen, J., ed.: Handbook of Theoretical Computer Science, vol. B. MIT Press (1990) 11. Costantini, S., Dell’Acqua, P., Pereira, L.M., Tsintza, P.: Runtime verification of agent prop- erties. In: Proc. of the Int. Conf. on Applications of Declarative Programming and Knowl- edge Management (INAP09). (2009) 12. Hopcroft, J.E., Motwani, R., Ullman, J.D.: Introduction to Automata Theory, Languages, and Computation (3rd Edition). Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA (2006) 13. Kowalski, R., Sergot, M.: A logic-based calculus of events 14. Cousot, P., Cousot, R.: Abstract interpretation: a unified lattice model for static analysis of programs by construction or approximation of fixpoints. In: Conference Record of the Fourth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Los Angeles, California, ACM Press, New York, NY (1977) 238–252 15. Holzmann, G.: The model checker spin. IEEE Transactions on Software Engineering (23) (199) 279–295 16. Bourahla, M., Benmohamed, M.: Model checking multi-agent systems. Informatica (Slove- nia) 29(2) (2005) 189–198 17. Walton, C.: Verifiable agent dialogues. J. Applied Logic 5(2) (2007) 197–213 18. Bordini, R., Fisher, M., Visser, W., Wooldridge, M.: Verifying multi-agent programs by model checking. Autonomous Agents and Multi-Agent Systems 12(2) (2006) 239–256 19. Jones, A., Lomuscio, A.: Distributed bdd-based bmc for the verification of multi-agent sys- tems. In: Proc. of the 9th Int. Conf. on Autonomous Agents and Multiagent Systems (AA- MAS 2010). (2010) 20. Montali, M., Alberti, M., Chesani, F., Gavanelli, M., Lamma, E., Mello, P., Torroni, P.: Ver- ification from declarative specifications using logic programming. In: 24th Int. Conf. on Logic Programming (ICLP’08). LNCS 5366, Springer Verlag (December 2008) 440–454 21. Visser, W., Havelund, K., Brat, G., Park, S., Lerda, F.: Model checking programs. Autom. Softw. Eng. 22. Dill, D., Drexler, A., Hu, A., Yang, C.: Protocol verification as a hardware design aid. In: Proc. of IEEE Int. Conf. on Computer Design: VLSI in Computers and Processors, IEEE Computer Society Press (1992) 522–525 23. Montali, M., Chesani, F., Mello, P., Torroni, P.: Modeling and verifying business processes and choreographies through the abductive proof procedure sciff and its extensions. Intelli- genza Artificiale, Intl. J. of the Italian Association AI*IA 5(1) (2011) 24. Torroni, P., Chesani, F., Mello, P., Montali, M.: Social commitments in time: Satisfied or compensated. In: DALT. Volume 5948 of Lecture Notes in Computer Science., Springer (2009) 228–243 A Pure Prolog Code Below we report the code of the version of the Queue agent implemented in DALI (by Alessio Paolucci, that we thank), but using only prolog constructs. The single DALI fea- ture that is exploited is related to the activation of the agent by means of a message. The test agent in fact gets active and performs a test session whenever it receives from the user a message with content run pure test(N um Items) where N um items speci- fies the number of elements to be pushed/popped on/from the queue. When the agent receives event run pure test it reacts, thus invoking the run pure testing goal with Times (=Size) as parameter, which starts the ’pushing’ phase. The pushing(T imes) goal pushes an item (through push item subgoal), when T imes > 0, otherwise it ends. push item as first step retrieves the data structure pqueue(Q). Then, it randomly generates an item, and checks if that item is already present in the queue. If so, then push item fails, and this (and only this) item pushing is skipped. If the new item is not in the queue, then it is added in the head. The old queue is removed from memory (retract(pqueue(Q))), and the new one is stored in the knowledge base (assert(pqueue(N Q)). popping is then invoked, to perform items removal from the queue. It makes use of pop item, a goal that retrieves and unifies the queue through clause(pqueue(Q), ), and the extracts the head of the queue Q. After the ’popping’ phase, the test ends. run pure testE(T imes):> run pure testing(T imes). run pure testing(T imes):- pretty start, now(StartT ime), T 1 is T imes + 1, nl, write(0 P U SHIN G...0 ), nl, pushing(T 1), nl, write(0 P OP P IN G...0 ), nl, popping(T 1), now(EndT ime), T estT iming is EndT ime − StartT ime, nl, write(0 T ime :0 ), write(T estT iming), nl, pretty end. pushing(0). pushing(T imes):- push item, T 1 is T imes − 1, pushing(T 1). push item:- clause(pqueue(Q), ), random(1, 300, Item), not(exists in queue(Item, Q)), nl, write(0 P ushing :0 ), write(Item), append(Q, [Item], N Q), retract(pqueue(Q)), assert(pqueue(N Q)), nl, write(0 Queue :0 ), write(N Q), nl. push item:- assert(pqueue([])). exists in queue(X, [X| ]):- true. exists in queue(X, [ |T ail]):- exists in queue(X, T ail). popping(0). popping(T imes):- pop item, T 1 is T imes − 1, popping(T 1). pop item:- clause(pqueue(Q), ), nl, write(0 P opping :0 ), Q = [H|T ], write(H), retract(pqueue(Q)), assert(pqueue(T )), nl, write(0 Queue :0 ), write(T ), nl. pop item:- assert(pqueue([])). pretty start:- nl, write(0 Start testing...0 ), nl. pretty end:- nl, write(0 T est f inished...0 ), nl. B DALI Code The DALI implementation makes use of DALI advanced features, and in particular exploits actions, and the ability to remember what happened in the past (past actions). Basically, the power of the DALI infrastructure made us able to write the program in a very comfortable manner: each pushing is an action, so every time the action is performed, the DALI engine takes care, for the future, of this action as a past event. We exploited this feature so as to perform pushing actions in the present. Then, we use parameters of the action to take care of the items that have been pushed and of the order, through an index. When a pop needs to be performed, we use the power of DALI past events to retrieve actions previously performed, and thus retrieve the correct item from the head of the queue, in a very elegant manner. The DALI implementation allows us to concentrate on the problem, without focusing that much on the data structure, in a very strict declarative fashion. Below we report the code of the proper version of the Queue agent implemented in DALI. The test agent gets active and performs a test session whenever it receives from the user a message with content run dali test(N um Items) where N um items specifies the number of elements to be pushed and popped on the queue. run dali testE(T imes):> dali test startA, run dali testing(T imes). run dali testing(T imes):< dali test startP. run dali testing(T imes):- dali start pushingA, dali pushing(T imes), dali end pushingA, dali start popA, dali popping(T imes), dali end popA, dali end testingA. dali pushing(0):- true. dali pushing(T imes):- dali remember(T imes), T 1 is T imes − 1, dali pushing(T 1). dali remember(T imes):- random(1, 300, Item), not(clause(do action(dali push queue(Item, ), ), )), get push index(P I), dali push queueA(Item, P I). get push index(I1):- clause(push index(Index), ), I1 is Index + 1, retract(push index(Index)), assert(push index(I1)). get push index(Index):- assert(push index(1)), Index = 1. get pop index(I1):- clause(pop index(Index), ), I1 is Index + 1, retract(pop index(Index)) assert(pop index(I1)). get pop index(Index):- assert(pop index(1)), Index = 1. dali popping(0):- true. dali popping(T imes):- dali f orget(T imes), V 1 is T imes, − 1, dali popping(V 1). dali f orget(Dummy):- get pop index(Index), clause(do action(dali push queue(Item, Index), ), ), dali pop queueA(Item). C Comparison In Figure 1 below we show the execution time of the two solutions reported in previous sections at the growth of the instance size. It can be observed that as the instance size grows, the DALI solution becomes significantly better. Fig. 1. x axis: instance size; y axis: execution time, blue bars pure prolog green bars DALI