Modeling Cardinality of Finite Sets in Coq - coq

I have made a basic theory of finite sets in Coq.
Syntax of Finite Sets (fsets)
An fset_expr can be
the empty set, an add operation,
a filter (set comprehension) of another set,
a cup (union) of two sets,
or a cap (intersection) of two sets.
Inductive fset_expr { A : Set } : Set :=
| fset_expr_empty : fset_expr
| fset_expr_add : fset_expr -> A -> fset_expr
| fset_expr_filter : fset_expr -> (A -> bool) -> fset_expr
| fset_expr_cup : fset_expr -> fset_expr -> fset_expr
| fset_expr_cap : fset_expr -> fset_expr -> fset_expr.
Semantics of Set Membership
in_fset s a means that the s : fset_expr contains the member a.
Inductive in_fset { A : Set } : fset_expr (A:=A) -> A -> Prop :=
| in_fset_add : forall x a, in_fset (fset_expr_add x a) a
| in_fset_added : forall x a0 a1, in_fset x a0 -> in_fset (fset_expr_add x a1) a0
| in_fset_cup_l : forall x y a, in_fset x a -> in_fset (fset_expr_cup x y) a
| in_fset_cup_r : forall x y a, in_fset y a -> in_fset (fset_expr_cup x y) a
| in_fset_cap : forall x y a, in_fset x a -> in_fset y a -> in_fset (fset_expr_cap x y) a
| in_fset_filter : forall x f a, in_fset x a -> (f a = true) -> in_fset (fset_expr_filter x f) a.
Subsets and Set Equality
Definition is_empty_fset {A : Set} (s : fset_expr (A:=A)) :=
forall a, ~(in_fset s a).
Definition subset_fset {A : Set} (x y : fset_expr (A:=A)) :=
forall a, in_fset x a -> in_fset y a.
Definition eq_fset {A : Set} (x y : fset_expr (A:=A)) :=
subset_fset x y /\ subset_fset y x.
Cardinality
This is where complications occured. I defined cardinality_fset s n which is supposed to mean that the finite set s : fset_expr contains n : nat elements.
Inductive cardinality_fset { A : Set } : fset_expr (A:=A) -> nat -> Prop :=
| cardinality_fset_empty : cardinality_fset fset_expr_empty 0
| cardinality_fset_add : forall s n a,
~(in_fset s a) ->
cardinality_fset s n ->
cardinality_fset (fset_expr_add s a) (S n)
| cardinality_fset_trans :
forall x y n,
eq_fset x y ->
cardinality_fset x n ->
cardinality_fset y n.
Problem
I could not prove that cardinality is well defined, i.e. every congruence class of fset_expr under relation eq_fset has a unique cardinality. Is it possible?
forall s : fset_expr (A:=A), exists n, (cardinality_fset s n /\ forall s' n', eq_fset s s' -> cardinality_fset s' n' -> n' = n).

