mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 16:23:12 +00:00
Pruning
This commit is contained in:
parent
05a1fbfbae
commit
1a0d6f4413
@ -437,9 +437,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stack_manipulation() {
|
fn stack_manipulation() {
|
||||||
let kernel = parse_and_assemble(&["%stack (a, b, c) -> (c, b, a)"]);
|
let pop = get_opcode("POP");
|
||||||
|
let swap1 = get_opcode("SWAP1");
|
||||||
let swap2 = get_opcode("SWAP2");
|
let swap2 = get_opcode("SWAP2");
|
||||||
|
|
||||||
|
let kernel = parse_and_assemble(&["%stack (a, b, c) -> (c, b, a)"]);
|
||||||
assert_eq!(kernel.code, vec![swap2]);
|
assert_eq!(kernel.code, vec![swap2]);
|
||||||
|
|
||||||
|
let kernel = parse_and_assemble(&["%stack (a, b, c) -> (b)"]);
|
||||||
|
assert_eq!(kernel.code, vec![pop, swap1, pop]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_and_assemble(files: &[&str]) -> Kernel {
|
fn parse_and_assemble(files: &[&str]) -> Kernel {
|
||||||
|
|||||||
@ -32,7 +32,6 @@ fn expand(names: Vec<String>, replacements: Vec<StackReplacement>) -> Vec<Item>
|
|||||||
})
|
})
|
||||||
.unique()
|
.unique()
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let all_ops = StackOp::all(unique_literals);
|
|
||||||
|
|
||||||
let mut dst = replacements
|
let mut dst = replacements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -50,13 +49,17 @@ fn expand(names: Vec<String>, replacements: Vec<StackReplacement>) -> Vec<Item>
|
|||||||
src.reverse();
|
src.reverse();
|
||||||
dst.reverse();
|
dst.reverse();
|
||||||
|
|
||||||
let path = shortest_path(src, dst, all_ops);
|
let path = shortest_path(src, dst, unique_literals);
|
||||||
path.into_iter().map(StackOp::into_item).collect()
|
path.into_iter().map(StackOp::into_item).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the lowest-cost sequence of `StackOp`s that transforms `src` to `dst`.
|
/// Finds the lowest-cost sequence of `StackOp`s that transforms `src` to `dst`.
|
||||||
/// Uses a variant of Dijkstra's algorithm.
|
/// Uses a variant of Dijkstra's algorithm.
|
||||||
fn shortest_path(src: Vec<StackItem>, dst: Vec<StackItem>, all_ops: Vec<StackOp>) -> Vec<StackOp> {
|
fn shortest_path(
|
||||||
|
src: Vec<StackItem>,
|
||||||
|
dst: Vec<StackItem>,
|
||||||
|
unique_literals: Vec<Literal>,
|
||||||
|
) -> Vec<StackOp> {
|
||||||
// Nodes to visit, starting with the lowest-cost node.
|
// Nodes to visit, starting with the lowest-cost node.
|
||||||
let mut queue = BinaryHeap::new();
|
let mut queue = BinaryHeap::new();
|
||||||
queue.push(Node {
|
queue.push(Node {
|
||||||
@ -90,7 +93,7 @@ fn shortest_path(src: Vec<StackItem>, dst: Vec<StackItem>, all_ops: Vec<StackOp>
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for op in &all_ops {
|
for op in next_ops(&node.stack, &dst, &unique_literals) {
|
||||||
let neighbor = match op.apply_to(node.stack.clone()) {
|
let neighbor = match op.apply_to(node.stack.clone()) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => continue,
|
None => continue,
|
||||||
@ -159,19 +162,51 @@ enum StackOp {
|
|||||||
Swap(u8),
|
Swap(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ops(src: Vec<StackItem>, dst: Vec<StackItem>) -> impl Iterator<Item = StackOp> {
|
/// A set of candidate operations to consider for the next step in the path from `src` to `dst`.
|
||||||
|
fn next_ops(src: &[StackItem], dst: &[StackItem], unique_literals: &[Literal]) -> Vec<StackOp> {
|
||||||
|
if let Some(top) = src.last() && !dst.contains(top) {
|
||||||
|
// If the top of src doesn't appear in dst, don't bother with anything other than a POP.
|
||||||
|
return vec![StackOp::Pop]
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ops = vec![StackOp::Pop];
|
||||||
|
|
||||||
|
ops.extend(
|
||||||
|
unique_literals
|
||||||
|
.iter()
|
||||||
|
// Only consider pushing this literal if we need more occurrences of it, otherwise swaps
|
||||||
|
// will be a better way to rearrange the existing occurrences as needed.
|
||||||
|
.filter(|lit| {
|
||||||
|
let item = StackItem::Literal((*lit).clone());
|
||||||
|
let src_count = src.iter().filter(|x| **x == item).count();
|
||||||
|
let dst_count = dst.iter().filter(|x| **x == item).count();
|
||||||
|
src_count < dst_count
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.map(StackOp::Push),
|
||||||
|
);
|
||||||
|
|
||||||
|
let src_len = src.len() as u8;
|
||||||
|
|
||||||
|
ops.extend(
|
||||||
|
(1..=src_len)
|
||||||
|
// Only consider duplicating this item if we need more occurrences of it, otherwise swaps
|
||||||
|
// will be a better way to rearrange the existing occurrences as needed.
|
||||||
|
.filter(|i| {
|
||||||
|
let item = &src[src.len() - *i as usize];
|
||||||
|
let src_count = src.iter().filter(|x| *x == item).count();
|
||||||
|
let dst_count = dst.iter().filter(|x| *x == item).count();
|
||||||
|
src_count < dst_count
|
||||||
|
})
|
||||||
|
.map(StackOp::Dup),
|
||||||
|
);
|
||||||
|
|
||||||
|
ops.extend((1..src_len).map(StackOp::Swap));
|
||||||
|
|
||||||
|
ops
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackOp {
|
impl StackOp {
|
||||||
fn all(literals: Vec<Literal>) -> Vec<Self> {
|
|
||||||
let mut all = literals.into_iter().map(StackOp::Push).collect_vec();
|
|
||||||
all.push(Pop);
|
|
||||||
all.extend((1..=32).map(StackOp::Dup));
|
|
||||||
all.extend((1..=32).map(StackOp::Swap));
|
|
||||||
all
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cost(&self) -> u32 {
|
fn cost(&self) -> u32 {
|
||||||
let (cpu_rows, memory_rows) = match self {
|
let (cpu_rows, memory_rows) = match self {
|
||||||
StackOp::Push(n) => {
|
StackOp::Push(n) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user