kotoba_rewrite/rewrite/
matcher.rs

1//! ルールマッチング
2
3use kotoba_core::{ir::*, types::*};
4use kotoba_graph::graph::*;
5use std::collections::HashMap;
6use kotoba_core::types::Result;
7
8/// ルールマッチャー
9#[derive(Debug)]
10pub struct RuleMatcher;
11
12impl RuleMatcher {
13    pub fn new() -> Self {
14        Self
15    }
16
17    /// グラフに対してルールをマッチング
18    pub fn find_matches(&self, graph: &GraphRef, rule: &RuleIR, catalog: &Catalog) -> Result<Vec<Match>> {
19        let graph = graph.read();
20
21        // LHS(Left-hand side)のマッチング
22        let mut matches = Vec::new();
23
24        // 初期マッチング候補を生成
25        let initial_candidates = self.generate_initial_candidates(&graph, &rule.lhs);
26
27        for candidate in initial_candidates {
28            if self.match_lhs(&graph, &rule.lhs, &candidate, catalog) {
29                // NAC(Negative Application Condition)をチェック
30                if self.check_nacs(&graph, &rule.nacs, &candidate, catalog) {
31                    // ガード条件をチェック
32                    if self.check_guards(&graph, &rule.guards, &candidate, catalog) {
33                        let match_score = self.calculate_match_score(&candidate);
34                        matches.push(Match {
35                            mapping: candidate,
36                            score: match_score,
37                        });
38                    }
39                }
40            }
41        }
42
43        // スコアでソート
44        matches.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap());
45
46        Ok(matches)
47    }
48
49    /// 初期マッチング候補を生成
50    fn generate_initial_candidates(&self, graph: &Graph, lhs: &GraphPattern)
51        -> Vec<HashMap<String, VertexId>> {
52
53        if lhs.nodes.is_empty() {
54            return vec![HashMap::new()];
55        }
56
57        let mut candidates = Vec::new();
58
59        // 最初のノードから候補を生成
60        let first_node = &lhs.nodes[0];
61        let vertex_ids = if let Some(label) = &first_node.type_ {
62            graph.vertices_by_label(label)
63        } else {
64            graph.vertices.keys().cloned().collect()
65        };
66
67        for vertex_id in vertex_ids {
68            let mut mapping = HashMap::new();
69            mapping.insert(first_node.id.clone(), vertex_id);
70            candidates.push(mapping);
71        }
72
73        candidates
74    }
75
76    /// LHSパターンマッチング
77    fn match_lhs(&self, graph: &Graph, lhs: &GraphPattern,
78                 mapping: &HashMap<String, VertexId>, catalog: &Catalog) -> bool {
79
80        // ノードマッチング
81        for node in &lhs.nodes {
82            if let Some(&vertex_id) = mapping.get(&node.id) {
83                if let Some(vertex) = graph.get_vertex(&vertex_id) {
84                    // ラベルチェック
85                    if let Some(expected_label) = &node.type_ {
86                        if !vertex.labels.contains(expected_label) {
87                            return false;
88                        }
89                    }
90
91                    // プロパティチェック
92                    if let Some(expected_props) = &node.props {
93                        for (key, expected_value) in expected_props {
94                            if let Some(actual_value) = vertex.props.get(key) {
95                                if !self.values_match(actual_value, expected_value) {
96                                    return false;
97                                }
98                            } else {
99                                return false;
100                            }
101                        }
102                    }
103                } else {
104                    return false;
105                }
106            }
107        }
108
109        // エッジマッチング
110        for edge in &lhs.edges {
111            if let (Some(&src_id), Some(&dst_id)) = (mapping.get(&edge.src), mapping.get(&edge.dst)) {
112                // エッジが存在するかチェック
113                if !graph.adj_out.get(&src_id)
114                    .map(|neighbors| neighbors.contains(&dst_id))
115                    .unwrap_or(false) {
116                    return false;
117                }
118
119                // エッジラベルチェック(簡易版)
120                // 実際の実装ではエッジIDをマッピングに含める必要がある
121            }
122        }
123
124        true
125    }
126
127    /// NACチェック
128    fn check_nacs(&self, graph: &Graph, nacs: &[Nac],
129                  mapping: &HashMap<String, VertexId>, catalog: &Catalog) -> bool {
130
131        for nac in nacs {
132            // NACパターンがマッチしないことを確認
133            if self.match_nac(graph, nac, mapping, catalog) {
134                return false;
135            }
136        }
137
138        true
139    }
140
141    /// NACマッチング
142    fn match_nac(&self, graph: &Graph, nac: &Nac,
143                 mapping: &HashMap<String, VertexId>, _catalog: &Catalog) -> bool {
144
145        // NAC内のノードをマッチング
146        for node in &nac.nodes {
147            if let Some(&vertex_id) = mapping.get(&node.id) {
148                if let Some(vertex) = graph.get_vertex(&vertex_id) {
149                    // NAC条件に合致する場合、falseを返す
150                    if let Some(expected_label) = &node.type_ {
151                        if vertex.labels.contains(expected_label) {
152                            return true;
153                        }
154                    }
155                }
156            }
157        }
158
159        // NAC内のエッジをチェック
160        for edge in &nac.edges {
161            if let (Some(&src_id), Some(&dst_id)) = (mapping.get(&edge.src), mapping.get(&edge.dst)) {
162                if graph.adj_out.get(&src_id)
163                    .map(|neighbors| neighbors.contains(&dst_id))
164                    .unwrap_or(false) {
165                    return true;
166                }
167            }
168        }
169
170        false
171    }
172
173    /// ガード条件チェック
174    fn check_guards(&self, graph: &Graph, guards: &[Guard],
175                    mapping: &HashMap<String, VertexId>, _catalog: &Catalog) -> bool {
176
177        for guard in guards {
178            if !self.evaluate_guard(graph, guard, mapping, _catalog) {
179                return false;
180            }
181        }
182
183        true
184    }
185
186    /// ガード条件評価
187    fn evaluate_guard(&self, graph: &Graph, guard: &Guard,
188                      mapping: &HashMap<String, VertexId>, _catalog: &Catalog) -> bool {
189
190        match guard.ref_.as_str() {
191            "deg_ge" => {
192                // 次数 >= k のチェック
193                if let Some(Value::Int(k)) = guard.args.get("k") {
194                    if let Some(Value::String(var)) = guard.args.get("var") {
195                        if let Some(&vertex_id) = mapping.get(var) {
196                            let degree = graph.degree(&vertex_id);
197                            return degree >= *k as usize;
198                        }
199                    }
200                }
201                false
202            }
203            _ => {
204                // その他のガードはtrueとして扱う(実際の実装では関数テーブルを使用)
205                true
206            }
207        }
208    }
209
210    /// 値のマッチング
211    fn values_match(&self, actual: &Value, expected: &Value) -> bool {
212        match (actual, expected) {
213            (Value::Null, Value::Null) => true,
214            (Value::Bool(a), Value::Bool(b)) => a == b,
215            (Value::Int(a), Value::Int(b)) => a == b,
216            (Value::String(a), Value::String(b)) => a == b,
217            _ => false,
218        }
219    }
220
221    /// マッチスコア計算
222    fn calculate_match_score(&self, mapping: &HashMap<String, VertexId>) -> f64 {
223        // 簡易的なスコア計算(マッピングサイズに基づく)
224        mapping.len() as f64
225    }
226}