dih-jupyter/4. Jupyter - kalkulator symboliczny.ipynb

1980 lines
233 KiB
Plaintext
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Przygotowanie innowacyjnych materiałów szkoleniowych i dokumentacji wewnętrznych w obszarze IT\n",
"\n",
"## 4. Jupyter - kalkulator symboliczny: zadanie \"Pudełko Pad Thai\"\n",
"### <i>Bartosz Naskręcki</i>\n",
"\n",
"W tym pliku rozważymy zadanie z geometrii, którego rozwiązanie może być w całości wykonane z wykorzystaniem możliwości symbolicznych pakietu SymPy. Wszystkie obliczenia będą wykonane w rachunku symbolicznym, co powoduje, że nasze wyniki nie są przybliżeniami i wszelkie uzyskane formuły są udowodnione w sposób algebraiczny."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Zadanie:\n",
"\n",
"Rozważamy pudełko, którego ściany są pięciokątami foremnymi o długości boku 1. Podstawa pudełka jest kwadratem o boku 1. Zakładając, że ściany pudełka stykają się, oblicz jaka jest odległość pomiędzy górnymi wierzchołkami ścian pudełka leżących naprzeciw siebie."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"pad_thai.png\"></img>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wykonujemy import z biblioteki SymPy. W przypadku komunikatu o błędzie importu, należy zainstalować bibliotekę w lokalnej instancji Pythona."
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {},
"outputs": [],
"source": [
"from sympy import *"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Biblioteka [SymPy](https://www.sympy.org) posiada wbudowane możliwości rachunków symbolicznych na zmiennych oraz obsługę funkcji matematycznych wraz z relacjami pomiędzy nimi. Konstruując rozwiązanie naszego zadania zapoznamy się z szeregiem standardowych funkcjonalności. Rozszerzone możliwości tej biblioteki są wbudowane w pakiet matematyczny [SageMath](https://www.sagemath.org)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Strategia rozwiązania zadania:\n",
"\n",
"Aby obliczyć pożądaną odległość spróbujemy \"wyobrazić\" sobie całą sytuację. Powstanie pudełka polega na obróceniu w przestrzeni 3D czterech pięciokątnych ścian o pewien kąt $\\alpha$. Wybór tego kąta jest jednoznacznie ustalony przez warunek stykania się ścian wzdłuż zewnętrznych krawędzi. Nasza strategia wygląda więc następująco:\n",
"\n",
"1. Generujemy mechanizm, który wyznacza symbolicznie współrzędne wierzchołków pięciokąta foremnego.\n",
"2. Pozycjonujemy cztery kopie takiego pięciokąta na płaszczyźnie.\n",
"3. Korzystając z transformacji obrotu o zadany kąt względem prostej obracamy wybrane ściany o pewien nieznany kąt $\\alpha$. \n",
"4. Formułujemy warunek stykania ścian (warunek ten jest równaniem).\n",
"5. Wyznaczamy kąt z równania (jako wyrażenie symboliczne).\n",
"6. Obliczamy odległość zadanych punktów korzystając z wbudowanych w SymPy tożsamości trygonometrycznych."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Macierz obrotu o zadany kąt\n",
"\n",
"Macierze w SymPy są inicjalizowane komendą <b>Matrix</b>. Jako argument funkcja ta pobiera listę składającą z się z list tej samej długości (reprezentujących wiersze)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}1 & 2\\\\3 & 4\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[1, 2],\n",
"[3, 4]])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"M1=Matrix([[1,2],[3,4]])\n",
"M1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na macierzach możemy wykonywać standardowe operacje dodawania i mnożenia, operację obliczania śladu, wyznacznika i wiele innych. Użytkownik może sprawdzić aktualną listę zaimplementowanych funkcji za pomocą nazwy obiektu i kropki oraz przez wciśnięcie tabulatora"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"M1. #<+tabulator>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Macierz obrotu wokół punktu $(0,0)$ o zadany kąt $t$ (przeciwnie do ruchu wskazówek zegara) jest macierzą postaci"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"def obrot(t):\n",
" m=Matrix([[cos(t),-sin(t)],[sin(t),cos(t)]])\n",
" return m"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}0 & -1\\\\1 & 0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[0, -1],\n",
"[1, 0]])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"obrot(pi/2) #obrót o 90 stopni przeciwnie do ruchu wskazówek zegara"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Działanie macierzy obrotu możemy przetestować na wektorach (macierzach o wymiarach $1\\times n$). Wykorzystamy zmienne symboliczne, aby wyrazić działanie w ogólnym przypadku"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"x,y=symbols('x,y') #za pomocą komendy symbols możemy inicjalizować listę abstrakcyjnych zmiennych symbolicznych"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na zmiennych symbolicznych $x,y$ możemy wykonywać operacje podstawiania, elementarne operacje oraz wykorzystywać je jako argumenty w funkcjach, a także podstawiać pod nie wartości."
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle x + y$"
],
"text/plain": [
"x + y"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#dodawanie zmiennych\n",
"x+y"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle x y$"
],
"text/plain": [
"x*y"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#mnożenie zmiennych\n",
"x*y"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle x^{y}$"
],
"text/plain": [
"x**y"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#potęgowanie zmiennych\n",
"x**y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<b>UWAGA!</b>\n",
"\n",
"W standardowym Pythonie symbol ^ oznacza operację dodawania bitowego XOR. Do oznaczenia potęgowania używamy symbolu **"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\sin{\\left(y \\right)} + \\cos{\\left(x \\right)}$"
],
"text/plain": [
"sin(y) + cos(x)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#funkcja z abstrakcyjnym argumentem\n",
"cos(x)+sin(y)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\sin{\\left(y^{2} + 1 \\right)}$"
],
"text/plain": [
"sin(y**2 + 1)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#podstawienie argumentu\n",
"#w celu podstawienie wykorzystujemy strukturę słownika dict, której kluczami są podstawiane zmienne, a wartościami kluczy\n",
"#są wartości podstawiane\n",
"sin(x).subs({x:y**2+1})"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 0.900968867902419$"
],
"text/plain": [
"0.900968867902419"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#wartości symboliczne można przybliżać numerycznie\n",
"cos(pi/7).n()"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.9009688679024191"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#możemy konwertować wartości numeryczne do standardowego typu danych float\n",
"float(cos(pi/7))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ciekawostka:\n",
"Niektóre stałe matematyczne, np. $\\pi$ są wbudowane w SymPy i traktowane jako pewne zmienne symboliczne, które posiadają szczególne własności, np. wartości $\\cos(\\pi/n)$ można podać algebraicznie i numerycznie. To bardzo wygodny sposób operowania podstawowymi stałymi matematyki."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zbadajmy działanie operacji obrotu o kąt $t$ na wektorze o zmiennych symbolicznych $(x,y)$ "
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [],
"source": [
"t,x,y=symbols('t,x,y') #UWAGA: nie musimy ponownie deklarować zmiennych symbolicznych, robimy to tylko dla zachowania\n",
" #przejrzystości kodu"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x\\\\y\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[x],\n",
"[y]])"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v=Matrix([[x],[y]])\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(t \\right)} & - \\sin{\\left(t \\right)}\\\\\\sin{\\left(t \\right)} & \\cos{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[cos(t), -sin(t)],\n",
"[sin(t), cos(t)]])"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"obrot_o_t=obrot(t)\n",
"obrot_o_t"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x \\cos{\\left(t \\right)} - y \\sin{\\left(t \\right)}\\\\x \\sin{\\left(t \\right)} + y \\cos{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[x*cos(t) - y*sin(t)],\n",
"[x*sin(t) + y*cos(t)]])"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#obrót wektora (x,y) o kąt t\n",
"obrot_o_t*v"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zadanie: jakie są współrzędne wektora $(1,3)$ po obrocie o kąt $\\pi/4$ ?"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}- \\sqrt{2}\\\\2 \\sqrt{2}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[ -sqrt(2)],\n",
"[2*sqrt(2)]])"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(obrot_o_t*v).subs({x:1,y:3,t:pi/4})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zadanie: Korzystając z wektorów i macierzy obrotów wyznacz współrzędne wierzchołków wielokata foremnego (mającego $n$ boków) na płaszczyźnie, którego boki mają długość 1\n",
"\n",
"Rozwiązanie metodą \"żółwia\":\n",
"\n",
"1. Wystartuj w punkcie $(0,0)$.\n",
"2. Przesuń się o jednostkę w prawo za pomocą wektora $k=(1,0)$. Jesteś w punkcie $P_0=(1,0)$.\n",
"3. Obróć głowę żółwia o kąt $2\\cdot \\pi/n$.\n",
"4. Przesuń żółwia o jednostkę \"do przodu\". Jesteś w punkcie $P_1=P_0+\\theta(t)(k)$\n",
"5. Powtarzaj punkty (3)-(5) $n-1$ razy.\n",
"\n",
"Zwróć listę wierzchołków: $P_0,\\ldots, P_{n-1}$.\n",
"\n",
"Uwaga: Operacja $\\theta(t)$ to obrót wektora o zadany kąt $t$. W naszym przypadku mnożymy wektor kolumnowy z lewej przez macierz obrotu o kąt $t$."
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {},
"outputs": [],
"source": [
"def NkatForemny(n):\n",
" p0=Matrix([[0],[0]])\n",
" k=Matrix([[1],[0]])\n",
" ob=obrot(2*pi/n)\n",
" nkat=[]\n",
" w=p0+k\n",
" for i in range(0,n):\n",
" nkat.append(w)\n",
" k=ob*k #obróć żółwia\n",
" w+=k #przesuń o jednostkę w nowym kierunku\n",
" return nkat"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"⎡ ⎡1/2⎤ ⎤\n",
"⎢⎡1⎤ ⎢ ⎥ ⎡0⎤⎥\n",
"⎢⎢ ⎥, ⎢√3 ⎥, ⎢ ⎥⎥\n",
"⎢⎣0⎦ ⎢── ⎥ ⎣0⎦⎥\n",
"⎣ ⎣2 ⎦ ⎦\n"
]
}
],
"source": [
"pretty_print(NkatForemny(3)) #współrzędne trójkąta foremnego"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Rysowanie z biblioteką matplotlib\n",
"\n",
"Do rysowania wykorzystamy uniwersalną bibliotekę matplotlib. Na potrzeby prawidłowego rysowania korzystamy z dodatkowej \"magicznej komendy\"\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Rysowanie wielokątów\n",
"\n",
"Wielokąt w bibliotece matplotlib możemy narysować korzystając z komendy `fill`. Do narysowania wielokąta przekazujemy osobno jako argumenty wartości współrzędnych $x$-owych i $y$-owych. Do rozbicia listy wierzcholków na współrzędne używamy komendy \n",
"\n",
"`zip(*lista_wierzcholkow)`\n",
"\n",
"Uwaga: aby figury nie nachodziły na siebie przesuwamy macierzowo zbiory wierzchołków o odpowiedni wektor $(3i,0)$ dla każdej $i$-tej figury."
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAD4CAYAAADxeG0DAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAAW+0lEQVR4nO3deXhV9Z3H8c83m0BYhRAkAeKISwF1FDpVsS5FWpj2qW21VsbaZWqxG9NtqsU+M512ZtTaqXSdto5dbGVsO9W2SoGKWqW2WiVuUIKAQCQQSELYwpL1O38k9MFIkpvcs9wfvl/Pw0Nycu/v+yXcfHLO7/zuOebuAgCEKy/tBgAA2SHIASBwBDkABI4gB4DAEeQAELiCNIqOGTPGKyoq0igNAMGqrKxscPeS7ttTCfKKigqtWrUqjdIAECwzqz7WdqZWACBwBDkABI4gB4DAEeQAEDiCHAACR5ADQOAIcgAIHEEOAIEjyAEgcAQ5AASOIAeAwBHkABA4ghwAAkeQA0DgCHIACBxBDgCBI8gBIHAEOQAEjiAHgMAR5AAQOIIcAAJHkANA4AhyAAgcQQ4AgSPIASBwBDkABI4gB4DAEeQAEDiCHAACR5ADQOAIcgAIHEEOAIEjyAEgcAQ5AASOIAeAwBHkABA4ghwAAkeQA0DgCHIACFxkQW5m+Wb2rJktiWpMAEDfotwj/6SkqgjHAwBkIJIgN7NySW+VdGcU4wEAMhfVHvnXJd0gqaOnB5jZfDNbZWar6uvrIyoLAMg6yM3sbZLq3L2yt8e5+x3uPsPdZ5SUlGRbFgDQJYo98pmS3m5mWyT9TNKbzOzuCMYFAGQg6yB394XuXu7uFZKulvSIu783684AABlhHTkABK4gysHc/VFJj0Y5JgCgd+yRA0DgCHIACBxBDgCBI8gBIHAEOQAEjiAHgMAR5AAQOIIcAAJHkANA4AhyAAgcQQ4AgSPIASBwBDkABI4gB4DAEeQAEDiCHAACR5ADQOAIcgAIHEEOAIEjyAEgcAQ5AASOIAeAwBHkABA4ghwAAkeQA0DgCHIACBxBDgCBI8gBIHAEOQAEjiAHgMAR5AAQOIIcAAJHkANA4AhyAAgcQQ7gNa+ttV1bqxrV0eFptzIgBWk3AABpaTncpjWPbdNzD2/VoX0tGl4yWOe+eaLOOP8k5ReEs5+bdZCb2QRJP5FUKskl3eHu38h2XACIy+EDrXrh9zV64fdb1Xyg7a/b99Uf0qOLX9SqpVv0t7MnauqF41VQlJ9ip5mJYo+8TdJn3f0ZMxsmqdLMVrj72gjGBoDIHNzXouceellrVm5T6+H2Hh/XtLtZj/9igyqXbdHZsybozEvKVTQodycwsu7M3Wsl1XZ9vN/MqiSVSSLIAeSE/Y2H9eyKl1X1+Ha1tXZk/LxD+1v15K836dkHX9aZl5br7DdN0KDiwhg7HRhzj25y38wqJK2UNM3d93X72nxJ8yVp4sSJ06urqyOrCwDHsrf+oCqXV+vFP+9QR1v2WVd4Qr6mXlSmc2ZP1JDhRRF02D9mVunuM161PaogN7Ohkh6T9J/ufl9vj50xY4avWrUqkroA0N2u7U2qXFatjZV18hhWouQX5mnKBSfpnLdM0rATB0U+fk96CvJIJn3MrFDSvZIW9xXiABCXuup9qlxWrU3P13cuvYhJe2uHVj+2TX95fLtOf8M4nfuWSRpZOiS+gn2IYtWKSfqBpCp3vz37lgCgf7Zv3KPKpVv08trGROt2tLuq/lSrdU/u0ORzSzR9boVGlw1NtAcpmj3ymZKulbTazJ7r2naTuy+NYGwA6NHLa3epclm1tm/Yk2of3uHasKpOGyrrdPJZYzR9boVKK4YnVj+KVSuPS7IIegEQgdbaWnlzc+Tj5g0bpoLRoyMfd6AevHONNqyqS7uNV3Jp8/MN2vx8g6bPnaTzLj8lkbK5uzASQL81b9qkTZe/Q2ptjXzsgpISnbJ8mfKKiyMfu7862ju0efWutNvo1ebnGxIL8nDegwqgTztvuTWWEJektvp6NXzv+7GM3V8NNU1qa+75DT25oLH2gJoPxvN/0R1BDhwnmh57TAf+8IdYazTedZdatm6NtUYmdmzam3YLfXNpx6Z9fT8uAgQ5cBzw1lbtvPUr8ddpaVHdbbfFXqcvtS8FEOSSal/ak0gdghyvKWsa1mjhHxaq/mB92q1EqvHuxWrZvDmRWvtXPKQDTz6ZSK2e7AgkyJM6ciDI8Zrg7vrhmh/q2mXXasmmJbri/iu0smZl2m1Foq2xUQ3//d+J1tx58y3y9nTmqJt2H1bT7uhX5cRh55b96mjP/NouA0WQ47jXcKhB16+4XosqF6mto/OSpbubd+vjD39ctz51q1raW1LuMDv1i76ujv37E63ZvH69dv/854nWPCKUaRVJamtuV0NNU+x1CHIc1x7f9riuuP8KPVH7xDG/vrhqsa5Zeo02701mWiJqh6uqtOfee1Op3fDNb6l9b/KhGsq0yhFJTK8Q5Dgutba36ranb9PHHvqYGg/3/rbtdY3r9J4l79F9G8K7TNDOm2+ROuI/dD+W9j17VP/t7yReN6Q9cimZfglyHHeq91XrmqXX6KdrfyrP8MpJh9oO6Yt/+qI+99jntL8l2WmKgdq3fLkOPv10qj3svuceNb/0UmL1WpvbtSuBqYooJXEEQZDjuPLrjb/WVQ9cparGqgE9f/mW5Xr3A+/Wc3XPRdtYxDqam1V321fTbkNqa+s8KkjIzi37grtBctPuZu1vPBxrDYIcx4WmlibduPJG/csf/0UH2w5mNda2pm364PIP6o4X7lCHpzNt0ZddP/iBWrdvT7sNSdKBP/5R+x/5fSK1QpsfPyLueXKCHMFbXb9a737g3Vq6OboLbrZ5m7717Lf04Qc/rLqDuXVhptYdO7Trf+5Mu41XqPvKV+Qt8a/+CW1+/Ii4+ybIESx3152r79T7lr9PNU01sdR4asdTuuL+K/To1kdjGX8g6r52u/zQobTbeIWW6mo1/vTuWGu4u3ZuDjPI4z6SIMgRpPqD9Zq/Yr6+8cw3/ro2PC57mvdowSMLdPOfb059zfnBZ5/VviVLUu2hJw3f/a7adsV3RcLOi1DF+38dl101TWqN8SJfBDmCs7Jmpa584Eo9WZvs28TvWXeP5v12njbt2ZRo3SPcvfPEYoQ3TI9SR1OT6hYtim38UOfHJamjw7VzS3wX0OJ65CH7txExjp17PzSt7a26vfJ2La5anPGywqit371eV//2at3w+ht05WlXJlp7769+rcOrVydas7/23vcrjZo3T4OnTo187CCueNiLHS/tVfnpo2IZmz1yBOObz35Td1fdnVqIH3Go7ZC+9MSX9HD1w4nVbG86oLpFAdwSt6MjtuWIoZ7oPCLO/glyBGN66fS0W/irfMvXOaXnJFZv1/e/r/b6hsTqZeNQZaX2LY32lr2H9rdob11uneDtr52b98pjmhY7boO8vcP1m+e2pd0GInTB+AtUXJj+bcakzl8qJw46MbF6h3J8SqW7Qy9E22/oe+OS1HywTY21B2IZ+7gN8v996mXdeO8Lqtmd3ZtDkDuK8ot0UflFabchSbps0mWJ1hv7uX+W8sL4cc0fMUJjPnJ9pGOGPj9+RFwnbMN4ZfTT3oOtWrRivQ63duiWpevSbgcRmj1pdtotyGSaNXFWojUHT52qEe96Z6I1B2rMggXKHzky0jHHThoe6XhpyCswjS4bGs/YsYyaskUPrVfjgc71vr9dXas/b8rtu20jcxeWXajBBYNT7eHskrM1dsjYxOuO/fSnlTc0niCIygmnnqpR866OfNzJ08fqnNkTIx83SRe95zSN+5t4Vpodd0G+sW6/7n6y+hXbvvTA2uAutINjG1wwWDPHz0y1h6SnVY4oGD1aYz760VRqZ6r0poWy/PxYxj7vnadowuviWb4XtykXjtfUN5bFNv5xF+RfXlKltm6hvbZ2n36+Kv07fyMaaQXpEWlO75z4vmtVNGlSavV7M3TWLBWff35s4+flmd583TQNHzMothpxKD15uC66+rRYaxxXQf5w1U6tXH/sm+p+7cE
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig = plt.figure()\n",
"for i in range(0,5):\n",
" wielokatli=(list(tuple(wierzcholek+Matrix([[3*i],[0]])) for wierzcholek in NkatForemny(i+3)));\n",
" wielokatli.append(wielokatli[0]) #dla domknięcia dodajemy ostatni wierzchołek równy pierwszemu\n",
" xli,yli=zip(*wielokatli)\n",
" plt.axis('equal') #proporcjonalne osie\n",
" #axis('off')\n",
" plt.fill(xli,yli)\n",
"plt.show() #rysowanie skonfigurowanej ilustracji"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz jesteśmy już gotowi do wygenerowania naszego modelowego pięciokąta foremnego. Pamiętamy o dodaniu na końcu listy dodatkowego wierzchołka, który jest równy $P_0$. Jest to potrzebne dla prawidłowego rysowania wielokątów."
]
},
{
"cell_type": "code",
"execution_count": 173,
"metadata": {},
"outputs": [],
"source": [
"pieciokat0=NkatForemny(5)\n",
"pieciokat0.append(pieciokat0[0])\n",
"pieciokat=[Matrix([[list(y)[0].simplify()],[list(y)[1].simplify()]]) for y in pieciokat0] #upraszczamy formuły"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"W kodzie powyżej użyliśmy potężnej funkcjonalności \n",
"\n",
"`<wyrazenie>.simplify()`\n",
"\n",
"która upraszcza w znany SymPy sposób wyrażenia symboliczne. Do uproszczeń stosuje się znane zależności między funkcjami oraz tożsamości. Efekt działania tej komendy zależy w istotny sposób od wyrażenia i jest zawsze taki sam dla tego samego wyrażenia."
]
},
{
"cell_type": "code",
"execution_count": 140,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 360x360 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"wielokatli=list(tuple(wierzcholek) for wierzcholek in NkatForemny(5));\n",
"wielokatli.append(wielokatli[0])\n",
"xli,yli=zip(*wielokatli)\n",
"fig=plt.figure(figsize=[5,5]) #wielkość figury w kierunku x i y\n",
"plt.axis('equal')\n",
"plt.axis('off') #wyłączenie wyświetlania osi\n",
"plt.fill(xli,yli,color='red')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wielokąty możemy na siebie nakładać i kolorować. Poniższy przykład polega na obracaniu pięciokątów o zadany kąt i ustawianiu ich jeden na drugim, ze zmieniającym się kolorem. Kolor jest zadany jako `color=(R,G,B)`, gdzie parametry $R$, $G$, $B$ są liczbami rzeczywistymi w przedziale $0$ do $1$."
]
},
{
"cell_type": "code",
"execution_count": 243,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 360x360 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"#wyznaczanie środka ciężkości\n",
"def sumM(li): \n",
" sum0=li[0]\n",
" for el in li[1:]:\n",
" sum0+=el\n",
" return sum0*Rational(1,len(li))\n",
"\n",
"#obrót wielokąta po przesunięcia środka ciężkości do (0,0) i przesunięcie go z powrotem + zastosowanie skali\n",
"def obrotSkalaWielokat(wiel,t,skala): #wiel[:-1]==wiel[0]\n",
" s=sumM(wiel[:-1])\n",
" rot=[obrot(t)*((el-s)*skala)+s for el in wiel[:-1]]\n",
" return rot+[rot[0]]\n",
"\n",
"\n",
"#inicjalizacja figury\n",
"fig=plt.figure(figsize=[5,5]) #wielkość figury w kierunku x i y\n",
"plt.axis('equal')\n",
"#plt.axis('off') #wyłączenie wyświetlania osi\n",
"\n",
"#trzydzieści iteracji rysowania pięciokąta\n",
"iteracje=30\n",
"for i in range(0,iteracje):\n",
" wielokatli=obrotSkalaWielokat(pieciokat,2*i*pi/(5*iteracje),Rational(iteracje-i,40*iteracje))\n",
" xli,yli=zip(*wielokatli)\n",
" plt.fill(xli,yli,color=(1-(i/iteracje)**(1/2),(i/iteracje)**2,(iteracje-i)/iteracje))\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wracając do naszego głównego zadania, pozycjonujemy cztery pięciokącie na płaszczyźnie, aby stworzyły makietę ścian naszego pudełka. Ponieważ dno pudełka nie będzie nam potrzebne, więc je ignorujemy.\n",
"\n",
"Pozycjonowanie odbywa się za pomocą obrotów o kąty $0,90,180$ i $270$ stopni, wraz z odpowiednimi przesunięciami o wektory na płaszczyźnie. Do szybkiego przetransformowania odpowiednich wektorów stosujemy komendę `map` wraz z argumentem, którym jest funkcja transformująca i lista (w tym przypadku `pieciokat`)."
]
},
{
"cell_type": "code",
"execution_count": 245,
"metadata": {},
"outputs": [],
"source": [
"pi1=list(map(lambda x: x+Matrix([[0],[1]]),pieciokat))\n",
"pi2=list(map(lambda x: obrot(-pi/2)*x+Matrix([[1],[1]]),pieciokat))\n",
"pi3=list(map(lambda x: obrot(-pi)*x+Matrix([[1],[0]]),pieciokat))\n",
"pi4=list(map(lambda x: obrot(-3/2*pi)*x+Matrix([[0],[0]]),pieciokat))"
]
},
{
"cell_type": "code",
"execution_count": 249,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 360x360 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"#definiujemy pomocniczą funkcję rysującą pojedynczy wielokąt\n",
"def polygon_draw(li,color):\n",
" wielokatli=list(tuple(wierzcholek) for wierzcholek in li);\n",
" wielokatli.append(wielokatli[0])\n",
" xli,yli=zip(*wielokatli)\n",
" plt.fill(xli,yli,color)\n",
"\n",
"fig=plt.figure(figsize=[5,5])\n",
"plt.axis('equal')\n",
"polygon_draw(pi1,color='red')\n",
"polygon_draw(pi2,color='blue')\n",
"polygon_draw(pi3,color='green')\n",
"polygon_draw(pi4,color='black')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz czeka nas trudniejsze zadanie. Musimy opracować wzory na obracanie naszych pięciokątów w trzech wymiarach, wokół krawędzi, która styka się z białym kwadratem. \n",
"\n",
"Nasze pięciokąty zyskają dodatkową, trzecią współrzędną, równą 0. Po obrocie ich współrzędne będą zazwyczaj niezerowe."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Obrót wokół osi $X$ odbywa się w ten sposób, że wektor $(x,y,z)$ zachowuje współrzędną $y$. Współrzędne $(x,z)$ obracamy za pomocą macierzy obrotu $\\theta(t)$ o zadany kąt $t$."
]
},
{
"cell_type": "code",
"execution_count": 258,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x \\cos{\\left(t \\right)} - z \\sin{\\left(t \\right)}\\\\y\\\\x \\sin{\\left(t \\right)} + z \\cos{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[x*cos(t) - z*sin(t)],\n",
"[ y],\n",
"[x*sin(t) + z*cos(t)]])"
]
},
"execution_count": 258,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x,y,z,t=symbols('x,y,z,t')\n",
"v=Matrix([[x],[y],[z]]) #wektor poddany transformacji\n",
"vtmp=obrot(t)*Matrix([v[0],v[2]]) #obrót tylko na 0 i 2 współrzędnej\n",
"vobr=Matrix([[vtmp[0]],[v[1]],[vtmp[1]]]) #złączenie ponowne w wektor 3D\n",
"vobr"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Bazując na powyższych kalkulacjach definiujemy zatem funkcję"
]
},
{
"cell_type": "code",
"execution_count": 256,
"metadata": {},
"outputs": [],
"source": [
"def ObrotWX0(v,t):\n",
" x,y,z=list(v)\n",
" return Matrix([[x*cos(t) - z*sin(t), y, x*sin(t)+z*cos(t)]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podobnie wyznaczamy obrót wokół osi Y"
]
},
{
"cell_type": "code",
"execution_count": 257,
"metadata": {},
"outputs": [],
"source": [
"def ObrotWY0(v,t):\n",
" x,y,z=list(v)\n",
" return Matrix([[x, y*cos(t) - z*sin(t), y*sin(t)+z*cos(t)]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz chcemy obrócić wokół osi zadanej równaniem $x=1$. W związku z tym, najpierw przesuwamy nasze punktu o $1$ jednostkę w lewo, obracamy, a następnie wracamy o jedną jednostkę w prawo. Tak uzyskana transformacja będzie obrotem o zadany kąt wokół osi przechodzącej przez $x=1$."
]
},
{
"cell_type": "code",
"execution_count": 259,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}- z \\sin{\\left(t \\right)} + \\left(x - 1\\right) \\cos{\\left(t \\right)} + 1\\\\y\\\\z \\cos{\\left(t \\right)} + \\left(x - 1\\right) \\sin{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[-z*sin(t) + (x - 1)*cos(t) + 1],\n",
"[ y],\n",
"[ z*cos(t) + (x - 1)*sin(t)]])"
]
},
"execution_count": 259,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x,y,z,t=symbols('x,y,z,t')\n",
"v=Matrix([[x],[y],[z]]) #wektor poddany transformacji\n",
"vtmp=obrot(t)*Matrix([v[0]-1,v[2]]) #obrót tylko na 0 i 2 współrzędnej\n",
"vobr=Matrix([[vtmp[0]+1],[v[1]],[vtmp[1]]]) #złączenie ponowne w wektor 3D\n",
"vobr"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Przedstawiamy rezultat w formie stosownej funkcji"
]
},
{
"cell_type": "code",
"execution_count": 260,
"metadata": {},
"outputs": [],
"source": [
"def ObrotWX1(v,t):\n",
" x,y,z=list(v)\n",
" return Matrix([[-z*sin(t)+(x-1)*cos(t) +1 , y, z*cos(t) + (x-1)*sin(t)]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Analogiczny rachunek pozwala nam skonstruować funkcję obrotu wokół osi zadanej równaniem $y=1$"
]
},
{
"cell_type": "code",
"execution_count": 261,
"metadata": {},
"outputs": [],
"source": [
"def ObrotWY1(v,t):\n",
" x,y,z=list(v)\n",
" return Matrix([[x, 1 - cos(t) + y*cos(t) - z*sin(t), z*cos(t) - sin(t) + y*sin(t)]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz mając zadany wektor oraz kąt obrotu, możemy śledzić zmiany konkretnych wektorów pod wpływem obrotów. Przykładowo"
]
},
{
"cell_type": "code",
"execution_count": 262,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(t \\right)} & 1 & \\sin{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([[cos(t), 1, sin(t)]])"
]
},
"execution_count": 262,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t=Symbol('t')\n",
"ObrotWX0([1,1,0],t)"
]
},
{
"cell_type": "code",
"execution_count": 263,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}1 & \\cos{\\left(t \\right)} & \\sin{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([[1, cos(t), sin(t)]])"
]
},
"execution_count": 263,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ObrotWY0([1,1,0],t)"
]
},
{
"cell_type": "code",
"execution_count": 264,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(t \\right)} + 1 & 0 & \\sin{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([[cos(t) + 1, 0, sin(t)]])"
]
},
"execution_count": 264,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ObrotWX1([2,0,0],t)"
]
},
{
"cell_type": "code",
"execution_count": 265,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}0 & \\cos{\\left(t \\right)} + 1 & \\sin{\\left(t \\right)}\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([[0, cos(t) + 1, sin(t)]])"
]
},
"execution_count": 265,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ObrotWY1([0,2,0],t)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Potrzebujemy teraz biblioteki do rysowania kształtów w 3D"
]
},
{
"cell_type": "code",
"execution_count": 266,
"metadata": {},
"outputs": [],
"source": [
"from mpl_toolkits.mplot3d import Axes3D"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wyrysujmy w 3D trajektorie ruchu czterech wierzchołków pod wpływem obrotu o zadany kąt. Funkcja `arange` pozwala nam wybrać częstotliwość próbkowania liczb z zadanego przedziału."
]
},
{
"cell_type": "code",
"execution_count": 270,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig = plt.figure()\n",
"ax = fig.gca(projection='3d')\n",
"\n",
"x,y,z=list(ObrotWX0([1,1,0],t))\n",
"xli=list(map(lambda v:x.subs({t:v}),arange(-pi/2,0,0.1)))\n",
"yli=list(map(lambda v:y.subs({t:v}),arange(-pi/2,0,0.1)))\n",
"zli=list(map(lambda v:z.subs({t:v}),arange(-pi/2,0,0.1)))\n",
"ax.plot(xli, yli, zli)\n",
"\n",
"x,y,z=list(ObrotWY0([1,1,0],t))\n",
"xli=list(map(lambda v:x.subs({t:v}),arange(0,pi/2,0.1)))\n",
"yli=list(map(lambda v:y.subs({t:v}),arange(0,pi/2,0.1)))\n",
"zli=list(map(lambda v:z.subs({t:v}),arange(0,pi/2,0.1)))\n",
"ax.plot(xli, yli, zli)\n",
"\n",
"x,y,z=list(ObrotWX1([2,0,0],t))\n",
"xli=list(map(lambda v:x.subs({t:v}),arange(0,pi/2,0.1)))\n",
"yli=list(map(lambda v:y.subs({t:v}),arange(0,pi/2,0.1)))\n",
"zli=list(map(lambda v:z.subs({t:v}),arange(0,pi/2,0.1)))\n",
"ax.plot(xli, yli, zli)\n",
"\n",
"x,y,z=list(ObrotWY1([0,2,0],t))\n",
"xli=list(map(lambda v:x.subs({t:v}),arange(0,pi/2,0.1)))\n",
"yli=list(map(lambda v:y.subs({t:v}),arange(0,pi/2,0.1)))\n",
"zli=list(map(lambda v:z.subs({t:v}),arange(0,pi/2,0.1)))\n",
"ax.plot(xli, yli, zli)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wprowadźmy teraz cztery pięciokąty jako trójwymiarowe figury. Będziemy na nich wykonywać operacje obrotu (na ich wierzchołkach), wokół wybranych wcześniej osi."
]
},
{
"cell_type": "code",
"execution_count": 272,
"metadata": {},
"outputs": [],
"source": [
"pi1_3d=list(map(lambda x: Matrix(list(x)+[0]),pi1))\n",
"pi2_3d=list(map(lambda x: Matrix(list(x)+[0]),pi2))\n",
"pi3_3d=list(map(lambda x: Matrix(list(x)+[0]),pi3))\n",
"pi4_3d=list(map(lambda x: Matrix(list(x)+[0]),pi4))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Funkcjonalność SymPy pozwala nam obrócić dany pięciokąt o abstrakcyjny kąt $t$."
]
},
{
"cell_type": "code",
"execution_count": 315,
"metadata": {},
"outputs": [],
"source": [
"t=symbols('t')\n",
"pol1_3d=list(map(lambda x: ObrotWY1(x,t),pi1_3d)) #obrót przeciwny do ruchu wskazówek zegara\n",
"pol2_3d=list(map(lambda x: ObrotWX1(x,t),pi2_3d)) #obrót przeciwny do ruchu wskazówek zegara\n",
"pol3_3d=list(map(lambda x: ObrotWY0(x,-t),pi3_3d)) #obrót zgodny z ruchem wskazówek zegara\n",
"pol4_3d=list(map(lambda x: ObrotWX0(x,-t),pi4_3d)) #obrót zgodny z ruchem wskazówek zegara"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Efekt takiej operacji jest skomplikowanym wyrażeniem wierzchołków jako funkcji zależnych od $t$.\n",
"\n",
"Uwaga: rezygnujemy z wektorów kolumnowych, od teraz będziemy posługiwać się tylko wektorami wierszowymi"
]
},
{
"cell_type": "code",
"execution_count": 277,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Matrix([[1, 1, 0]]),\n",
" Matrix([[sqrt(5)/4 + 3/4, -cos(t) + (sqrt(2*sqrt(5) + 10)/4 + 1)*cos(t) + 1, -sin(t) + (sqrt(2*sqrt(5) + 10)/4 + 1)*sin(t)]]),\n",
" Matrix([[1/2, -cos(t) + (1 + (sqrt(2) + sqrt(10))*sqrt(sqrt(5) + 5)/8)*cos(t) + 1, -sin(t) + (1 + (sqrt(2) + sqrt(10))*sqrt(sqrt(5) + 5)/8)*sin(t)]]),\n",
" Matrix([[1/4 - sqrt(5)/4, -cos(t) + (sqrt(2*sqrt(5) + 10)/4 + 1)*cos(t) + 1, -sin(t) + (sqrt(2*sqrt(5) + 10)/4 + 1)*sin(t)]]),\n",
" Matrix([[0, 1, 0]]),\n",
" Matrix([[1, 1, 0]])]"
]
},
"execution_count": 277,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pol1_3d"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wreszcie jesteśmy gotowi rozwiązać nasze zadanie. Mając dane dwa sąsiednie pięciokąty pod wpływem obrotu, czekamy na moment, gdy parametr $t$ spełnia warunek, że drugi wierzchołek pierwszego pięciokąta pokryje się z czwartym wierzchołkiem drugiego pięciokąta. Wtedy nasze pudełko domyka się."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Chcemy zatem, aby następujące trzy wyrażenia przyjęły wartość $0$."
]
},
{
"cell_type": "code",
"execution_count": 289,
"metadata": {},
"outputs": [],
"source": [
"#boki zetkną się, gdy wyrażenia poniżej zerują się\n",
"wyrazenia=list(pol1_3d[1]-pol2_3d[3])\n",
"eq1=Eq(wyrazenia[0],0) #komenda Eq służy do formowania równań\n",
"eq2=Eq(wyrazenia[1],0)\n",
"eq3=Eq(wyrazenia[2],0)"
]
},
{
"cell_type": "code",
"execution_count": 290,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle - \\frac{\\sqrt{2 \\sqrt{5} + 10} \\cos{\\left(t \\right)}}{4} - \\frac{1}{4} + \\frac{\\sqrt{5}}{4} = 0$"
],
"text/plain": [
"Eq(-sqrt(2*sqrt(5) + 10)*cos(t)/4 - 1/4 + sqrt(5)/4, 0)"
]
},
"execution_count": 290,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq1"
]
},
{
"cell_type": "code",
"execution_count": 291,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle - \\cos{\\left(t \\right)} + \\left(\\frac{\\sqrt{2 \\sqrt{5} + 10}}{4} + 1\\right) \\cos{\\left(t \\right)} - \\frac{\\sqrt{5}}{4} + \\frac{1}{4} = 0$"
],
"text/plain": [
"Eq(-cos(t) + (sqrt(2*sqrt(5) + 10)/4 + 1)*cos(t) - sqrt(5)/4 + 1/4, 0)"
]
},
"execution_count": 291,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq2"
]
},
{
"cell_type": "code",
"execution_count": 292,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle - \\sin{\\left(t \\right)} - \\frac{\\sqrt{2 \\sqrt{5} + 10} \\sin{\\left(t \\right)}}{4} + \\left(\\frac{\\sqrt{2 \\sqrt{5} + 10}}{4} + 1\\right) \\sin{\\left(t \\right)} = 0$"
],
"text/plain": [
"Eq(-sin(t) - sqrt(2*sqrt(5) + 10)*sin(t)/4 + (sqrt(2*sqrt(5) + 10)/4 + 1)*sin(t), 0)"
]
},
"execution_count": 292,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Upraszczanie wyrażeń\n",
"\n",
"Nasze równania $eq_1,eq_2,eq_3$ możemy uprościć stosując komendę `.simplify()`. Zauważymy, że dwa pierwsze równania są równoważne. Trzecie upraszcza się do postaci $0=0$."
]
},
{
"cell_type": "code",
"execution_count": 296,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{\\sqrt{2 \\sqrt{5} + 10} \\cos{\\left(t \\right)}}{4} - \\frac{\\sqrt{5}}{4} + \\frac{1}{4} = 0$"
],
"text/plain": [
"Eq(sqrt(2*sqrt(5) + 10)*cos(t)/4 - sqrt(5)/4 + 1/4, 0)"
]
},
"execution_count": 296,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq1.simplify()"
]
},
{
"cell_type": "code",
"execution_count": 297,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{\\sqrt{2 \\sqrt{5} + 10} \\cos{\\left(t \\right)}}{4} - \\frac{\\sqrt{5}}{4} + \\frac{1}{4} = 0$"
],
"text/plain": [
"Eq(sqrt(2*sqrt(5) + 10)*cos(t)/4 - sqrt(5)/4 + 1/4, 0)"
]
},
"execution_count": 297,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq2.simplify()"
]
},
{
"cell_type": "code",
"execution_count": 299,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 299,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(eq1.simplify())==(eq2.simplify())"
]
},
{
"cell_type": "code",
"execution_count": 300,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{True}$"
],
"text/plain": [
"True"
]
},
"execution_count": 300,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq3.simplify()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pozostaje nam zatem wyznaczyć wartość kąta $t$ z wykorzystaniem równania $1$. Do tego wykorzystamy funkcję `solve`, która równanie symboliczne rozwiązuje ze względu na wskazane zmienne. Zachowanie tej komendy będzie zależało w istotny sposób od wybranego równania."
]
},
{
"cell_type": "code",
"execution_count": 303,
"metadata": {},
"outputs": [],
"source": [
"#rozwiązujemy równanie ze względu na t (rozwiązanie dokładne)\n",
"solv=solve(eq1,t)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Obiekt rozwiązania `solv` przechowuje listę wszystkich rozwiązań. Są dokłądnie 2 - jedno odpowiadające obrotowi naszych ścian w górę, drugie obrotowi w dół. Zauważmy, że rozwiązania są wyrażone symbolicznie za pomocą funkcji arcus cosinus."
]
},
{
"cell_type": "code",
"execution_count": 304,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 304,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(solv)==2"
]
},
{
"cell_type": "code",
"execution_count": 305,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle - \\operatorname{acos}{\\left(\\frac{- \\sqrt{2} + \\sqrt{10}}{2 \\sqrt{\\sqrt{5} + 5}} \\right)} + 2 \\pi$"
],
"text/plain": [
"-acos((-sqrt(2) + sqrt(10))/(2*sqrt(sqrt(5) + 5))) + 2*pi"
]
},
"execution_count": 305,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solv[0]"
]
},
{
"cell_type": "code",
"execution_count": 306,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\operatorname{acos}{\\left(\\frac{- \\sqrt{2} + \\sqrt{10}}{2 \\sqrt{\\sqrt{5} + 5}} \\right)}$"
],
"text/plain": [
"acos((-sqrt(2) + sqrt(10))/(2*sqrt(sqrt(5) + 5)))"
]
},
"execution_count": 306,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solv[1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Gdy interesuje nas wartość numeryczna tych kątów wyrażona w stopniach, możemy posłużyć się przybliżeniem."
]
},
{
"cell_type": "code",
"execution_count": 307,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 288.960709881923$"
],
"text/plain": [
"288.960709881923"
]
},
"execution_count": 307,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(solv[0]*180/pi).n()"
]
},
{
"cell_type": "code",
"execution_count": 308,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 71.0392901180775$"
],
"text/plain": [
"71.0392901180775"
]
},
"execution_count": 308,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(solv[1]*180/pi).n()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Naszym \"magicznym\" kątem będzie wybór podyktowany obrotem w górę."
]
},
{
"cell_type": "code",
"execution_count": 309,
"metadata": {},
"outputs": [],
"source": [
"magiczny_kat=solv[1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz zobaczmy, że faktycznie znaleziony przez nas kąt odpowiada prawidłowemu złożeniu pudełka."
]
},
{
"cell_type": "code",
"execution_count": 314,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"from mpl_toolkits.mplot3d.art3d import Poly3DCollection\n",
"def VertFloat(li):\n",
" xl,yl,zl=zip(*li)\n",
" xl=[float(x) for x in xl]\n",
" yl=[float(x) for x in yl]\n",
" zl=[float(x) for x in zl]\n",
" return [list(zip(xl,yl,zl))]\n",
"fig = plt.figure()\n",
"ax = Axes3D(fig)\n",
"\n",
"#zakres\n",
"ax.set_xlim3d(-3,3)\n",
"ax.set_ylim3d(-3,3)\n",
"ax.set_zlim3d(0,3)\n",
"\n",
"#ustawienia kamery\n",
"ax.dist=5\n",
"ax.elev=8\n",
"ax.azim=170\n",
"\n",
"#wierzchołki wielokątów\n",
"tt=magiczny_kat\n",
"pol1_3d_float=[VertFloat(list(map(lambda x: ObrotWY1(x,tt),pi1_3d))),['red','black']]\n",
"pol2_3d_float=[VertFloat(list(map(lambda x: ObrotWX1(x,tt),pi2_3d))),['blue','black']]\n",
"pol3_3d_float=[VertFloat(list(map(lambda x: ObrotWY0(x,-tt),pi3_3d))),['green','black']]\n",
"pol4_3d_float=[VertFloat(list(map(lambda x: ObrotWX0(x,-tt),pi4_3d))),['black','white']]\n",
"#print(verts)\n",
"\n",
"#dodawanie figur\n",
"for verts in [pol1_3d_float,pol2_3d_float,pol3_3d_float,pol4_3d_float]:\n",
" ax.add_collection3d(Poly3DCollection(verts[0],facecolor =verts[1][0],edgecolor=verts[1][1]))\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Obliczamy odległość wierzchołków\n",
"\n",
"Pozostaje nam zatem ostatnie zadanie. Obliczymy odległość naprzeciwległych wierzchołków. Wybieramy je jako trzeci wierzchołek pierwszego pięciokąta i trzeci wierzchołek trzeciego pięciokąta."
]
},
{
"cell_type": "code",
"execution_count": 316,
"metadata": {},
"outputs": [],
"source": [
"wierzcholek1=pol1_3d[2]\n",
"wierzcholek2=pol3_3d[2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Odległość wierzchołków od siebie to długość wektora ich różnicy"
]
},
{
"cell_type": "code",
"execution_count": 318,
"metadata": {},
"outputs": [],
"source": [
"roznica=wierzcholek1-wierzcholek2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Współrzędne pierwsza i trzecia wektora roznica zerują się. Jedno zerowanie wynika automatycznie, drugie uzyskujemy po zastosowaniu metody `simplify()`"
]
},
{
"cell_type": "code",
"execution_count": 319,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 0$"
],
"text/plain": [
"0"
]
},
"execution_count": 319,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roznica[0]"
]
},
{
"cell_type": "code",
"execution_count": 322,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{\\sqrt{2 \\sqrt{5} + 10} \\cos{\\left(t \\right)}}{4} + \\frac{\\sqrt{10 \\sqrt{5} + 50} \\cos{\\left(t \\right)}}{4} + 1$"
],
"text/plain": [
"sqrt(2*sqrt(5) + 10)*cos(t)/4 + sqrt(10*sqrt(5) + 50)*cos(t)/4 + 1"
]
},
"execution_count": 322,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roznica[1].simplify()"
]
},
{
"cell_type": "code",
"execution_count": 323,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 0$"
],
"text/plain": [
"0"
]
},
"execution_count": 323,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roznica[2].simplify()"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{\\sqrt{2} \\sqrt{\\sqrt{5} + 5} \\cos{\\left(t \\right)} + \\sqrt{10} \\sqrt{\\sqrt{5} + 5} \\cos{\\left(t \\right)} + 4}{4}$"
],
"text/plain": [
"(sqrt(2)*sqrt(sqrt(5) + 5)*cos(t) + sqrt(10)*sqrt(sqrt(5) + 5)*cos(t) + 4)/4"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(wierzcholek1-wierzcholek2)[1].factor()"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 0$"
],
"text/plain": [
"0"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(wierzcholek1-wierzcholek2)[2].factor()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zatem odległość między wierzchołkami wynosi ostatecznie `abs(roznica[1])`. Obliczmy wprost to wyrażenie dla naszego kąta styku obliczonego wcześniej."
]
},
{
"cell_type": "code",
"execution_count": 324,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle 2$"
],
"text/plain": [
"2"
]
},
"execution_count": 324,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(roznica)[1].subs({t:magiczny_kat}).expand()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zatem udowodniliśmy matematycznie, że odległość między wybranymi wierzchołkami wynosi dokładnie 2. Wykorzystana przez nas biblioteka obliczeń symbolicznych SymPy pozwala nam na tę absolutną konluzję."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Inny sposób obliczenia odległosci\n",
"\n",
"W naszych obliczeniach wyliczenie kąta $t$ dla styku nie było tak istotne. Kluczowe było, że obliczyliśmy wartość funkcji $cos(t)$ dla tego kąta. To pozwala nam inaczej podejść do poprzednich rachunków i wyrugować z użycia funkcji solve odwracanie funkcji cosinus."
]
},
{
"cell_type": "code",
"execution_count": 345,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}0 & 2 & 0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([[0, 2, 0]])"
]
},
"execution_count": 345,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sol=(roznica).subs({cos(t):solve(eq1,cos(t))[0]})\n",
"sol.simplify()\n",
"sol"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na koniec obejrzyjmy jeszcze raz całą sytuację z wybranego kąta. Korzystamy w naszej funkcji rysującej dodatkowo z interaktywnych widżetów zawartych w bibliotece `ipywidgets`"
]
},
{
"cell_type": "code",
"execution_count": 350,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "5527cbe2eed445faaeed7fdf612f5124",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.61, description='tt', max=1.2398695108399236, step=0.01), FloatSlide…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from ipywidgets import interactive\n",
"from mpl_toolkits.mplot3d.art3d import Line3DCollection\n",
"\n",
"def VertFloat(li):\n",
" xl,yl,zl=zip(*li)\n",
" xl=[float(x) for x in xl]\n",
" yl=[float(x) for x in yl]\n",
" zl=[float(x) for x in zl]\n",
" return [list(zip(xl,yl,zl))]\n",
"def f(tt,dist,elev,azim):\n",
" fig = plt.figure(figsize=[3,3])\n",
" ax = Axes3D(fig)\n",
"\n",
" #zakres\n",
" ax.set_xlim3d(-3,3)\n",
" ax.set_ylim3d(-3,3)\n",
" ax.set_zlim3d(0,3)\n",
"\n",
" #ustawienia kamery\n",
" ax.dist=dist\n",
" ax.elev=elev\n",
" ax.azim=azim\n",
"\n",
" #wierzchołki wielokątów\n",
"\n",
" pol1_3d=[VertFloat(list(map(lambda x: ObrotWY1(x,tt),pi1_3d))),['red','black']]\n",
" pol2_3d=[VertFloat(list(map(lambda x: ObrotWX1(x,tt),pi2_3d))),['blue','black']]\n",
" pol3_3d=[VertFloat(list(map(lambda x: ObrotWY0(x,-tt),pi3_3d))),['green','black']]\n",
" pol4_3d=[VertFloat(list(map(lambda x: ObrotWX0(x,-tt),pi4_3d))),['black','white']]\n",
"\n",
" #dodawanie figur\n",
" for verts in [pol1_3d,pol2_3d,pol3_3d,pol4_3d]:\n",
" ax.add_collection3d(Poly3DCollection(verts[0],facecolor =verts[1][0],edgecolor=verts[1][1]))\n",
" w1=[float(x) for x in ObrotWY1(pi1_3d[2],tt)]\n",
" w2=[float(x) for x in ObrotWY0(pi3_3d[2],-tt)] \n",
" ax.add_collection3d(Line3DCollection([[w1,w2]], colors='black',linewidth=3,linestyle='dashed'))\n",
" plt.show()\n",
"\n",
"interactive_plot = interactive(f, tt=(0, float(magiczny_kat),0.01),dist=(0,10,0.1),elev=(0,10,0.1),azim=(0,360,1))\n",
"output = interactive_plot.children[-1]\n",
"output.layout.height = '350px'\n",
"interactive_plot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}