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 }