1
0
This commit is contained in:
2024-05-05 20:42:32 +03:00
parent 7513fe88cf
commit fe726bd935
10 changed files with 1074 additions and 0 deletions

BIN
Л5-В6/Lab_5.pdf Normal file

Binary file not shown.

View File

@@ -0,0 +1,71 @@
<mxfile host="app.diagrams.net" modified="2024-05-05T16:30:15.640Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" etag="G6RgyNxifMlW16WjdJVi" version="24.2.7" type="device">
<diagram name="Page-1" id="IsdQuIT6SBaa60DIysJm">
<mxGraphModel dx="989" dy="509" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-1" target="9QVsrVUUbt5jk-MIr5Bh-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-1" value="&lt;div&gt;runge_kutta_4(&lt;span style=&quot;background-color: initial;&quot;&gt;x_0,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;y_0,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;x_n,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;h,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;)&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="265" y="180" width="260" height="30" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-2" target="9QVsrVUUbt5jk-MIr5Bh-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-2" value="&lt;div&gt;result = []&lt;/div&gt;x_i = x_0&lt;div&gt;y_i = y_0&lt;/div&gt;&lt;div&gt;result[x_i] = y_i&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="335" y="230" width="120" height="90" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-7" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-4" target="9QVsrVUUbt5jk-MIr5Bh-6">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-4" target="9QVsrVUUbt5jk-MIr5Bh-11">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="560" y="380" />
<mxPoint x="560" y="640" />
<mxPoint x="395" y="640" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-4" value="x_i &amp;lt; x_n + h / 2" style="rhombus;whiteSpace=wrap;html=1;spacingLeft=0;spacingRight=0;perimeterSpacing=0;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="320" y="350" width="150" height="60" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-6" target="9QVsrVUUbt5jk-MIr5Bh-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-6" value="k_1 = f(x_i, y_i)&lt;div&gt;k_2 = f(x_i + h / 2, y_i + h / 2 * k_1)&lt;br&gt;&lt;/div&gt;&lt;div&gt;k_3 = f(x_i + h / 2, y_i + h / 2 * k_2)&lt;br&gt;&lt;/div&gt;&lt;div&gt;k_4 = f(x_i + h, y_i + h * k_3)&lt;br&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="250" y="430" width="290" height="90" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-8">
<mxGeometry relative="1" as="geometry">
<mxPoint x="395" y="330" as="targetPoint" />
<Array as="points">
<mxPoint x="395" y="630" />
<mxPoint x="230" y="630" />
<mxPoint x="230" y="330" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-8" value="y_i + h / 6 * (k_1 + 2 * k_2 + 2 * k_3 + k_4)&lt;div&gt;x_i += h&lt;/div&gt;&lt;div&gt;&amp;nbsp;result[x_i] = y_i&lt;br&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="300" y="540" width="190" height="70" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="9QVsrVUUbt5jk-MIr5Bh-11" target="9QVsrVUUbt5jk-MIr5Bh-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-11" value="return result" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="340" y="660" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-13" value="Конец" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="352.5" y="710" width="85" height="30" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-15" value="Да" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="391" y="403" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="9QVsrVUUbt5jk-MIr5Bh-16" value="Нет" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="470" y="355" width="40" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

BIN
Л5-В6/Отчет.docx Normal file

Binary file not shown.

2
Л5-В6/Программа/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.venv
*/__pycache__

View File

@@ -0,0 +1,5 @@
sympy
numpy
scipy
pyqt6
matplotlib

View File

