CPSC 333 --- Lecture 33 --- Wednesday, April 3, 1996 Aids to Presentation - mostly (but not only) to simplify creation of schemas that define operations 1. Schema Decoration --- provides a systematic way of introducing "dashed" names of the components of a schema together with the *data invariant* --- the set of predicates included in the schema that these must satisfy. Consider the small example schema, "Counter," introduced last name. Values "min_value" and "max_value" had been defined earlier, using axiomatic descriptions. ------- Counter ------------------------------------ | | value : ZZ | |---------------------------------------------------- | | (min_value \le value) \and (value \le max_value) | |____________________________________________________ Here is the "decorated schema" Counter' : ------- Counter' ----------------------------------- | | value' : ZZ | |---------------------------------------------------- | | (min_value \le value') \and (value' \le max_value) | |____________________________________________________ Note that only the values which are *declared* inside the schema get "dashed." 2. Schema Inclusion --- You can list the name of one schema inside another, in order to incorporate the first schema's declarations and predicates. This will be made more precise after an example is given: Consider the "Set_Counter" schema from the Monday, April 1, lecture. An equivalent schema (that looks slightly different, but which has the same declarations and logically equivalent predicates) would be produced using schema inclusion: ------- Set_Counter -------------------------------- | | Counter | Counter' | value_received? : ZZ | |---------------------------------------------------- | | ((min_value \le value_received?) \and | (value_received? \le max_value)) | \implies | (value' = value_received?) | | (\not ((min_value \le value_received?) \and | (value_received? \le max_value))) | \implies | (value' = value) | |____________________________________________________ This is *slightly* more succinct than the version of the schema given on Monday. In general, you can include one schema if, and only if, doing so would not generate a "type conflict" --- that is, provided that this wouldn't cause a variable to be defined to have two or more different types at once. Effects of Schema Inclusion: Some declarations in Z do more than just identify a value's type. For example, when you say x : NN you are declaring that x is an *integer*, x : ZZ and also including an *implicit predicate* that x is a natural number. One way to write this would be x \ge 0 ...and another would be to write x \in NN The declaration of "books" as a partial function, given in the first lecture on Z, actually defined the type of books as follows: books : PP(ZZ x (Title x (ZZ x (ZZ x (ZZ x (ZZ x ZZ)))))) The *implicit predicate* for this declaration is discussed in the second question of the first lab exercise on Z. In general you can think of a schema - as a set of introductions of variables with identification of their types (*part* of the information given in the "declaration part" of the schema), and - a predicate that is obtained by conjoining ("and"-ing together) all the predicates that are listed explicitly, in the predicate part of the schema, *AND* all the implicit predicates (the *rest* of the information in the declaration part of the schema) For example, consider the following schema. -------- Example_Schema ---------------------------- | | n : NN | f : ZZ \pfun ZZ | |---------------------------------------------------- | | n \le 2 | |____________________________________________________ I would consider the "set of introductions of variables with identifications of their types" for this schema to be n : ZZ f : PP(Z x Z) and I could consider the "predicate" for this schema to be something like ((n \in NN) \and (\forall x : ZZ \bullet (\forall y1 : ZZ \bullet (\forall y2 : ZZ \bullet ((((x \mapsto y1) \in f) and ((x \mapsto y2) \in f)) \implies (y1 = y2))))) \and (n \le 2)) with the long, middle part, saying that f is a partial function instead of an "arbitrary relation." Again, the "predicate" includes all the *implicit predicates* for things in the declaration part, as well as the assertions mentioned explicitly in the predicate part of the schema. When you list the name of a schema A in the declaration part of another schema B, this has the effect of - merging all the declarations (including names and types) from the declaration part of A, in with the declaration part of B - adding the "predicate" for A to the predicate part of B. It is an error to do this, if it would cause a variable to be defined more than once, when the variable is not always defined to have the same type. Now consider the following three attempts to include the above schema in a larger one: Attempt #1: ----------- Bigger_Example --------------------------------- | | Example_Schema | n:ZZ | |------------------------------------------------------------ | | n \ge 1 | |____________________________________________________________ Even though the definitions of n in the two schemas involved look different, they both define the type of n to be ZZ, so that they're compatible. The schema you obtain in this case is acceptable. Attempt #2: ----------- Bigger_Example2 -------------------------------- | | Example_Schema | n : ZZ \pfun ZZ | |------------------------------------------------------------ | | f(0) = 1 | |____________________________________________________________ This is *not* correct, because n is defined to have two different types in the schemas involved: It's defined to have type ZZ in the "Example_Schema" and type PP(Z x Z) in the schema in which you're trying to include "Example_Schema". Thus there is a "type clash" in this case, so that the resulting schema is incorrect. Attempt #3: ---------- Bigger_Example3 --------------------------------- | | Example_Schema | n:ZZ | |------------------------------------------------------------ | | n \ge 3 | |____________________________________________________________ In this case there is no type clash --- but the schema is useless, since it requires simultaneously that n be less than or equal to 2, and greater than or equal to 3. Therefore the schema's predicate is "unsatisfiable" and the schema does not describe any state or condition that could possibly occur. More Shortcuts: 3. The "Delta" Convention. In the following, when I type DELTA, this should refer to the Greek letter "upper case delta" --- which looks like a small equilateral triangle. If S is a schema then DELTA S is a schema including the declarations and predicates in both S and S' (and nothing else). This is useful for defining operations on data areas. For example, the schema DELTA Counter is (equivalent to) ------- DELTA Counter --------------------------------------- | | value : ZZ | value' : ZZ | |------------------------------------------------------------- | | (min_value \le value) \and (value \le max_value) | | (min_value \le value') \and (value' \le max_value) | |_____________________________________________________________ Now, I can include *one* schema --- DELTA Counter --- instead of two --- Counter and Counter' --- in order to develop operations on counters (like Set_Counter) more succinctly. 4. The "Xi" Convention. In the following when I type XI, this should refer to the Greek letter "upper case xi" --- which is hard to describe. You will find a schema "XI Bookstore_Data" that is included in the schema "Get_Book," at the top of page 5 of the handout "CPSC 333 --- Introduction to Z" (which was distributed during this lecture). If S is a schema then XI S is a schema that includes all the declarations and predicates in DELTA S together with a predicate x = x' for every value x that was declared in S. The "Xi" convention is useful for defining operations that report on the *state* of a data area without changing it. For example, the schema XI Counter is (equivalent to) ----------- XI Counter -------------------------------------- | | value : ZZ | value' : ZZ | |------------------------------------------------------------- | | (min_value \le value) \and (value \le max_value) | | (min_value \le value') \and (value' \le max_value) | | value = value' | |____________________________________________________________ Now, the schema "Report_Counter" from the last lecture could have been written *much* more succinctly as: ---------- Report_Counter ---------------------------------- | | XI Counter | value_reported! : ZZ | |------------------------------------------------------------ | | value_reported! = value | |____________________________________________________________ Schema Calculus: Suppose now that S and T are schemas and that no value is declared with different types in S and T, so that it is possible to include both S and T in a schema without necessarily introducing a type clash. Let pred_S be the predicate of S (obtaining by "and"-ing together all the explicit *and* implicit predicates in S) and let pred_T be the predicate of T. In the following, I'll type \schemaDef instead of = with a hat (^) on top of it. This symbol is called the "schema definition symbol." 5. Schema Disjunction Now, if I type R \schemaDef S \or T then this declares R to be a schema whose declarations can be obtained by merging together all the declarations in S and in T (the same set of declarations that you'd get by "including" S in T or vice-versa) and with a predicate pred_S \or pred_T. 6. Schema Conjunction If, instead, I type R \schemaDef S \and T then this sets R to be the same as above, except that is predicate is pred_S \and pred_T instead of pred_S \or pred_T. Consider, for example, the following schemas: ------ Set_Counter_OK --------------------------------------- | | DELTA Counter | value_received? : ZZ | |------------------------------------------------------------- | | min_value \le value_received? | | value_received? \le max_value | | value' = value_received? | |_____________________________________________________________ ------ Set_Counter_NotOK ------------------------------------ | | XI Counter | value_received? : ZZ | |------------------------------------------------------------- | | \not ((min_value \le value_received?) | \and (value_received? \le max_value)) | |_____________________________________________________________ Set_Counter \schemaDef Set_Counter_OK \or Set_Counter_NotOK This defines "Set_Counter" to be a schema that is equivalent to the schema that was named "Set_Counter" in the previous lecture. As this example indicates, you can define a complex operation --- one whose effect should be different in several cases --- by defining schemas that each identify a case which "must hold" and that specify the behaviour of the operation in that case --- and then using schema disjunction to construct a schema for the entire operation from the schemas for the cases. Be careful to make sure that your cases are both *exhaustive* (at least one case always holds) and *exclusive* (cases don't overlap). Otherwise, if your cases aren't exhaustive and you use this technique, then the schema will indicate that "the missing case can never hold" if none of the schemas you're including cover it. If you use disjunction with overlapping cases then this will have the effect of saying that "either (or any) of the applicable behaviours are acceptable" when more than one case is satisfied. Thus you should make sure that your cases are exhaustive and exclusive --- unless you really *do* want to declare that some cases (involving the inputs) should not be allowed, and you really *do* want to specify an operation that is to some extent (and in some sense) "nondeterministic" when cases overlap. There is a way to do something like this using *schema conjunction* as well --- this will be considered in a lab exercise. In *this* case, if you miss a case then your schema will probably consider *any* behaviour to be acceptable when none of the cases you've considered applies, and you run the risk of having a schema that *isn't satisfiable at all* when cases overlap. To see another reason that "schema conjunction" might be useful too, note that a precise way to define "DELTA Counter" from Counter and Counter' would be to write DELTA Counter \schemaDef Counter \and Counter'