1- /+ +
1+ /+
22$(H2 Piecewise Cubic Hermite Interpolating Polynomial)
33
44See_also: $(REF_ALTTEXT $(TT interp1), interp1, mir, interpolate)
@@ -11,22 +11,25 @@ Macros:
1111SUBREF = $(REF_ALTTEXT $(TT $2), $2, mir, interpolate, $1)$(NBSP)
1212T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
1313+/
14+ deprecated (" The PCHIP API was changed, the new one looks like spline!double(xSlice, ySlice, SplineType.monotone)" )
1415module mir.interpolate.pchip ;
1516
1617public import mir.interpolate.spline: Spline;
17-
18- import std.traits ;
19- private alias AliasSeq (T ... ) = T ;
18+ import mir.interpolate;
19+ import mir.interpolate.spline ;
20+ import mir.math.common: fmamath ;
2021import mir.ndslice.slice;
2122import mir.primitives;
22- import mir.math.common: fmamath;
23- import mir.ndslice.internal: ConstIfPointer;
23+ import std.traits ;
24+
25+ private alias AliasSeq (T... ) = T;
2426
2527@fmamath:
2628
2729/+ +
2830Constructs piecewise cubic hermite interpolating polynomial with nodes on rectilinear grid.
2931+/
32+
3033template pchip (T, size_t N = 1 , FirstGridIterator = immutable (T)* , NextGridIterators = Repeat! (N - 1 , FirstGridIterator))
3134 if (isFloatingPoint! T && is (T == Unqual! T) && N <= 6 )
3235{
@@ -48,162 +51,6 @@ template pchip(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridItera
4851 GridVectors grid,
4952 Slice! (yIterator, N, ykind) values ) @safe
5053 {
51- static if (__VERSION__ >= 2085 ) import core.lifetime : move; else import std.algorithm.mutation : move;
52- auto ret = Spline! T(grid);
53- ret._values = values ;
54- pchipSlopes(grid, values , typeof (return ).pickDataSubslice(ret._data, 1 ));
55- return ret.move;
56- }
57- }
58-
59- // /
60- version (mir_test)
61- @safe unittest
62- {
63- import mir.math.common: approxEqual;
64- import mir.algorithm.iteration: all;
65- import mir.ndslice.allocation: slice;
66- import mir.ndslice.slice: sliced;
67- import mir.ndslice.topology: vmap;
68-
69- auto x = [1.0 , 2 , 4 , 5 , 8 , 10 , 12 , 15 , 19 , 22 ].idup.sliced;
70- auto y = [17.0 , 0 , 16 , 4 , 10 , 15 , 19 , 5 , 18 , 6 ].idup.sliced;
71- auto interpolant = pchip! double (x, y);
72-
73- auto xs = x[0 .. $ - 1 ] + 0.5 ;
74-
75- () @trusted {
76- auto ys = xs.vmap(interpolant);
77-
78- assert (ys.all! approxEqual([
79- 5.333333333333334 ,
80- 2.500000000000000 ,
81- 10.000000000000000 ,
82- 4.288971807628524 ,
83- 11.202580845771145 ,
84- 16.250000000000000 ,
85- 17.962962962962962 ,
86- 5.558593750000000 ,
87- 17.604662698412699 ,
88- ]));
89- }();
90- }
91-
92- // Check direction equality
93- version (mir_test)
94- @safe unittest
95- {
96- import mir.math.common: approxEqual;
97- import mir.ndslice.slice: sliced;
98- import mir.ndslice.allocation: slice;
99- import mir.ndslice.topology: retro, map;
100-
101- auto points = [1.0 , 2 , 4 , 5 , 8 , 10 , 12 , 15 , 19 , 22 ].idup.sliced;
102- auto values = [17.0 , 0 , 16 , 4 , 10 , 15 , 19 , 5 , 18 , 6 ].idup.sliced;
103-
104- auto results = [
105- 5.333333333333334 ,
106- 2.500000000000000 ,
107- 10.000000000000000 ,
108- 4.288971807628524 ,
109- 11.202580845771145 ,
110- 16.250000000000000 ,
111- 17.962962962962962 ,
112- 5.558593750000000 ,
113- 17.604662698412699 ,
114- ];
115- auto interpolant = pchip! double (points, values );
116-
117- auto pointsR = slice(- points.retro);
118- auto valuesR = values .retro.slice;
119- auto interpolantR = pchip! double (pointsR, valuesR);
120-
121- version (X86_64 )
122- assert (map! interpolant(points[0 .. $ - 1 ] + 0.5 ) == map! interpolantR(pointsR.retro[0 .. $ - 1 ] - 0.5 ));
123- }
124-
125-
126- /+ +
127- Computes slopes for piecewise spline hermite interpolating polynomial.
128- Params:
129- points = `x` values for interpolant
130- values = `f(x)` values for interpolant
131- slopes = uninitialized ndslice to write slopes into
132- Constraints:
133- `points`, `values`, and `slopes` must have the same length >= 3
134- +/
135- void pchipSlopes (IG , IV , IS , SliceKind gkind, SliceKind vkind, SliceKind skind)(
136- Slice! (IG , 1 , gkind) points,
137- Slice! (IV , 1 , vkind) values ,
138- Slice! (IS , 1 , skind) slopes) @trusted
139- {
140- if (points.length < 3 )
141- assert (0 );
142- if (points.length != values .length)
143- assert (0 );
144- if (points.length != slopes.length)
145- assert (0 );
146-
147- auto step0 = cast ()(points[1 ] - points[0 ]);
148- auto step1 = cast ()(points[2 ] - points[1 ]);
149- auto diff0 = cast ()(values [1 ] - values [0 ]);
150- auto diff1 = cast ()(values [2 ] - values [1 ]);
151- diff0 /= step0;
152- diff1 /= step1;
153-
154- slopes.front = pchipTail(step0, step1, diff0, diff1);
155- for (size_t i = 1 ;;)
156- {
157- import mir.math.common: copysign;
158- if (diff0 && diff1 && copysign(1f , diff0) == copysign(1f , diff1))
159- {
160- auto w0 = step1 * 2 + step0;
161- auto w1 = step0 * 2 + step1;
162- slopes[i] = (w0 + w1) / (w0 / diff0 + w1 / diff1);
163- }
164- else
165- {
166- slopes[i] = 0 ;
167- }
168- if (++ i == slopes.length - 1 )
169- {
170- break ;
171- }
172- step0 = step1;
173- diff0 = diff1;
174- step1 = points[i + 1 ] - points[i + 0 ];
175- diff1 = values [i + 1 ] - values [i + 0 ];
176- diff1 /= step1;
177- }
178- slopes.back = pchipTail(step1, step0, diff1, diff0);
179- }
180-
181- auto pchipTail (T)(in T step0, in T step1, in T diff0, in T diff1)
182- {
183- import mir.math.common: copysign, fabs;
184- if (! diff0)
185- {
186- return 0 ;
187- }
188- auto slope = ((step0 * 2 + step1) * diff0 - step0 * diff1) / (step0 + step1);
189- if (copysign(1f , slope) != copysign(1f , diff0))
190- {
191- return 0 ;
192- }
193- if ((copysign(1f , diff0) != copysign(1f , diff1)) && (fabs(slope) > fabs(diff0 * 3 )))
194- {
195- return diff0 * 3 ;
196- }
197- return slope;
198- }
199-
200- template Repeat (ulong n, L... )
201- {
202- static if (n)
203- {
204- import std.meta : Repeat;
205- alias Repeat = std.meta.Repeat ! (n, L);
54+ return spline! T(grid, values , SplineType.monotone);
20655 }
207- else
208- alias Repeat = L[0 .. 0 ];
20956}
0 commit comments