Action Languages and Elaboration Tolerance, Part 1 Date: Fri, 14 Sep 2001 From: Michael Gelfond To: TAG This is a slightly edited version of a rather long and slow e-mail conversation about action languages between Vladimir and myself. The conversation started with Vladimir sending his first message to several people on 24th of July and my first response on Aug 2nd. I hope it is going to continue. We thought that it may be of some interest to other members of TAG and decided to make it public. And of course as usual we are interested in your comments. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Vladimir: Dear Friends, For a long time I've had the feeling that something is fundamentally wrong with action language C, or maybe with the idea of an action language in general. (Do you have this feeling too?) I just couldn't put my finger on it. I think maybe now I know what's wrong, although I have no idea at this point how to correct this problem. Imagine that we want to treat the expressions normally F (1) and takeItBack (2) as abbreviations for some C propositions so that they would behave as follows: - proposition (1) by itself has the same meaning as always F; - propositions (1) and (2) together have the same meaning as the empty set of propositions. Theorem: This is impossible. Proof: When we extend the set of propositions in C, the corresponding set of states can only become smaller. So here is the source of many of our difficulties: the set of states in the transition diagram denoted by a set of propositions depends on that set monotonically. In a sufficiently expressive action language, this should not be the case. Regards, Vladimir %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Michael: To better understand the point I'd like to switch from C to B, i.e. the language which allows statements 1. a causes F if P 2 F if G You want to expand B by default statements like 3. Normally F if G Is that right? If so then I think this can be done simply by expanding B by statements of the form (3) which should be given names and by statements 4. exception(Q,d) which says that Q is an exception to default d. So let d be of the type (3). Then I understand its meaning as 'any state containing G and not containing exceptions to d contain F. So a state is a (consistent) collection of fluent literals closed under rules (3). The rest is the same as in B. So if your action description does not contain 4 then (G,Q,~F) is not a state. If (4) is added then it does become a state. I am not sure if this is what you want but it should be at least related. (BTW (1) also can be made a default) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR: > As far as I understand you want > to expand B by default statements like > > 3. Normally F if G > > Is that right? > > If so then I think this can be done simply by expanding > B by statements of the form (3) which should be given names > and by statements > > 4. exception(Q,d) > > which says that Q is an exception to default d. Right. We are working now on an extension of C+ that will allow us to do things like this. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL: I am still a little unsure about Vladimir's interpretation of defaults in C. If I understand correctly in the absence of known exceptions you want a statement normally F (1) to be interpreted as always F; Am I right? If so I am not sure I view it this way. When I say 'Normally F' instead of always F I imply that there are exceptions to (1). (and promise to list those exceptions I know about). That is why I do not mind to view (1) as F if neg(ab) and consider states with and without ab. This leads to 'monotonic' collection of states. Are there some examples you'd like to formalize in which you prefer nonmonotonic states? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Vladimir: Let's try this. The domain is described by two propositions: normally Loaded, Shoot causes -Alive if Loaded. No information about the initial state is given. Action Shoot is executed at time 0. I want to be able to conclude that Alive is false at time 1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Michael: OK, I see some advantage of not having a state in which gun is unloaded here but it also causes problems. What do you expect to happen if at moment 1 alive is observed? It seems natural to conclude that in the initial state the gun was not loaded after all. But it is impossible unless of course existence of states depends on observations. Do you want this? Another extra complication in using 'normally loaded' (*) is that now you need to decide what is the relationship between this default and inertia. In this example inertia should of course win. (This is the reason I only use (*) type of defaults for non-inertial fluents). Do you think the advantage is worth the complications? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR: > What do you expect to happen if at moment 1 alive > is observed? It seems natural to conclude that > in the initial state the gun was not loaded after all. > But it is impossible unless of course existence of states > depends on observations. Do you want this? My "normally" represents a very strong default. To override it, we have to explicitly mention the abnormality predicate. > Do you think the advantage is worth the complications? The need to have such a construct in an action language occurred to me when I worked on McCarthy's elaborations of the Missionaries and Cannibals problem (MCP). In his Elaboration 17, "there are four cannibals and four missionaries, but if the strongest of the missionaries rows fast enough, the cannibals won't have gotten so hungry that they will eat the missionaries". I wanted to formalize this version by adding something to the formalization of the basic MCP. There is no way to do this if the basic formalization asserts that missionaries are never outnumbered by cannibals at any location. We have to be more careful in the basic formalization, and to postulate only that this is *normally* the case. When we reach Elaboration 17, we add the assumption that the states in which the cannibals are not hungry are abnormal. This has a nonmonotonic effect on the set of states: new states, in which missionaries are outnumbered, come into being. Another reason why we need this construct is related to the qualification problem: accommodating new preconditions by adding new propositions to the action description. We begin with the simple theory in which shooting always kills the turkey. Later we decide to add that this this actually happens only when the gun is loaded. Then we want to add also that the gun should be aimed properly, etc. The way to approach this is not to say Shoot causes -Alive, but rather normally Shoot causes -Alive, and then describe exceptions by additional propositions. (We are talking here about the qualification problem as it applies to "fluent preconditions" in the sense of Reiter. The qualification problem for "action preconditions" is handled by the "nonexecutable" construct that is already available in action languages.) What do you think about these examples? How would you represent them? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL. Well, I guess the best answer is to do it. I found some old version of missionaries and cannibals used by me in class to illustrate the use of action languages and SMODELS. I wanted it to be reasonably efficient and hence it is not very elaboration tolerant. It is, I think, very close to a solution by Mary which can be found in the TAG archives. I thought a little about adding 'hungry' to the problem but it didn't seem right. The problem was that I didn't know if 'hungry' was supposed to be inertial or not, what causes 'hungry' to become true, etc. So instead of 'hungry' I introduced an action 'convert' and a fluent 'converted'. Converted cannibals are harmless. Hope it is o.k. So below is the old program with changes marked by the words NEW or CHANGED. ------------------------------------------------------------------------------- Missionaries and Cannibals problem in smodels Three missionaries and three cannibals come to a river and find a boat that holds two. Normally (!!), if cannibals outnumber the missionaries on either bank, the missionaries will be eaten. If cannibals are converted to a more vegetarian religion this danger disappears (!!). How can they cross? ------------------------------------------------------------------------------- const lasttime=11. time(0..lasttime). next(T,T1):- time(T), time(T1), T1 = T + 1. agent(cannibal). agent(missionary). vehicle(boat). const max = 3. num(0..max). %---------------------------------------------------------------------------- FLUENTS %---------------------------------------------------------------------------- %fluent(i,located(X,N)) iff N number of type X are located on the first side of % the river fluent(i,located(A,N)) :- agent(A), num(N). fluent(i,located(O,N)) :- vehicle(O), num(N). fluent(i,converted). ( NEW!! ) All the above fluents are inertial. I also would like to introduce another (non-inertial) fluent, 'harmless'. I'll use it later in my constraint (4) which will prohibit too many non-harmless cannibals on one bank. This fluent plays the role usually played by the abnormality predicate. fluent(n,harmless). ( NEW!! ) fluent(F) :- fluent(i,F). fluent(F) :- fluent(n,F). %-------------------------------------------------------------------- ACTIONS %-------------------------------------------------------------------- %action(cross(A,N)) iff N number of agent(s) A cross to the opposite side of % the river action(cross(A,N)) :- agent(A), num(N), gt(N,0). %action(return(A,N)) iff N number of agent(s) A return to the original side of % the river action(return(A,N)) :- agent(A), num(N), gt(N,0). % action(convert). ( NEW!! ) %-------------------------------------------------------------------- FLUENT DEPENDENCES %-------------------------------------------------------------------- 1. ~located(A,N1) if located(A,N2)) nh(located(A,N1),T) :- h(located(A,N2),T), time(T), agent(A), num(N2), num(N1), neq(N2,N1). nh(located(V,N1),T) :- h(located(V,N2),T), time(T), vehicle(V), num(N2), num(N1), neq(N2,N1). 2. Next rule is the default "Normally, cannibals are not harmless". Normally harmless: nh(harmless,T) :- time(T), ( NEW!! ) not h(harmless,T). This is a typical representation I use for non-inertial fluents with default values. 3. harmless if converted. (This gives an exception to the above default.) h(harmless,T) :- time(T), ( NEW!! ) h(converted,T). 4. cannibals cannot outnumber missionaries on either side 4a :- time(T), num(N), num(N1), gt(N,N1), gt(N1,0), h(located(cannibal,N),T), h(located(missionary,N1),T), nh(harmless,T). ( NEW CONDITION!! ) 4b :- time(T), num(N), num(N1), lt(N1,max), lt(N,N1), h(located(cannibal,N),T), h(located(missionary,N1),T), nh(harmless,T). ( NEW CONDITION!! ) Here I am adding a new precondition to the old law: false if located(cannibal,N),located(missionary,N1), N > N1. %--------------------------------------------------------------------- DYNAMIC CAUSAL LAWS %--------------------------------------------------------------------- causes(cross(A,N), located(A,N1-N), located(A,N1)) h(located(A,N1-N),T2) :- next(T1,T2), agent(A), num(N1), num(N), h(located(A,N1),T1), o(cross(A,N),T1). h(located(boat,0),T2) :- next(T1,T2), agent(A), num(N), h(located(boat,1),T1), o(cross(A,N),T1). causes(return(A,N), located(A,N1+N), located(A,N1)) h(located(A,N1+N),T2) :- next(T1,T2), agent(A), num(N1), num(N), h(located(A,N1),T1), o(return(A,N),T1). h(located(boat,1),T2) :- next(T1,T2), agent(A), num(N), h(located(boat,0),T1), o(return(A,N),T1). h(converted,T2) :- next(T1,T2), ( NEW!! ) o(convert,T1). %----------------------------------------------------------------------- EXECUTABILITY CONSTRAINTS %---------------------------------------------------------------------- %it is impossible for more agents to cross than are on the first side :- time(T), agent(A), num(N), num(N1), gt(N,N1), o(cross(A,N),T), h(located(A,N1),T). %it is impossible for more agents to return than are on the other side :- time(T), agent(A), num(N), num(N1), gt(N+N1,max), o(return(A,N),T), h(located(A,N1),T). % agents cannot move if they are not on the same side with the boat :- time(T), num(N), agent(A), h(located(boat,0),T), o(cross(A,N),T). :- time(T), num(N), agent(A), h(located(boat,1),T), o(return(A,N),T). % the boat holds two. :- time(T), num(N), num(N1), gt(N+N1,2), o(cross(cannibal,N),T), o(cross(missionary,N1),T). :- time(T), num(N), num(N1), gt(N+N1,2), o(return(cannibal,N),T), o(return(missionary,N1),T). :- time(T), num(N), gt(N,2), o(cross(cannibal,N),T). :- time(T), num(N), gt(N,2), o(return(cannibal,N),T). :- time(T), num(N), gt(N,2), o(cross(missionary,N),T). :- time(T), num(N), gt(N,2), o(return(missionary,N),T). %----------------------------------------------------------------------------- % INERTIA %----------------------------------------------------------------------------- h(F,T1) :- next(T,T1), fluent(i,F), h(F,T), not nh(F,T1). nh(F,T1) :- next(T,T1), fluent(i,F), nh(F,T), not h(F,T1). % CONSISTENCY %----------------------------------------------------------------------------- :- h(F,T), nh(F,T), time(T), fluent(F). %-------------------------------------------------------------------- % GOAL %-------------------------------------------------------------------- goal(T):- time(T), h(located(missionary,0),T), h(located(cannibal,0),T). :- not goal(lasttime). %---------------------------------------------------------------------- CONTROL MODULE %---------------------------------------------------------------------- I changed this to look for plans without conversion but it is of course irrelevant. ok_action(A) :- action(A),neq(A,convert). {o(A,T) : ok_action(A)} :- time(T), not goal(T). If you want to allow conversion use action instead of ok_action %---------------------------------------------------------------------- INITIAL CONDITIONS %---------------------------------------------------------------------- h(located(cannibal,3),0). h(located(missionary,3),0). h(located(boat,1),0). nh(F,0) :- fluent(F), not h(F,0). ------------------------------DISPLAY------------------------ hide. show o(A,T). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Comments: I use the default here for a non-inertial fluent, as I think we should. The collection of states is monotonic: it allows the combination of harmless and ~converted. I can start in this (abnormal) situation and reason (i.e. look for plans) from it. It can also be used for the explanations. However, unless otherwise stated, I start with a 'normal' situation. Is this more or less example you wanted? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR. Not quite, because your formalization is in the language of logic programming, not in an action language. What I'm concerned about is the expressive power of the existing action languages, not the expressive power of logic programming. The original form of MCP can be viewed as a question about paths in a transition diagram described in Action Language B. I'm wondering whether we can treat the enhanced MCP in a similar way. There is no concept of a normal situation in the semantics of B. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL I guess our notions of action languages deviated substantially over the years. Of course my solution is a logic program - I wanted to run it (without writing a front-end). But part of this program is an action description in a simple extension of B. I have been using extensions of this sort for some time. So I think it may be useful to make this point clearer. Let me try to be more specific and attempt to describe the language I used in this solution, say B+: 1. SIGNATURE As in B, the signature of B+ consists of fluents and actions. Unlike B, B+ has two types of fluents: inertial as well as NON-inertial. These fluents (together with their types) and actions are defined by the corresponding rules of my program. 2. ACTION DESCRIPTIONS of B+ Transition diagrams (over this signature) are defined by static and dynamic causal laws as in B, impossibility conditions, and defaults, i.e. statement of the form 'Normally a NON-inertial fluent F has the value true (false)' This can be expressed as an atom in the style of original action languages, e.g. NORMALLY F is TRUE (FALSE). The (absent) front end will translate this into the rule h(F,T) :- not ~h(F,T) as I did in the program. (Actually my rule is of the form ~h(F,T) :- not h(F,T) since I want to say that harmless is normally false). We can of course also allow preconditions for defaults and even priorities between them but let me keep it simple. 3. TRANSLATION to LOGIC PROGRAMMING The sections of my program called FLUENT DEPENDENCES, DYNAMIC CAUSAL LAWS, and EXECUTABILITY CONDITIONS can be viewed as (an automatic) translation of an action description of B+ into logic programming rules. Of course semantically equivalent translation can be done by combining this action description with general rules like h(F,T+1) :- causes(A,F,P), o(A,T), h(P,T). h(F,T) :- normally(F,true), not ~h(F,T). etc So again the difference with B is: a. executability conditions b. addition of non-inertial fluents c. addition of statements expressing default values for non-inertial fluents. 4. SEMANTICS. Nowadays my favorite way to give semantics to this (and similar) languages is this: Let T(A) be a logic program consisting of the translation of action description A given above plus the inertia axiom as in my program. (For simplicity I also assume that time ranges over 0 and 1.) As usual a state is a consistent and complete collection of fluent literals which is closed under the static rules. Now consider a state s0 and a collection 'a' of elementary actions 'a1,..,ak' such that executability conditions of each 'ai' are satisfied by s0. (a is a collection of simultaneously executed actions. I do not remember if this was allowed in B but it could of) Now consider a program P = T(A) + {h(f,0) : f in s0} + {~h(f,0) : ~f in s0} + {o(ai,0) : ai in a} Def: s1 is a possible successor state of s0 (w.r.t. a) if there is an answer set S of P such that f in s1 iff h(f,1) in S ~f in s1 iff ~h(f,1) in S This defines the transition diagram of A. VLADIMIR SAYS: What I'm concerned about is the expressive power of the existing action languages, not the expressive power of logic programming. Well, I do not know if you acknowledge the existence of B+. I claim though that this is an action language which can be viewed as a non-essential extension of B. It is a very simple extension. I sometimes use more powerful ones but the definition of the transition diagram is still based on the translation into A-Prolog (and hence the use of the notion of answer set). VLADIMIR SAYS: The original form of MCP can be viewed as a question about paths in a transition diagram described in Action Language B. I'm wondering whether we can treat the enhanced MCP in a similar way. There is no concept of a normal situation in the semantics of B. I think the example shows that we can do it in B+. And B+ does not have a notion of normal situation even though it certainly can be introduced. Maybe what I should do to make this discussion more useful is to describe a 'general' extension of B. I do not think that there are any new insights though so I am not sure if this will help. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR: M. > I guess our notions of action languages deviated substantially > over the years. V. Let's see. In your message, you talk about - extending B to define B+, - defining the semantics of B+ by translation to logic programming, - using a logic program to describe initial conditions. I like all these ideas, we have no disagreement here. Did I miss anything? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL. No, I just thought that you contrasted my formalization with that given in an action language. I am glad we seem to agree. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR (continues) But even after we did all this, it seems to me, the example of elaboration tolerance that we are discussing (moving from the original MCP to MCP with harmless cannibals) cannot be handled in a completely satisfactory way. What I would consider a satisfactory solution should consist of two steps: (a) describing a set D of proposition in language B+ that formalizes the original MCP, and then (b) describing a superset D' of D that formalizes the enhanced form of MCP. Since the original form of MCP doesn't say anything about harmless cannibals, "harmless" should not be even part of the language of D. It should be added to the language when we move from D to D', and it should only occur in the new propositions, D'\D. Can we do that? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL: I thought I did exactly that (well almost exactly, since I was trying to cut on typing). I started with a standard solution and modified it by: 1. Adding the following info: fluent(i,converted). fluent(n,harmless). action(convert). h(converted,T2) :- next(T1,T2), o(convert,T1). h(harmless,T) :- time(T), h(converted,T). nh(harmless,T) :- time(T), not h(harmless,T). 2. Modifying the original rules below (a) :- h(located(cannibal,N),T), h(located(missionary,N1),T), gt(N,N1), gt(N1,0). (b) :- h(located(cannibal,N),T), h(located(missionary,N1),T), lt(N1,max), lt(N,N1). by adding ~h(harmless,T) to their bodies.. I argued that these rules can be viewed as causal laws of an action description language and you seem to agree. But you apparently do not want to replace statements of your domain description by new ones (only addition is o.k.) and as a result do not like modification (2), right? So let me show how we can hide this modification from the user. But first some 'general' comment: When we introduced A we knew that writing dynamic causal laws in the form 'a causes f if p1,...pn' is not very elaboration tolerant - adding new preconditions requires replacement of the rule. The same is of course true about static rules, f if p1,...,pn. This didn't bother me because of several reasons. One was that it is always possible to write this law in a different form. A static law (fluent dependency) can be written as: static_law(l1). (l1 is of course the law's name) head(l1,f). precon(l1,p1). ... precon(l1,pn). which allows addition of new preconditions without any rewriting. Similarly, for other laws. So the lack of elaboration tolerance of this sort was not a real problem. I believe that this view was actually shared by both of us. Now back to the example: As I mentioned before, the constraint 4a can be viewed as a special case of static causal laws: false if located(cannibal,N),located(missionary,N1), N > N1. Similarly for 4b. In B+ I can use the more elaboration tolerant syntax discussed above (which of course requires more typing) and write (4a) as: static_law(l1(N,N1)). head(l1(N,N1),false). precon(l1(N,N1), located(cannibal,N)). precon(l1(N,N1), located(missionary,N1)). precon(l1(N,N1), N > N1). (I am of course assuming here that N and N1 are properly typed.) Obviously, this law can be easily translated into the corresponding logic programming constraint I used in my program. (Similarly for (4b)). If we assume that my original formalization D was given in this form then, instead of modifying rules from (4) all you need to do is to ADD: precon(l1(N,N1),~harmless). precon(l2(N,N1),~harmless). >From the user's standpoint no replacement is necessary. The automatic translation will however replace the old logic programming rules by the new ones, e.g. (4a) will be translated into :- nh(harmless,T), h(located(cannibal,N),T), h(located(missionary,N1),T), gt(N,N1), gt(N1,0). Neither 'harmless' nor 'convert' and 'converted' are part of the language of D. They are added to the language when we move from D to D', and only occur in the new propositions, D'\D. Some time ago I'd probably write the causal laws in this general, elaboration tolerant, form and design our translation as a collection of domain independent axioms, P, such that the result of the translation of action description D into A-Prolog will be P + D. Then not even automatic translation will need to replace statements in our knowledge base - only addition will suffice. (e.g. something similar is done in our paper on diagnosis) I still believe that it is a good idea but: 1. Both translations are equally good for the purpose of defining the semantics of the language. 2. In its current state SMODELS work rather slowly for such a 'modular' translation. (This maybe because I use function symbols freely to make axioms of P to look natural). DLV does not work at all (This will of course change when they implement function symbols.) 3. I suspect that for comparatively large applications we will need to develop a front-end containing a fixed form for the laws. E.g. the interface will come up with a 'script', say, for dynamic law with fields like action effect precon a f p1 p2 If this is done the precise syntax of B+ will become fairly irrelevant. This is not difficult to do. We just need a student interested in a programming project. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% VLADIMIR. This discussion started when I suggested that, in a good action language, the set of states should not be a monotonically decreasing function of the set of propositions, and that in the existing action languages this dependence, unfortunately, is monotonic. In your last message, you propose to modify the syntax of B+ and replace f if p1,...,pn with static_law(l1), head(l1,f), precon(l1,p1), ... precon(l1,pn). I agree that this modification solves the problem of elaboration tolerance that we talked about. But this is not a refutation of my claim, it seems to me, because this new format does make the set of states a nonmonotonic function of the set of propositions. If we start with static_law(l), head(l,f) and then add precon(l,p) then the set of states will become larger. In the extension of action language C that we are working on now, we don't introduce labels and meta-predicates like "head"; instead, we divide all fluents into two groups: simple and statically determined. A statically determined fluent is not allowed in the head of dynamic laws; on the other hand, the static laws containing such a fluent in the head are viewed, more or less, as a logic-programming style definition of that predicate. If we expect that a static law caused f if p1,...,pn may need to be enhanced by new precondition some time in the future, we'll write it as caused f if p1,...,pn,-ab where ab is a statically determined fluent, and postulate also caused -ab if -ab (which can be abbreviated as "default -ab"). To add a precondition q, we'll add static law caused ab if -q. This method is different from your head/precond method, but, like yours, it achieves the goal of greater elaboration tolerance by destroying the monotonic dependence of the set of states on the set of propositions. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MICHAEL. o.k., I think I understand much better what it is you want and some, but not all, sources of my confusion. (And, for other people who may be reading except Vladimir - the intend of course is not to refute claims but to understand them). As usual I have a very long response to your short comment. Let me break it in parts. 1. Your solution seems very similar to my original one. I have false if p1,...,pn, ~harmless harmless if converted normally ~harmless 'harmless' is your ab, the added precondition is '~converted', and the defaults are the same. I require 'harmless' to be non-inertial, you require it to be 'statically determined'. I do not see an analogue to your requirement of not allowing statically determined fluents in the heads of dynamic laws, but it does not seem that important. But then you say: Since the original form of MCP doesn't say anything about harmless cannibals, "harmless" should not be even part of the language of D. It should be added to the language when we move from D to D', and it should only occur in the new propositions, D'\D. But MCP does not say anything about 'ab' either and you are using it anyway. I do exactly the same but use the different name. I guess this confusion is caused by my failure to stress that 'harmless' is just a name for 'ab'. I could have said: false if p1,...,pn, ~converted without introducing harmless at all. But this would require modification every time a new exception is found. Hence I used '~harmless' from the beginning to allow the possibility of adding exceptions other than 'converted'. So I do not see why this solution (at least to this problem) is not satisfactory. But apparently there is still a real difference between our formalizations because non-monotonicity of states appears in mine only if the signature of the language is extended by new symbols (say with 'converted' as in our example). But such non-monotonicity is trivial. Am I wrong somewhere? 2. Because of the confusion described above I misunderstood your comment and decided that you do not want to allow 'ab' ('harmless') in your initial language. In this case the use of different syntax helps. What I never noticed is that in this case the collection of states becomes non-monotonic even if the language is not changed. This is really interesting even though I am not sure what are the ramifications of it. 3. Let me also mention another of my confusions which may help to understand some of my comments. In the beginning I (a) assumed 'ab' to be part of the initial language. (b) considered action description with default 'Normally ~ab' and no causal laws with 'ab' in the head. (c) Assumed that in this case you do not want to have any states with 'ab' in them. So some of my initial arguments expressed (mild) doubts about this proposal.