How to write bigvee and big wedge in Isabelle - set

I'm trying to use Isabelle to do auto-prove. However, I got a problem of specifying formulas in Isabelle. For example, I have a formulas like this
Then, I define sets and use big_wedge and big_vee symbols in Isabelle as follows:
And the result is "Inner lexical error⌂ Failed to parse prop".
Could you explain what is wrong here, please?
Thank you very much.

Not all symbols shown in Isabelle/jEdit's Symbol tabs have a meaning. These are the symbols you can use in your code.
Based on the corresponding code for sums, I started the setup, but I did not finish it (in particular, the syntax ⋀t!=l. P t is not supported).
context comm_monoid_add
begin
sublocale bigvee: comm_monoid_set HOL.disj False
defines bigvee = bigvee.F and bigvee' = bigvee.G
by standard auto
abbreviation bigvee'' :: ‹bool set ⇒ bool› ("⋁")
where "⋁ ≡ bigvee (λx. x)"
sublocale bigwedge: comm_monoid_set HOL.conj True
defines bigwedge = bigwedge.F and bigwedge' = bigwedge.G
by standard auto
abbreviation bigwedge'' :: ‹bool set ⇒ bool› ("⋀")
where "⋀ ≡ bigwedge (λx. x)"
end
syntax
"_bigwedge" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b::comm_monoid_add" ("(2⋀(_/∈_)./ _)" [0, 51, 10] 10)
translations ― ‹Beware of argument permutation!›
"⋀i∈A. b" ⇌ "CONST bigwedge (λi. b) A"
syntax
"_bigvee" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b::comm_monoid_add" ("(2⋁(_/∈_)./ _)" [0, 51, 10] 10)
translations ― ‹Beware of argument permutation!›
"⋁i∈A. b" ⇌ "CONST bigvee (λi. b) A"
instantiation bool :: comm_monoid_add
begin
definition zero_bool where
[simp]: ‹zero_bool = False›
definition plus_bool where
[simp]: ‹plus_bool = (∨)›
instance
by standard auto
end
thm bigvee_def
lemma ‹finite A ⟹ (⋁i∈A. f i) ⟷ (∃i ∈ A. f i)›
apply (induction rule: finite_induct)
apply (auto simp: )
done
lemma ‹finite A ⟹ (⋀i∈A. f i) ⟷ A = {} ∨ (∀i ∈ A. f i)›
apply (induction rule: finite_induct)
apply (auto simp: )[2]
done
lemma ‹infinite A ⟹ (⋀i∈A. f i) ⟷ True›
by auto
lemma test1:
‹(⋀j∈L. ⋀u∈U. ⋀t∈T. ⋀l∈L. ⋀l⇩1∈L⇩1. ¬P j u t l⇩1) ∨
(⋁i∈I. ⋁v∈V. ⋀k∈K. ⋁h∈H. Q i ∨ k h) ⟹
(⋁i∈I. ⋁v∈V. ⋀k∈K. ⋁h∈H. Q i ∨ k h) ∨ (⋀j∈J. ⋀u∈U. ⋀t∈T. ⋀l⇩1∈L⇩1. ¬P j u t l⇩1)›
apply auto
The full setup is possible. But I am not certain that this is a good idea... You will need a lot of lemmas to make things work nicely and I am not certain the behaviour for infinite sets is the right one.

Related

How do you use the Ring solver in Cubical Agda?

