11.1 Irrationality of Sqrt[2]

 今回は

# g( `!p q. p*p=2*q*q ==> q=0` );;
val it : goalstack = 1 subgoal (1 total)

`!p q. p * p = 2 * q * q ==> q = 0`

をpについての wellfounded induction で証明します.方針は,p*p=2*q*qならばpは偶数,p=2r従って2*r*r=q*qと表せて仮定が使える,というものですが,一つ注意があります.それは,例えばp>0のときp*p=2*q*qからq=0が導けるのか?と言う点です.勿論導けませんが,それどころか以下の証明を見れば判るようにp*p=2*q*qからp=0が導けてしまうのです.つまり,今回のwellfounded inductionの利用は,積み上げが目的ではなく,p>0では不合理であることを示すためなのです.

# e ( MATCH_MP_TAC num_WF );;
val it : goalstack = 1 subgoal (1 total)

`!p. (!m. m < p ==> (!q. m * m = 2 * q * q ==> q = 0))
==> (!q. p * p = 2 * q * q ==> q = 0)`

 まず

# RIGHT_IMP_FORALL_THM;;
val it : thm = |- !P Q. P ==> (!x. Q x) <=> (!x. P ==> Q x)

により,全称記号を左にまとめておきます.冠頭標準形prenex normal formla までは必要ありませんが,これをやらないと,後で!m q.に対するSPECLの置換先が見つからないと叱られます.

# e ( REWRITE_TAC[RIGHT_IMP_FORALL_THM] );;
val it : goalstack = 1 subgoal (1 total)

`!p q.
(!m q. m < p ==> m * m = 2 * q * q ==> q = 0)
==> p * p = 2 * q * q
==> q = 0`

# e( REPEAT STRIP_TAC );;
val it : goalstack = 1 subgoal (1 total)

0 [`!m q. m < p ==> m * m = 2 * q * q ==> q = 0`]
1 [`p * p = 2 * q * q`]

`q = 0`

 では,仮定1からpが偶数であることを導きましょう.それには,FIRST_ASSUM により,仮定のうち,その辺々を

# EVEN;;
val it : thm = |- (EVEN 0 <=> T) /\ (!n. EVEN (SUC n) <=> ~EVEN n)

で定まるEVEN:num->boolで評価できる最初のもの,つまり,仮定1の辺々に AP_TERM `EVEN` として EVEN を結合させて,MP_TAC で結論の implies の前件に据えます.

# e( FIRST_ASSUM( MP_TAC o AP_TERM `EVEN` ) );;
val it : goalstack = 1 subgoal (1 total)

0 [`!m q. m < p ==> m * m = 2 * q * q ==> q = 0`]
1 [`p * p = 2 * q * q`]

`(EVEN (p * p) <=> EVEN (2 * q * q)) ==> q = 0`

 この前件を

# EVEN_MULT;;
val it : thm = |- !m n. EVEN (m * n) <=> EVEN m \/ EVEN n

および,ARITHを参照してREWRITEすると

# e( REWRITE_TAC[EVEN_MULT;ARITH] );;
val it : goalstack = 1 subgoal (1 total)

0 [`!m q. m < p ==> m * m = 2 * q * q ==> q = 0`]
1 [`p * p = 2 * q * q`]

`EVEN p ==> q = 0`

となるので,具体化する為

# EVEN_EXISTS;;
val it : thm = |- !n. EVEN n <=> (?m. n = 2 * m)

を続けて参照すると

# e( REWRITE_TAC[EVEN_EXISTS] );;
val it : goalstack = 1 subgoal (1 total)

0 [`!m q. m < p ==> m * m = 2 * q * q ==> q = 0`]
1 [`p * p = 2 * q * q`]

`(?m. p = 2 * m) ==> q = 0`

となり,前件のmとしてr:numを復元して,全ての p を 2*r に置き換えます.なお,SUBST_ALL_TAC(: thm -> tactic = )は仮定,結論の全ての出現を置換し,SUBST1_ALL_TACは結論の全ての出現を置換します.

# e ( DISCH_THEN( X_CHOOSE_THEN `r:num` SUBST_ALL_TAC ) );;
val it : goalstack = 1 subgoal (1 total)

0 [`!m q. m < 2 * r ==> m * m = 2 * q * q ==> q = 0`]
1 [`(2 * r) * 2 * r = 2 * q * q`]

`q = 0`

 後は,仮定0のm,qをそれぞれq,rとSPECLしたもので結論を導けば,全称の仮定からも導けるので十分です.仮定0は再利用しませんので,FIRST_X_ASSUMで取り出します.

# e( FIRST_X_ASSUM( MP_TAC o SPECL[`q:num`;`r:num`] ) );;
val it : goalstack = 1 subgoal (1 total)

