22using System . Collections ;
33using System . Globalization ;
44using System . IO . Compression ;
5- using System . Runtime . InteropServices ;
65using System . Text ;
76
87namespace MathCore . Interpolation ;
98
9+ /// <summary>Класс для линейной интерполяции многомерных данных</summary>
1010public 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 ) ;
0 commit comments