Module MultiFixpoint
Require Import Maps.
Require Lattice.
Require Import Coqlib.
Require Import Iteration.
Require Import Classical.
Require Kildall.
Require List.
Module Solver (
NS:
Kildall.NODE_SET) (
L:
Lattice.SEMILATTICE_WITH_WIDENING).
Module NodeMap :=
PMap.
Definition node :=
positive.
Definition nodemap_ge m1 m2 :=
forall n,
L.ge m1!!
n m2!!
n.
Lemma nodemap_ge_refl:
forall m,
nodemap_ge m m.
Proof.
Lemma nodemap_ge_trans:
forall a b c,
nodemap_ge a b ->
nodemap_ge b c ->
nodemap_ge a c.
Proof.
Record state :=
mkstate
{
state_map :
NodeMap.t L.t;
state_unstable :
NS.t }.
Section WIDEN_SELECT.
Variable use_widening:
node ->
bool.
Definition lub_or_widen n :=
if use_widening n then L.widen else L.lub.
Lemma ge_lub_or_widen_left:
forall n x y,
L.ge (
lub_or_widen n x y)
x.
Proof.
Lemma ge_lub_or_widen_right:
forall n x y,
L.ge (
lub_or_widen n x y)
y.
Proof.
Definition update_once (
s :
state) (
n :
node) (
update :
L.t):
state :=
let map :=
s.(
state_map)
in
let previous :=
NodeMap.get n map in
let updated :=
lub_or_widen n previous update in
let changed :=
negb (
L.beq previous updated)
in
let map' :=
if changed
then NodeMap.set n updated map
else map in
if changed
then {|
state_map :=
map';
state_unstable :=
NS.add n s.(
state_unstable) |}
else s.
Lemma update_once_unstable_remains:
forall s n n' update
(
IN :
NS.In n s.(
state_unstable)),
NS.In n (
update_once s n' update).(
state_unstable).
Proof.
Definition increase_b n (
a b :
L.t) :=
negb (
L.beq a (
lub_or_widen n a b)).
Definition increase n a b :=
increase_b n a b =
true.
Lemma update_once_map_stable_remains:
forall s n update n'
(
NOT_IN : ~
NS.In n' (
update_once s n update).(
state_unstable)),
(
update_once s n update).(
state_map) !!
n' =
s.(
state_map) !!
n'.
Proof.
Definition update_multiple (
s0 :
state)
(
updates :
list (
node *
L.t)%
type):
state :=
List.fold_left (
fun s (
update : (
node *
L.t)%
type) =>
let (
node,
v) :=
update in
update_once s node v)
updates s0.
Lemma update_multiple_unstable_remains:
forall updates s n
(
IN :
NS.In n s.(
state_unstable)),
NS.In n (
update_multiple s updates).(
state_unstable).
Proof.
induction updates.
{
cbn.
auto. }
simpl update_multiple.
destruct a as [
n' update].
intros.
apply IHupdates.
apply update_once_unstable_remains.
assumption.
Qed.
Lemma update_multiple_map_stable_remains:
forall updates s n'
(
NOT_IN : ~
NS.In n' (
update_multiple s updates).(
state_unstable)),
(
update_multiple s updates).(
state_map) !!
n' =
s.(
state_map) !!
n'.
Proof.
Definition initialize :=
update_multiple
{|
state_map :=
NodeMap.init L.bot ;
state_unstable :=
NS.empty |}.
Lemma Nge_widen:
forall n a b c
(
NGE : ~
L.ge (
lub_or_widen n a b)
c),
~
L.ge a c.
Proof.
Lemma eq_widen_ge:
forall n a b
(
EQ :
L.eq a (
lub_or_widen n a b)), (
L.ge a b).
Proof.
Lemma update_once_greater2:
forall s n update,
(
L.ge ((
state_map (
update_once s n update)) !!
n)
update).
Proof.
Lemma update_once_greater1:
forall s n update n',
(
L.ge ((
state_map (
update_once s n update)) !!
n')
((
state_map s) !!
n')).
Proof.
Lemma update_multiple_greater1:
forall updates s n',
(
L.ge ((
state_map (
update_multiple s updates)) !!
n')
((
state_map s) !!
n')).
Proof.
Lemma update_multiple_greater2:
forall updates s n update
(
IN :
In (
n,
update)
updates),
(
L.ge ((
state_map (
update_multiple s updates)) !!
n)
update).
Proof.
induction updates;
intros.
contradiction.
destruct a as [
n0 update0].
destruct IN as [
FIRST |
OTHERS].
{
inv FIRST.
simpl update_multiple.
eapply L.ge_trans.
-
apply update_multiple_greater1.
-
apply update_once_greater2.
}
simpl update_multiple.
apply IHupdates.
assumption.
Qed.
Section STEP.
Variable f :
node ->
L.t ->
list (
node *
L.t)%
type.
Hypothesis f_strict :
forall n,
(
f n L.bot) =
nil.
Definition stabilized_node (
s :
state) (
n :
node) :=
forall (
n' :
node) (
v' :
L.t)
(
IN_UPDATE :
In (
n',
v') (
f n (
NodeMap.get n s.(
state_map))))
(
INCREASE : ~
L.ge (
NodeMap.get n' s.(
state_map))
v'),
NS.In n (
s.(
state_unstable)).
Lemma update_once_stabilized_remains:
forall s n nu update
(
STABLE :
stabilized_node s n),
stabilized_node (
update_once s nu update)
n.
Proof.
Lemma update_multiple_stabilized_remains:
forall updates s n
(
STABLE :
stabilized_node s n),
stabilized_node (
update_multiple s updates)
n.
Proof.
induction updates;
simpl update_multiple;
intros.
assumption.
destruct a as [
nu update].
apply IHupdates.
apply update_once_stabilized_remains.
assumption.
Qed.
Lemma stabilize_node:
forall s n,
stabilized_node
(
update_multiple s (
f n (
state_map s) !!
n))
n.
Proof.
Definition stability_invariant (
s :
state) :=
forall n, (
stabilized_node s n).
Lemma initialize_stable :
forall l, (
stability_invariant (
initialize l)).
Proof.
Definition step (
s :
state) :
option state :=
match NS.pick (
state_unstable s)
with
|
None =>
None
|
Some(
node,
unstable') =>
Some (
update_multiple {|
state_map :=
s.(
state_map);
state_unstable :=
unstable' |}
(
f node (
NodeMap.get node s.(
state_map))))
end.
Definition is_stable (
m :
NodeMap.t L.t) :=
forall (
n n':
node) (
v' :
L.t)
(
IN_UPDATE :
In (
n',
v') (
f n (
NodeMap.get n m))),
L.ge (
NodeMap.get n' m)
v'.
Lemma step_end :
forall s
(
INVARIANT :
stability_invariant s)
(
END : (
step s) =
None),
is_stable (
s.(
state_map)).
Proof.
Lemma step_invariant:
forall s s' (
INVARIANT : (
stability_invariant s))
(
STEP : (
step s) = (
Some s')),
(
stability_invariant s').
Proof.
Definition step_ret :=
fun s =>
match step s with
|
None =>
inl s.(
state_map)
|
Some s' =>
inr s'
end.
Definition next_fixpoint :=
PrimIter.iterate _ _
step_ret.
Lemma next_fixpoint_solves :
forall s (
INVARIANT :
stability_invariant s)
m
(
SOLVED : (
next_fixpoint s) =
Some m),
is_stable m.
Proof.
Lemma step_ge:
forall s s' (
STEP : (
step s) = (
Some s')),
(
nodemap_ge s'.(
state_map)
s.(
state_map)).
Proof.
Lemma next_fixpoint_ge :
forall s0 m
(
SOLVED : (
next_fixpoint s0) =
Some m),
nodemap_ge m s0.(
state_map).
Proof.
Variable initial :
list (
node *
L.t)%
type.
Definition solution_opt :=
next_fixpoint (
initialize initial).
Lemma solution_stable :
forall solution,
solution_opt =
Some solution ->
is_stable solution.
Proof.
Lemma solution_includes_initial :
forall solution node v
(
SOL :
solution_opt =
Some solution)
(
IN :
In (
node,
v)
initial),
L.ge (
solution !!
node)
v.
Proof.
Section INVARIANT.
Variable P :
L.t ->
Prop.
Hypothesis P_bot :
P L.bot.
Hypothesis P_widen :
forall n x y,
P x ->
P y ->
P (
lub_or_widen n x y).
Hypothesis P_f :
forall n v n' v',
P v ->
In (
n',
v') (
f n v) ->
P v'.
Hypothesis P_initial :
forall n v,
In (
n,
v)
initial ->
P v.
Definition P_state s :=
forall n,
P (
PMap.get n s.(
state_map)).
Definition update_once_P:
forall s n update
(
BEFORE :
P_state s)
(
UPDATE :
P update),
(
P_state (
update_once s n update)).
Proof.
Definition update_multiple_P:
forall updates s
(
BEFORE :
P_state s)
(
UPDATE :
forall n' v',
In (
n',
v')
updates ->
P v'),
(
P_state (
update_multiple s updates)).
Proof.
induction updates;
intros.
assumption.
destruct a as (
n',
v').
simpl update_multiple.
apply IHupdates.
{
apply update_once_P.
assumption.
{
eapply UPDATE.
cbn.
left.
reflexivity.
}
}
intros.
eapply UPDATE.
cbn.
right.
eassumption.
Qed.
Lemma step_P:
forall s (
BEFORE :
P_state s)
s'
(
STEP : (
step s) =
Some s'),
(
P_state s').
Proof.
intros.
unfold step in *.
destruct NS.pick. 2:
discriminate.
destruct p as [
n v].
inv STEP.
apply update_multiple_P.
assumption.
intros.
eauto.
Qed.
Lemma next_fixpoint_P :
forall s (
INVARIANT :
P_state s)
m'
(
SOLVED : (
next_fixpoint s) =
Some m')
n,
P (
PMap.get n m').
Proof.
Lemma initialize_P:
P_state (
initialize initial).
Proof.
Lemma solution_P :
forall solution,
solution_opt =
Some solution ->
forall n,
P (
PMap.get n solution).
Proof.
End INVARIANT.
End STEP.
End WIDEN_SELECT.
End Solver.