Skip to content

Commit 7c3a3bf

Browse files
committed
feat(Watchtower): Simplification
# |<---- Using a Maximum Of 50 Characters ---->| # Explain why this change is being made # |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->| # Provide links or keys to any relevant tickets, articles or other resources # Example: Github issue #23 # --- COMMIT END --- # Type can be # feat (new feature) # fix (bug fix) # refactor (refactoring production code) # style (formatting, missing semi colons, etc; no code change) # docs (changes to documentation) # test (adding or refactoring tests; no production code change) # chore (updating grunt tasks etc; no production code change) # -------------------- # Remember to # Capitalize the subject line # Use the imperative mood in the subject line # Do not end the subject line with a period # Separate subject from body with a blank line # Use the body to explain what and why vs. how # Can use multiple lines with "-" for bullet points in body # -------------------- # For more information about this template, check out # https://gist.github.com/adeekshith/cd4c95a064977cdc6c50
1 parent 0854d84 commit 7c3a3bf

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import functools
2+
import operator
3+
import re
4+
5+
6+
class Polynomial:
7+
def __init__(self, val):
8+
if isinstance(val, list):
9+
self.plist = val
10+
11+
def __add__(self, other):
12+
if len(self.plist) > len(other.plist):
13+
new = [i for i in self.plist]
14+
for i in range(len(other.plist)):
15+
new[i] += other.plist[i]
16+
else:
17+
new = [i for i in other.plist]
18+
for i in range(len(self.plist)):
19+
new[i] += self.plist[i]
20+
return Polynomial(new)
21+
22+
def __radd__(self, other):
23+
return self.__add__(other)
24+
25+
def __sub__(self, other):
26+
return self.__add__(other.__neg__())
27+
28+
def __rsub__(self, other):
29+
return -Polynomial.__sub__(other)
30+
31+
def __mul__(self, other):
32+
result = []
33+
for i in range(len(other.plist)):
34+
result.append(
35+
Polynomial([0] * i + [j * other.plist[i] for j in self.plist])
36+
)
37+
return functools.reduce(operator.add, result)
38+
39+
def __rmul__(self, other):
40+
return self.__mul__(other)
41+
42+
def __neg__(self):
43+
return Polynomial([-1]) * self
44+
45+
def __repr__(self):
46+
result = []
47+
for i in range(len(self.plist)):
48+
if i == 0:
49+
result.insert(0, str(self.plist[i]))
50+
else:
51+
if self.plist[i] == 0:
52+
continue
53+
else:
54+
if self.plist[i] == 1:
55+
base_str = 'x'
56+
else:
57+
base_str = str(self.plist[i]) + '*x'
58+
if i == 1:
59+
result.insert(0, base_str)
60+
else:
61+
result.insert(0, base_str + '**' + str(i))
62+
for i in range(1, len(result)):
63+
if result[i][0] != '-':
64+
result[i] = '+' + result[i]
65+
for i in range(len(result)):
66+
if result[i][0] == '-':
67+
if result[i][1] == '1' and '*' in result[i] and result[i][2] == '*':
68+
result[i] = result[i][0] + result[i][3:]
69+
70+
if result[-1] == '+0' and len(result) > 1:
71+
result.pop()
72+
return ''.join(result)
73+
74+
75+
def tokenise(expr):
76+
symbols = list(expr)
77+
# merge numbers
78+
changed = True
79+
while changed:
80+
changed = False
81+
for i in range(len(symbols) - 1):
82+
try:
83+
int(symbols[i])
84+
int(symbols[i + 1])
85+
symbols = symbols[:i] + [symbols[i] + symbols[i + 1]] + symbols[i + 2 :]
86+
changed = True
87+
break
88+
except ValueError:
89+
pass
90+
91+
# convert numbers and x
92+
for i in range(len(symbols)):
93+
try:
94+
int(symbols[i])
95+
symbols[i] = Polynomial([int(symbols[i])])
96+
except ValueError:
97+
if symbols[i] == 'x':
98+
symbols[i] = Polynomial([0, 1])
99+
return symbols
100+
101+
102+
def calc(tokens):
103+
while len(tokens) > 1:
104+
if ')' in tokens:
105+
right_bracket = tokens.index(')')
106+
sub_tokens = tokens[:right_bracket]
107+
sub_tokens.reverse()
108+
left_bracket = len(sub_tokens) - sub_tokens.index('(') - 1
109+
tokens = (
110+
tokens[:left_bracket]
111+
+ calc(tokens[left_bracket + 1 : right_bracket])
112+
+ tokens[right_bracket + 1 :]
113+
)
114+
elif '*' in tokens:
115+
index = tokens.index('*')
116+
tokens = (
117+
tokens[: index - 1]
118+
+ [tokens[index - 1] * tokens[index + 1]]
119+
+ tokens[index + 2 :]
120+
)
121+
elif '-' in tokens:
122+
index = tokens.index('-')
123+
tokens = (
124+
tokens[: index - 1]
125+
+ [tokens[index - 1] - tokens[index + 1]]
126+
+ tokens[index + 2 :]
127+
)
128+
else:
129+
index = tokens.index('+')
130+
tokens = (
131+
tokens[: index - 1]
132+
+ [tokens[index - 1] + tokens[index + 1]]
133+
+ tokens[index + 2 :]
134+
)
135+
return tokens
136+
137+
138+
def simplify(expr):
139+
tokens = tokenise(expr)
140+
result = calc(tokens)[0]
141+
return str(result)
142+
143+
144+
if __name__ == "__main__": # pragma: no cover
145+
# These "asserts" using only for self-checking and not necessary for
146+
# auto-testing
147+
assert simplify("(x-1)*(x+1)") == "x**2-1", "First and simple"
148+
assert simplify("(x+1)*(x+1)") == "x**2+2*x+1", "Almost the same"
149+
assert simplify("(x+3)*x*2-x*x") == "x**2+6*x", "Different operations"
150+
assert simplify("x+x*x+x*x*x") == "x**3+x**2+x", "Don't forget about order"
151+
assert simplify("(2*x+3)*2-x+x*x*x*x") == "x**4+3*x+6", "All together"
152+
assert simplify("x*x-(x-1)*(x+1)-1") == "0", "Zero"
153+
assert simplify("5-5-x") == "-x", "Negative C1"
154+
assert simplify("x*x*x-x*x*x-1") == "-1", "Negative C0"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import unittest
2+
3+
from simplification import simplify
4+
5+
6+
class Tests(unittest.TestCase):
7+
TESTS = {
8+
"Basics": [
9+
{"input": "(x-1)*(x+1)", "answer": "x**2-1"},
10+
{"input": "(x+1)*(x+1)", "answer": "x**2+2*x+1"},
11+
{"input": "(x+3)*x*2-x*x", "answer": "x**2+6*x"},
12+
{"input": "x+x*x+x*x*x", "answer": "x**3+x**2+x"},
13+
{"input": "(2*x+3)*2-x+x*x*x*x", "answer": "x**4+3*x+6"},
14+
{"input": "x*x-(x-1)*(x+1)-1", "answer": "0"},
15+
{"input": "5-5-x", "answer": "-x"},
16+
{"input": "x*x*x-x*x*x-1", "answer": "-1"},
17+
],
18+
"Extra": [
19+
{"input": "(x-1)*(x-1)", "answer": "x**2-2*x+1"},
20+
{"input": "(x+3)*(x+3)", "answer": "x**2+6*x+9"},
21+
{"input": "(x+4)*x*3-x*x", "answer": "2*x**2+12*x"},
22+
{"input": "x+x*x+x*x*x*x", "answer": "x**4+x**2+x"},
23+
{"input": "2*(2*x+3)-x+x*x*x*x", "answer": "x**4+3*x+6"},
24+
{"input": "3+4*x-24-2*x", "answer": "2*x-21"},
25+
{"input": "(x+1)*x*(x+1)", "answer": "x**3+2*x**2+x"},
26+
{"input": "x*x*x*x*x+100-2", "answer": "x**5+98"},
27+
{"input": "(x-500)*(x+500)", "answer": "x**2-250000"},
28+
{"input": "(x-2)*(x+2)*(x+2)", "answer": "x**3+2*x**2-4*x-8"},
29+
],
30+
"Generated": [
31+
{
32+
"input": "84-x+x*37*80+78-98+x-(x)+(23)*x+x-x+x+78-(x*32+61+x-10*x*x)-(59*x)-(x)-x*49+x+23*72+0+(x+x)+(x*(x))",
33+
"answer": "11*x**2+2844*x+1737",
34+
},
35+
{
36+
"input": "74-x-15+x+31*x+95*(x+88)*38-x-25-23+x*x+49+x-(47+x+28-43*x-x-39+x-x-83*62)",
37+
"answer": "x**2+3684*x+322850",
38+
},
39+
{
40+
"input": "(x+13-(x*x*x)*x-(x)-x+19-x*10*(x*62)+x-x*0*(66)*83-93+x-(21*x+(85-77+x-x)))",
41+
"answer": "-x**4-620*x**2-20*x-69",
42+
},
43+
{
44+
"input": "79+15*7-x+x-x+48-65+x-38+x+46*x*x*(3)+0+(45)",
45+
"answer": "138*x**2+x+174",
46+
},
47+
{
48+
"input": "98*85*x*(x-x-(x*(x-41-(x)+3-31+(41)*54*13-x+(x))))",
49+
"answer": "-239179290*x**2",
50+
},
51+
{
52+
"input": "24*45*(23*42+73-x)-x-75-13-41*(47-49*(x*25*(x*(x-(x-48*16+55*97)+x-54))))",
53+
"answer": "50225*x**3-232089725*x**2-1081*x+1120105",
54+
},
55+
{
56+
"input": "x+x-x+x*x+x*x*x-x*x*x*(4*x+84*x*x-x*x*x-x-x)+x-x-x",
57+
"answer": "x**6-84*x**5-2*x**4+x**3+x**2",
58+
},
59+
{"input": "72*x*x-(x+x-x*x)+x*81", "answer": "73*x**2+79*x"},
60+
{
61+
"input": "11+(x)*(x*x)*x*(x+x*20-(15)*x-(40+(x)-(x*x*x+x+x)*x+47-(x)))",
62+
"answer": "x**8+2*x**6+6*x**5-87*x**4+11",
63+
},
64+
],
65+
}
66+
67+
def test_Basics(self):
68+
for i in self.TESTS['Basics']:
69+
assert simplify(i['input']) == i['answer']
70+
71+
def test_Extra(self):
72+
for i in self.TESTS['Extra']:
73+
assert simplify(i['input']) == i['answer']
74+
75+
def test_Generated(self):
76+
for i in self.TESTS['Generated']:
77+
assert simplify(i['input']) == i['answer']

0 commit comments

Comments
 (0)