Skip to content

Commit bd586e4

Browse files
committed
v0.0.93.1 - Мелкие исправления в многомерном интерполяторе
1 parent 9ed1765 commit bd586e4

File tree

6 files changed

+166
-73
lines changed

6 files changed

+166
-73
lines changed

.github/copilot-instructions.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Всегда отвечай мне используя русский язык.
2+
Всегда пиши комментарии в коде на русском языке.
3+
Комментарии к классам, структурам делегатам и перечислениям, а также к их членам всегда пиши в системном виде.
4+
При написании комментариев (ели они короткие) в коде предпочитай размещение комментария в конце той же строке, что и сам комментируемый код.
5+
Старайся избегать тривиальных комментариев.
6+
При герерации кода старайся минимизировать количество фигурных скобок.
7+
При генерации кода используй самые современные виды синтаксических конструкций языка.
8+
Всегда старайся минимизировтаь размер кода если не запрошено иное.
9+
Используй стиль именования локальных переменных snake_case.
10+
Используй стиль именования входных переменных методов PascalCase.
11+
Используй стиль именования полей классов _PascalCase для нестатических переменных и __PascalCase для статических переменных.
12+
Ппредпочитай английский язык при именовании переменных, методов, классов и прочих сущностей.
13+
При инициализации массивов, списков и словарей используй выражения инициализации массивов.
14+
При объявлении переменных предпочитай использовать ключевое слово var.
15+
При написании системных комментариев старайся писать их компактно в одну строку, если длина текста небольшая.