To prove that theorem, you need to be able to write a function cardinality : fset_expr -> nat that computes the cardinality of a finite set, and to do that, you will need to decide whether or not two elements (a1 a2 : A) are equal (so that you don't double-count).
If you include an assumption forall a1 a2 : A, {a1 = a2} + {a1 <> a2}, then your theorem should be provable.

Related

Fix vs. Fix_sub

I'm attempting to use Fix to express a well-founded function.
It has Fix_eq to unwrap it for 1 level, however, the confusing
part is that Fix_eq is expressed in terms of Fix_sub instead of Fix.
The difference appears to be that
Check Fix.
(* ... *)
(forall x : A, (forall y : A, R y x -> P y) -> P x) ->
Check Fix_sub.
(* ... *)
(forall x : A, (forall y : {y : A | R y x}, P (proj1_sig y)) -> P x) ->
Fix uses 2 arguments and Fix_sub packages them both together into a sig.
So, they are essentially equivalent. However, I don't see any included
convenience functions to switch between Fix and Fix_sub. Is there
a reason that Fix_eq doesn't work with Fix ? How is it supposed
to be used?
I'm aware of Program and Function, but here I am trying to use Fix directly.
Which version and libraries are you using?
in 8.16 I get
Fix_eq:
forall [A : Type] [R : A -> A -> Prop] (Rwf : well_founded R)
(P : A -> Type) (F : forall x : A, (forall y : A, R y x -> P y) -> P x),
(forall (x : A) (f g : forall y : A, R y x -> P y),
(forall (y : A) (p : R y x), f y p = g y p) -> F x f = F x g) ->
forall x : A, Fix Rwf P F x = F x (fun (y : A) (_ : R y x) => Fix Rwf P F y)
and Fib_subis unknown.
You may have imported some module which masks the definitions from Coq.Init.Wf ?

Abstraction/typing error resulting from case_eq and rewriting in Coq

Consider the situation described by the code below, wherein I have a "piecewise" function h behaving differently (like f, or like g) depending on some (decidable) property condition of its input (h is defined using case_eq). Assume that I can prove that a property is guaranteed of the image of any x after application of either of the partial functions f or g; I should be able to prove that the entire function h guarantees property using a simple case_eq proof, no? Yet the following code rejects the rewrite step:
Section Error.
Variables X Y : Type.
Variables n m : Y.
Variable condition : X -> bool.
Variable property : Y -> Prop.
Definition type1 (x : X) : Prop := condition x = true.
Definition type2 (x : X) : Prop := condition x = false.
Variable f : {x:X | type1 x} -> Y.
Variable g : {x:X | type2 x} -> Y.
Definition h : X -> Y. intro x. case_eq (condition x); intro.
- exact (f (exist type1 x H)).
- exact (g (exist type2 x H)).
Defined.
Hypothesis Hf : forall x, property (f x).
Hypothesis Hg : forall x, property (g x).
Theorem hRange : forall x, property (h x).
Proof. intro. case_eq (condition x); intro.
- unfold h. rewrite H.
with the error
Abstracting over the term "condition x" leads to a term
fun b : bool =>
property
((if b as b0 return (b = b0 -> Y)
then fun H0 : b = true => f (exist type1 x H0)
else fun H0 : b = false => g (exist type2 x H0)) eq_refl)
which is ill-typed.
Reason is: Illegal application:
The term "exist" of type "forall (A : Type) (P : A -> Prop) (x : A), P x -> {x : A | P x}"
cannot be applied to the terms
"X" : "Type"
"type1" : "X -> Prop"
"x" : "X"
"H0" : "b = true"
The 4th term has type "b = true" which should be coercible to "type1 x".
Of course, I wish it would eliminate the if clause, rewriting the goal to property (f (exist type1 x H)) but Coq doesn't like this. Why not?
I feel Coq wouldn't behave like this if the hypothesis generated by case_eq in the definition of h wasn't implicated in the result (in this case, I could've rewritten h with a match clause, and those cause me no issue. In the present situation, just assume that the hypothesis is crucial to constructing some "non-computational" part of either f x or g x, e.g. if Y is itself a sig-type). I've read other threads like this and this, but to the short extent that I understand them, they don't help me understand my situation.
This problem occurs when you try to destruct or rewrite all the occurrences of a subterm. Here, you've rewritten condition x in the type of H0, which causes exist type1 x H0 to be ill-typed (can you see why?).
The solution is to restrict the destruct or rewrite to only some of the subterms. This might require you to generalize part of your goal. For example:
From Coq Require Import ssreflect.
Section Error.
Variables X Y : Type.
Variables n m : Y.
Variable condition : X -> bool.
Variable property : Y -> Prop.
Definition type1 (x : X) : Prop := condition x = true.
Definition type2 (x : X) : Prop := condition x = false.
Variable f : {x:X | type1 x} -> Y.
Variable g : {x:X | type2 x} -> Y.
Definition h : X -> Y. intro x. case_eq (condition x); intro.
- exact (f (exist type1 x H)).
- exact (g (exist type2 x H)).
Defined.
Hypothesis Hf : forall x, property (f x).
Hypothesis Hg : forall x, property (g x).
Theorem hRange : forall x, property (h x).
Proof.
intro; unfold h; generalize (eq_refl (condition x)).
case: {2 3}(condition x).
- intros H. apply Hf.
- intros H. apply Hg.
Qed.
End Error.
After generalizing eq_refl, the goal looks like this:
1 subgoal (ID 16)
X, Y : Type
n, m : Y
condition : X -> bool
property : Y -> Prop
f : {x : X | type1 x} -> Y
g : {x : X | type2 x} -> Y
Hf : forall x : {x : X | type1 x}, property (f x)
Hg : forall x : {x : X | type2 x}, property (g x)
x : X
============================
forall e : condition x = condition x,
property
((if condition x as b return (condition x = b -> Y)
then fun H : condition x = true => f (exist type1 x H)
else fun H : condition x = false => g (exist type2 x H)) e)
The tactic case: {2 3}..., which was imported from ssreflect, says that condition x should only be destructed on the RHS of e and on the condition of the if.

Logic: All_In can't expand nested forall

I am facing a pretty strange problem: coq doesn't want to move forall variable into the context.
In the old times it did:
Example and_exercise :
forall n m : nat, n + m = 0 -> n = 0 /\ m = 0.
Proof.
intros n m.
It generates:
n, m : nat
============================
n + m = 0 -> n = 0 /\ m = 0
But when we have forall inside forall, it doesn't work:
(* Auxilliary definition *)
Fixpoint All {T : Type} (P : T -> Prop) (l : list T) : Prop :=
(* ... *)
Lemma All_In :
forall T (P : T -> Prop) (l : list T),
(forall x, In x l -> P x) <->
All P l.
Proof.
intros T P l. split.
- intros H.
After this we get:
T : Type
P : T -> Prop
l : list T
H : forall x : T, In x l -> P x
============================
All P l
But how to move x outside of H and destruct it into smaller pieces? I tried:
destruct H as [x H1].
But it gives an error:
Error: Unable to find an instance for the variable x.
What is it? How to fix?
The problem is that forall is nested to the left of an implication rather than the right. It does not make sense to introduce x from a hypothesis of the form forall x, P x, just like it wouldn't make sense to introduce the n in plus_comm : forall n m, n + m = m + n into the context of another proof. Instead, you need to use the H hypothesis by applying it at the right place. I can't give you the answer to this question, but you might want to refer to the dist_not_exists exercise in the same chapter.

Coq Index Relation

I'm defining an indexed inductive type in Coq:
Module Typ.
(* My index -- a t is a `t H` or a `t Z`. *)
Inductive hz : Set := H | Z .
(* I'd like to use this relation to constrain Cursor and Arrow. *)
(* E.g. one specialized Cursor has type `t H -> t Z -> t Z` *)
Inductive maxHZ : hz -> hz -> hz -> Type :=
| HZ : maxHZ H Z Z
| ZH : maxHZ Z H Z
| HH : maxHZ H H H
.
Inductive t : hz -> Type :=
| Num : t H
| Hole : t H
| Cursor : t H -> t Z
| Arrow : forall a b c, t a -> t b -> t c
| Sum : forall a b c, t a -> t b -> t c
.
End Typ.
How can I constrain my Arrow / Sum indices to be the same shape as the maxHZ relation (short of creating more constructors, like ArrowHZ : t H -> t Z -> t Z).
One approach:
(* Bring the coercion is_true into scope *)
From Coq Require Import ssreflect ssrfun ssrbool.
Module Typ.
(* My index -- a t is a `t H` or a `t Z`. *)
Inductive hz : Set := H | Z .
(* I'd like to use this relation to constrain Cursor and Arrow. *)
(* E.g. one specialized Cursor has type `t H -> t Z -> t Z` *)
Definition maxHZ (x y z : hz) : bool :=
match x, y, z with
| H, Z, Z
| Z, H, Z
| H, H, H => true
| _, _, _ => false
end.
Inductive t : hz -> Type :=
| Num : t H
| Hole : t H
| Cursor : t H -> t Z
| Arrow : forall a b c, maxHZ a b c -> t a -> t b -> t c
| Sum : forall a b c, maxHZ a b c -> t a -> t b -> t c
.
End Typ.
the other:
Inductive t : hz -> Type :=
| Num : t H
| Hole : t H
| Cursor : t H -> t Z
| Arrow : forall a b c, t a -> t b -> t c
| Sum : forall a b c, t a -> t b -> t c
.
Definition t_wf x (m : t x) : bool :=
match m with
| Arrow a b c _ _ => maxHZ a b c
| Sum a b c _ _ => maxHZ a b c
| _ => true
end.
Definition t' x := { m : t x | t_wf x m }.
(* This is automatically a subtype. *)

Moving from computable functions to inductive relations

I am trying to understand how to move from theorems that operate on computable functions to theorems that use inductively defined relations to represent computations. Consider this simple development below. Let's start with a standard definition of relations and their properties:
Definition relation (X : Type) := X -> X -> Prop.
Definition reflexive {X : Type} (R : relation X) :=
forall a, R a a.
Definition transitive {X : Type} (R : relation X) :=
forall a b c : X, (R a b) -> (R b c) -> (R a c).
Now I define three properties defined for a relation R and two functions F and G:
Definition propA {X : Type} (R : relation X) (F G : X -> X) :=
forall p q, R (F p) q <-> R p (G q).
Definition propB {X : Type} (R : relation X) (F G : X -> X) :=
forall x, R x (G (F x)).
Definition propC {X : Type} (R : relation X) (F : X -> X) :=
forall a b : X, R a b -> R (F a) (F b).
I state a theorem that if R is reflexive and property A holds for R, F and G, then property B also holds R, F and G.
Lemma aPropB {X : Type} {R : relation X} {F G : X -> X} (Rrefl : reflexive R)
(H : propA R F G) :
propB R F G.
Proof.
unfold propB in *.
intros.
apply H. apply Rrefl.
Qed.
Finally I state a theorem that if R is reflexive and transitive, and property A holds for R, F and G, then property C holds for R and F.
Lemma aPropC {X : Type} {R : relation X} {F G : X -> X}
(Rrefl : reflexive R) (Rtrans : transitive R) (H : propA R F G) :
propC R F.
Proof.
unfold propC in *.
intros.
apply H.
eapply Rtrans. eassumption.
apply aPropB; assumption.
Qed.
Now I would like to move from representing F and G as computations to representing them as relations. So instead of saying F : X -> X I will now just say F : relation X and insist that F is deterministic:
Definition deterministic {X : Type} (F : relation X) :=
forall x y1 y2, F x y1 -> F x y2 -> y1 = y2.
I restate all three properties:
Definition propA' {X : Type} (R : relation X) (F G : relation X)
(Fdet : deterministic F) (Gdet : deterministic G) :=
forall p q x y, F p x -> G q y -> R x q <-> R p y.
Definition propB' {X : Type} (R : relation X) (F G : relation X)
(Fdet : deterministic F) (Gdet : deterministic G) :=
forall x y z, F x y -> G y z -> R x z.
Definition propC' {X : Type} (R : relation X) (F : relation X)
(Fdet : deterministic F) :=
forall a b x y : X, F a x -> F b y -> R a b -> R x y.
Transformation pattern that I have followed is that expression R a (F b) is turned into F b x -> R a x, meaning "F b evaluates to some x and a is in relation R with that x". Now for the theorems. First one follows quite easily:
Lemma aPropB' {X : Type} {R : relation X} {Rrefl : reflexive R}
{F G : relation X} {Fdet : deterministic F} {Gdet : deterministic G}
(H : propA' R F G Fdet Gdet) :
propB' R F G Fdet Gdet.
Proof.
unfold propA', propB' in *.
intros.
specialize (H x y y z).
apply H; auto.
Qed.
But I am stuck with the second one. I start the proof like this:
Lemma aPropC' {X : Type} {R : relation X} {F G : relation X}
{Fdet : deterministic F} {Gdet : deterministic G}
(Rrefl : reflexive R) (Rtrans : transitive R)
(H : propA' R F G Fdet Gdet) :
propC' R F Fdet.
Proof.
unfold propC' in *.
intros.
eapply H; try eassumption.
and end with a following goal to prove (some irrelevant hypotheses omitted):
H : propA' R F G Fdet Gdet
H0 : F a x
H1 : F b y
H2 : R a b
─────────────────────────────────────────────────────
G y b
The problem is that G is now an explicit premise of propA' and I have to prove it if I want to rely on propA'. But I have no assumptions about G in my current proof context and I don't see a way to finish the proof. Previously in aPropC, that used functions, G would only appear in conclusions of aPropA and aPropB. So the shape of the goal matched the shape of my hypotheses and known lemmas, allowing me to use them easily.
Where am I going wrong here? Is my transition from functions to relations incorrect? Is there any technique that I could use here?
Functions in Coq are not just deterministic relations but also total ones. So you may want to throw in:
Definition total {X : Type} (R : relation X) : Prop :=
forall x, exists y, R x y.
And then the notion of being functional is the conjunction of deterministic and total:
Definition functional {X : Type} (R : relation X) : Prop :=
deterministic R /\ total R.
Alternatively, you can add assumptions to your lemmas relating the domains of the partial functions your relations represent.