|
@@ -0,0 +1,152 @@
|
|
|
|
+from sympy import *
|
|
|
|
+from itertools import product, combinations
|
|
|
|
+import plotly.graph_objects as go
|
|
|
|
+import numpy as np
|
|
|
|
+import math
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class solver:
|
|
|
|
+ corners = (-100, 100)
|
|
|
|
+
|
|
|
|
+ data: list[str]
|
|
|
|
+ equalations: list[Equality]
|
|
|
|
+ sequance = None
|
|
|
|
+ solutions: list
|
|
|
|
+ points: list
|
|
|
|
+ ndims: int
|
|
|
|
+ __X = [*symbols('x1 x2 x3')]
|
|
|
|
+
|
|
|
|
+ @staticmethod
|
|
|
|
+ def toEq(data):
|
|
|
|
+ data = data[:]
|
|
|
|
+ for i,linEx in enumerate(data):
|
|
|
|
+ data[i] = Eq(*[simplify(side) for side in linEx.split('=')])
|
|
|
|
+ return data
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def solve(self):
|
|
|
|
+ result = []
|
|
|
|
+ for Eq in self.equalations:
|
|
|
|
+ lin = []
|
|
|
|
+ for prod in product([-100, 100], repeat=self.ndims-1):
|
|
|
|
+ subEq = Eq.copy()
|
|
|
|
+ X = self.__X[:]
|
|
|
|
+ high_sym = sorted(list(subEq.free_symbols), key=lambda x: x.name)[0]
|
|
|
|
+ X.remove(high_sym)
|
|
|
|
+ values = [(sym,corner) for sym, corner in zip(X, prod)]
|
|
|
|
+ subEq = subEq.subs(values)
|
|
|
|
+ solution = int(solve(subEq, high_sym)[0])
|
|
|
|
+ values.append((high_sym, solution))
|
|
|
|
+ lin.append(sorted(values, key=lambda x: x[0].name))
|
|
|
|
+ result.append([[dot[dim][1] for dot in lin] for dim in range(self.ndims)])
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def right_dote(self, dote):
|
|
|
|
+ flag = True
|
|
|
|
+ for line in self.data:
|
|
|
|
+ for sym, val in zip(self.__X, dote): line = line.replace(sym.name, str(val))
|
|
|
|
+ flag *= eval(line)
|
|
|
|
+ return flag
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def get_dots(self):
|
|
|
|
+ result = []
|
|
|
|
+ for Eqs in combinations(self.equalations, r=2):
|
|
|
|
+ if Eqs[0] == Eqs[1]: continue
|
|
|
|
+ solution = list(solve(Eqs, Eqs[0].free_symbols | Eqs[1].free_symbols, set=True))[1]
|
|
|
|
+ if len(solution) == 0: continue
|
|
|
|
+ dot = list(solve(Eqs, Eqs[0].free_symbols | Eqs[1].free_symbols, set=True)[1])[0]
|
|
|
|
+ if self.right_dote(dot): result.append(dot)
|
|
|
|
+ reference_point = result[0]
|
|
|
|
+ sorted_coordinates = sorted(result, key=lambda point: math.atan2(point[1] - reference_point[1], point[0] - reference_point[0]))
|
|
|
|
+ return [[float(val[dim]) for val in sorted_coordinates] for dim in range(self.ndims)]
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def show(self):
|
|
|
|
+ fig = go.Figure()
|
|
|
|
+ for line, names in zip(self.solutions, self.data):
|
|
|
|
+ fig.add_trace(go.Scatter({dim:val for val, dim in zip(line, ('x','y','z'))}, name=str(names)))
|
|
|
|
+ fig.add_trace(go.Scatter({dim:val for val, dim in zip(self.get_dots(), ('x','y','z'))}, mode='markers', fill='toself', fillpattern=dict(fillmode='replace', shape='x')))
|
|
|
|
+ fig.add_trace(go.Scatter(x=[0, self.gradient[0]], y=[0, self.gradient[1]],
|
|
|
|
+ marker=dict(color='black', symbol='arrow', size=16, angleref="previous"),
|
|
|
|
+ line = dict(width=4, dash='dot', color='black')))
|
|
|
|
+ touch = len(fig.data)
|
|
|
|
+
|
|
|
|
+ for step in np.arange(0, self.count, self.step):
|
|
|
|
+ k = ((self.gradient[1]-0) * (step-0) - (self.gradient[1]-0) * (0-0)) / ((self.gradient[1]-0)**2 + (self.gradient[0]-0)**2)
|
|
|
|
+ x4 = step - k * (self.gradient[1]-0)
|
|
|
|
+ y4 = 0 + k * (self.gradient[0]-0)
|
|
|
|
+ y5 = y4+y4
|
|
|
|
+ x5 = x4+(x4-step)
|
|
|
|
+
|
|
|
|
+ fig.add_trace(
|
|
|
|
+ go.Scatter(visible=False, line=dict(color='black', width=2),
|
|
|
|
+ x=[step, x4, x5], y=[0, y4, y5])
|
|
|
|
+ )
|
|
|
|
+ fig.data[touch].visible = True
|
|
|
|
+
|
|
|
|
+ steps = []
|
|
|
|
+ for i in range(len(fig.data[touch:])):
|
|
|
|
+ step = dict(
|
|
|
|
+ method="update",
|
|
|
|
+ args=[{"visible": [True]*touch + [False] * (len(fig.data)-touch)},
|
|
|
|
+ {"title": "Slider switched to step: " + str(i)}], # layout attribute
|
|
|
|
+ )
|
|
|
|
+ step["args"][0]["visible"][i] = True # Toggle i'th trace to "visible"
|
|
|
|
+ steps.append(step)
|
|
|
|
+
|
|
|
|
+ sliders = [dict(
|
|
|
|
+ active=10,
|
|
|
|
+ currentvalue={"prefix": "Frequency: "},
|
|
|
|
+ pad={"t": 50},
|
|
|
|
+ steps=steps
|
|
|
|
+ )]
|
|
|
|
+
|
|
|
|
+ fig.update_layout(
|
|
|
|
+ sliders=sliders
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ fig.update_xaxes(title_text='x1', gridwidth=1)
|
|
|
|
+ fig.update_yaxes(title_text='x2', gridwidth=1)
|
|
|
|
+ fig.show()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def __init__(self, seq: str, data: list[str], ndims=2, step=0.01, count=10):
|
|
|
|
+ self.data = data
|
|
|
|
+ self.gradient = list(map(int,Poly(simplify(seq)).coeffs()))
|
|
|
|
+ self.equalations = solver.toEq([lin.replace('>','').replace('<', '') for lin in data])
|
|
|
|
+ self.ndims = ndims
|
|
|
|
+ self.__X = self.__X[:ndims]
|
|
|
|
+ self.solutions = self.solve()
|
|
|
|
+ self.count = count
|
|
|
|
+ self.step = step
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
+ # solver( seq='3*x1 + 4*x2',
|
|
|
|
+ # data=['4*x1 + x2 <= 8',
|
|
|
|
+ # 'x1 >= 0',
|
|
|
|
+ # 'x1 - x2 >= -3',
|
|
|
|
+ # 'x2 >= 0'], ndims=2).show()
|
|
|
|
+
|
|
|
|
+ # solver( seq='3*x1 + 2*x2',
|
|
|
|
+ # data=['2*x1 + 3*x2 <= 6',
|
|
|
|
+ # 'x1 <= 2', 'x1 >= 0',
|
|
|
|
+ # '2*x1 - x2 >= 0',
|
|
|
|
+ # 'x2 >= 0', 'x2 <= 1'], ndims=2).show()
|
|
|
|
+
|
|
|
|
+ # solver( seq='x1 + 3*x2',
|
|
|
|
+ # data=['2*x1 + 3*x2 <= 24',
|
|
|
|
+ # 'x1 >= 0',
|
|
|
|
+ # 'x1 - x2 <= 7',
|
|
|
|
+ # 'x2 >= 0', 'x2 <= 6'], ndims=2, step=0.1, count=25).show()
|
|
|
|
+
|
|
|
|
+ # solver( seq='x1 - 1.1*x2 + 7.4',
|
|
|
|
+ # data=['x1 >= 0',
|
|
|
|
+ # 'x2 >= 0',
|
|
|
|
+ # 'x1 + x2 <= 10',
|
|
|
|
+ # '10 - x1 >= 0', '10 - x2 >= 0'], ndims=2, step=0.1, count=15).show()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ pass
|