pattern_compiler/
matrix.rs

1use ::std::collections::HashSet;
2
3use ::prettytable::Table;
4
5use ::petgraph::graph::NodeIndex;
6
7use ::either::Either;
8
9use super::pattern::PatternProvider;
10
11#[derive(Debug, Derivative)]
12#[derivative(Clone(bound=""))]
13pub struct MatchMatrix<P> where P: PatternProvider {
14    pub data: Vec<MatchMatrixElement<P>>,
15
16    pub variables: Vec<P::CfgVariable>,
17    pub clause_leaves: Vec<super::cfg::CfgNodeIndex>,
18}
19
20#[derive(Debug, Derivative)]
21#[derivative(Clone(bound=""))]
22pub struct MatchMatrixElement<P> where P: PatternProvider {
23    pub node: P::PatternNodeKey,
24    pub variable_num: usize,
25    pub clause_num: usize,
26}
27
28fn chunks_len<'a, T>(entities: &'a [T], chunk_len: usize, num_chunks: usize)
29                     -> Box<Iterator<Item = &'a [T]> + 'a> {
30
31    assert!(entities.len() == (chunk_len * num_chunks));
32    let ret = if chunk_len == 0 {
33        Either::Left((0..num_chunks).map(|_| [].as_ref()))
34    } else {
35        Either::Right(entities.chunks(chunk_len))
36    };
37    Box::new(ret)
38}
39
40impl<P> MatchMatrix<P> where P: PatternProvider {
41
42    pub fn new(nodes: &[P::PatternNodeKey],
43               leaves: Vec<super::cfg::CfgNodeIndex>,
44               vars: Vec<P::CfgVariable>) -> Self {
45        assert!(vars.len() * leaves.len() == nodes.len());
46
47        let data = if vars.len() == 0 {
48            vec![]
49        } else {
50            nodes.chunks(vars.len()).enumerate()
51                .flat_map(|(clause_idx, clause)| {
52                    clause.iter().enumerate().map(move |(variable_idx, pat)| {
53                        MatchMatrixElement {
54                            variable_num: variable_idx,
55                            clause_num: clause_idx,
56                            node: *pat,
57                        }
58                    })
59                }).collect()
60        };
61
62        MatchMatrix {
63            data: data,
64            variables: vars,
65            clause_leaves: leaves,
66        }
67    }
68
69    /// Selects which variable should be specialized on in this matrix.
70    /// This will always select the variable which has the most consecutive
71    /// wildcards from the top, as this will minimize the amount of
72    /// comparisons we will have to perform.
73    pub fn select_specialize_variable(&self, pattern: &P) -> usize
74    {
75        let mut sums = vec![(0, true); self.variables.len()];
76
77        let clauses = self.data.chunks(self.variables.len());
78        for clause in clauses {
79            for variable_pattern in clause.iter() {
80                if pattern.is_wildcard(pattern.get_kind(variable_pattern.node)) {
81                    sums[variable_pattern.variable_num].1 = false;
82                } else {
83                    if sums[variable_pattern.variable_num].1 {
84                        sums[variable_pattern.variable_num].0 += 1;
85                    }
86                }
87            }
88        }
89
90        sums.iter().enumerate()
91            .max_by_key(|&(_, s)| s.0)
92            .map(|(i, _)| i).unwrap()
93    }
94
95    pub fn get_var(&self, var: usize) -> P::CfgVariable {
96        self.variables[var]
97    }
98
99    /// Constructs a set of all node kinds in the given variable in the given pattern
100    pub fn collect_specialization_types<'a>(&self, pattern: &'a P,
101                                            variable: usize)
102                                            -> HashSet<P::PatternNodeKind>
103    {
104        let mut types = HashSet::new();
105
106        let clauses = self.data.chunks(self.variables.len());
107        for clause in clauses {
108            let variable_pattern = &clause[variable];
109            types.insert(pattern.get_kind(variable_pattern.node));
110        }
111
112        types.remove(&pattern.get_wildcard());
113
114        types
115    }
116
117    pub fn specialize(&self, ctx: &mut super::MatchCompileContext<P>,
118                         variable: usize,
119                         on: P::PatternNodeKind)
120                         -> (Vec<P::CfgVariable>, MatchMatrix<P>)
121    {
122
123        // 1: Collect rows that should be included in the specialization
124        let to_specialize_rows: Vec<(usize, &[MatchMatrixElement<_>])> = self.data
125            .chunks(self.variables.len())
126            .enumerate()
127            .filter(|&(_, node)| ctx.pattern.kind_includes(on, node[variable].node))
128            .collect();
129
130        // 2: Split rows into list of specialization nodes, and the rest
131        let specialize_nodes: Vec<&MatchMatrixElement<_>> = to_specialize_rows.iter()
132            .map(|&(_, nodes)| &nodes[variable])
133            .collect();
134        let rest_nodes: Vec<Vec<&MatchMatrixElement<_>>> = to_specialize_rows.iter()
135            .map(|&(_, nodes)| {
136                nodes.iter()
137                    .filter(|node| node.variable_num != variable)
138                    .collect::<Vec<_>>()
139            })
140            .collect();
141
142        // 3: Generate specialized by PatternProvider::expand_clause_nodes
143        let specialized = {
144            let nodes: Vec<_> = specialize_nodes.iter()
145                .map(|node| node.node)
146                .collect();
147            ctx.pattern.expand_clause_nodes(nodes)
148        };
149
150        // 4: Merge specialized with rest from step 2 and return new matrix
151        //let specialized_chunked = specialized.nodes
152        //    .chunks(specialized.variables.len());
153        let specialized_chunked = chunks_len(&specialized.nodes, specialized.variables.len(),
154                                             specialized.clauses);
155
156        let new_nodes: Vec<_> = specialized_chunked
157            .zip(rest_nodes.iter())
158            .flat_map(|(specialized, rest)| {
159                let specialized_m = specialized.iter().map(|node| *node);
160                let rest_m = rest.iter().map(|node| node.node);
161
162                specialized_m.chain(rest_m)
163            })
164            .collect();
165
166        let new_clause_leaves: Vec<_> = to_specialize_rows.iter()
167            .map(|&(clause_num, _)| self.clause_leaves[clause_num])
168            .collect();
169
170        let new_variables: Vec<_> = {
171            let rest_variables = self.variables.iter()
172                .enumerate()
173                .filter(|&(var_num, _)| var_num != variable)
174                .map(|(_, var)| *var);
175
176            specialized.variables.iter()
177                .map(|var| *var)
178                .chain(rest_variables)
179                .collect()
180        };
181
182        let new_mat = Self::new(new_nodes.as_slice(),
183                                new_clause_leaves, new_variables);
184        (specialized.variables, new_mat)
185    }
186
187    pub fn iterate_clauses<'a>(&'a self) -> Box<Iterator<Item = (NodeIndex, &'a [MatchMatrixElement<P>])> + 'a> {
188        let iter = self.clause_leaves.iter().map(|l| *l)
189            .zip(chunks_len(&self.data, self.variables.len(), self.clause_leaves.len()));
190
191        Box::new(iter)
192    }
193
194    pub fn default(&self, ctx: &mut super::MatchCompileContext<P>,
195                   variable: usize)
196                   -> (Vec<P::CfgVariable>, MatchMatrix<P>)
197    {
198        let wildcard = ctx.pattern.get_wildcard();
199        self.specialize(ctx, variable, wildcard)
200    }
201
202    pub fn is_empty(&self) -> bool {
203        self.clause_leaves.len() == 0
204    }
205
206    pub fn has_wildcard_head(&self, pattern: &P)
207                             -> Option<super::cfg::CfgNodeIndex>
208    {
209
210        assert!(self.clause_leaves.len() > 0);
211        if self.variables.len() == 0 {
212            Some(self.clause_leaves[0])
213        } else {
214            let has_wildcard_head = self.data
215                .chunks(self.variables.len())
216                .next().unwrap()
217                .iter().all(|p| {
218                    pattern.is_wildcard(pattern.get_kind(p.node))
219                });
220            if has_wildcard_head {
221                Some(self.clause_leaves[0])
222            } else {
223                None
224            }
225        }
226    }
227
228    pub fn to_table(&self, pat: &P) -> Table {
229        use ::prettytable::Cell;
230
231        let mut table = Table::new();
232
233        {
234            let head_row = table.add_empty_row();
235            head_row.add_cell(Cell::new(&format!(
236                "{}*{}=={}",
237                self.variables.len(),
238                self.clause_leaves.len(),
239                self.data.len())));
240            for variable in self.variables.iter() {
241                let var_str = format!("{:?}", variable);
242                head_row.add_cell(Cell::new(&var_str));
243            }
244        }
245
246        for row_idx in 0..self.clause_leaves.len() {
247            let t_row = table.add_empty_row();
248            let leaf_id = format!("{:?}", self.clause_leaves[row_idx]);
249            t_row.add_cell(Cell::new(&leaf_id));
250
251            let row_start = row_idx * self.variables.len();
252            for col in &self.data[row_start..(row_start+self.variables.len())] {
253                let node = pat.get_kind(col.node);
254                let cell_fmt = format!("{:?}", node);
255                let cell = Cell::new(&cell_fmt);
256                t_row.add_cell(cell);
257            }
258        }
259
260        table
261    }
262
263}