]> matita.cs.unibo.it Git - helm.git/blob - matita/matita/lib/tutorial/chapter1.ma
e726eac071f060ecebd349a0e86380166afb80ad
[helm.git] / matita / matita / lib / tutorial / chapter1.ma
1 (* 
2 Data types, functions and theorems
3
4 Matita is both a programming language and a theorem proving environment:
5 you define datatypes and programs, and then prove properties on them.
6 Very few things are built-in: not even booleans or logical connectives
7 (but you may of course use libraries, as in normal programming languages). 
8 The main philosophy of the system is to let you define your own data-types 
9 and functions using a powerful computational mechanism based on the 
10 declaration of inductive types. 
11
12 Let us start this tutorial with a simple example based on the following well 
13 known problem.
14
15 The goat, the wolf and the cabbage
16 A farmer need to transfer a goat, a wolf and a cabbage across a river, but there
17 is only one place available on his boat. Furthermore, the goat will eat the 
18 cabbage if they are left alone on the same bank, and similarly the wolf will eat
19 the goat. The problem consists in bringing all three items safely across the 
20 river. 
21
22 Our first data type defines the two banks of the river, which will be named east
23 and west. It is a simple example of enumerated type, defined by explicitly 
24 declaring all its elements. The type itself is called "bank".
25 Before giving its definition we "include" the file "logic.ma" that contains a 
26 few preliminary notions not worth discussing for the moment.
27 *)
28
29 include "basics/logic.ma".
30
31 inductive bank: Type[0] ≝
32 | east : bank 
33 | west : bank.
34
35 (* We can now define a simple function computing, for each bank of the river, the
36 opposite one. *)
37
38 definition opposite ≝ λs.
39 match s with
40   [ east ⇒ west
41   | west ⇒ east
42   ].
43
44 (* Functions are live entities, and can be actually computed. To check this, let
45 us state the property that the opposite bank of east is west; every lemma needs a 
46 name for further reference, and we call it "east_to_west". *)
47  
48 lemma east_to_west : opposite east = west.
49
50 (* 
51 The goal window
52
53 If you stop the execution here you will see a new window on the  right side
54 of the screen: it is the goal window, providing a sequent like representation of
55 the form
56
57 B1
58 B2
59 ....
60 Bk
61 -----------------------
62 A
63
64 for each open goal remaining to be solved. A is the conclusion of the goal and 
65 B1, ..., Bk is its context, that is the set of current hypothesis and type 
66 declarations. In this case, we have only one goal, and its context is empty. 
67 The proof proceeds by typing commands to the system. In this case, we
68 want to evaluate the function, that can be done by invoking the  "normalize"
69 command:
70 *)
71
72 normalize
73
74 (* By executing it - just type the advance command - you will see that the goal
75 has changed to west = west, by reducing the subexpression (opposite east). 
76 You may use the retract bottom to undo the step, if you wish. 
77
78 The new goal west = west is trivial: it is just a consequence of reflexivity.
79 Such trivial steps can be just closed in Matita by typing a double slash. 
80 We complete the proof by the qed command, that instructs the system to store the
81 lemma performing some book-keeping operations. 
82 *)
83
84 // qed.
85
86 (* In exactly the same way, we can prove that the opposite side of west is east.
87 In this case, we avoid the unnecessary simplification step: // will take care of 
88 it. *) 
89
90 lemma west_to_east : opposite west = east.
91 // qed.
92
93 (*
94 Introduction
95
96 A slightly more complex problem consists in proving that opposite is idempotent *)
97
98 lemma idempotent_opposite : ∀x. opposite (opposite x) = x.
99
100 (* we start the proof moving x from the conclusion into the context, that is a 
101 (backward) introduction step. Matita syntax for an introduction step is simply 
102 the sharp character followed by the name of the item to be moved into the 
103 context. This also allows us to rename the item, if needed: for instance if we 
104 wish to rename x into b (since it is a bank), we just type #b. *)
105
106 #b
107
108 (* See the effect of the execution in the goal window on the right: b has been 
109 added to the context (replacing x in the conclusion); moreover its implicit type 
110 "bank" has been made explicit. 
111 *)
112
113 (*
114 Case analysis
115
116 But how are we supposed to proceed, now? Simplification cannot help us, since b
117 is a variable: just try to call normalize and you will see that it has no effect.
118 The point is that we must proceed by cases according to the possible values of b,
119 namely east and west. To this aim, you must invoke the cases command, followed by
120 the name of the hypothesis (more generally, an arbitrary expression) that must be
121 the object of the case analysis (in our case, b).
122 *)
123
124 cases b
125
126 (* Executing the previous command has the effect of opening two subgoals, 
127 corresponding to the two cases b=east and b=west: you may switch from one to the 
128 other by using the hyperlinks over the top of the goal window. 
129 Both goals can be closed by trivial computations, so we may use // as usual.
130 If we had to treat each subgoal in a different way, we should focus on each of 
131 them in turn, in a way that will be described at the end of this section.
132 *)
133
134 // qed.
135
136 (* 
137 Predicates
138
139 Instead of working with functions, it is sometimes convenient to work with
140 predicates. For instance, instead of defining a function computing the opposite 
141 bank, we could declare a predicate stating when two banks are opposite to each 
142 other. Only two cases are possible, leading naturally to the following 
143 definition:
144 *)
145
146 inductive opp : bank → bank → Prop ≝ 
147 | east_west : opp east west
148 | west_east : opp west east.
149
150 (* In precisely the same way as "bank" is the smallest type containing east and
151 west, opp is the smallest predicate containing the two sub-cases east_west and
152 weast_east. If you have some familiarity with Prolog, you may look at opp as the
153 predicate defined by the two clauses - in this case, the two facts - ast_west and
154 west_east.
155
156 Between opp and opposite we have the following relation:
157     opp a b iff a = opposite b
158 Let us prove it, starting from the left to right implication, first *)
159
160 lemma opp_to_opposite: ∀a,b. opp a b → a = opposite b.
161  
162 (* We start the proof introducing a, b and the hypothesis opp a b, that we
163 call oppab. *)
164 #a #b #oppab
165
166 (* Now we proceed by cases on the possible proofs of (opp a b), that is on the 
167 possible shapes of oppab. By definition, there are only two possibilities, 
168 namely east_west or west_east. Both subcases are trivial, and can be closed by
169 automation *)
170
171 cases oppab // qed.
172
173 (* 
174 Rewriting
175
176 Let us come to the opposite direction. *)
177
178 lemma opposite_to_opp: ∀a,b. a = opposite b → opp a b.
179
180 (* As usual, we start introducing a, b and the hypothesis (a = opposite b), 
181 that we call eqa. *)
182
183 #a #b #eqa
184
185 (* The right way to proceed, now, is by rewriting a into (opposite b). We do
186 this by typing ">eqa". If we wished to rewrite in the opposite direction, namely
187 opposite b into a, we would have typed "<eqa". *)
188
189 >eqa
190
191 (* We conclude the proof by cases on b. *)
192
193 cases b // qed.
194
195 (*
196 Records
197
198 It is time to proceed with our formalization of the farmer's problem. 
199 A state of the system is defined by the position of four items: the goat, the 
200 wolf, the cabbage, and the boat. The simplest way to declare such a data type
201 is to use a record.
202 *)
203
204 record state : Type[0] ≝
205   {goat_pos : bank;
206    wolf_pos : bank;
207    cabbage_pos: bank;
208    boat_pos : bank}.
209
210 (* When you define a record named foo, the system automatically defines a record 
211 constructor named mk_foo. To construct a new record you pass as arguments to 
212 mk_foo the values of the record fields *)
213
214 definition start ≝ mk_state east east east east.
215 definition end ≝ mk_state west west west west.
216
217 (* We must now define the possible moves. A natural way to do it is in the form 
218 of a relation (a binary predicate) over states. *)
219
220 inductive move : state → state → Prop ≝
221 | move_goat: ∀g,g1,w,c. opp g g1 → move (mk_state g w c g) (mk_state g1 w c g1)
222   (* We can move the goat from a bank g to the opposite bank g1 if and only if the
223      boat is on the same bank g of the goat and we move the boat along with it. *)
224 | move_wolf: ∀g,w,w1,c. opp w w1 → move (mk_state g w c w) (mk_state g w1 c w1)
225 | move_cabbage: ∀g,w,c,c1.opp c c1 → move (mk_state g w c c) (mk_state g w c1 c1)
226 | move_boat: ∀g,w,c,b,b1. opp b b1 → move (mk_state g w c b) (mk_state g w c b1).
227
228 (* A state is safe if either the goat is on the same bank of the boat, or both 
229 the wolf and the cabbage are on the opposite bank of the goat. *)
230
231 inductive safe_state : state → Prop ≝
232 | with_boat : ∀g,w,c.safe_state (mk_state g w c g)
233 | opposite_side : ∀g,g1,b.opp g g1 → safe_state (mk_state g g1 g1 b).
234
235 (* Finally, a state y is reachable from x if either there is a single move 
236 leading from x to y, or there is a safe state z such that z is reachable from x 
237 and there is a move leading from z to y *)
238
239 inductive reachable : state → state → Prop ≝
240 | one : ∀x,y.move x y → reachable x y
241 | more : ∀x,z,y. reachable x z → safe_state z → move z y → reachable x y.
242
243 (* 
244 Automation
245
246 Remarkably, Matita is now able to solve the problem by itslef, provided
247 you allow automation to exploit more resources. The command /n/ is similar to
248 //, where n is a measure of this complexity: in particular it is a bound to
249 the depth of the expected proof tree (more precisely, to the number of nested
250 applicative nodes). In this case, there is a solution in six moves, and we
251 need a few more applications to handle reachability, and side conditions. 
252 The magic number to let automation work is, in this case, 9.  *)
253
254 lemma problem: reachable start end.
255 normalize /9/ qed. 
256
257 (* 
258 Application
259
260 Let us now try to derive the proof in a more interactive way. Of course, we
261 expect to need several moves to transfer all items from a bank to the other, so 
262 we should start our proof by applying "more". Matita syntax for invoking the 
263 application of a property named foo is to write "@foo". In general, the philosophy 
264 of Matita is to describe each proof of a property P as a structured collection of 
265 objects involved in the proof, prefixed by simple modalities (#,<,@,...) explaining 
266 the way it is actually used (e.g. for introduction, rewriting, in an applicative 
267 step, and so on).
268 *)
269
270 lemma problem1: reachable start end.
271 normalize @more
272
273 (* 
274 Focusing
275
276 After performing the previous application, we have four open subgoals:
277
278   X : STATE
279   Y : reachable [east,east,east,east] X
280   W : safe_state X
281   Z : move X [west,west,west,west]
282  
283 That is, we must guess a state X, such that this is reachable from start, it is 
284 safe, and there is a move leading from X to end. All goals are active, that is
285 emphasized by the fact that they are all red. Any command typed by the user is
286 normally applied in parallel to all active goals, but clearly we must proceed 
287 here is a different way for each of them. The way to do it, is by structuring
288 the script using the following syntax: [...|... |...|...] where we typically have
289 as many cells inside the brackets as the number of the active subgoals. The
290 interesting point is that we can associate with the three symbol "[", "|" and
291 "]" a small-step semantics that allow to execute them individually. In particular
292
293 - the operator "[" opens a new focusing section for the currently active goals,
294   and focus on the first of them
295 - the operator "|" shift the focus to the next goal
296 - the operator "]" close the focusing section, falling back to the previous level
297   and adding to it all remaining goals not yet closed
298
299 Let us see the effect of the "[" on our proof:
300 *)
301
302   [  
303
304 (* As you see, only the first goal has now the focus on. Moreover, all goals got
305 a progressive numerical label, to help designating them, if needed. 
306 We can now proceed in several possible ways. The most straightforward way is to 
307 provide the intermediate state, that is [east,west,west,east]. We can do it, by 
308 just applying this term. *)
309
310    @(mk_state east west west east) 
311
312 (* This application closes the goal; at present, no goal has the focus on.
313 In order to act on the next goal, we must focus on it using the "|" operator. In
314 this case, we would like to skip the next goal, and focus on the trivial third 
315 subgoal: a simple way to do it, is by retyping "|". The proof that 
316 [east,west,west,east] is safe is trivial and can be done with //.*)
317
318   || //
319
320 (*
321 We then advance to the next goal, namely the fact that there is a move from 
322 [east,west,west,east] to [west,west,west,west]; this is trivial too, but it 
323 requires /2/ since move_goat opens an additional subgoal. By applying "]" we
324 refocus on the skipped goal, going back to a situation similar to the one we
325 started with. *)
326
327   | /2/ ] 
328
329 (* 
330 Implicit arguments
331
332 Let us perform the next step, namely moving back the boat, in a sligtly 
333 different way. The more operation expects as second argument the new 
334 intermediate state, hence instead of applying more we can apply this term
335 already instatated on the next intermediate state. As first argument, we
336 type a question mark that stands for an implicit argument to be guessed by
337 the system. *)
338
339 @(more ? (mk_state east west west west))
340
341 (* We now get three independent subgoals, all actives, and two of them are 
342 trivial. We can just apply automation to all of them, and it will close the two
343 trivial goals. *)
344
345 /2/
346
347 (* Let us come to the next step, that consists in moving the wolf. Suppose that 
348 instead of specifying the next intermediate state, we prefer to specify the next 
349 move. In the spirit of the previous example, we can do it in the following way 
350 *)
351
352 @(more … (move_wolf … ))
353
354 (* The dots stand here for an arbitrary number of implicit arguments, to be 
355 guessed by the system. 
356 Unfortunately, the previous move is not enough to fully instantiate the new 
357 intermediate state: a bank B remains unknown. Automation cannot help here,
358 since all goals depend from this bank and automation refuses to close some
359 subgoals instantiating other subgoals remaining open (the instantiation could
360 be arbitrary). The simplest way to proceed is to focus on the bank, that is
361 the fourth subgoal, and explicitly instatiate it. Instead of repeatedly using "|",
362 we can perform focusing by typing "4:" as described by the following command. *)
363
364 [4: @east] /2/
365
366 (* Alternatively, we can directly instantiate the bank into the move. Let
367 us complete the proof in this, very readable way. *)
368
369 @(more … (move_goat west … )) /2/
370 @(more … (move_cabbage ?? east … )) /2/
371 @(more … (move_boat ??? west … )) /2/
372 @one /2/ qed.