Files
@ 48b0400c877f
Branch filter:
Location: CSY/reowolf/src/runtime/experimental/predicate.rs
48b0400c877f
8.1 KiB
application/rls-services+xml
clearer input output wiring
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | use crate::common::*;
use crate::runtime::ProtocolS;
use core::ops::Index;
use core::ops::IndexMut;
use std::collections::BTreeMap;
// we assume a dense ChannelIndex domain!
enum CommonSatisfier<T> {
FormerNotLatter,
LatterNotFormer,
Equivalent,
New(T),
Nonexistant,
}
type ChunkType = u16;
const MASK_BITS: ChunkType = 0x_AA_AA; // 101010...
#[test]
fn mask_ok() {
assert_eq!(!0, MASK_BITS | (MASK_BITS >> 1));
assert_eq!(0, MASK_BITS & (MASK_BITS >> 1));
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct TernChunk(ChunkType); // invariant: no pair is 01
impl TernChunk {
fn overwrite(&mut self, index: usize, value: bool) -> Option<bool> {
assert!(index < Self::vars_per_chunk());
let mask_bit_mask = 1 << (index * 2 + 1);
let bool_bit_mask = 1 << (index * 2);
let ret = if self.0 & mask_bit_mask != 0 {
let was_value = self.0 & bool_bit_mask != 0;
if was_value != value {
// flip the value bit
self.0 ^= bool_bit_mask;
}
Some(was_value)
} else {
if value {
// set the value bit
self.0 |= bool_bit_mask;
}
None
};
// set the mask bit
self.0 |= mask_bit_mask;
ret
}
fn new_singleton(index: usize, value: bool) -> Self {
assert!(index < Self::vars_per_chunk());
let mask_bits = 1 << (index * 2 + 1);
let maybe_bit: ChunkType = value as ChunkType;
assert_eq!(maybe_bit == 1, value);
assert!(maybe_bit <= 1);
let bool_bits = maybe_bit << (index * 2);
Self(mask_bits | bool_bits)
}
const fn vars_per_chunk() -> usize {
std::mem::size_of::<ChunkType>() / 2
}
#[inline]
fn query(self, index: usize) -> Option<bool> {
assert!(index < Self::vars_per_chunk());
let mask_bit_mask = 1 << (index * 2 + 1);
let bool_bit_mask = 1 << (index * 2);
if self.0 & mask_bit_mask != 0 {
Some(self.0 & bool_bit_mask != 0)
} else {
None
}
}
fn mutual_satisfaction(self, othe: Self) -> [bool; 2] {
let s_mask = self.0 & MASK_BITS;
let o_mask = othe.0 & MASK_BITS;
let both_mask = s_mask & o_mask;
let diff = self.0 ^ othe.0;
let masked_diff = diff & (both_mask >> 1);
if masked_diff != 0 {
[false; 2]
} else {
let s_sat_o = s_mask & !o_mask == 0;
let o_sat_s = o_mask & !s_mask == 0;
[s_sat_o, o_sat_s]
}
}
/// Returns whether self satisfies other
/// false iff either:
/// 1. there exists a pair which you specify and I dont.
// i.e., self has 00, othe has 1?
/// 2. we both specify a variable with different values.
/// i.e., self has 10, othe has 11 or vice versa.
fn satisfies(self, othe: Self) -> bool {
let s_mask = self.0 & MASK_BITS;
let o_mask = othe.0 & MASK_BITS;
let both_mask = s_mask & o_mask;
let diff = self.0 ^ othe.0;
// FALSE if othe has a 1X pair where self has a 1(!X) pair
let masked_diff = diff & (both_mask >> 1);
// FALSE if othe has a 1X pair where self has a 0Y pair.
let o_not_s_mask = o_mask & !s_mask;
o_not_s_mask | masked_diff == 0
}
fn common_satisfier(self, othe: Self) -> Option<Self> {
let s_mask = self.0 & MASK_BITS;
let o_mask = othe.0 & MASK_BITS;
let both_mask = s_mask & o_mask;
let diff = self.0 ^ othe.0;
let masked_diff = diff & (both_mask >> 1);
if masked_diff != 0 {
// an inconsistency exists
None
} else {
let s_vals = (s_mask >> 1) & self.0;
let o_vals = (o_mask >> 1) & othe.0;
let new = s_mask | o_mask | s_vals | o_vals;
Some(Self(new))
}
}
}
struct TernSet(Vec<TernChunk>); // invariant: last byte != 00
impl TernSet {
fn new_singleton(index: ChannelIndex, value: bool) -> Self {
let which_chunk = index as usize / TernChunk::vars_per_chunk();
let inner_index = index as usize % TernChunk::vars_per_chunk();
let it = std::iter::repeat(TernChunk(0))
.take(which_chunk)
.chain(std::iter::once(TernChunk::new_singleton(inner_index, value)));
Self(it.collect())
}
fn overwrite(&mut self, index: ChannelIndex, value: bool) -> Option<bool> {
let which_chunk = index as usize / TernChunk::vars_per_chunk();
let inner_index = index as usize % TernChunk::vars_per_chunk();
if let Some(tern_chunk) = self.0.get_mut(which_chunk) {
tern_chunk.overwrite(inner_index, value)
} else {
self.0.reserve(which_chunk - self.0.len());
self.0.resize(which_chunk, TernChunk(0));
self.0.push(TernChunk::new_singleton(inner_index, value));
None
}
}
fn query(&self, index: ChannelIndex) -> Option<bool> {
let which_chunk = index as usize / TernChunk::vars_per_chunk();
self.0.get(which_chunk).copied().and_then(move |tern_chunk| {
tern_chunk.query(index as usize % TernChunk::vars_per_chunk())
})
}
fn satisfies(&self, othe: &Self) -> bool {
self.0.len() >= othe.0.len() && self.0.iter().zip(&othe.0).all(|(s, o)| s.satisfies(*o))
}
fn common_satisfier(&self, othe: &Self) -> CommonSatisfier<Self> {
use CommonSatisfier as Cs;
let [slen, olen] = [self.0.len(), othe.0.len()];
let [mut s_sat_o, mut o_sat_s] = [slen >= olen, slen <= olen];
for (s, o) in self.0.iter().zip(&othe.0) {
let [s2, o2] = s.mutual_satisfaction(*o);
s_sat_o &= s2;
o_sat_s &= o2;
}
match [s_sat_o, o_sat_s] {
[true, true] => Cs::Equivalent,
[true, false] => Cs::FormerNotLatter,
[false, true] => Cs::LatterNotFormer,
[false, false] => Cs::New(Self(
self.0.iter().zip(&othe.0).map(|(s, o)| s.common_satisfier(*o).unwrap()).collect(),
)),
}
}
#[inline]
fn restore_invariant(&mut self) {
while self.0.iter().copied().last() == Some(TernChunk(0)) {
self.0.pop();
}
}
fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
struct Predicate(BTreeMap<ControllerId, TernSet>);
impl Predicate {
pub fn overwrite(&mut self, channel_id: ChannelId, value: bool) -> Option<bool> {
let ChannelId { controller_id, channel_index } = channel_id;
use std::collections::btree_map::Entry;
match self.0.entry(controller_id) {
Entry::Occupied(mut x) => x.get_mut().overwrite(channel_index, value),
Entry::Vacant(x) => {
x.insert(TernSet::new_singleton(channel_index, value));
None
}
}
}
pub fn query(&self, channel_id: ChannelId) -> Option<bool> {
let ChannelId { controller_id, channel_index } = channel_id;
self.0.get(&controller_id).and_then(move |tern_set| tern_set.query(channel_index))
}
pub fn satisfies(&self, other: &Self) -> bool {
let mut s_it = self.0.iter();
let mut s = if let Some(s) = s_it.next() {
s
} else {
return other.0.is_empty();
};
for (oid, ob) in other.0.iter() {
while s.0 < oid {
s = if let Some(s) = s_it.next() {
s
} else {
return false;
};
}
if s.0 > oid || !s.1.satisfies(ob) {
return false;
}
}
true
}
pub fn common_satisfier(&self, othe: &Self) -> CommonSatisfier<Self> {
// use CommonSatisfier as Cs;
// let [slen, olen] = [self.0.len(), othe.0.len()];
// let [mut s_sat_o, mut o_sat_s] = [slen >= olen, slen <= olen];
// let [mut s_it, mut o_it] = [self.0.iter(), othe.0.iter()];
// let [mut s, mut o] = [s_it.next(), o_it.next()];
todo!()
}
}
////////////////////////////
|