sql_cli/sql/generators/
math_generators.rs

1use super::{create_two_column_table, TableGenerator};
2use crate::data::datatable::{DataColumn, DataTable, DataValue};
3use anyhow::Result;
4use std::sync::Arc;
5
6/// Generate Collatz sequence (3n+1 sequence)
7/// Famous unsolved problem: does every positive integer reach 1?
8pub 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
59/// Generate Pascal's triangle
60pub 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                    // Use the recurrence relation: C(n,k) = C(n-1,k-1) + C(n-1,k)
100                    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
133/// Generate triangular numbers: 1, 3, 6, 10, 15, ...
134pub 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
177/// Generate perfect squares
178pub 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
220/// Generate factorial sequence
221pub 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            // Limit to 20! to avoid overflow
250            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
271/// Helper function to generate Collatz sequence
272fn 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        // Safety limit to prevent infinite loops
284        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}