{"id":309190,"date":"2020-08-29T21:00:31","date_gmt":"2020-08-29T21:00:31","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=309190"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=309190","title":{"rendered":"\u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u043d\u0430 \u0431\u0430\u0437\u0435 Jupyter"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/517056\/\">Jupyter \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u0437\u0430\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u044f\u0445 \u043d\u0430 \u0441\u0442\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445. \u0412\u043e\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0447\u0435\u043d\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f <a href=\"https:\/\/jakevdp.github.io\/PythonDataScienceHandbook\/index.html\" rel=\"nofollow\">\u043a\u043d\u0438\u0433\u0430<\/a> \u043f\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 Jupyter \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u0432. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cc7\/fd2\/e2e\/cc7fd2e2e2cf8a1b7f087eef109a6780.svg\" alt=\"$\\TeX$\" data-tex=\"inline\"><\/math>, markdown, html \u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Jupyter \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0443\u0447\u043d\u043e\u0433\u043e-\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430. \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u0432 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0442\u044c \u0441\u0443\u0445\u043e\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u044d\u0442\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432 Jupyter \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0438 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043d\u0438\u0445 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u043a\u0431\u0435\u0439\u0442\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0414\u0435\u0439\u043a\u0441\u0442\u0440\u044b.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cf\/8b\/yz\/cf8byzvgriyvc1cu-ttmpc4iotu.gif\"><br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h3>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h3>\n<p>  \u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u0441\u0442\u0430\u0442\u044c\u0435, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u043e\u0442 \u0432 <a href=\"https:\/\/github.com\/Malkovsky\/python-examples\/blob\/master\/overview.ipynb\" rel=\"nofollow\">\u044d\u0442\u043e\u043c \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0435<\/a>, \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u0441\u043f\u0440\u044f\u0442\u0430\u043d \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u0430\u043c\u0438 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043a\u043e\u0434\u0430 \u0438 gif \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e. \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u044d\u0442\u043e\u0442 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0443\u0442\u0438\u043b\u0438\u0442\u044b.<\/p>\n<h3>\u0427\u0435\u043c \u0430\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u043c<\/h3>\n<p>  \u041f\u043e\u0434 Jupyter \u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 (<a href=\"https:\/\/ipywidgets.readthedocs.io\/en\/latest\/user_guide.html\" rel=\"nofollow\">ipywidgets<\/a>), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044f \u0441 \u043c\u043e\u0434\u0443\u043b\u0435\u043c IPython.display \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u043c\u0438, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0430:<\/p>\n<pre><code class=\"python\">from ipywidgets import interact, interactive, fixed, interact_manual import ipywidgets as widgets from IPython.display import display   def step_slice(lst, step):     return lst[step]   def animate_list(lst, play=False, interval=200):     slider = widgets.IntSlider(min=0, max=len(lst) - 1, step=1, value=0)     if play:         play_widjet = widgets.Play(interval=interval)         widgets.jslink((play_widjet, 'value'), (slider, 'value'))         display(play_widjet)         # slider = widgets.Box([play_widject, slider])     return interact(step_slice,                     lst=fixed(lst),                     step=slider) <\/code><\/pre>\n<p>  \u0412\u043e\u0442 \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 animate_list \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u0446\u0435\u043b\u044b\u0445 \u0447\u0438\u0441\u0435\u043b:<\/p>\n<pre><code class=\"python\">a = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] animate_list(a, play=True, interval=200); <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dj\/nc\/9o\/djnc9owit3qlvs2fieog86rnrfo.gif\"><\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e animate_list \u043d\u0443\u0436\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u0445 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435.<\/p>\n<h3>\u0422\u0435\u043a\u0442\u043e\u0432\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438<\/h3>\n<p>  \u0411\u0430\u0437\u043e\u0432\u044b\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044f\u043c\u0438\/\u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f. \u0423 \u043c\u0435\u043d\u044f \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0442\u0440\u043e\u043a\u0438, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b IPython.display.Code. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from IPython.display import Code import random  def qsort_state(array, left, right, x, p, q):     extended_array = list(map(str, array[:left])) + ['['] + list(map(str, array[left: right])) + [']'] + list(map(str, array[right:]))     offset_x = sum(list(map(len, extended_array[:left]))) + left + 2     zero_line = ''.join([' ' for i in range(offset_x)]) + f'x = {x}'     first_line = ' '.join(extended_array)     offset_p = sum(list(map(len, extended_array[:p + 1]))) + p + 1 + len(extended_array[p + 1]) \/\/ 2     offset_q = sum(list(map(len, extended_array[:q + 1]))) + q + 1 + len(extended_array[q + 1]) \/\/ 2     second_line = ''.join([' ' if i != offset_p and i != offset_q else '\u2191' for i in range(len(first_line))])      return Code(zero_line + '\\n' + first_line + '\\n' + second_line)  def qsort(array, left, right, states):     if right - left &lt;= 1:         return     x = array[random.randint(left, right - 1)]     p = left     q = right - 1     states.append(qsort_state(array, left, right, x, p, q))     while p &lt;= q:         while array[p] &lt; x:             p += 1             states.append(qsort_state(array, left, right, x, p, q))         while array[q] &gt; x:             q -= 1             states.append(qsort_state(array, left, right, x, p, q))         if p &lt;= q:             array[p], array[q] = (array[q], array[p])             states.append(qsort_state(array, left, right, x, p, q))             p += 1             q -= 1             if p &lt;= q:                 states.append(qsort_state(array, left, right, x, p, q))     qsort(array, left, q + 1, states)     qsort(array, p, right, states)   <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"python\">a = [234, 1, 42, 3, 15, 3, 10, 9, 2] states = [] qsort(a, 0, len(a), states) animate_list(states, play=True); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/-e\/kh\/uo\/-ekhuo_dk_mqz3ylutzfmuw6tf0.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u0445\u043e\u0436\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def bs_state(array, left, right, x):     extended_array = list(map(str, array[:left])) + ['['] + list(map(str, array[left: right])) + [']'] + list(map(str, array[right:]))      mid = (left + right) \/\/ 2     offset_x = sum(list(map(len, extended_array[:mid + 1]))) + mid + 1     return Code(' '.join(extended_array) + '\\n' + ''.join([' ' for i in range(offset_x)]) + str(x))  # \u042d\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 # \u043c\u0435\u043d\u044c\u0448\u0435 \u0438\u043b\u0438 \u0440\u0430\u0432\u0435\u043d \u0438\u0441\u043a\u043e\u043c\u043e\u0433\u043e states = [] left = 0 right = len(a) x = 14 while right - left &gt; 1:     states.append(bs_state(a, left, right, x))     mid = (left + right) \/\/ 2     if a[mid] &lt;= x:         left = mid     else:         right = mid states.append(bs_state(a, left, right, x))  animate_list(states, play=True, interval=400); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/fr\/tv\/3d\/frtv3dzmngnha3g8fmxwc4xcwku.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u0410 \u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a: \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0444\u0438\u043a\u0441-\u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def prefix_function_state(s, p, k, intermidiate=False):     third_string = ''.join([s[i] if i &lt; k else ' ' for i in range(len(p))])     fourth_string = ''.join([s[i] if i &gt;= len(p) - k else ' ' for i in range(len(p))])     return Code(s + '\\n' + ''.join(list(map(str, (p + ['*'] if intermidiate else p )))) \\                   + '\\n' + third_string + '\\n' + fourth_string)  def prefix_function(s, states):     p = [0]     k = 0     states.append(prefix_function_state(s, p, k))     for letter in s[1:]:         states.append(prefix_function_state(s, p, k, True))         while k &gt; 0 and s[k] != letter:             k = p[k - 1]             states.append(prefix_function_state(s, p, k, True))         if s[k] == letter:             k += 1         p.append(k)         states.append(prefix_function_state(s, p, k))     return p  states = [] p = prefix_function('ababadababa', states) animate_list(states, play=True); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zc\/gh\/7b\/zcgh7borvj_ykj7r6ro42jha__q.gif\">  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h3>\u0412\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Matplotlib<\/h3>\n<p>  Matplotlib \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Python \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432. \u0412\u043e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0435\u0451 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u0432 \u043d\u0435\u0433\u043e \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043d\u043e\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043b\u0443\u0447\u0448\u0435:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import numpy as np import matplotlib.pyplot as plt  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c, \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0432 \u0442\u043e\u0447\u043a\u0435 (0, 0) def f(x, y):     return 1.3 * (x - y) ** 2 + 0.7 * (x + y) ** 2  # \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0442\u0440\u0430\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438 \u043b\u0438\u043d\u0438\u0439 \u0443\u0440\u043e\u0432\u043d\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 def plot_trajectory(func, traj, limit_point=None):     fig = plt.figure(figsize=(7, 7))     ax = fig.add_axes([0, 0, 1, 1])              if limit_point:         ax.plot([limit_point[0]], [limit_point[1]], 'o', color='green')     #Level contours     delta = 0.025     x = np.arange(-2, 2, delta)     y = np.arange(-2, 2, delta)     X, Y = np.meshgrid(x, y)     Z = np.zeros_like(X)     for i in range(X.shape[0]):         for j in range(X.shape[1]):             Z[i][j] = func(X[i][j], Y[i][j])     CS = ax.contour(X, Y, Z, [0.5, 1.5, 3], colors=['blue', 'purple', 'red'])     ax.plot([u[0] for u in traj], [u[1] for u in traj], color='black')     ax.plot([u[0] for u in traj], [u[1] for u in traj], 'o', color='black')          plt.close(fig)     return fig  x, y = (1.0, 1.0) num_iters = 50 trajectory = [(x, y)] plots = [] # \u0418\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0443\u0442\u044c \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435 for i in range(num_iters):     angle = 2 * np.pi * np.random.rand(1)     dx, dy = (np.cos(angle) \/ 2 \/ (i + 1) ** 0.5, np.sin(angle) \/ 2 \/ (i + 1) ** 0.5)     trajectory.append((x + dx, y + dy))     plots.append(plot_trajectory(f, trajectory, limit_point=(0, 0)))     if f(x, y) &gt; f(x + dx, y + dy):         x = x + dx         y = y + dy     else:         trajectory = trajectory[:-1]  animate_list(plots, play=True, interval=300); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6w\/8g\/2l\/6w8g2lriemj6imy74ziy3hmjrew.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u0410 \u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u0415\u041c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437\u0432\u0435\u0440\u0436\u0435\u043d\u0438\u0439 Old Faithful \u0433\u0435\u0439\u0437\u0435\u0440\u0430, \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043d\u0430 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Expectation%E2%80%93maximization_algorithm\" rel=\"nofollow\">\u0432\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u0438<\/a>:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># \u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0437\u0434\u0435\u0441\u044c # http:\/\/www.stat.cmu.edu\/~larry\/all-of-statistics\/=data\/faithful.dat data = [] with open('data\/faithful.csv') as f:     for line in f:         _, x, y = line.split(',')         try:             data.append((float(x), float(y)))         except ValueError:             pass  colors = ['red', 'blue', 'yellow', 'green']  # \u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0437\u044f\u0442\u043e https:\/\/jakevdp.github.io\/PythonDataScienceHandbook\/05.12-gaussian-mixtures.html from matplotlib.patches import Ellipse  def draw_ellipse(position, covariance, ax=None, **kwargs):     &quot;&quot;&quot;Draw an ellipse with a given position and covariance&quot;&quot;&quot;     ax = ax or plt.gca()          # Convert covariance to principal axes     if covariance.shape == (2, 2):         U, s, Vt = np.linalg.svd(covariance)         angle = np.degrees(np.arctan2(U[1, 0], U[0, 0]))         width, height = 2 * np.sqrt(s)     else:         angle = 0         width, height = 2 * np.sqrt(covariance)          # Draw the Ellipse     for nsig in range(1, 4):         ax.add_patch(Ellipse(position, nsig * width, nsig * height,                              angle, color='red', **kwargs))          def plot_gmm(gmm, X, label=True, ax=None):     ax = ax or plt.gca()     if label:         labels = gmm.predict(X)         ax.scatter(X[:, 0], X[:, 1], c=labels, s=20, cmap='plasma', zorder=2)     else:         ax.scatter(X[:, 0], X[:, 1], s=20, zorder=2)          w_factor = 0.2 \/ gmm.weights_.max()     for pos, covar, w in zip(gmm.means_, gmm.covariances_, gmm.weights_):         draw_ellipse(pos, covar, alpha=w * w_factor)          def step_figure(gmm, X, label=True):     fig = plt.figure(figsize=(7, 7))     ax = fig.add_axes([0, 0, 1, 1])     ax.set_ylim(30, 100)     ax.set_xlim(1, 6)     plot_gmm(gmm, X, label=True, ax=ax)     plt.close(fig)     return fig  from sklearn.mixture import GaussianMixture  x = np.array(data) # max_iters=1 \u0438 warm_start=True \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 gmm.fit \u0434\u0435\u043b\u0430\u0442\u044c \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u043d\u0443 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044e # \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 gmm = GaussianMixture(2, warm_start=True, init_params='random', max_iter=1) # GMM \u0432\u044b\u0434\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043e\u0434\u043d\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u043c\u0430\u043b\u043e import warnings  warnings.simplefilter('ignore') # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043e\u0440\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 gmm.fit(x[:10,:]) steps = [step_figure(gmm, x)]    for i in range(17):     gmm.fit(x)     steps.append(step_figure(gmm, x))  animate_list(steps, play=True, interval=400); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hm\/ym\/ho\/hmymhoxhyvgxbqmftin1ckqwxyq.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043a\u043e\u0440\u0435\u0435 \u0438\u0433\u0440\u0443\u0448\u0435\u0447\u043d\u044b\u0439, \u043d\u043e \u0442\u043e\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 matplotlib: \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u0430\u043c\u043e\u0449\u0435\u043d\u0438\u044f \u043a\u043b\u0435\u0442\u0447\u0430\u0442\u043e\u0439 \u0444\u0438\u0433\u0443\u0440\u044b \u043d\u0430 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0447\u0438\u0441\u043b\u043e\u043c \u0434\u043e\u043c\u0438\u043d\u043e\u0448\u0435\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># \u041e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 matplotlib \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u044b \u0440\u0430\u0437\u043d\u044b\u0445 \u0446\u0432\u0435\u0442\u043e\u0432 from animation_utils.matplotlib import draw_filling  def check_valid(i, j, n, m, tiling):     return 0 &lt;= i and i &lt; n and 0 &lt;= j and j &lt; m and tiling[i][j] != '#'  def find_augmenting_path(x, y, n, m, visited, matched, tiling):     if not check_valid(x, y, n, m, tiling):         return False     if (x, y) in visited:         return False     visited.add((x, y))          for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:         if not check_valid(x + dx, y + dy, n, m, tiling):             continue         if (x + dx, y + dy) not in matched or find_augmenting_path(*matched[(x + dx , y + dy)], n, m, visited, matched, tiling):             matched[(x + dx, y + dy)] = (x, y)             return True     return False  def convert_match(matched, tiling, n, m):     result = [[-1 if tiling[i][j] == '#' else -2 for j in range(m)] for i in range(n)]     num = 0     for x, y in matched:         _x, _y = matched[(x, y)]         result[x][y] = num         result[_x][_y] = num         num += 1     return result  def match_with_flow(tiling):     result_slices = []     n = len(tiling)     m = len(tiling[0])          matched = dict()     # \u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438     rows = list(range(n))     columns = list(range(m))     random.shuffle(rows)     random.shuffle(columns)     result_slices.append(convert_match(matched, tiling, n, m))                  for i in rows:         for j in columns:             if (i + j) % 2 == 1:                 continue             visited = set()             if find_augmenting_path(i, j, n, m, visited, matched, tiling):                 result_slices.append(convert_match(matched, tiling, n, m))                  return result_slices  tiling_custom=[     '...####',     '....###',     '......#',     '#.#....',     '#......',     '##.....',     '###...#', ] sequencial_match = match_with_flow(tiling_custom) animate_list(list(map(draw_filling, sequencial_match)), play=True); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ws\/da\/dk\/wsdadkbcungwolucpahblg8zx8c.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041d\u0443 \u0438 \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0440\u0430\u0441\u043a\u0440\u0430\u0441\u043a\u0438 \u043f\u043b\u0430\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430 \u0432 5 \u0446\u0432\u0435\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u043b\u043e\u0441\u044c \u043b\u0443\u0447\u0448\u0435:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def color_5(filling):     result = [[i for i in row] for row in filling]     # \u0421\u0442\u0440\u043e\u0438\u043c \u0433\u0440\u0430\u0444     domino_tiles = [[] for i in range(max(map(max, filling)) + 1)]     domino_neighbours = [set() for i in range(max(map(max, filling)) + 1)]     degree = [0 for i in range(max(map(max, filling)) + 1)]          n = len(filling)     m = len(filling[0])          for i, row in enumerate(filling):         for j, num in enumerate(row):             if num &gt;= 0:                 domino_tiles[num].append((i, j))                      for i, tiles in enumerate(domino_tiles):         for x, y in tiles:             for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]:                 a, b = x + dx, y + dy                 if 0 &lt;= a and a &lt; n and 0 &lt;= b and b &lt; m and filling[a][b] &gt;= 0 and filling[a][b] != i \\                         and filling[a][b] not in domino_neighbours[i]:                     domino_neighbours[i].add(filling[a][b])                     degree[i] += 1          # \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0432\u0435\u0440\u0448\u0438\u043d, \u0432\u0441\u0435 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u0438\u043c\u0435\u043b\u0438 \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 5 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0441\u0440\u0435\u0434\u0438     # \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445. \u0422\u0430\u043a\u043e\u0439 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0441\u0438\u043b\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0433\u0440\u0430\u0444 \u043f\u043b\u0430\u043d\u0430\u0440\u043d\u044b\u0439, \u0430 \u043d\u0430\u0439\u0442\u0438 \u0435\u0433\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e     # \u043f\u043e \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043d\u0430\u0445\u043e\u0434\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u0443 \u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448\u0435\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0438 \u0443\u0434\u0430\u043b\u044f\u044f \u0435\u0451 \u0438\u0437 \u0433\u0440\u0430\u0444\u0430, \u0442\u0430\u043a \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a     active_degrees = [set() for i in range(max(degree) + 1)]     for i, deg in enumerate(degree):         active_degrees[deg].add(i)          reversed_order = []          for step in range(len(domino_tiles)):         min_degree = min([i for i, dominoes in enumerate(active_degrees) if len(dominoes) &gt; 0])         domino = active_degrees[min_degree].pop()                  reversed_order.append(domino)         for other in domino_neighbours[domino]:             if other in active_degrees[degree[other]]:                 active_degrees[degree[other]].remove(other)                 degree[other] -= 1                 active_degrees[degree[other]].add(other)                              # \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0438 \u043b\u0438\u0431\u043e \u043a\u0440\u0430\u0441\u0438\u043c \u0432 \u0435\u0449\u0435 \u043d\u0435 \u0437\u0430\u043d\u044f\u0442\u044b\u0439 \u0446\u0432\u0435\u0442,     # \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u0438\u0437 5 \u0446\u0432\u0435\u0442\u043e\u0432, \u0438\u043d\u0430\u0447\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0438\u0437 \u0447\u0435\u0440\u0435\u0434\u0443\u044e\u0449\u0438\u0445\u0441\u044f \u0446\u0432\u0435\u0442\u043e\u0432,     # \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043a\u0440\u0430\u0448\u0435\u043d\u044b. \u0422\u0430\u043a\u0430\u044f \u043d\u0430\u0439\u0434\u0435\u0442\u0441\u044f \u0432 \u0441\u0438\u043b\u0443 \u043f\u043b\u0430\u043d\u0430\u0440\u043d\u043e\u0441\u0442\u0438     colors = [-1 for domino in domino_tiles]     slices = [draw_filling(result)]     for domino in reversed(reversed_order):         used_colors = [colors[other] for other in domino_neighbours[domino] if colors[other] != -1]                  domino_color = len(used_colors)         for i, color in enumerate(sorted(set(used_colors))):             if i != color:                 domino_color = i                 break               if domino_color &lt; 5:             colors[domino] = domino_color             for x, y in domino_tiles[domino]:                 result[x][y] = domino_color                              slices.append(draw_filling(result))                     continue                     # \u041d\u0430\u0447\u0438\u043d\u0430\u044f \u043e\u0442\u0441\u044e\u0434\u0430 \u043a\u043e\u0434 \u044f \u043d\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b, \u043d\u0435 \u043d\u0430\u0448\u0435\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u0430                 c = 0         other = [other for other in domino_neighbours[domino] if colors[other] == c]         visited = set([other])         q = Queue()         q.put(other)         domino_was_reached = False         while not q.empty():             cur = q.get()             for other in domino_neighbours[cur]:                 if other == domino:                     domino_was_reached = True                     break                 if color[other] == c or color[other] == c + 1 and other not in visited:                     visited.add(other)                     q.put(other)                              if not domino_was_reached:             for other in visited:                 color[other] = color[other] ^ 1                 for x, y in domino_tiles[other]:                     result[x][y] = color[other]             color[domino] = c             for x, y in domino_tiles[domino]:                 result[x][y] = c                              slices.append(draw_filling(result))             continue                      # \u041f\u0440\u043e\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0434\u043b\u044f 2 \u0438 3.         c = 2         other = [other for other in domino_neighbours[domino] if colors[other] == c]         visited = set([other])         q = Queue()         q.put(other)         domino_was_reached = False         while not q.empty():             cur = q.get()             for other in domino_neighbours[cur]:                 if other == domino:                     domino_was_reached = True                     break                 if color[other] == c or color[other] == c + 1 and other not in visited:                     visited.add(other)                     q.put(other)         for other in visited:             color[other] = color[other] ^ 1             for x, y in domino_tiles[other]:                 result[x][y] = color[other]         color[domino] = c         for x, y in domino_tiles[domino]:             result[x][y] = c         slices.append(draw_filling(result))                          return result, slices  filling_colored, slices =color_5(sequencial_match[-1]) animate_list(slices, play=True); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/r8\/ub\/eg\/r8ubegou0gahowqqsyglacfsdze.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441 matplotlib \u0438\u0437 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438 \u2014 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0413\u0440\u044d\u0445\u044d\u043c\u0430-\u042d\u043d\u0434\u0440\u044e \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0432\u044b\u043f\u0443\u043a\u043b\u043e\u0439 \u043e\u0431\u043e\u043b\u043e\u0447\u043a\u0438 \u043d\u0430 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def convex_hull_state(points, lower_path, upper_path):     fig = plt.figure(figsize=(6, 6))     ax = fig.add_axes([0, 0, 1, 1])          ax.get_xaxis().set_visible(False)     ax.get_yaxis().set_visible(False)      for name, spine in ax.spines.items():         spine.set_visible(False)         spine.set_visible(False)          ax.scatter([x for x, y in points], [y for x, y in points])     ax.plot([x for x, _ in lower_path], [y for _, y in lower_path], color='red')     ax.plot([x for x, _ in upper_path], [y for _, y in upper_path], color='blue')          plt.close(fig)     return fig  def vector_prod(point_a, point_b):     return point_a[0] *  point_b[1] - point_a[1] * point_b[0]  def convex_hull(poitns):     sorted_points = sorted(points, key=lambda x: x[1])     sorted_points = sorted(sorted_points, key=lambda x: x[0])     states = []          upper_path = [sorted_points[0]]     lower_path = [sorted_points[0]]     states.append(convex_hull_state(points, lower_path, upper_path))          for point in sorted_points[1:]:         while len(upper_path) &gt; 1 and vector_prod(point - upper_path[-1], upper_path[-1] - upper_path[-2]) &gt; 0:             upper_path = upper_path[:-1]             upper_path.append(point)             states.append(convex_hull_state(poitns, lower_path, upper_path))             upper_path = upper_path[:-1]         upper_path.append(point)         states.append(convex_hull_state(points, lower_path, upper_path))              for point in sorted_points[1:]:         while len(lower_path) &gt; 1 and vector_prod(point - lower_path[-1], lower_path[-1] - lower_path[-2]) &lt; 0:             lower_path = lower_path[:-1]             lower_path.append(point)             states.append(convex_hull_state(poitns, lower_path, upper_path))             lower_path = lower_path[:-1]         lower_path.append(point)         states.append(convex_hull_state(poitns, lower_path, upper_path))          return states  points = [np.random.rand(2) for i in range(20)] states = convex_hull(points) animate_list(states, play=True, interval=300); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pl\/nf\/ul\/plnful3lcaatrwn40t8ocewyt8g.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u0447\u0442\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 matplotlib \u2014 \u044d\u0442\u043e \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 matplotlib.animation.FuncAnimation. \u0423 \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u043b\u044e\u0441\u044b: \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 html \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e IPython.display.HTML, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c, \u0447\u0435\u043c \u043d\u0430 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445 (\u0443 \u043c\u0435\u043d\u044f \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0442\u043e\u0440\u043e\u043c\u043e\u0437\u044f\u0442), \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u044f\u0434\u0440\u0430 Jupyter, \u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0441\u0442\u043e\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0432\u0438\u0434\u0435\u043e \u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<h3>Graphviz<\/h3>\n<p>  \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e graphviz \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u044b. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c graphviz \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 python, \u043d\u043e \u0438 \u0432 <a href=\"https:\/\/graphviz.org\/download\/\" rel=\"nofollow\">\u0441\u0438\u0441\u0442\u0435\u043c\u0443<\/a>. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u0431\u0445\u043e\u0434\u0430 \u0432 \u0433\u043b\u0443\u0431\u0438\u043d\u0443:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># \u041e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0433\u0440\u0430\u0444\u0430\u043c\u0438 from graph_utils.graph import Graph, Arc, Node  def enter_node(node):     node.SetColor('blue')      def enter_arc(node, arc):     node.SetColor('green')     arc.attributes['style'] = 'dashed'     arc.attributes['color'] = 'green'      def return_from_arc(node, arc):     arc.attributes['style'] = 'solid'     arc.attributes['color'] = 'red'     node.SetColor('blue')      def ignore_arc(arc):     arc.attributes['color'] = 'blue'      def leave_node(node):     node.SetColor('red')      def dfs(graph, node_id, visited, outlist, path):     visited.add(node_id)     path.append(node_id)     enter_node(graph.nodes[node_id])     outlist.append(graph.Visualize())     for arc in graph.nodes[node_id].arcs:         if arc.end not in visited:             enter_arc(graph.nodes[node_id], arc)             dfs(graph, arc.end, visited, outlist, path)              return_from_arc(graph.nodes[node_id], arc)             path.append(node_id)         else:             ignore_arc(arc)         outlist.append(graph.Visualize())           leave_node(graph.nodes[node_id])  arcs = [     Arc(1, 3, 3),     Arc(1, 4, 7),     Arc(4, 3, 2),     Arc(4, 5, 3),     Arc(1, 5, 2),     Arc(6, 4, 2),     Arc(5, 6, 2),     Arc(6, 7, 1),     Arc(7, 2, 7),     Arc(4, 2, 2),     Arc(3, 2, 5) ]  # \u0415\u0441\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0432\u044b\u0434\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0447\u0442\u043e \u0435\u043c\u0443 \u043d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c `dot`, \u0442\u043e # \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c graphviz # https:\/\/graphviz.org\/download\/ graph = Graph(arcs) visited = set() dfs_outlist = [] path = [] dfs_outlist.append(graph.Visualize()) dfs(graph, 1, visited, dfs_outlist, path) dfs_outlist.append(graph.Visualize()) animate_list(dfs_outlist, play=True, interval=400); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hx\/r0\/od\/hxr0odwz5k6x6k1k8-_bw6qcp_4.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041d\u0443 \u0430 \u0432\u043e\u0442 \u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0414\u0435\u0439\u043a\u0441\u0442\u0440\u044b \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def mark_labelled(node):     node.SetColor('red')      def mark_scanned(node):     node.SetColor('green')      def process_node(node):     node.SetColor('blue')      def set_previous(arc):     arc.SetColor('green')      def unset_previous(arc):     arc.SetColor('black')  def scan_arc(graph, arc, l, p, mark):     if l[arc.end] &gt; l[arc.beginning] + arc.weight:         l[arc.end] = l[arc.beginning] + arc.weight         if p[arc.end] is not None:             unset_previous(p[arc.end])         # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c arc, \u0430 \u043d\u0435 arc.beginning, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438         p[arc.end] = arc         set_previous(p[arc.end])         mark[arc.end] = True         mark_labelled(graph.nodes[arc.end])  def scan_node(graph, node_id, l, p, mark):     for arc in graph.nodes[node_id].arcs:         scan_arc(graph, arc, l, p, mark)     mark[node_id] = False     mark_scanned(graph.nodes[node_id])                # \u042d\u0442\u043e \u043d\u0435 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0414\u0435\u0439\u043a\u0441\u0442\u0440\u044b, \u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f # \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0442\u0443\u0442 # http:\/\/forskning.diku.dk\/PATH05\/GoldbergSlides.pdf def base_scanning_method(graph, s, choice_function):     l    = {key: float('Inf') for key in graph.nodes.keys()}     p    = {key: None for key in graph.nodes.keys()}     mark = {key: False for key in graph.nodes.keys()}          l[s] = 0     mark[s] = True     mark_labelled(graph.nodes[s])          out_lst = []          while True:         node_id = choice_function(l, mark)         if node_id is None:             break         process_node(graph.nodes[node_id])         out_lst.append(graph.Visualize(l))         scan_node(graph, node_id, l, p, mark)         out_lst.append(graph.Visualize(l))     return l, p, out_lst  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0432 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0435 \u0414\u0435\u0439\u043a\u0441\u0442\u0440\u044b def least_distance_choice(l, mark):     labelled = [node_id for node_id, value in mark.items() if value == True]     if len(labelled) == 0:         return None     return min(labelled, key=lambda x: l[x])   graph = Graph(arcs) l, p, bfs_shortest_path_lst = \\     base_scanning_method(graph, 1, least_distance_choice) animate_list(bfs_shortest_path_lst, play=True, interval=400); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cf\/8b\/yz\/cf8byzvgriyvc1cu-ttmpc4iotu.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u0410 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u043e\u0433\u043e \u0434\u0435\u0440\u0435\u0432\u0430 \u0434\u043b\u044f \u0441\u043b\u043e\u0432 &#8216;\u043c\u0430\u043c\u0430&#8217;, &#8216;\u043c\u0430\u0442\u044c&#8217;, &#8216;\u043c\u0430\u0440\u0442\u044b\u0448\u043a\u0430&#8217;, &#8216;\u043c\u044b\u043b\u0430&#8217;, &#8216;\u043c\u043e\u043b\u043e\u043a\u043e&#8217;:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">class TrieNode:     def __init__(self, parent, word=None):         # \u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u043e\u0447\u0435\u043d\u044c \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e         # \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043b\u0435\u043d\u0438\u0432\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u043d\u044b\u0445 \u0441\u0441\u044b\u043b\u043e\u043a         self.parent = parent         # \u0417\u0434\u0435\u0441\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e         self.word = word         self.children = {}         self.suff_link = None  def init_trie():     trie = [TrieNode(-1)]     return trie  def to_graph(trie):     arcs = []     for i, node in enumerate(trie):         for c, nextstate in node.children.items():             arcs.append(Arc(i, nextstate, c))         if node.suff_link is not None and node.suff_link != 0:             arcs.append(Arc(i,                              node.suff_link,                              attributes={&quot;constraint&quot; : &quot;False&quot;, &quot;style&quot; : &quot;dashed&quot;}))                  return Graph(arcs)  def add_word(trie, word, steps):     _num = 0     for ch in word:         if not ch in trie[_num].children:             _n = len(trie)             trie[_num].children[ch] = _n             trie.append(TrieNode((_num, ch)))         _num = trie[_num].children[ch]         graph = to_graph(trie)         graph.nodes[_num].SetColor('red')         steps.append(graph.Visualize())     trie[_num].word = word      def make_trie(words):     steps = []     trie = init_trie()     steps.append(to_graph(trie).Visualize())     for word in words:         add_word(trie, word, steps)         steps.append(to_graph(trie).Visualize())     return trie, steps  words = [     '\u043c\u0430\u043c\u0430',     '\u043c\u0430\u0442\u044c',     '\u043c\u0430\u0440\u0442\u044b\u0448\u043a\u0430',     '\u043c\u044b\u043b\u0430',     '\u043c\u043e\u043b\u043e\u043a\u043e' ] trie, steps = make_trie(words) animate_list(steps, play=True, interval=500); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/u0\/9h\/wq\/u09hwq3vihlg8_l56a8-2qimyya.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041d\u0443 \u0438 \u043d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u041a\u0443\u043d\u0430 \u0434\u043b\u044f \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def mark_for_delete(arc):     arc.SetColor('red')     arc.SetStyle('dashed')      def mark_for_add(arc):     arc.SetColor('blue')      def clear(arc):     arc.SetColor('black')     arc.SetStyle('solid')          def find_augmenting_path(graph, node_id, visited, match, deleted):     if node_id in visited:         return False     visited.add(node_id)     for arc in graph.nodes[node_id].arcs:         if arc.end not in match or find_augmenting_path(graph, match[arc.end].beginning, visited, match, deleted):             if arc.end in match:                 mark_for_delete(match[arc.end])                 deleted.append(match[arc.end])             match[arc.end] = arc             mark_for_add(arc)             return True     return False  def kuhns_matching(graph, first_part):     states = [graph.Visualize()]     match = dict()     for node_id in first_part:         node = graph.nodes[node_id]         node.SetColor('Blue')         states.append(graph.Visualize())         deleted = []         if find_augmenting_path(graph, node_id, set(), match, deleted):             states.append(graph.Visualize())             for arc in deleted:                 clear(arc)             states.append(graph.Visualize())         node.SetColor('red')     states.append(graph.Visualize())     return states  arcs = [     Arc(1, 6),     Arc(1, 7),     Arc(2, 6),     Arc(3, 7),     Arc(3, 8),     Arc(4, 8),     Arc(4, 9),     Arc(4, 10),     Arc(5, 10),     Arc(2, 8) ] first_part = [1, 2, 3, 4, 5] graph = Graph(arcs) states = kuhns_matching(graph, first_part)  animate_list(states, play=True, interval=400); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yd\/yt\/58\/ydyt58frtdxw4mj860glie03eeo.gif\">  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h3>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0441 \u043c\u0430\u0442\u0440\u0438\u0446\u0430\u043c\u0438<\/h3>\n<p>  \u0410 \u0432\u043e\u0442 \u044d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u043d\u0435\u0443\u0434\u0430\u0432\u0448\u0435\u0439\u0441\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0435. IPython.display \u0443\u043c\u0435\u0435\u0442 \u043f\u0430\u0440\u0441\u0438\u0442\u044c latex, \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0442 \u0447\u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c (\u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u0431\u044b\u0442\u044c \u043c\u0435\u0442\u043e\u0434 \u0413\u0430\u0443\u0441\u0441\u0430):<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from animation_utils.latex import Matrix from IPython.display import Math  n = 5 A = np.random.rand(n, n) L = np.identity(n) U = np.array(A) steps = [] steps.append(Math(str(Matrix(L)) + str(Matrix(U)))) for k in range(n):     x = U[k,k]     for i in range(k+1, n):         L[i,k] = U[i,k] \/ x         U[i,k:] -= L[i,k] * U[k,k:]     steps.append(Math(str(Matrix(L)) + str(Matrix(U))))  animate_list(steps, play=True, interval=500); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xl\/uj\/xx\/xlujxxpmi9mrd0k9aksxiijwuew.gif\">  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u043a\u0430 \u044f \u043d\u0435 \u0437\u043d\u0430\u044e, \u0447\u0442\u043e \u0441 \u044d\u0442\u0438\u043c \u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u043d\u0430\u044e\u0449\u0438\u0435 \u043b\u044e\u0434\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0443\u0442.<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/517056\/\"> https:\/\/habr.com\/ru\/post\/517056\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/517056\/\">Jupyter \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u0437\u0430\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u044f\u0445 \u043d\u0430 \u0441\u0442\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445. \u0412\u043e\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0447\u0435\u043d\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f <a href=\"https:\/\/jakevdp.github.io\/PythonDataScienceHandbook\/index.html\" rel=\"nofollow\">\u043a\u043d\u0438\u0433\u0430<\/a> \u043f\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 Jupyter \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u0432. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cc7\/fd2\/e2e\/cc7fd2e2e2cf8a1b7f087eef109a6780.svg\" alt=\"$\\TeX$\" data-tex=\"inline\"><\/math>, markdown, html \u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Jupyter \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0443\u0447\u043d\u043e\u0433\u043e-\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430. \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u0432 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0442\u044c \u0441\u0443\u0445\u043e\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u044d\u0442\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432 Jupyter \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0438 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043d\u0438\u0445 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u043a\u0431\u0435\u0439\u0442\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0414\u0435\u0439\u043a\u0441\u0442\u0440\u044b.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cf\/8b\/yz\/cf8byzvgriyvc1cu-ttmpc4iotu.gif\">  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-309190","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/309190","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=309190"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/309190\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=309190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=309190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=309190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}