1 module dnum.utils; 2 3 import dnum.tensor; 4 5 /++ 6 Create Single Tensor 7 +/ 8 Tensor seq(int start, int end, int step = 1) { 9 auto r = Range(start, end, step); 10 return Tensor(r); 11 } 12 13 /++ 14 Extract Row 15 +/ 16 Tensor row(Tensor t, ulong i) { 17 assert(i <= t.nrow, "No valid row"); 18 19 auto container = Tensor(t.data[i][], Shape.Row); 20 return container; 21 } 22 23 /++ 24 Extract Column 25 +/ 26 Tensor col(Tensor t, ulong i) { 27 assert(i <= t.ncol, "No valid column"); 28 29 auto container = Tensor(t.nrow, 1); 30 31 foreach (j, ref rows; t.data) { 32 container[j,0] = rows[i]; 33 } 34 return container; 35 } 36 37 /++ 38 Check Single Column 39 +/ 40 pure bool isCol(Tensor t) { 41 return t.ncol == 1; 42 } 43 44 /++ 45 Check Single Row 46 +/ 47 pure bool isRow(Tensor t) { 48 return t.nrow == 1; 49 } 50 51 /++ 52 Check Single 53 +/ 54 pure bool isSingle(Tensor t) { 55 return isCol(t) || isRow(t); 56 } 57 58 // ============================================================================= 59 // Python Functions 60 // ============================================================================= 61 /++ 62 where - Like numpy.where 63 +/ 64 65 // ============================================================================= 66 // R Functions 67 // ============================================================================= 68 /++ 69 Column Bind (Like R Syntax) 70 +/ 71 Tensor cbind(Tensor t1, Tensor t2) { 72 auto container = Tensor(t1.nrow, t1.ncol + t2.ncol); 73 74 foreach (i, ref rows; container.data) { 75 rows = t1.data[i][] ~ t2.data[i][]; 76 } 77 78 return container; 79 } 80 81 /++ 82 Generic cbind 83 +/ 84 Tensor cbind(Tensor[] t...) { 85 int cols = 0; 86 foreach (elem; t) { 87 cols += elem.ncol; 88 } 89 90 auto container = Tensor(t[0].nrow, cols); 91 92 foreach (i, ref rows; container.data) { 93 auto initTen = t[0].data[i][]; 94 foreach (k; 1 .. t.length) { 95 initTen ~= t[k].data[i][]; 96 } 97 rows = initTen[]; 98 } 99 return container; 100 } 101 102 /++ 103 Row Bind (Like R Syntax) 104 +/ 105 Tensor rbind(Tensor t1, Tensor t2) { 106 return Tensor(t1.data ~ t2.data); 107 } 108 109 /++ 110 Generic rbind 111 +/ 112 Tensor rbind(Tensor[] t...) { 113 auto initTen = Tensor(t[0]); 114 foreach (k; 1 .. t.length) { 115 initTen.data ~= t[k].data; 116 } 117 return initTen; 118 } 119 120 /++ 121 Vectorize Function 122 +/ 123 auto vectorize(double delegate(double) f) { 124 return (Tensor t) => t.fmap(f); 125 } 126 127 /++ 128 runif - generate uniform random seq 129 +/ 130 Tensor runif(int n, double a, double b, Shape byRow = Shape.Row) { 131 import std.random : Random, unpredictableSeed, uniform; 132 133 auto rnd = Random(unpredictableSeed); 134 135 double[] w; 136 w.length = n; 137 138 foreach (i; 0 .. n) { 139 w[i] = uniform!"()"(a, b, rnd); 140 } 141 142 return Tensor(w, byRow); 143 } 144 145 /++ 146 runif - D version 147 +/ 148 Tensor runif(int n, Range r, Shape byRow = Shape.Row) { 149 import std.random : Random, unpredictableSeed, uniform; 150 151 auto rnd = Random(unpredictableSeed); 152 153 double[] w; 154 w.length = n; 155 156 foreach (i; 0 .. n) { 157 w[i] = uniform!"()"(r.start, r.end, rnd); 158 } 159 160 return Tensor(w, byRow); 161 } 162 163 // ============================================================================= 164 // MATLAB(Julia) Functions 165 // ============================================================================= 166 /++ 167 rand - random tensor with uniform dist (0, 1) 168 +/ 169 Tensor rand(int n, Shape byRow = Shape.Row) { 170 return runif(n, 0, 1, byRow); 171 } 172 173 /++ 174 rand - D version 175 +/ 176 Tensor rand(int n, Range r, Shape byRow = Shape.Row) { 177 return runif(n, r, byRow); 178 } 179 180 /++ 181 rand tensor version 182 +/ 183 Tensor rand(int m, int n) { 184 import std.random : Random, unpredictableSeed, uniform; 185 186 auto rnd = Random(unpredictableSeed); 187 188 auto container = Tensor(m, n); 189 190 foreach(ref rows; container.data) { 191 foreach(ref elem; rows) { 192 elem = uniform!"()"(0., 1., rnd); 193 } 194 } 195 196 return container; 197 } 198 199 /++ 200 rand tensor version - D version 201 +/ 202 Tensor rand(Size s, Range r) { 203 import std.random : Random, unpredictableSeed, uniform; 204 205 auto rnd = Random(unpredictableSeed); 206 207 auto container = Tensor(s.row, s.col); 208 209 foreach(ref rows; container.data) { 210 foreach(ref elem; rows) { 211 elem = uniform!"()"(r.start, r.end, rnd); 212 } 213 } 214 215 return container; 216 } 217 218 // ============================================================================= 219 // Functional Programming Tools - Unstable 220 // ============================================================================= 221 /++ 222 take - take the number of components of tensor 223 +/ 224 Tensor take(Tensor t, int n) { 225 assert(t.isSingle, "Use Range to extract components for not single tensors (see tensor.d - opIndex)"); 226 if (t.isRow) { 227 return t[Range(0,0), Range(0, n-1)]; 228 } else { 229 return t[Range(0, n-1), Range(0,0)]; 230 } 231 } 232 233 /++ 234 takeWhile 235 +/ 236 Tensor takeWhile(Tensor t, bool delegate(double) f) { 237 assert(t.isSingle, "You can't use take while for not single tensors"); 238 if (t.isRow) { 239 int n = 0; 240 double[] container; 241 while (f(t[0, n])) { 242 container ~= t[0,n]; 243 n++; 244 } 245 return Tensor(container, Shape.Row); 246 } else { 247 int n = 0; 248 double[] container; 249 while (f(t[n,0])) { 250 container ~= t[n,0]; 251 n++; 252 } 253 return Tensor(container, Shape.Col); 254 } 255 } 256 257 alias DFunc = double delegate(double, double); 258 alias Func = double delegate(double); 259 260 /++ 261 Currying 262 +/ 263 Func currying(DFunc f, double x) { 264 return t => f(x,t); 265 } 266 267 /++ 268 zipWith - zip two Tensor with operation to one tensor 269 +/ 270 Tensor zipWith(double delegate(double, double) op, Tensor t1, Tensor t2) { 271 assert(t1.isSingle && t2.isSingle, "zipWith for not single tensor is not yet implemented"); 272 import std.algorithm.comparison : min; 273 if (t1.isCol && t2.isCol) { 274 auto n = min(t1.nrow, t2.nrow); 275 auto result = Tensor(n, 1); 276 foreach(i; 0 .. n) { 277 result[i, 0] = op(t1[i,0], t2[i,0]); 278 } 279 return result; 280 } else if (t1.isRow && t2.isRow) { 281 auto n = min(t1.ncol, t2.ncol); 282 auto result = Tensor(1, n); 283 foreach(i; 0 .. n) { 284 result[0, i] = op(t1[0,i], t2[0,i]); 285 } 286 return result; 287 } else { 288 assert(false, "Both tensors should be same form! (Row vs Row or Col vs Col)"); 289 } 290 }