diff --git a/Untitled.ipynb b/Untitled.ipynb new file mode 100644 index 0000000..d721670 --- /dev/null +++ b/Untitled.ipynb @@ -0,0 +1,326 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "from collections import OrderedDict, defaultdict\n", + "from functions import functions" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"functions.py\", 'w') as out:\n", + " out.writelines('import math \\n\\n')\n", + " out.writelines('functions = {\\n\\t')\n", + " \n", + " is_first = True\n", + " for key, item in math.__dict__.items():\n", + " try: \n", + " if str(item)[0] == '<' and key[0] != '_':\n", + " if not is_first:\n", + " out.writelines(\", \\n\\t'{}': lambda x: math.{}(x)\".format(key, key))\n", + " else:\n", + " out.writelines(\"'{}': lambda x: math.{}(x)\".format(key, key))\n", + " is_first = False\n", + " except:\n", + " continue\n", + " out.writelines('\\n}')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "string = '8+cos(cos5+2+sin(cos6+cos7)*9)/9+cos8*5*5/9 - cos(8+8)'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[4, 'cos'], [8, 'cos'], [19, 'sin'], [23, 'cos'], [30, 'cos'], [43, 'cos']]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arithmetic = OrderedDict([\n", + " (\"+\", lambda x, y: x + y),\n", + " (\"-\", lambda x, y: x - y),\n", + " (\"*\", lambda x, y: x * y),\n", + " (\"/\", lambda x, y: x / y),\n", + " (\"//\",lambda x, y: x //y),\n", + " (\"%\", lambda x, y: x % y),\n", + " (\"^\", lambda x, y: x ^ y),\n", + "])\n", + "\n", + "comparison = OrderedDict([\n", + " (\"<\", lambda x, y: x + y),\n", + " (\"<=\", lambda x, y: x + y),\n", + " (\"==\", lambda x, y: x + y),\n", + " (\"!=\", lambda x, y: x + y),\n", + " (\">=\", lambda x, y: x + y),\n", + " (\">\", lambda x, y: x + y),\n", + "])\n", + "\n", + "\n", + "arithmetic_symbols = arithmetic.keys()\n", + "comparison_sympols = comparison.keys()\n", + "functions_names = functions.keys()\n", + "\n", + "\n", + "def check_brackets(row):\n", + " stack = []\n", + " for i_close, symbol in enumerate(row):\n", + " try:\n", + " if symbol == ')':\n", + " stack.pop() \n", + " elif symbol == '(':\n", + " stack.append('(')\n", + " if len(stack) == 0:\n", + " return i_close\n", + " except:\n", + " print(\"Error\")\n", + " return\n", + " \n", + "# return not bool(stack)\n", + "\n", + "def get_idx_func_list(expr):\n", + " func_idx = defaultdict(list)\n", + " for sub in functions_names:\n", + " if sub in expr:\n", + " sub_size = len(sub)\n", + " expr_ = expr\n", + " size_deleted = 0\n", + " while 1:\n", + " try:\n", + " index = expr_.index(sub) + size_deleted\n", + " size_deleted = len(expr[:index + sub_size])\n", + " expr_ = expr[index + sub_size:]\n", + " func_idx[sub].append(index)\n", + " except:\n", + " break\n", + " \n", + " idx_func = []\n", + " for func, idxs in func_idx.items():\n", + " for idx in idxs:\n", + " idx_func.append([idx, func])\n", + " \n", + " idx_func = sorted(idx_func, key=lambda x: x[0])\n", + " \n", + " return idx_func\n", + "\n", + "get_idx_func_list(string)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'8+0.19461946733844862/9+-0.14550003380861354*5*5/9 - -0.9576594803233847'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def solve_functions(expr):\n", + "\n", + " idx_func = get_idx_func_list(expr)\n", + " end = -1\n", + " new_expr = ''\n", + " while idx_func:\n", + " idx, func = idx_func.pop(0)\n", + " start = idx + len(func)\n", + " new_expr += expr[end + 1:idx]\n", + "# print(new_expr)\n", + "\n", + " len_content = check_brackets(expr[start:])\n", + " if len_content != 0:\n", + " end = start + len_content\n", + " is_expression_inside = False\n", + " \n", + " while idx_func:\n", + " if idx_func[0][0] < end:\n", + " is_expression_inside = True\n", + " idx_func.pop(0)\n", + " else:\n", + " break\n", + " \n", + " if is_expression_inside:\n", + " number_expr = solve_functions(expr[start+1:end]) \n", + " number = calc(number_expr)\n", + " else :\n", + " number = calc(expr[start+1:end])\n", + " \n", + "\n", + " else:\n", + " number_expr = ''\n", + " end = start-1\n", + " for char in expr[start:]:\n", + " if char.isdigit() or char == \".\" and \".\" not in number_expr:\n", + " number_expr += char\n", + " end += 1\n", + " else:\n", + " number = float(number_expr)\n", + " break\n", + " else:\n", + " number = float(number_expr)\n", + " new_expr += str( functions[func](number) )\n", + "\n", + " if not idx_func:\n", + " new_expr += expr[end +1 :]\n", + " \n", + " return new_expr\n", + " \n", + "solve_functions(string)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def lex(expr):\n", + " \"\"\"\n", + " seperates numbers from symbols, recursively nests parens\n", + " \"\"\"\n", + " tokens = []\n", + " while expr: \n", + " char, *expr = expr\n", + " if char == \"(\":\n", + " try:\n", + " paren, expr = lex(expr)\n", + " tokens.append(paren)\n", + " except ValueError:\n", + " raise Exception(\"paren mismatch\")\n", + " elif char == \")\":\n", + " return tokens, expr\n", + " \n", + " elif char.isdigit() or char == \".\":\n", + " #number\n", + " try:\n", + " if tokens[-1] in arithmetic_symbols:\n", + " tokens.append(char) #start a new num\n", + " elif type(tokens[-1]) is list:\n", + " raise Exception(\"parens cannot be followed by numbers\")\n", + " #no support for 5(1+1) yet\n", + " else:\n", + " tokens[-1] += char #add to last num\n", + " except IndexError:\n", + " #if tokens is empty\n", + " tokens.append(char) #start first num\n", + " elif char in arithmetic_symbols:\n", + " tokens.append(char)\n", + " \n", + " elif char.isspace():\n", + " pass\n", + " else:\n", + " raise Exception(\"invalid charecter: \" + char)\n", + " return tokens\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input? \n" + ] + } + ], + "source": [ + "\n", + "def evaluate(tokens):\n", + " for symbol, func in arithmetic.items():\n", + " #try to find an operation to eval in order\n", + " try:\n", + " pos = tokens.index(symbol)\n", + "# print(symbol, pos)\n", + " #split the tokens by the operation and eval that\n", + " leftTerm = evaluate(tokens[:pos])\n", + " rightTerm = evaluate(tokens[pos + 1:])\n", + " return func(leftTerm, rightTerm)\n", + " #incidentially, return immediatly breaks all loops within the\n", + " # function\n", + " except ValueError:\n", + " pass\n", + " #index raises ValueError when it's not found\n", + " if len(tokens) is 1:\n", + " try:\n", + " #it must be a number\n", + " return float(tokens[0])\n", + " except TypeError:\n", + " #if it's not a number\n", + " return evaluate(tokens[0])\n", + " else:\n", + " raise Exception(\"bad expression: \" + tokens)\n", + "\n", + "def calc(expr):\n", + " return evaluate(lex(expr))\n", + " \n", + "while 1:\n", + " try:\n", + " print(calc(input(\"Input? \")))\n", + " except:\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/functions.py b/functions.py new file mode 100644 index 0000000..7dddc3a --- /dev/null +++ b/functions.py @@ -0,0 +1,48 @@ +import math + +functions = { + 'hypot': lambda x: math.hypot(x), + 'ceil': lambda x: math.ceil(x), + 'factorial': lambda x: math.factorial(x), + 'cosh': lambda x: math.cosh(x), + 'isnan': lambda x: math.isnan(x), + 'erf': lambda x: math.erf(x), + 'asin': lambda x: math.asin(x), + 'modf': lambda x: math.modf(x), + 'pow': lambda x: math.pow(x), + 'isclose': lambda x: math.isclose(x), + 'sqrt': lambda x: math.sqrt(x), + 'atanh': lambda x: math.atanh(x), + 'gcd': lambda x: math.gcd(x), + 'sin': lambda x: math.sin(x), + 'exp': lambda x: math.exp(x), + 'lgamma': lambda x: math.lgamma(x), + 'cos': lambda x: math.cos(x), + 'expm1': lambda x: math.expm1(x), + 'log1p': lambda x: math.log1p(x), + 'gamma': lambda x: math.gamma(x), + 'floor': lambda x: math.floor(x), + 'frexp': lambda x: math.frexp(x), + 'log10': lambda x: math.log10(x), + 'trunc': lambda x: math.trunc(x), + 'erfc': lambda x: math.erfc(x), + 'tan': lambda x: math.tan(x), + 'asinh': lambda x: math.asinh(x), + 'log': lambda x: math.log(x), + 'fabs': lambda x: math.fabs(x), + 'radians': lambda x: math.radians(x), + 'tanh': lambda x: math.tanh(x), + 'isfinite': lambda x: math.isfinite(x), + 'atan': lambda x: math.atan(x), + 'acos': lambda x: math.acos(x), + 'fmod': lambda x: math.fmod(x), + 'atan2': lambda x: math.atan2(x), + 'log2': lambda x: math.log2(x), + 'isinf': lambda x: math.isinf(x), + 'degrees': lambda x: math.degrees(x), + 'sinh': lambda x: math.sinh(x), + 'copysign': lambda x: math.copysign(x), + 'ldexp': lambda x: math.ldexp(x), + 'fsum': lambda x: math.fsum(x), + 'acosh': lambda x: math.acosh(x) +} \ No newline at end of file