MathCore.sln

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Service", ".Service", "{B1
1616
BuildAndPublish.bat = BuildAndPublish.bat
1717
BuildAndTest.bat = BuildAndTest.bat
1818
BuildRelease.bat = BuildRelease.bat
19+
.github\copilot-instructions.md = .github\copilot-instructions.md
1920
Directory.Build.props = Directory.Build.props
21+
.github\workflows\publish.yml = .github\workflows\publish.yml
22+
.github\workflows\testing.yml = .github\workflows\testing.yml
2023
EndProjectSection
2124
EndProject
2225
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Tests\Benchmarks\Benchmarks.csproj", "{80108823-1EA4-46AC-B365-8B0F9CE59CC6}"
@@ -25,6 +28,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MathCore.Algorithms", "Test
2528
EndProject
2629
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MathCore.Tests.WPF", "Tests\MathCore.Tests.WPF\MathCore.Tests.WPF.csproj", "{2DDA14D6-76EE-4D0A-B9DE-638778395934}"
2730
EndProject
31+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{386742AE-F590-4AA4-8395-53877DC1799F}"
32+
ProjectSection(SolutionItems) = preProject
33+
.github\copilot-instructions.md = .github\copilot-instructions.md
34+
EndProjectSection
35+
EndProject
36+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{DC32AE4E-B09F-4746-BDC2-2168F61E5454}"
37+
ProjectSection(SolutionItems) = preProject
38+
.github\workflows\publish.yml = .github\workflows\publish.yml
39+
.github\workflows\testing.yml = .github\workflows\testing.yml
40+
EndProjectSection
41+
EndProject
2842
Global
2943
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3044
Debug|Any CPU = Debug|Any CPU
@@ -33,14 +47,6 @@ Global
3347
Release|x64 = Release|x64
3448
EndGlobalSection
3549
GlobalSection(ProjectConfigurationPlatforms) = postSolution
36-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|Any CPU.Build.0 = Debug|Any CPU
38-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|x64.ActiveCfg = Debug|Any CPU
39-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|x64.Build.0 = Debug|Any CPU
40-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|Any CPU.ActiveCfg = Release|Any CPU
41-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|Any CPU.Build.0 = Release|Any CPU
42-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|x64.ActiveCfg = Release|Any CPU
43-
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|x64.Build.0 = Release|Any CPU
4450
{AFA60C84-107F-4582-8EED-2273957E89C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4551
{AFA60C84-107F-4582-8EED-2273957E89C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
4652
{AFA60C84-107F-4582-8EED-2273957E89C5}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -81,16 +87,26 @@ Global
8187
{2B8FF1EE-42E8-4961-A734-1068F008D7D1}.Release|Any CPU.Build.0 = Release|Any CPU
8288
{2B8FF1EE-42E8-4961-A734-1068F008D7D1}.Release|x64.ActiveCfg = Release|Any CPU
8389
{2B8FF1EE-42E8-4961-A734-1068F008D7D1}.Release|x64.Build.0 = Release|Any CPU
90+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
91+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|Any CPU.Build.0 = Debug|Any CPU
92+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|x64.ActiveCfg = Debug|Any CPU
93+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Debug|x64.Build.0 = Debug|Any CPU
94+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|Any CPU.ActiveCfg = Release|Any CPU
95+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|Any CPU.Build.0 = Release|Any CPU
96+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|x64.ActiveCfg = Release|Any CPU
97+
{2DDA14D6-76EE-4D0A-B9DE-638778395934}.Release|x64.Build.0 = Release|Any CPU
8498
EndGlobalSection
8599
GlobalSection(SolutionProperties) = preSolution
86100
HideSolutionNode = FALSE
87101
EndGlobalSection
88102
GlobalSection(NestedProjects) = preSolution
89103
{25AFB0DF-BCC9-45CA-AA0D-CB76AC5F906D} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
90-
{2DDA14D6-76EE-4D0A-B9DE-638778395934} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
91104
{744E4BA2-2EA7-4AD5-B732-47230ED0A3F1} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
92105
{80108823-1EA4-46AC-B365-8B0F9CE59CC6} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
93106
{2B8FF1EE-42E8-4961-A734-1068F008D7D1} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
107+
{2DDA14D6-76EE-4D0A-B9DE-638778395934} = {3B53E842-750F-4865-97C0-1703CDDE4C9F}
108+
{386742AE-F590-4AA4-8395-53877DC1799F} = {B1568FA3-D7EB-4AC6-8208-7F6095E14ED6}
109+
{DC32AE4E-B09F-4746-BDC2-2168F61E5454} = {386742AE-F590-4AA4-8395-53877DC1799F}
94110
EndGlobalSection
95111
GlobalSection(ExtensibilityGlobals) = postSolution
96112
SolutionGuid = {5C46D916-D8DA-4B92-A70C-6EE0C6B01CAD}

MathCore/Interpolation/InterpolatorNDLinear.cs

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22
using System.Collections;
33
using System.Globalization;
44
using System.IO.Compression;
5-
using System.Runtime.InteropServices;
65
using System.Text;
76

87
namespace MathCore.Interpolation;
98

9+
/// <summary>Класс для линейной интерполяции многомерных данных</summary>
1010
public class InterpolatorNDLinear
1111
{
12+
/// <summary>Загрузить интерполятор из CSV файла</summary>
13+
/// <param name="FilePath">Путь к файлу</param>
14+
/// <param name="Header">Присутствует ли заголовок</param>
15+
/// <param name="Separator">Символ-разделитель</param>
16+
/// <param name="SkipWrongLines">Пропускать ли некорректные строки</param>
17+
/// <param name="ValueSelector">Функция для выбора значений</param>
18+
/// <returns>Экземпляр <see cref="InterpolatorNDLinear"/></returns>
1219
public static InterpolatorNDLinear LoadCSV(
1320
string FilePath,
1421
bool Header = true,
@@ -17,6 +24,13 @@ public static InterpolatorNDLinear LoadCSV(
1724
Func<double[], double, bool>? ValueSelector = null)
1825
=> LoadCSV(new FileInfo(FilePath), Header, Separator, SkipWrongLines, ValueSelector);
1926

27+
/// <summary>Загрузить интерполятор из CSV файла</summary>
28+
/// <param name="file">Файл</param>
29+
/// <param name="Header">Присутствует ли заголовок</param>
30+
/// <param name="Separator">Символ-разделитель</param>
31+
/// <param name="SkipWrongLines">Пропускать ли некорректные строки</param>
32+
/// <param name="ValueSelector">Функция для выбора значений</param>
33+
/// <returns>Экземпляр <see cref="InterpolatorNDLinear"/></returns>
2034
public static InterpolatorNDLinear LoadCSV(
2135
FileInfo file,
2236
bool Header = true,
@@ -51,6 +65,13 @@ public static InterpolatorNDLinear LoadCSV(
5165
return LoadCSV(reader, Header, Separator, SkipWrongLines, ValueSelector);
5266
}
5367

68+
/// <summary>Загрузить интерполятор из CSV файла</summary>
69+
/// <param name="reader">Читатель текстовых данных</param>
70+
/// <param name="Header">Присутствует ли заголовок</param>
71+
/// <param name="Separator">Символ-разделитель</param>
72+
/// <param name="SkipWrongLines">Пропускать ли некорректные строки</param>
73+
/// <param name="ValueSelector">Функция для выбора значений</param>
74+
/// <returns>Экземпляр <see cref="InterpolatorNDLinear"/></returns>
5475
public static InterpolatorNDLinear LoadCSV(
5576
TextReader reader,
5677
bool Header = true,
@@ -103,11 +124,7 @@ public static InterpolatorNDLinear LoadCSV(
103124
}
104125

105126
if (i < arguments_count)
106-
{
107-
args[i] = v;
108-
109-
i++;
110-
}
127+
args[i++] = v;
111128
else
112129
{
113130
value = v;
@@ -133,7 +150,6 @@ public static InterpolatorNDLinear LoadCSV(
133150
for (var i = 0; i < values_list.Count; i++)
134151
{
135152
var argument = arguments_list[i];
136-
137153
var value = values_list[i];
138154

139155
ValueTreeNode.Add(nodes, argument, value);
@@ -145,12 +161,19 @@ public static InterpolatorNDLinear LoadCSV(
145161
private readonly int _ArgumentsCount;
146162
private readonly List<ValueTreeNode> _Nodes;
147163

164+
/// <summary>Внутренний класс для представления узла дерева значений</summary>
148165
private class ValueTreeNode(double Value, List<ValueTreeNode>? Childs = null) :
149166
IComparable<ValueTreeNode>, IComparable<double>,
150167
IEnumerable<ValueTreeNode>
151168
{
169+
/// <summary>Индексатор для доступа к дочерним узлам</summary>
170+
/// <param name="ChildIndex">Индекс дочернего узла</param>
152171
public ValueTreeNode? this[int ChildIndex] => Childs?[ChildIndex];
153172

173+
/// <summary>Добавить узел в дерево значений</summary>
174+
/// <param name="nodes">Список узлов</param>
175+
/// <param name="args">Аргументы</param>
176+
/// <param name="value">Значение</param>
154177
public static void Add(List<ValueTreeNode> nodes, ArrayPtr<double> args, double value)
155178
{
156179
if (nodes is []) // если в списке нет узлов (пока ещё...)
@@ -172,52 +195,52 @@ public static void Add(List<ValueTreeNode> nodes, ArrayPtr<double> args, double
172195
var index = nodes.SearchBinaryValue(head_arg);
173196

174197
if (index >= 0)
198+
nodes[index].Add(tail_args, value);
199+
else if (tail_args.Length > 0)
175200
{
176-
var node = nodes[index];
201+
var node = new ValueTreeNode(head_arg, []);
202+
nodes.Insert(~index, node);
177203
node.Add(tail_args, value);
178204
}
179205
else
180-
{
181-
var ind = ~index;
182-
183-
if (tail_args.Length > 0)
184-
{
185-
var node = new ValueTreeNode(head_arg, []);
186-
nodes.Insert(ind, node);
187-
node.Add(tail_args, value);
188-
}
189-
else
190-
{
191-
nodes.Insert(ind, new ValueTreeNode(head_arg, [new(value)]));
192-
}
193-
}
206+
nodes.Insert(~index, new(head_arg, [new(value)]));
194207
}
195208

209+
/// <summary>Значение узла</summary>
196210
public double Value { get; } = Value;
197211

212+
/// <summary>Добавить узел в дерево значений</summary>
213+
/// <param name="args">Аргументы</param>
214+
/// <param name="value">Значение</param>
198215
private void Add(ArrayPtr<double> args, double value) => Add(Childs, args, value);
199216

217+
/// <summary>Получить значение по аргументам</summary>
218+
/// <param name="args">Аргументы</param>
219+
/// <returns>Значение</returns>
200220
public double GetValue(ArrayPtr<double> args)
201221
{
202-
if (args.Length == 0)
203-
return Childs[0].Value;
222+
var childs = Childs;
223+
if (args.Length == 0 || childs is null)
224+
return childs?[0].Value ?? double.NaN;
204225

205226
var (x, xx) = args;
206227

207-
var index = Childs.SearchBinaryValue(x);
228+
var index = childs.SearchBinaryValue(x);
208229

209230
if (index >= 0)
210-
return Childs[index].GetValue(xx);
231+
return childs[index].GetValue(xx);
211232

212233
var i1 = Math.Max(0, ~index - 1);
213-
var i2 = i1 + 1;
234+
var i2 = Math.Min(childs.Count - 1, i1 + 1);
214235

215-
var node1 = Childs[i1];
216-
var node2 = Childs[i2];
236+
var node1 = childs[i1];
237+
var node2 = childs[i2];
217238

218239
var a = node1.Value;
219240
var b = node2.Value;
220241

242+
if (a == b) return node1.GetValue(xx);
243+
221244
var kx = (x - a) / (b - a);
222245

223246
var y1 = node1.GetValue(xx);
@@ -227,6 +250,8 @@ public double GetValue(ArrayPtr<double> args)
227250
return y;
228251
}
229252

253+
/// <summary>Преобразовать узел в строку</summary>
254+
/// <returns>Строковое представление узла</returns>
230255
public override string ToString()
231256
{
232257
var result = new StringBuilder().Append(Value);
@@ -251,46 +276,66 @@ public override string ToString()
251276
return result.ToString();
252277
}
253278

279+
/// <summary>Сравнить узел с другим узлом</summary>
280+
/// <param name="other">Другой узел</param>
281+
/// <returns>Результат сравнения</returns>
254282
public int CompareTo(ValueTreeNode? other) => Value.CompareTo(other.NotNull().Value);
283+
284+
/// <summary>Сравнить узел с числом</summary>
285+
/// <param name="other">Число</param>
286+
/// <returns>Результат сравнения</returns>
255287
public int CompareTo(double other) => Value.CompareTo(other);
256288

257289
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
258290

291+
/// <summary>Получить перечислитель для дочерних узлов</summary>
292+
/// <returns>Перечислитель</returns>
259293
public IEnumerator<ValueTreeNode> GetEnumerator() => Childs.GetEnumerator();
260294

261295
public static implicit operator ValueTreeNode(double value) => new(value);
262296
public static implicit operator double(ValueTreeNode node) => node.Value;
263297
}
264298

299+
/// <summary>Индексатор для получения значения по аргументам</summary>
300+
/// <param name="args">Аргументы</param>
265301
public double this[params double[] args] => GetValue(args);
266302

303+
/// <summary>Конструктор интерполятора</summary>
304+
/// <param name="ArgumentsCount">Количество аргументов</param>
305+
/// <param name="nodes">Список узлов</param>
267306
private InterpolatorNDLinear(int ArgumentsCount, List<ValueTreeNode> nodes)
268307
{
269308
_ArgumentsCount = ArgumentsCount;
270309
_Nodes = nodes;
271310
}
272311

312+
/// <summary>Получить значение по аргументам</summary>
313+
/// <param name="arguments">Аргументы</param>
314+
/// <returns>Значение</returns>
273315
public double GetValue(params double[] arguments)
274316
{
275317
if (arguments.Length != _ArgumentsCount)
276318
throw new ArgumentException($"Передано аргументов {arguments.Length}, а требуется {_ArgumentsCount}");
277319

278320
var (x, xx) = arguments.ToArrayPtr();
279321

280-
var index = _Nodes.SearchBinaryValue(x);
322+
var nodes = _Nodes;
323+
var index = nodes.SearchBinaryValue(x);
281324

282325
if (index >= 0)
283-
return _Nodes[index].GetValue(xx);
326+
return nodes[index].GetValue(xx);
284327

285328
var i1 = Math.Max(0, ~index - 1);
286-
var i2 = i1 + 1;
329+
var i2 = Math.Min(nodes.Count - 1, i1 + 1);
287330

288-
var node1 = _Nodes[i1];
289-
var node2 = _Nodes[i2];
331+
var node1 = nodes[i1];
332+
var node2 = nodes[i2];
290333

291334
var a = node1.Value;
292335
var b = node2.Value;
293336

337+
if (a == b) return node1.GetValue(xx);
338+
294339
var kx = (x - a) / (b - a);
295340

296341
var y1 = node1.GetValue(xx);

MathCore/MathCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</PropertyGroup>
1212

1313
<PropertyGroup>
14-
<Version>0.0.93</Version>
14+
<Version>0.0.93.1</Version>
1515
<PackageReleaseNotes>
1616
Добавлен многомерный линейный интерполятор на основе дерева
1717
</PackageReleaseNotes>

0 commit comments

Comments
 (0)