From 3b55a325837f7048378c5856a4c946a54e383089 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 15 Feb 2024 17:21:41 -0500 Subject: [PATCH] finish up curry optimization on builtins --- crates/uplc/src/optimize/shrinker.rs | 201 +++++++++++++++++---------- 1 file changed, 127 insertions(+), 74 deletions(-) diff --git a/crates/uplc/src/optimize/shrinker.rs b/crates/uplc/src/optimize/shrinker.rs index fa9f6df3..06139c3d 100644 --- a/crates/uplc/src/optimize/shrinker.rs +++ b/crates/uplc/src/optimize/shrinker.rs @@ -1,6 +1,6 @@ use std::{ cmp::Ordering, - iter::{self, Peekable}, + iter::{self}, rc::Rc, vec, }; @@ -13,6 +13,7 @@ use pallas::ledger::primitives::babbage::{BigInt, PlutusData}; use crate::{ ast::{Constant, Data, Name, Program, Term, Type}, builtins::DefaultFunction, + parser::interner::Interner, }; #[derive(Eq, Hash, PartialEq, Clone, Debug, PartialOrd)] @@ -268,6 +269,22 @@ pub struct UplcNode { term: Term, } +#[derive(Eq, Hash, PartialEq, Clone, Debug)] +pub struct CurriedName { + func_name: String, + id_vec: Vec, +} + +impl CurriedName { + pub fn len(&self) -> usize { + self.id_vec.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[derive(PartialEq, Clone, Debug)] pub enum CurriedArgs { TwoArgs { @@ -673,46 +690,6 @@ impl Term { } } } - - fn traverse_to_scope<'a, 'b, I>(&'a mut self, scope: &mut Peekable) -> &'a mut Self - where - I: Iterator, - { - if scope.peek().is_none() { - self - } else { - match self { - Term::Apply { function, argument } => { - let scope_path = scope.next(); - - match scope_path.unwrap() { - ScopePath::FUNC => Self::traverse_to_scope(Rc::make_mut(function), scope), - ScopePath::ARG => Self::traverse_to_scope(Rc::make_mut(argument), scope), - } - } - Term::Delay(d) => { - let d = Rc::make_mut(d); - // First we recurse further to reduce the inner terms before coming back up to the Delay - Self::traverse_to_scope(d, scope) - } - Term::Lambda { body, .. } => { - let body = Rc::make_mut(body); - // First we recurse further to reduce the inner terms before coming back up to the Delay - Self::traverse_to_scope(body, scope) - } - - Term::Force(f) => { - let f = Rc::make_mut(f); - // First we recurse further to reduce the inner terms before coming back up to the Delay - Self::traverse_to_scope(f, scope) - } - Term::Case { .. } => todo!(), - Term::Constr { .. } => todo!(), - - _ => unreachable!("Incorrect scope path"), - } - } - } } impl Program { @@ -732,12 +709,6 @@ impl Program { } } - fn find_node_by_scope(&mut self, scope: &Scope) -> &mut Term { - let term = &mut self.term; - let iter = &mut scope.scope.iter().peekable(); - term.traverse_to_scope(iter) - } - pub fn lambda_reducer(self) -> Self { let mut lambda_applied_ids = vec![]; @@ -1103,10 +1074,11 @@ impl Program { // WIP pub fn builtin_curry_reducer(self) -> Self { let mut curried_terms = vec![]; - let mut id_mapped_curry_terms: IndexMap, (Scope, Term, bool)> = + let mut id_mapped_curry_terms: IndexMap, bool)> = IndexMap::new(); let mut curry_applied_ids = vec![]; - let mut other_thing: IndexMap)>> = IndexMap::new(); + let mut scope_mapped_to_term: IndexMap)>> = + IndexMap::new(); let a = self.traverse_uplc_with(&mut |_id, term, arg_stack, scope| match term { Term::Builtin(func) => { @@ -1156,34 +1128,40 @@ impl Program { id_only_vec.push(node.curried_id); + let curry_name = CurriedName { + func_name: func.aiken_name(), + id_vec: id_only_vec, + }; + if let Some((map_scope, _, multi_occurrences)) = - id_mapped_curry_terms.get_mut(&id_only_vec) + id_mapped_curry_terms.get_mut(&curry_name) { *map_scope = map_scope.common_ancestor(&scope); *multi_occurrences = true; } else if id_vec.is_empty() { id_mapped_curry_terms.insert( - id_only_vec, + curry_name, (scope.clone(), Term::Builtin(*func).apply(node.term), false), ); } else { - let var_name = id_vec - .iter() - .map(|item| item.curried_id.to_string()) - .collect::>() - .join("_"); + let var_name = format!( + "{}_{}", + func.aiken_name(), + id_vec + .iter() + .map(|item| item.curried_id.to_string()) + .collect::>() + .join("_") + ); id_mapped_curry_terms.insert( - id_only_vec, + curry_name, (scope.clone(), Term::var(var_name).apply(node.term), false), ); } - - curry_applied_ids.push(node.applied_id); } } } - Term::Constr { .. } => todo!(), Term::Case { .. } => todo!(), _ => {} @@ -1197,25 +1175,100 @@ impl Program { id_mapped_curry_terms .into_iter() .filter(|(_, (_, _, multi_occurrence))| *multi_occurrence) - .for_each(|(key, val)| { - let name = key.into_iter().map(|item| item.to_string()).join("_"); + .for_each(|(key, val)| match scope_mapped_to_term.get_mut(&val.0) { + Some(list) => { + let insert_position = list + .iter() + .position(|(list_key, _)| key.len() <= list_key.len()) + .unwrap_or(list.len()); - match other_thing.get_mut(&val.0) { - Some(list) => list.push((name, val.1)), - None => { - other_thing.insert(val.0, vec![(name, val.1)]); - } + list.insert(insert_position, (key, val.1)); + } + None => { + scope_mapped_to_term.insert(val.0, vec![(key, val.1)]); } }); - // other_thing - // .into_iter() - // .sorted_by(|item1, item2| item1.0.partial_cmp(&item2.0).expect("HOWWW?")) - // .for_each(|(scope, nodes_to_insert)| { - // // b.get_s - // }); + let mut b = a.traverse_uplc_with(&mut |id, term, arg_stack, scope| match term { + Term::Builtin(func) => { + if func.can_curry_builtin() { + let Some(curried_builtin) = + curried_terms.iter().find(|curry| curry.func == *func) + else { + return; + }; - todo!() + let builtin_args = BuiltinArgs::args_from_arg_stack( + arg_stack, + func.is_order_agnostic_builtin(), + ); + + let Some(id_vec) = curried_builtin.get_id_args(&builtin_args) else { + return; + }; + + let id_str = id_vec + .iter() + .map(|item| item.curried_id.to_string()) + .collect::>() + .join("_"); + + id_vec.iter().for_each(|item| { + curry_applied_ids.push(item.applied_id); + }); + + let name = format!("{}_{}", func.aiken_name(), id_str); + + *term = Term::var(name); + } + } + Term::Apply { function, .. } => { + let id = id.unwrap(); + + if curry_applied_ids.contains(&id) { + *term = function.as_ref().clone(); + } + + if let Some(insert_list) = scope_mapped_to_term.remove(scope) { + for (key, val) in insert_list.into_iter().rev() { + let name = format!( + "{}_{}", + key.func_name, + key.id_vec + .into_iter() + .map(|item| item.to_string()) + .join("_") + ); + + *term = term.clone().lambda(name).apply(val); + } + } + } + Term::Constr { .. } => todo!(), + Term::Case { .. } => todo!(), + _ => { + if let Some(insert_list) = scope_mapped_to_term.remove(scope) { + for (key, val) in insert_list.into_iter().rev() { + let name = format!( + "{}_{}", + key.func_name, + key.id_vec + .into_iter() + .map(|item| item.to_string()) + .join("_") + ); + + *term = term.clone().lambda(name).apply(val); + } + } + } + }); + + let mut interner = Interner::new(); + + interner.program(&mut b); + + b } }