@@ -0,0 +1,45 @@
import numpy as np
import typing
def runge_kutta_4(
x_0: float,
y_0: typing.List[float],
x_n: float,
h: float,
f: typing.List[typing.Callable[[float, typing.List[float]], float]],
) -> typing.Dict[float, np.ndarray]:
count = len(y_0)
if count != len(f):
raise ValueError("len(y_0) != len(f)")
x_i = x_0
y_i = np.array(y_0, dtype=np.float64)
result = {x_i: y_i}
while x_i < x_n + h / 2:
y_i = calculate_y(x_i, y_i, h, f)
x_i += h
result[x_i] = y_i
return result
def calculate_y(x_i, y_i, h, f):
k_1 = np.array([f[i](x_i, y_i) for i in range(len(y_i))], dtype=np.float64)
k_2 = np.array(
[f[i](x_i + h / 2, y_i + h * k_1 / 2) for i in range(len(y_i))],
dtype=np.float64,
)
k_3 = np.array(
[f[i](x_i + h / 2, y_i + h * k_2 / 2) for i in range(len(y_i))],
dtype=np.float64,
)
k_4 = np.array(
[f[i](x_i + h, y_i + h * k_3) for i in range(len(y_i))], dtype=np.float64
)
y_i = y_i + h / 6 * (k_1 + 2 * k_2 + 2 * k_3 + k_4)
return y_i

View File

@@ -0,0 +1,17 @@
import sys
from PyQt6.QtWidgets import QApplication
from PyQt6.QtGui import QFont
import window
import widgets
if __name__ == "__main__":
widgets.setup_dark_theme()
app = QApplication(sys.argv)
font = QFont("Cascadia Code", 14)
app.setFont(font)
window = window.MainWindow()
window.show()
sys.exit(app.exec())

View File

@@ -0,0 +1,68 @@
import sympy
import typing
f_str = "y * ln(y) / sin(x)"
f_expr = sympy.sympify(f_str)
f_l = sympy.lambdify("x, y", f_expr, cse=True)
def task1_f(x: float, y: typing.List[float]) -> float:
return f_l(x, *y)
def task1_f_display() -> str:
return f_str
f_1_str = "sin(x**2 + y_2**2)"
f_1_expr = sympy.sympify(f_1_str)
f_1_l = sympy.lambdify("x, y_1, y_2", f_1_expr, cse=True)
f_2_str = "cos(x * y_1)"
f_2_expr = sympy.sympify(f_2_str)
f_2_l = sympy.lambdify("x, y_1, y_2", f_2_expr, cse=True)
def task2_f_1(x: float, y: typing.List[float]) -> float:
return f_1_l(x, *y)
def task2_f_2(x: float, y: typing.List[float]) -> float:
return f_2_l(x, *y)
def task2_f_1_display() -> str:
return f_1_str
def task2_f_2_display() -> str:
return f_2_str
def task3_f_display() -> str:
return "y'' + a1 * y' + a2 * y"
x, a1, a2 = sympy.symbols("x a1 a2", real=True)
y = sympy.symbols("y", cls=sympy.Function)(x)
yp = y.diff(x)
ypp = y.diff(x, 2)
f_xy = ypp + a1 * yp + a2 * y
task3_generic_solution = sympy.dsolve(f_xy, y).rhs
def task3_solution_display() -> str:
return str(task3_generic_solution)
def task3_make_f_sympy(a1_, a2_, x_0_, y_0_, y_d_0_):
solution = task3_generic_solution.subs({a1: a1_, a2: a2_})
cnd1 = sympy.Eq(solution.subs(x, x_0_), y_0_)
cnd2 = sympy.Eq(solution.diff(x).subs(x, x_0_), y_d_0_)
C1, C2 = sympy.symbols("C1 C2")
C1C2_sl = sympy.solve([cnd1, cnd2], (C1, C2))
return sympy.simplify(solution.subs(C1C2_sl))

View File

