-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
125 lines (100 loc) · 3.91 KB
/
Copy pathmain.py
File metadata and controls
125 lines (100 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from abc import ABC, abstractmethod
import re
class Equation(ABC):
degree: int
type: str
def __init__(self, *args):
if len(args) != self.degree+1:
raise TypeError(f"'{self.__class__.__name__}' object takes {self.degree + 1} positional arguments but {len(args)} were given")
if any(not isinstance(arg, (int, float)) for arg in args):
raise TypeError("Coefficients must be of type 'int' or 'float'")
if args[0] == 0:
raise ValueError('Highest degree coefficient must be different from zero')
self.coefficients = {i: args[self.degree - i] for i in range(self.degree, -1, -1) }
def __init_subclass__(cls):
if not hasattr(cls, 'degree'):
raise AttributeError(f"Cannot create '{cls.__name__}' class: missing required attribute 'degree'")
if not hasattr(cls, 'type'):
raise AttributeError(f"Cannot create '{cls.__name__}' class: missing required attribute 'type'")
def __str__(self):
terms = []
for n, coefficient in self.coefficients.items():
if not coefficient:
continue
if n == 0:
terms.append(f'{coefficient:+}')
elif n == 1:
terms.append(f'{coefficient:+}x')
else:
terms.append(f'{coefficient:+}x**{n}')
equation_string = ' '.join(terms) + ' = 0'
return re.sub(r'(?<!\d)1(?=x)','',equation_string.strip('+'))
@abstractmethod
def solve(self):
pass
@abstractmethod
def analyze(self):
pass
class LinearEquation(Equation):
degree = 1
type = 'Linear Equation'
def solve(self):
a, b = self.coefficients.values()
x = -b/a
return [x]
def analyze(self):
slope, intercept = self.coefficients.values()
return {'slope': slope, 'intercept': intercept}
class QuadraticEquation(Equation):
degree = 2
type = 'Quadratic Equation'
def __init__(self, *args):
super().__init__(*args)
a, b, c = self.coefficients.values()
self.delta = b**2 - 4 * a * c
def solve(self):
if self.delta < 0:
return []
a, b, _ = self.coefficients.values()
x1 = (-b + self.delta**0.5) / (2 * a)
x2 = (-b - self.delta**0.5) / (2 * a)
if self.delta == 0:
return[x1]
return [x1, x2]
def analyze(self):
a, b, c = self.coefficients.values()
x = -b/(2*a)
y = a*x**2 + b*x + c
concavity = 'upwards' if a>0 else 'downwards'
min_max = 'min' if a>0 else 'max'
return {'x': x, 'y': y, 'min_max': min_max, 'concavity':concavity}
def solver(equation):
if not isinstance(equation, Equation):
raise TypeError('Argument must be an Equation object')
output_string = f'\n{equation.type:-^24}'
output_string += f'\n\n{equation!s:^24}\n\n'
output_string += f'{"Solutions":-^24}\n\n'
results = equation.solve()
match results:
case []:
result_list = ['No real roots']
case [x]:
result_list = [f'x = {x:+.3f}']
case [x1, x2]:
result_list = [f'x1 = {x1:+.3f}', f'x2 = {x2:+.3f}']
for result in result_list:
output_string += f'{result:^24}\n'
output_string += f'\n{"Details":-^24}\n\n'
details = equation.analyze()
match details:
case {'slope': slope, 'intercept': intercept}:
details_list = [f'slope = {slope:>16.3f}', f'y-intercept = {intercept:>10.3f}']
case {'x': x, 'y': y, 'min_max': min_max, 'concavity': concavity}:
coord = f'({x:.3f}, {y:.3f})'
details_list = [f'concavity = {concavity:>12}', f'{min_max} = {coord:>18}']
for detail in details_list:
output_string += f'{detail}\n'
return output_string
lin_eq = LinearEquation(2,3)
quadr_eq = QuadraticEquation(1, 2, 1)
print(solver(lin_eq))