Library OracleLanguages.OracleLanguage
Basic definitions about correlating oracles.
A correlating oracle is a program that realizes a relation between
reduction traces in such a way that the verification that this
relation holds between the reduction traces of two programs is
reduced to the proof of a program, more precisely to the proof
that an invariant holds during the evaluation of a Coq program.
We are interested in defining languages of correlating oracles,
each oracle language corresponding to a specific class of
relations. For instance, the oracle language of "renaming"s
contains all the oracles that relate pair of reduction traces
(tr₁, tr₂) where the configurations of tr₁ can be obtained by
a renaming of the configurations of tr₂.
An oracle language is characterized by a class of invariants that
is fulfilled by its inhabitants. The purpose of this invariant is
twofold: first, it represents the static property that holds
between the program configurations related by the oracle; second,
it is a sufficient condition for the oracle to effectively realize
a trace relation (i.e. the oracle must be “productive” and it must
relate actual program configurations).
Require Import Common.
Require Import ProgrammingLanguage.
Require Import ReductionTrace.
Require Import ReductionTracesRelation.
As with programming languages, we specify a record signature for
oracle languages. This signature is parameterized by two programming
languages, as an oracle relates a pair of programs written in
two potentially different programming languages.
Oracle languages are very similar to programming languages, except
they are not required to provide a decidable equality on their states.
Furthermore, oracle languages are equipped with projection functions
to recover left and right program states (left_state and right_state)
from an oracle state, as well as as left and right global environments
(left_genv and right_genv) from global oracle environments.
Oracle languages also provide a class of invariants invariant as well
as several proofs:
1. Proof invariant_1 that the invariant holds
2. Proof prediction_soundness that if an oracle configuration for which
invariant holds relates two program configurations, the oracle's
reduction function oracle_step is defined on this oracle state and
leads to an oracle state relating two program configurations reachable
from the previous ones.
Record oracle_language (L₁ L₂ : language) :=
{
oracle_state : Type;
oracle_genv : Type;
oracle_step : oracle_genv → oracle_state → option oracle_state;
left_state :
oracle_state → state L₁;
right_state :
oracle_state → state L₂;
left_genv :
oracle_genv → genv_type L₁;
right_genv :
oracle_genv → genv_type L₂;
invariant :
oracle_genv → oracle_state → Prop ;
invariant_1 :
∀ genv os os',
invariant genv os →
oracle_step genv os = Some os' →
invariant genv os';
prediction_soundness :
∀ genv os os',
invariant genv os →
oracle_step genv os = Some os' →
∃ n₁ n₂,
opt_state_eq (nsteps (left_genv genv) n₁ (left_state os))
(Some (left_state os'))
∧ opt_state_eq (nsteps (right_genv genv) n₂ (right_state os))
(Some (right_state os'))
∧ n₁ + n₂ > 0;
prediction_completeness :
∀ genv os,
invariant genv os →
oracle_step genv os = None →
step L₁ (left_genv genv) (left_state os) = None
∧ step L₂ (right_genv genv) (right_state os) = None;
}.
Definition oracle_correlation_relation
{L₁ L₂ : language} (OT : oracle_language L₁ L₂)
(genv : oracle_genv OT) (state : oracle_state OT)
: trace_relation L₁ L₂ :=
λ tr₁ tr₂,
let '(genv₁, S₁) := first tr₁ in
let '(genv₂, S₂) := first tr₂ in
trace L₁ (genv₁, S₁) tr₁ ∧ trace L₂ (genv₂, S₂) tr₂
∧ genv_eq L₁ (left_genv OT genv) genv₁
∧ genv_eq L₂ (right_genv OT genv) genv₂
∧ state_eq L₁ (left_state OT state) S₁
∧ state_eq L₂ (right_state OT state) S₂
∧ invariant OT genv state.
Definition correlation_relation
{L1 L2 : language} (OT : oracle_language L1 L2)
: trace_relation L1 L2 :=
λ tr₁ tr₂,
∃ genv os, oracle_correlation_relation OT genv os tr₁ tr₂.
An oracle realizes a relation between configurations of two languages.
CoFixpoint correlation_trace_from
{L₁ L₂ : language} (OT : oracle_language L₁ L₂)
(genv : oracle_genv OT)
(state : oracle_state OT)
: coplist (configuration L₁ × configuration L₂) :=
let c₁ := (left_genv OT genv, left_state OT state) in
let c₂ := (right_genv OT genv, right_state OT state) in
match oracle_step OT genv state with
| Some next_state ⇒
CCons _ (c₁, c₂) (correlation_trace_from OT genv next_state)
| None ⇒
CSingle _ (c₁, c₂)
end.
Definition left_trace {L1 L2 : language}
(cotrace : coplist (configuration L1 × configuration L2))
:= Common.map fst cotrace.
Definition right_trace {L1 L2 : language}
(cotrace : coplist (configuration L1 × configuration L2))
:= Common.map snd cotrace.
{L₁ L₂ : language} (OT : oracle_language L₁ L₂)
(genv : oracle_genv OT)
(state : oracle_state OT)
: coplist (configuration L₁ × configuration L₂) :=
let c₁ := (left_genv OT genv, left_state OT state) in
let c₂ := (right_genv OT genv, right_state OT state) in
match oracle_step OT genv state with
| Some next_state ⇒
CCons _ (c₁, c₂) (correlation_trace_from OT genv next_state)
| None ⇒
CSingle _ (c₁, c₂)
end.
Definition left_trace {L1 L2 : language}
(cotrace : coplist (configuration L1 × configuration L2))
:= Common.map fst cotrace.
Definition right_trace {L1 L2 : language}
(cotrace : coplist (configuration L1 × configuration L2))
:= Common.map snd cotrace.
If two traces are related by an oracle, then the oracle realizes a
relation between the configurations of these two traces.
Theorem oracle_relates_configurations_of_programs
{L₁ L₂ : language} (OT : oracle_language L₁ L₂) :
∀ (genv : oracle_genv OT) (state : oracle_state OT) tr₁ tr₂,
oracle_correlation_relation OT genv state tr₁ tr₂ →
let correlation_trace := correlation_trace_from OT genv state in
let subtr₁ := left_trace correlation_trace in
let subtr₂ := right_trace correlation_trace in
included_subtrace subtr₁ tr₁ ∧ included_subtrace subtr₂ tr₂.
{L₁ L₂ : language} (OT : oracle_language L₁ L₂) :
∀ (genv : oracle_genv OT) (state : oracle_state OT) tr₁ tr₂,
oracle_correlation_relation OT genv state tr₁ tr₂ →
let correlation_trace := correlation_trace_from OT genv state in
let subtr₁ := left_trace correlation_trace in
let subtr₂ := right_trace correlation_trace in
included_subtrace subtr₁ tr₁ ∧ included_subtrace subtr₂ tr₂.
The definition oracle_correlation_relation defined previously only depends on
the initial states of those traces, and exploiting them may rely on oracle-specific
knowledge.
Fortunately, every pair of traces related by an oracle are also related by a slightly
more general γ-correlation trace relation that abstracts away a few of the oracle
details.
Definition γ_from_oracle {L₁ L₂ : language}
(OT : oracle_language L₁ L₂) (genv : oracle_genv OT)
: configuration L₁ → configuration L₂ → Prop :=
λ c₁ c₂,
∃ os,
configuration_eq c₁ (left_genv OT genv, left_state OT os)
∧ configuration_eq c₂ (right_genv OT genv, right_state OT os)
∧ invariant OT genv os.
Theorem oracle_gamma_correlated
{L₁ L₂ : language} (OT : oracle_language L₁ L₂) :
∀ (genv : oracle_genv OT) (state : oracle_state OT) tr₁ tr₂,
oracle_correlation_relation OT genv state tr₁ tr₂ →
gamma_correlated (γ_from_oracle OT genv) tr₁ tr₂.
CoInductive oracle_eq {L₁ L₂ : language}
(OT₁ OT₂ : oracle_language L₁ L₂)
(genv₁ : oracle_genv OT₁) (genv₂ : oracle_genv OT₂) :
oracle_state OT₁ → oracle_state OT₂ → Prop :=
| OracleStuckEquality :
∀ os₁ os₂,
state_eq L₁ (left_state OT₁ os₁) (left_state OT₂ os₂) →
state_eq L₂ (right_state OT₁ os₁) (right_state OT₂ os₂) →
oracle_step OT₁ genv₁ os₁ = None →
oracle_step OT₂ genv₂ os₂ = None →
oracle_eq OT₁ OT₂ genv₁ genv₂ os₁ os₂
| OracleStepEquality :
∀ os₁ os₂ os₁' os₂',
state_eq L₁ (left_state OT₁ os₁) (left_state OT₂ os₂) →
state_eq L₂ (right_state OT₁ os₁) (right_state OT₂ os₂) →
oracle_step OT₁ genv₁ os₁ = Some os₁' →
oracle_step OT₂ genv₂ os₂ = Some os₂' →
oracle_eq OT₁ OT₂ genv₁ genv₂ os₁' os₂' →
oracle_eq OT₁ OT₂ genv₁ genv₂ os₁ os₂.
Lemma oracle_eq_refl:
∀ {L₁ L₂ : language} {OT : oracle_language L₁ L₂}
(genv : oracle_genv OT) (os : oracle_state OT),
oracle_eq OT OT genv genv os os.
Lemma oracle_eq_sym:
∀ {L₁ L₂ : language}
{OT₁ OT₂ : oracle_language L₁ L₂}
(genv₁ : oracle_genv OT₁) (genv₂ : oracle_genv OT₂)
(os₁ : oracle_state OT₁) (os₂ : oracle_state OT₂),
oracle_eq OT₁ OT₂ genv₁ genv₂ os₁ os₂ →
oracle_eq OT₂ OT₁ genv₂ genv₁ os₂ os₁.
Lemma oracle_eq_trans:
∀ {L₁ L₂ : language}
{OT₁ OT₂ OT₃ : oracle_language L₁ L₂}
(genv₁ : oracle_genv OT₁) (genv₂ : oracle_genv OT₂) (genv₃ : oracle_genv OT₃)
(os₁ : oracle_state OT₁) (os₂ : oracle_state OT₂) (os₃ : oracle_state OT₃),
oracle_eq OT₁ OT₂ genv₁ genv₂ os₁ os₂ →
oracle_eq OT₂ OT₃ genv₂ genv₃ os₂ os₃ →
oracle_eq OT₁ OT₃ genv₁ genv₃ os₁ os₃.
Definition oracle_nsteps {L₁ L₂} {OT : oracle_language L₁ L₂}
(genv : oracle_genv OT)
(n : nat) (os : oracle_state OT) :
option (oracle_state OT) := napply (oracle_step OT genv) n os.
Definition oracle_nsteps' {L₁ L₂} {OT : oracle_language L₁ L₂}
(genv : oracle_genv OT)
(n : nat)
(os : oracle_state OT) :
oracle_state OT × nat := napply' (oracle_step OT genv) n os.
Lemma oracle_nsteps_left:
∀ {L₁ L₂} {OT : oracle_language L₁ L₂} genv n os os',
invariant OT genv os →
oracle_nsteps genv n os = Some os' →
∃ n',
opt_state_eq (nsteps (left_genv OT genv) n' (left_state OT os))
(Some (left_state OT os')).
Lemma oracle_nsteps_right:
∀ {L₁ L₂} {OT : oracle_language L₁ L₂} genv n os os',
invariant OT genv os →
oracle_nsteps genv n os = Some os' →
∃ n',
opt_state_eq (nsteps (right_genv OT genv) n' (right_state OT os))
(Some (right_state OT os')).
Require Import Omega.
Lemma oracle_nsteps_termination:
∀ {L₁ L₂} {OT : oracle_language L₁ L₂}
(genv : oracle_genv OT)
(n n' n₁ n₂ : nat) (os os' : oracle_state OT)
S₁'' S₂'',
let S₁ := left_state OT os in
let S₂ := right_state OT os in
invariant OT genv os →
opt_state_eq (nsteps (left_genv OT genv) n₁ S₁) (Some S₁'') →
opt_state_eq (nsteps (right_genv OT genv) n₂ S₂) (Some S₂'') →
step L₁ (left_genv OT genv) S₁'' = None →
step L₂ (right_genv OT genv) S₂'' = None →
oracle_nsteps' genv n os = (os', n') →
n ≥ n₁ + n₂ →
let S₁' := left_state OT os' in
let S₂' := right_state OT os' in
state_eq L₁ S₁' S₁'' ∧ state_eq L₂ S₂' S₂'' ∧ invariant OT genv os'.
Lemma oracle_nsteps_termination'':
∀ {L₁ L₂} {OT : oracle_language L₁ L₂}
(genv : oracle_genv OT)
(os : oracle_state OT),
let S₁ := left_state OT os in
let S₂ := right_state OT os in
invariant OT genv os →
terminates (left_genv OT genv) S₁ →
terminates (right_genv OT genv) S₂ →
∃ n os',
oracle_nsteps genv n os = Some os'
∧ invariant OT genv os'
∧ let S₁' := left_state OT os' in
let S₂' := right_state OT os' in
step L₁ (left_genv OT genv) S₁' = None
∧ step L₂ (right_genv OT genv) S₂' = None.