2
\$\begingroup\$

I quickly wrote this program to transform quadratic expressions in general form into vertex form.

\$ax^2 + bx + c \;=\; a(x-h)^2 + k,\quad\text{where}\quad h = -\frac{b}{2a} \quad\text{and}\quad k = c - ah^2 = c - \frac{b^2}{4a}.\$

The actual conversion is easy, but with writing a lexer/parser came pain points:

  • I tokenize with Regex, and some of the regex patterns are built dynamically using f-strings (which seems suspect).

  • I use eval to compute terms in parentheses (to make fractions easy to input, for example).

I also feel like there's probably a library for working with ASCII-fied algebraic expressions, (lots of the same kind of code populates sites like Symbolab, Cymath and Desmos,) but I do not know of it.

## Tests:
# user_in = "(16/4)x^2 7x (3**2)" -> "Result is: 4.0(x + (0.875))^2 + (5.9375)" (Passes)
# user_in = "(41*4)x^2 41x 2" -> "Result is: 164.0(x + (0.125))^2 + (-0.5625)" (Passes)
# user_in = "x^2 4" -> "Result is: (x + (2.0))^2 + (-4.0)" (Fails)
# user_in = "x^2 4x 16" -> "Result is (x + (2.0))^2 + 12.0" (Fails)
import re
print("""~~~Square Completer!~~~
Enter the terms of your quadratic equation in standard form
Addition is implied, terms separated by spaces.
Only use one kind of single-letter variable in the whole expression.
Surround computations such as constant multiplication and fractions in parens.
DO NOT put variables inside parens!""")
user_in = input("> ")
# extract the variable
def extract_variable(expression):
 letters = re.findall(r'[a-z]', expression) # all the letters
 if all(match == letters[0] for match in letters): # if all letters == the first one
 return letters[0] # we have our variable
 else:
 raise ValueError("Only use one kind of single-letter variable in the whole expression.")
variable = extract_variable(user_in)
# eval all things in parens and split string into terms
def split_into_terms(expression):
 expression = re.sub(fr"\([^{variable}\)]+\)", lambda m: str(eval(m.group())), expression)
 print(f"working with {expression}")
 return expression.split(' ')
terms = split_into_terms(user_in)
print(terms)
# sort terms into bins
def bin_terms(terms):
 squareds, x_es, constants = [], [], []
 for term in terms:
 term = term.strip().lower()
 if term.endswith('^2'):
 squareds.append(term[:-2]) # without trailing '^2'
 elif term.endswith(variable):
 x_es.append(term)
 elif bool(re.search(r"^-?[0-9\.]+$", term)): # if the term contains only numbers
 constants.append(term)
 return squareds, x_es, constants
squareds, x_es, constants = bin_terms(terms)
print('unprocessed:', squareds, x_es, constants, sep='\n')
def sum_bins(squareds, x_es, constants):
 squareds = [squared[:-1] for squared in squareds if squared.endswith(variable)] # 2x -> 2
 print('squareds step1:', squareds, sep='\n')
 squareds = ['1' if squared == variable else squared for squared in squareds] # x -> 1
 print('step2:', squareds)
 print('\nprocessed:', squareds, x_es, constants, sep='\n')
 constant = sum(float(c) for c in constants)
 print('\n ***EXES: ', x_es,'***')
 x = sum(float(el[:-1]) for el in x_es)
 print('\n ***SUMX: ', x,'***')
 squared = sum(float(el) for el in squareds)
 return squared, x, constant
squared, x, constant = sum_bins(squareds, x_es, constants)
##print('\ntotals:', squared, x, constant, sep='\n')
##constant = constant / squared
##x = x / squared
##squared = 1
##print('\nover square term:', squared, x, constant, sep='\n')
def complete_square(a,b,c):
 """
 Complete the square, transforming a quadratic
 of form
 ax^2 + bx + c
 to form
 a(x + p)^2 - q
 """
 p = b/(2*a)
 q = c - (b**2)/(4*a)
 return p, q
p, q = complete_square(squared, x, constant)
a = squared
print(f'Result is: {a}({variable} + ({p}))^2 + ({q})')
asked Nov 19, 2019 at 6:15
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

There is a library to help with this! Check out sympy, particularly sympify and parse_expr.

answered Nov 19, 2019 at 22:14
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.