diff --git a/__pycache__/app.cpython-37.pyc b/__pycache__/app.cpython-37.pyc index 71a4213..d78afc5 100644 Binary files a/__pycache__/app.cpython-37.pyc and b/__pycache__/app.cpython-37.pyc differ diff --git a/app.py b/app.py index ce4a859..4293c78 100644 --- a/app.py +++ b/app.py @@ -1,9 +1,199 @@ -from flask import Flask, render_template +from flask import Flask, render_template, request, redirect +from sympy import * + +from helpers import apology, login_required, lookup, usd app = Flask(__name__) @app.route('/') def hello(): return render_template('index.html') +@app.route('/differentiation', methods=['GET', 'POST']) +def differentiation(): + if request.method == "POST": + # Check if inputs were given + if not request.form.get("function"): + return apology("must provide a function", 400) + f = request.form.get("function") + x = symbols('x') + f = sympify(f) + + # Differentiate and return latex expressions + fprime = latex(f.diff(x)) + value = latex(f) + return render_template("differentiated.html", value=value, fprime=fprime) + else: + return render_template("differentiation.html") + +@app.route("/integration", methods=["GET", "POST"]) +def integration(): + if request.method == "POST": + # Check if inputs were given + if not request.form.get("function"): + return apology("must provide a function", 400) + + # Integrate and return latex expressions + f = request.form.get("function") + x = symbols('x') + f = sympify(f) + fintegral = latex(f.integrate(x)) + value = latex(f) + return render_template("integrated.html", value=value, fintegral=fintegral) + else: + return render_template("integration.html") + +@app.route("/riemann", methods = ["GET", "POST"]) +def riemann(): + if request.method == "POST": + # Check if inputs were given + if not request.form.get("function"): + return apology("must provide a function", 400) + if not request.form.get("lowerbound"): + return apology("must provide a lower bound", 400) + if not request.form.get("upperbound"): + return apology("must provide an upper bound", 400) + if not request.form.get("subintervals"): + return apology("must provide a number of subintervals", 400) + if not request.form.get("sumtype"): + return apology("must choose left or right", 400) + + # Get inputs, check for validity and sympify + f = request.form.get("function") + sumtype = request.form.get("sumtype") + lb = int(request.form.get("lowerbound")) + ub = int(request.form.get("upperbound")) + si = int(request.form.get("subintervals")) + x = symbols('x') + f = sympify(f) + dx = (ub - lb) / si + value = latex(f) + + # Run through Riemann Sum algorithm, creatings lists for display + # of inputs, outputs, and areas (their products) + inputs = list() + if sumtype == "1": + for i in range(0, si): + inputs.append(dx * (i)) + if sumtype == "2": + for i in range(0, si): + inputs.append(dx * (i + 1)) + outputs = list() + for input in inputs: + temp = f.subs(x, input) + outputs.append(temp) + rectangles = list() + for output in outputs: + temp = output * dx + rectangles.append(temp) + result = sum(rectangles) + + # Choose template based on left or right sum + if sumtype == "1": + return render_template("summed.html", value=value, sumtype=sumtype, lb=lb, ub=ub, si=si, dx=dx, + inputs=inputs, outputs=outputs, rectangles=rectangles, result=result) + else: + return render_template("rightSummed.html", value=value, sumtype=sumtype, lb=lb, ub=ub, si=si, dx=dx, + inputs=inputs, outputs=outputs, rectangles=rectangles, result=result) + else: + return render_template("riemann.html") + +@app.route("/maxmin", methods=["GET", "POST"]) +def maxmin(): + if request.method == "POST": + # Check if inputs were given + if not request.form.get("function"): + return apology("must provide a function", 400) + if not request.form.get("lowerbound"): + return apology("must provide a lower bound", 400) + if not request.form.get("upperbound"): + return apology("must provide an upper bound", 400) + + # Get input from form + f = request.form.get("function") + lb = sympify(request.form.get("lowerbound")) + ub = sympify(request.form.get("upperbound")) + + # Prep input for numpy / sympy + x = symbols('x') + f = sympify(f) + + # Get Derivative, solve for real solutions, update candidates list + fprime = f.diff(x) + solutions = list() + solutions.append(f.subs(x,0)) + candidates = list() + for solution in solutions: + candidates.append(solution) + candidates.append(lb) + candidates.append(ub) + + # Fill values list with solutions + values = list() + for candidate in candidates: + temp = f.subs(x, candidate) + values.append(temp) + + # Find max/min of values + maximum = max(values) + newvar = min(values) + + # Turn all into latex + value = latex(f) + fprime = latex(fprime) + for i, solution in enumerate(solutions): + solutions[i] = latex(solution) + return render_template("optimized.html", value=value, fprime=fprime, solutions=solutions, lb=lb, ub=ub, + candidates=candidates, newvar=newvar, values=values, maximum=maximum) + else: + return render_template("maxmin.html") + +@app.route("/aprox", methods=["GET", "POST"]) +def aprox(): + if request.method == "POST": + # Check if inputs were given + if not request.form.get("function"): + return apology("must provide a function", 400) + if not request.form.get("easy"): + return apology("must provide an easy value", 400) + if not request.form.get("hard"): + return apology("must provide a difficult value", 400) + + # Get inputs, sympify them, and check to see if valid + f = request.form.get("function") + a = request.form.get("easy") + h = request.form.get("hard") + x = symbols('x') + f = sympify(f) + a = sympify(a) + h = sympify(h) + if not a.is_number: + return apology("easy value must be a number", 400) + if not h.is_number: + return apology("difficult value must be a number", 400) + + # Run through Linearization algorithm + fprime = f.diff(x) + fa = f.subs(x, a) + fprimea = fprime.subs(x, a) + lh = fa + fprimea*(float(h)-float(a)) + + # Convert to latex for MathJax reading + value = latex(f) + fprime = latex(fprime) + fa = latex(fa) + lh = latex(lh) + + return render_template("aproxd.html", value=value, fprime=fprime, a=a, h=h, fa=fa, fprimea=fprimea, lh=lh) + else: + return render_template("aprox.html") + +def errorhandler(e): + """Handle error""" + if not isinstance(e, HTTPException): + e = InternalServerError() + return apology(e.name, e.code) + + + if __name__ == '__main__': app.run() diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..f163498 --- /dev/null +++ b/helpers.py @@ -0,0 +1,61 @@ +import requests +import urllib.parse + +from flask import redirect, render_template, request, session +from functools import wraps + + +def apology(message, code=400): + """Render message as an apology to user.""" + def escape(s): + """ + Escape special characters. + + https://github.com/jacebrowning/memegen#special-characters + """ + for old, new in [("-", "--"), (" ", "-"), ("_", "__"), ("?", "~q"), + ("%", "~p"), ("#", "~h"), ("/", "~s"), ("\"", "''")]: + s = s.replace(old, new) + return s + return render_template("apology.html", top=code, bottom=escape(message)), code + + +def login_required(f): + """ + Decorate routes to require login. + + http://flask.pocoo.org/docs/1.0/patterns/viewdecorators/ + """ + @wraps(f) + def decorated_function(*args, **kwargs): + if session.get("user_id") is None: + return redirect("/login") + return f(*args, **kwargs) + return decorated_function + + +def lookup(symbol): + """Look up quote for symbol.""" + + # Contact API + try: + response = requests.get(f"https://api.iextrading.com/1.0/stock/{urllib.parse.quote_plus(symbol)}/quote") + response.raise_for_status() + except requests.RequestException: + return None + + # Parse response + try: + quote = response.json() + return { + "name": quote["companyName"], + "price": float(quote["latestPrice"]), + "symbol": quote["symbol"] + } + except (KeyError, TypeError, ValueError): + return None + + +def usd(value): + """Format value as USD.""" + return f"${value:,.2f}" diff --git a/requirements.txt b/requirements.txt index 54b3b4a..191f5e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,120 @@ +absl-py==0.8.1 +astor==0.8.0 +attrs==19.2.0 +audioread==2.1.8 +Babel==2.7.0 +backcall==0.1.0 +bleach==3.1.0 +blinker==1.4 +certifi==2019.9.11 +cffi==1.13.0 +chardet==3.0.4 Click==7.0 +colorama==0.4.1 +cs50==4.0.3 +cycler==0.10.0 +decorator==4.4.0 +defusedxml==0.6.0 +entrypoints==0.3 Flask==1.1.1 -gunicorn==20.0.4 +Flask-BabelEx==0.9.3 +Flask-Login==0.4.1 +Flask-Mail==0.9.1 +Flask-Principal==0.4.0 +Flask-Security==3.0.0 +Flask-Session==0.3.1 +Flask-SQLAlchemy==2.4.1 +Flask-WTF==0.14.2 +gast==0.2.2 +google-pasta==0.1.7 +grpcio==1.24.1 +h5py==2.10.0 +idna==2.8 +importlib-metadata==0.23 +ipykernel==5.1.2 +ipython==7.8.0 +ipython-genutils==0.2.0 +ipywidgets==7.5.1 itsdangerous==1.1.0 +jedi==0.15.1 Jinja2==2.10.3 +joblib==0.14.0 +jsonschema==3.1.1 +jupyter==1.0.0 +jupyter-client==5.3.4 +jupyter-console==6.0.0 +jupyter-core==4.6.0 +kaggle==1.5.6 +Keras==2.3.1 +Keras-Applications==1.0.8 +Keras-Preprocessing==1.1.0 +kiwisolver==1.1.0 +latex2sympy==1.0.3 +librosa==0.7.1 +llvmlite==0.30.0 +Markdown==3.1.1 MarkupSafe==1.1.1 +matplotlib==3.1.1 +mistune==0.8.4 +more-itertools==7.2.0 +mpmath==1.1.0 +nbconvert==5.6.0 +nbformat==4.4.0 +notebook==6.0.1 +numba==0.46.0 +numpy==1.17.2 +opt-einsum==3.1.0 +pandas==0.25.1 +pandocfilters==1.4.2 +parso==0.5.1 +passlib==1.7.2 +pickleshare==0.7.5 +prometheus-client==0.7.1 +prompt-toolkit==2.0.10 +protobuf==3.10.0 +pycparser==2.19 +Pygments==2.4.2 +pyparsing==2.4.2 +pyrsistent==0.15.4 +python-dateutil==2.8.0 +python-slugify==4.0.0 +python-speech-features==0.6 +pytz==2019.3 +pywin32==225 +pywinpty==0.5.5 +PyYAML==5.1.2 +pyzmq==18.1.0 +qtconsole==4.5.5 +requests==2.22.0 +resampy==0.2.2 +scikit-learn==0.21.3 +scipy==1.3.1 +Send2Trash==1.5.0 +six==1.12.0 +sklearn==0.0 +sklearn-pandas==1.8.0 +SoundFile==0.10.2 +speaklater==1.3 +SQLAlchemy==1.3.10 +sqlparse==0.3.0 +sympy==1.4 +tensorboard==2.0.0 +tensorflow==2.0.0 +tensorflow-estimator==2.0.0 +termcolor==1.1.0 +terminado==0.8.2 +testpath==0.4.2 +text-unidecode==1.3 +tornado==6.0.3 +tqdm==4.36.1 +traitlets==4.3.3 +urllib3==1.24.3 +virtualenv==16.7.8 +wcwidth==0.1.7 +webencodings==0.5.1 Werkzeug==0.16.0 +widgetsnbextension==3.5.1 +wrapt==1.11.2 +WTForms==2.2.1 +xlrd==1.2.0 +zipp==0.6.0 diff --git a/templates/QuillDiff.html b/templates/QuillDiff.html new file mode 100644 index 0000000..cf8bb3d --- /dev/null +++ b/templates/QuillDiff.html @@ -0,0 +1,49 @@ +{% extends "layout.html" %} + +{% block title %} + Differentiation +{% endblock %} + +{% block main %} +

