{"id":18064307,"url":"https://github.com/maxbarsukov-itmo/functional-programming-3","last_synced_at":"2025-08-03T06:36:46.967Z","repository":{"id":259693959,"uuid":"879218140","full_name":"maxbarsukov-itmo/functional-programming-3","owner":"maxbarsukov-itmo","description":"🧪λ Функциональное программирование: Лабораторная работа №3","archived":false,"fork":false,"pushed_at":"2024-10-29T14:02:21.000Z","size":2689,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-02-11T10:26:11.459Z","etag":null,"topics":["command-line","computational-math","elixir","functional-programming","itmo","laboratory-work","maxbarsukov"],"latest_commit_sha":null,"homepage":"https://gitlab.se.ifmo.ru/functional-programming/main/-/blob/master/laboratory-course.md#%D0%BB%D0%B0%D0%B1%D0%BE%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D0%B0%D1%8F-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-3","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxbarsukov-itmo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-27T10:29:59.000Z","updated_at":"2024-10-29T14:03:00.000Z","dependencies_parsed_at":"2024-10-27T12:07:06.908Z","dependency_job_id":"af4656a5-3f61-470f-8db4-4dda9bd16b70","html_url":"https://github.com/maxbarsukov-itmo/functional-programming-3","commit_stats":null,"previous_names":["maxbarsukov-itmo/functional-programming-3"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxbarsukov-itmo%2Ffunctional-programming-3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxbarsukov-itmo%2Ffunctional-programming-3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxbarsukov-itmo%2Ffunctional-programming-3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxbarsukov-itmo%2Ffunctional-programming-3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxbarsukov-itmo","download_url":"https://codeload.github.com/maxbarsukov-itmo/functional-programming-3/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247345842,"owners_count":20924102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","computational-math","elixir","functional-programming","itmo","laboratory-work","maxbarsukov"],"created_at":"2024-10-31T06:05:26.799Z","updated_at":"2025-04-05T14:13:30.431Z","avatar_url":"https://github.com/maxbarsukov-itmo.png","language":"Elixir","readme":"# Лабораторная работа 3\n\n[![Elixir](https://github.com/maxbarsukov-itmo/functional-programming-3/actions/workflows/elixir.yml/badge.svg?branch=master)](https://github.com/maxbarsukov-itmo/functional-programming-3/actions/workflows/elixir.yml)\n[![Markdown](https://github.com/maxbarsukov-itmo/functional-programming-3/actions/workflows/markdown.yml/badge.svg?branch=master)](https://github.com/maxbarsukov-itmo/functional-programming-3/actions/workflows/markdown.yml)\n[![Coverage Status](https://coveralls.io/repos/github/maxbarsukov-itmo/functional-programming-3/badge.svg?branch=master)](https://coveralls.io/github/maxbarsukov-itmo/functional-programming-3?branch=master)\n\n\u003cimg alt=\"bumps\" src=\"./.resources/anime.gif\" height=\"280\"\u003e\n\n\u003e [!TIP]\n\u003e Ah shit, here we go again...\n\n---\n\n  * Студент: `Барсуков Максим Андреевич`\n  * Группа: `P3315`\n  * ИСУ: `367081`\n  * Функциональный язык: `Elixir`\n\n---\n\n## Описание работы\n\n**Цель**: получить навыки работы с *вводом/выводом*, *потоковой обработкой данных*, *командной строкой*.\n\nВ рамках лабораторной работы вам предлагается повторно реализовать лабораторную работу по предмету *«Вычислительная математика»*,посвящённую **интерполяции** (в разные годы это лабораторная работа 3 или 4) со следующими дополнениями:\n\n  * обязательно должна быть реализована **линейная интерполяция** ([отрезками](https://en.wikipedia.org/wiki/Linear_interpolation));\n  * настройки алгоритма интерполяции и выводимых данных должны задаваться через **аргументы командной строки**:\n    * какие **алгоритмы** использовать (в том числе два сразу);\n    * **частота дискретизации** результирующих данных;\n    * и т.п.;\n  * входные данные должны задаваться в **текстовом формате** на подобии `.csv` (к примеру `x;y\\n` или `x\\ty\\n`) и подаваться на **стандартный ввод**, входные данные должны быть отсортированы по возрастанию `x`;\n  * выходные данные должны подаваться на **стандартный вывод**;\n  * программа должна работать в **потоковом режиме** (пример -- `cat | grep 11`), это значит, что при запуске программы она должна ожидать получения данных на стандартный ввод, и, по мере получения достаточного количества данных, должна выводить рассчитанные точки в стандартный вывод;\n\n#### Архитектура\n\nПриложение должно быть организовано следующим образом:\n\n```text\n    +---------------------------+\n    | обработка входного потока |\n    +---------------------------+\n            |\n            | поток / список / последовательность точек\n            v\n    +-----------------------+      +------------------------------+\n    | алгоритм интерполяции |\u003c-----| генератор точек, для которых |\n    +-----------------------+      | необходимо вычислить         |\n            |                      | промежуточные значения       |\n            |                      +------------------------------+\n            |\n            | поток / список / последовательность рассчитанных точек\n            v\n    +------------------------+\n    | печать выходных данных |\n    +------------------------+\n```\n\n#### Потоковый режим\n\nПотоковый режим для алгоритмов, работающих с группой точек должен работать следующим образом:\n\n```text\no o o o o o . . x x x\n  x x x . . o . . x x x\n    x x x . . o . . x x x\n      x x x . . o . . x x x\n        x x x . . o . . x x x\n          x x x . . o . . x x x\n            x x x . . o o o o o o EOF\n```\n\nгде:\n\n  * **каждая строка -- окно данных**, на основании которых производится расчёт алгоритма;\n  * строки сменяются по мере поступления в систему новых данных (старые данные удаляются из окна, новые -- добавляются);\n  * `o` -- рассчитанные данные, можно видеть:\n    * большинство окон используется для расчёта всего одной точки, так как именно в \"центре\" результат наиболее точен;\n    * первое и последнее окно используются для расчёта большого количества точек, так лучших данных для расчёта у нас не будет.\n  * `.` -- точки, задействованные в рассчете значения o.\n  * `x` -- точки, расчёт которых для \"окон\" не требуется.\n\n#### Пример\n\nПример вычислений для шага `1.0` и функции `sin(x)`:\n\n```ocaml\nВвод первых двух точек (в данном примере X Y через пробел):\n0 0.00\n1.571 1\n\nВывод:\nЛинейная (идем от первой точки из введенных (0.00) с шагом 1, покрывая все введенные X (1.571 \u003c 2)):\n0.00    1.00    2.00\n0.00    0.64    1.27\n\nВвод третьей точки:\n3.142 0\n\nСледующий вывод:\nЛинейная (идем от второй точки из введенных (1.571) с шагом 1, покрывая все введенные X (3.142 \u003c 3.57)):\n1.57    2.57    3.57\n1.00    0.36    -0.27\n\nВвод четвертой точки:\n4.712 -1\n\nСледующий вывод:\nЛинейная (идем от третьей точки из введенных (3.142) с шагом 1, покрывая все введенные X (4.712 \u003c 5.14)):\n3.14    4.14    5.14\n0.00    -0.64   -1.27\n\nЛагранж (теперь количество введенных точек повзоляет его рассчитать, идем от первой точки (0.00) из введенных с шагом 1, покрывая все введенные X (4.712 \u003c 5)):\n0.00    1.00    2.00    3.00    4.00    5.00\n0.00    0.97    0.84    0.12    -0.67   -1.03\n\nИ т.д.\n```\n\nКак видно из примера выше, **окна для каждого метода двигаются по-разному**.\n\nДля *линейной* окно начало сдвигаться уже при вводе третьей точки (т.к. для вычисления нужно всего две), в то время как для *Лагранжа* окно начало двигаться только когда была введена пятая точка (т.к. здесь для вычислений нужно больше точек).\n\n## Требования\n\n**Общие требования**:\n\n  * программа должна быть реализована в функциональном стиле;\n  * ввод/вывод должен быть отделён от алгоритмов интерполяции;\n  * требуется использовать идиоматичный для технологии стиль программирования.\n\n**Содержание отчёта**:\n\n  * титульный лист;\n  * требования к разработанному ПО, включая описание алгоритма;\n  * ключевые элементы реализации с минимальными комментариями;\n  * ввод/вывод программы;\n  * выводы (отзыв об использованных приёмах программирования).\n\n**Общие рекомендации по реализации**. Не стоит писать большие и страшные автоматы, управляющие поведением приложения в целом. Если у вас:\n\n  * Язык с ленью -- используйте лень.\n  * Языки с параллельным программированием и акторами -- используйте их.\n  * Язык без всей этой прелести -- используйте генераторы/итераторы/и т.п.\n\n---\n\n## Выполнение\n\n### Архитектура приложения\n\n```text\n+---------------------------+\n|   Обработка конфигурации  |\n|   и аргументов программы  |\n+---------------------------+\n             |\n             | Конфигурация шага и точности\n             v\n+---------------------------+\n| Обработка входного потока |\u003c----+\n+---------------------------+     |\n             |                    |\n             +--------------------+\n             |\n             | Новая точка\n             v\n+---------------------------+\n|   Валидация новой точки   |\n+---------------------------+             +-----------------+\n|                           |\u003c------------| Генерация точек |\n|       Интерполяция        |             +-----------------+\n|                           |-----------+\n+---------------------------+  Метод 1  |\n             |        |-----------------+\n             |        |        Метод 2  |\n             |        |-----------------+\n             |        |        ...      |\n             |        |-----------------+\n             |\n             |\n             | Результаты вычислений\n             v\n+---------------------------+\n|  Печать выходных значений |\n+---------------------------+\n```\n\n### Ключевые элементы реализации\n\nЛинейная интерполяция:\n\n```elixir\ndefmodule InterpolationApp.Algo.LinearInterpolation do\n  use InterpolationApp.Algo.Interpolation\n\n  @impl true\n  def get_name, do: \"Линейная интерполяция\"\n\n  @impl true\n  def get_enough_points_count, do: 2\n\n  @impl true\n  def need_concrete_number_of_points?, do: true\n\n  @impl true\n  def interpolate(points, x) when not is_list(x) do\n    [{x0, y0}, {x1, y1}] = points\n\n    a = (y1 - y0) / (x1 - x0)\n    b = y0 - a * x0\n\n    {x, a * x + b}\n  end\nend\n```\n\nREPL:\n\n```elixir\ndefmodule InterpolationApp.CLI.Repl do\n  alias InterpolationApp.CLI.{Applier, Interpolator, Printer}\n\n  def start(config) do\n    IO.puts(\"Введите 'quit', чтобы закончить ввод.\")\n    IO.puts(\"Введите узлы интерполяции:\")\n\n    {:ok, printer_pid} = Printer.start_link(config)\n    {:ok, interpolator_pid} = Interpolator.start_link(config, printer_pid)\n    {:ok, applier_pid} = Applier.start_link(interpolator_pid)\n\n    loop(applier_pid)\n  end\n\n  defp loop(applier_pid) do\n    :io.setopts(:standard_io, active: true)\n    input = IO.gets(\"\") |\u003e check_quit\n\n    GenServer.cast(applier_pid, {:apply_input, String.trim(input)})\n    loop(applier_pid)\n  end\n\n  ...\nend\n```\n\nGenServer интерполяции:\n\n```elixir\ndefmodule InterpolationApp.CLI.Interpolator do\n  use GenServer\n\n  alias InterpolationApp.Utils.PointGenerator\n\n  # Client API\n\n  def start_link(config, printer_pid) do\n    GenServer.start_link(__MODULE__, {config, printer_pid}, name: __MODULE__)\n  end\n\n  def add_point(point) do\n    GenServer.cast(__MODULE__, {:add_point, point})\n  end\n\n  # Server Callbacks\n\n  @impl true\n  def init({config, printer_pid}) do\n    {:ok, {[], config, printer_pid}}\n  end\n\n  @impl true\n  def handle_cast({:add_point, point}, {points, config, printer_pid}) do\n    points = Enum.reverse([point | Enum.reverse(points)])\n\n    Enum.each(config.methods, fn method -\u003e\n      handle_method(method, points, printer_pid, config)\n    end)\n\n    {:noreply, {points, config, printer_pid}}\n  end\n\n  # Helper Functions\n\n  defp handle_method(method, points, printer_pid, config) do\n    if method.points_enough?(points) do\n      limit = method.get_enough_points_count()\n\n      interpolation_points =\n        if method.need_concrete_number_of_points?(),\n          do: Enum.slice(points, -limit, limit),\n          else: points\n\n      generated_points = PointGenerator.generate(interpolation_points, config.step)\n\n      GenServer.cast(printer_pid, {\n        :print,\n        method,\n        method.interpolate(interpolation_points, generated_points)\n      })\n    end\n\n    :ok\n  end\nend\n```\n\n### Как запустить?\n\n**1.** Склонировать репозиторий:\n\n```bash\ngit clone git@github.com:maxbarsukov-itmo/functional-programming-3.git\n```\n\n**2.** Установить зависимости:\n\n```bash\nmix deps.get\nmix deps.compile\n```\n\n**3.** Собрать `escript` — исполняемый файл, который может быть запущен на любой системе с установленным Erlang.:\n\n```bash\nmix escript.build\n```\n\n**4.** Линтинг:\n\n```bash\nmix check\n```\n\n**5.** Тестирование:\n\n```bash\nmix test --trace\n```\n\n**6.** Запустить приложение: `./out/interpolation-app`\n\nHelp message:\n\n```text\nusage: interpolation-app [options] --methods=\u003cmethod1,method2,...\u003e --step=\u003cstep\u003e\noptions:\n  -h, --help              Prints this message\n  --accuracy=\u003caccuracy\u003e   Set printing accuracy\n\nmethods:\n  * linear\n  * lagrange3\n  * lagrange4\n  * newton\n```\n\n### Пример работы программы\n\nДля значений из [data/sin_x.csv](./data/sinx.csv):\n\n```bash\ncat data/sinx.csv | ./out/interpolation-app --methods=linear,newton,lagrange4 --step=1 --accuracy=3\n```\n\n```ocaml\n❯ ./out/interpolation-app --methods=linear,newton,lagrange4 --step=1\nВведите 'quit', чтобы закончить ввод.\nВведите узлы интерполяции:\n0 0\n1.571 1\n\u003e\u003e Линейная интерполяция (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   \n0.000   0.637   1.273   \n\n\u003e\u003e Интерполяция по Ньютону (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   \n0.000   0.637   1.273   \n\n3.142 0\n\u003e\u003e Линейная интерполяция (идем от точки из введенных 1.571 с шагом 1.0, покрывая все введенные X)\n1.571   2.571   3.571   \n1.000   0.363   -0.273  \n\n\u003e\u003e Интерполяция по Ньютону (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   3.000   4.000   \n0.000   0.868   0.925   0.173   -1.391  \n\n4.712 -1\n\u003e\u003e Линейная интерполяция (идем от точки из введенных 3.142 с шагом 1.0, покрывая все введенные X)\n3.142   4.142   5.142   \n0.000   -0.637  -1.274  \n\n\u003e\u003e Интерполяция по Ньютону (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   3.000   4.000   5.000   \n0.000   0.973   0.841   0.120   -0.674  -1.026  \n\n\u003e\u003e Интерполяционный многочлен Лагранжа для 4 точек (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   3.000   4.000   5.000   \n0.000   0.973   0.841   0.120   -0.674  -1.026  \n\n12.568 0\n\u003e\u003e Линейная интерполяция (идем от точки из введенных 4.712 с шагом 1.0, покрывая все введенные X)\n4.712   5.712   6.712   7.712   8.712   9.712   10.712  11.712  12.712  \n-1.000  -0.873  -0.745  -0.618  -0.491  -0.364  -0.236  -0.109  0.018   \n\n\u003e\u003e Интерполяция по Ньютону (идем от точки из введенных 0.0 с шагом 1.0, покрывая все введенные X)\n0.000   1.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000   9.000   10.000  11.000  12.000  13.000  \n0.000   1.001   0.825   0.114   -0.637  -1.083  -1.031  -0.436  0.595   1.806   2.792   2.996   1.712   -1.916  \n\n\u003e\u003e Интерполяционный многочлен Лагранжа для 4 точек (идем от точки из введенных 1.571 с шагом 1.0, покрывая все введенные X)\n1.571   2.571   3.571   4.571   5.571   6.571   7.571   8.571   9.571   10.571  11.571  12.571  \n1.000   0.373   -0.280  -0.915  -1.486  -1.950  -2.262  -2.378  -2.254  -1.845  -1.107  0.004   \n\nquit\n\nСпасибо за использование программы!\n\n      |      _,,,---,,_\nZZZzz /,`.-'`'    -.  ;-;;,_\n    |,4-  ) )-,_. , (  `'-'\n    '---''(_/--'  `-'_)\n\n```\n\n### Форматирование, линтинг и тестирование\n\nВ рамках данной работы были применены инструменты:\n\n  * [ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html) - для модульного тестирования;\n  * [Quixir](https://github.com/pragdave/quixir) - для тестирования свойств (property-based).\n  * [Credo](https://github.com/rrrene/credo) - инструмент статического анализа кода для языка Elixir;\n  * [Dialyxir](https://github.com/jeremyjh/dialyxir) - Dialy~~zer~~xir is a **DI**screpancy **A**na**LY**zer for ~~**ER**lang~~ Eli**XIR** programs.\n\n---\n\n## Выводы\n\nВ ходе работы были разработаны и протестированы алгоритмы для различных методов интерполяции и вспомогательные утилиты. \n\nДостигнуты следующие результаты:\n\n  * С использованием параллелизма и серверов OTP была разработана утилита для асинхронного подсчёта интерполяции.\n  * Реализованы алгоритмы интерполяции (линейная, Лагранжа и Ньютона) с использованием подходов для работы с заданным количеством точек.\n  * Созданы утилиты для генерации промежуточных точек, проверки входных данных и конфигурации CLI.\n  * Подтверждена корректность работы модулей при различных входных данных, в том числе при случайных значениях (property-based тесты).\n\n---\n\n## Полезные ссылки\n\n| Ссылка | Описание |\n| --- | --- |\n| [github.com/maxbarsukov/itmo/4 вычмат/лабораторные/lab5](https://github.com/maxbarsukov/itmo/tree/master/4%20%D0%B2%D1%8B%D1%87%D0%BC%D0%B0%D1%82/%D0%BB%D0%B0%D0%B1%D0%BE%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D0%B5/lab5) | Вычмат: ЛР 5 по интерполяции функции |\n| [en.wikipedia.org/wiki/Interpolation](https://en.wikipedia.org/wiki/Interpolation) | Что такое интерполяция? |\n| [elixirschool.com/ru/lessons/intermediate/concurrency](https://elixirschool.com/ru/lessons/intermediate/concurrency) | Параллелизм в Elixir |\n| [elixirschool.com/ru/lessons/advanced/otp_concurrency](https://elixirschool.com/ru/lessons/advanced/otp_concurrency) | Параллелизм в OTP |\n| [habr.com/ru/articles/114232/](https://habr.com/ru/articles/114232/) | Erlang и его процессы |\n| [perso.ens-lyon.fr/laurent.modolo/unix/7_streams_and_pipes.html](https://perso.ens-lyon.fr/laurent.modolo/unix/7_streams_and_pipes.html) | Unix Streams and pipes |\n\n## Лицензия \u003ca name=\"license\"\u003e\u003c/a\u003e\n\nПроект доступен с открытым исходным кодом на условиях [Лицензии MIT](https://opensource.org/license/mit/). \\\n*Авторские права 2024 Max Barsukov*\n\n**Поставьте звезду :star:, если вы нашли этот проект полезным.**\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxbarsukov-itmo%2Ffunctional-programming-3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxbarsukov-itmo%2Ffunctional-programming-3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxbarsukov-itmo%2Ffunctional-programming-3/lists"}