How to proof an instantiated subgoal? - isabelle

In the subgoal of the proof, the premise uses variable modified by a universal quantifier, and the conclusion instantiates the universal quantifier to a concrete value. What strategies can be used for such proofs?
[enter image description here][1][enter image description here][2]
The following two examples:
the first example,in the conclusion variable i is replaced by 1;
Second example,In the conclusion the variable i is replaced by i +1 and j is replaced by 2.
⋀m s a i j r k t.
((i = j ∧ m ! i ! j = 0 ∨
i < j ∧ m ! i ! j = Min (⋃k∈{i..<j}. {m ! i ! k + m ! (k + 1) ! j + a ! (i - 1) * a ! i
a ! j})) ∧
1 ≤ r ∧ r < length m ∧ 1 ≤ i ∧ i < length m - r + 1 ∧ j = i + r - 1) ∧
r ≤ length m - 1 ⟹
1 = j ∧ m ! 1 ! j = 0 ∨
1 < j ∧ m ! 1 ! j = Min (⋃k∈{1..<j}. {m ! 1 ! k + m ! (k + 1) ! j + a ! (1 - 1) * a ! 1 *
a ! j})
⋀L A B i j.
((A ! (i - 1) = B ! (j - 1) ∧ L ! (i - 1) ! (j - 1) = L ! (i - 2) ! (j - 2) + 1 ∨
A ! (i - 1) ≠ B ! (j - 1) ∧ L ! (i - 1) ! (j - 1) = max (L ! (i - 1) ! (j - 2)) (L ! (i
! (j - 1)))
∧2 ≤ i
∧i < length L
∧2 ≤ j ∧ j ≤ length (L ! (i - 1)) ∧ (∀k<length L. length (L ! k) = length (L ! (k - 1))
∧ 2 ≤ length (L ! k)))
∧ ¬ j ≤ length (L ! i) - 1 ⟹
A ! (i + 1 - 1) = B ! (2 - 1) ∧ L ! (i + 1 - 1) ! (2 - 1) = L ! (i + 1 - 2) ! (2 - 2) + 1
∨
A ! (i + 1 - 1) ≠ B ! (2 - 1) ∧
L ! (i + 1 - 1) ! (2 - 1) = max (L ! (i + 1 - 1) ! (2 - 2)) (L ! (i + 1 - 2) ! (2 - 1))

Related

Modular arithmetic proofs in agda

I'm trying to prove (n : ℕ) → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥. Typically I would prove this by rewriting it in terms of congruence, and then splitting on each case. There doesn't seem to be a modular arithmetic module in agda-stdlib. How should I implement modular arithmetic or approach this kind of problem without modular arithmetic?
Edit: there has been discussion in the comments that is not quite precise enough to lead me to an answer, so in the hopes of clarifying what cannot fit in the word count I am dumping my various attempts at this problem, some of which inspired by things in the comments.
open Data.Nat.Divisibility.Core
open Data.Nat.Base
open Relation.Binary.Core
open Level using (0ℓ)
open Relation.Binary.PropositionalEquality
open Data.Empty
open Relation.Nullary
open Data.Product using (Σ; _,_; ∃; Σ-syntax; ∃-syntax)
open Relation.Binary.PropositionalEquality.≡-Reasoning
open Data.Nat.Solver
open +-*-Solver
data Z/3 : (n : ℕ) → Set where
Z/3₀ : (n : ℕ) → ∃[ m ] n ≡ 3 * m → Z/3 n
Z/3₁ : (n : ℕ) → ∃[ m ] n ≡ 3 * m + 1 → Z/3 n
Z/3₂ : (n : ℕ) → ∃[ m ] n ≡ 3 * m + 2 → Z/3 n
data _≋_ : Rel ℕ 0ℓ where
3∣|a-b| : ∀ {a b : ℕ} → 3 ∣ ∣ a - b ∣ → a ≋ b
q' : {a : ℕ} → (2 ≋ ((a + 3) * (a + 3))) → (∃[ a' ] 2 ≋ (a' * a'))
q' = {!!}
qq : (n : ℕ) → Z/3 (n * n)
qq zero = Z/3₀ zero (zero , refl)
qq (suc zero) = Z/3₁ 1 (zero , refl)
qq (suc (suc zero)) = Z/3₁ 4 (1 , refl)
qq (suc (suc (suc n))) = Z/3₁ ((3 + n) * (3 + n)) ({!!} , {!!})
q'' : (n : ℕ) → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥
q'' zero (zero , ())
q'' zero (suc fst , ())
q'' (suc zero) (suc zero , ())
q'' (suc zero) (suc (suc fst) , ())
q'' (suc (suc zero)) (suc (suc (suc (suc zero))) , ())
q'' (suc (suc zero)) (suc (suc (suc (suc (suc fst)))) , ())
q'' (suc (suc (suc n))) (suc fst , snd) = q'' n ({!!} , {!!})
sq : {a : ℕ} → Z/3 a → Z/3 (a * a)
sq (Z/3₀ n (m , p)) = Z/3₀ (n * n) (3 * m * m , q) where
q =
begin
n * n
≡⟨ cong (λ e → e * n) p ⟩
(3 * m) * n
≡⟨ cong (λ e → (3 * m) * e) p ⟩
(3 * m) * (3 * m)
≡⟨ solve 1 (λ m' → (con 3 :* m') :* (con 3 :* m') := con 3 :* m' :* m' :+ (con 3 :* m' :* m' :+ (con 3 :* m' :* m' :+ con zero))) refl m ⟩
3 * m * m + (3 * m * m + (3 * m * m + zero))
∎
-- (3 * b + 1) * (3 * b + 1)
-- 9b^2 + 6b + 1
-- 3(3b^2 + 2b) +1
-- (3 * b + 2) * (3 * b + 2)
-- 9b^2 + 12b + 4
-- 3(3b^2+4b+1) + 1
sq (Z/3₁ n (m , p)) = Z/3₁ (n * n) (3 * m * m + 2 * m , q) where
q =
begin
n * n
≡⟨ cong (λ e → e * n) p ⟩
(3 * m + 1) * n
≡⟨ cong (λ e → (3 * m + 1) * e) p ⟩
(3 * m + 1) * (3 * m + 1)
≡⟨ solve 1 (λ m' → (con 3 :* m' :+ con 1) :* (con 3 :* m' :+ con 1) := (m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ ((m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ ((m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ con 0)) :+ con 1 ) refl m ⟩
(m + (m + (m + 0))) * m + (m + (m + 0)) + ((m + (m + (m + 0))) * m + (m + (m + 0)) + ((m + (m + (m + 0))) * m + (m + (m + 0)) + 0)) + 1
∎
sq (Z/3₂ n (m , p)) = Z/3₁ (n * n) (3 * m * m + 4 * m + 1 , {!!})
q : {a : ℕ} → ¬(2 ≋ (a * a))
q {zero} (3∣|a-b| (divides zero ()))
q {zero} (3∣|a-b| (divides (suc quotient) ()))
q {suc zero} (3∣|a-b| (divides zero ()))
q {suc zero} (3∣|a-b| (divides (suc quotient) ()))
q {suc (suc zero)} (3∣|a-b| (divides zero ()))
q {suc (suc zero)} (3∣|a-b| (divides (suc quotient) ()))
q {suc (suc (suc a))} (3∣|a-b| (divides (suc quotient) equality)) = {!!}
Building on Mark's proof outline:
module SOMod where
open import Data.Empty
open import Data.Nat
open import Data.Nat.Properties
open import Data.Nat.DivMod
open import Data.Product
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary.Negation
open ≡-Reasoning
lemma : ∀ m n → (n * n) % 3 ≢ (3 * m + 2) % 3
lemma m n p = contradiction ≡2 (≢2 n)
where
≡2 : ((n % 3) * (n % 3)) % 3 ≡ 2
≡2 = begin
((n % 3) * (n % 3)) % 3 ≡˘⟨ %-distribˡ-* n n 3 ⟩
(n * n) % 3 ≡⟨ p ⟩
(3 * m + 2) % 3 ≡⟨ cong (_% 3) (+-comm (3 * m) 2) ⟩
(2 + 3 * m) % 3 ≡⟨ cong (λ # → (2 + #) % 3) (*-comm 3 m) ⟩
(2 + m * 3) % 3 ≡⟨ [m+kn]%n≡m%n 2 m 3 ⟩
2 % 3 ≡⟨⟩
2 ∎
≢2 : ∀ n → ((n % 3) * (n % 3)) % 3 ≢ 2
≢2 zero = λ ()
≢2 (suc zero) = λ ()
≢2 (suc (suc zero)) = λ ()
≢2 (suc (suc (suc n))) = ≢2 n
proof : ∀ n → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥
proof n (m , p) = contradiction (cong (_% 3) p) (lemma m n)

How to make Isabelle use basic math rules?

I'm trying to learn Isabelle:
theory test
imports Main
begin
datatype tree = Leaf | Node tree tree
fun nodes :: "tree ⇒ nat" where
"nodes Leaf = 1"|
"nodes (Node x y) = 1 + (nodes x) + (nodes y)"
fun explode :: "nat ⇒ tree ⇒ tree" where
"explode 0 t = t" |
"explode (Suc n) t = explode n (Node t t)"
theorem tree_count: "nodes (explode h l) = 2^h + 2^h * (nodes l) - 1"
apply(induction h arbitrary: l)
apply(auto simp add: numeral_eq_Suc)
done
end
However, the theorem is not solved:
Failed to finish proof:
goal (1 subgoal):
1. ⋀h l. (⋀l. nodes (explode h l) = Suc (Suc 0) ^ h + Suc (Suc 0) ^ h * nodes l - Suc 0) ⟹
Suc (Suc 0) ^ h + (Suc (Suc 0) ^ h + Suc (Suc 0) ^ h * (nodes l + nodes l)) - Suc 0 =
Suc (Suc 0) ^ h + Suc (Suc 0) ^ h + (Suc (Suc 0) ^ h + Suc (Suc 0) ^ h) * nodes l - Suc 0
If I'm not mistaken, Isabelle is just not applying x + x = 2*x and a + (b + c) = a + b + c. So I tried adding a lemma to use it with simp:
lemma a: "(x:nat) + x = 2*x"
But this fails with
Type unification failed: Clash of types "_ ⇒ _" and "_ set"
Type error in application: incompatible operand type
Operator: (∈) x :: ??'a set ⇒ bool
Operand: nat :: int ⇒ nat
I assume that it's just not possible to define the type of a variable in a lemma?
Now I could of course redifine the addition - but I guess that's not really best practice.
What would be the best way to solve the initial problem?
Some general approaches to find the right lemmas:
Use the theorem search, either via the query panel or in the text with find_theorems:
find_theorems ‹_ * (_ + _)›
find_theorems name: assoc "_ + _ + _"
find_theorems ‹2 * ?z = ?z + ?z›
Use sledgehammer.
Try the algebra_simps collection as suggested by waldelb (There are also ac_simps, algebra_split_simps, field_simps, and field_split_simps ).
Try to split it up into smaller steps. This helps the simp tool, because simplification can work on both sides of the equation and because you can guide it to the right intermediate steps. The example below is a bit too extreme, doing only one rewrite per step. In general, you can just add intermediary steps where the automatic ones fail.
theorem tree_count: ‹nodes (explode h l) = 2^h + 2^h * (nodes l) - 1›
proof (induction h arbitrary: l)
case 0
show ‹nodes (explode 0 l) = 2 ^ 0 + 2 ^ 0 * nodes l - 1›
by simp
next
case (Suc h)
have ‹nodes (explode (Suc h) l)
= nodes (explode h (Node l l))›
by (subst explode.simps, rule refl)
also have "... = 2 ^ h + 2 ^ h * nodes (Node l l) - 1"
by (subst Suc, rule refl)
also have "... = 2 ^ h + 2 ^ h * (1 + nodes l + nodes l) - 1"
by (subst nodes.simps, rule refl)
also have "... = 2 ^ h + 2 ^ h * (1 + (nodes l + nodes l)) - 1"
by (subst add.assoc, rule refl)
also have "... = 2 ^ h + 2 ^ h * (1 + (2 * nodes l)) - 1"
by (subst mult_2, rule refl)
also have "... = 2 ^ h + (2 ^ h * 1 + 2 ^ h * (2 * nodes l)) - 1"
by (subst distrib_left, rule refl)
also have "... = 2 ^ h + (2 ^ h * 1 + 2 ^ h * 2 * nodes l) - 1"
by (subst mult.assoc, rule refl)
also have "... = 2 ^ h + (2 ^ h * 1 + 2 ^ Suc h * nodes l) - 1"
by (subst power_Suc2, rule refl)
also have "... = (2 ^ h + 2 ^ h * 1) + 2 ^ Suc h * nodes l - 1"
by (subst add.assoc, rule refl)
also have "... = (2 ^ h + 2 ^ h) + 2 ^ Suc h * nodes l - 1"
by (subst mult_1_right, rule refl)
also have "... = 2 ^ h * 2 + 2 ^ Suc h * nodes l - 1"
by (subst mult_2_right, rule refl)
also have "... = 2 ^ Suc h + 2 ^ Suc h * nodes l - 1"
by (subst power_Suc2, rule refl)
finally show ?case .
qed
algebra_simps is a list of common math rules. Adding it solves the problem:
apply(auto simp add: numeral_eq_Suc algebra_simps)

Why is my simproc not activated on the prescribed pattern?

I'm writing a simproc for sine simplifications. Here is an example rewriting sin(x+8pi+pi/2) to cos(x):
lemma rewrite_sine_1:
fixes k' :: int and k :: real
assumes "k ≡ 2 * of_int k'"
shows "sin (x + k*pi + pi/2) ≡ cos (x)"
sorry
ML ‹
fun rewrite_sine ctxt ct =
let
val sum = ct |> Thm.term_of |> dest_comb |> snd
val x = sum |> dest_comb |> fst |> dest_comb |> snd
|> dest_comb |> fst |> dest_comb |> snd
val k = sum |> dest_comb |> fst |> dest_comb |> snd
|> dest_comb |> snd |> dest_comb |> fst
|> dest_comb |> snd |> dest_comb |> snd |> HOLogic.dest_numeral
val rk = SOME (Thm.cterm_of ctxt (HOLogic.mk_number HOLogic.realT k))
val ik2 = SOME (Thm.cterm_of ctxt (HOLogic.mk_number HOLogic.intT (k div 2)))
val cx = SOME( Thm.cterm_of ctxt x)
in
SOME (Thm.instantiate' [] [rk,ik2,cx] #{thm rewrite_sine_1})
end
›
ML ‹
rewrite_sine #{context} #{cterm "sin(x+8*pi+pi/2)"}
›
Up to here everything works but once I set up my simproc:
simproc_setup sine1 ("sin (x + 8 * pi + pi / 2)") = ‹K rewrite_sine›
(* this should be handled by sine1 only, but is not *)
lemma "sin (x + 8 * pi + pi / 2) = cos(x)"
apply simp
sorry
(* this should be handled by sine1 only, but is not *)
lemma "sin(x+8*pi+pi/2) = cos(x)"
apply(tactic ‹simp_tac (put_simpset HOL_basic_ss #{context} addsimprocs [#{simproc sine1}]) 1›)
sorry
I see that it is not really applying even with a basic simpset. Others simprocs is set-up did work, see here.
In the first example, your simproc is not called becaus simprocs (if I remember correctly) are only called after exhausting all ‘normal’ rewriting, and your goal is immediately rewritten to sin (17 * pi / 2 + x) = cos x. Since your simproc does not match that goal anymore, it is not called.
In the second example, your simproc is called (you can verify this by inserting e.g. a val _ = #{print} "foo" into your let block) and it indeed produces a rewrite rule. Unfortunately, this rewrite rule still has the precondition 8 ≡ 2 * real_of_int 4, which simp cannot solve with the very basic simplifier setup you are using, so it fails to apply the rule.
You can find out what's going on there using the simplifier trace:
lemma "sin(x+8*pi+pi/2) = cos(x)"
using [[simp_trace, simp_trace_depth_limit = 100]]
apply(tactic ‹simp_tac (put_simpset HOL_basic_ss #{context} addsimprocs [#{simproc sine1}]) 1›)
Output:
[0]Adding simplification procedure "Scratch.sine1" for
sin (?x + 8 * pi + pi / 2)
[0]Adding simplification procedure "Scratch.sine1" for
sin (?x + 8 * pi + pi / 2)
[1]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
sin (x + 8 * pi + pi / 2) = cos x
[1]Procedure "Scratch.sine1" produced rewrite rule:
8 ≡ 2 * real_of_int 4 ⟹
sin (x + 8 * pi + pi / 2) ≡ cos x
[1]Applying instance of rewrite rule
8 ≡ 2 * real_of_int 4 ⟹
sin (x + 8 * pi + pi / 2) ≡ cos x
[1]Trying to rewrite:
8 ≡ 2 * real_of_int 4 ⟹
sin (x + 8 * pi + pi / 2) ≡ cos x
[2]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
8 ≡ 2 * real_of_int 4
[1]FAILED
8 ≡ 2 * real_of_int 4 ⟹
sin (x + 8 * pi + pi / 2) ≡ cos x
[1]IGNORED result of simproc "Scratch.sine1" -- does not match
sin (x + 8 * pi + pi / 2)
If you add the rule 2 * real_of_int 4 ≡ 8 to your simpset, it works as intended.

How to get a big-O, Big-Ω and big-Θ for this function?

I have a function f(n) defined as follows:
f(n) = (n-1)(n+1)lg(n+5)/(n+3)
Here, lg is log2. I'd like to determine the big-O, big-Ω, and big-Θ values for this function. How would I go about approaching this?
Thanks!
Let's start off by simplifying your expression:
f(n) = (n-1)(n+1)lg(n+5)/(n+3)
= ((n2 - 1) lg (n + 5)) / (n + 3)
For now, let's pretend that the additive constants are there. If we delete those constants, we get this function g(n):
g(n) = n2 lg n / n = n lg n
Since we don't expect those constants to make all that much of a difference in the long term, it's reasonable to venture a guess that this function is Θ(n log n). We can prove this by taking the limit of f(n) / n log n as n tends toward infinity. If we get back a nonzero finite value, then we known that f(n) = Θ(n log n).
So let's try it!
limn → ∞ f(n) / n log n
= limn → ∞ (((n2 - 1) lg (n + 5)) / (n + 3)) / n lg n
= limn → ∞ ((n2 - 1) lg (n + 5)) / n lg n (n + 3)
= (limn → ∞ (n2 - 1) / n(n+3)) (limn → ∞ (lg (n + 5) / lg n)
= (limn → ∞ (n2 - 1) / (n2 + n)) (limn → ∞ (lg (n + 5) / lg n)
Both of these limits are degenerate forms of type ∞ / ∞, so we can use l'Hopital's rule and replace each with its derivative:
limn → ∞ (n2 - 1) / (n2 + n)
= limn → ∞ (2n / 2n + 1)
= 1
and
limn → ∞ lg (n + 5) / lg n
= limn → ∞ (1 / (n+5)) / (1 / n)
= limn → ∞ (n / (n+5))
= 1
Therefore, we get
(limn → ∞ (n2 - 1) / (n2 + n)) (limn → ∞ (lg (n + 5) / lg n)
= 1
Consequently, the ratio of f(n) / n lg n tends toward 1 as n goes to infinity, and so we have that f(n) = Θ(n log n), as required. Because of this, we also get that f(n) = O(n log n) and f(n) = Ω(n log n). We also have that f(n) ~ n log n, which is a much stronger claim.
Hope this helps!

How to simplify modulo

I am trying to find the modulo of an expression. All I know is that
(a+b) mod N = ((a mod N) + (b mod N)) mod N
How do I use it to simplify the following modulo operation?
(a - 2*b + 1) mod N
There must be some way to simplify it by considering it as
(a - b - b + 1) mod N ?
EDIT:
I have stumbled upon the following property too:
ab mod N = ((a mod N) (b mod N)) mod N
Will this be helpful somehow?
If: (a+b) mod N = ((a mod N) + (b mod N)) mod N
then:
(a - 2*b + 1) mod N = ((a mod N) - (b mod N) - (b mod N) + (1 mod N)) mod N
It is simpler with large values of a and b and a small value for N.
For example: a=85773, b = 77733340, N=5:
which would you rather solve
(85773 - 77733340 - 77733340 + 1) mod 5
or
((85773 mod 5) - (77733340 mod 5) - (77733340 mod 5) + (1 mod 5)) mod 5
for the second one i get (3 - 0 - 0 + 1) % 5 = 4
There is no way to simplify (b*-2 + a + 1) % n unfortunately.

Resources