Function you would like to Derive:

+

Type math here:

+
+
+ +
+

Your Input Will Appear Here

+ +
+ + + +{% endblock %} \ No newline at end of file diff --git a/templates/apology.html b/templates/apology.html new file mode 100644 index 0000000..6003a56 --- /dev/null +++ b/templates/apology.html @@ -0,0 +1,9 @@ +{% extends "layout.html" %} + +{% block title %} + Apology +{% endblock %} + +{% block main %} + {{ top }} +{% endblock %} diff --git a/templates/aprox.html b/templates/aprox.html new file mode 100644 index 0000000..9d62dc5 --- /dev/null +++ b/templates/aprox.html @@ -0,0 +1,34 @@ +{% extends "layout.html" %} + +{% block title %} + Approximation +{% endblock %} + +{% block main %} + Function you would like to Approximate: +
+
+ +
+

Your Input Will Appear Here

+

To create the Linearization of f at a, L(x) = f(a) + f'(a)(x-a), we need an easy to calculate value, a, + and a difficult to find value for x

+
+ + +
+ +
+ + + +{% endblock %} \ No newline at end of file diff --git a/templates/aproxd.html b/templates/aproxd.html new file mode 100644 index 0000000..8c8c899 --- /dev/null +++ b/templates/aproxd.html @@ -0,0 +1,60 @@ +{% extends "layout.html" %} + +{% block title %} + Differentiated +{% endblock %} + +{% block main %} +
+

