1
0
skaitiniai-metodai-labs/Lab2/main_2.py
2023-11-27 23:05:39 +02:00

366 lines
11 KiB
Python

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from dataclasses import dataclass
from typing import Iterable
import tkinter as tk
EPSILON = 1e-12
def ScrollTextBox(w,h):
"""
sukuria TextBox su scrolais pagal w ir pagal h
w ir h _ plotis ir aukstis
Grazina textBoxa T
Programoje textBox sukuriamas: T=ScrollTextBox(140,20)
Irasoma komandomis : T.insert(END,str+"\n"); T.yview(END)
"""
root = tk.Tk(); root.title("Scroll Text Box")
frame1=tk.Frame(root); frame1.pack()
#T = ScrolledText(root, height=h, width=w,wrap=WORD) # jeigu reikia scrolinti tik pagal h
scrollbarY = tk.Scrollbar(frame1, orient='vertical'); scrollbarY.pack(side=tk.RIGHT, fill=tk.Y)
scrollbarX = tk.Scrollbar(frame1, orient='horizontal'); scrollbarX.pack(side=tk.BOTTOM, fill=tk.X)
T = tk.Text(frame1, width = w, height = h, wrap = tk.NONE,yscrollcommand = scrollbarY.set,xscrollcommand = scrollbarX.set)
T.pack();
scrollbarX.config(command = T.xview); scrollbarY.config(command = T.yview)
return T
def SpausdintiMatrica(*args):
"""
A - matrica
T - TextBox
str - eilute pradzioje, str=, neprivaloma
"""
A=args[0]; T=args[1]; str="";
if len(args) == 3: str=args[2];
siz=np.shape(A)
T.insert(tk.END,"\n"+str+"=")
if len(siz) > 0:
for i in range (0,siz[0]):
T.insert(tk.END,"\n")
if len(siz) > 1:
for j in range (0,siz[1]): T.insert(tk.END,"%12g "%A[i,j]);
else: T.insert(tk.END,"%12g "%A[i])
else : T.insert(tk.END,"%12g "%A);
T.yview(tk.END)
T.update()
def Pavirsius(X, Y,LFF):
"""
X,Y - meshgrid masyvai
LF - dvieju kintamuju vektorines funkcijos vardas, argumentas paduodamas vektoriumi, isejimas vektorius ilgio 2
rezultatas - dvigubas meshgrid masyvas Z[:][:][0:1]
"""
siz=np.shape(X)
Z=np.zeros(shape=(siz[0],siz[1],2))
for i in range (0,siz[0]):
for j in range (0,siz[1]): Z[i,j,:]=LFF([X[i][j],Y[i][j]]).transpose();
return Z
@dataclass
class BroidenoRezultatas:
x1: float
x2: float
y1: float
y2: float
tikslumas: float
iteracija: int
@dataclass
class Tinklelis:
from_x1: float
to_x1: float
from_x2: float
to_x2: float
density: int
def gauti_bendra_lygti(Z1, Z2):
def LF(x): # grazina reiksmiu stulpeli
s = np.array([
Z1(x[0], x[1]),
Z2(x[0], x[1]),
])
s.shape=(2,1)
return np.matrix(s)
return LF
def gauti_tiksluma(x1, x2, f1, f2):
x_abs_diff = np.abs(x1-x2)
x_abs_sum = x1+x2
f1_abs = np.abs(f1)
f2_abs = np.abs(f2)
if not np.isscalar(x1):
x_abs_diff = sum(x_abs_diff)
x_abs_sum = sum(x_abs_sum)
f1_abs = sum(f1_abs)
f2_abs = sum(f2_abs)
if x_abs_sum > EPSILON:
return x_abs_diff/(x_abs_sum + f1_abs + f2_abs)
else:
return x_abs_diff + f1_abs + f2_abs
def broideno_metodas_iter(
init_x1: float,
init_x2: float,
Z1,
Z2,
) -> Iterable[BroidenoRezultatas]:
MAX_ITERATIONS = 80 # didziausias leistinas iteraciju skaicius
JACOB_DX = 0.1 # dx pradiniam Jakobio matricos iverciui
if init_x1 == 0 and init_x2 == 0:
return
n = 2 # lygciu skaicius
x = np.matrix(np.zeros(shape=(n,1)))
x[0] = init_x1
x[1] = init_x2
LF = gauti_bendra_lygti(Z1, Z2)
A = np.matrix(np.zeros(shape=(n,n)))
x1 = np.zeros(shape=(n,1))
for i in range(0,n):
x1 = np.matrix(x)
x1[i] += JACOB_DX
A[:,i] = (LF(x1) - LF(x))/JACOB_DX
ff = LF(x)
for i in range(1, MAX_ITERATIONS+1):
deltax = -np.linalg.solve(A,ff)
x1 = np.matrix(x + deltax)
ff1 = LF(x1)
A += (ff1 - ff - A*deltax)*deltax.transpose()/(deltax.transpose() * deltax)
tiksl = gauti_tiksluma(x, x1, ff, ff1)
ff = ff1
x = x1
yield BroidenoRezultatas(
x1[0, 0],
x1[1, 0],
ff1[0, 0],
ff1[1, 0],
tiksl[0, 0],
i
)
def broideno_metodas(
init_x1: float,
init_x2: float,
Z1,
Z2,
):
for rez in broideno_metodas_iter(init_x1, init_x2, Z1, Z2):
if rez.tikslumas < EPSILON:
return rez
def viz_broideno_metodas(
init_x1: float,
init_x2: float,
Z1,
Z2,
view_x1 = (-8, 8),
view_x2 = (-8, 8)
):
T = ScrollTextBox(100,20) # sukurti teksto isvedimo langa
T.insert(tk.END,"Broideno metodas")
#------ Grafika: funkciju LF pavirsiai -----------------------------------------------------------------------
fig1 = plt.figure(1, figsize=plt.figaspect(0.5))
ax1 = fig1.add_subplot(1, 2, 1, projection='3d')
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_zlabel('Z')
ax2 = fig1.add_subplot(1, 2, 2, projection='3d')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_zlabel('z')
plt.draw() #plt.pause(1);
xx = np.linspace(view_x1[0], view_x1[1], 20)
yy = np.linspace(view_x2[0], view_x2[1], 20)
X, Y = np.meshgrid(xx, yy)
Z = Pavirsius(X, Y, gauti_bendra_lygti(Z1, Z2))
# surf1 = ax1.plot_surface(X, Y, Z[:,:,0], color='blue', alpha=0.4, linewidth=0.1, antialiased=True)
wire1 = ax1.plot_wireframe(X, Y, Z[:,:,0], color='black', alpha=1, linewidth=1, antialiased=True)
surf2 = ax1.plot_surface(X, Y, Z[:,:,1], color='purple', alpha=0.4, linewidth=0.1, antialiased=True)
CS11 = ax1.contour(X, Y, Z[:,:,0],[0], colors='b')
CS12 = ax1.contour(X, Y, Z[:,:,1],[0], colors='g')
CS1 = ax2.contour(X, Y, Z[:,:,0],[0], colors='b')
CS2 = ax2.contour(X, Y, Z[:,:,1],[0], colors='g')
XX = np.linspace(-5,5,2)
YY = XX
XX, YY = np.meshgrid(XX, YY)
ZZ = XX*0
zeroplane = ax2.plot_surface(XX, YY, ZZ, color='gray', alpha=0.4, linewidth=0, antialiased=True)
#---------------------------------------------------------------------------------------------------------------
init_y1 = Z1(init_x1, init_x2)
init_y2 = Z2(init_x1, init_x2)
ax1.plot3D([init_x1, init_x1], [init_x2, init_x2], [0, init_y1], "m*-")
plt.draw()
plt.pause(1)
prev_x = (init_x1, init_x2)
prev_y = (init_y1, init_y2)
final_rez = None
for rez in broideno_metodas_iter(init_x1, init_x2, Z1, Z2):
SpausdintiMatrica(rez.tikslumas, T, "tiksl")
if rez.tikslumas < EPSILON:
final_rez = rez
break
SpausdintiMatrica(np.matrix([[rez.x1], [rez.x2]]), T, "x1")
#------ Grafika: -----------------------------------------------------------------------------------------------
ax1.plot3D([rez.x1,rez.x1], [rez.x2,rez.x2], [0 ,0 ], "ro-") # reikia prideti antra indeksa, kadangi x yra matrica
ax1.plot3D([rez.x1,rez.x1], [rez.x2,rez.x2], [rez.y1,rez.y1], "c-.")
ax1.plot3D([rez.x1,rez.x1], [rez.x2,rez.x2], [0 ,rez.y1], "m*-")
ax2.plot3D([rez.x1,rez.x1], [rez.x2,rez.x2], [0 ,0 ], "ro-")
plt.draw()
plt.pause(2)
#---------------------------------------------------------------------------------------------------------------
prev_x = (rez.x1, rez.x2)
prev_y = (rez.y1, rez.y2)
#------ Grafika: ---------------------------------------
ax1.plot3D([prev_x[0],prev_x[0]], [prev_y[1],prev_y[1]], [0,0], "ks")
ax2.plot3D([prev_x[0],prev_x[0]], [prev_y[1],prev_y[1]], [0,0], "ks")
plt.draw()
plt.pause(1)
#--------------------------------------------------------
assert final_rez
SpausdintiMatrica(np.matrix([[final_rez.x1], [final_rez.x2]]), T, "Sprendinys")
SpausdintiMatrica(final_rez.tikslumas, T, "Galutinis tikslumas")
# print("Plotting pre-finished")
# plt.show()
# print("Plotting finished")
def iter_tinklelis(tinklelis: Tinklelis):
for x1_idx in range(tinklelis.density):
x1 = lerp(tinklelis.from_x1, tinklelis.to_x1, (x1_idx + 0.5)/tinklelis.density)
for x2_idx in range(tinklelis.density):
x2 = lerp(tinklelis.from_x2, tinklelis.to_x2, (x2_idx + 0.5)/tinklelis.density)
yield (x1, x2)
def viz_broideno_tinklelis(
Z1,
Z2,
tinklelis: Tinklelis,
precision = 5,
circle_colors = [
(0.1, 0.1, 0.1),
(0.1, 0.8, 0.8),
(0.1, 0.8, 0.1),
(0.1, 0.1, 0.8),
(0.8, 0.8, 0.1),
(0.8, 0.1, 0.8),
(0.4, 0.4, 0.4)
]
):
tinklelio_reiksmes = {}
sprendiniai = []
for x1, x2 in iter_tinklelis(tinklelis):
broideno_rez = broideno_metodas(x1, x2, Z1, Z2)
if broideno_rez:
rez_x1 = round(broideno_rez.x1, precision)
rez_x2 = round(broideno_rez.x2, precision)
tinklelio_reiksmes[(x1, x2)] = (rez_x1, rez_x2)
if (rez_x1, rez_x2) not in sprendiniai:
sprendiniai.append((rez_x1, rez_x2))
else:
tinklelio_reiksmes[(x1, x2)] = None
print(sprendiniai)
fig1 = plt.figure(1)
ax = fig1.add_subplot(1, 1, 1)
ax.set_xlabel('x1')
ax.set_ylabel('x2')
ax.set_xlim(tinklelis.from_x1, tinklelis.to_x1)
ax.set_ylim(tinklelis.from_x2, tinklelis.to_x2)
plt.draw()
xx = np.linspace(tinklelis.from_x1, tinklelis.to_x1, tinklelis.density)
yy = np.linspace(tinklelis.from_x2, tinklelis.to_x2, tinklelis.density)
X, Y = np.meshgrid(xx, yy)
Z = Pavirsius(X, Y, gauti_bendra_lygti(Z1, Z2))
ax.contour(X, Y, Z[:,:,0],[0], colors=[(0.8, 0.4, 0.1, 1)], linewidths=4.0)
ax.contour(X, Y, Z[:,:,1],[0], colors=[(0.8, 0.1, 0.4, 1)], linewidths=4.0)
assert (len(sprendiniai)+1) <= len(circle_colors)
circle_width = (tinklelis.to_x1 - tinklelis.from_x1) / tinklelis.density / 2
circle_height = (tinklelis.to_x2 - tinklelis.from_x2) / tinklelis.density / 2
circle_radius = min(circle_width, circle_height) * 0.85
for i in range(len(sprendiniai)):
x1, x2 = sprendiniai[i]
pos = np.array([x1, x2])
star_vertices = np.array([
[0, 1], [0.3, 0.3], [1, 0.3], [0.45, 0], [0.6, -0.7],
[0, -0.35], [-0.6, -0.7], [-0.45, 0], [-1, 0.3], [-0.3, 0.3]
]) * (circle_radius*1.5)
star = patches.Polygon(star_vertices + pos, closed=True, edgecolor='black', facecolor=circle_colors[i+1], zorder=5)
ax.add_patch(star)
for x1, x2 in iter_tinklelis(tinklelis):
sprendinys_idx = 0
if tinklelio_reiksmes[(x1, x2)] is not None:
sprendinys_idx = sprendiniai.index(tinklelio_reiksmes[(x1, x2)])+1
circle_color = circle_colors[sprendinys_idx]
ax.add_patch(patches.Circle((x1, x2), circle_radius, edgecolor=circle_color, facecolor=circle_color))
plt.show()
def lerp(min_x, max_x, percent):
return min_x + (max_x - min_x) * percent
def main(Z1, Z2, tinklelis: Tinklelis):
viz_broideno_metodas(2.5, 0.3, Z1, Z2)
viz_broideno_tinklelis(Z1, Z2, tinklelis)
print(broideno_metodas(-4, 0, Z1, Z2))
print(broideno_metodas( 4, 0, Z1, Z2))
print(broideno_metodas(-2, 4, Z1, Z2))
print(broideno_metodas( 2, 4, Z1, Z2))
# Variantas: 10
main(
lambda x1, x2: x1**2 + 2*(x2 - np.cos(x1))**2 - 20,
lambda x1, x2: x1**2 * x2 - 2,
tinklelis = Tinklelis(
from_x1=-8, to_x1=8,
from_x2=-8, to_x2=8,
density=60
)
)