The Setoid of Setoid functions



The setoid functions form again a setoid.

Definition ap_fun (A B : CSetoid) (f g : CSetoid_fun A B) :=
  {a : A | f a[#]g a}.

Definition eq_fun (A B : CSetoid) (f g : CSetoid_fun A B) :=
  forall a : A, f a[=]g a.

Lemma irrefl_apfun : forall A B : CSetoid, irreflexive (ap_fun A B).

Lemma cotrans_apfun : forall A B : CSetoid, cotransitive (ap_fun A B).

Lemma ta_apfun : forall A B : CSetoid, tight_apart (eq_fun A B) (ap_fun A B).

Lemma sym_apfun : forall A B : CSetoid, Csymmetric (ap_fun A B).

Definition FS_is_CSetoid (A B : CSetoid) :=
  Build_is_CSetoid (CSetoid_fun A B) (eq_fun A B) (ap_fun A B)
  (irrefl_apfun A B) (sym_apfun A B) (cotrans_apfun A B) (ta_apfun A B).

Definition FS_as_CSetoid (A B : CSetoid) :=
  Build_CSetoid (CSetoid_fun A B) (eq_fun A B) (ap_fun A B)
    (FS_is_CSetoid A B).

Nullary and n-ary operations


Definition is_nullary_operation (S:CSetoid) (s:S):Prop := True.

Fixpoint n_ary_operation (n:nat)(V:CSetoid){struct n}:CSetoid:=
match n with
|0 => V
|(S m)=> (FS_as_CSetoid V (n_ary_operation m V))
end.

Section unary_function_composition.

Composition of Setoid functions



Let S1, S2 and S3 be setoids, f a setoid function from S1 to S2, and g from S2 to S3 in the following definition of composition.

Variables S1 S2 S3 : CSetoid.
Variable f : CSetoid_fun S1 S2.
Variable g : CSetoid_fun S2 S3.

Definition compose_CSetoid_fun : CSetoid_fun S1 S3.

Defined.

End unary_function_composition.

Composition as operation

Definition comp (A B C : CSetoid) :
  FS_as_CSetoid A B -> FS_as_CSetoid B C -> FS_as_CSetoid A C.
Defined.

Definition comp_as_bin_op (A:CSetoid) : CSetoid_bin_op (FS_as_CSetoid A A).

Defined.

Lemma assoc_comp : forall A : CSetoid, associative (comp_as_bin_op A).

Section unary_and_binary_function_composition.

Definition compose_CSetoid_bin_un_fun (A B C : CSetoid)
  (f : CSetoid_bin_fun B B C) (g : CSetoid_fun A B) : CSetoid_bin_fun A A C.
Defined.

Definition compose_CSetoid_bin_fun A B C (f g : CSetoid_fun A B)
  (h : CSetoid_bin_fun B B C) : CSetoid_fun A C.
Defined.

Definition compose_CSetoid_un_bin_fun A B C (f : CSetoid_bin_fun B B C)
 (g : CSetoid_fun C A) : CSetoid_bin_fun B B A.
Defined.

End unary_and_binary_function_composition.

Projections


Section function_projection.

Lemma proj_bin_fun : forall A B C (f : CSetoid_bin_fun A B C) a, fun_strext (f a).

Definition projected_bin_fun A B C (f : CSetoid_bin_fun A B C) (a : A) :=
 Build_CSetoid_fun B C (f a) (proj_bin_fun A B C f a).

End function_projection.

Section BinProj.

Variable S : CSetoid.

Definition binproj1 (x y:S) := x.

Lemma binproj1_strext : bin_fun_strext _ _ _ binproj1.

Definition cs_binproj1 : CSetoid_bin_op S.
Defined.

End BinProj.

Combining operations

Let S1, S2 and S3 be setoids.

Section CombiningOperations.
Variables S1 S2 S3 : CSetoid.

In the following definition, we assume f is a setoid function from S1 to S2, and op is an unary operation on S2. Then opOnFun is the composition op after f.
Section CombiningUnaryOperations.
Variable f : CSetoid_fun S1 S2.
Variable op : CSetoid_un_op S2.

Definition opOnFun : CSetoid_fun S1 S2.
Defined.

End CombiningUnaryOperations.

End CombiningOperations.

Section p66E2b4.

The Free Setoid

Let A:CSetoid.
Variable A:CSetoid.

Definition Astar := (list A).

Definition empty_word := (@nil A).

Definition appA:= (@app A).

Fixpoint eq_fm (m:Astar)(k:Astar){struct m}:Prop:=
match m with
|nil => match k with
        |nil => True
        |cons a l => ⊥
        end
|cons b n => match k with
        |nil => ⊥
        |cons a l => b[=]a /\ (eq_fm n l)
        end
end.

Fixpoint ap_fm (m:Astar)(k:Astar){struct m}: CProp :=
match m with
|nil => match k with
        |nil => ⊥
        |cons a l => CTrue
        end
|cons b n => match k with
        |nil => CTrue
        |cons a l => b[#]a or (ap_fm n l)
        end
end.

Lemma ap_fm_irreflexive: (irreflexive ap_fm).

Lemma ap_fm_symmetric: Csymmetric ap_fm.

Lemma ap_fm_cotransitive : (cotransitive ap_fm).

Lemma ap_fm_tight : (tight_apart eq_fm ap_fm).

Definition free_csetoid_is_CSetoid:(is_CSetoid Astar eq_fm ap_fm):=
  (Build_is_CSetoid Astar eq_fm ap_fm ap_fm_irreflexive ap_fm_symmetric
  ap_fm_cotransitive ap_fm_tight).

Definition free_csetoid_as_csetoid:CSetoid:=
(Build_CSetoid Astar eq_fm ap_fm free_csetoid_is_CSetoid).

Lemma app_strext:
  (bin_fun_strext free_csetoid_as_csetoid free_csetoid_as_csetoid
   free_csetoid_as_csetoid appA).

Definition app_as_csb_fun:
(CSetoid_bin_fun free_csetoid_as_csetoid free_csetoid_as_csetoid
  free_csetoid_as_csetoid):=
  (Build_CSetoid_bin_fun free_csetoid_as_csetoid free_csetoid_as_csetoid
   free_csetoid_as_csetoid appA app_strext).

Lemma eq_fm_reflexive: forall (x:Astar), (eq_fm x x).

End p66E2b4.

Partial Functions



In this section we define a concept of partial function for an arbitrary setoid. Essentially, a partial function is what would be expected---a predicate on the setoid in question and a total function from the set of points satisfying that predicate to the setoid. There is one important limitations to this approach: first, the record we obtain has type Type, meaning that we can't use, for instance, elimination of existential quantifiers.

Furthermore, for reasons we will explain ahead, partial functions will not be defined via the CSetoid_fun record, but the whole structure will be incorporated in a new record.

Finally, notice that to be completely general the domains of the functions have to be characterized by a CProp-valued predicate; otherwise, the use you can make of a function will be a priori restricted at the moment it is defined.

Before we state our definitions we need to do some work on domains.

Section SubSets_of_G.

Subsets of Setoids



Subsets of a setoid will be identified with predicates from the carrier set of the setoid into CProp. At this stage, we do not make any assumptions about these predicates.

We will begin by defining elementary operations on predicates, along with their basic properties. In particular, we will work with well defined predicates, so we will prove that these operations preserve welldefinedness.

Let S:CSetoid and P,Q:S->CProp.

Variable S : CSetoid.

Section Conjunction.

Variables P Q : S -> CProp.

Definition conjP (x : S) : CProp := P x and Q x.

Lemma prj1 : forall x : S, conjP x -> P x.

Lemma prj2 : forall x : S, conjP x -> Q x.

Lemma conj_wd : pred_wd _ P -> pred_wd _ Q -> pred_wd _ conjP.

End Conjunction.

Section Disjunction.

Variables P Q : S -> CProp.

Although at this stage we never use it, for completeness's sake we also treat disjunction (corresponding to union of subsets).

Definition disj (x : S) : CProp := P x or Q x.

Lemma inj1 : forall x : S, P x -> disj x.

Lemma inj2 : forall x : S, Q x -> disj x.

Lemma disj_wd : pred_wd _ P -> pred_wd _ Q -> pred_wd _ disj.

End Disjunction.

Section Extension.

The next definition is a bit tricky, and is useful for choosing among the elements that satisfy a predicate P those that also satisfy R in the case where R is only defined for elements satisfying P---consider R to be a condition on the image of an object via a function with domain P. We chose to call this operation extension.

Variable P : S -> CProp.
Variable R : forall x : S, P x -> CProp.

Definition extend (x : S) : CProp := P x and (forall H : P x, R x H).

Lemma ext1 : forall x : S, extend x -> P x.

Lemma ext2_a : forall x : S, extend x -> {H : P x | R x H}.

Lemma ext2 : forall (x : S) (Hx : extend x), R x (ProjT1 (ext2_a x Hx)).

Lemma extension_wd : pred_wd _ P ->
 (forall (x y : S) Hx Hy, x [=] y -> R x Hx -> R y Hy) -> pred_wd _ extend.

End Extension.

End SubSets_of_G.

Notation Conj := (conjP _).


Operations



We are now ready to define the concept of partial function between arbitrary setoids.

Record BinPartFunct (S1 S2 : CSetoid) : Type :=
  {bpfdom : S1 -> CProp;
   bdom_wd : pred_wd S1 bpfdom;
   bpfpfun :> forall x : S1, bpfdom x -> S2;
   bpfstrx : forall x y Hx Hy, bpfpfun x Hx [#] bpfpfun y Hy -> x [#] y}.

Notation BDom := (bpfdom _ _).

The next lemma states that every partial function is well defined.

Lemma bpfwdef : forall S1 S2 (F : BinPartFunct S1 S2) x y Hx Hy,
 x [=] y -> F x Hx [=] F y Hy.

Similar for automorphisms.

Record PartFunct (S : CSetoid) : Type :=
  {pfdom : S -> CProp;
   dom_wd : pred_wd S pfdom;
   pfpfun :> forall x : S, pfdom x -> S;
   pfstrx : forall x y Hx Hy, pfpfun x Hx [#] pfpfun y Hy -> x [#] y}.

Notation Dom := (pfdom _).
Notation Part := (pfpfun _).

The next lemma states that every partial function is well defined.

Lemma pfwdef : forall S (F : PartFunct S) x y Hx Hy, x [=] y -> F x Hx [=] F y Hy.

A few characteristics of this definition should be explained:
  • The domain of the partial function is characterized by a predicate that is required to be well defined but not strongly extensional. The motivation for this choice comes from two facts: first, one very important subset of real numbers is the compact interval [a,b]---characterized by the predicate fun x : IR => a [<=] x /\ x [<=] b, which is not strongly extensional; on the other hand, if we can apply a function to an element s of a setoid S it seems reasonable (and at some point we do have to do it) to apply that same function to any element s' which is equal to s from the point of view of the setoid equality.
  • The last two conditions state that pfpfun is really a subsetoid function. The reason why we do not write it that way is the following: when applying a partial function f to an element s of S we also need a proof object H; with this definition the object we get is f(s,H), where the proof is kept separate from the object. Using subsetoid notation, we would get f(⟨s,H⟩); from this we need to apply two projections to get either the original object or the proof, and we need to apply an extra constructor to get f(⟨s,H⟩) from s and H. This amounts to spending more resources when actually working with these objects.
  • This record has type Type, which is very unfortunate, because it means in particular that we cannot use the well behaved set existential quantification over partial functions; however, later on we will manage to avoid this problem in a way that also justifies that we don't really need to use that kind of quantification. Another approach to this definition that completely avoid this complication would be to make PartFunct a dependent type, receiving the predicate as an argument. This does work in that it allows us to give PartFunct type Set and do some useful stuff with it; however, we are not able to define something as simple as an operator that gets a function and returns its domain (because of the restrictions in the type elimination rules). This sounds very unnatural, and soon gets us into strange problems that yield very unlikely definitions, which is why we chose to altogether do away with this approach.


All partial functions will henceforth be denoted by capital letters.

We now present some methods for defining partial functions.


Section CSetoid_Ops.

Variable S : CSetoid.

To begin with, we want to be able to ``see'' each total function as a partial function.

Definition total_eq_part : CSetoid_un_op S -> PartFunct S.
Defined.

Section Part_Function_Const.

In any setoid we can also define constant functions (one for each element of the setoid) and an identity function:

Let c:S.

Variable c : S.

Definition Fconst := total_eq_part (Const_CSetoid_fun _ _ c).

End Part_Function_Const.

Section Part_Function_Id.

Definition Fid := total_eq_part (id_un_op S).

End Part_Function_Id.

(These happen to be always total functions, but that is more or less obvious, as we have no information on the setoid; however, we will be able to define partial functions just applying other operators to these ones.)

If we have two setoid functions F and G we can always compose them. The domain of our new function will be the set of points s in the domain of F for which F(s) is in the domain of G. Notice that the use of extension here is essential. The inversion in the order of the variables is done to maintain uniformity with the usual mathematical notation.

Let G,F:(PartFunct S) and denote by Q and P, respectively, the predicates characterizing their domains.

Section Part_Function_Composition.

Variables G F : PartFunct S.

Let R x := {Hx : P x | Q (F x Hx)}.

Lemma part_function_comp_strext : forall x y (Hx : R x) (Hy : R y),
 G (F x (ProjT1 Hx)) (ProjT2 Hx) [#] G (F y (ProjT1 Hy)) (ProjT2 Hy) -> x [#] y.

Lemma part_function_comp_dom_wd : pred_wd S R.

Definition Fcomp := Build_PartFunct _ R part_function_comp_dom_wd
  (fun x (Hx : R x) => G (F x (ProjT1 Hx)) (ProjT2 Hx))
  part_function_comp_strext.

End Part_Function_Composition.

End CSetoid_Ops.

Let F:(BinPartFunct S1 S2) and G:(PartFunct S2 S3), and denote by Q and P, respectively, the predicates characterizing their domains.

Section BinPart_Function_Composition.

Variables S1 S2 S3 : CSetoid.

Variable G : BinPartFunct S2 S3.
Variable F : BinPartFunct S1 S2.

Let R x := {Hx : P x | Q (F x Hx)}.

Lemma bin_part_function_comp_strext : forall x y (Hx : R x) (Hy : R y),
 G (F x (ProjT1 Hx)) (ProjT2 Hx) [#] G (F y (ProjT1 Hy)) (ProjT2 Hy) -> x [#] y.

Lemma bin_part_function_comp_dom_wd : pred_wd S1 R.

Definition BinFcomp := Build_BinPartFunct _ _ R bin_part_function_comp_dom_wd
  (fun x (Hx : R x) => G (F x (ProjT1 Hx)) (ProjT2 Hx))
  bin_part_function_comp_strext.

End BinPart_Function_Composition.


Notation "[-C-] x" := (Fconst x) (at level 2, right associativity).

Notation FId := (Fid _).

Infix "⋅" := Fcomp (at level 65, no associativity).


Section bijections.

Bijections


Definition injective A B (f : CSetoid_fun A B) := (forall a0 a1 : A,
 a0 [#] a1 -> f a0 [#] f a1):CProp.

Definition injective_weak A B (f : CSetoid_fun A B) := forall a0 a1 : A,
 f a0 [=] f a1 -> a0 [=] a1.

Definition surjective A B (f : CSetoid_fun A B) := (forall b : B, {a : A | f a [=] b}):CProp.


Lemma injective_imp_injective_weak : forall A B (f : CSetoid_fun A B),
 injective f -> injective_weak f.

Definition bijective A B (f:CSetoid_fun A B) := injective f and surjective f.


Lemma id_is_bij : forall A, bijective (id_un_op A).

Lemma comp_resp_bij : forall A B C f g, bijective f -> bijective g ->
 bijective (compose_CSetoid_fun A B C f g).

Lemma inv : forall A B (f:CSetoid_fun A B),
 bijective f -> forall b : B, {a : A | f a [=] b}.


Definition invfun A B (f : CSetoid_fun A B) (H : bijective f) : B -> A.
Defined.


Lemma inv1 : forall A B (f : CSetoid_fun A B) (H : bijective f) (b : B),
 f (invfun f H b) [=] b.

Lemma inv2 : forall A B (f : CSetoid_fun A B) (H : bijective f) (a : A),
 invfun f H (f a) [=] a.

Lemma inv_strext : forall A B (f : CSetoid_fun A B) (H : bijective f),
 fun_strext (invfun f H).

Definition Inv A B f (H : bijective f) :=
  Build_CSetoid_fun B A (invfun f H) (inv_strext A B f H).


Definition Inv_bij : forall A B (f : CSetoid_fun A B) (H : bijective f),
  bijective (Inv f H).

Qed.

End bijections.


Notation Prj1 := (prj1 _ _ _ _).
Notation Prj2 := (prj2 _ _ _ _).