1
0
This commit is contained in:
2024-04-22 01:04:56 +03:00
parent 4326494c2e
commit 70c7975eeb
10 changed files with 1082 additions and 0 deletions

BIN
Л4-В6/Lab_4.pdf Normal file

Binary file not shown.

View File

@@ -0,0 +1,205 @@
<mxfile host="app.diagrams.net" modified="2024-04-21T20:49:14.389Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" etag="L70BZ2SPwnqLO1KppO7W" version="24.2.7" type="device" pages="2">
<diagram name="difference_n" id="QT74YzUSpF6bmaEzPSn7">
<mxGraphModel dx="472" dy="736" 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="DQ9j4h5ksd5OBPriSE9t-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-1" target="DQ9j4h5ksd5OBPriSE9t-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-1" value="difference_n(func, x_array, n)" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="229.5" y="150" width="230" height="30" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-2" target="DQ9j4h5ksd5OBPriSE9t-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-2" value="result = 0" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="295" y="210" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-7" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-4" target="DQ9j4h5ksd5OBPriSE9t-6">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-20" 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="DQ9j4h5ksd5OBPriSE9t-4" target="DQ9j4h5ksd5OBPriSE9t-19">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="290" />
<mxPoint x="490" y="760" />
<mxPoint x="345" y="760" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-4" value="k = 0(1)n" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="290" y="270" width="110" height="40" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-6" target="DQ9j4h5ksd5OBPriSE9t-9">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-6" value="prod = 1" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="295" y="340" width="100" height="40" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-8" target="DQ9j4h5ksd5OBPriSE9t-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-8">
<mxGeometry relative="1" as="geometry">
<mxPoint x="345" y="620" as="targetPoint" />
<Array as="points">
<mxPoint x="440" y="505" />
<mxPoint x="440" y="620" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-8" value="j != k" style="rhombus;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="305" y="480" width="80" height="50" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-9" target="DQ9j4h5ksd5OBPriSE9t-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-15" 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="DQ9j4h5ksd5OBPriSE9t-9" target="DQ9j4h5ksd5OBPriSE9t-12">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="460" y="430" />
<mxPoint x="460" y="650" />
<mxPoint x="344" y="650" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-9" value="j = 0(1)n" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="290" y="410" width="110" height="40" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-12" target="DQ9j4h5ksd5OBPriSE9t-4">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="345" y="740" />
<mxPoint x="210" y="740" />
<mxPoint x="210" y="290" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-12" value="result += func(x_array[k]) / prod" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="276" y="670" width="137" height="50" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-13" target="DQ9j4h5ksd5OBPriSE9t-9">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="345" y="620" />
<mxPoint x="240" y="620" />
<mxPoint x="240" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-13" value="prod *= x_array[k] - x_array[j]" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="260" y="560" width="170" height="40" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="DQ9j4h5ksd5OBPriSE9t-19" target="DQ9j4h5ksd5OBPriSE9t-23">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-19" value="return result" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="296.75" y="780" width="95.5" height="30" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-21" 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="340" y="528" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-22" 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="380" y="478" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="DQ9j4h5ksd5OBPriSE9t-23" value="Конец" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="295" y="840" width="100" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="YRw7BwRxA9GMbmWKKpqw" name="forward_interpolate">
<mxGraphModel dx="477" dy="613" 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="FBLyEU0xljRjRjxMH2o2-1" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-2" target="FBLyEU0xljRjRjxMH2o2-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-2" value="forward_interpolate(func, x_array, x)" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="229.5" y="140" width="230" height="40" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-4" target="FBLyEU0xljRjRjxMH2o2-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-4" value="n = len(x_array)&lt;div&gt;L = func(x_array[0])&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="263.5" y="200" width="163" height="40" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-7" target="FBLyEU0xljRjRjxMH2o2-26">
<mxGeometry relative="1" as="geometry">
<mxPoint x="345" y="330" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-6" 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="FBLyEU0xljRjRjxMH2o2-7" target="FBLyEU0xljRjRjxMH2o2-21">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="290" />
<mxPoint x="490" y="650" />
<mxPoint x="345" y="650" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-7" value="k = 1(1)n-1" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="290" y="270" width="110" height="40" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-26" target="FBLyEU0xljRjRjxMH2o2-15">
<mxGeometry relative="1" as="geometry">
<mxPoint x="345" y="380" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-14" 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="FBLyEU0xljRjRjxMH2o2-15" target="FBLyEU0xljRjRjxMH2o2-17">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="460" y="430" />
<mxPoint x="460" y="560" />
<mxPoint x="345" y="560" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-15" target="FBLyEU0xljRjRjxMH2o2-19">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-15" value="i = 0(1)k-1" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="290" y="410" width="110" height="40" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontFamily=Cascadia Code;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-17" target="FBLyEU0xljRjRjxMH2o2-7">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="345" y="640" />
<mxPoint x="210" y="640" />
<mxPoint x="210" y="290" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-17" value="L += prod" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="292.5" y="585" width="104" height="35" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontFamily=Cascadia Code;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-19" target="FBLyEU0xljRjRjxMH2o2-15">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="345" y="540" />
<mxPoint x="240" y="540" />
<mxPoint x="240" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-19" value="prod *= x - x_array[i]" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="260" y="480" width="170" height="40" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontFamily=Cascadia Code;" edge="1" parent="1" source="FBLyEU0xljRjRjxMH2o2-21" target="FBLyEU0xljRjRjxMH2o2-24">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-21" value="return L" style="rounded=0;whiteSpace=wrap;html=1;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="296.75" y="670" width="95.5" height="30" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-24" value="Конец" style="rounded=1;whiteSpace=wrap;html=1;arcSize=50;fontFamily=Cascadia Code;" vertex="1" parent="1">
<mxGeometry x="295" y="720" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="FBLyEU0xljRjRjxMH2o2-26" value="&lt;span style=&quot;font-family: &amp;quot;Cascadia Code&amp;quot;;&quot;&gt;prod = difference_n(func, x_array, k)&lt;/span&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;size=0.07142857142857142;" vertex="1" parent="1">
<mxGeometry x="264" y="330" width="162.5" height="60" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

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

