sql_cli/sql/generators/
math_generators.rs1use super::{create_two_column_table, TableGenerator};
2use crate::data::datatable::{DataColumn, DataTable, DataValue};
3use anyhow::Result;
4use std::sync::Arc;
5
6pub struct Collatz;
9
10impl TableGenerator for Collatz {
11 fn name(&self) -> &str {
12 "COLLATZ"
13 }
14
15 fn columns(&self) -> Vec<DataColumn> {
16 vec![DataColumn::new("step"), DataColumn::new("value")]
17 }
18
19 fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
20 if args.len() != 1 {
21 return Err(anyhow::anyhow!(
22 "COLLATZ expects 1 argument (starting number)"
23 ));
24 }
25
26 let start = match &args[0] {
27 DataValue::Integer(n) => *n as u64,
28 DataValue::Float(f) => *f as u64,
29 _ => {
30 return Err(anyhow::anyhow!(
31 "COLLATZ argument must be a positive number"
32 ))
33 }
34 };
35
36 if start == 0 {
37 return Err(anyhow::anyhow!("COLLATZ starting number must be positive"));
38 }
39
40 let sequence = collatz_sequence(start);
41 let rows: Vec<(DataValue, DataValue)> = sequence
42 .into_iter()
43 .enumerate()
44 .map(|(i, val)| (DataValue::Integer(i as i64), DataValue::Integer(val as i64)))
45 .collect();
46
47 Ok(create_two_column_table("collatz", "step", "value", rows))
48 }
49
50 fn description(&self) -> &str {
51 "Generate Collatz sequence (3n+1 sequence) until reaching 1"
52 }
53
54 fn arg_count(&self) -> usize {
55 1
56 }
57}
58
59pub struct PascalTriangle;
61
62impl TableGenerator for PascalTriangle {
63 fn name(&self) -> &str {
64 "PASCAL_TRIANGLE"
65 }
66
67 fn columns(&self) -> Vec<DataColumn> {
68 vec![
69 DataColumn::new("row"),
70 DataColumn::new("position"),
71 DataColumn::new("value"),
72 ]
73 }
74
75 fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
76 if args.len() != 1 {
77 return Err(anyhow::anyhow!(
78 "PASCAL_TRIANGLE expects 1 argument (number of rows)"
79 ));
80 }
81
82 let rows = match &args[0] {
83 DataValue::Integer(n) => *n as usize,
84 DataValue::Float(f) => *f as usize,
85 _ => return Err(anyhow::anyhow!("PASCAL_TRIANGLE rows must be a number")),
86 };
87
88 let mut table = DataTable::new("pascal");
89 table.add_column(DataColumn::new("row"));
90 table.add_column(DataColumn::new("position"));
91 table.add_column(DataColumn::new("value"));
92
93 for row in 0..rows {
94 let mut current_row = vec![1i64];
95 for col in 1..=row {
96 let val = if col == row {
97 1
98 } else {
99 let prev_val = if col > 0 && col <= current_row.len() {
101 current_row[col - 1]
102 } else {
103 0
104 };
105 prev_val * (row as i64 - col as i64 + 1) / col as i64
106 };
107 current_row.push(val);
108 }
109
110 for (pos, &val) in current_row.iter().enumerate() {
111 table
112 .add_row(crate::data::datatable::DataRow::new(vec![
113 DataValue::Integer(row as i64),
114 DataValue::Integer(pos as i64),
115 DataValue::Integer(val),
116 ]))
117 .unwrap();
118 }
119 }
120
121 Ok(Arc::new(table))
122 }
123
124 fn description(&self) -> &str {
125 "Generate Pascal's triangle with (row, position, value) format"
126 }
127
128 fn arg_count(&self) -> usize {
129 1
130 }
131}
132
133pub struct TriangularNumbers;
135
136impl TableGenerator for TriangularNumbers {
137 fn name(&self) -> &str {
138 "TRIANGULAR"
139 }
140
141 fn columns(&self) -> Vec<DataColumn> {
142 vec![DataColumn::new("n"), DataColumn::new("value")]
143 }
144
145 fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
146 if args.len() != 1 {
147 return Err(anyhow::anyhow!("TRIANGULAR expects 1 argument (count)"));
148 }
149
150 let count = match &args[0] {
151 DataValue::Integer(n) => *n as usize,
152 DataValue::Float(f) => *f as usize,
153 _ => return Err(anyhow::anyhow!("TRIANGULAR count must be a number")),
154 };
155
156 let mut rows = Vec::new();
157 for n in 1..=count {
158 let value = n * (n + 1) / 2;
159 rows.push((
160 DataValue::Integer(n as i64),
161 DataValue::Integer(value as i64),
162 ));
163 }
164
165 Ok(create_two_column_table("triangular", "n", "value", rows))
166 }
167
168 fn description(&self) -> &str {
169 "Generate triangular numbers (sum of first n natural numbers)"
170 }
171
172 fn arg_count(&self) -> usize {
173 1
174 }
175}
176
177pub struct Squares;
179
180impl TableGenerator for Squares {
181 fn name(&self) -> &str {
182 "SQUARES"
183 }
184
185 fn columns(&self) -> Vec<DataColumn> {
186 vec![DataColumn::new("n"), DataColumn::new("square")]
187 }
188
189 fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
190 if args.len() != 1 {
191 return Err(anyhow::anyhow!("SQUARES expects 1 argument (count)"));
192 }
193
194 let count = match &args[0] {
195 DataValue::Integer(n) => *n as usize,
196 DataValue::Float(f) => *f as usize,
197 _ => return Err(anyhow::anyhow!("SQUARES count must be a number")),
198 };
199
200 let mut rows = Vec::new();
201 for n in 1..=count {
202 rows.push((
203 DataValue::Integer(n as i64),
204 DataValue::Integer((n * n) as i64),
205 ));
206 }
207
208 Ok(create_two_column_table("squares", "n", "square", rows))
209 }
210
211 fn description(&self) -> &str {
212 "Generate perfect squares (n²)"
213 }
214
215 fn arg_count(&self) -> usize {
216 1
217 }
218}
219
220pub struct Factorials;
222
223impl TableGenerator for Factorials {
224 fn name(&self) -> &str {
225 "FACTORIALS"
226 }
227
228 fn columns(&self) -> Vec<DataColumn> {
229 vec![DataColumn::new("n"), DataColumn::new("factorial")]
230 }
231
232 fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
233 if args.len() != 1 {
234 return Err(anyhow::anyhow!("FACTORIALS expects 1 argument (count)"));
235 }
236
237 let count = match &args[0] {
238 DataValue::Integer(n) => *n as usize,
239 DataValue::Float(f) => *f as usize,
240 _ => return Err(anyhow::anyhow!("FACTORIALS count must be a number")),
241 };
242
243 let mut rows = Vec::new();
244 let mut factorial: i64 = 1;
245
246 rows.push((DataValue::Integer(0), DataValue::Integer(1)));
247
248 for n in 1..=count.min(20) {
249 factorial = factorial.saturating_mul(n as i64);
251 rows.push((DataValue::Integer(n as i64), DataValue::Integer(factorial)));
252 }
253
254 Ok(create_two_column_table(
255 "factorials",
256 "n",
257 "factorial",
258 rows,
259 ))
260 }
261
262 fn description(&self) -> &str {
263 "Generate factorial sequence (n!)"
264 }
265
266 fn arg_count(&self) -> usize {
267 1
268 }
269}
270
271fn collatz_sequence(mut n: u64) -> Vec<u64> {
273 let mut sequence = vec![n];
274
275 while n != 1 {
276 if n % 2 == 0 {
277 n /= 2;
278 } else {
279 n = n.saturating_mul(3).saturating_add(1);
280 }
281 sequence.push(n);
282
283 if sequence.len() > 1000 {
285 break;
286 }
287 }
288
289 sequence
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 #[test]
297 fn test_collatz_sequence() {
298 assert_eq!(collatz_sequence(5), vec![5, 16, 8, 4, 2, 1]);
299 assert_eq!(
300 collatz_sequence(7),
301 vec![7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
302 );
303 }
304}