14 Sets and functions
■ HOL Lightにおいては,集合は,述語と見做せるよう定義されています.
let IN = new_definition
`!P:A->bool. !x. x IN P <=> P x`;;
■ 集合のconstantには
(typ) (typは:num,:realなどのhol.type)
EMPTY or {}
UNIV
があり,UNIVは
# `x+ &1 IN UNIV`;;
val it : term = `x + &1 IN (:real)`
のように直ちに書き換えられます.
■ 集合についての作用子には
x IN s
s SUBSET t
s PSUBSET t (Is proper subset ?)
s DISJOINT t
SING s (Is singleton ?)s UNION t
s INTER t
s DIFF t
x INSERT s (Insertion of x into s)
s DELETE x (Deletion of x from s)
UNIONS s (Union of all members of s)
INTERS s (Intersection of all members of s)
がありますが,述語,集合の別を設けない点に注意しましょう.
これらの性質もthmになっています.
# SUBSET;;
val it : thm = |- !s t. s SUBSET t <=> (!x. x IN s ==> x IN t)
# NOT_IN_EMPTY;;
val it : thm = |- !x. ~(x IN {})
# IN_INTER;;
val it : thm = |- !s t x. x IN s INTER t <=> x IN s /\ x IN t
# IN_UNION;;
val it : thm = |- !s t x. x IN s UNION t <=> x IN s \/ x IN t
# IN_INSERT;;
val it : thm = |- !x y s. x IN y INSERT s <=> x = y \/ x IN s
# IN_DIFF;;
val it : thm = |- !s t x. x IN s DIFF t <=> x IN s /\ ~(x IN t)
■ 述語 p,関数 f から集合 {x|p(x)} や {f(x)|p(x)} も作れます.
# `{ x | ?n. ODD(n) /\ x = n * n }`;;
val it : term = `{x | ?n. ODD n /\ x = n * n}`
# `{ n * n | ODD(n) }`;;
val it : term = `{n * n | ODD n}`
逆に,e IN {x|p(x)} を p(e) に,また,e IN {f(x)|p(x)} を ?x. p(x) /\ e=f(x) にrewriteするには,IN_ELIM_THM を参照します.
# REWRITE_CONV[IN_ELIM_THM]`e IN {n|ODD(n)}`;;
val it : thm = |- e IN {n | ODD n} <=> ODD e
# REWRITE_CONV[IN_ELIM_THM]`e IN {n*n|ODD(n)}`;;
val it : thm = |- e IN {n * n | ODD n} <=> (?n. ODD n /\ e = n * n)
■ 列挙による集合の表現です.
# `{1,2,3}`;;
val it : term = `{1, 2, 3}`
# `1 INSERT 2 INSERT 3 INSERT EMPTY`;;
val it : term = `{1, 2, 3}`
所謂,外延性の公理
# EXTENSION;;
val it : thm = |- !s t. s = t <=> (!x. x IN s <=> x IN t)
は
# FUN_EQ_THM;;
val it : thm = |- !f g. f = g <=> (!x. f x = g x)
を IN に適用したものです.
let EXTENSION = prove
(`!s t. (s = t) <=> !x:A. x IN s <=> x IN t`,
REWRITE_TAC[IN; FUN_EQ_THM]);;
■ 集合の理論における prover は SET_RULE
# SET_RULE `UNIV DIFF {a} = {x| ~(x=a)}` ;;
Warning: inventing type variables
val it : thm = |- (:?108270) DIFF {a} = {x | ~(x = a)}# SET_RULE `!a:num. UNIV DIFF {a} = {x| ~(x=a)}` ;;
val it : thm = |- !a. (:num) DIFF {a} = {x | ~(x = a)}# SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {y | Q y}`;;
Warning: inventing type variables
val it : thm = |- {x | P x /\ Q x} = {x | P x} INTER {y | Q y}# SET_RULE `a IN s ==> (s = a INSERT (s DELETE a))`;;
Warning: inventing type variables
0..0..solved at 2
0..0..solved at 2
0..0..solved at 2
0..0..solved at 3
val it : thm = |- a IN s ==> s = a INSERT (s DELETE a)# SET_RULE `{2,3,2} ={2,3} INTER UNIV` ;;
0..0..solved at 3
0..0..solved at 2
0..0..solved at 3
0..0..solved at 3
0..0..solved at 2
val it : thm = |- {2, 3, 2} = {2, 3} INTER (:num)
そのtactic版は SET_TAC[] で,仮定を参照させるには,ASM を冠して用います.
g `!a:real b c d X. X={a,b,c} ==> X DIFF {b,d} = X DELETE b` ;;
e ( REPEAT STRIP_TAC ) ;;
e ( ASM SET_TAC[] ) ;;
これらは集合論の基本的な同値性を検証した上で,MESON[] を呼んでいます.なお,集合のhol.typeは述語と同じく,:bool値の関数です.
# type_of `{1}` ;;
val it : hol_type = `:num->bool`# SET_RULE `!s:A->bool t. s UNION t = s UNION (t DIFF s)` ;;
0..0..solved at 3
0..0..solved at 2
0..0..solved at 2
0..0..solved at 2
0..0..solved at 3
0..0..solved at 3
val it : thm = |- !s t. s UNION t = s UNION t DIFF s
■ DIFF に関して,例えば
# prove( `{1,2} DIFF {2} = {1}` , SET_TAC );;
0..0..solved at 3
0..0..solved at 2
0..0..solved at 3
0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0.
.0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..Excepti
on: Failure "solve_goal: Too deep".# prove( `{1,2} DIFF {2,3} = {1}` , SET_TAC );;
0..0..solved at 4
0..0..solved at 3
0..0..solved at 3
0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0.
.0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..0..Excepti
on: Failure "solve_goal: Too deep".
のようになります.これは,SET_TACやMESONが1,2,3が異なることを知らない為なので,ARITHを参照させると
# prove( `{1,2} DIFF {2} = {1}` , SET_TAC[ARITH] );;
0..0..solved at 3
0..0..solved at 2
0..0..solved at 3
0..0..15..solved at 28
val it : thm = |- {1, 2} DIFF {2} = {1}
# prove( `{1,2} DIFF {2,3} = {1}` , SET_TAC[ARITH] );;
0..0..solved at 4
0..0..solved at 3
0..0..solved at 3
0..0..15..solved at 28
0..0..15..93..solved at 249
val it : thm = |- {1, 2} DIFF {2, 3} = {1}
となり,変数の場合には
# prove( `!a b c. ~a=c /\ ~a=b ==> {a} = {a,b} DIFF {b,c}` , SET_TAC[] );;
val it : thm =
|- !a b c. (~a <=> c) /\ (~a <=> b) ==> {a} = {a, b} DIFF {b, c}
のような注意が必要です.
■ 簡単な証明ですが,SET_TAC[ARITH] では無理なようです.
# let set12 = `{n|n=1 \/ n=2}={n|0
しかし,rewrite方法を指定すると
# g set12;;
val it : goalstack = 1 subgoal (1 total)`{n | n = 1 \/ n = 2} = {n | 0 < n /\ n < 3}`
# e ( REWRITE_TAC[EXTENSION;IN_ELIM_THM] );;
val it : goalstack = 1 subgoal (1 total)`!x. x = 1 \/ x = 2 <=> 0 < x /\ x < 3`
# e( ARITH_TAC );;
val it : goalstack = No subgoals
となります.勿論,述語を書き換えてしまえば,直ちに
# prove( set12 , REWRITE_TAC[ARITH_RULE`n=1 \/ n=2 <=> 0
となります.
■ より簡単な例ですが
# prove( `0 IN (:num)` , SET_TAC[] );;
val it : thm = |- 0 IN (:num)
は良くても
# prove( `(:num)0` , SET_TAC[IN] );;
0..0..1..2..3..4..5..6..7..8..9..10..11..12..13..14..15..16..17..18..19..20..21.
.22..23..24..25..26..27..28..29..30..31..32..33..34..35..36..37..38..39..40..41.
.42..43..44..45..46..47..48..49..Exception: Failure "solve_goal: Too deep".
は無理で
# prove( `(:num)0` , ONCE_REWRITE_TAC[GSYM(IN)] THEN SET_TAC[] );;
val it : thm = |- (:num) 0
のような前処理が必要です.