Skip to content

Commit

Permalink
Added funcadd, funclist, subt
Browse files Browse the repository at this point in the history
  • Loading branch information
avighnac committed Mar 20, 2024
1 parent 6dd7363 commit cffe31e
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ set(sources

set(helper_sources
helpers/center.cpp
helpers/check_for_implicit_eval.cpp
helpers/compare_printed_text.cpp
helpers/compare_text_without_ansi.cpp
helpers/get_console_width.cpp
helpers/get_matching_brace.cpp
helpers/get_printable_result.cpp
helpers/getch.cpp
helpers/is_valid_arithmetic_expression.cpp
helpers/print_eval_expression.cpp
helpers/print_expression.cpp
helpers/print_result.cpp
Expand Down
65 changes: 63 additions & 2 deletions src/algnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,24 @@ algnum::algnum(const char *s) {
variables = newVariables;
}

bool algnum::is_constant() {
for (auto &i : variables) {
if (!i.constant) {
return false;
}
}
return true;
}

bool algexpr::is_constant() {
for (auto &i : expr) {
if (!i.is_constant()) {
return false;
}
}
return true;
}

std::string algnum::latex() {
if (constant.numerator == "0")
return "0";
Expand Down Expand Up @@ -765,15 +783,33 @@ size_t get_matching_open_brace(std::string str, size_t index) {
return -1;
}

std::string algnum::to_string() {
std::string ans;
if (constant.numerator == "0") {
ans += std::string("0");
return ans;
}
// if (n.variables.empty()) {
rfraction m = constant;
ans += m.to_string();
// }
for (auto i = 0; i < variables.size(); i++) {
ans += "(" + variables[i].var + ")";
ans += std::string("^");
ans += std::string("(") + variables[i].power.to_string() + std::string(")");
}
return ans;
}

std::ostream &operator<<(std::ostream &os, const algnum n) {
if (n.constant.numerator == "0") {
os << std::string("0");
return os;
}
if (n.variables.empty()) {
// if (n.variables.empty()) {
rfraction m = n.constant;
os << m.to_string();
}
// }
if (n.constant.numerator != n.constant.denominator) {
if (!n.variables.empty())
os << std::string(" ");
Expand Down Expand Up @@ -919,6 +955,31 @@ void algexpr::clean_double_signs(std::string &expression) {
replace_all(expression, "/+", "/");
};

std::string algexpr::to_string() {
std::string temp;
std::string ans;
if (expr.empty())
return ans;
for (auto i = 0; i < expr.size(); i++) {
if (expr[i].constant.numerator[0] != '-')
ans += expr[i].to_string();
else {
algnum n1;
n1.constant = expr[i].constant.numerator.substr(
1, expr[i].constant.numerator.length());
n1.variables = expr[i].variables;
ans += n1.to_string();
}
if (i + 1 < expr.size()) {
if (expr[i + 1].constant.numerator[0] != '-')
ans += std::string("+");
else
ans += std::string("-");
}
}
return ans;
}

std::ostream &operator<<(std::ostream &os, const algexpr n) {
std::string temp;
if (n.expr.empty())
Expand Down
5 changes: 5 additions & 0 deletions src/algnum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class algnum {
std::string latex();
algnum(const char *s);
algnum() {}
bool is_constant();

std::string to_string();

algnum operator+(algnum a2);
algnum operator*(algnum a2);
Expand All @@ -49,8 +52,10 @@ class algexpr {
algnum element(size_t index);
size_t size();
void insert(algnum n);
bool is_constant();

algexpr combine_like_terms(algexpr e);
std::string to_string();

algexpr operator+(algexpr e2);
algexpr operator*(algexpr e2);
Expand Down
88 changes: 88 additions & 0 deletions src/arithmetica_tui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <vector>

#include "constants.hpp"
#include <functions.hpp>
#include <helpers.hpp>

std::string remove_spaces(std::string s) {
std::string ans = s;
replace_all(ans, " ", "");
return ans;
}

void print_add_whole_steps(std::string l_in, std::string s_in) {
if (l_in.length() < s_in.length())
std::swap(l_in, s_in);
Expand Down Expand Up @@ -55,6 +62,40 @@ std::string factor_polynomial(std::string expr, std::vector<std::string> &steps,
bool show_steps);
};

std::string funcsub(std::map<std::string, algnum::algexpr> &user_defined_funcs, std::string func_name, std::vector<std::string> &orig_vals, std::vector<std::string> &new_vals) {
// If the function exists in the map
std::string s;
if (user_defined_funcs.find(func_name) != user_defined_funcs.end()) {
s = user_defined_funcs[func_name].to_string();
} else {
s = algnum::algexpr(func_name.c_str()).to_string();
}
size_t num_vars = orig_vals.size();
for (size_t i = 0; i < num_vars; ++ i) {
replace_all(s, "(" + orig_vals[i] + ")", "(" + new_vals[i] + ")");
}
// Since my algebraic parser is .. not that great, it doesn't really support evaluating normal arithmetic expressions.
// So we'll add a check to see if our expression does not have any variables anymore.
// If so, we'll use the much better arithmetic expression parser, otherwise, we'll settle
// with the broken algebraic parser.
if (is_valid_arithmetic_expression(s)) {
return arithmetica::simplify_arithmetic_expression(s, 1, accuracy);
} else {
algnum::algexpr e(s.c_str());
std::stringstream ss;
ss << e;
return ss.str();
}
}

bool check_for_implicit_eval(std::string &s) {
if (is_valid_arithmetic_expression(s)) {
s = "eval " + s;
return true;
}
return false;
}

int arithmetica_tui(int argc, char **argv, std::istream &instream_,
std::ostream &outstream_) {
using namespace basic_math_operations;
Expand Down Expand Up @@ -91,6 +132,8 @@ int arithmetica_tui(int argc, char **argv, std::istream &instream_,
bool numeric_eval = false;
bool experimental_pretty_fractions_eval = true;

std::map<std::string, algnum::algexpr> user_defined_funcs;

if (argc >= 2) {
if (std::string(argv[1]) == "--version") {
outstream << printable_version << "\n";
Expand Down Expand Up @@ -304,6 +347,10 @@ int arithmetica_tui(int argc, char **argv, std::istream &instream_,
"divisor of the given numbers\n";
outstream << "lcm <number> <number> ... - computes the least common "
"multiple of the given numbers\n";
outstream << "funcadd <name> <algexpr> - add a function to the function list, see funclist\n";
outstream << "funclist - list all added functions\n";
outstream << "subt [function_name/algexpr], var1=new1, var2=new2 - substitute variables in functions/algebraic with constant values\n";

outstream
<< "\nFor help with a specific function, type help <function>\n\n";
outstream << "Options:\n";
Expand Down Expand Up @@ -1010,6 +1057,47 @@ int arithmetica_tui(int argc, char **argv, std::istream &instream_,
outstream << "==> " << divide(tokens[1], tokens[2], accuracy) << "\n";
}
}

if (tokens[0] == "funcadd") {
// funcadd [name] [algexpr]
if (tokens.size() < 3) {
std::cout << "Syntax: funcadd [name] [algexpr]\n";
continue;
}
algnum::algexpr e(tokens[2].c_str());
user_defined_funcs[tokens[1]] = e;
}

if (tokens[0] == "funclist") {
for (auto &i : user_defined_funcs) {
std::cout << i.first << ": " << i.second << "\n";
}
}

if (tokens[0] == "subt") {
// subt [algexpr/function name], var1=newval, var2=newval, ...
bool bad = false;
if (tokens.size() < 2) {
bad = true;
}
std::vector<std::string> orig_vals, new_vals;
input = input.substr(5);
std::vector<std::string> tokens = tokenize(input, ',');
for (size_t i = 1; i < tokens.size(); ++i) {
std::vector<std::string> tk = tokenize(tokens[i], '=');
if (tk.size() != 2) {
bad = true;
break;
}
orig_vals.push_back(remove_spaces(tk[0]));
new_vals.push_back(remove_spaces(tk[1]));
}
if (bad) {
std::cout << "Syntax: subt [algexpr/function name], var1=newval, var2=newval, ...\n";
continue;
}
std::cout << "==> " << funcsub(user_defined_funcs, remove_spaces(tokens[0]), orig_vals, new_vals) << "\n";
}
}

ret:
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ void print_eval_expression(std::string expression, int outputType, int padding,
std::vector<std::string> *outTerms = NULL,
std::vector<std::string> *outSigns = NULL,
std::ostream &outstream = std::cout);
std::vector<std::string> tokenize(std::string s);
bool check_for_implicit_eval(std::string &s);
std::vector<std::string> tokenize(std::string s, char ch = ' ');
bool is_valid_arithmetic_expression(const std::string &s);

#ifdef __linux__
char getch(std::istream &instream);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "helpers.hpp"

bool check_for_implicit_eval(std::string &s) {
bool is_valid_arithmetic_expression(const std::string &s) {
// If the input contains only numbers, (), [], {}, +-*/^ and all brackets are
// correctly opened and closed, automatically eval This is to make it easier
// for the user to use the program
Expand Down Expand Up @@ -33,8 +33,5 @@ bool check_for_implicit_eval(std::string &s) {
return false;
}
}

s = "eval " + s;

return true;
}
6 changes: 3 additions & 3 deletions src/helpers/tokenize.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "helpers.hpp"

std::vector<std::string> tokenize(std::string s) {
// Tokenize on the character ' ', essentially splitting the string into its
std::vector<std::string> tokenize(std::string s, char ch) {
// Tokenize on the character ch, essentially splitting the string into its
// individual words
// Also don't split on spaces inside of parentheses

Expand All @@ -27,7 +27,7 @@ std::vector<std::string> tokenize(std::string s) {
continue;
}

if (s[i] == ' ') {
if (s[i] == ch) {
tokens.push_back(token);
token.clear();
continue;
Expand Down

0 comments on commit cffe31e

Please sign in to comment.