|
| 1 | +/++ |
| 2 | +$(H1 Interpolation Algorithms) |
| 3 | +
|
| 4 | +$(BOOKTABLE $(H2 Interpolation modules), |
| 5 | +$(TR $(TH Module) $(TH Interpolation kind)) |
| 6 | +$(T2M linear, Linear Interpolation) |
| 7 | +$(T2M pchip, Cubic Hermite Interpolation) |
| 8 | +) |
| 9 | +
|
| 10 | +Copyright: Copyright © 2017-, Ilya Yaroshenko |
| 11 | +Authors: Ilya Yaroshenko |
| 12 | +
|
| 13 | +Macros: |
| 14 | +SUBREF = $(REF_ALTTEXT $(TT $2), $2, mir, interpolation, $1)$(NBSP) |
| 15 | +T2M=$(TR $(TDNW $(MREF mir,interpolation,$1)) $(TD $+)) |
| 16 | +T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) |
| 17 | ++/ |
| 18 | +module mir.interpolation; |
| 19 | + |
| 20 | +import mir.primitives; |
| 21 | + |
| 22 | +/++ |
| 23 | +Lazy interpolation shell with linear complexity. |
| 24 | +
|
| 25 | +Params: |
| 26 | + range = sorted range |
| 27 | + interpolation = interpolation structure with `._grid` and `.opCall(x, interval)` methods. |
| 28 | +Complexity: |
| 29 | + `O(range.length + interpolation._grid.length)` to evaluate all elements. |
| 30 | +Returns: |
| 31 | + Lazy input range. |
| 32 | +See_also: |
| 33 | + $(SUBREF linear, linearInterpolation), |
| 34 | + $(SUBREF pchip, pchip). |
| 35 | ++/ |
| 36 | +auto interp1(Range, Interpolation)(Range range, Interpolation interpolation, size_t interval = 0) |
| 37 | +{ |
| 38 | + return Interp1!(Range, Interpolation)(range, interpolation, interval); |
| 39 | +} |
| 40 | + |
| 41 | +/// ditto |
| 42 | +struct Interp1(Range, Interpolation) |
| 43 | +{ |
| 44 | + /// Sorted range (descending) |
| 45 | + Range _range; |
| 46 | + /// Interpolation structure |
| 47 | + Interpolation _interpolation; |
| 48 | + /// Current interpolation interval |
| 49 | + size_t _interval; |
| 50 | + |
| 51 | + static if (hasLength!Range) |
| 52 | + /// Length (optional) |
| 53 | + size_t length() @property { return _range.length; } |
| 54 | + /// Input range primitives |
| 55 | + bool empty () @property { return _range.empty; } |
| 56 | + /// ditto |
| 57 | + void popFront() { _range.popFront; } |
| 58 | + /// ditto |
| 59 | + auto front() @property |
| 60 | + |
| 61 | + { |
| 62 | + assert(!empty); |
| 63 | + auto x = _range.front; |
| 64 | + while (x > _interpolation._grid[_interval + 1] && _interpolation._grid.length > _interval + 2) |
| 65 | + _interval++; |
| 66 | + return _interpolation(x, _interval); |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +/++ |
| 71 | +PCHIP interpolation. |
| 72 | +
|
| 73 | +Complexity: |
| 74 | + `O(x.length + xs.length)` |
| 75 | +
|
| 76 | +See_also: |
| 77 | + $(MREF mir,_interpolation,pchip) |
| 78 | ++/ |
| 79 | +unittest |
| 80 | +{ |
| 81 | + import std.math: approxEqual; |
| 82 | + import mir.interpolation: interp1; |
| 83 | + import mir.interpolation.pchip; |
| 84 | + |
| 85 | + auto x = [1.0, 2, 4, 5, 8, 10, 12, 15, 19, 22]; |
| 86 | + auto y = [17.0, 0, 16, 4, 10, 15, 19, 5, 18, 6]; |
| 87 | + auto interpolation = x.pchip(y); |
| 88 | + |
| 89 | + auto xs = x[0 .. $ - 1].dup; |
| 90 | + xs[] += 0.5; |
| 91 | + |
| 92 | + auto ys = xs.interp1(interpolation); |
| 93 | + |
| 94 | + import std.stdio; |
| 95 | + writeln(ys); |
| 96 | + |
| 97 | + assert(ys.approxEqual([ |
| 98 | + 5.333333333333334, |
| 99 | + 2.500000000000000, |
| 100 | + 10.000000000000000, |
| 101 | + 4.288971807628524, |
| 102 | + 11.202580845771145, |
| 103 | + 16.250000000000000, |
| 104 | + 17.962962962962962, |
| 105 | + 5.558593750000000, |
| 106 | + 17.604662698412699, |
| 107 | + ])); |
| 108 | + |
| 109 | +} |
| 110 | + |
| 111 | +unittest |
| 112 | +{ |
| 113 | + import mir.interpolation.linear; |
| 114 | + import mir.ndslice; |
| 115 | + import std.math: approxEqual; |
| 116 | + |
| 117 | + auto x = [0, 1, 2, 3, 5.00274, 7.00274, 10.0055, 20.0137, 30.0192]; |
| 118 | + auto y = [0.0011, 0.0011, 0.0030, 0.0064, 0.0144, 0.0207, 0.0261, 0.0329, 0.0356,]; |
| 119 | + auto xs = [1, 2, 3, 4.00274, 5.00274, 6.00274, 7.00274, 8.00548, 9.00548, 10.0055, 11.0055, 12.0082, 13.0082, 14.0082, 15.0082, 16.011, 17.011, 18.011, 19.011, 20.0137, 21.0137, 22.0137, 23.0137, 24.0164, 25.0164, 26.0164, 27.0164, 28.0192, 29.0192, 30.0192]; |
| 120 | + |
| 121 | + auto interpolation = linearInterpolation(x, y); |
| 122 | + |
| 123 | + auto data = [0.0011, 0.0030, 0.0064, 0.0104, 0.0144, 0.0176, 0.0207, 0.0225, 0.0243, 0.0261, 0.0268, 0.0274, 0.0281, 0.0288, 0.0295, 0.0302, 0.0309, 0.0316, 0.0322, 0.0329, 0.0332, 0.0335, 0.0337, 0.0340, 0.0342, 0.0345, 0.0348, 0.0350, 0.0353, 0.0356]; |
| 124 | + |
| 125 | + assert(approxEqual(xs.interp1(interpolation), data, 1e-4, 1e-4)); |
| 126 | +} |
0 commit comments