dsntk_recognizer/
builder.rs1use crate::errors::*;
4use crate::recognizer::Recognizer;
5use crate::{AnnotationEntry, DecisionRule, DecisionTable, HitPolicy, InputClause, InputEntry, OutputClause, OutputEntry, RuleAnnotationClause};
6use dsntk_common::Result;
7
8struct Size {
9 input_clauses_count: usize,
10 input_values_count: usize,
11 output_clauses_count: usize,
12 output_components_count: usize,
13 output_values_count: usize,
14 annotation_clauses_count: usize,
15 rule_count: usize,
16}
17
18fn size_err(details: &str) -> Result<Size> {
19 Err(err_invalid_size(details))
20}
21
22fn validate_size(recognizer: &Recognizer) -> Result<Size> {
24 let input_clauses_count = recognizer.input_clause_count;
26 let input_expression_count = recognizer.input_expressions.len();
28 if input_expression_count != input_clauses_count {
29 return size_err(&format!(
30 "number of input expressions ({input_expression_count}) must be equal to the number of input clauses ({input_clauses_count})"
31 ));
32 }
33 let input_values_count = recognizer.allowed_input_values.len();
35 if input_values_count > 0 && input_values_count != input_clauses_count {
36 return size_err(&format!(
37 "number of input values ({input_values_count}) must be equal to the number of input clauses ({input_clauses_count})"
38 ));
39 }
40 let output_clauses_count = recognizer.output_clause_count;
42 if output_clauses_count == 0 {
43 return size_err("decision table must have minimum one output clause");
44 }
45 let output_components_count = recognizer.output_components.len();
47 if output_clauses_count > 1 {
48 if output_components_count != output_clauses_count {
49 return size_err(&format!(
50 "number of output components ({output_components_count}) must be equal to the number of output clauses ({output_clauses_count})"
51 ));
52 }
53 } else if output_components_count != 0 {
54 return size_err("number of output components must be zero");
55 }
56 let output_values_count = recognizer.allowed_output_values.len();
58 if output_values_count > 0 && output_values_count != output_clauses_count {
59 return size_err(&format!(
60 "number of output values ({output_values_count}) must be equal to the number of output clauses ({output_clauses_count})"
61 ));
62 }
63 let rule_count = recognizer.rule_count;
65 if rule_count == 0 {
66 return size_err("decision table must contain minimum one rule");
67 }
68 let input_entries_row_count = recognizer.input_entries.len();
70 if input_entries_row_count != rule_count {
71 return size_err(&format!(
72 "number of input entries ({input_entries_row_count}) must be equal to the number of rules ({rule_count})",
73 ));
74 }
75 for (row_index, row) in recognizer.input_entries.iter().enumerate() {
77 if row.len() != input_clauses_count {
78 return size_err(&format!(
79 "number of input entries ({}) must be equal to the number of input clauses ({input_clauses_count}) in row {row_index}",
80 row.len(),
81 ));
82 }
83 }
84 let output_entries_row_count = recognizer.output_entries.len();
86 if output_entries_row_count != rule_count {
87 return size_err(&format!(
88 "number of output entries ({output_entries_row_count}) must be equal to the number of rules ({rule_count})"
89 ));
90 }
91 for (row_index, row) in recognizer.output_entries.iter().enumerate() {
93 if row.len() != output_clauses_count {
94 return size_err(&format!(
95 "number of output entries ({}) must be equal to the number of output clauses ({output_clauses_count}) in row {row_index}",
96 row.len()
97 ));
98 }
99 }
100 let annotation_clauses_count = recognizer.annotation_clause_count;
102 if annotation_clauses_count > 0 {
103 let annotation_entries_row_count = recognizer.annotation_entries.len();
105 if annotation_entries_row_count != rule_count {
106 return size_err(&format!(
107 "number of annotation entries ({annotation_entries_row_count}) must be equal to the number of rules ({rule_count})"
108 ));
109 }
110 for (row_index, row) in recognizer.annotation_entries.iter().enumerate() {
112 if row.len() != annotation_clauses_count {
113 return size_err(&format!(
114 "number of annotation entries ({}) must be equal to the number of annotation clauses ({}) in row {}",
115 row.len(),
116 annotation_clauses_count,
117 row_index
118 ));
119 }
120 }
121 }
122 Ok(Size {
123 input_clauses_count,
124 input_values_count,
125 output_clauses_count,
126 output_components_count,
127 output_values_count,
128 annotation_clauses_count,
129 rule_count,
130 })
131}
132
133pub fn recognize(text: &str, trace: bool) -> Result<DecisionTable> {
135 let recognizer = Recognizer::recognize(text, trace)?;
137
138 let size = validate_size(&recognizer)?;
140
141 let information_item_name = recognizer.information_item_name.clone();
142 let hit_policy = recognizer.hit_policy;
143 let aggregation = if let HitPolicy::Collect(built_in_aggregator) = hit_policy {
144 Some(built_in_aggregator)
145 } else {
146 None
147 };
148 let preferred_orientation = recognizer.orientation;
149 let output_label = recognizer.output_label.clone();
150
151 let mut input_clauses = vec![];
152 for i in 0..size.input_clauses_count {
153 input_clauses.push(InputClause {
154 input_expression: recognizer.input_expressions[i].clone(),
155 allowed_input_values: if size.input_values_count > 0 {
156 recognizer.allowed_input_values[i].clone()
157 } else {
158 None
159 },
160 });
161 }
162
163 let mut output_clauses = vec![];
164 for i in 0..size.output_clauses_count {
165 output_clauses.push(OutputClause {
166 name: if size.output_components_count > 0 {
167 recognizer.output_components[i].clone()
168 } else {
169 None
170 },
171 allowed_output_values: if size.output_values_count > 0 {
172 recognizer.allowed_output_values[i].clone()
173 } else {
174 None
175 },
176 default_output_entry: None,
177 });
178 }
179
180 let mut annotations = vec![];
181 for i in 0..recognizer.annotation_clause_count {
182 annotations.push(RuleAnnotationClause {
183 name: recognizer.annotations[i].clone(),
184 });
185 }
186
187 let mut rules = vec![];
188 for rule_index in 0..size.rule_count {
189 let mut input_entries = vec![];
190 for column_index in 0..size.input_clauses_count {
191 let input_entry = InputEntry {
192 text: recognizer.input_entries[rule_index][column_index].clone(),
193 };
194 input_entries.push(input_entry);
195 }
196 let mut output_entries = vec![];
197 for column_index in 0..size.output_clauses_count {
198 let output_entry = OutputEntry {
199 text: recognizer.output_entries[rule_index][column_index].clone(),
200 };
201 output_entries.push(output_entry);
202 }
203 let mut annotation_entries = vec![];
204 for column_index in 0..size.annotation_clauses_count {
205 let annotation_entry = AnnotationEntry {
206 text: recognizer.annotation_entries[rule_index][column_index].clone(),
207 };
208 annotation_entries.push(annotation_entry);
209 }
210 rules.push(DecisionRule {
211 input_entries,
212 output_entries,
213 annotation_entries,
214 });
215 }
216
217 Ok(DecisionTable::new(
218 information_item_name,
219 input_clauses,
220 output_clauses,
221 annotations,
222 rules,
223 hit_policy,
224 aggregation,
225 preferred_orientation,
226 output_label,
227 ))
228}