comparison src/Reflection.v @ 147:f103f28a6b57

my_tauto prose
author Adam Chlipala <adamc@hcoop.net>
date Tue, 28 Oct 2008 16:31:55 -0400
parents 2779c651406a
children 0952c4ba209b
comparison
equal deleted inserted replaced
146:2779c651406a 147:f103f28a6b57
359 (** Extensions of this basic approach are used in the implementations of the [ring] and [field] tactics that come packaged with Coq. *) 359 (** Extensions of this basic approach are used in the implementations of the [ring] and [field] tactics that come packaged with Coq. *)
360 360
361 361
362 (** * A Smarter Tautology Solver *) 362 (** * A Smarter Tautology Solver *)
363 363
364 (** Now we are ready to revisit our earlier tautology solver example. We want to broaden the scope of the tactic to include formulas whose truth is not syntactically apparent. We will want to allow injection of arbitrary formulas, like we allowed arbitrary monoid expressions in the last example. Since we are working in a richer theory, it is important to be able to use equalities between different injected formulas. For instance, we cannott prove [P -> P] by translating the formula into a value like [Imp (Var P) (Var P)], because a Gallina function has no way of comparing the two [P]s for equality.
365
366 To arrive at a nice implementation satisfying these criteria, we introduce the [quote] tactic and its associated library. *)
367
364 Require Import Quote. 368 Require Import Quote.
365 369
366 Inductive formula : Set := 370 Inductive formula : Set :=
367 | Atomic : index -> formula 371 | Atomic : index -> formula
368 | Truth : formula 372 | Truth : formula
369 | Falsehood : formula 373 | Falsehood : formula
370 | And : formula -> formula -> formula 374 | And : formula -> formula -> formula
371 | Or : formula -> formula -> formula 375 | Or : formula -> formula -> formula
372 | Imp : formula -> formula -> formula. 376 | Imp : formula -> formula -> formula.
373 377
374 Definition asgn := varmap Prop. 378 (** The type [index] comes from the [Quote] library and represents a countable variable type. The rest of [formula]'s definition should be old hat by now.
379
380 The [quote] tactic will implement injection from [Prop] into [formula] for us, but it is not quite as smart as we might like. In particular, it interprets implications incorrectly, so we will need to declare a wrapper definition for implication, as we did in the last chapter. *)
375 381
376 Definition imp (P1 P2 : Prop) := P1 -> P2. 382 Definition imp (P1 P2 : Prop) := P1 -> P2.
377 Infix "-->" := imp (no associativity, at level 95). 383 Infix "-->" := imp (no associativity, at level 95).
384
385 (** Now we can define our denotation function. *)
386
387 Definition asgn := varmap Prop.
378 388
379 Fixpoint formulaDenote (atomics : asgn) (f : formula) : Prop := 389 Fixpoint formulaDenote (atomics : asgn) (f : formula) : Prop :=
380 match f with 390 match f with
381 | Atomic v => varmap_find False v atomics 391 | Atomic v => varmap_find False v atomics
382 | Truth => True 392 | Truth => True
384 | And f1 f2 => formulaDenote atomics f1 /\ formulaDenote atomics f2 394 | And f1 f2 => formulaDenote atomics f1 /\ formulaDenote atomics f2
385 | Or f1 f2 => formulaDenote atomics f1 \/ formulaDenote atomics f2 395 | Or f1 f2 => formulaDenote atomics f1 \/ formulaDenote atomics f2
386 | Imp f1 f2 => formulaDenote atomics f1 --> formulaDenote atomics f2 396 | Imp f1 f2 => formulaDenote atomics f1 --> formulaDenote atomics f2
387 end. 397 end.
388 398
399 (** The [varmap] type family implements maps from [index] values. In this case, we define an assignment as a map from variables to [Prop]s. [formulaDenote] works with an assignment, and we use the [varmap_find] function to consult the assignment in the [Atomic] case. The first argument to [varmap_find] is a default value, in case the variable is not found. *)
400
389 Section my_tauto. 401 Section my_tauto.
390 Variable atomics : asgn. 402 Variable atomics : asgn.
391 403
392 Definition holds (v : index) := varmap_find False v atomics. 404 Definition holds (v : index) := varmap_find False v atomics.
405
406 (** We define some shorthand for a particular variable being true, and now we are ready to define some helpful functions based on the [ListSet] module of the standard library, which (unsurprisingly) presents a view of lists as sets. *)
393 407
394 Require Import ListSet. 408 Require Import ListSet.
395 409
396 Definition index_eq : forall x y : index, {x = y} + {x <> y}. 410 Definition index_eq : forall x y : index, {x = y} + {x <> y}.
397 decide equality. 411 decide equality.
398 Defined. 412 Defined.
399 413
400 Definition add (s : set index) (v : index) := set_add index_eq v s. 414 Definition add (s : set index) (v : index) := set_add index_eq v s.
415
401 Definition In_dec : forall v (s : set index), {In v s} + {~In v s}. 416 Definition In_dec : forall v (s : set index), {In v s} + {~In v s}.
402 Open Local Scope specif_scope. 417 Open Local Scope specif_scope.
403 418
404 intro; refine (fix F (s : set index) : {In v s} + {~In v s} := 419 intro; refine (fix F (s : set index) : {In v s} + {~In v s} :=
405 match s return {In v s} + {~In v s} with 420 match s return {In v s} + {~In v s} with
406 | nil => No 421 | nil => No
407 | v' :: s' => index_eq v' v || F s' 422 | v' :: s' => index_eq v' v || F s'
408 end); crush. 423 end); crush.
409 Defined. 424 Defined.
425
426 (** We define what it means for all members of an index set to represent true propositions, and we prove some lemmas about this notion. *)
410 427
411 Fixpoint allTrue (s : set index) : Prop := 428 Fixpoint allTrue (s : set index) : Prop :=
412 match s with 429 match s with
413 | nil => True 430 | nil => True
414 | v :: s' => holds v /\ allTrue s' 431 | v :: s' => holds v /\ allTrue s'
432 Qed. 449 Qed.
433 450
434 Hint Resolve allTrue_add allTrue_In. 451 Hint Resolve allTrue_add allTrue_In.
435 452
436 Open Local Scope partial_scope. 453 Open Local Scope partial_scope.
454
455 (** Now we can write a function [forward] which implements deconstruction of hypotheses. It has a dependent type, in the style of Chapter 6, guaranteeing correctness. The arguments to [forward] are a goal formula [f], a set [known] of atomic formulas that we may assume are true, a hypothesis formula [hyp], and a success continuation [cont] that we call when we have extended [known] to hold new truths implied by [hyp]. *)
437 456
438 Definition forward (f : formula) (known : set index) (hyp : formula) 457 Definition forward (f : formula) (known : set index) (hyp : formula)
439 (cont : forall known', [allTrue known' -> formulaDenote atomics f]) 458 (cont : forall known', [allTrue known' -> formulaDenote atomics f])
440 : [allTrue known -> formulaDenote atomics hyp -> formulaDenote atomics f]. 459 : [allTrue known -> formulaDenote atomics hyp -> formulaDenote atomics f].
441 refine (fix F (f : formula) (known : set index) (hyp : formula) 460 refine (fix F (f : formula) (known : set index) (hyp : formula)
451 | Or h1 h2 => F f known h1 cont && F f known h2 cont 470 | Or h1 h2 => F f known h1 cont && F f known h2 cont
452 | Imp _ _ => Reduce (cont known) 471 | Imp _ _ => Reduce (cont known)
453 end); crush. 472 end); crush.
454 Defined. 473 Defined.
455 474
475 (** A [backward] function implements analysis of the final goal. It calls [forward] to handle implications. *)
476
456 Definition backward (known : set index) (f : formula) : [allTrue known -> formulaDenote atomics f]. 477 Definition backward (known : set index) (f : formula) : [allTrue known -> formulaDenote atomics f].
457 refine (fix F (known : set index) (f : formula) : [allTrue known -> formulaDenote atomics f] := 478 refine (fix F (known : set index) (f : formula) : [allTrue known -> formulaDenote atomics f] :=
458 match f return [allTrue known -> formulaDenote atomics f] with 479 match f return [allTrue known -> formulaDenote atomics f] with
459 | Atomic v => Reduce (In_dec v known) 480 | Atomic v => Reduce (In_dec v known)
460 | Truth => Yes 481 | Truth => Yes
463 | Or f1 f2 => F known f1 || F known f2 484 | Or f1 f2 => F known f1 || F known f2
464 | Imp f1 f2 => forward f2 known f1 (fun known' => F known' f2) 485 | Imp f1 f2 => forward f2 known f1 (fun known' => F known' f2)
465 end); crush; eauto. 486 end); crush; eauto.
466 Defined. 487 Defined.
467 488
489 (** A simple wrapper around [backward] gives us the usual type of a partial decision procedure. *)
490
468 Definition my_tauto (f : formula) : [formulaDenote atomics f]. 491 Definition my_tauto (f : formula) : [formulaDenote atomics f].
469 intro; refine (Reduce (backward nil f)); crush. 492 intro; refine (Reduce (backward nil f)); crush.
470 Defined. 493 Defined.
471 End my_tauto. 494 End my_tauto.
495
496 (** Our final tactic implementation is now fairly straightforward. First, we [intro] all quantifiers that do not bind [Prop]s. Then we call the [quote] tactic, which implements the reflection for us. Finally, we are able to construct an exact proof via [partialOut] and the [my_tauto] Gallina function. *)
472 497
473 Ltac my_tauto := 498 Ltac my_tauto :=
474 repeat match goal with 499 repeat match goal with
475 | [ |- forall x : ?P, _ ] => 500 | [ |- forall x : ?P, _ ] =>
476 match type of P with 501 match type of P with
481 quote formulaDenote; 506 quote formulaDenote;
482 match goal with 507 match goal with
483 | [ |- formulaDenote ?m ?f ] => exact (partialOut (my_tauto m f)) 508 | [ |- formulaDenote ?m ?f ] => exact (partialOut (my_tauto m f))
484 end. 509 end.
485 510
511 (** A few examples demonstrate how the tactic works. *)
512
486 Theorem mt1 : True. 513 Theorem mt1 : True.
487 my_tauto. 514 my_tauto.
488 Qed. 515 Qed.
489 516
490 Print mt1. 517 Print mt1.
518 (** [[
519
520 mt1 = partialOut (my_tauto (Empty_vm Prop) Truth)
521 : True
522 ]]
523
524 We see [my_tauto] applied with an empty [varmap], since every subformula is handled by [formulaDenote]. *)
491 525
492 Theorem mt2 : forall x y : nat, x = y --> x = y. 526 Theorem mt2 : forall x y : nat, x = y --> x = y.
493 my_tauto. 527 my_tauto.
494 Qed. 528 Qed.
495 529
496 Print mt2. 530 Print mt2.
531 (** [[
532
533 mt2 =
534 fun x y : nat =>
535 partialOut
536 (my_tauto (Node_vm (x = y) (Empty_vm Prop) (Empty_vm Prop))
537 (Imp (Atomic End_idx) (Atomic End_idx)))
538 : forall x y : nat, x = y --> x = y
539 ]]
540
541 Crucially, both instances of [x = y] are represented with the same index, [End_idx]. The value of this index only needs to appear once in the [varmap], whose form reveals that [varmap]s are represented as binary trees, where [index] values denote paths from tree roots to leaves. *)
497 542
498 Theorem mt3 : forall x y z, 543 Theorem mt3 : forall x y z,
499 (x < y /\ y > z) \/ (y > z /\ x < S y) 544 (x < y /\ y > z) \/ (y > z /\ x < S y)
500 --> y > z /\ (x < y \/ x < S y). 545 --> y > z /\ (x < y \/ x < S y).
501 my_tauto. 546 my_tauto.
502 Qed. 547 Qed.
503 548
504 Print mt3. 549 Print mt3.
550 (** [[
551
552 fun x y z : nat =>
553 partialOut
554 (my_tauto
555 (Node_vm (x < S y) (Node_vm (x < y) (Empty_vm Prop) (Empty_vm Prop))
556 (Node_vm (y > z) (Empty_vm Prop) (Empty_vm Prop)))
557 (Imp
558 (Or (And (Atomic (Left_idx End_idx)) (Atomic (Right_idx End_idx)))
559 (And (Atomic (Right_idx End_idx)) (Atomic End_idx)))
560 (And (Atomic (Right_idx End_idx))
561 (Or (Atomic (Left_idx End_idx)) (Atomic End_idx)))))
562 : forall x y z : nat,
563 x < y /\ y > z \/ y > z /\ x < S y --> y > z /\ (x < y \/ x < S y)
564 ]]
565
566 Our goal contained three distinct atomic formulas, and we see that a three-element [varmap] is generated.
567
568 It can be interesting to observe differences between the level of repetition in proof terms generated by [my_tauto] and [tauto] for especially trivial theorems. *)
505 569
506 Theorem mt4 : True /\ True /\ True /\ True /\ True /\ True /\ False --> False. 570 Theorem mt4 : True /\ True /\ True /\ True /\ True /\ True /\ False --> False.
507 my_tauto. 571 my_tauto.
508 Qed. 572 Qed.
509 573
510 Print mt4. 574 Print mt4.
575 (** [[
576
577 mt4 =
578 partialOut
579 (my_tauto (Empty_vm Prop)
580 (Imp
581 (And Truth
582 (And Truth
583 (And Truth (And Truth (And Truth (And Truth Falsehood))))))
584 Falsehood))
585 : True /\ True /\ True /\ True /\ True /\ True /\ False --> False
586 ]] *)
511 587
512 Theorem mt4' : True /\ True /\ True /\ True /\ True /\ True /\ False -> False. 588 Theorem mt4' : True /\ True /\ True /\ True /\ True /\ True /\ False -> False.
513 tauto. 589 tauto.
514 Qed. 590 Qed.
515 591
516 Print mt4'. 592 Print mt4'.
593 (** [[
594
595 mt4' =
596 fun H : True /\ True /\ True /\ True /\ True /\ True /\ False =>
597 and_ind
598 (fun (_ : True) (H1 : True /\ True /\ True /\ True /\ True /\ False) =>
599 and_ind
600 (fun (_ : True) (H3 : True /\ True /\ True /\ True /\ False) =>
601 and_ind
602 (fun (_ : True) (H5 : True /\ True /\ True /\ False) =>
603 and_ind
604 (fun (_ : True) (H7 : True /\ True /\ False) =>
605 and_ind
606 (fun (_ : True) (H9 : True /\ False) =>
607 and_ind (fun (_ : True) (H11 : False) => False_ind False H11)
608 H9) H7) H5) H3) H1) H
609 : True /\ True /\ True /\ True /\ True /\ True /\ False -> False
610 ]] *)
611