CUV  0.9.201304091348
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tensor_ops.hpp
1 //*LB*
2 // Copyright (c) 2010, University of Bonn, Institute for Computer Science VI
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of the University of Bonn
14 // nor the names of its contributors may be used to endorse or promote
15 // products derived from this software without specific prior written
16 // permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //*LE*
29 
30 
31 #ifndef __TENSOR_OPS_HPP__
32 #define __TENSOR_OPS_HPP__
33 
34 #include <cuv/basics/tensor.hpp>
35 
36 namespace cuv{
57  NF_FILL,
58  NF_SEQ
59  };
60 
68  template<class __value_type, class __memory_space_type>
69  void
70  apply_0ary_functor(tensor<__value_type, __memory_space_type>& v, const NullaryFunctor& sf);
71 
75  template<class __value_type, class __memory_space_type>
78  }
89  template<class V1, class M>
90  void
91  apply_0ary_functor(tensor<V1, M>& v, const NullaryFunctor& sf, const V1& param);
92 
96  template<class V1, class M>
97  void apply_0ary_functor(tensor<V1, M, column_major>& v, const NullaryFunctor& sf, const V1& param){
98  apply_0ary_functor(* reinterpret_cast<tensor<V1, M, row_major>* >(&v), sf, param);
99  }
100 
108  template<class __value_type, class __memory_space_type, class __memory_layout_type>
110 
119  template<class __value_type, class __memory_space_type, class __memory_layout_type, class S>
121  apply_0ary_functor(v,NF_FILL,(__value_type)p);
122  }
123 
193  // w/o params
194  SF_EXP,
195  SF_SIN,
196  SF_COS,
197  //SF_EXACT_EXP,
198  SF_LOG,
199  SF_SIGN,
200  SF_SIGM,
201  //SF_EXACT_SIGM,
202  SF_DSIGM,
203  SF_SQUARE,
204  SF_SUBLIN,
205  SF_ENERG,
206  SF_INV,
207  SF_SQRT,
208  SF_NEGATE,
209  SF_ABS,
210  SF_SMAX,
211  SF_POSLIN,
212  // rectifying transfer function
213  SF_RECT,
214  SF_DRECT,
215  SF_COPY,
216  SF_LOG1P,
217 
218  // with param
219  SF_POW,
220  SF_DPOW,
221  SF_ADD,
222  SF_SUBTRACT,
223  SF_RSUB,
224  SF_MULT,
225  SF_DIV,
226  SF_RDIV,
227  SF_LOGADDEXP,
228  SF_MIN,
229  SF_MAX,
230  SF_ROBUST_ABS,
231  SF_DROBUST_ABS,
232  SF_EQ,
233  SF_LT,
234  SF_GT,
235  SF_LEQ,
236  SF_GEQ,
237  SF_BERNOULLI_KL,
238  SF_DBERNOULLI_KL,
239 
240  // with two params
241  SF_AXPB,
242  SF_TANH,
243  SF_DTANH
244  };
245  namespace detail{
259  template<class V1, class V2, class M, class S1, class S2>
260  void apply_scalar_functor(tensor<V1, M>&dst, const tensor<V2, M>&src, const ScalarFunctor& sf, const int& numparams=0, const tensor<unsigned char,M>* mask=NULL,const S1& p=S1(), const S2& p2=S2());
261 
265  template<class V1, class V2, class M, class S1, class S2>
266  void apply_scalar_functor(tensor<V1, M, column_major>& dst, const tensor<V2, M, column_major>& src, const ScalarFunctor& sf, const int& numparams=0, const tensor<unsigned char,M,column_major>* mask=NULL, const S1& p=S1(), const S2& p2=S2()){
267  apply_scalar_functor(*reinterpret_cast<tensor<V1, M, row_major>* >(&dst), * reinterpret_cast<const tensor<V2, M, row_major>*>(&src), sf, numparams,reinterpret_cast<const tensor<unsigned char, M, row_major>*>(mask), p, p2);
268  }
269  }
270 
288  template<class D>
289  void
291  typedef typename D::value_type V;
292  detail::apply_scalar_functor(v,v,sf,0,mask,V(),V());
293  }
306  template<class D, class S>
307  void
309  typedef typename S::value_type V;
310  detail::apply_scalar_functor(dst,src,sf,0,mask,V(),V());
311  }
312 
331  template<class D>
332  void
334  typedef typename D::value_type V;
335  detail::apply_scalar_functor(v,v,sf,1,mask,p,V());
336  }
355  template<class D, class S>
356  void
357  apply_scalar_functor(D& dst,const S& src, const ScalarFunctor& sf, const typename S::value_type& p,const tensor<unsigned char,typename D::memory_space_type, typename D::memory_layout_type>*mask=NULL){
358  typedef typename S::value_type V;
359  detail::apply_scalar_functor(dst,src,sf,1,mask,p,V());
360  }
361 
380  template<class D>
381  void
382  apply_scalar_functor(D& v, const ScalarFunctor& sf, const typename D::value_type& p, const typename D::value_type& p2, const tensor<unsigned char,typename D::memory_space_type, typename D::memory_layout_type>*mask=NULL){
383  detail::apply_scalar_functor(v,v,sf,2,mask,p,p2);
384  }
385 
405  template<class D, class S>
406  void
407  apply_scalar_functor(D& dst, const S& src, const ScalarFunctor& sf, const typename S::value_type& p, const typename S::value_type& p2, const tensor<unsigned char,typename D::memory_space_type, typename D::memory_layout_type>*mask=NULL){
408  detail::apply_scalar_functor(dst,src,sf,2,mask,p,p2);
409  }
410 
460  // w/o params
461  BF_1ST,
462  BF_2ND,
463  BF_EQ,
464  BF_AND,
465  BF_OR,
466  BF_POW,
467  BF_ADD,
468  BF_SUBTRACT,
469  BF_MULT,
470  BF_DIV,
471  BF_MIN,
472  BF_MAX,
473  BF_ATAN2,
474  BF_NORM,
475  BF_LOGADDEXP,
476  BF_LOGCE_OF_LOGISTIC,
477  BF_BERNOULLI_KL,
478  BF_DBERNOULLI_KL,
479 
480  // w/ param
481  BF_AXPY,
482  BF_XPBY,
483  BF_AXPBY,
484  BF_EPSILON_INSENSITIVE_LOSS,
485  BF_DEPSILON_INSENSITIVE_LOSS,
486  BF_HINGE_LOSS,
487  BF_DHINGE_LOSS,
488  BF_SQHINGE_LOSS,
489  BF_DSQHINGE_LOSS
490  };
491 
492  namespace detail{
506  template<class V1, class V2, class V3, class M, class S1, class S2>
507  void apply_binary_functor(tensor<V1, M>& dst,const tensor<V2, M>& src1, const tensor<V3, M>&src2, const BinaryFunctor& bf, const int& numparams=0, const S1& p=S1(), const S2& p2=S2());
508  template<class V1, class V2, class V3, class M, class S1, class S2>
509  void apply_binary_functor(tensor<V1, M, column_major>& dst, const tensor<V2, M, column_major>& src1, const tensor<V3, M, column_major>& src2, const BinaryFunctor& bf, const int& numparams=0, const S1& p=S1(), const S2& p2=S2()){
510  apply_binary_functor(*reinterpret_cast<tensor<V1, M, row_major>* >(&dst), * reinterpret_cast<const tensor<V2, M, row_major>*>(&src1), * reinterpret_cast<const tensor<V3, M, row_major>*>(&src2), bf, numparams, p, p2);
511  }
512  }
528  template<class D, class S>
529  void
530  apply_binary_functor(D& v, const S& w, const BinaryFunctor& bf){
531  typedef typename S::value_type V;
532  detail::apply_binary_functor(v,v,w,bf,0,V(),V());
533  }
551  template<class D, class S, class S2>
552  void
553  apply_binary_functor(D& v, const S& w, const S2& w2, const BinaryFunctor& bf){
554  typedef typename S::value_type V;
555  detail::apply_binary_functor(v,w,w2,bf,0,V(),V());
556  }
557 
575  template<class D, class S>
576  void
577  apply_binary_functor(D& v,const S& w, const BinaryFunctor& bf, const typename S::value_type& param){
578  typedef typename S::value_type V;
579  detail::apply_binary_functor(v,v,w,bf,1,param,V());
580  }
581 
600  template<class D, class S, class S2>
601  void
602  apply_binary_functor(D& v,const S& w, const S2& w2, const BinaryFunctor& bf, const typename S::value_type& param){
603  detail::apply_binary_functor(v,w,w2,bf,1,param,param);
604  }
605 
624  template<class D, class S>
625  void
626  apply_binary_functor(D& v, const S& w, const BinaryFunctor& bf, const typename S::value_type& param, const typename S::value_type& param2){
627  detail::apply_binary_functor(v,v,w,bf,2,param,param2);
628  }
629 
649  template<class D, class S, class S2>
650  void
651  apply_binary_functor(D& v, const S& w, const S2& w2, const BinaryFunctor& bf, const typename S::value_type& param, const typename S::value_type& param2){
652  detail::apply_binary_functor(v,w,w2,bf,2,param,param2);
653  }
662  template<class __value_type, class __memory_space_type, class __memory_layout_type>
664  apply_scalar_functor(dst,src,SF_COPY);
665  } //end group binary_functors
667  //end group functors_vectors
669 
681  template<class __value_type, class __memory_space_type> bool has_inf(const tensor<__value_type, __memory_space_type>& v);
683  template<class __value_type, class __memory_space_type> bool has_inf(const tensor<__value_type, __memory_space_type, column_major>& v){
684  return has_inf(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
685  }
693  template<class __value_type, class __memory_space_type> bool has_nan(const tensor<__value_type, __memory_space_type>& v);
695  template<class __value_type, class __memory_space_type> bool has_nan(const tensor<__value_type, __memory_space_type, column_major>& v){
696  return has_nan(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
697  }
706  template<class __value_type, class __memory_space_type> unsigned int count(const tensor<__value_type, __memory_space_type>& v, const __value_type& s);
708  template<class __value_type, class __memory_space_type> unsigned int count(const tensor<__value_type, __memory_space_type, column_major>& v, const __value_type& s){
709  return count(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v,s));
710  }
718  template<class __value_type, class __memory_space_type> float sum(const tensor<__value_type, __memory_space_type>& v);
720  template<class __value_type, class __memory_space_type> float sum(const tensor<__value_type, __memory_space_type, column_major>& v){
721  return sum(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
722  }
730  template<class __value_type, class __memory_space_type> float norm2(const tensor<__value_type, __memory_space_type>& v);
732  template<class __value_type, class __memory_space_type> float norm2(const tensor<__value_type, __memory_space_type, column_major>& v){
733  return norm2(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
734  }
743  template<class __value_type, class __memory_space_type> float diff_norm2(const tensor<__value_type, __memory_space_type>& v, const tensor<__value_type, __memory_space_type>& w);
745  template<class __value_type, class __memory_space_type> float diff_norm2(const tensor<__value_type, __memory_space_type, column_major>& v, const tensor<__value_type, __memory_space_type, column_major>& w){
746  return diff_norm2(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v), *reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&w));
747  }
755  template<class __value_type, class __memory_space_type> float norm1(const tensor<__value_type, __memory_space_type>& v);
757  template<class __value_type, class __memory_space_type> float norm1(const tensor<__value_type, __memory_space_type, column_major>& v){
758  return norm1(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
759  }
767  template<class __value_type, class __memory_space_type> float minimum(const tensor<__value_type, __memory_space_type>& v);
769  template<class __value_type, class __memory_space_type> float minimum(const tensor<__value_type, __memory_space_type, column_major>& v){
770  return minimum(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
771  }
779  template<class __value_type, class __memory_space_type> float maximum(const tensor<__value_type, __memory_space_type>& v);
781  template<class __value_type, class __memory_space_type> float maximum(const tensor<__value_type, __memory_space_type, column_major>& v){
782  return maximum(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
783  }
791  template<class __value_type, class __memory_space_type> float mean(const tensor<__value_type, __memory_space_type>& v);
793  template<class __value_type, class __memory_space_type> float mean(const tensor<__value_type, __memory_space_type, column_major>& v){
794  return mean(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
795  }
803  template<class __value_type, class __memory_space_type> float var(const tensor<__value_type, __memory_space_type>& v);
805  template<class __value_type, class __memory_space_type> float var(const tensor<__value_type, __memory_space_type, column_major>& v){
806  return var(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
807  }
808 
816  template<class __value_type, class __memory_space_type>
817  typename tensor<__value_type, __memory_space_type>::index_type
818  arg_max(const tensor<__value_type, __memory_space_type>& v);
820  template<class __value_type, class __memory_space_type>
821  typename tensor<__value_type, __memory_space_type, column_major>::index_type
823  return arg_max(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
824  }
832  template<class __value_type, class __memory_space_type>
833  typename tensor<__value_type, __memory_space_type>::index_type
834  arg_min(const tensor<__value_type, __memory_space_type>& v);
836  template<class __value_type, class __memory_space_type>
837  typename tensor<__value_type, __memory_space_type, column_major>::index_type
839  return arg_min(*reinterpret_cast<const tensor<__value_type,__memory_space_type>* >(&v));
840  }
841  //end group reductions_vectors
843  // end group BLAS1
845 
846 } // cuv
847 
848 
849  /*
850  * operator overloading for arithmatic operations on tensors
851  */
852 
853 
854 /*
855  * binary operators (tensor, scalar)
856  */
857  template<class T, class V, class M>
859  operator+ (const cuv::tensor<T, V, M>& v, const T& p){
860  cuv::tensor<T, V, M> temp(v.shape());
861  apply_scalar_functor(temp, v, cuv::SF_ADD, p);
862  return temp;
863  }
864  template<class T, class V, class M>
866  operator- (const cuv::tensor<T, V, M>& v, const T& p){
867  cuv::tensor<T, V, M> temp(v.shape());
868  apply_scalar_functor(temp, v, cuv::SF_SUBTRACT, p);
869  return temp;
870  }
871  template<class T, class V, class M>
873  operator* (const cuv::tensor<T, V, M>& v, const T& p){
874  cuv::tensor<T, V, M> temp(v.shape());
875  apply_scalar_functor(temp, v, cuv::SF_MULT, p);
876  return temp;
877  }
878  template<class T, class V, class M>
880  operator/ (const cuv::tensor<T, V, M>& v, const T& p){
881  cuv::tensor<T, V, M> temp(v.shape());
882  apply_scalar_functor(temp, v, cuv::SF_DIV, p);
883  return temp;
884  }
885 
886 /*
887  * binary operators (scalar, tensor)
888  */
889  template<class T, class V, class M>
891  operator+ (const T& p, const cuv::tensor<T, V, M>& v){
892  cuv::tensor<T, V, M> temp(v.shape());
893  apply_scalar_functor(temp, v, cuv::SF_ADD, p);
894  return temp;
895  }
896  template<class T, class V, class M>
898  operator- (const T& p, const cuv::tensor<T, V, M>& v){
899  cuv::tensor<T, V, M> temp(v.shape());
900  apply_scalar_functor(temp, v, cuv::SF_RSUB, p);
901  return temp;
902  }
903  template<class T, class V, class M>
905  operator* (const T& p, const cuv::tensor<T, V, M>& v){
906  cuv::tensor<T, V, M> temp(v.shape());
907  apply_scalar_functor(temp, v, cuv::SF_MULT, p);
908  return temp;
909  }
910  template<class T, class V, class M>
912  operator/ (const T& p, const cuv::tensor<T, V, M>& v){
913  cuv::tensor<T, V, M> temp(v.shape());
914  apply_scalar_functor(temp, v, cuv::SF_RDIV, p);
915  return temp;
916  }
917 
918 /*
919  * binary operators (tensor, tensor)
920  */
921 
922  template<class T, class V, class M>
924  operator+ (const cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
925  cuv::tensor<T, V, M> temp(v1.shape());
926  apply_binary_functor(temp, v1, v2, cuv::BF_ADD);
927  return temp;
928  }
929 
930  template<class T, class V, class M>
932  operator- (const cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
933  cuv::tensor<T, V, M> temp(v1.shape());
934  apply_binary_functor(temp, v1, v2, cuv::BF_SUBTRACT);
935  return temp;
936  }
937  template<class T, class V, class M>
939  operator* (const cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
940  cuv::tensor<T, V, M> temp(v1.shape());
941  apply_binary_functor(temp, v1, v2, cuv::BF_MULT);
942  return temp;
943  }
944  template<class T, class V, class M>
946  operator/ (const cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
947  cuv::tensor<T, V, M> temp(v1.shape());
948  apply_binary_functor(temp, v1, v2, cuv::BF_DIV);
949  return temp;
950  }
951 
952 /*
953  * Boolean binary operators
954  */
955  template<class T, class V, class M>
957  operator>=(const cuv::tensor<T, V, M>& v, const T cmp){
959  cuv::apply_scalar_functor(temp, v, cuv::SF_GEQ, cmp);
960  return temp;
961  }
962  template<class T, class V, class M>
964  operator<=(const cuv::tensor<T, V, M>& v, const T cmp){
966  cuv::apply_scalar_functor(temp, v, cuv::SF_LEQ, cmp);
967  return temp;
968  }
969  template<class T, class V, class M>
971  operator>(const cuv::tensor<T, V, M>& v, const T cmp){
973  cuv::apply_scalar_functor(temp, v, cuv::SF_GT, cmp);
974  return temp;
975  }
976  template<class T, class V, class M>
978  operator<(const cuv::tensor<T, V, M>& v, const T cmp){
980  cuv::apply_scalar_functor(temp, v, cuv::SF_LT, cmp);
981  return temp;
982  }
983  template<class T, class V, class M>
985  operator==(const cuv::tensor<T, V, M>& v, const T cmp){
987  cuv::apply_scalar_functor(temp, v, cuv::SF_EQ, cmp);
988  return temp;
989  }
990  template<class T, class V, class M>
992  operator==(const cuv::tensor<T, V, M>& v, const cuv::tensor<T,V,M>& w){
994  cuv::apply_binary_functor(temp, v, w, cuv::BF_EQ);
995  return temp;
996  }
997  template<class T, class V, class M>
999  operator&&(const cuv::tensor<T, V, M>& v, const cuv::tensor<T,V,M>& w){
1000  cuv::tensor<T, V, M> temp(v.shape());
1001  cuv::apply_binary_functor(temp, v, w, cuv::BF_AND);
1002  return temp;
1003  }
1004  template<class T, class V, class M>
1006  operator||(const cuv::tensor<T, V, M>& v, const cuv::tensor<T,V,M>& w){
1007  cuv::tensor<T, V, M> temp(v.shape());
1008  cuv::apply_binary_functor(temp, v, w, cuv::BF_OR);
1009  return temp;
1010  }
1011 
1012 /*
1013  * compound binary operators (tensor, tensor)
1014  */
1015 
1016  template<class T, class V, class M>
1018  operator-=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1019  cuv::apply_binary_functor(v1,v2, cuv::BF_SUBTRACT);
1020  return v1;
1021  }
1022 
1023  template<class T, class V, class M>
1025  operator*=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1026  cuv::apply_binary_functor(v1,v2, cuv::BF_MULT);
1027  return v1;
1028  }
1029  template<class T, class V, class M>
1031  operator/=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1032  cuv::apply_binary_functor(v1,v2, cuv::BF_DIV);
1033  return v1;
1034  }
1035  template<class T, class V, class M>
1037  operator+=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1038  cuv::apply_binary_functor(v1,v2, cuv::BF_ADD);
1039  return v1;
1040  }
1041 
1042  template<class T, class V, class M>
1044  operator|=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1045  cuv::apply_binary_functor(v1,v2, cuv::BF_OR);
1046  return v1;
1047  }
1048  template<class T, class V, class M>
1050  operator&=(cuv::tensor<T, V, M>& v1, const cuv::tensor<T, V, M>& v2){
1051  cuv::apply_binary_functor(v1,v2, cuv::BF_AND);
1052  return v1;
1053  }
1054 
1055 /*
1056  * compound binary operators (tensor, scalar)
1057  */
1058 
1059  template<class T, class V, class M>
1061  operator-=(cuv::tensor<T, V, M>& v, const T& p){
1062  cuv::apply_scalar_functor(v, cuv::SF_SUBTRACT, p);
1063  return v;
1064  }
1065  template<class T, class V, class M>
1067  operator*=(cuv::tensor<T, V, M>& v, const T& p){
1068  cuv::apply_scalar_functor(v, cuv::SF_MULT, p);
1069  return v;
1070  }
1071 
1072  template<class T, class V, class M>
1074  operator/=(cuv::tensor<T, V, M>& v, const T& p){
1075  cuv::apply_scalar_functor(v, cuv::SF_DIV, p);
1076  return v;
1077  }
1078  template<class T, class V, class M>
1080  operator+=(cuv::tensor<T, V, M>& v, const T& p){
1081  cuv::apply_scalar_functor(v, cuv::SF_ADD, p);
1082  return v;
1083  }
1084 
1085 /*
1086  * unary operators (tensor)
1087  */
1088  template<class T, class V, class M>
1090  operator-(const cuv::tensor<T, V, M>& v){
1091  cuv::tensor<T, V, M> temp(v.shape());
1092  cuv::apply_scalar_functor(temp, v, cuv::SF_NEGATE);
1093  return temp;
1094  }
1095  template<class V, class M>
1097  operator!(const cuv::tensor<unsigned char, V, M>& v){
1099  temp = (unsigned char) 1;
1100  temp -= v;
1101  return temp;
1102  }
1103 
1104 
1105 #endif