0 [`(2 * r) * 2 * r = 2 * q * q`]

`(q < 2 * r ==> q * q = 2 * r * r ==> r = 0) ==> q = 0`

この仮定0があればq * q = 2 * r * rは不要です.実際

# e( ONCE_REWRITE_TAC[ARITH_RULE`q*q=2*r*r<=>(2*r)*(2*r)=2*q*q`] THEN ASM_SIMP_TAC[] );;
val it : goalstack = 1 subgoal (1 total)

0 [`(2 * r) * 2 * r = 2 * q * q`]

`(q < 2 * r ==> r = 0) ==> q = 0`

得られた前件は~(q<2*r)\/ r=0つまり2*r<=q\/r=0となりますが,r=0==>2*r<=qなので

# e( REWRITE_TAC[ARITH_RULE`(q < 2 * r ==> r = 0) <=> 2*r<=q`] );;
val it : goalstack = 1 subgoal (1 total)

0 [`(2 * r) * 2 * r = 2 * q * q`]

`2 * r <= q ==> q = 0`

にまとめられます.実は,この前件の形を見越して,仮定0を書き換えなかったわけで,この前件と

# LE_MULT2;;
val it : thm = |- !m n p q. m <= n /\ p <= q ==> m * p <= n * q

により(2 * r) * 2 * r <= q * q,仮定0を用いて 2 * q * q <= q * q,ARITH_RULE で導ける |- 2*x<=x <=> x=0 を参照して q * q =0,最後に

# MULT_EQ_0;;
val it : thm = |- !m n. m * n = 0 <=> m = 0 \/ n = 0

によりq=0となります.

# e( ASM_MESON_TAC[LE_MULT2;ARITH_RULE`2*x<=x <=> x=0`;MULT_EQ_0] );;
0..0..1..3..9..22..48..204..698..2758..solved at 8153
val it : goalstack = No subgoals

 以上をまとめると

prove( `!p q. p*p=2*q*q==>q=0` ,
MATCH_MP_TAC num_WF THEN
REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
REPEAT STRIP_TAC THEN
FIRST_ASSUM( MP_TAC o AP_TERM `EVEN` ) THEN
REWRITE_TAC[EVEN_MULT;ARITH;EVEN_EXISTS] THEN
DISCH_THEN( X_CHOOSE_THEN `r:num` SUBST_ALL_TAC ) THEN
FIRST_X_ASSUM( MP_TAC o SPECL[`q:num`;`r:num`] ) THEN
ONCE_REWRITE_TAC[ARITH_RULE`q*q=2*r*r<=>(2*r)*(2*r)=2*q*q`] THEN
ASM_SIMP_TAC[] THEN
REWRITE_TAC[ARITH_RULE`(q<2*r==>r=0)<=>2*r<=q`] THEN
ASM_MESON_TAC[LE_MULT2;ARITH_RULE`2*x<=x<=>x=0`;MULT_EQ_0] );;

となりますが

 ONCE_REWRITE_TAC[ARITH_RULE`q*q=2*r*r<=>(2*r)*(2*r)=2*q*q`] THEN
 ASM_SIMP_TAC[] THEN
 REWRITE_TAC[ARITH_RULE`(q<2*r==>r=0)<=>2*r<=q`] THEN

の部分をARITH_RULEに任せて

 ASM_SIMP_TAC
 [ARITH_RULE
  `((q < 2 * r ==> q * q = 2 * r * r ==> r = 0))
    <=>((2 * r) * 2 * r = 2 * q * q ==> 2 * r <= q)`] THEN

とすることも,また,sos.mlをロードすれば

# prove( `!p q. p*p=2*q*q==>q=0` ,
MATCH_MP_TAC num_WF THEN
REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
REPEAT STRIP_TAC THEN
FIRST_ASSUM( MP_TAC o AP_TERM `EVEN` ) THEN
REWRITE_TAC[EVEN_MULT;ARITH;EVEN_EXISTS] THEN
DISCH_THEN( X_CHOOSE_THEN `r:num` SUBST_ALL_TAC ) THEN
FIRST_X_ASSUM( MP_TAC o SPECL[`q:num`;`r:num`] ) THEN
FIRST_X_ASSUM( MP_TAC ) THEN
CONV_TAC( SOS_RULE ) );;
Searching with depth limit 0
Searching with depth limit 1
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Searching with depth limit 2
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Searching with depth limit 2
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Searching with depth limit 2
Translating proof certificate to HOL
Searching with depth limit 0
Searching with depth limit 1
Searching with depth limit 2
Translating proof certificate to HOL
val it : thm = |- !p q. p * p = 2 * q * q ==> q = 0

ともできます.