synthphonia/backward/
liststr.rs1
2
3use std::{collections::{HashMap, HashSet}, pin::pin};
4
5use simple_rc_async::task::{self, JoinHandle};
6
7use crate::{backward::str::HandleRcVec, closure, debg, expr::{cfg::Cfg, context::Context, ops::{self, Op1Enum}, Expr}, forward::executor::Executor, galloc::{self, AllocForAny, AllocForExactSizeIter}, never, solutions::new_thread_with_limit, utils::{select_ret, select_ret3, select_ret4}, value::Value};
8
9use super::{Deducer, Problem};
10
11#[derive(Debug)]
12pub struct ListDeducer {
16 pub nt: usize,
17 pub map: Option<Cfg>,
18 pub filter: Option<Cfg>,
19}
20
21impl Deducer for ListDeducer {
22 async fn deduce(&'static self, exec: &'static crate::forward::executor::Executor, prob: Problem) -> &'static crate::expr::Expr {
28 debg!("Deducing subproblem: {} {:?}", exec.cfg[self.nt].name, prob.value);
29 let task = exec.data[self.nt].all_eq.acquire(prob.value);
30
31 let futures = HandleRcVec::new();
32 let map_event = exec.data[self.nt].len().unwrap().listen_for_each(prob.value.length_inside().unwrap(), closure! { clone futures, clone prob; move |delimiter: Value| {
33 if self.map.is_some() {
34 futures.extend_iter(self.map(exec, prob, delimiter).into_iter());
35 }
36 None::<&'static Expr>
37 }});
38 let filter_event = exec.data[self.nt].contains.as_ref().unwrap().listen_for_each(prob.value, closure! { clone futures, clone prob; move |list: Value| {
39 if self.filter.is_some() && subseq_test(prob.value, list) {
40 futures.extend_iter(self.filter(exec, prob, list).into_iter());
41 }
42 None::<&'static Expr>
43 }});
44
45 select_ret4(pin!(map_event), pin!(filter_event), pin!(task), pin!(futures)).await
46 }
47}
48
49impl ListDeducer {
50 #[inline]
51 pub fn map(&'static self, exec: &'static Executor, mut prob: Problem, list: Value) -> Option<JoinHandle<&'static Expr>> {
53 if prob.used_cost >= 6 { return None; }
54 let p = prob.value.to_liststr();
55 if p.iter().all(|x| x.len() <= 2) { return None; }
56 let l = list.to_liststr();
57 assert!(p.iter().zip(l.iter()).all(|(a, b)| a.len() == b.len()));
58
59
60 let p = prob.value.flatten_leak();
61 let l = list.flatten_leak();
62 Some(task::spawn(async move {
63
64 let mut cfg = self.map.as_ref().unwrap().clone();
65 let ctx = Context::new(p.len(), vec![l.into()], vec![], p.into());
66 cfg.config.size_limit = 10;
67 cfg.config.time_limit = 1000;
68 let handle = new_thread_with_limit(cfg, ctx);
69 debg!("ListDeducer::map {:?} {:?} new thread {}", prob.value, list, handle.id());
70 let inner = exec.bridge.wait(handle).await;
71 let mut result = exec.data[prob.nt].all_eq.get(list);
72 Expr::Op1(Op1Enum::Map(ops::Map(Some(inner.alloc_local()))).galloc(), result).galloc()
73 }))
74 }
75 #[inline]
76 pub fn filter(&'static self, exec: &'static Executor, mut prob: Problem, list: Value) -> Option<JoinHandle<&'static Expr>> {
78 if prob.used_cost >= 6 { return None; }
79 let p = prob.value.to_liststr();
80 if p.iter().all(|x| x.len() <= 2) { return None; }
81 let l = list.to_liststr();
82 let mut io = HashMap::<&'static str, bool>::new();
83 if exec.size() > 7 { return None; }
84
85 for (p, l) in p.iter().zip(l.iter()) {
86 for elem in l.iter() {
87 match io.entry(elem) {
88 std::collections::hash_map::Entry::Occupied(o) => { if *o.get() != p.contains(elem) { return None } }
89 std::collections::hash_map::Entry::Vacant(v) => {v.insert(p.contains(elem)); }
90 }
91 }
92 }
93 let outputs = io.iter().map(|(_, o)| *o).galloc_scollect();
94 let inputs = io.into_iter().map(|(i, _)| i).galloc_scollect();
95
96 Some(task::spawn(async move {
97 let mut cfg = self.filter.as_ref().unwrap().clone();
98 let ctx = Context::new(outputs.len(), vec![inputs.into()], vec![], outputs.into());
99 cfg.config.size_limit = 10;
100 cfg.config.time_limit = 1000;
101 let handle = new_thread_with_limit(cfg, ctx);
102 debg!("ListDeducer::filter {:?} {:?} {:?} {:?} new thread {}", p, l, inputs, outputs, handle.id());
103 let inner = exec.bridge.wait(handle).await;
104 let mut result = exec.data[prob.nt].all_eq.get(list);
105 Expr::Op1(Op1Enum::Filter(ops::Filter(Some(inner.alloc_local()))).galloc(), result).galloc()
106 }))
107 }
108}
109
110fn subseq_test(sublist: Value, list: Value) -> bool {
111 let Value::ListStr(sublist) = sublist else { return false; };
112 let Value::ListStr(list) = list else { return false; };
113 let mut set = HashSet::new();
114 for (s, l) in sublist.iter().zip(list.iter()) {
115 let mut sublist_id = 0;
116 for p in l.iter() {
117 if sublist_id < s.len() && *p == s[sublist_id] {
118 set.insert(s[sublist_id]);
119 sublist_id += 1;
120 } else if set.contains(*p) {
121 return false;
122 }
123 }
124 if sublist_id != s.len() {
125 return false;
126 }
127 }
128
129 true
130}