@@ -0,0 +1,330 @@
from io import BytesIO
from PyQt6.QtWidgets import (
QLabel,
QWidget,
QLineEdit,
QHBoxLayout,
QSlider,
QVBoxLayout,
)
from PyQt6.QtCore import Qt
from PyQt6.QtSvgWidgets import QSvgWidget
import matplotlib
import matplotlib.figure
import matplotlib.axes
from matplotlib.backends.backend_qtagg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar,
)
import sympy
import abc
import typing
import matplotlib.pyplot
def setup_dark_theme():
matplotlib.pyplot.style.use(
{
"figure.facecolor": "#1e1e1e",
"savefig.facecolor": "#1e1e1e",
"text.color": "white",
"xtick.color": "white",
"ytick.color": "white",
"legend.facecolor": "#1e1e1e",
"legend.edgecolor": "white",
"legend.labelcolor": "white",
"grid.color": "white",
"figure.edgecolor": "white",
"axes.facecolor": "#1e1e1e",
"axes.axisbelow": "true",
"axes.edgecolor": "white",
"axes.labelcolor": "white",
"axes.grid": True,
"axes.spines.left": False,
"axes.spines.right": False,
"axes.spines.top": False,
"axes.spines.bottom": False,
}
)
class DisplayField(QWidget):
label: str
def __init__(self, parent, label="", text="", wrap=False):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
self.label = label
self.text = QLabel(f"{self.label}{text}")
self.text.setWordWrap(wrap)
self.text.setAlignment(Qt.AlignmentFlag.AlignLeft)
self._layout.addWidget(self.text)
def set_visible(self, visible):
self.text.setVisible(visible)
def set_text(self, text):
self.text.setText(f"{self.label}{text}")
class InputWidget(QWidget):
value: typing.Any
previous_value: typing.Any
callback: typing.Callable[[typing.Self], bool] | None = None
def init(self):
self.value = self._get_value_internal()
self.previous_value = self.value
self._set_callback_internal(self._on_change_internal)
def get_value(self) -> typing.Any:
return self.value
def get_previous_value(self) -> typing.Any:
return self.previous_value
def set_value(self, value: typing.Any):
self._set_value_internal(value)
self._set_value_no_sync(value)
def set_callback(self, callback: typing.Callable[[typing.Self], bool]):
self.callback = callback
@abc.abstractmethod
def _get_value_internal(self) -> typing.Any:
pass
@abc.abstractmethod
def _set_value_internal(self, value: typing.Any):
pass
@abc.abstractmethod
def _set_callback_internal(self, callback: typing.Callable[[], None]):
pass
def _set_value_no_sync(self, value: typing.Any):
self.previous_value = self.value
self.value = value
def _on_change_internal(self):
self._set_value_no_sync(self._get_value_internal())
if self.callback:
self.callback(self)
def make_callback_chain(
callbacks: typing.List[typing.Callable[[InputWidget], bool]]
) -> typing.Callable[[InputWidget], bool]:
def callback(widget: InputWidget):
for callback in callbacks:
if not callback(widget):
break
return True
return callback
def make_min_max_callback(
min: typing.Any, max: typing.Any
) -> typing.Callable[[InputWidget], bool]:
def callback(widget: InputWidget):
value = widget.get_value()
if type(min)(value) < min:
widget.set_value(min)
if type(max)(value) > max:
widget.set_value(max)
return True
return callback
def float_check_callback(widget: InputWidget):
try:
internal_value = widget._get_value_internal()
if not (internal_value == "" or internal_value == "-" or internal_value == "."):
_ = float(widget.get_value())
return True
else:
widget.value = widget.previous_value
return False
except:
widget.set_value(widget.previous_value)
return False
def int_check_callback(widget: InputWidget):
try:
internal_value = widget._get_value_internal()
if not (internal_value == "" or internal_value == "-"):
_ = int(widget.get_value())
return True
else:
widget.value = widget.previous_value
return False
except:
widget.set_value(widget.previous_value)
return False
class InputField(InputWidget):
def __init__(
self,
parent,
label_text="",
placeholder_text="",
lineedit_text="",
label_position="left",
):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
self.label = QLabel(label_text)
self.lineedit = QLineEdit(lineedit_text)
self.lineedit.setPlaceholderText(placeholder_text)
self.lineedit.setMinimumWidth(50)
if label_position == "left":
self._layout.addWidget(self.label)
self._layout.addWidget(self.lineedit)
elif label_position == "right":
self._layout.addWidget(self.lineedit)
self._layout.addWidget(self.label)
elif label_position == "none":
self._layout.addWidget(self.lineedit)
super().init()
super().set_value(lineedit_text)
def _get_value_internal(self):
return self.lineedit.text()
def _set_value_internal(self, value):
self.lineedit.setText(str(value))
def _set_callback_internal(self, callback):
self.lineedit.textChanged.connect(callback)
class MathInputField(InputField):
internal_value: typing.Any
def __init__(
self,
parent,
label_text="",
placeholder_text="",
lineedit_value="0.0",
label_position="left",
):
super().__init__(
parent, label_text, placeholder_text, lineedit_value, label_position
)
def _get_value_internal(self):
try:
self.internal_value = str(
float(
sympy.sympify(self.lineedit.text()).evalf(
subs={
"e": sympy.E,
"Pi": sympy.pi,
"PI": sympy.pi,
}
)
)
)
except:
pass
return self.internal_value
class InputSlider(InputWidget):
slider: QSlider
def __init__(
self,
parent,
label_text="",
value=0,
min_value=0,
max_value=100,
step=1,
ticks=False,
):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
self.label = QLabel(label_text)
self.slider = QSlider(Qt.Orientation.Horizontal)
if ticks:
self.slider.setTickPosition(QSlider.TickPosition.TicksBelow)
self.slider.setTickInterval(step)
self.slider.setMinimum(min_value)
self.slider.setMaximum(max_value)
self.slider.setValue(value)
self.slider.setSingleStep(step)
self._layout.addWidget(self.label)
self._layout.addWidget(self.slider)
super().init()
super().set_value(value)
def _get_value_internal(self):
return self.slider.value()
def _set_value_internal(self, value):
self.slider.setValue(value)
def _set_callback_internal(self, callback):
self.slider.valueChanged.connect(callback)
class PlotWidget(QWidget):
figure: matplotlib.figure.Figure
toolbar: NavigationToolbar = None
canvas: FigureCanvas
def __init__(self, parent, figure: matplotlib.figure.Figure, toolbar: bool = False):
super().__init__(parent)
self._layout = QVBoxLayout(self)
self.figure = figure
self.canvas = FigureCanvas(self.figure)
self.canvas.setStyleSheet("background-color:transparent;")
if toolbar:
self.toolbar = NavigationToolbar(self.canvas, self)
self._layout.addWidget(self.toolbar)
self._layout.addWidget(self.canvas)
def set_figure(self, figure: matplotlib.figure.Figure):
self.figure = figure
self.canvas = FigureCanvas(self.figure)
self._layout.addWidget(self.canvas)
self.redraw()
def get_figure(self) -> matplotlib.figure.Figure:
return self.figure
def redraw(self):
self.canvas.draw()