I have started playing around with Cubical Agda. Last thing I tried doing was building the type of integers (assuming the type of naturals is already defined) in a way similar to how it is done in classical mathematics (see the construction of integers on wikipedia). This is
data dInt : Set where
_⊝_ : ℕ → ℕ → dInt
canc : ∀ a b c d → a + d ≡ b + c → a ⊝ b ≡ c ⊝ d
trunc : isSet (dInt)
After doing that, I wanted to define addition
_++_ : dInt → dInt → dInt
(x ⊝ z) ++ (u ⊝ v) = (x + u) ⊝ (z + v)
(x ⊝ z) ++ canc a b c d u i = canc (x + a) (z + b) (x + c) (z + d) {! !} i
...
I am now stuck on the part between the two braces. A term of type x + a + (z + d) ≡ z + b + (x + c) is asked. Not wanting to prove this by hand, I wanted to use the ring solver made in Cubical Agda. But I could never manage to make it work, even trying to set it up for simple ring equalities like x + x + x ≡ 3 * x.
How can I make it work ? Is there a minimal example to make it work for naturals ? There is a file NatExamples.agda in the library, but it makes you have to rewrite your equalities in a convoluted way.
You can see how the solver for natural numbers is supposed to be used in this file in the cubical library:
Cubical/Tactics/NatSolver/Examples.agda
Note that this solver is different from the solver for commutative rings, which is designed for proving equations in abstract rings and is explained here:
Cubical/Tactics/CommRingSolver/Examples.agda
However, if I read your problem correctly, the equality you want to prove requires the use of other propositional equalities in Nat. This is not supported by any solver in the cubical library (as far as I know, also the standard library doesn't support it). But of course, you can use the solver for all the steps that don't use other equalities.
Just in case you didn't spot this: here is a definition of the integers in math-style using the SetQuotients of the cubical library. SetQuotients help you to avoid the work related to your third constructor trunc. This means you basically just need to show some constructions are well defined as you would in 'normal' math.
I've successfully used the ring solver for exactly the same problem: defining Int as a quotient of ℕ ⨯ ℕ. You can find the complete file here, the relevant parts are the following:
Non-cubical propositional equality to path equality:
open import Cubical.Core.Prelude renaming (_+_ to _+̂_)
open import Relation.Binary.PropositionalEquality renaming (refl to prefl; _≡_ to _=̂_) using ()
fromPropEq : ∀ {ℓ A} {x y : A} → _=̂_ {ℓ} {A} x y → x ≡ y
fromPropEq prefl = refl
An example of using the ring solver:
open import Function using (_$_)
import Data.Nat.Solver
open Data.Nat.Solver.+-*-Solver
using (prove; solve; _:=_; con; var; _:+_; _:*_; :-_; _:-_)
reorder : ∀ x y a b → (x +̂ a) +̂ (y +̂ b) ≡ (x +̂ y) +̂ (a +̂ b)
reorder x y a b = fromPropEq $ solve 4 (λ x y a b → (x :+ a) :+ (y :+ b) := (x :+ y) :+ (a :+ b)) prefl x y a b
So here, even though the ring solver gives us a proof of _=̂_, we can use _=̂_'s K and _≡_'s reflexivity to turn that into a path equality which can be used further downstream to e.g. prove that Int addition is representative-invariant.

How can I subtract a multiset from a set with a given multiset?

So I'm trying to define a function apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset"
It takes in a function C that may convert an 'a multiset into a single element of type 'a. Here we assume that each element in the domain of C is pairwise mutually exclusive and not the empty multiset (I already have another function that checks these things). apply will also take another multiset inp. What I'd like the function to do is check if there is at least one element in the domain of C that is completely contained in inp. If this is the case, then perform a set difference inp - s where s is the element in the domain of C and add the element the (C s) into this resulting multiset. Afterwards, keep running the function until there are no more elements in the domain of C that are completely contained in the given inp multiset.
What I tried was the following:
fun apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset" where
"apply_C C inp = (if ∃s ∈ (domain C). s ⊆# inp then apply_C C (add_mset (the (C s)) (inp - s)) else inp)"
However, I get this error:
Variable "s" occurs on right hand side only:
⋀C inp s.
apply_C C inp =
(if ∃s∈domain C. s ⊆# inp
then apply_C C
(add_mset (the (C s)) (inp - s))
else inp)
I have been thinking about this problem for days now, and I haven't been able to find a way to implement this functionality in Isabelle. Could I please have some help?
After thinking more about it, I don't believe there is a simple solutions for that Isabelle.
Do you need that?
I have not said why you want that. Maybe you can reduce your assumptions? Do you really need a function to calculate the result?
How to express the definition?
I would use an inductive predicate that express one step of rewriting and prove that the solution is unique. Something along:
context
fixes C :: ‹'a multiset ⇒ 'a option›
begin
inductive apply_CI where
‹apply_CI (M + M') (add_mset (the (C M)) M')›
if ‹M ∈ dom C›
context
assumes
distinct: ‹⋀a b. a ∈ dom C ⟹ b ∈ dom C ⟹ a ≠ b ⟹ a ∩# b = {#}› and
strictly_smaller: ‹⋀a b. a ∈ dom C ⟹ size a > 1›
begin
lemma apply_CI_determ:
assumes
‹apply_CI⇧*⇧* M M⇩1› and
‹apply_CI⇧*⇧* M M⇩2› and
‹⋀M⇩3. ¬apply_CI M⇩1 M⇩3›
‹⋀M⇩3. ¬apply_CI M⇩2 M⇩3›
shows ‹M⇩1 = M⇩2›
sorry
lemma apply_CI_smaller:
‹apply_CI M M' ⟹ size M' ≤ size M›
apply (induction rule: apply_CI.induct)
subgoal for M M'
using strictly_smaller[of M]
by auto
done
lemma wf_apply_CI:
‹wf {(x, y). apply_CI y x}›
(*trivial but very annoying because not enough useful lemmas on wf*)
sorry
end
end
I have no clue how to prove apply_CI_determ (no idea if the conditions I wrote down are sufficient or not), but I did spend much thinking about it.
After that you can define your definitions with:
definition apply_C where
‹apply_C M = (SOME M'. apply_CI⇧*⇧* M M' ∧ (∀M⇩3. ¬apply_CI M' M⇩3))›
and prove the property in your definition.
How to execute it
I don't see how to write an executable function on multisets directly. The problem you face is that one step of apply_C is nondeterministic.
If you can use lists instead of multisets, you get an order on the elements for free and you can use subseqs that gives you all possible subsets. Rewrite using the first element in subseqs that is in the domain of C. Iterate as long as there is any possible rewriting.
Link that to the inductive predicate to prove termination and that it calculates the right thing.
Remark that in general you cannot extract a list out of a multiset, but it is possible to do so in some cases (e.g., if you have a linorder over 'a).

Isabelle/HOL: proof by 'simp' is slow while 'value' is instantaneous

I am new to Isabelle/HOL, still in the study of the prog-prov exercises. In the meantime, I am exercising by applying these proof techniques to questions of combinatorial words. I observe a very different behavior (in terms of efficiency), between 'value' and 'lemma'.
Can one explain the different evaluation/search strategies between the two commands?
Is there a way to have the speed of 'value' used inside a proof of a 'lemma'?
Of course, I am asking because I have not found the answer in the documentation (so far). What is the manual where this difference of efficiency would be documented and explained?
Here is a minimal piece of source to reproduce the problem.
theory SlowLemma
imports Main
begin
(* Alphabet for Motzkin words. *)
datatype alphabet = up | lv | dn
(* Keep the [...] notation for lists. *)
no_notation Cons (infixr "#" 65) and append (infixr "#" 65)
primrec count :: "'a ⇒ 'a list ⇒ nat" where
"count _ Nil = 0" |
"count s (Cons h q) = (if h = s then Suc (count s q) else count s q)"
(* prefix n l simply returns undefined if n > length l. *)
fun prefix :: "'a list ⇒ nat ⇒ 'a list" where
"prefix _ 0 = []" |
"prefix (Cons h q) (Suc n) = Cons h (prefix q n)"
definition M_ex_7 :: "alphabet list" where
"M_ex_7 ≡ [lv, lv, up, up, lv, dn, dn]"
definition M_ex_19 :: "alphabet list" where
"M_ex_19 ≡ [lv, lv, up, up, lv, up, lv, dn, lv, dn, lv, up, dn, dn, lv, up, dn, lv, lv]"
fun height :: "alphabet list ⇒ int" where
"height w = (int (count up w + count up w)) - (int (count dn w + count dn w))"
primrec is_pre_M :: "alphabet list ⇒ nat ⇒ bool" where
"is_pre_M _ (0 :: nat) = True"
| "is_pre_M w (Suc n) = (let w' = prefix w (Suc n) in is_pre_M w' n ∧ height w' ≥ 0)"
fun is_M :: "alphabet list ⇒ bool" where
"is_M w = (is_pre_M w (length w) ∧ height w = 0)"
(* These two calls to value are fast. *)
value "is_M M_ex_7"
value "is_M M_ex_19"
(* This first lemma goes fast. *)
lemma is_M_M_ex_7: "is_M M_ex_7"
by (simp add: M_ex_7_def)
(* This second lemma takes five minutes. *)
lemma is_M_M_ex_19: "is_M M_ex_19"
by (simp add: M_ex_19_def)
end
simp is a proof method that goes through the proof kernel, i.e., every step has to be justified. For long rewriting chains, this may be quite expensive.
On the other hand, value uses the code generator where possible. All used constants are translated into ML code, which is then executed. You have to trust the result, i.e., it didn't go through the kernel and may be wrong.
The equivalent of value as a proof method is eval. Thus, an easy way to speed up your proofs is to use this:
lemma is_M_M_ex_19: "is_M M_ex_19"
by eval
Opinions in the Isabelle community about whether or not this should be used differ. Some say it's similar to axiomatization (because you have to trust it), others consider it a reasonable way if going through the kernel is prohibitively slow. Everyone agrees though that you have to be really careful about custom setup of the code generator (which you haven't done, so it should be fine).
There's middle ground: the code_simp method will set up simp to use only the equations that would otherwise be used by eval. That means: a much smaller set of rules for simp, while still going through the kernel. In your case, it is actually the same speed as by eval, so I would highly recommend doing that:
lemma is_M_M_ex_19: "is_M M_ex_19"
by code_simp
In your case, the reason why code_simp is much faster than simp is because of a simproc that has exponential runtime in the number of nested let expressions. Hence, another solution would be to use simp add: Let_def to just unfold let expressions.
Edited to reflect comment by Andreas Lochbihler

Custom Isabelle syntax breaks existing syntax

I am attempting to generate a nice syntax for mapping a function over the values of an associative list, i.e. I want to write [x ↦ f y | (x ↦ y) ∈ l] for mapAList f l. I came up with
syntax
"_alist_map" :: "['b, pttrn, ('a × 'b) list] ⇒ ('a × 'b) list"
("[x ↦ _ | '(x ↦ _') ∈ _]")
which works, but causes term "(x,y)#[]" to tell me Inner syntax error at "(x , y ) # []" and the (x is shaded slightly different.
The reason seems that once x appears in a mixfix annotation, it now always a literal token to the grammer (a delimiter according to §7.4.1 of isar-ref) and no longer an identifier – just like the syntax for if ... then ... else ... prevents if from being a variable name
Can I somehow work around this problem?
Identifier names used in mixfix annotations cannot be used as identifiers any longer, and I don't know any way around that. Therefore, instead of using x as a variable name, you can pick a non-identifier symbol like \<xX> or \<mapAListvariable> and setup the LaTeX output to print this as x by adding \newcommand{\isasymmapAListvariable}{x} to your root.tex.
You can also add \<xX> or \<mapAListvariable> to the symbols file of Isabelle/JEdit (preferably in $ISABELLE_HOME_USER/etc/symbols) and assign it some Unicode point that will be used for display in Isabelle/JEdit.
I just made a small experiment with a function map_alist that hopefully corresponds to your mapAList and which is defined as follows:
fun map_alist :: "('b ⇒ 'c) ⇒ ('a × 'b) list ⇒ ('a × 'c) list"
where
"map_alist f [] = []" |
"map_alist f ((x, y) # xs) = (x, f y) # map_alist f xs"
Then existing syntax can be used which looks a little bit as you intended. Maybe this is an option?
lemma "map_alist f xs = [(x, f y). (x, y) ← xs]"
by (induct xs) auto

Coq: apply transitivity with substitution

I want to proof this lemma in Coq:
a : Type
b : Type
f : a -> b
g : a -> b
h : a -> b
______________________________________(1/1)
(forall x : a, f x = g x) ->
(forall x : a, g x = h x) -> forall x : a, f x = h x
I know that Coq.Relations.Relation_Definitions defines transitivity for relations:
Definition transitive : Prop := forall x y z:A, R x y -> R y z -> R x z.
Simply using the proof tactic apply transitivity obviously fails. How can I apply the transitivity lemma to the goal above?
The transitivity tactic requires an argument, which is the intermediate term that you want to introduce into the equality. First call intros (that's almost always the first thing to do in a proof) to have the hypotheses nicely in the environment. Then you can say transitivity (g x) and you're left with two immediate applications of an assumption.
intros.
transitivity (g x); auto.
You can also make Coq guess which intermediate term to use. This doesn't always work, because sometimes Coq finds a candidate that doesn't work out in the end, but this case is simple enough and works immediately. The lemma that transitivity applies is eq_trans; use eapply eq_trans to leave a subterm open (?). The first eauto chooses a subterm that works for the first branch of the proof, and here it also works in the second branch of the proof.
intros.
eapply eq_trans.
eauto.
eauto.
This can be abbreviated as intros; eapply eq_trans; eauto. It can even be abbreviated further to
eauto using eq_trans.
eq_trans isn't in the default hint database because it often leads down an unsuccessful branch.
Ok, I was on the wrong track. Here is the proof of the lemma:
Lemma fun_trans : forall (a b:Type) (f g h:a->b),
(forall (x:a), f x = g x) ->
(forall (x:a), g x = h x) ->
(forall (x:a), f x = h x).
Proof.
intros a b f g h f_g g_h x.
rewrite f_g.
rewrite g_h.
trivial.
Qed.

Resources