use vstd::prelude::*;
verus! {
pub struct QualityHierarchy {
pub num_nodes: usize,
pub max_level: u64,
pub level: Vec<u64>,
pub cost: Vec<u64>,
pub parent: Vec<usize>,
pub edges: Vec<(usize, usize)>,
}
impl QualityHierarchy {
pub open spec fn lengths_ok(&self) -> bool {
self.level.len() == self.num_nodes
&& self.cost.len() == self.num_nodes
&& self.parent.len() == self.num_nodes
}
pub open spec fn levels_bounded(&self) -> bool {
forall|n: int| 0 <= n < self.num_nodes ==> #[trigger] self.level@[n] <= self.max_level
}
pub open spec fn parents_valid(&self) -> bool {
forall|n: int| 0 <= n < self.num_nodes ==> #[trigger] self.parent@[n] <= self.num_nodes
}
pub open spec fn edges_wf(&self) -> bool {
forall|e: int|
#![trigger self.edges@[e]]
0 <= e < self.edges.len() ==>
self.edges@[e].0 < self.num_nodes && self.edges@[e].1 < self.num_nodes
}
pub open spec fn type_invariant(&self) -> bool {
self.lengths_ok() && self.levels_bounded() && self.parents_valid() && self.edges_wf()
}
pub open spec fn strict_level_descent(&self) -> bool {
forall|e: int|
#![trigger self.edges@[e]]
0 <= e < self.edges.len() ==>
self.level@[self.edges@[e].0 as int] > self.level@[self.edges@[e].1 as int]
}
pub open spec fn parent_edge_agreement(&self) -> bool {
forall|e: int|
#![trigger self.edges@[e]]
0 <= e < self.edges.len() ==>
self.parent@[self.edges@[e].1 as int] == self.edges@[e].0
}
pub open spec fn cost_monotonicity(&self) -> bool {
forall|e: int|
#![trigger self.edges@[e]]
0 <= e < self.edges.len() ==>
self.cost@[self.edges@[e].0 as int] <= self.cost@[self.edges@[e].1 as int]
}
pub open spec fn is_null(&self, x: usize) -> bool {
x == self.num_nodes
}
pub open spec fn edge_exists(&self, p: usize, c: usize) -> bool {
exists|e: int| 0 <= e < self.edges.len() && #[trigger] self.edges@[e] == (p, c)
}
pub fn new(num_nodes: usize, max_level: u64) -> (h: QualityHierarchy)
ensures
h.num_nodes == num_nodes,
h.max_level == max_level,
h.edges@.len() == 0,
h.type_invariant(),
h.strict_level_descent(),
h.parent_edge_agreement(),
h.cost_monotonicity(),
forall|n: int| 0 <= n < num_nodes ==> h.level@[n] == 0,
forall|n: int| 0 <= n < num_nodes ==> h.cost@[n] == 0,
forall|n: int| 0 <= n < num_nodes ==> h.parent@[n] == num_nodes,
{
let mut level: Vec<u64> = Vec::new();
let mut cost: Vec<u64> = Vec::new();
let mut parent: Vec<usize> = Vec::new();
let mut i: usize = 0;
while i < num_nodes
invariant
i <= num_nodes,
level.len() == i,
cost.len() == i,
parent.len() == i,
forall|k: int| 0 <= k < i ==> level@[k] == 0,
forall|k: int| 0 <= k < i ==> cost@[k] == 0,
forall|k: int| 0 <= k < i ==> parent@[k] == num_nodes,
decreases num_nodes - i,
{
level.push(0);
cost.push(0);
parent.push(num_nodes);
i = i + 1;
}
QualityHierarchy { num_nodes, max_level, level, cost, parent, edges: Vec::new() }
}
pub fn level_of(&self, n: usize) -> (l: u64)
requires self.lengths_ok(), n < self.num_nodes,
ensures l == self.level@[n as int],
{
self.level[n]
}
pub fn cost_of(&self, n: usize) -> (c: u64)
requires self.lengths_ok(), n < self.num_nodes,
ensures c == self.cost@[n as int],
{
self.cost[n]
}
pub fn parent_of(&self, n: usize) -> (p: usize)
requires self.lengths_ok(), n < self.num_nodes,
ensures p == self.parent@[n as int],
{
self.parent[n]
}
pub fn has_children(&self, n: usize) -> (b: bool)
ensures b == (exists|e: int|
#![trigger self.edges@[e]] 0 <= e < self.edges.len() && self.edges@[e].0 == n),
{
let len = self.edges.len();
let mut i: usize = 0;
while i < len
invariant
i <= len,
len == self.edges.len(),
forall|e: int| #![trigger self.edges@[e]] 0 <= e < i ==> self.edges@[e].0 != n,
decreases len - i,
{
if self.edges[i].0 == n {
assert(self.edges@[i as int].0 == n);
return true;
}
i = i + 1;
}
false
}
pub fn can_add_child(&self, p: usize, c: usize) -> (b: bool)
requires
self.type_invariant(),
p < self.num_nodes,
c < self.num_nodes,
ensures
b == (p != c
&& !self.edge_exists(p, c)
&& self.parent@[c as int] == self.num_nodes
&& self.level@[p as int] > self.level@[c as int]
&& self.cost@[p as int] <= self.cost@[c as int]),
{
p != c
&& !self.has_edge(p, c)
&& self.parent_of(c) == self.num_nodes
&& self.level_of(p) > self.level_of(c)
&& self.cost_of(p) <= self.cost_of(c)
}
pub fn can_set_node_properties(&self, n: usize, l: u64, c: u64) -> (b: bool)
requires
self.type_invariant(),
n < self.num_nodes,
ensures
b == (!self.has_children_spec(n)
&& self.parent@[n as int] == self.num_nodes
&& l <= self.max_level
&& c <= self.max_level),
{
!self.has_children(n)
&& self.parent_of(n) == self.num_nodes
&& l <= self.max_level
&& c <= self.max_level
}
pub open spec fn has_children_spec(&self, n: usize) -> bool {
exists|e: int| 0 <= e < self.edges.len() && #[trigger] self.edges@[e].0 == n
}
pub fn has_edge(&self, p: usize, c: usize) -> (b: bool)
ensures b == self.edge_exists(p, c),
{
let len = self.edges.len();
let mut i: usize = 0;
while i < len
invariant
i <= len,
len == self.edges.len(),
forall|e: int| 0 <= e < i ==> #[trigger] self.edges@[e] != (p, c),
decreases len - i,
{
if self.edges[i].0 == p && self.edges[i].1 == c {
assert(self.edges@[i as int].0 == p);
assert(self.edges@[i as int].1 == c);
return true;
}
i = i + 1;
}
false
}
pub fn add_child(&mut self, p: usize, c: usize)
requires
old(self).type_invariant(),
old(self).strict_level_descent(),
old(self).parent_edge_agreement(),
old(self).cost_monotonicity(),
p < old(self).num_nodes,
c < old(self).num_nodes,
p != c,
!old(self).edge_exists(p, c), old(self).parent@[c as int] == old(self).num_nodes, old(self).level@[p as int] > old(self).level@[c as int], old(self).cost@[p as int] <= old(self).cost@[c as int], ensures
final(self).num_nodes == old(self).num_nodes,
final(self).max_level == old(self).max_level,
final(self).level@ == old(self).level@,
final(self).cost@ == old(self).cost@,
final(self).edges@ == old(self).edges@.push((p, c)),
final(self).parent@ == old(self).parent@.update(c as int, p),
final(self).type_invariant(),
final(self).strict_level_descent(),
final(self).parent_edge_agreement(),
final(self).cost_monotonicity(),
{
assert forall|e: int| #![trigger self.edges@[e]]
0 <= e < self.edges.len() implies self.edges@[e].1 != c by {
assert(self.parent@[self.edges@[e].1 as int] == self.edges@[e].0);
assert(self.edges@[e].0 < self.num_nodes);
}
self.edges.push((p, c));
self.parent.set(c, p);
}
pub fn set_node_properties(&mut self, n: usize, l: u64, c: u64)
requires
old(self).type_invariant(),
old(self).strict_level_descent(),
old(self).parent_edge_agreement(),
old(self).cost_monotonicity(),
n < old(self).num_nodes,
l <= old(self).max_level,
c <= old(self).max_level,
old(self).parent@[n as int] == old(self).num_nodes, forall|e: int| #![trigger old(self).edges@[e]]
0 <= e < old(self).edges.len() ==> old(self).edges@[e].0 != n,
ensures
final(self).num_nodes == old(self).num_nodes,
final(self).max_level == old(self).max_level,
final(self).parent@ == old(self).parent@,
final(self).edges@ == old(self).edges@,
final(self).level@ == old(self).level@.update(n as int, l),
final(self).cost@ == old(self).cost@.update(n as int, c),
final(self).type_invariant(),
final(self).strict_level_descent(),
final(self).parent_edge_agreement(),
final(self).cost_monotonicity(),
{
assert forall|e: int| #![trigger self.edges@[e]] 0 <= e < self.edges.len()
implies self.edges@[e].0 != n && self.edges@[e].1 != n by {
assert(self.parent@[self.edges@[e].1 as int] == self.edges@[e].0);
assert(self.edges@[e].0 < self.num_nodes);
}
self.level.set(n, l);
self.cost.set(n, c);
}
}
}