Skip to content

Commit 4cdb1ed

Browse files
authored
Merge pull request #17 from segeljakt/rust-reactive
Add Rust implementation of FlatFAT + Reactive Aggregator
2 parents 90edd58 + 5d74786 commit 4cdb1ed

File tree

4 files changed

+290
-0
lines changed

4 files changed

+290
-0
lines changed

rust/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ pub mod soe;
4949

5050
/// Two-Stacks
5151
pub mod two_stacks;
52+
53+
/// Reactive-Aggregator
54+
pub mod reactive;
55+

rust/src/reactive/flat_fat.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use alga::general::AbstractMonoid;
2+
use alga::general::Operator;
3+
use std::collections::HashSet;
4+
5+
pub trait FAT<Value, BinOp>
6+
where
7+
Value: AbstractMonoid<BinOp> + Clone,
8+
BinOp: Operator,
9+
{
10+
/// Creates a new FAT from a batch of values
11+
fn new(batch: &[Value]) -> Self;
12+
13+
/// Creates a new FAT with uninitialized values
14+
fn with_capacity(capacity: usize) -> Self;
15+
16+
/// Updates a non-contiguous batch of leaves
17+
fn update<I>(&mut self, batch: I)
18+
where
19+
I: IntoIterator<Item = (usize, Value)>;
20+
21+
/// Updates a contiguous batch of leaves
22+
fn update_ordered<I>(&mut self, values: I)
23+
where
24+
I: IntoIterator<Item = Value>;
25+
26+
/// Aggregates all nodes in the FAT and returns the result
27+
fn aggregate(&self) -> Value;
28+
29+
/// Aggregates a prefix of nodes in the FAT and returns the result
30+
fn prefix(&self, i: usize) -> Value;
31+
32+
/// Aggregates a suffix of nodes in the FAT and returns the result
33+
fn suffix(&self, i: usize) -> Value;
34+
}
35+
36+
pub struct FlatFAT<Value, BinOp>
37+
where
38+
Value: AbstractMonoid<BinOp> + Clone,
39+
BinOp: Operator,
40+
{
41+
/// A flat binary tree, indexed as:
42+
/// 0
43+
/// / \
44+
/// / \
45+
/// 1 2
46+
/// / \ / \
47+
/// 3 4 5 6
48+
pub(crate) tree: Vec<Value>,
49+
/// Number of leaves which can be stored in the tree
50+
pub(crate) capacity: usize,
51+
binop: std::marker::PhantomData<BinOp>,
52+
}
53+
54+
impl<Value, BinOp> FlatFAT<Value, BinOp>
55+
where
56+
Value: AbstractMonoid<BinOp> + Clone,
57+
BinOp: Operator,
58+
{
59+
/// Returns all leaf nodes of the tree
60+
pub(crate) fn leaves(&self) -> &[Value] {
61+
&self.tree[self.leaf(0)..]
62+
}
63+
/// Returns the index of the root node
64+
fn root(&self) -> usize {
65+
0
66+
}
67+
/// Returns the index of a leaf node
68+
fn leaf(&self, i: usize) -> usize {
69+
i + self.capacity - 1
70+
}
71+
/// Returns the index of an node's left child
72+
fn left(&self, i: usize) -> usize {
73+
2 * (i + 1) - 1
74+
}
75+
/// Returns the index of an node's right child
76+
fn right(&self, i: usize) -> usize {
77+
2 * (i + 1)
78+
}
79+
/// Returns the index of an node's parent
80+
fn parent(&self, i: usize) -> usize {
81+
(i - 1) / 2
82+
}
83+
}
84+
85+
impl<Value, BinOp> FAT<Value, BinOp> for FlatFAT<Value, BinOp>
86+
where
87+
Value: AbstractMonoid<BinOp> + Clone,
88+
BinOp: Operator,
89+
{
90+
fn new(values: &[Value]) -> Self {
91+
let capacity = values.len();
92+
let mut new = Self::with_capacity(capacity);
93+
new.update_ordered(values.iter().cloned());
94+
new
95+
}
96+
97+
fn with_capacity(capacity: usize) -> Self {
98+
assert_ne!(capacity, 0, "Capacity of window must be greater than 0");
99+
Self {
100+
tree: vec![Value::identity(); 2 * capacity - 1],
101+
binop: std::marker::PhantomData,
102+
capacity,
103+
}
104+
}
105+
106+
fn update<I>(&mut self, batch: I)
107+
where
108+
I: IntoIterator<Item = (usize, Value)>,
109+
{
110+
let mut parents: HashSet<usize> = batch
111+
.into_iter()
112+
.map(|(idx, val)| {
113+
let leaf = self.leaf(idx);
114+
self.tree[leaf] = val;
115+
self.parent(leaf)
116+
})
117+
.collect();
118+
let mut new_parents: HashSet<usize> = HashSet::new();
119+
loop {
120+
parents.drain().for_each(|parent| {
121+
let left = self.left(parent);
122+
let right = self.right(parent);
123+
self.tree[parent] = self.tree[left].operate(&self.tree[right]);
124+
if parent != self.root() {
125+
new_parents.insert(self.parent(parent));
126+
}
127+
});
128+
if new_parents.is_empty() {
129+
break;
130+
} else {
131+
std::mem::swap(&mut parents, &mut new_parents);
132+
}
133+
}
134+
}
135+
136+
fn update_ordered<I>(&mut self, values: I)
137+
where
138+
I: IntoIterator<Item = Value>,
139+
{
140+
values.into_iter().enumerate().for_each(|(idx, val)| {
141+
let leaf = self.leaf(idx);
142+
self.tree[leaf] = val;
143+
});
144+
(0..self.leaf(0)).into_iter().rev().for_each(|parent| {
145+
let left = self.left(parent);
146+
let right = self.right(parent);
147+
self.tree[parent] = self.tree[left].operate(&self.tree[right]);
148+
});
149+
}
150+
151+
fn aggregate(&self) -> Value {
152+
self.tree[self.root()].clone()
153+
}
154+
155+
fn prefix(&self, idx: usize) -> Value {
156+
let mut node = self.leaf(idx);
157+
let mut agg = self.tree[node].clone();
158+
while node != self.root() {
159+
let parent = self.parent(node);
160+
if node == self.right(parent) {
161+
let left = self.left(parent);
162+
agg = self.tree[left].operate(&agg);
163+
}
164+
node = parent;
165+
}
166+
return agg;
167+
}
168+
169+
fn suffix(&self, i: usize) -> Value {
170+
let mut node = self.leaf(i);
171+
let mut agg = self.tree[node].clone();
172+
while node != self.root() {
173+
let parent = self.parent(node);
174+
if node == self.left(parent) {
175+
agg = agg.operate(&self.tree[self.right(parent)]);
176+
}
177+
node = parent;
178+
}
179+
return agg;
180+
}
181+
}