Your function is $f(x) = {{ value }}$

+

Your Linear Approximation of $f(x)$ at $x = {{ h }}$ is ${{ lh }}$

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Step 1Setup L(x)
$L(x) = f({{ a }}) + f'({{ a }})(x-{{ a }})$
Step 2Take the Derivative
$f'(x) = {{ fprime }}$
Step 3Plug in values
$f({{ a }}) = {{ fa }}$
$f'({{ a }}) = {{ fprimea }}$
$L(x) = {{ fa }} + [{{ fprimea }}(x - {{ a }})]$
Step 4Use our $L(x)$ to approximate $f({{ h }})$
$L({{ h }}) = {{ fa }} + [{{ fprimea }}({{ h }} - {{ a }})]$
$= {{ lh }}$
+{% endblock %} \ No newline at end of file diff --git a/templates/differentiated.html b/templates/differentiated.html new file mode 100644 index 0000000..fa6cef2 --- /dev/null +++ b/templates/differentiated.html @@ -0,0 +1,12 @@ +{% extends "layout.html" %} + +{% block title %} + Differentiated +{% endblock %} + +{% block main %} +
+

For $f(x) = {{ value }}$

+

$f'(x) = {{ fprime }}$

+
+{% endblock %} \ No newline at end of file diff --git a/templates/differentiation.html b/templates/differentiation.html new file mode 100644 index 0000000..ebfad20 --- /dev/null +++ b/templates/differentiation.html @@ -0,0 +1,28 @@ +{% extends "layout.html" %} + +{% block title %} + Differentiation +{% endblock %} + +{% block main %} +

