use super::super::modes::*;
use super::super::prelude::*;
use super::Loc;
use super::agree::AgreementRA;
use super::algebra::Resource;
use super::algebra::ResourceAlgebra;
use super::pcm::PCM;
use super::product::ProductRA;
use super::storage_protocol::*;
use super::*;
verus! {
pub enum FractionRA {
Frac(real),
Invalid,
}
impl FractionRA {
pub open spec fn new(f: real) -> Self
recommends
0real < f <= 1real,
{
FractionRA::Frac(f)
}
pub open spec fn frac(self) -> real
recommends
self is Frac,
{
self->Frac_0
}
}
impl ResourceAlgebra for FractionRA {
open spec fn valid(self) -> bool {
match self {
FractionRA::Invalid => false,
FractionRA::Frac(frac) => (0 as real) < frac <= (1 as real),
}
}
open spec fn op(a: Self, b: Self) -> Self {
match (a, b) {
(FractionRA::Invalid, _) => FractionRA::Invalid,
(_, FractionRA::Invalid) => FractionRA::Invalid,
(FractionRA::Frac(a_frac), FractionRA::Frac(b_frac)) => {
if !a.valid() || !b.valid() {
FractionRA::Invalid
} else if a_frac + b_frac <= (1 as real) {
FractionRA::Frac(a_frac + b_frac)
} else {
FractionRA::Invalid
}
},
}
}
proof fn valid_op(a: Self, b: Self) {
}
proof fn commutative(a: Self, b: Self) {
}
proof fn associative(a: Self, b: Self, c: Self) {
}
}
pub proof fn lemma_whole_fraction_has_no_frame(a: FractionRA)
requires
a == FractionRA::Frac(1 as real),
ensures
forall|b: FractionRA|
#![trigger FractionRA::op(a, b).valid()]
!FractionRA::op(a, b).valid(),
{
assert forall|b: FractionRA|
#![trigger FractionRA::op(a, b).valid()]
!FractionRA::op(a, b).valid() by {
if FractionRA::op(a, b).valid() {
FractionRA::commutative(a, b);
FractionRA::valid_op(b, a);
assert(b.valid());
assert(b is Frac);
assert((0 as real) < b->Frac_0 <= (1 as real));
assert(a->Frac_0 + b->Frac_0 > (1 as real)); };
}
}
type FractionalCarrier<T> = ProductRA<FractionRA, AgreementRA<T>>;
pub tracked struct FracGhost<T> {
r: Resource<FractionalCarrier<T>>,
}
impl<T> FracGhost<T> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
&&& self.r.value().left is Frac
&&& self.r.value().right is Agree
}
pub closed spec fn id(self) -> Loc {
self.r.loc()
}
pub closed spec fn view(self) -> T {
self.r.value().right->Agree_0
}
pub closed spec fn frac(self) -> real {
self.r.value().left->Frac_0
}
pub open spec fn valid(self, id: Loc, frac: real) -> bool {
&&& self.id() == id
&&& self.frac() == frac
}
pub proof fn new(v: T) -> (tracked result: Self)
ensures
result.frac() == 1 as real,
result@ == v,
{
let f = FractionalCarrier {
left: FractionRA::Frac(1 as real),
right: AgreementRA::Agree(v),
};
let tracked r = Resource::alloc(f);
Self { r }
}
pub proof fn agree(tracked self: &Self, tracked other: &Self)
requires
self.id() == other.id(),
ensures
self@ == other@,
{
use_type_invariant(self);
use_type_invariant(other);
let tracked joined = self.r.join_shared(&other.r);
joined.validate()
}
pub proof fn take(tracked &mut self) -> (tracked result: Self)
ensures
result == *old(self),
{
self.bounded();
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
mself
}
pub proof fn split_to(tracked &mut self, result_frac: real) -> (tracked result: Self)
requires
(0 as real) < result_frac < old(self).frac(),
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
final(self)@ == old(self)@,
result@ == old(self)@,
final(self).frac() == old(self).frac() - result_frac,
result.frac() == result_frac,
{
self.bounded();
let self_frac = self.frac();
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
use_type_invariant(&mself);
let tracked (r1, r2) = mself.r.split(
FractionalCarrier {
left: FractionRA::Frac(self_frac - result_frac),
right: AgreementRA::Agree(mself@),
},
FractionalCarrier {
left: FractionRA::Frac(result_frac),
right: AgreementRA::Agree(mself@),
},
);
self.r = r1;
Self { r: r2 }
}
pub proof fn split(tracked &mut self) -> (tracked result: Self)
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
final(self)@ == old(self)@,
result@ == old(self)@,
final(self).frac() == old(self).frac() / 2 as real,
result.frac() == old(self).frac() / 2 as real,
{
self.bounded();
self.split_to(self.frac() / 2 as real)
}
pub proof fn combine(tracked &mut self, tracked other: Self)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@ == other@,
final(self).frac() == old(self).frac() + other.frac(),
{
self.bounded();
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
use_type_invariant(&mself);
use_type_invariant(&other);
let tracked mut r = mself.r;
r.validate_2(&other.r);
*self = Self { r: r.join(other.r) };
}
pub proof fn update(tracked &mut self, v: T)
requires
old(self).frac() == (1 as real),
ensures
final(self).id() == old(self).id(),
final(self)@ == v,
final(self).frac() == old(self).frac(),
{
self.bounded();
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
use_type_invariant(&mself);
let tracked mut r = mself.r;
let f = FractionalCarrier {
left: FractionRA::Frac(1 as real),
right: AgreementRA::Agree(v),
};
lemma_whole_fraction_has_no_frame(r.value().left);
*self = Self { r: r.update(f) };
}
pub proof fn update_with(tracked &mut self, tracked other: &mut Self, v: T)
requires
old(self).id() == old(other).id(),
old(self).frac() + old(other).frac() == 1 as real,
ensures
final(self).id() == old(self).id(),
final(other).id() == old(other).id(),
final(self).frac() == old(self).frac(),
final(other).frac() == old(other).frac(),
old(self)@ == old(other)@,
final(self)@ == v,
final(other)@ == v,
{
let ghost other_frac = other.frac();
other.bounded();
let tracked mut xother = Self::dummy();
tracked_swap(other, &mut xother);
self.bounded();
self.combine(xother);
self.update(v);
let tracked mut xother = self.split_to(other_frac);
tracked_swap(other, &mut xother);
}
pub proof fn bounded(tracked &self)
ensures
(0 as real) < self.frac() <= (1 as real),
{
use_type_invariant(self);
self.r.validate()
}
pub proof fn dummy() -> (tracked result: Self) {
Self::new(arbitrary())
}
}
}