22662 >> Rustan Leino: Good afternoon, everyone, and welcome to yet another lecture of Dr. Jean-Raymond Abrial, who is going to continue taking us through Event-B. So far we've seen systems that make use of the events as small concurrently executing events. And today and next time we're going to see how these are put together into sequential programs. And then as a final advertisement, after this lecture and the next, we'll do one more lecture, which we're going to report on what we have done with the hypervisor that we have been working on in the Event-B system. So here is sequential programs. >> Jean-Raymond Abrial: Thank you, Rustan. Good afternoon. So as Rustan said, you have seen Event-B used in the development of system, the car and the bridge. Half of the price, mechanic price. We skipped the second half because there was one lecture missing. So you might say how can we develop sequential program, because we have seen so far heavily using events. And events as you know is a very simple device made of guards. So it's a predicate that are initially conditioned for the event to be triggered. And some actions. And that's all. Events might have parameters and some actions might be nondeterministic but that's all. We have all these little device, all these little events. If we want to think in terms of operationally, we have these events a little process. And they all together run, if they are enabled. And the sequential program is completely different. Sequential program is made of a precondition, the specification of a specification of a sequential program is made of a precondition and a post condition. And here we have a guard and some post conditions. So this is completely different. Before engaging into seeing this, I would like to hammer a bit the very important distinction between guard and preconditions. When you have a program defined by a precondition and post condition, it means that when you knock at the door of this program to execute it, you have to be sure on your side the coding that the precondition holds. Otherwise, it crashes. Okay? And when you refine a program, define with a precondition, you can weaken the precondition. What does that mean? It means that -- let me take an operational definition. You want to buy a motor and the motor has a precondition it should work between minus 10 degrees centigrade and 30 degrees centigrade so this is a precondition. So you go to the vendor, the motor vendor, and you ask for exactly this motor. And the vendor knows that he has not got exactly that. But he has a more expensive one that goes from one minus 15 to plus 50 or something like this. Okay. So he's going to cheat you. He's going to sell you the one that has a weakened precondition, because it goes now from minus 15 to plus 50. And he will not tell you. But on your side you buy this, and that's okay, because you still believe that it is going from minus 10 to plus 30 or whatever. And it can do more. Of course, he has cheated you because you pay more. Okay. So this is a thing of the weakening of the precondition. Now, about the guard. When we have an event of say many, many times, that when we refine, we strengthen the guard. So we go exactly into the reverse direction. Why is that? Because we are not knocking at the door of the event. An event is not something you call. An event is something you observe. You observe that event's occurring. And the guard is -- again, it's enabling condition. So when you refine an event, why do you refine an event? You refine an event because you have more functionalities and you enlarge maybe the state, but maybe the condition enabling that event is now stronger. Okay. So you are strengthening the guard. And this could be a bit strange, because if you have a population of events, and you strengthen the guard, you can strengthen them so much that you have deadlock. So this is something that never exists in the case of the precondition. Okay. But it might happen in the case of events. That's the reason why we have to do something the other way around. We have to prove that the refinement of a population of events doesn't deadlock more than the population of the abstract event you have. So you prove that the disjunction of the guard of the abstract events implies the disjunction of the guard of the concrete event. So it goes in the other direction. Another thing that is a bit misleading is the following. When you prove something about a pre-post condition, what you do on your side when you prove this program which has a pre-post condition, you assume the precondition and you prove the post condition. And when you do the same thing for an event, you assume the guard and you prove the post condition. So in both cases you assume either the guard or the precondition. But I just said two minutes ago that they are different. So why is that? It's very simple. It's very simple. It's because if we take an operational view, precondition is when a precondition is false, when you call something and on your side the precondition is false, you crash. Okay. When you observe an event whose guard is false, this guard is not enabled. That's it. So you wait. You wait for a better time where the guard will be true. And why -- so it's normal because the guard is necessary condition for the event to be triggered. So it's normal to assume the guard in order to prove the post condition. Now, why do you assume the precondition in order to prove the post condition in the case of a pre-post definition? It's because it's not -- because it's not your duty to prove the guard. The duty is from the caller. So you assume the caller has done it. And in fact what you have to prove is P and Q. P the precondition and Q the post condition. But if it is exactly the same as P and P implies Q. So that's what you do, that's why you assume the precondition because the precondition is proved by somebody else. So that's it. So think about it. It's not completely obvious. And people are a bit confused by this. But I think it's very, very, very important to make the distinction again and again between a guard and a precondition. Okay? You follow me? You are with me? Fine. Let me now enter the subject. So -- >>: So in some sense we refine, actually means to prove the disjunction of the guards implies that then you can think of the disjunction of the guards being the precondition of the type system and that indeed you can weaken? >> Jean-Raymond Abrial: Yeah, you can have this. Yeah. You have to prove that the concrete system does not deadlock more than the abstract one. This would be very embarrassing if you do something very nice you add functionality, but unfortunately the system deadlocks. And so you have to prove that in spite of the fact that your strengthening the guard, the system -- the system or the whole doesn't deadlock. Okay? So let me go now into sequential program. I'm not going to change the idea of sequential program. We will still have pre and post conditions. How can we encode this into a bunch of events? So this is the story that I want to tell you today. So we are going to present a number of examples today and next time. Array program, [inaudible] program, middle array program, you all know this little program. Rustan has done many of them with Daphne. So a typical program is made of a number of multiple assignments, I assume there are multiple assignments. Scheduled by means of some conditional operator if iterative operators while sequential operators semicolon. So when we have two programs we have two things that are completely different. The assignment of value to some variables. And these things conditional iterative and sequential. Here is a program. Never mind what it does. We have a why. And we have an if and if else and we have simultaneous assignment statement and we have a semicolon. We have all the features here. Now, how can we with advance go to this? Well, not so difficult. Suppose we separate -- we separate completely this, this and this from this environment of if and else and while. So here is our paging language. So we have not put curly brackets. So as I said before, we are just going to separate completely the individual assignments from their scheduling, from the if and else, the while, and semicolon. And we favor the distribution of computation over its centralization. When you have a sequential program, this is centralized. Everything is there. You have the if, you do something else. You have the while, you loop. And when the loop is finished, hopefully, we go outside and we do something else. Okay. So this is centralized. So here we -- and it is a flavor of events. We separate completely, and we suppose again that we have our little machines working nicely, independently. So an event, I refresh you, a firing addition or trigger condition, the guard, the interaction the multiple assignments and these events are scheduled implicitly. Implicitly in the sky there is a guard who sees all these events and says you, you, you in a fair way of course he gives control because the guard was a necessary condition, maybe not sufficient, it's sufficient if there is a guard or a scheduler guard that gives control to these things. Okay? Now, let's extract from a program an event. Here so I'm going to take in turn all the assignments. Here J, J plus 1. And what are the conditions for J, J plus 1 to be enabled? Well, we go down here and we see certainly when J is different from M, because we have to enter the loop. And we have to enter the first branch of the if and else and so this is it. So we have extracted these little events. And we can do the same for the other assignments. So for the second one, we are still inside the loop. We are now in the second branch, therefore, the first predicate is false. Or, sorry, the first predicate we take the negation of it. And then we have the third one. So this is the second one. And the third one forget about swap. It doesn't matter. And the third one is just this. The guard, both predicates are false, and we are now here. And eventually when J is equal to M, then P columns equal K. So what we have done here, just by looking at this program, we have extracted from this program the various events. And now let's go on to the sky as guard. And let's give control to these things. This is very nice, because only one of them can be tried at a time. We have no determinicity, because all these conditions are, only one of them is true and all of them could be true. So you see we have now completely separated the events from the program. What we will do is exactly the reverse. We will start from the problem, Okay. defining the events, like this, and then at the end, when we are happy with them, and I will explain why, we will put them together to form the sequential program. Okay? So the idea is then we have just decomposed and we will do exactly the reverse operation. So we shall first construct the events list and then we will compose our program from these events. And of course at the beginning when we will have the population of events, they might be nondeterministic. So maybe several events can be filed at a time. But we don't care we have the guard scheduler on top. When we refine strengthening the guard, we might be in a final situation deadlock freeness, careful, we will be in a final situation where only one events can be fired at a time. It is time now to put things together to form the program. Okay. So you see we have set up the scene in this way. So the idea will be to have a specification phase where we are going to translate the pre-post condition into some initial events. Then we head into the design phase where you remember when we refine a population of events we can add new events and the refine skip. And when we add events, also we have to prove that the new events do not take control forever. Going out of loop. Finishing a loop. That will be done in this occasion. at the end when we are happy, we psst, we concentrate then to build the program. And So it's very, very much the other way around, as what people do like starting with the final program and trying to with very nice things like Daphne or Boogie to prove or verify the program. Here it's the other way around. It's top-down. Okay. Pre-post condition. We have to encode this, the first level, with this is the famous [inaudible] triple and we have to encode this into a population of events. Okay. So usually what we have in the precondition is essentially a specification of the parameters of the program. Okay. And I am supposing that the parameters of the program, the arguments are given by value and they are not modified within the program. No side effect. So this inside the program here, the arguments, the parameters are constant. Ah, we have ways to define constant. We can use context. Okay. So what we shall do is we shall use context here. And then you will see what we do here. Let me give you a little example. The search program. This is the program that everybody used to begin with. We are given a precondition, a natural number N, which is positive. And an array of element, which is formalized as a function from the interval 1 N to some state S. We are given a value V that is guaranteed to be part of the array. So V belongs to the range of F. This is a precondition. And we are looking post condition to an index R which is in the domain of F such that F of R is equal to V. Okay. I have added this to simplify this example. Of course, we could have had two answers. Nothing exists with the value V or there is a value V and here is the index. But I've simplified things by assuming these underlying conditions. a pre and post condition. So this is what we want to do. So this is Okay. So as you can see, I have not changed anything in the usual whole triple formality. Preprogram, post. Okay. So I've said before these things are not going to be changed in search. So I introduce them as constants. So they are constants. And the precondition corresponds exactly to the axioms of this constant. And the output parameters are variable and the post condition is a guard of unique event. I'll explain more about this. Forget about this. So let me encode the whole triple here. I'm defining carrier set S, because this is generic. Three constant. NFV and I copy blindly the precondition in the axioms. And I have a variable R, which is a result, and at this level R is a natural number. And the way I'm going to encode the post condition is as follows: I am defining a very strange event which just as a guard the post condition here, and it does nothing. Okay. So we want to go there. We want to be sure to go there. And here I have this thing which is a bit -- it's not dirty. It's convenient. It's something called progress. But it does a status call anticipated, which means that we do not consider -- we consider that we will refine this, of course, with doing something here for R, but at this level we just consider these two. This is just a convenient way to say that we will have something modifying R, of course, we will have something modifying R. And this is anticipated. Fine. And so now we are in this situation. We are here. We here. Okay. And now we have to go here, but we are here but an event system. And now we are going to refine. And so the refinement is extremely simple. We suppose that the variable initially. And we don't know what is in the array here. are here. We are we are here with idea of the R is set to 1 And in the middle, in the current situation, we found that in the first R minus 1 -- sorry, I start at 1, not at 0. In the first R minus 1 elements of the array, we didn't find the famous V. And here we don't know yet. And, of course, we are sure that V is here because it was in the axiom that V was in the range of F. So it's not here. Therefore it's here. Here this is an image of F with the interval, within the interval 1 R minus 1. Okay? So this is what we're going to do. And for doing this we are going to define our progress. And so progress is very, very simple. If F of R is different from V, F of R is here in this area where we have the question mark. If F of R is different from V, then R becomes R plus 1. So we just move this limit one step forward. And final here is just the same as before. But this is a new event. And the new event has to be convergence. Okay. So we have to prove that there is a variant that makes these things finishing eventually. So we introduce the variant, which is completely obvious, of course. This is N minus R. And R was defined as being in 1 N as an invariant, and NV -- and we have this also. So now this is very simple. We are going to prove that this population of events maintain this invariant. No problem with this one because I will just skip here. And this one -- this is really easy -- if V is not there, and if F of R is different from V, then V is not in 1 R. F 1 R. Okay. So we have proved this. So we are now with these two events, progress and final. They have -- they are deterministic. The guard is on top. And sees this and this. So only this. Only this. While F of R is different from V and then this eventually. So now what we're going to do is to put them together, and in order to put them together, we have to prove all this, of course. Of course. And then we have to -- this is the population of event in it, progress and final. And now we are going to do exactly the reverse that we've done before. We are going to aggregate things. So we have to have some merging rules, and those merging rules are completely syntactic. So the first merging rule is as follows: If we have two events like PQ then S and P not Q and then T, we can change them into a monster, which is still an event because there's an event P. But here this is -- it looks like a program. So it's in between a program and an event. Okay. But there are some conditions. Forget about the first one here. And the first event, so this one, must have been introduced at one refinement step below the second one. Why is that? Because if it has been introduced, the new event, at a refinement step below the second one, then we would have to prove that it is convergent, which is exactly the termination of the loop. Okay. And a special case, this is the reason why I said don't care too much about this one. If P is missing, then the resulting event, in quotes, has no guard. Haha, pffft, the guard has disappeared. And we have another one, which is exactly the same two events. You have PQ and P not Q and we change them into if Us then SLT and ha, and the other one will change while Q is -- while Q do S. So why is that? So the side conditions, it's just a disjunctive condition of the previous site conditions. So in particular, if the two have been -- if these two have been introduced in the same refinement step, you cannot prove that there is a termination of something like this. So they are at the same level. That's the reason we do that. Okay. And that's it. That's it. So now we are going to use our rules. So here we put progress and final together. Progress was anticipated, but we don't count the fact that it was anticipated. So it was introduced in the first refinement and final was introduced in the initial model. And we proved termination here. We proved convergence here. So now we do something called progress final, which is these two together. Okay? And this is almost finished. And then once we have an event without guard, we like to add in it by sequential composition at the beginning. So in it was this. So we just add here by sequential composition. We have nothing after it, because final will skip. And that's it. That's it. We have developed a program. Okay. >>: [inaudible] arbitrary order. >> Jean-Raymond Abrial: If we have. >>: If you have two events with those, you plug them in. >> Jean-Raymond Abrial: We will see this in an example. >>: Okay. >> Jean-Raymond Abrial: Okay. So I'm going to repeat this on other examples. Okay. It's completely systematic. For example, let's take the very classical binary search. Everybody takes a binary search. Okay. The same -- almost the same specification of this example. And more usage of the merging rule. The precondition, natural number, and this is positive. Sorted array. And value V in the range. This is too much. This can be proved as a theorem. And post condition, exactly the same as before. Okay? So here is an initial situation. The only difference with before is that we have this precondition here that the file is -- that the array is sorted. And we have the same progress and we have the same final as before. Okay? So now what we are going to do is refine. And everybody knows the binary search. This is very easy. You introduce -- we introduce two more variables, which was not the case last time. But when we refine, we can add variables. And we have these two variables are in the range, in the domain of F. And V is in the image of the interval PQ. So at the beginning of P is 1. And Q is N. Okay? And in the situation, in the current situation, we have something like this. From P to Q, we have V somewhere but we don't know where. we put R in the middle. And we have R in -- And R is always -- this is an invariant -- in the interval P..Q. So we have two cases. Ink. If F of R is smaller than -- if F of R is smaller than V because the array is sorted, V is not here. It was not already here. So it's not here now. And it's certainly here. So we can move P to R plus 1 and so now we go between -- we consider between R plus 1 and Q. And we have the deck, which is the symmetric one. If V is smaller than F of R, so V is not here. So V now is here. About R, R is still nondeterministic. It's in between P and Q. So here -sorry. Here I've assigned nondeterministically R to the interval R plus 1 Q. R plus 1 Q. So here nondeterministically I don't care. And the same here, R nondeterministically for P to R minus 1. And now I'm going to refine this. So this is the situation after the first refinement. But we are nondeterministic here and here. The events are deterministic. But the contents of the action of the events are nondeterministic. So the external nondeterministity is true, but the internal nondeterminisity is not true. We have to go further. And as you know we take, will now be chosen in the middle of PQ. So R -- this was the abstract ink and now the concrete ink, we take R plus 1 plus Q over 2, and here the abstract deck, and now we take the concrete deck as this. Okay. And now this is the end of it. So we have in it, we take also this alleged value here. We have still this skip event here. And we have these two people. And these two people have been introduced in the same refinement. candidates for if then else. So they are Okay. So we can do -- we use this. So ink and deck are building ink deck with this if then else here and final is just this. So now we put ink deck and final together. And so we apply this and clearly ink and deck, therefore ink deck is introduced in a refinement step that is after final. So we can now go on to this one. Or, by the way, about ink and deck we prove that they were not, that they were not going forever. So they were convergent and they were decreasing. It's obvious the variant is Q minus P. And so now we can apply the while. And that gives us this. it at the beginning and this is the final program. Okay? And now we put in >>: So your construction for a while says the first event has to be one hole below the second one. Can it be more holes below? >> Jean-Raymond Abrial: Yes. It can be. >>: It has to be at least one. >> Jean-Raymond Abrial: Yeah, yeah. Because you are sure that this is some level below that they were you so you have proved the convergence. Okay. So much. I told you, this is always the same. It's boring. So I'm going maybe this is the last one. I'm going to do some more on arrays. And last time -- next time I will do something on, with pointers. I'm not sure I will have enough time to treat the show it example. Maybe I will do it. And at the end I will take also some numerical examples. Okay. Among the examples I will do next time there will be an example with two loops. Okay. Loop inside the loop. And this is a sorting algorithm, as you could imagine. And the problem is when you use whole triple to prove something where you have a loop inside another loop, it's not so easy because you have an invariant which is -- and then a second invariant inside. Whereas here this is simple because you've got all these events. They're all flat. They're all on the table. And you just put them together and then you put them together to form the inner loop and then the outer loop. So let's go into array partitioning. This is part of Quicksort as you know. So we have an array of distinct elements. We are given a number X and we want to construct another array G with some constraints. And the constraints are G has got the same element as F. So the same domain. And there exists a number K in 0 N. So outside even. And number K such that all the elements in 1 K are smaller or equal to X and all elements in K plus 1 N are greater than X. So we partition -- we partition the thing. So we have to rearrange F into G in order to have this situation. Okay. So this is the classical partitioning of an array. So let's have a little example. So we have this array. We say X is equal to 5. And now this happens that K is also to 5. So under this they're all smaller or equal to 5. And above K here from K plus 1 to N they are greater than 5. Strictly greater than 5 and smaller or equal here. So we want to achieve this. We have two special cases. In that case let X be 0 then K is here. There is nothing before. And the second special case is when, if X is 10, greater than all of them, then K is here, from 1 to K they're all smaller than 10. Okay? Smaller than or equal to 10. Fine. So we start with this situation. We have the same thing. F here is an injective function. So it's a one-to-one function. It's a total function. And with this little thing here it means injective. So we have a one-to-one correspondence between 1 N and the range of 1 N. And X is any number. Okay. And about K and G, this is the result. We don't care. And final -- final I copy here completely the thing and skip as usual. And progress here, this is an anticipation. I allow the future progress to modify nondeterministically at this level K and G. And now we proceed. We introduce a variable J which is in 0 N. And the current situation is that from 1 to K it's okay, so to speak. We are smaller than or equal to X. From K plus 1 to J it's okay. We are greater than X. And here we don't know. Okay. And J is going to progress this way. And this is what is described here in this invariant. K is smaller than J. Smaller than or equal to J. The blue here is it's here for L in 1 K then we have this. And from L in K plus 1 J we have this. And here we don't say anything. So this is very, very classical with array programs we just moved something. Sometimes we've seen in the binary search we do things like this or we compare. But here this will be exactly the same. By the way, this notion of a pointer here, J, which moves along the data structure, we will find out exactly the same with pointers, when we have a list where the elements in the list are connected by pointers going to the next. We will move like this. Okay? And sometimes we have to move the other way around. Therefore, it's very nice to have a double link list. But there is no different -- there is no fundamental difference between the array and list by pointers. We will always do the same sort of thing. Here it's very convenient with arrays because we can play with intervals. And there are very nice notion about intervals if L is in 1 K, L is greater than or equal to 1 and smaller than or equal to K. So we can have arithmetic reasoning in order to do these things. And with pointers, this is exactly the same thing. But the mathematical structure is a bit more complicated, because it is in fact the transitive closure of the relation of the function defined by the pointers. First refinement. So this is the invariant for the first refinement. And now let me do a little animation here. We partitioned this with 5. here to begin with. And then we compare -- we compare this with 5. J is And it's greater than 5. So we can move. And here we compare it with 5. So it's smaller than 5 or equal to 5. So we are going to interchange. Okay. And the same here. And yet this is smaller. So we can move. Smaller. We can move. Bigger so we are going to exchange 4 and 7. And then 1 and we'll change 1 and 8 and that's it because we have reached the end. So the refining events, so these are not changed. Oh, yes, here we have -there is a data refinement here. We have J equal to N. And we have to prove, of course, that it refines its abstraction. And here progress 1, we must prove that it is convergent. And we have this situation. So JG plus 1 is greater than X so we just move on the right. This is the situation there. And we have the variant N minus J which is very important. So this is convergent. Progress two, which is JG plus 1 is smaller than, it's smaller or equal to X, so we could also move. And we move K and J. And finally here we have to swap in this situation we swapped the two values here. And we have to prove again that they maintained the invariant and that they decreased the variant. And so this is the animation. And now this is the end of it. We put together progress 2 and progress 3, which were defined at the same level. So this is an if then. And then we have P and Q. P and not Q. So that gives us -- and again another merging rule with an if then else if we already have an if then. So now we have progress 2, 3, so we put the three together. And now we put this together with progress 1 and this was not at the same level as this one. So we can do a while, and we have two contradictory conditions here. And the same G different from N. So we have this and now this is the final. We put the loop on top. And we add the init and that's the program. By the way, this is the program I showed you at the beginning. So you've seen how we have done it completely the other way around. Okay. 18 proved, and six were interactive. So I think Daphne and Boogie would do better on this. So we are like Avis, we are working very hard to have more automation into, with the prover. Okay? All right. That's something. So we will do that next time. >>: You did not show sequential composition. >> Jean-Raymond Abrial: No, I did not show sequential composition. >>: Next lecture or did you want to say something? >> Jean-Raymond Abrial: No, we know that much. But I will explain how it could be done with, there are various -- there's a little of sequential composition at the beginning when I add in it or at the end if final would have something to do which was not the case here. So we have already seen a little of sequential composition. But there are two other cases which I will describe a bit next time. >>: Two other questions. When you introduced the variant, you used the same invariant for all of the events refined at one level. >> Jean-Raymond Abrial: The same variant. >>: Right. How is that -- where is that stated? I mean, in Event-B, there's a little section for each event to say where you can include an invariant -where you can include the variant. >> Jean-Raymond Abrial: is unique. When you say that it is convergent. But the variant >>: So if you refine two different events, and you want each -- and you want them to have the same variant function, do you just state the same variant function in both places? >> Jean-Raymond Abrial: No, you don't put a variant function into the event. The variant function is at the level of the machine. >>: Oh, I see. >> Jean-Raymond Abrial: There is a unique. >>: I see, unique one for the entire machine. >> Jean-Raymond Abrial: Entire machine. >>: That makes sense. >> Jean-Raymond Abrial: That's actually fundamental, because if you have a different variant, this is okay for this one. This is okay for this one, but they could play Ping-Pong. Okay? So it's -- no, no, this is very important, this is the same -- and that's the reason why we can do an if then else, because each branch of they are in the same level and each branch has decreased the variant. And this was. >>: The possibilities will individually decrease the variance. >> Jean-Raymond Abrial: Decrease. >>: Doesn't matter which one you pick. >> Jean-Raymond Abrial: Yeah, yeah. >>: And my final question is, can you say something more about the status of the anticipated events? >> Jean-Raymond Abrial: Okay. >>: What's different with them? >> Jean-Raymond Abrial: At the beginning we have no anticipation. Okay. Now, if you have no anticipation, you remember that a new event must refine skip. Okay. So the problem is if we have no anticipation, we could not play with R, the result, because the result is just in it and final doesn't do anything. So in order to cope with this, we couldn't have a final doing skip, the final has to do something precisely to assign a certain value. And then the new event that we are introducing cannot play with R. to play with something else, let's say S. They have So S is a variable that's used in the process and at the end we assign R to S. And it's boring. If R and S are smallest thing, that's okay. But if R and S are big things, you cannot work like this. So it took us a long time to figure out this notion of anticipation. So the idea of anticipation is the following: I have seen in an unanticipated event R becomes any number. So it's completely nondeterministic. From the point of view of the level where it is introduced, it is just there because we want later to use, to assign in the real progress some value to R. But from the point of view of convergence, we are not proving the convergence there. We anticipate that the refinement will be convergence. And so that's exactly it. So most of the time all the time the progress was an unanticipated event, and in the next refinement progress is really introduced and would change the status from unanticipated to convergence. And something might stay -- in several steps might stay anticipated unanticipated and at some point it becomes convergent. >>: If I zoom in to a design at the particular model and I see an event there is anticipated, from the point of view from above, I should just ignore it then? >> Jean-Raymond Abrial: Yeah, you would ignore it. Yeah. It's a convenient way -- and most of the time it's doing something that is completely nondeterministic. By the way, we were thinking of a feature in our formalism. We have skip that does nothing, and we were thinking of something like called keep. Keep is nondeterministically changed things in order for the invariant to hold. It's like a havoc. It's a bit like a havoc. But it's a havoc that maintains the variant. >>: Havoc followed assuming the variant. >> Jean-Raymond Abrial: Exactly. And we had discussion on this and finally we didn't do it. But it could be exactly where this keep or havoc or sort of havoc could have been used. Further questions? [applause] No? Okay.