Minsky
tensorOp.h
Go to the documentation of this file.
1 /*
2  @copyright Russell Standish 2019
3  @author Russell Standish
4  This file is part of Civita.
5 
6  Civita is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Civita is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Civita. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef CIVITA_TENSOROP_H
21 #define CIVITA_TENSOROP_H
22 #include "tensorVal.h"
23 #include "ravelState.h"
24 
25 #include <functional>
26 #include <memory>
27 #include <vector>
28 
29 namespace civita
30 {
31 
33  struct ElementWiseOp: public ITensor
34  {
35  std::function<double(double)> f;
36  std::shared_ptr<ITensor> arg;
37  template <class F>
38  ElementWiseOp(F f, const std::shared_ptr<ITensor>& arg={}): f(f), arg(arg) {}
39  void setArgument(const TensorPtr& a,const ITensor::Args&) override {arg=a;}
40  const Hypercube& hypercube() const override {return arg? arg->hypercube(): m_hypercube;}
41  const Index& index() const override {return arg? arg->index(): m_index;}
42  double operator[](std::size_t i) const override {return arg? f((*arg)[i]): 0;}
43  std::size_t size() const override {return arg? arg->size(): 1;}
44  Timestamp timestamp() const override {return arg? arg->timestamp(): Timestamp();}
45  };
46 
49  class BinOp: public ITensor
50  {
51  protected:
52  std::function<double(double,double)> f;
54  public:
55  template <class F>
56  BinOp(F f, const TensorPtr& arg1={},const TensorPtr& arg2={}):
57  f(f) {BinOp::setArguments(arg1,arg2,{"",0});}
58 
59  void setArguments(const TensorPtr& a1, const TensorPtr& a2, const ITensor::Args&) override;
60 
61  double operator[](std::size_t i) const override {
62  // missing arguments treated as group identity
63  if (!arg1)
64  {
65  if (arg2)
66  return (*arg2)[i];
67  else
68  throw std::runtime_error("inputs undefined");
69  }
70  if (!arg2) return (*arg1)[i];
71  assert(index().size()==0 || i<index().size());
72  auto hcIndex=index().size()? index()[i]: i;
73  // scalars are broadcast
74  return f(arg1->rank()? arg1->atHCIndex(hcIndex): (*arg1)[0],
75  arg2->rank()? arg2->atHCIndex(hcIndex): (*arg2)[0]);
76  }
77  Timestamp timestamp() const override
78  {return max(arg1->timestamp(), arg2->timestamp());}
79  };
80 
82  class ReduceArguments: public ITensor
83  {
84  std::vector<TensorPtr> args;
85  std::function<void(double&,double)> f;
86  double init;
87  public:
88  template <class F> ReduceArguments(F f, double init): f(f), init(init) {}
89  void setArguments(const std::vector<TensorPtr>& a,const ITensor::Args&) override;
90  double operator[](std::size_t i) const override;
91  Timestamp timestamp() const override;
92  };
93 
94 
96  struct ReduceAllOp: public ITensor
97  {
98  std::function<void(double&,double,std::size_t)> f;
99  double init;
100  std::shared_ptr<ITensor> arg;
101  void setArgument(const TensorPtr& a,const ITensor::Args&) override {arg=a;}
102 
103  template <class F>
104  ReduceAllOp(F f, double init, const std::shared_ptr<ITensor>& arg={}):
105  f(f),init(init), arg(arg) {}
106 
107  double operator[](std::size_t) const override;
108  Timestamp timestamp() const override {return arg->timestamp();}
109  };
110 
113  class ReductionOp: public ReduceAllOp
114  {
115  std::size_t dimension;
116  struct SOI {std::size_t index, dimIndex;};
117  std::map<std::size_t, std::vector<SOI>> sumOverIndices;
118  public:
119 
120  template <class F>
121  ReductionOp(F f, double init, const TensorPtr& arg={}, const std::string& dimName=""):
123 
124  void setArgument(const TensorPtr& a, const ITensor::Args&) override;
125  double operator[](std::size_t i) const override;
126  };
127 
128  // general tensor expression - all elements calculated and cached
129  class CachedTensorOp: public ITensor
130  {
131  protected:
132  mutable TensorVal cachedResult;
136  virtual void computeTensor() const=0;
137  public:
138  const Index& index() const override {return cachedResult.index();}
139  std::size_t size() const override {return cachedResult.size();}
140  double operator[](std::size_t i) const override;
141  const Hypercube& hypercube() const override {return cachedResult.hypercube();}
142  const Hypercube& hypercube(const Hypercube& hc) override {return cachedResult.hypercube(hc);}
143  const Hypercube& hypercube(Hypercube&& hc) override {return cachedResult.hypercube(std::move(hc));}
144  };
145 
147  struct Sum: public ReductionOp
148  {
149  public:
150  Sum(): ReductionOp([](double& x, double y,std::size_t){x+=y;},0) {}
151  };
152 
154  struct Product: public ReductionOp
155  {
156  public:
157  Product(): ReductionOp([](double& x, double y,std::size_t){x*=y;},1) {}
158  };
159 
161  class Min: public civita::ReductionOp
162  {
163  public:
164  Min(): civita::ReductionOp([](double& x, double y,std::size_t){if (y<x) x=y;},std::numeric_limits<double>::max()){}
165  };
167  class Max: public civita::ReductionOp
168  {
169  public:
170  Max(): civita::ReductionOp([](double& x, double y,std::size_t){if (y>x) x=y;},-std::numeric_limits<double>::max()){}
171  };
172 
174  struct Average: public ReductionOp
175  {
176  mutable std::size_t count;
177  public:
178  Average(): ReductionOp([this](double& x, double y,std::size_t){x+=y; ++count;},0) {}
179  double operator[](std::size_t i) const override
180  {count=0; return ReductionOp::operator[](i)/count;}
181  };
182 
184  struct StdDeviation: public ReductionOp
185  {
186  mutable std::size_t count;
187  mutable double sqr;
188  public:
189  StdDeviation(): ReductionOp([this](double& x, double y,std::size_t){x+=y; sqr+=y*y; ++count;},0) {}
190  double operator[](std::size_t i) const override {
191  count=0; sqr=0;
192  double av=ReductionOp::operator[](i)/count;
193  return sqrt(std::max(0.0, sqr/count-av*av));
194  }
195  };
196 
198  {
200  std::size_t dimension=std::numeric_limits<std::size_t>::max();
202  double argVal=0;
204  void setArgument(const TensorPtr& a, const ITensor::Args&) override;
205  Timestamp timestamp() const override {return arg? arg->timestamp(): Timestamp();}
206  };
207 
209  {
210  public:
211  std::function<void(double&,double,std::size_t)> f;
212  template <class F>
213  Scan(F f, const TensorPtr& arg={}, const std::string& dimName="", double av=0): f(f)
214  {Scan::setArgument(arg,{dimName,av});}
215  void setArgument(const TensorPtr& arg, const ITensor::Args& args) override {
217  if (arg)
218  cachedResult.hypercube(arg->hypercube());
219  // TODO - can we handle sparse data?
220  }
221  void computeTensor() const override;
222  };
223 
225  class Slice: public ITensor
226  {
227  std::size_t stride=1, split=1, sliceIndex=0;
229  std::vector<std::size_t> arg_index;
230  public:
231  void setArgument(const TensorPtr& a,const ITensor::Args&) override;
232  double operator[](std::size_t i) const override;
233  Timestamp timestamp() const override {return arg->timestamp();}
234  };
235 
237  class Pivot: public ITensor
238  {
239  std::vector<std::size_t> permutation;
240  std::vector<std::size_t> permutedIndex;
242  // returns hypercube index of arg given hypercube index of this
243  std::size_t pivotIndex(std::size_t i) const;
244  public:
245  void setArgument(const TensorPtr& a,const ITensor::Args& args={"",0}) override;
248  void setOrientation(const std::vector<std::string>& axes);
249  double operator[](std::size_t i) const override;
250  Timestamp timestamp() const override {return arg->timestamp();}
251  };
252 
253  class PermuteAxis: public ITensor
254  {
256  std::size_t m_axis;
257  std::vector<std::size_t> m_permutation;
258  std::vector<std::size_t> permutedIndex;
259  public:
260  void setArgument(const TensorPtr& a,const ITensor::Args& args={"",0}) override;
261  void setPermutation(const std::vector<std::size_t>& p)
262  {auto pp(p); setPermutation(std::move(pp));}
263  void setPermutation(std::vector<std::size_t>&&);
264  std::size_t axis() const {return m_axis;}
265  const std::vector<std::size_t>& permutation() const {return m_permutation;}
266  double operator[](std::size_t i) const override;
267  Timestamp timestamp() const override {return arg->timestamp();}
268  };
269 
272  {
274  ravel::HandleSort::Order order;
275  public:
276  SortByValue(ravel::HandleSort::Order order): order(order) {}
277  void setArgument(const TensorPtr& a,const ITensor::Args& args={"",0}) override {
278  if (a->rank()!=1)
279  throw std::runtime_error("Sort by Value only applicable for rank 1 tensors");
280  else
281  arg=a;
282  cachedResult.hypercube(a->hypercube()); // no data, unsorted
283  }
284  void computeTensor() const override;
285  Timestamp timestamp() const override {return arg->timestamp();}
286  const Hypercube& hypercube() const override {
288  return cachedResult.hypercube();
289  }
290  std::size_t size() const override {
292  return cachedResult.size();
293  }
294  };
295 
296  class SpreadBase: public ITensor
297  {
298  protected:
300  std::size_t numSpreadElements=1;
301  public:
302  void setArgument(const TensorPtr& a,const ITensor::Args& args={"",0}) override {
303  arg=a;
304  if (arg){
305  hypercube(arg->hypercube());
306  m_index=arg->index();
307  }
308  }
309  Timestamp timestamp() const override {return arg? arg->timestamp(): Timestamp();}
310  };
311 
312  class SpreadFirst: public SpreadBase
313  {
314  public:
315  void setSpreadDimensions(const Hypercube& hc) {
316  if (!arg) return;
317  numSpreadElements=hc.numElements();
318  m_hypercube=hc;
319  m_hypercube.xvectors.insert(m_hypercube.xvectors.end(), arg->hypercube().xvectors.begin(),
320  arg->hypercube().xvectors.end());
321  std::set<std::size_t> idx;
322  for (auto& i: arg->index())
323  for (std::size_t j=0; j<numSpreadElements; ++j)
324  idx.insert(j+i*numSpreadElements);
325  m_index=idx;
326  }
327 
328  double operator[](std::size_t i) const override {
329  if (arg) return (*arg)[i/numSpreadElements];
330  return nan("");
331  }
332  };
333 
334  class SpreadLast: public SpreadBase
335  {
336  public:
337  void setSpreadDimensions(const Hypercube& hc) {
338  if (!arg) return;
339  numSpreadElements=hc.numElements();
340  m_hypercube=arg->hypercube();
341  m_hypercube.xvectors.insert(m_hypercube.xvectors.end(), hc.xvectors.begin(), hc.xvectors.end());
342  std::set<std::size_t> idx;
343  for (auto& i: arg->index())
344  for (std::size_t j=0; j<numSpreadElements; ++j)
345  idx.insert(i+j*arg->size());
346  m_index=idx;
347  }
348 
349  double operator[](std::size_t i) const override {
350  if (arg) return (*arg)[i%arg->size()];
351  return nan("");
352  }
353  };
354 
355 
358  std::vector<TensorPtr> createRavelChain(const ravel::RavelState&, const TensorPtr& arg);
359 
360 }
361 
362 #endif
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:328
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:179
std::size_t dimension
Definition: tensorOp.h:115
calculate the sum along an axis or whole tensor
Definition: tensorOp.h:147
virtual void computeTensor() const =0
computeTensor updates the above two mutable fields, but is logically const
std::vector< TensorPtr > args
Definition: tensorOp.h:84
TensorPtr arg1
Definition: tensorOp.h:53
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:190
If a rank 1 argument, sort by the value of the argument.
Definition: tensorOp.h:271
std::size_t numSpreadElements
Definition: tensorOp.h:300
virtual const Hypercube & hypercube() const
information describing the axes, types and labels of this tensor
double argVal
op arg value, eg binsize or delta in difference op
Definition: tensorOp.h:202
void setArgument(const TensorPtr &a, const ITensor::Args &args={"", 0}) override
argument indices corresponding to this indices, when sparse
Definition: tensorOp.cc:413
calculates the average along an axis or whole tensor
Definition: tensorOp.h:174
std::size_t axis() const
Definition: tensorOp.h:264
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:77
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:61
vector< TensorPtr > createRavelChain(const ravel::RavelState &state, const TensorPtr &arg)
creates a chain of tensor operations that represents a Ravel in state state, operating on arg ...
Definition: tensorOp.cc:497
const Index & index() const override
the index vector - assumed to be ordered and unique
Definition: tensorOp.h:41
double operator[](std::size_t) const override
return or compute data at a location
Definition: tensorOp.cc:90
compute the reduction along the indicated dimension, ignoring any missing entry (NaNs) ...
Definition: tensorOp.h:113
reduce all elements to a single number
Definition: tensorOp.h:96
Expr sqrt(const Expr &x)
Definition: expr.h:154
void setArgument(const TensorPtr &a, const ITensor::Args &args={"", 0}) override
Definition: tensorOp.h:277
std::size_t sliceIndex
Definition: tensorOp.h:227
virtual const Index & index() const
the index vector - assumed to be ordered and unique
ElementWiseOp(F f, const std::shared_ptr< ITensor > &arg={})
Definition: tensorOp.h:38
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:44
perform an operation elementwise over a tensor valued argument
Definition: tensorOp.h:33
STL namespace.
std::vector< std::size_t > arg_index
Definition: tensorOp.h:229
std::map< std::size_t, std::vector< SOI > > sumOverIndices
Definition: tensorOp.h:117
std::shared_ptr< ITensor > arg
Definition: tensorOp.h:100
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:285
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:137
std::function< void(double &, double)> f
Definition: tensorOp.h:85
void setSpreadDimensions(const Hypercube &hc)
Definition: tensorOp.h:337
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:42
void setSpreadDimensions(const Hypercube &hc)
Definition: tensorOp.h:315
Timestamp m_timestamp
Definition: tensorOp.h:133
const Index & index() const override
the index vector - assumed to be ordered and unique
Definition: tensorOp.h:138
std::size_t size() const override
return number of elements in tensor - maybe less than hypercube.numElements if sparse ...
Definition: tensorOp.h:290
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:451
ReduceAllOp(F f, double init, const std::shared_ptr< ITensor > &arg={})
Definition: tensorOp.h:104
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:108
std::vector< std::size_t > permutation
Definition: tensorOp.h:239
std::size_t pivotIndex(std::size_t i) const
Definition: tensorOp.cc:377
virtual std::size_t size() const
return number of elements in tensor - maybe less than hypercube.numElements if sparse ...
const Hypercube & hypercube(const Hypercube &hc) override
Definition: tensorOp.h:142
std::vector< std::size_t > permutedIndex
Definition: tensorOp.h:258
void setArgument(const TensorPtr &a, const ITensor::Args &args={"", 0}) override
Definition: tensorOp.cc:309
TensorPtr arg
argument indices corresponding to this indices, when sparse
Definition: tensorOp.h:241
corresponds to the OLAP pivot operation
Definition: tensorOp.h:237
void setArguments(const std::vector< TensorPtr > &a, const ITensor::Args &) override
Definition: tensorOp.cc:49
void setArgument(const TensorPtr &a, const ITensor::Args &) override
Definition: tensorOp.cc:244
void setArgument(const TensorPtr &a, const ITensor::Args &) override
Definition: tensorOp.cc:184
std::chrono::time_point< std::chrono::high_resolution_clock > Timestamp
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:250
std::size_t hcIndex(const std::initializer_list< T > &indices) const
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:267
void setArguments(const TensorPtr &a1, const TensorPtr &a2, const ITensor::Args &) override
Definition: tensorOp.cc:28
void setArgument(const TensorPtr &a, const ITensor::Args &) override
Definition: tensorOp.h:101
calculate the minimum along an axis or whole tensor
Definition: tensorOp.h:161
arguments relevant for tensor expressions, not always meaningful. Exception thrown if not...
TensorPtr arg2
Definition: tensorOp.h:53
ReductionOp(F f, double init, const TensorPtr &arg={}, const std::string &dimName="")
Definition: tensorOp.h:121
const Hypercube & hypercube() const override
information describing the axes, types and labels of this tensor
Definition: tensorOp.h:141
Scan(F f, const TensorPtr &arg={}, const std::string &dimName="", double av=0)
Definition: tensorOp.h:213
BinOp(F f, const TensorPtr &arg1={}, const TensorPtr &arg2={})
Definition: tensorOp.h:56
std::size_t m_axis
Definition: tensorOp.h:256
perform a binary operation elementwise over two tensor arguments. Arguments need to be conformal: at ...
Definition: tensorOp.h:49
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:309
std::size_t size() const override
return number of elements in tensor - maybe less than hypercube.numElements if sparse ...
Definition: tensorOp.h:139
std::size_t dimIndex
Definition: tensorOp.h:116
calculate the maximum along an axis or whole tensor
Definition: tensorOp.h:167
std::size_t count
Definition: tensorOp.h:186
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:233
std::size_t split
Definition: tensorOp.h:227
std::function< void(double &, double, std::size_t)> f
Definition: tensorOp.h:98
void setOrientation(const std::vector< std::string > &axes)
set&#39;s the pivots orientation
Definition: tensorOp.cc:319
std::shared_ptr< ITensor > TensorPtr
void setArgument(const TensorPtr &a, const ITensor::Args &args={"", 0}) override
Definition: tensorOp.h:302
std::size_t dimension
dimension to apply operation over. >rank = all dims
Definition: tensorOp.h:200
const Hypercube & hypercube(Hypercube &&hc) override
Definition: tensorOp.h:143
std::shared_ptr< ITensor > arg
Definition: tensorOp.h:36
corresponds to OLAP slice operation
Definition: tensorOp.h:225
ReduceArguments(F f, double init)
Definition: tensorOp.h:88
const std::vector< std::size_t > & permutation() const
Definition: tensorOp.h:265
void computeTensor() const override
computeTensor updates the above two mutable fields, but is logically const
Definition: tensorOp.cc:464
std::size_t size() const override
return number of elements in tensor - maybe less than hypercube.numElements if sparse ...
Definition: tensorOp.h:43
std::function< void(double &, double, std::size_t)> f
Definition: tensorOp.h:211
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.h:205
std::vector< std::size_t > permutedIndex
permutation of axes
Definition: tensorOp.h:240
void computeTensor() const override
computeTensor updates the above two mutable fields, but is logically const
Definition: tensorOp.cc:199
const Hypercube & hypercube() const override
information describing the axes, types and labels of this tensor
Definition: tensorOp.h:40
TensorPtr arg
Definition: tensorOp.h:228
elementwise reduction over a vector of arguments
Definition: tensorOp.h:82
TensorPtr arg
Definition: tensorOp.h:299
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:69
void setPermutation(const std::vector< std::size_t > &p)
Definition: tensorOp.h:261
Hypercube m_hypercube
calculates the standard deviation along an axis or whole tensor
Definition: tensorOp.h:184
void setArgument(const TensorPtr &arg, const ITensor::Args &args) override
Definition: tensorOp.h:215
SortByValue(ravel::HandleSort::Order order)
Definition: tensorOp.h:276
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:174
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:298
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.cc:386
std::size_t stride
Definition: tensorOp.h:227
void setArgument(const TensorPtr &a, const ITensor::Args &) override
Definition: tensorOp.h:39
std::vector< std::size_t > m_permutation
Definition: tensorOp.h:257
std::function< double(double)> f
Definition: tensorOp.h:35
calculate the product along an axis or whole tensor
Definition: tensorOp.h:154
TensorVal cachedResult
Definition: tensorOp.h:132
const Hypercube & hypercube() const override
information describing the axes, types and labels of this tensor
Definition: tensorOp.h:286
std::size_t count
Definition: tensorOp.h:176
Timestamp timestamp() const override
timestamp indicating how old the dependendent data might be. Used in CachedTensorOp to determine when...
Definition: tensorOp.cc:82
std::function< double(double, double)> f
Definition: tensorOp.h:52
void setArgument(const TensorPtr &a, const ITensor::Args &) override
Definition: tensorOp.cc:101
ravel::HandleSort::Order order
Definition: tensorOp.h:274
double operator[](std::size_t i) const override
return or compute data at a location
Definition: tensorOp.h:349