Skip to content

Commit cd68606

Browse files
committed
feat: ✨ implement interpolation algorithms
1 parent 9a4a3a3 commit cd68606

File tree

5 files changed

+141
-10
lines changed

5 files changed

+141
-10
lines changed

lib/algo/interpolation.ex

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,25 @@ defmodule InterpolationApp.Algo.Interpolation do
1313
"""
1414
@callback interpolate(points :: [tuple()], target_points :: [number()]) :: [number()]
1515

16-
@callback points_enough?(points :: [tuple()]) :: boolean
16+
@callback get_name() :: binary()
17+
18+
@callback get_enough_points_count() :: number()
19+
20+
@callback need_concrete_number_of_points?() :: boolean()
21+
22+
@callback points_enough?(points :: [tuple()]) :: boolean()
23+
24+
defmacro __using__(_) do
25+
quote do
26+
@behaviour InterpolationApp.Algo.Interpolation
27+
28+
@impl true
29+
def points_enough?(points), do: length(points) >= get_enough_points_count()
30+
31+
@impl true
32+
def interpolate(points, xs) when is_list(xs) do
33+
Enum.map(xs, fn x -> interpolate(points, x) end)
34+
end
35+
end
36+
end
1737
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmodule InterpolationApp.Algo.Lagrange3Interpolation do
2+
@moduledoc """
3+
In numerical analysis, the Lagrange interpolating polynomial is the
4+
unique polynomial of lowest degree that interpolates a given set of data.
5+
"""
6+
7+
use InterpolationApp.Algo.Interpolation
8+
9+
@impl true
10+
def get_name, do: "Интерполяционный многочлен Лагранжа для 3 точек"
11+
12+
@impl true
13+
def get_enough_points_count, do: 3
14+
15+
@impl true
16+
def need_concrete_number_of_points?, do: true
17+
18+
@impl true
19+
def interpolate(points, x) when not is_list(x) do
20+
[{x0, y0}, {x1, y1}, {x2, y2}] = points
21+
22+
y =
23+
y0 * ((x - x1) * (x - x2)) / ((x0 - x1) * (x0 - x2)) +
24+
y1 * ((x - x0) * (x - x2)) / ((x1 - x0) * (x1 - x2)) +
25+
y2 * ((x - x0) * (x - x1)) / ((x2 - x0) * (x2 - x1))
26+
27+
{x, y}
28+
end
29+
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
defmodule InterpolationApp.Algo.Lagrange4Interpolation do
2+
@moduledoc """
3+
In numerical analysis, the Lagrange interpolating polynomial is the
4+
unique polynomial of lowest degree that interpolates a given set of data.
5+
"""
6+
7+
use InterpolationApp.Algo.Interpolation
8+
9+
@impl true
10+
def get_name, do: "Интерполяционный многочлен Лагранжа для 4 точек"
11+
12+
@impl true
13+
def get_enough_points_count, do: 4
14+
15+
@impl true
16+
def need_concrete_number_of_points?, do: true
17+
18+
@impl true
19+
def interpolate(points, x) when not is_list(x) do
20+
[{x0, y0}, {x1, y1}, {x2, y2}, {x3, y3}] = points
21+
22+
y =
23+
y0 * ((x - x1) * (x - x2) * (x - x3)) / ((x0 - x1) * (x0 - x2) * (x0 - x3)) +
24+
y1 * ((x - x0) * (x - x2) * (x - x3)) / ((x1 - x0) * (x1 - x2) * (x1 - x3)) +
25+
y2 * ((x - x0) * (x - x1) * (x - x3)) / ((x2 - x0) * (x2 - x1) * (x2 - x3)) +
26+
y3 * ((x - x0) * (x - x1) * (x - x2)) / ((x3 - x0) * (x3 - x1) * (x3 - x2))
27+
28+
{x, y}
29+
end
30+
end

lib/algo/linear_interpolation.ex

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,24 @@ defmodule InterpolationApp.Algo.LinearInterpolation do
44
new data points within the range of a discrete set of known data points.
55
"""
66

7-
@behaviour InterpolationApp.Algo.Interpolation
7+
use InterpolationApp.Algo.Interpolation
88

9+
@impl true
910
def get_name, do: "Линейная интерполяция"
1011

12+
@impl true
1113
def get_enough_points_count, do: 2
1214

1315
@impl true
14-
def points_enough?(points), do: length(points) >= get_enough_points_count()
16+
def need_concrete_number_of_points?, do: true
1517

1618
@impl true
17-
def interpolate(points, target_point) when not is_list(target_point) do
19+
def interpolate(points, x) when not is_list(x) do
1820
[{x0, y0}, {x1, y1}] = points
1921

2022
a = (y1 - y0) / (x1 - x0)
2123
b = y0 - a * x0
2224

23-
{target_point, a * target_point + b}
24-
end
25-
26-
@impl true
27-
def interpolate(points, xs) when is_list(xs) do
28-
Enum.map(xs, fn x -> interpolate(points, x) end)
25+
{x, a * x + b}
2926
end
3027
end

lib/algo/newton_interpolation.ex

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
defmodule InterpolationApp.Algo.NewtonInterpolation do
2+
@moduledoc """
3+
In the mathematical field of numerical analysis, a Newton polynomial, named after its inventor
4+
Isaac Newton, is an interpolation polynomial for a given set of data points.
5+
"""
6+
7+
use InterpolationApp.Algo.Interpolation
8+
9+
@impl true
10+
def get_name, do: "Интерполяция по Ньютону"
11+
12+
@impl true
13+
def get_enough_points_count, do: 2
14+
15+
@impl true
16+
def need_concrete_number_of_points?, do: false
17+
18+
@impl true
19+
def interpolate(points, x) when not is_list(x) do
20+
{x, points |> divided_differences |> evaluate_polynomial(points, x)}
21+
end
22+
23+
defp divided_differences(points) do
24+
n = length(points)
25+
xs = Enum.map(points, fn {x, _} -> x end)
26+
ys = Enum.map(points, fn {_, y} -> y end)
27+
28+
Enum.reduce(1..(n - 1), [ys], fn i, acc ->
29+
prev_diffs = hd(acc)
30+
31+
diffs =
32+
Enum.map(0..(n - i - 1), fn j ->
33+
(Enum.at(prev_diffs, j + 1) - Enum.at(prev_diffs, j)) /
34+
(Enum.at(xs, j + i) - Enum.at(xs, j))
35+
end)
36+
37+
[diffs | acc]
38+
end)
39+
|> Enum.reverse()
40+
|> Enum.map(&List.first/1)
41+
end
42+
43+
defp evaluate_polynomial(coeffs, points, x) do
44+
xs = Enum.map(points, fn {x, _} -> x end)
45+
46+
Enum.reduce(Enum.with_index(coeffs), 0, fn {coeff, i}, acc ->
47+
term =
48+
Enum.reduce(0..(i - 1), 1, fn j, prod ->
49+
prod * (x - Enum.at(xs, j))
50+
end)
51+
52+
acc + coeff * term
53+
end)
54+
end
55+
end

0 commit comments

Comments
 (0)