sokobo
Loading...
Searching...
No Matches
cli.cpp
1#include <algorithm>
2#include <cctype>
3#include <cmath>
4#include <exception>
5#include <iostream>
6#include <memory>
7#include <sstream>
8#include <stdexcept>
9#include <string>
10#include <vector>
11
12#include "include/cli.h"
13
14#include "include/calculus.h"
15#include "include/complex_number.h"
16#include "include/differential_equations.h"
17#include "include/expression.h"
18#include "include/fourier.h"
19#include "include/laplace.h"
20#include "include/numerical_methods.h"
21#include "include/polynomial.h"
22
23void CAS_CLI::run()
24{
25 std::cout << "=== sokobo - Computational Algebra System ===" << '\n';
26 std::cout << "Type 'help' for available commands or 'quit' to exit." << '\n';
27
28 std::string line;
29 while (true) {
30 std::cout << "sokobo > ";
31 if (!std::getline(std::cin, line)) {
32 break;
33 }
34
35 // Trim whitespace
36 line.erase(0, line.find_first_not_of(" \t"));
37 line.erase(line.find_last_not_of(" \t") + 1);
38
39 if (line.empty()) {
40 continue;
41 }
42 if (line == "quit" || line == "exit") {
43 break;
44 }
45
46 std::vector<std::string> tokens = split(line);
47 if (tokens.empty()) {
48 continue;
49 }
50
51 try {
52 std::string cmd = tokens[0];
53 std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);
54
55 if (cmd == "help") {
56 showHelp();
57 } else if (cmd == "clear") {
58 clearAll();
59 } else if (cmd == "list") {
60 listObjects();
61 } else if (cmd == "expr") {
62 handleExpression(tokens);
63 } else if (cmd == "deriv") {
64 handleDerivative(tokens);
65 } else if (cmd == "integral") {
66 handleIntegral(tokens);
67 } else if (cmd == "limit") {
68 handleLimit(tokens);
69 } else if (cmd == "series") {
70 handleSeries(tokens);
71 } else if (cmd == "poly") {
72 handlePolynomial(tokens);
73 } else if (cmd == "peval") {
74 handlePolynomialEvaluate(tokens);
75 } else if (cmd == "padd") {
76 handlePolynomialAdd(tokens);
77 } else if (cmd == "pmult") {
78 // handlePolynomialMultiply(tokens);
79 } else if (cmd == "pgcd") {
80 // handlePolynomialGCD(tokens);
81 } else if (cmd == "proots") {
82 handlePolynomialRoots(tokens);
83 } else if (cmd == "pfactor") {
84 // handlePolynomialFactor(tokens);
85 } else if (cmd == "complex") {
86 handleComplex(tokens);
87 } else if (cmd == "cadd") {
88 handleComplexAdd(tokens);
89 } else if (cmd == "cmult") {
90 handleComplexMultiply(tokens);
91 } else if (cmd == "cpower") {
92 handleComplexPower(tokens);
93 } else if (cmd == "croots") {
94 handleComplexRoots(tokens);
95 } else if (cmd == "matrix") {
96 handleMatrix(tokens);
97 } else if (cmd == "matrix_raw") {
98 handleMatrixRaw(tokens);
99 } else if (cmd == "madj") {
100 handleMatrixAdjoint(tokens);
101 } else if (cmd == "mdisp") {
102 handleMatrixDisplay(tokens);
103 } else if (cmd == "mrank") {
104 handleMatrixRank(tokens);
105 } else if (cmd == "mset") {
106 handleMatrixSet(tokens);
107 } else if (cmd == "mdet") {
108 handleMatrixDeterminant(tokens);
109 } else if (cmd == "minv") {
110 handleMatrixInverse(tokens);
111 } else if (cmd == "meigen") {
112 handleMatrixEigenvalues(tokens);
113 } else if (cmd == "meigenv") {
114 handleMatrixEigenvectors(tokens);
115 } else if (cmd == "laplace") {
116 handleLaplace(tokens);
117 } else if (cmd == "fourier") {
118 handleFourier(tokens);
119 } else if (cmd == "ode") {
120 handleODE(tokens);
121 } else if (cmd == "pde") {
122 handlePDE(tokens);
123 } else if (cmd == "root") {
124 // handleRootFind(tokens);
125 } else if (cmd == "optimize") {
126 // handleOptimize(tokens);
127 } else if (cmd == "interpolate") {
128 // handleInterpolate(tokens);
129 } else {
130 std::cout << "Unknown command: " << cmd << '\n';
131 std::cout << "Type 'help' for available commands." << '\n';
132 }
133 } catch (const std::exception& e) {
134 std::cout << "Error: " << e.what() << '\n';
135 }
136 }
137
138 std::cout << "Goodbye!" << '\n';
139}
140
141std::vector<std::string> CAS_CLI::split(const std::string& str)
142{
143 std::vector<std::string> tokens;
144 std::istringstream iss(str);
145 std::string token;
146 while (iss >> token) {
147 tokens.push_back(token);
148 }
149 return tokens;
150}
151
152void CAS_CLI::showHelpMatrices()
153{
154 std::cout << "\nMatrices:" << '\n';
155 std::cout << " matrix <name> <rows> <cols> - Create matrix" << '\n';
156 std::cout
157 << " matrix_raw <name> <raw> - Create a matrix from a raw input"
158 << '\n';
159 std::cout << " mdisp <name> - Display matrix" << '\n';
160 std::cout << " mset <matrix> <i> <j> <val> - Set matrix element" << '\n';
161 std::cout << " mdet <matrix> - Matrix determinant" << '\n';
162 std::cout << " minv <matrix> - Matrix inverse" << '\n';
163 std::cout << " meigen <matrix> - Matrix eigenvalues" << '\n';
164 std::cout << " meigenv <matrix> - Matrix eigenvectors"
165 << '\n';
166 std::cout << " madj <matrix> - Matrix adjoint" << '\n';
167 std::cout << " mrank <matrix> - Matrix rank" << '\n';
168 std::cout << " mtrans <matrix> - Matrix transpose" << '\n';
169}
170
171void CAS_CLI::showHelp()
172{
173 std::cout << "\n=== CAS Commands ===" << std::endl;
174
175 std::cout << "\nGeneral:" << std::endl;
176 std::cout << " help - Show this help" << std::endl;
177 std::cout << " list - List all stored objects"
178 << std::endl;
179 std::cout << " clear - Clear all stored objects"
180 << std::endl;
181 std::cout << " quit/exit - Exit the program" << std::endl;
182
183 std::cout << "\nExpressions:" << std::endl;
184 std::cout << " expr <name> <expression> - Define expression" << std::endl;
185 std::cout << " deriv <expr> <var> - Compute derivative" << std::endl;
186 std::cout << " integral <expr> <var> <a> <b> - Numerical integration"
187 << std::endl;
188 std::cout << " limit <expr> <var> <val> - Compute limit" << std::endl;
189 std::cout << " series <expr> <var> <center> <degree> - Taylor series"
190 << std::endl;
191
192 std::cout << "\nPolynomials:" << std::endl;
193 std::cout << " poly <name> <coeffs...> - Define polynomial" << std::endl;
194 std::cout << " peval <poly> <value> - Evaluate polynomial" << std::endl;
195 std::cout << " padd <p1> <p2> <result> - Add polynomials" << std::endl;
196 std::cout << " pmult <p1> <p2> <result> - Multiply polynomials" << std::endl;
197 std::cout << " pgcd <p1> <p2> - Compute polynomial GCD"
198 << std::endl;
199 std::cout << " proots <poly> - Find polynomial roots" << std::endl;
200 std::cout << " pfactor <poly> - Factor polynomial" << std::endl;
201
202 std::cout << "\nComplex Numbers:" << std::endl;
203 std::cout << " complex <name> <real> <imag> - Define complex number"
204 << std::endl;
205 std::cout << " cadd <c1> <c2> <result> - Add complex numbers" << std::endl;
206 std::cout << " cmult <c1> <c2> <result> - Multiply complex numbers"
207 << std::endl;
208 std::cout << " cpower <c> <n> <result> - Complex power" << std::endl;
209 std::cout << " croots <n> - Roots of unity" << std::endl;
210
211 CAS_CLI::showHelpMatrices();
212
213 std::cout << "\nTransforms:" << std::endl;
214 std::cout << " laplace <expr> <var> - Laplace transform" << std::endl;
215 std::cout << " fourier <signal> - Fourier transform" << std::endl;
216
217 std::cout << "\nDifferential Equations:" << std::endl;
218 std::cout << " ode <method> <expr> <x0> <y0> <h> <steps> - Solve ODE"
219 << std::endl;
220 std::cout << " pde <type> <params...> - Solve PDE" << std::endl;
221
222 std::cout << "\nNumerical Methods:" << std::endl;
223 std::cout << " root <method> <expr> <params...> - Find roots" << std::endl;
224 std::cout << " optimize <method> <expr> <params...> - Optimization"
225 << std::endl;
226 std::cout << " interpolate <method> <x_vals> <y_vals> - Interpolation"
227 << std::endl;
228 std::cout << std::endl;
229}
230
231void CAS_CLI::handleExpression(const std::vector<std::string>& tokens)
232{
233 if (tokens.size() < 3) {
234 std::cout << "Usage: expr <name> <expression>" << std::endl;
235 return;
236 }
237
238 std::string name = tokens[1];
239 std::string exprStr = tokens[2];
240 for (size_t i = 3; i < tokens.size(); ++i) {
241 exprStr += " " + tokens[i];
242 }
243
244 try {
245 // Parse the expression string into an Expression object
246 auto expr = parseExpression(exprStr);
247
248 // Store the expression in the expressions map
249 expressions[name] = expr;
250
251 std::cout << "Expression '" << name << "' = " << exprStr
252 << " stored successfully." << std::endl;
253
254 // Optionally show the parsed form
255 std::cout << "Parsed as: " << expr->toString() << std::endl;
256
257 } catch (const std::exception& e) {
258 std::cout << "Error parsing expression: " << e.what() << std::endl;
259 std::cout << "Expression '" << name << "' was not stored." << std::endl;
260 }
261}
262
263void CAS_CLI::clearAll()
264{
265 int totalObjects = expressions.size() + polynomials.size()
266 + complexNumbers.size() + matrices.size();
267
268 if (totalObjects == 0) {
269 std::cout << "No objects to clear." << std::endl;
270 return;
271 }
272
273 // Clear all containers
274 expressions.clear();
275 polynomials.clear();
276 complexNumbers.clear();
277 matrices.clear();
278
279 std::cout << "All objects cleared (" << totalObjects << " objects removed)."
280 << std::endl;
281}
282
283void CAS_CLI::listObjects()
284{
285 bool hasObjects = false;
286
287 // List expressions
288 if (!expressions.empty()) {
289 std::cout << "\nExpressions:" << std::endl;
290 for (const auto& pair : expressions) {
291 std::cout << " " << pair.first << " = " << pair.second->toString()
292 << std::endl;
293 }
294 hasObjects = true;
295 }
296
297 // List polynomials
298 if (!polynomials.empty()) {
299 std::cout << "\nPolynomials:" << std::endl;
300 for (const auto& pair : polynomials) {
301 std::cout << " " << pair.first << " = " << pair.second.toString()
302 << std::endl;
303 }
304 hasObjects = true;
305 }
306
307 // List complex numbers
308 if (!complexNumbers.empty()) {
309 std::cout << "\nComplex Numbers:" << std::endl;
310 for (const auto& pair : complexNumbers) {
311 std::cout << " " << pair.first << " = " << pair.second.toString()
312 << std::endl;
313 }
314 hasObjects = true;
315 }
316
317 // List matrices
318 if (!matrices.empty()) {
319 std::cout << "\nMatrices:" << std::endl;
320 for (const auto& pair : matrices) {
321 std::cout << " " << pair.first << " (" << pair.second.getRows() << "x"
322 << pair.second.getCols() << ")" << std::endl;
323 }
324 hasObjects = true;
325 }
326
327 if (!hasObjects) {
328 std::cout << "No objects stored." << std::endl;
329 }
330
331 std::cout << std::endl;
332}
333
334// Helper method to parse expression strings (you'll need to implement this)
335std::shared_ptr<Expression> CAS_CLI::parseExpression(const std::string& exprStr)
336{
337 // Remove whitespace
338 std::string cleanExpr = removeWhitespace(exprStr);
339
340 if (cleanExpr.empty()) {
341 throw std::runtime_error("Empty expression");
342 }
343
344 // Parse the expression using recursive descent
345 size_t pos = 0;
346 return parseAddSub(cleanExpr, pos);
347}
348
349// Remove whitespace from expression string
350std::string CAS_CLI::removeWhitespace(const std::string& str)
351{
352 std::string result;
353 for (char c : str) {
354 if (!std::isspace(c)) {
355 result += c;
356 }
357 }
358 return result;
359}
360
361// Parse addition and subtraction (lowest precedence)
362std::shared_ptr<Expression> CAS_CLI::parseAddSub(const std::string& expr,
363 size_t& pos)
364{
365 auto left = parseMulDiv(expr, pos);
366
367 while (pos < expr.length() && (expr[pos] == '+' || expr[pos] == '-')) {
368 char op = expr[pos++];
369 auto right = parseMulDiv(expr, pos);
370 left = std::make_shared<BinaryOp>(left, op, right);
371 }
372
373 return left;
374}
375
376// Parse multiplication and division
377std::shared_ptr<Expression> CAS_CLI::parseMulDiv(const std::string& expr,
378 size_t& pos)
379{
380 auto left = parsePower(expr, pos);
381
382 while (pos < expr.length() && (expr[pos] == '*' || expr[pos] == '/')) {
383 char op = expr[pos++];
384 auto right = parsePower(expr, pos);
385 left = std::make_shared<BinaryOp>(left, op, right);
386 }
387
388 return left;
389}
390
391// Parse exponentiation (highest precedence)
392std::shared_ptr<Expression> CAS_CLI::parsePower(const std::string& expr,
393 size_t& pos)
394{
395 auto left = parseFactor(expr, pos);
396
397 if (pos < expr.length() && expr[pos] == '^') {
398 pos++;
399 auto right = parsePower(expr, pos); // Right associative
400 left = std::make_shared<BinaryOp>(left, '^', right);
401 }
402
403 return left;
404}
405
406// Parse factors (numbers, variables, functions, parentheses)
407std::shared_ptr<Expression> CAS_CLI::parseFactor(const std::string& expr,
408 size_t& pos)
409{
410 if (pos >= expr.length()) {
411 throw std::runtime_error("Unexpected end of expression");
412 }
413
414 // Handle parentheses
415 if (expr[pos] == '(') {
416 pos++; // Skip '('
417 auto result = parseAddSub(expr, pos);
418 if (pos >= expr.length() || expr[pos] != ')') {
419 throw std::runtime_error("Missing closing parenthesis");
420 }
421 pos++; // Skip ')'
422 return result;
423 }
424
425 // Handle unary minus
426 if (expr[pos] == '-') {
427 pos++;
428 auto operand = parseFactor(expr, pos);
429 return std::make_shared<BinaryOp>(
430 std::make_shared<Constant>(-1), '*', operand);
431 }
432
433 // Handle unary plus
434 if (expr[pos] == '+') {
435 pos++;
436 return parseFactor(expr, pos);
437 }
438
439 // Handle numbers
440 if (std::isdigit(expr[pos]) || expr[pos] == '.') {
441 return parseNumber(expr, pos);
442 }
443
444 // Handle variables and functions
445 if (std::isalpha(expr[pos])) {
446 return parseVariableOrFunction(expr, pos);
447 }
448
449 throw std::runtime_error("Unexpected character: "
450 + std::string(1, expr[pos]));
451}
452
453// Parse numeric constants
454std::shared_ptr<Expression> CAS_CLI::parseNumber(const std::string& expr,
455 size_t& pos)
456{
457 size_t start = pos;
458 bool hasDecimal = false;
459
460 while (pos < expr.length()
461 && (std::isdigit(expr[pos]) || (expr[pos] == '.' && !hasDecimal)))
462 {
463 if (expr[pos] == '.') {
464 hasDecimal = true;
465 }
466 pos++;
467 }
468
469 std::string numStr = expr.substr(start, pos - start);
470 double value = std::stod(numStr);
471 return std::make_shared<Constant>(value);
472}
473
474// Parse variables and functions
475std::shared_ptr<Expression> CAS_CLI::parseVariableOrFunction(
476 const std::string& expr, size_t& pos)
477{
478 size_t start = pos;
479
480 // Parse identifier
481 while (pos < expr.length() && (std::isalnum(expr[pos]) || expr[pos] == '_')) {
482 pos++;
483 }
484
485 std::string identifier = expr.substr(start, pos - start);
486
487 // Check if it's a function call
488 if (pos < expr.length() && expr[pos] == '(') {
489 pos++; // Skip '('
490 auto argument = parseAddSub(expr, pos);
491 if (pos >= expr.length() || expr[pos] != ')') {
492 throw std::runtime_error("Missing closing parenthesis in function call");
493 }
494 pos++; // Skip ')'
495 return std::make_shared<Function>(identifier, argument);
496 }
497
498 // It's a variable
499 return std::make_shared<Variable>(identifier);
500}
501
502void CAS_CLI::handleDerivative(const std::vector<std::string>& tokens)
503{
504 if (tokens.size() < 3) {
505 std::cout << "Usage: deriv <expression> <variable>" << std::endl;
506 return;
507 }
508
509 std::string expr = tokens[1];
510 std::string var = tokens[2];
511
512 if (expressions.find(expr) == expressions.end()) {
513 std::cout << "Expression '" << expr << "' not found." << std::endl;
514 return;
515 }
516
517 auto derivative = Calculus::differentiate(expressions[expr], var);
518 std::cout << "d/d" << var << "(" << expr << ") = " << derivative->toString()
519 << std::endl;
520}
521
522void CAS_CLI::handleIntegral(const std::vector<std::string>& tokens)
523{
524 if (tokens.size() < 5) {
525 std::cout << "Usage: integral <expression> <variable> <lower> <upper>"
526 << std::endl;
527 return;
528 }
529
530 std::string expr = tokens[1];
531 std::string var = tokens[2];
532 double lower = std::stod(tokens[3]);
533 double upper = std::stod(tokens[4]);
534
535 // For demo - using numerical integration
536 auto f = [](double x) { return x * x; }; // Example function
537 double result = Calculus::simpsonsRule(f, lower, upper);
538 std::cout << "∫[" << lower << "," << upper << "] " << expr << " d" << var
539 << " ≈ " << result << std::endl;
540}
541
542void CAS_CLI::handleLimit(const std::vector<std::string>& tokens)
543{
544 if (tokens.size() < 4) {
545 std::cout << "Usage: limit <expression> <variable> <value>" << std::endl;
546 return;
547 }
548
549 std::string expr = tokens[1];
550 std::string var = tokens[2];
551 double value = std::stod(tokens[3]);
552
553 auto f = [](double x) { return x * x; }; // Example function
554 double result = Calculus::limit(f, value);
555 std::cout << "lim(" << var << "→" << value << ") " << expr << " = " << result
556 << std::endl;
557}
558
559void CAS_CLI::handleSeries(const std::vector<std::string>& tokens)
560{
561 if (tokens.size() < 5) {
562 std::cout << "Usage: series <expression> <variable> <center> <degree>"
563 << std::endl;
564 return;
565 }
566
567 std::string expr = tokens[1];
568 std::string var = tokens[2];
569 double center = std::stod(tokens[3]);
570 int degree = std::stoi(tokens[4]);
571
572 auto f = [](double x) { return std::exp(x); }; // Example function
573 Polynomial series = Calculus::taylorSeries(f, center, degree);
574 std::cout << "Taylor series of " << expr << " around " << var << "=" << center
575 << " (degree " << degree << "): " << series.toString() << std::endl;
576}
577
578void CAS_CLI::handlePolynomial(const std::vector<std::string>& tokens)
579{
580 if (tokens.size() < 3) {
581 std::cout << "Usage: poly <name> <coefficient0> <coefficient1> ..."
582 << std::endl;
583 return;
584 }
585
586 std::string name = tokens[1];
587 std::vector<double> coeffs;
588 for (size_t i = 2; i < tokens.size(); ++i) {
589 coeffs.push_back(std::stod(tokens[i]));
590 }
591
592 polynomials[name] = Polynomial(coeffs);
593 std::cout << "Polynomial '" << name << "' = " << polynomials[name].toString()
594 << " stored." << std::endl;
595}
596
597void CAS_CLI::handlePolynomialEvaluate(const std::vector<std::string>& tokens)
598{
599 if (tokens.size() < 3) {
600 std::cout << "Usage: peval <polynomial> <value>" << std::endl;
601 return;
602 }
603
604 std::string name = tokens[1];
605 double value = std::stod(tokens[2]);
606
607 if (polynomials.find(name) == polynomials.end()) {
608 std::cout << "Polynomial '" << name << "' not found." << std::endl;
609 return;
610 }
611
612 double result = polynomials[name].evaluate(value);
613 std::cout << name << "(" << value << ") = " << result << std::endl;
614}
615
616void CAS_CLI::handlePolynomialAdd(const std::vector<std::string>& tokens)
617{
618 if (tokens.size() < 4) {
619 std::cout << "Usage: padd <poly1> <poly2> <result_name>" << std::endl;
620 return;
621 }
622
623 std::string p1_name = tokens[1];
624 std::string p2_name = tokens[2];
625 std::string result_name = tokens[3];
626
627 if (CAS_CLI::polynomials.find(p1_name) == CAS_CLI::polynomials.end()
628 || CAS_CLI::polynomials.find(p2_name) == CAS_CLI::polynomials.end())
629 {
630 std::cout << "One or both polynomials not found." << std::endl;
631 return;
632 }
633
634 CAS_CLI::polynomials[result_name] =
635 CAS_CLI::polynomials[p1_name] + CAS_CLI::polynomials[p2_name];
636 std::cout << result_name << " = "
637 << CAS_CLI::polynomials[result_name].toString() << std::endl;
638}
639
640//
641// void CAS_CLI::handlePolynomialMultiply(const std::vector<std::string>&
642// tokens)
643//{
644// if (tokens.size() < 4) {
645// std::cout << "Usage: pmult <poly1> <poly2> <result_name>" << std::endl;
646// return;
647// }
648//
649// std::string p1_name = tokens[1];
650// std::string p2_name = tokens[2];
651// std::string result_name = tokens[3];
652//
653// if (polynomials.find(p1_name) == polynomials.end()
654// || polynomials.find(p2_name) == polynomials.end())
655// {
656// std::cout << "One or both polynomials not found." << std::endl;
657// return;
658// }
659//
660// polynomials[result_name] = polynomials[p1_name] * polynomials[p2_name];
661// std::cout << result_name << " = " << polynomials[result_name].toString()
662// << std::endl;
663//}
664
665// void CAS_CLI::handlePolynomialGCD(const std::vector<std::string>& tokens)
666//{
667// if (tokens.size() < 3) {
668// std::cout << "Usage: pgcd <poly1> <poly2>" << std::endl;
669// return;
670// }
671//
672// std::string p1_name = tokens[1];
673// std::string p2_name = tokens[2];
674//
675// if (polynomials.find(p1_name) == polynomials.end()
676// || polynomials.find(p2_name) == polynomials.end())
677// {
678// std::cout << "One or both polynomials not found." << std::endl;
679// return;
680// }
681//
682// Polynomial gcd = polynomials[p1_name].gcd(polynomials[p2_name]);
683// std::cout << "GCD(" << p1_name << ", " << p2_name << ") = " <<
684// gcd.toString()
685// << std::endl;
686// }
687//
688void CAS_CLI::handlePolynomialRoots(const std::vector<std::string>& tokens)
689{
690 if (tokens.size() < 2) {
691 std::cout << "Usage: proots <polynomial>" << '\n';
692 return;
693 }
694
695 std::string const name = tokens[1];
696
697 if (polynomials.find(name) == polynomials.end()) {
698 std::cout << "Polynomial '" << name << "' not found." << std::endl;
699 return;
700 }
701
702 auto roots = polynomials[name].roots();
703 std::cout << "Roots of " << name << ":" << std::endl;
704 for (size_t i = 0; i < roots.size(); ++i) {
705 std::cout << " r" << (i + 1) << " = " << ComplexNumber(roots[i]).toString()
706 << std::endl;
707 }
708}
709
710//
711// void CAS_CLI::handlePolynomialFactor(const std::vector<std::string>& tokens)
712//{
713// if (tokens.size() < 2) {
714// std::cout << "Usage: pfactor <polynomial>" << std::endl;
715// return;
716// }
717//
718// std::string name = tokens[1];
719//
720// if (polynomials.find(name) == polynomials.end()) {
721// std::cout << "Polynomial '" << name << "' not found." << std::endl;
722// return;
723// }
724//
725// auto factors = polynomials[name].factor();
726// std::cout << "Factorization of " << name << ":" << std::endl;
727// for (size_t i = 0; i < factors.size(); ++i) {
728// std::cout << " Factor " << (i + 1) << ": " << factors[i].toString()
729// << std::endl;
730// }
731// }
732
733void CAS_CLI::handleComplex(const std::vector<std::string>& tokens)
734{
735 if (tokens.size() < 4) {
736 std::cout << "Usage: complex <name> <real> <imaginary>" << std::endl;
737 return;
738 }
739
740 std::string name = tokens[1];
741 double real = std::stod(tokens[2]);
742 double imag = std::stod(tokens[3]);
743
744 complexNumbers[name] = ComplexNumber(real, imag);
745 std::cout << "Complex number '" << name
746 << "' = " << complexNumbers[name].toString() << " stored."
747 << std::endl;
748}
749
750void CAS_CLI::handleComplexAdd(const std::vector<std::string>& tokens)
751{
752 if (tokens.size() < 4) {
753 std::cout << "Usage: cadd <complex1> <complex2> <result_name>" << std::endl;
754 return;
755 }
756
757 std::string c1_name = tokens[1];
758 std::string c2_name = tokens[2];
759 std::string result_name = tokens[3];
760
761 if (complexNumbers.find(c1_name) == complexNumbers.end()
762 || complexNumbers.find(c2_name) == complexNumbers.end())
763 {
764 std::cout << "One or both complex numbers not found." << std::endl;
765 return;
766 }
767
768 complexNumbers[result_name] =
769 complexNumbers[c1_name] + complexNumbers[c2_name];
770 std::cout << result_name << " = " << complexNumbers[result_name].toString()
771 << std::endl;
772}
773
774void CAS_CLI::handleComplexMultiply(const std::vector<std::string>& tokens)
775{
776 if (tokens.size() < 4) {
777 std::cout << "Usage: cmult <complex1> <complex2> <result_name>"
778 << std::endl;
779 return;
780 }
781
782 std::string c1_name = tokens[1];
783 std::string c2_name = tokens[2];
784 std::string result_name = tokens[3];
785
786 if (complexNumbers.find(c1_name) == complexNumbers.end()
787 || complexNumbers.find(c2_name) == complexNumbers.end())
788 {
789 std::cout << "One or both complex numbers not found." << std::endl;
790 return;
791 }
792
793 complexNumbers[result_name] =
794 complexNumbers[c1_name] * complexNumbers[c2_name];
795 std::cout << result_name << " = " << complexNumbers[result_name].toString()
796 << std::endl;
797}
798
799void CAS_CLI::handleComplexPower(const std::vector<std::string>& tokens)
800{
801 if (tokens.size() < 4) {
802 std::cout << "Usage: cpower <complex> <power> <result_name>" << std::endl;
803 return;
804 }
805
806 std::string c_name = tokens[1];
807 int power = std::stoi(tokens[2]);
808 std::string result_name = tokens[3];
809
810 if (complexNumbers.find(c_name) == complexNumbers.end()) {
811 std::cout << "Complex number '" << c_name << "' not found." << std::endl;
812 return;
813 }
814
815 complexNumbers[result_name] = complexNumbers[c_name] ^ power;
816 std::cout << result_name << " = " << complexNumbers[result_name].toString()
817 << std::endl;
818}
819
820void CAS_CLI::handleComplexRoots(const std::vector<std::string>& tokens)
821{
822 if (tokens.size() < 2) {
823 std::cout << "Usage: croots <n>" << std::endl;
824 return;
825 }
826
827 int n = std::stoi(tokens[1]);
828
829 auto roots = ComplexNumber::rootsOfUnity(n);
830 std::cout << n << "th roots of unity:" << std::endl;
831 for (size_t i = 0; i < roots.size(); ++i) {
832 std::cout << " ω^" << i << " = " << roots[i].toString() << std::endl;
833 }
834}
835
836void CAS_CLI::handleMatrixAdjoint(const std::vector<std::string>& tokens)
837{
838 if (tokens.size() < 2) {
839 std::cout << "Usage: madj <name>";
840 }
841 std::string name = tokens[1];
842 std::cout << matrices[name].adjoint().toString() << '\n';
843}
844
845void CAS_CLI::handleMatrixRaw(const std::vector<std::string>& tokens)
846{
847 if (tokens.size() < 3) {
848 std::cout << "Usage: matrix <name> (<raw>)\n";
849 return;
850 }
851
852 const std::string& name = tokens[1];
853 const std::string& raw = tokens[2];
854
855 if (raw.front() != '(' || raw.back() != ')') {
856 std::cout << "Invalid format: expected '(...)'\n";
857 return;
858 }
859
860 std::string content = raw.substr(1, raw.size() - 2);
861
862 std::vector<std::vector<float>> data;
863 size_t i = 0;
864 int expected_cols = -1;
865
866 while (i < content.size()) {
867 if (content[i] != '[') {
868 std::cout << "Invalid format: expected '['\n";
869 return;
870 }
871
872 size_t close = content.find(']', i);
873 if (close == std::string::npos) {
874 std::cout << "Invalid format: missing ']'\n";
875 return;
876 }
877
878 std::string row_str = content.substr(i + 1, close - i - 1);
879 std::stringstream ss(row_str);
880
881 std::vector<float> row;
882 std::string value;
883
884 while (getline(ss, value, ',')) {
885 try {
886 row.push_back(std::stof(value));
887 } catch (...) {
888 std::cout << "Invalid numeric value\n";
889 return;
890 }
891 }
892
893 if (row.empty()) {
894 std::cout << "Empty row not allowed\n";
895 return;
896 }
897
898 if (expected_cols == -1) {
899 expected_cols = row.size();
900 } else if (row.size() != expected_cols) {
901 std::cout << "Rows with different column count\n";
902 return;
903 }
904
905 data.push_back(row);
906
907 i = close + 1;
908 if (i < content.size() && content[i] == ',') {
909 i++;
910 }
911 }
912
913 if (data.empty()) {
914 std::cout << "Matrix cannot be empty\n";
915 return;
916 }
917
918 Matrix<float> matrix(data.size(), expected_cols);
919
920 for (size_t r = 0; r < data.size(); ++r) {
921 for (size_t c = 0; c < data[r].size(); ++c) {
922 matrix(r, c) = data[r][c];
923 }
924 }
925
926 matrices[name] = matrix;
927
928 std::cout << "Matrix '" << name << "' created (" << data.size() << "x"
929 << expected_cols << ")\n";
930}
931
932void CAS_CLI::handleMatrix(const std::vector<std::string>& tokens)
933{
934 if (tokens.size() < 4) {
935 std::cout << "Usage: matrix <name> <rows> <cols>" << std::endl;
936 return;
937 }
938
939 std::string name = tokens[1];
940 int rows = std::stoi(tokens[2]);
941 int cols = std::stoi(tokens[3]);
942
943 matrices[name] = Matrix<float>(rows, cols);
944 std::cout << "Matrix '" << name << "' (" << rows << "x" << cols
945 << ") created." << std::endl;
946}
947
948void CAS_CLI::handleMatrixDisplay(const std::vector<std::string>& tokens)
949{
950 if (tokens.size() < 2) {
951 std::cout << "Usage: mdisp <name>" << std::endl;
952 }
953 std::string name = tokens[1];
954 std::cout << matrices[name].toString() << std::endl;
955}
956
957void CAS_CLI::handleMatrixRank(const std::vector<std::string>& tokens)
958{
959 if (tokens.size() < 2) {
960 std::cout << "Usage: mrank <name>" << std::endl;
961 }
962 std::string name = tokens[1];
963 std::cout << matrices[name].rank() << std::endl;
964}
965
966void CAS_CLI::handleMatrixSet(const std::vector<std::string>& tokens)
967{
968 if (tokens.size() < 5) {
969 std::cout << "Usage: mset <matrix> <row> <col> <value>" << std::endl;
970 return;
971 }
972
973 std::string name = tokens[1];
974 int row = std::stoi(tokens[2]);
975 int col = std::stoi(tokens[3]);
976 double value = std::stod(tokens[4]);
977
978 if (matrices.find(name) == matrices.end()) {
979 std::cout << "Matrix '" << name << "' not found." << std::endl;
980 return;
981 }
982
983 matrices[name](row, col) = value;
984 std::cout << name << "[" << row << "][" << col << "] = " << value
985 << std::endl;
986}
987
988void CAS_CLI::handleMatrixDeterminant(const std::vector<std::string>& tokens)
989{
990 if (tokens.size() < 2) {
991 std::cout << "Usage: mdet <matrix>" << std::endl;
992 return;
993 }
994
995 std::string name = tokens[1];
996
997 if (matrices.find(name) == matrices.end()) {
998 std::cout << "Matrix '" << name << "' not found." << std::endl;
999 return;
1000 }
1001
1002 double det = matrices[name].determinant();
1003 std::cout << "det(" << name << ") = " << det << std::endl;
1004 std::cout << matrices[name].toString() << std::endl;
1005}
1006
1007void CAS_CLI::handleMatrixInverse(const std::vector<std::string>& tokens)
1008{
1009 if (tokens.size() < 2) {
1010 std::cout << "Usage: minv <matrix>" << std::endl;
1011 return;
1012 }
1013
1014 std::string name = tokens[1];
1015
1016 if (matrices.find(name) == matrices.end()) {
1017 std::cout << "Matrix '" << name << "' not found." << std::endl;
1018 return;
1019 }
1020
1021 try {
1022 Matrix<float> inv = matrices[name].inverse();
1023 std::cout << "Inverse of " << name << ":" << std::endl;
1024 std::cout << inv.toString() << std::endl;
1025 } catch (const std::exception& e) {
1026 std::cout << "Cannot compute inverse: " << e.what() << std::endl;
1027 }
1028}
1029
1030void CAS_CLI::handleMatrixEigenvalues(const std::vector<std::string>& tokens)
1031{
1032 if (tokens.size() < 2) {
1033 std::cout << "Usage: meigen <matrix>" << std::endl;
1034 return;
1035 }
1036
1037 std::string name = tokens[1];
1038
1039 if (matrices.find(name) == matrices.end()) {
1040 std::cout << "Matrix '" << name << "' not found." << std::endl;
1041 return;
1042 }
1043
1044 auto eigenvals = matrices[name].eigenvalues();
1045 std::cout << "Eigenvalues of " << name << ":" << std::endl;
1046 for (size_t i = 0; i < eigenvals.size(); ++i) {
1047 std::cout << "lambda_" << (i + 1) << " = " << eigenvals[i] << std::endl;
1048 }
1049}
1050
1051void CAS_CLI::handleMatrixEigenvectors(const std::vector<std::string>& tokens)
1052{
1053 if (tokens.size() < 2) {
1054 std::cout << "Usage: meigenv <matrix> " << std::endl;
1055 return;
1056 }
1057 std::string name = tokens[1];
1058 if (matrices.find(name) == matrices.end()) {
1059 std::cout << "Matrix '" << name << "' not found." << std::endl;
1060 return;
1061 }
1062 auto eigenvectors = matrices[name].eigenvectors();
1063 for (int i = 0; i < eigenvectors.getRows(); i++) {
1064 for (int j = 0; j < eigenvectors.getCols(); j++) {
1065 std::cout << eigenvectors(i, j) << " ";
1066 }
1067 std::cout << "\n";
1068 }
1069}
1070
1071void CAS_CLI::handleLaplace(const std::vector<std::string>& tokens)
1072{
1073 if (tokens.size() < 3) {
1074 std::cout << "Usage: laplace <expression> <variable>" << std::endl;
1075 return;
1076 }
1077
1078 std::string expr = tokens[1];
1079 std::string var = tokens[2];
1080
1081 std::cout << "Laplace transform of " << expr << " with respect to " << var
1082 << ":" << std::endl;
1083 std::cout
1084 << "Note: Full Laplace transform implementation not shown in this demo."
1085 << std::endl;
1086}
1087
1088void CAS_CLI::handleFourier(const std::vector<std::string>& tokens)
1089{
1090 if (tokens.size() < 2) {
1091 std::cout << "Usage: fourier <signal_values...>" << std::endl;
1092 return;
1093 }
1094
1095 std::vector<ComplexNumber> signal;
1096 for (size_t i = 1; i < tokens.size(); ++i) {
1097 signal.push_back(ComplexNumber(std::stod(tokens[i])));
1098 }
1099
1100 auto spectrum = FourierTransform::FFT(signal);
1101 std::cout << "FFT result:" << std::endl;
1102 for (size_t i = 0; i < spectrum.size(); ++i) {
1103 std::cout << " X[" << i << "] = " << spectrum[i].toString() << std::endl;
1104 }
1105}
1106
1107void CAS_CLI::handleODE(const std::vector<std::string>& tokens)
1108{
1109 if (tokens.size() < 7) {
1110 std::cout << "Usage: ode <method> <dy/dx_expression> <x0> <y0> <h> <steps>"
1111 << std::endl;
1112 std::cout << "Methods: euler, rk4" << std::endl;
1113 return;
1114 }
1115
1116 std::string method = tokens[1];
1117 std::string expr = tokens[2];
1118 double x0 = std::stod(tokens[3]);
1119 double y0 = std::stod(tokens[4]);
1120 double h = std::stod(tokens[5]);
1121 int steps = std::stoi(tokens[6]);
1122
1123 // Example function: dy/dx = x + y
1124 auto f = [](double x, double y) { return x + y; };
1125
1126 std::vector<double> solution;
1127 if (method == "euler") {
1128 solution = DifferentialEquations::eulerMethod(f, x0, y0, h, steps);
1129 } else if (method == "rk4") {
1130 solution = DifferentialEquations::rungeKutta4(f, x0, y0, h, steps);
1131 } else {
1132 std::cout << "Unknown method: " << method << std::endl;
1133 return;
1134 }
1135
1136 std::cout << "ODE solution using " << method << " method:" << std::endl;
1137 for (int i = 0; i < steps && i < static_cast<int>(solution.size()); ++i) {
1138 double x = x0 + i * h;
1139 std::cout << " x = " << x << ", y = " << solution[i] << std::endl;
1140 }
1141}
1142
1143void CAS_CLI::handlePDE(const std::vector<std::string>& tokens)
1144{
1145 if (tokens.size() < 2) {
1146 std::cout << "Usage: pde <type> <parameters...>" << std::endl;
1147 std::cout << "Types: heat, wave, laplace" << std::endl;
1148 return;
1149 }
1150}
A templated matrix class supporting various linear algebra operations.
Definition: matrix.h:23
std::string toString() const
Converts the matrix to a formatted string representation.
Definition: matrix.cpp:684
Matrix< T > inverse() const
Computes the inverse of the matrix.
Definition: matrix.cpp:303