rust/src/reactive/mod.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
pub(crate) mod flat_fat;
2+
3+
use crate::reactive::flat_fat::{FlatFAT, FAT};
4+
use crate::FifoWindow;
5+
use alga::general::AbstractMonoid;
6+
use alga::general::Operator;
7+
8+
pub struct Reactive<Value, BinOp>
9+
where
10+
Value: AbstractMonoid<BinOp> + Clone,
11+
BinOp: Operator,
12+
{
13+
fat: FlatFAT<Value, BinOp>,
14+
size: usize,
15+
front: usize,
16+
back: usize,
17+
}
18+
19+
impl<Value, BinOp> Reactive<Value, BinOp>
20+
where
21+
Value: AbstractMonoid<BinOp> + Clone,
22+
BinOp: Operator,
23+
{
24+
/// Returns a Reactive Aggregator with a pre-allocated `capacity`
25+
pub fn with_capacity(capacity: usize) -> Self {
26+
Self {
27+
fat: FlatFAT::with_capacity(capacity),
28+
size: 0,
29+
front: 0,
30+
back: 0,
31+
}
32+
}
33+
fn inverted(&self) -> bool {
34+
return self.front > self.back;
35+
}
36+
fn resize(&mut self, capacity: usize) {
37+
let leaves = self.fat.leaves();
38+
let mut fat = FlatFAT::with_capacity(capacity);
39+
if self.inverted() {
40+
fat.update_ordered(
41+
leaves[self.front..]
42+
.iter()
43+
.chain(leaves[..self.back].iter())
44+
.cloned(),
45+
);
46+
} else {
47+
fat.update_ordered(leaves[self.front..self.back].iter().cloned());
48+
}
49+
self.fat = fat;
50+
self.front = 0;
51+
self.back = self.size;
52+
}
53+
}
54+
55+
impl<Value, BinOp> FifoWindow<Value, BinOp> for Reactive<Value, BinOp>
56+
where
57+
Value: AbstractMonoid<BinOp> + Clone,
58+
BinOp: Operator,
59+
{
60+
fn new() -> Self {
61+
Self {
62+
fat: FlatFAT::with_capacity(8),
63+
size: 0,
64+
front: 0,
65+
back: 0,
66+
}
67+
}
68+
fn push(&mut self, v: Value) {
69+
self.fat.update([(self.back, v)].iter().cloned());
70+
self.size += 1;
71+
self.back += 1;
72+
if self.size > (3 * self.fat.capacity) / 4 {
73+
self.resize(self.fat.capacity * 2);
74+
}
75+
}
76+
fn pop(&mut self) {
77+
self.fat
78+
.update([(self.front, Value::identity())].iter().cloned());
79+
self.size -= 1;
80+
self.front += 1;
81+
if self.size <= self.fat.capacity / 4 {
82+
self.resize(self.fat.capacity / 2);
83+
}
84+
}
85+
fn query(&self) -> Value {
86+
if self.front > self.back {
87+
self.fat
88+
.suffix(self.front)
89+
.operate(&self.fat.prefix(self.back))
90+
} else {
91+
self.fat.aggregate()
92+
}
93+
}
94+
}

rust/tests/fifo-window.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use alga::general::Identity;
88
use alga::general::Operator;
99
use alga::general::TwoSidedInverse;
1010
use rand::Rng;
11+
use swag::reactive::*;
1112
use swag::recalc::*;
1213
use swag::soe::*;
1314
use swag::two_stacks::*;
@@ -122,3 +123,13 @@ fn test1_two_stacks() {
122123
fn test2_two_stacks() {
123124
test2::<TwoStacks<Value, Sum>>();
124125
}
126+
127+
#[test]
128+
fn test1_reactive() {
129+
test1::<Reactive<Value, Sum>>();
130+
}
131+
132+
#[test]
133+
fn test2_reactive() {
134+
test2::<Reactive<Value, Sum>>();
135+
}

0 commit comments

Comments
 (0)