Binary file not shown.

2
Л4-В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,60 @@
import numpy as np
import typing
def difference_n(
func: typing.Callable[[float], float], x_array: np.ndarray, start: int, end: int
) -> float:
if len(x_array) < end + 1:
return None
result = 0
for k in range(start, end + 1):
prod = 1
for j in range(start, end + 1):
if j != k:
prod *= x_array[k] - x_array[j]
result += func(x_array[k]) / prod
return result
def make_forward_interpolate_function(
func: typing.Callable[[float], float], x_array: np.ndarray
) -> typing.Callable[[float], float]:
n = len(x_array)
diffs = [difference_n(func, x_array, 0, k) for k in range(1, n)]
def forward_interpolate(x: float) -> float:
L = func(x_array[0])
for k in range(1, n):
prod = diffs[k - 1]
for i in range(k):
prod *= x - x_array[i]
L += prod
return L
return forward_interpolate
def make_backward_interpolate_function(
func: typing.Callable[[float], float], x_array: np.ndarray
) -> typing.Callable[[float], float]:
n = len(x_array)
diffs = [difference_n(func, x_array, n - k - 1, n - 1) for k in range(1, n)]
def backward_interpolate(x: float) -> float:
L = func(x_array[-1])
for k in range(n - 1):
prod = diffs[k]
for i in range(n - 1, n - k - 2, -1):
prod *= x - x_array[i]
L += prod
return L
return backward_interpolate

View File

@@ -0,0 +1,14 @@
import sys
from PyQt6.QtWidgets import QApplication
from PyQt6.QtGui import QFont
import window
if __name__ == "__main__":
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,10 @@
func_str = "exp(-b * x) * cos(pi * (x + x ** 2))"
func_args = {"b": 0.15}
def f_str() -> str:
return func_str
def f_args() -> dict:
return func_args.copy()

View File

@@ -0,0 +1,219 @@
from PyQt6.QtWidgets import (
QLabel,
QWidget,
QLineEdit,
QHBoxLayout,
QSlider,
)
from PyQt6.QtCore import Qt
import abc
import typing
class DisplayField(QWidget):
label_text: str
def __init__(self, parent, label_text="", text=""):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
self.label_text = label_text
self.text = QLabel(f"{self.label_text}{text}")
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}{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 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)

View File