View File

@@ -0,0 +1,536 @@
from PyQt6.QtWidgets import (
QMainWindow,
QLabel,
QPushButton,
QFormLayout,
QWidget,
QHBoxLayout,
QTabWidget,
)
from PyQt6 import QtWidgets
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use("QtAgg")
import numpy as np
import sympy
import typing
import widgets
import task
import algorithm
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_ui()
def setup_ui(self):
self.setWindowTitle("Лабораторная работа №5")
self.setFixedSize(800, 900)
central_widget = QTabWidget(self)
central_widget.setTabsClosable(False)
central_widget.setContentsMargins(0, 0, 0, 0)
central_widget.addTab(Tab1(central_widget), "Задание 1")
central_widget.addTab(Tab2(central_widget), "Задание 2")
central_widget.addTab(Tab3(central_widget), "Задание 3")
self.setCentralWidget(central_widget)
class Tab1(QWidget):
initialized = False
x_0_field: widgets.InputField
y_0_field: widgets.InputField
x_n_field: widgets.InputField
h_display: widgets.DisplayField
h_field: widgets.InputSlider
x_0: float
y_0: float
x_n: float
h: float
solution_plot: widgets.PlotWidget
solution_figure: plt.Figure
solution_axes: plt.Axes
def __init__(self, parent):
super().__init__(parent)
self._initialize()
self.reset()
self.initialized = True
self.update_solution()
def _initialize(self):
self._layout = QFormLayout(self)
self._function_display = widgets.DisplayField(self, "f(x, y) = ", "")
self._layout.addWidget(self._function_display)
self.x_0_field = widgets.MathInputField(self, label_text="x_0: ")
self.x_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_0_field_changed]
)
)
self._layout.addWidget(self.x_0_field)
self.y_0_field = widgets.MathInputField(self, label_text="y_0: ")
self.y_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._y_0_field_changed]
)
)
self._layout.addWidget(self.y_0_field)
self.x_n_field = widgets.MathInputField(self, label_text="x_n: ")
self.x_n_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_n_field_changed]
)
)
self._layout.addWidget(self.x_n_field)
self.h_display = widgets.DisplayField(self, "h: ", "")
self._layout.addWidget(self.h_display)
self.h_field = widgets.InputSlider(
self, label_text="", value=0, min_value=1, max_value=100, step=1
)
self.h_field.set_callback(self._h_field_changed)
self._layout.addWidget(self.h_field)
self.solution_figure = plt.figure()
self.solution_figure.patch.set_facecolor("none")
self.solution_axes = self.solution_figure.add_subplot(111)
self.solution_figure.tight_layout(pad=3.0)
self.solution_plot = widgets.PlotWidget(self, self.solution_figure, True)
self._layout.addWidget(self.solution_plot)
def reset(self):
self._function_display.set_text(task.task1_f_display())
self.x_0_field.set_value("pi / 2")
self.y_0_field.set_value("e")
self.x_n_field.set_value("pi")
self.h_field.set_value(5)
QtWidgets.QApplication.processEvents()
def _x_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.x_0 = float(w.get_value())
self.update_solution()
return True
def _y_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.y_0 = float(w.get_value())
return True
def _x_n_field_changed(self, w: widgets.InputWidget) -> bool:
self.x_n = float(w.get_value())
self.update_solution()
return True
def _h_field_changed(self, w: widgets.InputWidget) -> bool:
self.h = float(w.get_value()) / 100.0
self.h_display.set_text(str(self.h))
self.update_solution()
return True
def update_solution(self):
if not self.initialized:
return
solution = algorithm.runge_kutta_4(
self.x_0, [self.y_0], self.x_n, self.h, [task.task1_f]
)
x = np.array(list(solution.keys()))
y = np.array(list(map(lambda x: x[0], solution.values())))
self.solution_axes.clear()
self.solution_axes.set_xlabel("x")
self.solution_axes.set_ylabel("y")
self.solution_axes.grid(True)
self.solution_axes.plot(x, y, label="y(x)")
solution = algorithm.runge_kutta_4(
self.x_0, [self.y_0], self.x_n, self.h / 2, [task.task1_f]
)
x = np.array(list(solution.keys()))
y = np.array(list(map(lambda x: x[0], solution.values())))
self.solution_axes.plot(x, y, label="y(x) (h/2)")
solution = algorithm.runge_kutta_4(
self.x_0, [self.y_0], self.x_n, self.h * 2, [task.task1_f]
)
x = np.array(list(solution.keys()))
y = np.array(list(map(lambda x: x[0], solution.values())))
self.solution_axes.plot(x, y, label="y(x) (h*2)")
self.solution_axes.set_yscale("log")
self.solution_axes.legend(loc="upper left")
self.solution_plot.redraw()
class Tab2(QWidget):
initialized = False
_function1_display: widgets.DisplayField
_function2_display: widgets.DisplayField
x_0_field: widgets.InputField
y_10_field: widgets.InputField
y_20_field: widgets.InputField
x_n_field: widgets.InputField
h_display: widgets.DisplayField
h_field: widgets.InputSlider
x_0: float
y_10: float
y_20: float
x_n: float
h: float
def __init__(self, parent):
super().__init__(parent)
self._initialize()
self.reset()
self.initialized = True
self.update_solution()
def _initialize(self):
self._layout = QFormLayout(self)
self._function1_display = widgets.DisplayField(self, "f1(x, y) = ", "")
self._layout.addWidget(self._function1_display)
self._function2_display = widgets.DisplayField(self, "f2(x, y) = ", "")
self._layout.addWidget(self._function2_display)
self.x_0_field = widgets.MathInputField(self, label_text="x_0: ")
self.x_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_0_field_changed]
)
)
self._layout.addWidget(self.x_0_field)
self.y_10_field = widgets.MathInputField(self, label_text="y_10: ")
self.y_10_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._y_10_field_changed]
)
)
self._layout.addWidget(self.y_10_field)
self.y_20_field = widgets.MathInputField(self, label_text="y_20: ")
self.y_20_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._y_20_field_changed]
)
)
self._layout.addWidget(self.y_20_field)
self.x_n_field = widgets.MathInputField(self, label_text="x_n: ")
self.x_n_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_n_field_changed]
)
)
self._layout.addWidget(self.x_n_field)
self.h_display = widgets.DisplayField(self, "h: ", "")
self._layout.addWidget(self.h_display)
self.h_field = widgets.InputSlider(
self, label_text="", value=0, min_value=1, max_value=100, step=1
)
self.h_field.set_callback(self._h_field_changed)
self._layout.addWidget(self.h_field)
self.solution_figure = plt.figure()
self.solution_figure.patch.set_facecolor("none")
self.solution_axes = self.solution_figure.add_subplot(111)
self.solution_figure.tight_layout(pad=3.0)
self.solution_plot = widgets.PlotWidget(self, self.solution_figure)
self._layout.addWidget(self.solution_plot)
def reset(self):
self._function1_display.set_text(task.task2_f_1_display())
self._function2_display.set_text(task.task2_f_2_display())
self.x_0_field.set_value("0")
self.y_10_field.set_value("0")
self.y_20_field.set_value("0")
self.x_n_field.set_value("4")
self.h_field.set_value(5)
QtWidgets.QApplication.processEvents()
def _x_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.x_0 = float(w.get_value())
self.update_solution()
return True
def _y_10_field_changed(self, w: widgets.InputWidget) -> bool:
self.y_10 = float(w.get_value())
self.update_solution()
return True
def _y_20_field_changed(self, w: widgets.InputWidget) -> bool:
self.y_20 = float(w.get_value())
self.update_solution()
return True
def _x_n_field_changed(self, w: widgets.InputWidget) -> bool:
self.x_n = float(w.get_value())
self.update_solution()
return True
def _h_field_changed(self, w: widgets.InputWidget) -> bool:
self.h = float(w.get_value()) / 100.0
self.h_display.set_text(str(self.h))
self.update_solution()
return True
def update_solution(self):
if not self.initialized:
return
solution = algorithm.runge_kutta_4(
self.x_0,
[self.y_10, self.y_20],
self.x_n,
self.h,
[task.task2_f_1, task.task2_f_2],
)
x = np.array(list(solution.keys()))
y1 = np.array(list(map(lambda x: x[0], solution.values())))
y2 = np.array(list(map(lambda x: x[1], solution.values())))
self.solution_axes.cla()
self.solution_axes.plot(x, y1, label="y_1")
self.solution_axes.plot(x, y2, label="y_2")
self.solution_axes.legend()
self.solution_plot.redraw()
class Tab3(QWidget):
initialized = False
a1_field: widgets.InputField
a2_field: widgets.InputField
x_0_field: widgets.InputField
y_0_field: widgets.InputField
y_d_0_field: widgets.InputField
generic_solution_display: widgets.DisplayField
solution_display: widgets.DisplayField
a1: float
a2: float
x_0: float
y_0: float
y_d_0: float
solution_plot: widgets.PlotWidget
solution_figure: plt.Figure
solution_axes: plt.Axes
def __init__(self, parent):
super().__init__(parent)
self._initialize()
self.reset()
self.initialized = True
self.update_solution()
def _initialize(self):
self._layout = QFormLayout(self)
self._function_display = widgets.DisplayField(
self, task.task3_f_display(), " = 0"
)
self._layout.addWidget(self._function_display)
self.a1_field = widgets.InputField(
self,
"a1: ",
)
self.a1_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._a1_changed]
)
)
self._layout.addWidget(self.a1_field)
self.a2_field = widgets.InputField(
self,
"a2: ",
)
self.a2_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._a2_changed]
)
)
self._layout.addWidget(self.a2_field)
self.x_0_field = widgets.InputField(
self,
"x_0: ",
)
self.x_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_0_field_changed]
)
)
self._layout.addWidget(self.x_0_field)
self.y_0_field = widgets.InputField(
self,
"y_0: ",
)
self.y_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._y_0_field_changed]
)
)
self._layout.addWidget(self.y_0_field)
self.y_d_0_field = widgets.InputField(
self,
"y_d_0: ",
)
self.y_d_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._y_d_0_field_changed]
)
)
self._layout.addWidget(self.y_d_0_field)
self.generic_solution_display = widgets.DisplayField(
self, "Общее решение: ", wrap=True
)
self._layout.addWidget(self.generic_solution_display)
self.solution_display = widgets.DisplayField(self, "Решение: ", wrap=True)
self._layout.addWidget(self.solution_display)
self.solution_figure = plt.figure()
self.solution_figure.patch.set_facecolor("none")
self.solution_axes = self.solution_figure.add_subplot(111)
self.solution_figure.tight_layout(pad=3.0)
self.solution_plot = widgets.PlotWidget(self, self.solution_figure, True)
self._layout.addWidget(self.solution_plot)
def reset(self):
self.a1_field.set_value("-4.0")
self.a2_field.set_value("4.0")
self.x_0_field.set_value("0.3")
self.y_0_field.set_value("1.0")
self.y_d_0_field.set_value("1.0")
QtWidgets.QApplication.processEvents()
def _a1_changed(self, w: widgets.InputWidget) -> bool:
self.a1 = float(w.get_value())
self.update_solution()
return True
def _a2_changed(self, w: widgets.InputWidget) -> bool:
self.a2 = float(w.get_value())
self.update_solution()
return True
def _x_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.x_0 = float(w.get_value())
self.update_solution()
return True
def _y_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.y_0 = float(w.get_value())
self.update_solution()
return True
def _y_d_0_field_changed(self, w: widgets.InputWidget) -> bool:
self.y_d_0 = float(w.get_value())
self.update_solution()
return True
def update_solution(self):
if not self.initialized:
return
self.generic_solution_display.set_text(
"\n" + str(task.task3_solution_display())
)
solution = task.task3_make_f_sympy(
self.a1, self.a2, self.x_0, self.y_0, self.y_d_0
)
self.solution_display.set_text(str(solution))
try:
f = sympy.lambdify("x", solution, cse=True)
x = np.linspace(self.x_0, self.x_0 + 5, 100)
y = f(x)
self.solution_axes.clear()
self.solution_axes.grid(True)
self.solution_axes.plot(x, y, label="y")
self.solution_axes.legend()
self.solution_plot.redraw()
except Exception as e:
print(e)