Function you would like to Derive:

+
+
+ +
+

Your Input Will Appear Here

+ +
+ + + +{% endblock %} diff --git a/templates/differentiation0.html b/templates/differentiation0.html new file mode 100644 index 0000000..4d26591 --- /dev/null +++ b/templates/differentiation0.html @@ -0,0 +1,28 @@ +{% extends "layout.html" %} + +{% block title %} + Differentiation +{% endblock %} + +{% block main %} +

Function you would like to Derive:

+
+
+ +
+

Your Input Will Appear Here

+ +
+ + + +{% endblock %} \ No newline at end of file diff --git a/templates/index0.html b/templates/index0.html new file mode 100644 index 0000000..ea6e207 --- /dev/null +++ b/templates/index0.html @@ -0,0 +1,15 @@ +{% extends "layout.html" %} + +{% block title %} + Index +{% endblock %} + +{% block main %} +

This is a website dedicated to making the lives of calculus students easier, if ever so slightly.

+

All function inputs will be taken assuming 'x' as your variable. All other letters will be treated as constants

+

That noted, you may enter terms for well known constants and they will likely be accounted for

+

As an example you could enter the function $sin(\pi x)$ with the notation sin(pi*x)

+

As a once struggling calculus student, I highly recommend this site be used either to check your work or as a tool + to understand the steps behind those problems which you failed in solving alone

