1 /++ 2 $(H2 Constant Interpolation) 3 4 See_also: $(REF_ALTTEXT $(TT interp1), interp1, mir, interpolate) 5 6 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0) 7 Copyright: 2020 Ilya Yaroshenko, Kaleidic Associates Advisory Limited, Symmetry Investments 8 Authors: Ilya Yaroshenko 9 10 Macros: 11 SUBREF = $(REF_ALTTEXT $(TT $2), $2, mir, interpolate, $1)$(NBSP) 12 T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) 13 +/ 14 module mir.interpolate.constant; 15 16 @optmath: 17 18 /// 19 version(mir_test) 20 @safe pure @nogc unittest 21 { 22 import mir.ndslice; 23 import mir.math.common: approxEqual; 24 25 static immutable x = [0, 1, 2, 3]; 26 static immutable y = [10, 20, 30, 40]; 27 28 auto interpolant = constant!int(x.rcslice, y.rcslice!(const int)); 29 30 assert(interpolant(-1) == 10); 31 assert(interpolant(0) == 10); 32 assert(interpolant(0.5) == 10); 33 34 assert(interpolant(1) == 20); 35 36 assert(interpolant(3) == 40); 37 assert(interpolant(4) == 40); 38 } 39 40 41 import core.lifetime: move; 42 import mir.internal.utility; 43 import mir.functional; 44 import mir.interpolate; 45 import mir.math.common: optmath; 46 import mir.ndslice.slice; 47 import mir.primitives; 48 import mir.rc.array; 49 import mir.utility: min, max; 50 import std.meta: AliasSeq, staticMap; 51 import std.traits; 52 public import mir.interpolate: atInterval; 53 54 /++ 55 Constructs multivariate constant interpolant with nodes on rectilinear grid. 56 57 Params: 58 grid = `x` values for interpolant 59 values = `f(x)` values for interpolant 60 61 Constraints: 62 `grid`, `values` must have the same length >= 1 63 64 Returns: $(LREF Constant) 65 +/ 66 Constant!(F, N, X) constant(F, size_t N = 1, X = F) 67 (Repeat!(N, Slice!(RCI!(immutable X))) grid, Slice!(RCI!(const F), N) values) 68 { 69 return typeof(return)(forward!grid, values.move); 70 } 71 72 /++ 73 Multivariate constant interpolant with nodes on rectilinear grid. 74 +/ 75 struct Constant(F, size_t N = 1, X = F) 76 if (N && N <= 6) 77 { 78 @optmath: 79 80 /// Aligned buffer allocated with `mir.internal.memory`. $(RED For internal use.) 81 Slice!(RCI!(const F), N) _data; 82 /// Grid iterators. $(RED For internal use.) 83 Repeat!(N, RCI!(immutable X)) _grid; 84 85 extern(D): 86 87 /++ 88 +/ 89 this(Repeat!(N, Slice!(RCI!(immutable X))) grid, Slice!(RCI!(const F), N) data) @safe @nogc 90 { 91 enum msg_min = "constant interpolant: minimal allowed length for the grid equals 1."; 92 enum msg_eq = "constant interpolant: X and Y values length should be equal."; 93 version(D_Exceptions) 94 { 95 static immutable exc_min = new Exception(msg_min); 96 static immutable exc_eq = new Exception(msg_eq); 97 } 98 foreach(i, ref x; grid) 99 { 100 if (x.length < 1) 101 { 102 version(D_Exceptions) throw exc_min; 103 else assert(0, msg_min); 104 } 105 if (x.length != data._lengths[i]) 106 { 107 version(D_Exceptions) throw exc_eq; 108 else assert(0, msg_eq); 109 } 110 _grid[i] = x._iterator; 111 } 112 _data = data; 113 } 114 115 @trusted: 116 117 /// 118 Constant lightConst()() const @property { return *cast(Constant*)&this; } 119 120 /// 121 Slice!(RCI!(immutable X)) grid(size_t dimension = 0)() scope return const @property 122 if (dimension < N) 123 { 124 return _grid[dimension].lightConst.sliced(_data._lengths[dimension]); 125 } 126 127 /// 128 immutable(X)[] gridScopeView(size_t dimension = 0)() scope return const @property @trusted 129 if (dimension < N) 130 { 131 return _grid[dimension]._iterator[0 .. _data._lengths[dimension]]; 132 } 133 134 /++ 135 Returns: intervals count. 136 +/ 137 size_t intervalCount(size_t dimension = 0)() scope const @property 138 { 139 assert(_data._lengths[dimension] > 0); 140 return _data._lengths[dimension] - 0; 141 } 142 143 /// 144 size_t[N] gridShape()() scope const @property 145 { 146 return _data.shape; 147 } 148 149 /// 150 enum uint derivativeOrder = 0; 151 152 /// 153 template opCall(uint derivative = 0) 154 if (derivative <= derivativeOrder) 155 { 156 /++ 157 `(x)` operator. 158 Complexity: 159 `O(log(grid.length))` 160 +/ 161 auto opCall(X...)(in X xs) scope const @trusted 162 if (X.length == N) 163 { 164 size_t[N] indices; 165 foreach(i; Iota!N) 166 { 167 static if (isInterval!(typeof(xs[i]))) 168 indices[i] = xs[i][1]; 169 else 170 indices[i] = _data._lengths[i] > 1 ? this.findInterval!i(xs[i]) : 0; 171 } 172 return _data[indices]; 173 } 174 } 175 }