OpencypherCoq.ExecutionPlan
Require Import Utils.
Require Import Maps.
Require Import PropertyGraph.
Require Import Cypher.
Require Import BindingTable.
Require Import Semantics.
Require Import PatternE.
Import PartialMap.Notations.
Import PropertyGraph.
Module FilterMode.
Inductive t : Type :=
| Vertices
| Edges
.
End FilterMode.
Module ExpandMode .
Inductive t : Type :=
| All
| Into
.
End ExpandMode.
(* r' is expanded from r by traversing one edge *)
Definition expansion_of' (g : PropertyGraph.t) (r' r : Rcd.t)
(mode : ExpandMode.t)
(v_from : vertex) (e : edge) (v_to : vertex)
(n_from n_edge n_to : Name.t)
(d : Pattern.direction) :=
<< HIn_e : In e (edges g) >> /\
<< Hdir : Path.matches_direction g v_from v_to e d >> /\
<< Hval_from : r n_from = Some (Value.GVertex v_from) >> /\
<< Hval_edge : r n_edge = None >> /\
<< Hval' : r' = (n_to |-> Value.GVertex v_to; n_edge |-> Value.GEdge e; r) >> /\
match mode with
| ExpandMode.All =>
<< Hval_to : r n_to = None >>
| ExpandMode.Into =>
<< Hval_to : r n_to = Some (Value.GVertex v_to) >>
end.
(* r' is expanded from r by traversing one edge *)
Definition expansion_of (g : PropertyGraph.t) (r' r : Rcd.t)
(mode : ExpandMode.t)
(n_from n_edge n_to : Name.t)
(d : Pattern.direction) :=
exists v_from e v_to,
expansion_of' g r' r mode v_from e v_to n_from n_edge n_to d.
Import FilterMode.
Import ExpandMode.
Module ExecutionPlan.
Definition step0 := PropertyGraph.t -> option BindingTable.t.
Definition step1 := PropertyGraph.t -> BindingTable.t -> option BindingTable.t.
Module Type Spec.
(* scan_vertices (n : Name.t) : step0 *)
Parameter scan_vertices : Name.t -> step0.
(* filter_by_label (mode : FilterMode.t) (n : Name.t) (l : label) : step1 *)
Parameter filter_by_label : FilterMode.t -> Name.t -> label -> step1.
(* filter_by_property (mode : FilterMode.t) (n : Name.t) (key : Property.name) (value : Property.t) : step1 *)
Parameter filter_by_property : FilterMode.t -> Name.t -> Property.name -> Property.t -> step1.
(* expand (mode : ExpandMode.t) (n_from n_edge n_to : Name.t) (d : Pattern.direction) : step1 *)
Parameter expand : ExpandMode.t -> Name.t -> Name.t -> Name.t -> Pattern.direction -> step1.
(* return_all : step1 *)
Parameter return_all : step1.
(* traverse (slice : PatternSlice.t) (n_from : Name.t) : step1 *)
Parameter traverse : PatternSlice.t -> Name.t -> step1.
Section axioms.
Variable graph : PropertyGraph.t.
Variable table : BindingTable.t.
Variable table' : BindingTable.t.
Variable ty : BindingTable.T.
Require Import Maps.
Require Import PropertyGraph.
Require Import Cypher.
Require Import BindingTable.
Require Import Semantics.
Require Import PatternE.
Import PartialMap.Notations.
Import PropertyGraph.
Module FilterMode.
Inductive t : Type :=
| Vertices
| Edges
.
End FilterMode.
Module ExpandMode .
Inductive t : Type :=
| All
| Into
.
End ExpandMode.
(* r' is expanded from r by traversing one edge *)
Definition expansion_of' (g : PropertyGraph.t) (r' r : Rcd.t)
(mode : ExpandMode.t)
(v_from : vertex) (e : edge) (v_to : vertex)
(n_from n_edge n_to : Name.t)
(d : Pattern.direction) :=
<< HIn_e : In e (edges g) >> /\
<< Hdir : Path.matches_direction g v_from v_to e d >> /\
<< Hval_from : r n_from = Some (Value.GVertex v_from) >> /\
<< Hval_edge : r n_edge = None >> /\
<< Hval' : r' = (n_to |-> Value.GVertex v_to; n_edge |-> Value.GEdge e; r) >> /\
match mode with
| ExpandMode.All =>
<< Hval_to : r n_to = None >>
| ExpandMode.Into =>
<< Hval_to : r n_to = Some (Value.GVertex v_to) >>
end.
(* r' is expanded from r by traversing one edge *)
Definition expansion_of (g : PropertyGraph.t) (r' r : Rcd.t)
(mode : ExpandMode.t)
(n_from n_edge n_to : Name.t)
(d : Pattern.direction) :=
exists v_from e v_to,
expansion_of' g r' r mode v_from e v_to n_from n_edge n_to d.
Import FilterMode.
Import ExpandMode.
Module ExecutionPlan.
Definition step0 := PropertyGraph.t -> option BindingTable.t.
Definition step1 := PropertyGraph.t -> BindingTable.t -> option BindingTable.t.
Module Type Spec.
(* scan_vertices (n : Name.t) : step0 *)
Parameter scan_vertices : Name.t -> step0.
(* filter_by_label (mode : FilterMode.t) (n : Name.t) (l : label) : step1 *)
Parameter filter_by_label : FilterMode.t -> Name.t -> label -> step1.
(* filter_by_property (mode : FilterMode.t) (n : Name.t) (key : Property.name) (value : Property.t) : step1 *)
Parameter filter_by_property : FilterMode.t -> Name.t -> Property.name -> Property.t -> step1.
(* expand (mode : ExpandMode.t) (n_from n_edge n_to : Name.t) (d : Pattern.direction) : step1 *)
Parameter expand : ExpandMode.t -> Name.t -> Name.t -> Name.t -> Pattern.direction -> step1.
(* return_all : step1 *)
Parameter return_all : step1.
(* traverse (slice : PatternSlice.t) (n_from : Name.t) : step1 *)
Parameter traverse : PatternSlice.t -> Name.t -> step1.
Section axioms.
Variable graph : PropertyGraph.t.
Variable table : BindingTable.t.
Variable table' : BindingTable.t.
Variable ty : BindingTable.T.
If the inputs are well-formed then the operation will return the result
Axiom scan_vertices_wf : forall n,
PropertyGraph.wf graph ->
exists table', scan_vertices n graph = Some table'.
Axiom filter_vertices_by_label_wf : forall n l,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n = Some Value.GVertexT ->
exists table', filter_by_label Vertices n l graph table = Some table'.
Axiom filter_edges_by_label_wf : forall n l,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n = Some Value.GEdgeT ->
exists table', filter_by_label Edges n l graph table = Some table'.
Axiom filter_vertices_by_property_wf : forall n k val,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n = Some Value.GVertexT ->
exists table', filter_by_property Vertices n k val graph table = Some table'.
Axiom filter_edges_by_property_wf : forall n k val,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n = Some Value.GEdgeT ->
exists table', filter_by_property Edges n k val graph table = Some table'.
Axiom expand_all_wf : forall n_from n_edge n_to d,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n_from = Some Value.GVertexT -> ty n_edge = None -> ty n_to = None ->
exists table', expand All n_from n_edge n_to d graph table = Some table'.
Axiom expand_into_wf : forall n_from n_edge n_to d,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
ty n_from = Some Value.GVertexT -> ty n_edge = None -> ty n_to = Some Value.GVertexT ->
exists table', expand Into n_from n_edge n_to d graph table = Some table'.
Axiom return_all_wf :
exists table', return_all graph table = Some table'.
Axiom traverse_wf : forall slice n_from,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
PatternSlice.wf ty slice -> ty n_from = Some Value.GVertexT ->
exists table', traverse slice n_from graph table = Some table'.
If the operation returned some table then the type of the table is correct
Axiom scan_vertices_type : forall n,
scan_vertices n graph = Some table' ->
BindingTable.of_type table' (n |-> Value.GVertexT).
Axiom filter_by_label_type : forall mode n l,
filter_by_label mode n l graph table = Some table' ->
BindingTable.of_type table ty ->
BindingTable.of_type table' ty.
Axiom filter_by_property_type : forall mode n k val,
filter_by_property mode n k val graph table = Some table' ->
BindingTable.of_type table ty ->
BindingTable.of_type table' ty.
Axiom expand_type : forall mode n_from n_edge n_to d,
expand mode n_from n_edge n_to d graph table = Some table' ->
BindingTable.of_type table ty ->
BindingTable.of_type table'
(n_to |-> Value.GVertexT; n_edge |-> Value.GEdgeT; ty).
Axiom return_all_type :
return_all graph table = Some table' ->
BindingTable.of_type table ty ->
BindingTable.of_type table' (Rcd.explicit_projT ty).
Axiom traverse_type : forall slice n_from,
traverse slice n_from graph table = Some table' ->
BindingTable.of_type table ty -> PatternSlice.wf ty slice ->
BindingTable.of_type table' (PatternSlice.type_of ty slice).
scan_vertices specification
Axiom scan_vertices_spec : forall n v,
scan_vertices n graph = Some table' ->
In v (vertices graph) ->
In (n |-> Value.GVertex v) table'.
Axiom scan_vertices_spec' : forall n r',
scan_vertices n graph = Some table' ->
In r' table' -> exists v,
r' = (n |-> Value.GVertex v) /\ In v (vertices graph).
filter_by_label specification
Axiom filter_vertices_by_label_spec : forall n l v r,
filter_by_label Vertices n l graph table = Some table' ->
r n = Some (Value.GVertex v) -> In l (vlabels graph v) ->
In r table -> In r table'.
Axiom filter_vertices_by_label_spec' : forall n l r',
filter_by_label Vertices n l graph table = Some table' ->
In r' table' -> In r' table /\
exists v, r' n = Some (Value.GVertex v) /\ In l (vlabels graph v).
Axiom filter_edges_by_label_spec : forall n l e r,
filter_by_label Edges n l graph table = Some table' ->
r n = Some (Value.GEdge e) -> elabel graph e = l ->
In r table -> In r table'.
Axiom filter_edges_by_label_spec' : forall n l r',
filter_by_label Edges n l graph table = Some table' ->
In r' table' -> In r' table /\
exists e, r' n = Some (Value.GEdge e) /\ elabel graph e = l.
filter_by_property specification
Axiom filter_vertices_by_property_spec : forall n k val v r,
filter_by_property Vertices n k val graph table = Some table' ->
r n = Some (Value.GVertex v) -> get_vprop graph k v = Some val ->
In r table -> In r table'.
Axiom filter_vertices_by_property_spec' : forall n k val r',
filter_by_property Vertices n k val graph table = Some table' ->
In r' table' -> In r' table /\
exists v, r' n = Some (Value.GVertex v) /\
get_vprop graph k v = Some val.
Axiom filter_edges_by_property_spec : forall n k val e r,
filter_by_property Edges n k val graph table = Some table' ->
r n = Some (Value.GEdge e) -> get_eprop graph k e = Some val ->
In r table -> In r table'.
Axiom filter_edges_by_property_spec' : forall n k val r',
filter_by_property Edges n k val graph table = Some table' ->
In r' table' -> In r' table /\
exists e, r' n = Some (Value.GEdge e) /\
get_eprop graph k e = Some val.
expand specification
Axiom expand_spec : forall r r' mode n_from n_edge n_to d,
expand mode n_from n_edge n_to d graph table = Some table' ->
expansion_of graph r' r mode n_from n_edge n_to d ->
In r table -> In r' table'.
Axiom expand_spec' : forall r' mode n_from n_edge n_to d,
expand mode n_from n_edge n_to d graph table = Some table' -> In r' table' ->
exists r, In r table /\ expansion_of graph r' r mode n_from n_edge n_to d.
return_all specification
Axiom return_all_spec : forall r,
return_all graph table = Some table' ->
In r table -> In (Rcd.explicit_proj r) table'.
Axiom return_all_spec' : forall r',
return_all graph table = Some table' ->
In r' table' -> exists r, In r table /\ r' = Rcd.explicit_proj r.
traverse specification
Axiom traverse_spec : forall path r r' slice n_from,
PropertyGraph.wf graph -> PatternSlice.wf (Rcd.type_of r) slice ->
traverse slice n_from graph table = Some table' ->
PathSlice.matches graph r n_from r' path slice ->
In r table -> In r' table'.
Axiom traverse_spec' : forall r' slice n_from,
PropertyGraph.wf graph -> BindingTable.of_type table ty ->
PatternSlice.wf ty slice ->
traverse slice n_from graph table = Some table' ->
In r' table' -> exists r path, In r table /\
PathSlice.matches graph r n_from r' path slice.
End axioms.
End Spec.
Inductive t :=
| ScanVertices (n : Name.t)
| FilterByLabel (mode : FilterMode.t) (n : Name.t) (l : label) (plan : t)
| FilterByProperty (mode : FilterMode.t) (n : Name.t) (k : Property.name) (val : Property.t) (plan : t)
| Expand (mode : ExpandMode.t) (n_from n_edge n_to : Name.t) (d : Pattern.direction) (plan : t)
| ReturnAll (plan : t)
| Traverse (slice : PatternSlice.t) (n_from : Name.t) (plan : t)
.
Fixpoint type_of (plan : t) : BindingTable.T :=
match plan with
| ScanVertices n => n |-> Value.GVertexT
| FilterByLabel mode n l plan => type_of plan
| FilterByProperty mode n k val plan => type_of plan
| Expand mode n_from n_edge n_to d plan => n_to |-> Value.GVertexT; n_edge |-> Value.GEdgeT; type_of plan
| ReturnAll plan => Rcd.explicit_projT (type_of plan)
| Traverse slice n_from plan => PatternSlice.type_of (type_of plan) slice
end.
Lemma type_of_types plan k :
type_of plan k = Some Value.GVertexT \/
type_of plan k = Some Value.GEdgeT \/
type_of plan k = None.
Proof using.
induction plan; simpl in *.
all: unfold Rcd.explicit_projT.
all: autounfold with unfold_pat.
all: desf.
all: auto using PatternSlice.type_of__types.
Qed.
Fixpoint wf (plan : t) :=
match plan with
| ScanVertices n => True
| FilterByLabel Vertices n l plan =>
<< Htype : type_of plan n = Some Value.GVertexT >> /\
<< Hwf : wf plan >>
| FilterByLabel Edges n l plan =>
<< Htype : type_of plan n = Some Value.GEdgeT >> /\
<< Hwf : wf plan >>
| FilterByProperty Vertices n k val plan =>
<< Htype : type_of plan n = Some Value.GVertexT >> /\
<< Hwf : wf plan >>
| FilterByProperty Edges n k val plan =>
<< Htype : type_of plan n = Some Value.GEdgeT >> /\
<< Hwf : wf plan >>
| Expand All n_from n_edge n_to d plan =>
<< Htype_from : type_of plan n_from = Some Value.GVertexT >> /\
<< Htype_edge : type_of plan n_edge = None >> /\
<< Htype_to : type_of plan n_to = None >> /\
<< Hneq_from : n_from =/= n_edge >> /\
<< Hneq_to : n_to =/= n_edge >> /\
<< Hwf : wf plan >>
| Expand Into n_from n_edge n_to d plan =>
<< Htype_from : type_of plan n_from = Some Value.GVertexT >> /\
<< Htype_edge : type_of plan n_edge = None >> /\
<< Htype_to : type_of plan n_to = Some Value.GVertexT >> /\
<< Hneq_from : n_from =/= n_edge >> /\
<< Hneq_to : n_to =/= n_edge >> /\
<< Hwf : wf plan >>
| ReturnAll plan =>
<< Hwf : wf plan >>
| Traverse slice n_from plan =>
<< Htype : type_of plan n_from = Some Value.GVertexT >> /\
<< Hwf_slice : PatternSlice.wf (type_of plan) slice >> /\
<< Hwf : wf plan >>
end.
Module EvalPlan (S : Spec).
Import S.
#[local]
Hint Resolve scan_vertices_type filter_by_label_type filter_by_property_type
expand_type return_all_type traverse_type : type_axioms.
#[local]
Hint Resolve scan_vertices_wf
filter_vertices_by_label_wf filter_edges_by_label_wf
filter_vertices_by_property_wf filter_edges_by_property_wf
expand_all_wf expand_into_wf
return_all_wf traverse_wf : wf_axioms.
Section eval.
Variable graph : PropertyGraph.t.
Fixpoint eval (plan : ExecutionPlan.t) :=
match plan with
| ScanVertices n => scan_vertices n graph
| FilterByLabel mode n l plan =>
eval plan >>= filter_by_label mode n l graph
| FilterByProperty mode n k val plan =>
eval plan >>= filter_by_property mode n k val graph
| Expand mode n_from n_edge n_to d plan =>
eval plan >>= expand mode n_from n_edge n_to d graph
| ReturnAll plan => eval plan >>= return_all graph
| Traverse slice n_from plan =>
eval plan >>= traverse slice n_from graph
end.
End eval.
(* TODO: generalize the following for just the option_bind *)
Local Ltac eval_operation_reduce_aux Hres :=
simpl in Hres; unfold option_bind in Hres; desf; eauto.
Lemma eval_filter_by_label_reduce plan graph mode n l table'
(Hres : eval graph plan >>= filter_by_label mode n l graph = Some table') :
exists table, eval graph plan = Some table /\
filter_by_label mode n l graph table = Some table'.
Proof. eval_operation_reduce_aux Hres. Qed.
Lemma eval_filter_by_property_reduce plan graph mode n k val table'
(Hres : eval graph plan >>= filter_by_property mode n k val graph = Some table') :
exists table, eval graph plan = Some table /\
filter_by_property mode n k val graph table = Some table'.
Proof. eval_operation_reduce_aux Hres. Qed.
Lemma eval_expand_reduce plan graph mode n_from n_edge n_to d table'
(Hres : eval graph plan >>= expand mode n_from n_edge n_to d graph = Some table') :
exists table, eval graph plan = Some table /\
expand mode n_from n_edge n_to d graph table = Some table'.
Proof. eval_operation_reduce_aux Hres. Qed.
Lemma eval_traverse_reduce plan graph slice n_from table'
(Hres : eval graph plan >>= traverse slice n_from graph = Some table') :
exists table, eval graph plan = Some table /\
traverse slice n_from graph table = Some table'.
Proof. eval_operation_reduce_aux Hres. Qed.
Lemma eval_return_all_reduce plan graph table'
(Hres : eval graph plan >>= return_all graph = Some table') :
exists table, eval graph plan = Some table /\
return_all graph table = Some table'.
Proof. eval_operation_reduce_aux Hres. Qed.
Ltac eval_operation_reduce_impl Hres Hres' :=
let table := fresh "table" in
match type of Hres with
| eval _ _ >>= filter_by_label _ _ _ _ = Some _ =>
apply eval_filter_by_label_reduce in Hres as [table [Hres Hres']]
| eval _ _ >>= filter_by_property _ _ _ _ _ = Some _ =>
apply eval_filter_by_property_reduce in Hres as [table [Hres Hres']]
| eval _ _ >>= expand _ _ _ _ _ _ = Some _ =>
apply eval_expand_reduce in Hres as [table [Hres Hres']]
| eval _ _ >>= traverse _ _ _ = Some _ =>
apply eval_traverse_reduce in Hres as [table [Hres Hres']]
| eval _ _ >>= return_all _ = Some _ =>
apply eval_return_all_reduce in Hres as [table [Hres Hres']]
| _ => fail "the hypothesis is of the wrong form"
end.
Tactic Notation "eval_operation_reduce" "in" hyp(Hres) :=
let Hres' := fresh "Hres'" in
eval_operation_reduce_impl Hres Hres'.
Tactic Notation "eval_operation_reduce" "in" hyp(Hres) "eqn:" ident(Hres') :=
eval_operation_reduce_impl Hres Hres'.
Theorem eval_type_of plan graph table'
(Heval : eval graph plan = Some table')
(Hwf : wf plan) :
BindingTable.of_type table' (type_of plan).
Proof using.
generalize dependent table'.
induction plan; intros; simpl in *.
{ apply scan_vertices_type with graph. assumption. }
all: destruct (eval graph plan); try discriminate.
all: try destruct mode; desc.
all: eauto with type_axioms.
Qed.
Theorem eval_wf plan graph (Hwf : wf plan) (Hwf' : PropertyGraph.wf graph) :
exists table', eval graph plan = Some table'.
Proof with (try eassumption).
induction plan. all: simpl in *; desf; desf.
{ apply scan_vertices_wf... }
all: destruct IHplan as [table IH]...
all: rewrite IH; simpl.
all: eauto using eval_type_of with wf_axioms.
Qed.
End EvalPlan.
End ExecutionPlan.