@@ -0,0 +1,567 @@
from PyQt6.QtWidgets import (
QMainWindow,
QLabel,
QPushButton,
QFormLayout,
QWidget,
QHBoxLayout,
)
from PyQt6 import QtWidgets
import numpy as np
import sympy
from typing import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.axes import Axes
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
matplotlib.use("QtAgg")
import widgets
import task
import algorithm
class ParamsField(widgets.InputWidget):
_layout: QFormLayout
fields: Dict[str, widgets.InputWidget]
callback_internal: Callable
def __init__(self, parent, fields: List[str]):
super().__init__(parent)
self._initialize()
self._create(fields)
super().init()
def _initialize(self):
self.fields = {}
self._layout = QFormLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
def _create(self, fields: List[str]):
fields = sorted(fields)
for field in fields:
val = "0.0"
if not self.value.get(field) is None:
val = str(self.value.get(field))
self.fields[field] = widgets.InputField(
self, label_text=f" {field}: ", lineedit_text=val
)
self.fields[field].set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._callback]
)
)
self._layout.addRow(self.fields[field])
def recreate(self, fields: List[str]):
for field in self.fields:
self.fields[field].deleteLater()
self.fields = {}
self._create(fields)
self.callback_internal()
def _get_value_internal(self) -> Dict[str, float]:
value = {}
for field in self.fields:
value[field] = float(self.fields[field].get_value())
return value
def _set_value_internal(self, value: Dict[str, float]):
for field in self.fields:
self.fields[field].set_value(value[field])
def _set_callback_internal(self, callback):
self.callback_internal = callback
def _callback(self, widget: widgets.InputWidget):
self.callback_internal()
return True
class PointsField(widgets.InputWidget):
_layout: QFormLayout
points: List[widgets.InputField]
min: float
max: float
DIVISIONS = 1_000_000
callback_internal: Callable[[None], None]
def __init__(self, parent, start: int, points: List[float], min: float, max: float):
super().__init__(parent)
self._initialize()
self._create(start, points, min, max)
super().init()
def _initialize(self):
self.points = []
self.min = 0.0
self.max = 1.0
self._layout = QFormLayout(self)
self._layout.setContentsMargins(0, 0, 0, 0)
def _create(self, start: int, points: List[float], min: float, max: float):
self.min = min
self.max = max
for i in range(0, len(points)):
value = int((points[i] - min) / (max - min) * self.DIVISIONS)
self.points.append(
widgets.InputSlider(
self,
label_text=f" {i + start}: ",
value=value,
min_value=0,
max_value=self.DIVISIONS,
)
)
self.points[i].set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._callback]
)
)
self._layout.addRow(self.points[i])
def recreate(self, start: int, points: List[float], min: float, max: float):
for point in self.points:
point.deleteLater()
self.points = []
self._create(start, points, min, max)
self.callback_internal()
def _get_value_internal(self) -> List[float]:
value = []
for point in self.points:
value.append(
float(point.get_value()) / self.DIVISIONS * (self.max - self.min)
+ self.min
)
return value
def _set_value_internal(self, value: List[float]):
for i in range(0, len(value)):
self.points[i].set_value(
(value[i] - self.min) / (self.max - self.min) * self.DIVISIONS
)
def _set_callback_internal(self, callback):
self.callback_internal = callback
def _callback(self, widget: widgets.InputWidget):
self.callback_internal()
return True
class PlotWidget(QWidget):
figure: Figure
axes: Axes
canvas: FigureCanvasQTAgg
pre_style: Callable[[Axes], None]
post_style: Callable[[Axes], None]
plots: List[Callable[[Axes], None]]
def __init__(self, parent):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self.figure = plt.figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvasQTAgg(self.figure)
self._layout.addWidget(self.canvas)
self.pre_style = lambda _: None
self.plots = []
def set_pre_style(self, style: Callable[[Axes], None]):
self.pre_style = style
def set_post_style(self, style: Callable[[Axes], None]):
self.post_style = style
def clear_plots(self):
self.plots = []
def add_plot(self, plot: Callable[[Axes], None]):
self.plots.append(plot)
def redraw(self):
self.axes.clear()
self.pre_style(self.axes)
for plot in self.plots:
plot(self.axes)
self.post_style(self.axes)
self.canvas.draw()
class MainWindow(QMainWindow):
central_widget: QWidget
function_field: widgets.InputField
function_param_fields: ParamsField
x_0_field: widgets.InputField
x_n_field: widgets.InputField
n_slider: widgets.InputSlider
points_field: PointsField
margin_slider: widgets.InputSlider
function_plot: PlotWidget
error_plot: PlotWidget
function: Callable[[float], float]
interpolated_function: Callable[[float], float]
function_params: Dict[str, float]
x_0: float
x_n: float
n: int
points: List[float]
margin: float
parsing_function: bool
updating: bool
def __init__(self):
super().__init__()
self.n = 2
self.margin = 5
self.x_0 = 0.0
self.x_n = 1.0
self.points = [0.5]
self.function = None
self.function_params = {}
self.parsing_function = False
self.setup_ui()
self.reset()
def setup_ui(self):
self.setWindowTitle("Лабораторная работа №4")
self.setFixedSize(1400, 800)
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
layout = QHBoxLayout(self)
left_row = QWidget(self.central_widget)
left_row_layout = QFormLayout(left_row)
right_row = QWidget(self.central_widget)
right_row_layout = QFormLayout(right_row)
self.function_field = widgets.InputField(self, label_text="Функция: ")
self.function_field.set_callback(self._function_field_changed)
left_row_layout.addWidget(self.function_field)
self.function_param_fields = ParamsField(self, [])
self.function_param_fields.set_callback(self._function_param_field_changed)
left_row_layout.addWidget(self.function_param_fields)
self.x_0_field = widgets.InputField(
self, label_text="x_0: ", lineedit_text="0.0"
)
self.x_0_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_0_field_changed]
)
)
left_row_layout.addWidget(self.x_0_field)
self.x_n_field = widgets.InputField(
self, label_text="x_n: ", lineedit_text="1.0"
)
self.x_n_field.set_callback(
widgets.make_callback_chain(
[widgets.float_check_callback, self._x_n_field_changed]
)
)
left_row_layout.addWidget(self.x_n_field)
self.n_slider = widgets.InputSlider(self, "n: ", 1, 1, 20, 1, True)
self.n_slider.set_callback(self._n_slider_changed)
left_row_layout.addWidget(self.n_slider)
self.points_field = PointsField(self, 1, [0.5], 0.0, 1.0 - 0.001)
self.points_field.set_callback(self._points_field_changed)
left_row_layout.addWidget(self.points_field)
self.margin_slider = widgets.InputSlider(self, "отсутп (%): ", 5, 0, 100, 1)
self.margin_slider.set_callback(self._margin_slider_changed)
left_row_layout.addWidget(self.margin_slider)
reset_button = QPushButton("Сброс", self)
reset_button.clicked.connect(self.reset)
left_row_layout.addWidget(reset_button)
label1 = QLabel("График функции", self)
right_row_layout.addWidget(label1)
self.function_plot = PlotWidget(self)
self.function_plot.set_pre_style(self.function_plot_pre_style)
self.function_plot.set_post_style(self.function_plot_post_style)
right_row_layout.addWidget(self.function_plot)
label2 = QLabel("График ошибки", self)
right_row_layout.addWidget(label2)
self.error_plot = PlotWidget(self)
self.error_plot.set_pre_style(self.function_plot_pre_style)
self.error_plot.set_post_style(self.function_plot_post_style)
right_row_layout.addWidget(self.error_plot)
left_row.setLayout(left_row_layout)
right_row.setLayout(right_row_layout)
layout.addWidget(left_row)
layout.addWidget(right_row)
self.central_widget.setLayout(layout)
def function_plot_pre_style(self, axes: Axes):
axes.set_xlabel("x")
axes.set_ylabel("y")
axes.axhline(0, color="black", linewidth=1)
axes.axvline(0, color="black", linewidth=1)
axes.grid(True)
def function_plot_post_style(self, axes: Axes):
axes.legend()
def reset(self):
self.function_field.set_value(task.f_str())
self.x_0_field.set_value(0.0)
self.x_n_field.set_value(1.0)
self.n_slider.set_value(5)
self.margin_slider.set_value(5)
QtWidgets.QApplication.processEvents()
self.function_params = task.f_args()
self.function_param_fields.set_value(self.function_params)
QtWidgets.QApplication.processEvents()
self.redraw_plots()
QtWidgets.QApplication.processEvents()
def redraw_plots(self):
length = abs(self.x_n - self.x_0)
margin = length * self.margin / 100.0
x_min = self.x_0 - margin
x_max = self.x_n + margin
x_values = np.linspace(x_min, x_max, 200)
y_values = self.function(x_values)
y_interpolated = self.interpolated_function(x_values)
self.function_plot.clear_plots()
self.function_plot.add_plot(
lambda axes: axes.set_xlim(x_min - length * 0.05, x_max + length * 0.05)
)
self.function_plot.add_plot(
lambda axes: axes.plot(x_values, y_values, label="y = f(x)", color="red")
)
self.function_plot.add_plot(
lambda axes: axes.plot(
x_values,
y_interpolated,
label="y = L(x)",
color="blue",
linestyle="dashed",
)
)
points = [self.x_0, self.x_n]
points[1:1] = self.points
points = np.array(points)
# points = np.linspace(self.x_0, self.x_n, self.n + 1)
self.function_plot.add_plot(
lambda axes: axes.scatter(
points, self.function(points), color="green", zorder=10
)
)
def label_func(axes):
for i in range(len(points)):
axes.text(
points[i],
self.function(points[i]) + 0.05,
str(i),
ha="center",
va="bottom",
color="green",
)
self.function_plot.add_plot(label_func)
self.error_plot.clear_plots()
self.error_plot.add_plot(
lambda axes: axes.set_xlim(x_min - length * 0.05, x_max + length * 0.05)
)
self.error_plot.add_plot(
lambda axes: axes.plot(
x_values,
np.abs(y_values - y_interpolated),
color="blue",
label="|f(x) - L(x)|",
)
)
self.function_plot.redraw()
self.error_plot.redraw()
def parse_function(self, func_str: str) -> Callable[[float], float]:
func = sympy.sympify(func_str)
params = []
for name in func.atoms(sympy.Symbol):
params.append(str(name))
if len(params) == 0 or params.count("x") < 1:
raise ValueError("No x in function")
func_lambda = sympy.lambdify(params, func, cse=True)
if func_lambda.__code__.co_argcount != len(params):
raise ValueError("Bad arguments count")
params = [p for p in params if p != "x"]
old_params = self.function_params
if set(old_params.keys()) != set(params):
self.recreate_params_field(params)
def f(x: float) -> float:
return func_lambda(x=x, **self.function_params)
return f
def update_function(self):
if self.parsing_function:
return
try:
self.recalculate_interpolated_function()
self.redraw_plots()
except Exception as e:
print(e)
def recalculate_interpolated_function(self):
points = [self.x_0, self.x_n]
points[1:1] = self.points
points = np.array(points)
self.interpolated_function = algorithm.make_forward_interpolate_function(
self.function, points
)
# self.interpolated_function = algorithm.make_backward_interpolate_function(
# self.function, points
# )
def recreate_params_field(self, params: List[str]):
self.function_param_fields.recreate(params)
def recreate_points_field(self):
points = np.linspace(self.x_0, self.x_n, self.n + 1)
points = [float(p) for p in points[1:-1]]
self.points_field.recreate(
1,
points,
self.x_0 + 1 / self.points_field.DIVISIONS,
self.x_n - 1 / self.points_field.DIVISIONS,
)
self.points = points
def _function_field_changed(self, w: widgets.InputWidget) -> bool:
try:
self.parsing_function = True
self.function = self.parse_function(w.get_value())
self.parsing_function = False
except Exception as e:
print(f"{e}")
self.parsing_function = False
return False
self.update_function()
return True
def _function_param_field_changed(self, w: widgets.InputWidget) -> bool:
self.function_params = self.function_param_fields.get_value()
self.update_function()
return True
def _x_0_field_changed(self, w: widgets.InputWidget) -> bool:
value = float(w.get_value())
if value == self.x_n:
w.value = w.previous_value
return False
self.x_0 = value
self.recreate_points_field()
self.update_function()
return True
def _x_n_field_changed(self, w: widgets.InputWidget) -> bool:
value = float(w.get_value())
if value == self.x_0:
w.value = w.previous_value
return False
self.x_n = value
self.recreate_points_field()
self.update_function()
return True
def _n_slider_changed(self, w: widgets.InputWidget) -> bool:
self.n = int(w.get_value())
self.recreate_points_field()
# self.update_function()
return True
def _points_field_changed(self, w: widgets.InputWidget) -> bool:
self.points = w.get_value()
self.update_function()
return True
def _margin_slider_changed(self, w: widgets.InputWidget) -> bool:
self.margin = float(w.get_value())
self.redraw_plots()
return True