+

Good luck!

+{% endblock %} \ No newline at end of file diff --git a/templates/integrated.html b/templates/integrated.html new file mode 100644 index 0000000..632ab8a --- /dev/null +++ b/templates/integrated.html @@ -0,0 +1,12 @@ +{% extends "layout.html" %} + +{% block title %} + Integrated +{% endblock %} + +{% block main %} +
+

Your Equation is: ${{ value }}$

+

Your integral is: ${{ fintegral }}$

+
+{% endblock %} \ No newline at end of file diff --git a/templates/integration.html b/templates/integration.html new file mode 100644 index 0000000..6c18d83 --- /dev/null +++ b/templates/integration.html @@ -0,0 +1,28 @@ +{% extends "layout.html" %} + +{% block title %} + Integration +{% endblock %} + +{% block main %} +

Function you would like to Integrate:

+
+
+ +
+

Your Input Will Appear Here

+ +
+ + + +{% endblock %} \ No newline at end of file diff --git a/templates/layout.html b/templates/layout.html index 84b351f..485f9e2 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -43,7 +43,6 @@ diff --git a/templates/layout0.html b/templates/layout0.html new file mode 100644 index 0000000..84b351f --- /dev/null +++ b/templates/layout0.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + ` + + + + C$50 Math: {% block title %}{% endblock %} + + + + + + + + {% if get_flashed_messages() %} +
+ +
+ {% endif %} + +
+ {% block main %}{% endblock %} +
+ + + + + + diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..0a2404b --- /dev/null +++ b/templates/login.html @@ -0,0 +1,17 @@ +{% extends "layout.html" %} + +{% block title %} + Log In +{% endblock %} + +{% block main %} +
+
+ +
+
+ +
+ +
+{% endblock %} diff --git a/templates/maxmin.html b/templates/maxmin.html new file mode 100644 index 0000000..69b0b82 --- /dev/null +++ b/templates/maxmin.html @@ -0,0 +1,31 @@ +{% extends "layout.html" %} + +{% block title %} + Max/Min +{% endblock %} + +{% block main %} + Function you would like to Max/Min: +
+
+ +
+

Your Input Will Appear Here

+
+ + +
+ +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/optimized.html b/templates/optimized.html new file mode 100644 index 0000000..7f04fb2 --- /dev/null +++ b/templates/optimized.html @@ -0,0 +1,64 @@ +{% extends "layout.html" %} + +{% block title %} + Optimized +{% endblock %} + +{% block main %} +
+

Your function is $f(x) = {{ value }}$

+

Your maximum value is ${{ maximum }}$ and your minimum value is ${{ newvar }}$

+
+ + + + + + + + + + + + + + + + + + + + + + + {% for solution in solutions %} + + + + + {% endfor %} + + + + + {% for candidate in candidates %} + + + + + {% endfor %} + + + + + + + + + + + + + +
Step 1Take the Derivative
$f'(x) = {{ fprime }}$
Step 2Set $f'(x) = 0$
$0 = {{ fprime }}$
Step 3Solve for $x$:
$x = {{ solution }}$
Step 4Plug solutions and endpoints into $f(x)$:
$f({{ candidate }}) = {{values[loop.index - 1]}}$
Step 5Grab the highest and lowest values
Your maximum value is ${{ maximum }}$
Your minimum value is ${{ newvar }}$
+{% endblock %} \ No newline at end of file diff --git a/templates/register.html b/templates/register.html new file mode 100644 index 0000000..fc4b942 --- /dev/null +++ b/templates/register.html @@ -0,0 +1,37 @@ +{% extends "layout.html" %} + +{% block title %} + Register +{% endblock %} + +{% block main %} +
+
+ +
+
+ +
+ +
+ +
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/riemann.html b/templates/riemann.html new file mode 100644 index 0000000..c009c4b --- /dev/null +++ b/templates/riemann.html @@ -0,0 +1,42 @@ +{% extends "layout.html" %} + +{% block title %} + Riemann +{% endblock %} + +{% block main %} + Function you would like to integrate: +
+
+ +
+

Your Input Will Appear Here

+ Range of values (a,b): +
+ + +
+ Amount of subintervals (how many rectangles?): +
+ +
+
+ +
+
+ +
+ +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/rightSummed.html b/templates/rightSummed.html new file mode 100644 index 0000000..31eb384 --- /dev/null +++ b/templates/rightSummed.html @@ -0,0 +1,49 @@ +{% extends "layout.html" %} + +{% block title%} + Summed +{% endblock %} + +{% block main %} + Approximating the integral of $f(x) = {{ value }}$ from ${{ lb }}$ to ${{ ub }}$ using ${{ si }}$ subintervals + + + + + + + + + + + + + + + {% for input in inputs %} + + + + + {% endfor %} + + + + + {% for rectangle in rectangles %} + + + + + {% endfor %} + + + + + + + + + +
Step 1Calculate $\Delta x$
$\Delta x = {{ dx }}$
Step 2Check values for $x_i$ (start at lowerbound a and add $\Delta x$ repeatedly)
$f(x_{{ loop.index }}) = f({{ input }}) = {{ outputs[loop.index - 1] }}$
Step 3Multiply $f(x_i)$ and $\Delta x$ for each subinterval
$f(x_{{ loop.index}}) \Delta x = f({{ inputs[loop.index - 1]}})*{{ dx }} = {{ rectangle }}$
Step 4Add up all products (rectangles) to get final approximation:
The integral of $f(x) = {{ value }}$ from ${{ lb }}$ to ${{ ub }}$ is approximately equal to ${{ result }}$
+{% endblock %} \ No newline at end of file diff --git a/templates/summed.html b/templates/summed.html new file mode 100644 index 0000000..abbb7ee --- /dev/null +++ b/templates/summed.html @@ -0,0 +1,49 @@ +{% extends "layout.html" %} + +{% block title%} + Summed +{% endblock %} + +{% block main %} + Approximating the integral of $f(x) = {{ value }}$ from ${{ lb }}$ to ${{ ub }}$ using ${{ si }}$ subintervals + + + + + + + + + + + + + + + {% for input in inputs %} + + + + + {% endfor %} + + + + + {% for rectangle in rectangles %} + + + + + {% endfor %} + + + + + + + + + +
Step 1Calculate $\Delta x$
$\Delta x = {{ dx }}$
Step 2Check values for $x_i$ (start at lowerbound a and add $\Delta x$ repeatedly)
$f(x_{{ loop.index - 1 }}) = f({{ input }}) = {{ outputs[loop.index - 1] }}$
Step 3Multiply $f(x_i)$ and $\Delta x$ for each subinterval
$f(x_{{ loop.index - 1 }}) \Delta x = f({{ inputs[loop.index - 1]}})*{{ dx }} = {{ rectangle }}$
Step 4Add up all products (rectangles) to get final approximation:
The integral of $f(x) = {{ value }}$ from ${{ lb }}$ to ${{ ub }}$ is approximately equal to ${{ result }}$
+{% endblock %} \ No newline at end of file