Mefresa.Examples.GCMSpec

Proving the absence of Cross Bindings

In this section we show how we can prove one of the properties that is expected to hold in any GCM application. GCM inherits a lot of its features from Fractal, and as such many properties expected to hold in Fractal, are also expected to hold in GCM. From the Fractal specification, we know that there are 3 types of bindings: Normal, Export and Import.
It is stated in the Fractal specification that if a binding meets the constraint of being of Normal, Export or Import type, then it cannot cross any component boundary except through its interfaces.
In the following, we demonstrate how this can be proved within our framework.

Preliminary Definitions - Setting Up the Scene!

First of all, we to define what it means to be a cross binding. Since we have 3 types of bindings, Normal, Export and Import, we gonna have 3 types of cross bindings. As such, we need to define each of them w.r.t. our framework.

Definition cross_normal idC1 idI1 idC2 idI2 lc : Prop :=
  (exists c, Some c = lc [idC1] /\
              (exists i, Some i = (c ->interfaces)%comp [idI1, External] /\
                         (i ->role)%int = Client)%int) /\
  (~ exists c, Some c = lc[idC2] /\
              (exists i, Some i = (c ->interfaces)%comp [idI2, External])%int) /\
  (forall c, In c lc ->
              (exists c' c'', In c' (c->subComponents%comp) /\
                          Some c'' = (c'->subComponents%comp)[idC2] /\
              (exists i, Some i = (c'' ->interfaces)%comp [idI2, External]%int /\
                         (i ->role)%int = Server))).


Definition cross_export idI1 idC2 idI2 lc li : Prop :=
  (exists i, Some i = li [idI1, Internal]%int /\ (i ->role)%int = Client) /\
  (~ exists c, Some c = lc[idC2] /\
    (exists i, Some i = (c ->interfaces)%comp [idI2, External])%int) /\
  (forall c, In c lc -> exists c', Some c' = (c->subComponents%comp)[idC2] /\
                        exists i, Some i = (c'->interfaces%comp)[idI2, External]%int /\
                                  (i ->role)%int = Server).


Definition cross_import idI1 idC2 idI2 lc li : Prop :=
  (exists i, Some i = li [idI1, Internal]%int /\ (i ->role)%int = Server) /\
  (~ exists c, Some c = lc[idC2] /\
    (exists i, Some i = (c ->interfaces)%comp [idI2, External])%int) /\
  (forall c, In c lc -> exists c', Some c' = (c->subComponents%comp)[idC2] /\
                        exists i, Some i = (c'->interfaces%comp)[idI2, External]%int /\
                                  (i ->role)%int = Client).


The 3 above definitions cross_normal, cross_export and cross_import define what it means to be a cross binding of type Normal, Export and Import, respectively. Essentially, they all state that the "second part" of the binding (idC2 IdI2, for id of second component and id of second interface, resp.), is located at a different level in the component hierarchy. Since we use idents to identify components and interfaces, and since they need not to be unique among different levels of the hierarchy, we need to explicitly state that there exists no component and/or interface with such ident.
From this, we can proceed to the remaining few definitions that basically just place the above ones in the context of our hierarchical component framework.

Definition valid_cross_binding b lc li : Prop :=
  match b with
    Normal p idC1 idI1 idC2 idI2 => cross_normal idC1 idI1 idC2 idI2 lc
  | Export p idI1 idC2 idI2 => cross_export idI1 idC2 idI2 lc li
  | Import _ idI1 idC2 idI2 => cross_import idI1 idC2 idI2 lc li
  end.


Inductive cross_binding' b p lc : Prop :=
  | CrossBinding_Base: p = (nil : path) ->
                       valid_cross_binding b lc nil ->
                       cross_binding' b p lc
  | CrossBinding_Step: forall c,
                       Some c = get_component_with_path_aux p lc ->
                       valid_cross_binding b (c ->subComponents)%comp (c ->interfaces)%comp ->
                       cross_binding' b p lc.


Definition cross_binding b s : Prop :=
  cross_binding' b (b->path%bind) (s->components%st).


Axiom binding_type_dec : forall b s,
  {cross_binding b s} + {valid_component_binding b s}.


Cross Bindings Cannot Occur? Proof? Sure thing!

Before proceeding proving the property we want, we shall first prove a lemma that states that if a binding is valid, then it cannot be crossing. This lemma will serve as an auxiliary to prove our main theorem.

Lemma binding_cannot_be_crossing_if_valid:
  forall b s,
  valid_component_binding b s ->
  cross_binding b s ->
  False.

Proof.

  intros.

  destruct s.

  destruct b.

  Case "Normal Binding".

    inversion H; simpl in *; subst.

    SCase "Path is nil".

      clear H.

      inversion H0; simpl in *.

      clear H H0.

      unfold normal_binding in H2.

      destruct H1 as (He, (Hf, Hg)).

      clear Hg.

      destruct He as (c', (He1,(i', (He3, He4)))).

      rewrite <- He1 in H2.

      destruct (l [i3]).

      apply Hf.

      exists c0; split; auto.

      rewrite <- He3 in H2.

      destruct (((c0 ->interfaces)%comp [i4, External])%int).

      exists i5; auto.

      inversion H2.

      inversion H2.

      inversion H.

  SCase "Path is not Nil".

destruct H1 as (c1, (H01, H02)).

    clear H.

    inversion H0; simpl in *; subst.

    simpl in H01.

congruence.

    assert (c0 = c1).

      rewrite <- H01 in H.

      inversion H; auto.

    subst.

    unfold normal_binding in H02.

    destruct H1 as (He, (Hf, Hg)).

    clear Hg.

    destruct He as (c', (He1,(i', (He3, He4)))).

    rewrite <- He1 in H02.

    destruct ((c1 ->subComponents)%comp [i3]).

    apply Hf.

    exists c0; split; auto.

    rewrite <- He3 in H02.

    destruct (((c0 ->interfaces)%comp [i4, External])%int).

    exists i5; auto.

fromfalse.

fromfalse.

  Case "Export Binding".

    inversion H; simpl in *; subst.

    SCase "Path is nil".

      clear H.

      inversion H0; simpl in *.

      clear H H0.

      unfold export_binding in H2.

      destruct H1 as (He, (Hf, Hg)).

      clear Hg.

      destruct He as (i', (He1,He4)).

      inversion He1.

      inversion H.

  SCase "Path is not Nil".

destruct H1 as (c1, (H01, H02)).

    clear H.

    inversion H0; simpl in *; subst.

    simpl in H01.

    inversion H01.

    assert (c0 = c1).

      rewrite <- H01 in H.

      inversion H; auto.

    subst.

    unfold export_binding in H02.

    destruct H1 as (He, (Hf, Hg)).

    clear Hg.

    destruct He as (i', (He1, He4)).

    rewrite <- He1 in H02.

    destruct ((c1 ->subComponents)%comp [i2]).

    apply Hf.

    exists c0; split; auto.

    rewrite <- He4 in H02.

    destruct (((c0 ->interfaces)%comp [i3, External])%int).

    exists i4; auto.

fromfalse.

fromfalse.

  Case "Import Binding".

    inversion H; simpl in *; subst.

    SCase "Path is nil".

      clear H.

      inversion H0; simpl in *.

      clear H H0.

      unfold export_binding in H2.

      destruct H1 as (He, (Hf, Hg)).

      clear Hg.

      destruct He as (i', (He1,He4)).

      inversion He1.

      inversion H.

  SCase "Path is not Nil".

destruct H1 as (c1, (H01, H02)).

    clear H.

    inversion H0; simpl in *; subst.

    simpl in H01.

congruence.

    assert (c0 = c1).

      rewrite <- H01 in H.

      inversion H; auto.

    subst.

    unfold import_binding in H02.

    destruct H1 as (He, (Hf, Hg)).

    clear Hg.

    destruct He as (i', (He1, He4)).

    rewrite <- He1 in H02.

    destruct ((c1 ->subComponents)%comp [i2]).

    apply Hf.

    exists c0; split; auto.

    rewrite <- He4 in H02.

    destruct (((c0 ->interfaces)%comp [i3, External])%int).

    exists i4; auto.

fromfalse.

fromfalse.

Qed.



The proof of binding_cannot_be_crossing_if_valid gives us that a binding cannot be valid and crossing for the same state. The argument of the proof is essentially a case analysis on the binding type, where we show a contradiction for all of the 3 constructors.
The proof above, although a little bit long, should pose no trouble to the reader. Our definition of cross_bindings is defined in a way that makes this proof easy, as it requires to explicitly negate the presence of a component and/or interface that would match the specified idents in the "second part" of the cross_binding. This is a direct implication of the data structure used to defined our hierarchical component framework. As usual in Coq developments relying on inductive definitions, choosing adequates data structures may considerably ease the burden of theorem proving.
We shall now proceed to one last definition before moving to the main proof. We define a predicate system_binding that states whether a binding belongs to a state.

Definition system_binding (b:binding) (s:state) : Prop :=
  match get_component_with_path (b->path%bind) s with
    | None => False
    | Some c => In b (c->bindings%comp)
  end.


Theorem cross_binding_cannot_happen:
  forall b system,
    well_formed system ->
    system_binding b system ->
    cross_binding b system ->
    False.

Proof.

  intros.

  apply binding_cannot_be_crossing_if_valid
      with (b:=b) (s:=system); auto.

  clear H1.

  unfold system_binding in H0.

  destruct get_component_with_path_dec
            with (p:=b->path%bind)(s:=system); auto.

  destruct system.

  unfold well_formed in H.

  destruct H as (Hi, (Hp, (Hic, (Hc, (Hl, Hw))))); subst; auto.

  Case "It does exists!".

    unfold valid_component_binding.

    destruct (b->path%bind).

    SCase "Path is nil".

      destruct H1 as (c, (He, Hp)).

      rewrite <- He in H0.

      simpl in He.

      inversion He.

    SCase "Path is not nil".

      destruct H1 as (c, (He, Hp)).

      rewrite <- He in H0.

      apply ValidComponentBinding_Step .

      unfold get_component_with_path in He.

      destruct system.

exists c.

      split;auto.

      assert (well_formed_bindings (c ->bindings)%comp (c ->subComponents)%comp (c ->interfaces)%comp).

        destruct c; simpl in *; subst; auto.

        inversion Hp; auto.

      unfold well_formed_bindings in H1.

      apply H1;auto.

  Case "It does not exists!".

    rewrite <- H1 in H0.

    inversion H0.

Qed.


The key to the proof of our main theorem cross_binding_cannot_happen lies in the argument of our previously proved lemma binding_cannot_be_crossing_if_valid. The idea is to show that any binding present in the state must be a valid_component_binding - this follows from the fact that the state is well_formed. Then, since we know from binding_cannot_be_crossing_if_valid that a binding cannot be a valid_component_binding and a valid_cross_binding at the same time, we can conclude the proof.