Cyclops Tensor Framework
parallel arithmetic on multidimensional arrays
core.pyx
Go to the documentation of this file.
1 #import dereference and increment operators
2 import sys
3 from cython.operator cimport dereference as deref, preincrement as inc
4 from libc.stdint cimport int64_t
5 from libc.stdint cimport int32_t
6 from libc.stdint cimport int16_t
7 from libc.stdint cimport int8_t
8 #from libcpp.complex cimport double complex as double complex
9 #from libcpp.complex cimport complex
10 from libcpp.complex cimport *
11 ctypedef double complex complex128_t
12 ctypedef float complex complex64_t
13 from libc.stdlib cimport malloc, free
14 import numpy as np
15 import string
16 import collections
17 from copy import deepcopy
18 cimport numpy as cnp
19 #from std.functional cimport function
20 
21 import struct
22 
23 from libcpp cimport bool
24 from libc.stdint cimport int64_t
25 
26 cdef extern from "<functional>" namespace "std":
27  cdef cppclass function[dtype]:
28  function()
29  function(dtype)
30 
31 #class SYM(Enum):
32 # NS=0
33 # SY=1
34 # AS=2
35 # SH=3
36 cdef extern from "mpi.h":# namespace "MPI":
37  void MPI_Init(int * argc, char *** argv)
38  int MPI_Initialized(int *)
39  void MPI_Finalize()
40 
41 type_index = {}
42 type_index[np.bool] = 1
43 type_index[np.int32] = 2
44 type_index[np.int64] = 3
45 type_index[np.float32] = 4
46 type_index[np.float64] = 5
47 type_index[np.complex64] = 6
48 type_index[np.complex128] = 7
49 type_index[np.int16] = 8
50 type_index[np.int8] = 9
51 
52 cdef int is_mpi_init=0
53 MPI_Initialized(<int*>&is_mpi_init)
54 if is_mpi_init == 0:
55  MPI_Init(&is_mpi_init, <char***>NULL)
56 
57 def MPI_Stop():
58  """
59  Kill all working nodes.
60  """
61  MPI_Finalize()
62 
63 cdef extern from "ctf.hpp" namespace "CTF_int":
64  cdef cppclass algstrct:
65  char * addid()
66  char * mulid()
67 
68  cdef cppclass ctensor "CTF_int::tensor":
69  World * wrld
70  algstrct * sr
71  bool is_sparse
72  ctensor()
73  ctensor(ctensor * other, bool copy, bool alloc_data)
74  ctensor(ctensor * other, int * new_sym)
75  void prnt()
76  void set(char *)
77  int read(int64_t num_pair,
78  char * alpha,
79  char * beta,
80  char * data);
81  int read(int64_t num_pair,
82  char * alpha,
83  char * beta,
84  int64_t * inds,
85  char * data);
86  int write(int64_t num_pair,
87  char * alpha,
88  char * beta,
89  int64_t * inds,
90  char * data);
91  int write(int64_t num_pair,
92  char * alpha,
93  char * beta,
94  char * data);
95  int read_local(int64_t * num_pair,
96  char ** data)
97  int read_local(int64_t * num_pair,
98  int64_t ** inds,
99  char ** data)
100  int read_local_nnz(int64_t * num_pair,
101  int64_t ** inds,
102  char ** data)
103  void allread(int64_t * num_pair, char * data, bool unpack)
104  void slice(int *, int *, char *, ctensor *, int *, int *, char *)
105  int64_t get_tot_size(bool packed)
106  void get_raw_data(char **, int64_t * size)
107  int permute(ctensor * A, int ** permutation_A, char * alpha, int ** permutation_B, char * beta)
108  void conv_type[dtype_A,dtype_B](ctensor * B)
109  void compare_elementwise[dtype](ctensor * A, ctensor * B)
110  void not_equals[dtype](ctensor * A, ctensor * B)
111  void smaller_than[dtype](ctensor * A, ctensor * B)
112  void smaller_equal_than[dtype](ctensor * A, ctensor * B)
113  void larger_than[dtype](ctensor * A, ctensor * B)
114  void larger_equal_than[dtype](ctensor * A, ctensor * B)
115  void exp_helper[dtype_A,dtype_B](ctensor * A)
116  void read_sparse_from_file[dtype](char * fpath, bool with_vals)
117  void write_sparse_to_file[dtype](char * fpath, bool with_vals)
118  void read_dense_from_file(char *)
119  void write_dense_to_file(char *)
120  void true_divide[dtype](ctensor * A)
121  void pow_helper_int[dtype](ctensor * A, int p)
122  int sparsify(char * threshold, int take_abs)
123 
124  cdef cppclass Term:
125  Term * clone();
126  Contract_Term operator*(double scl);
127  Contract_Term operator*(Term A);
128  Sum_Term operator+(Term A);
129  Sum_Term operator-(Term A);
130  void operator<<(double scl);
131  void operator<<(Term B);
132  void mult_scl(char *);
133 
134 
135  cdef cppclass Sum_Term(Term):
136  Sum_Term(Term * B, Term * A);
137  Sum_Term operator+(Term A);
138  Sum_Term operator-(Term A);
139 
140  cdef cppclass Contract_Term(Term):
141  Contract_Term(Term * B, Term * A);
142  Contract_Term operator*(double scl);
143  Contract_Term operator*(Term A);
144 
145  cdef cppclass endomorphism:
146  endomorphism()
147 
148  cdef cppclass univar_function:
150 
151  cdef cppclass bivar_function:
153 
154  cdef cppclass Endomorphism[dtype_A](endomorphism):
155  Endomorphism(function[void(dtype_A&)] f_);
156 
157  cdef cppclass Univar_Transform[dtype_A,dtype_B](univar_function):
158  Univar_Transform(function[void(dtype_A,dtype_B&)] f_);
159 
160  cdef cppclass Bivar_Transform[dtype_A,dtype_B,dtype_C](bivar_function):
161  Bivar_Transform(function[void(dtype_A,dtype_B,dtype_C&)] f_);
162 
163 cdef extern from "../ctf_ext.h" namespace "CTF_int":
164  cdef int64_t sum_bool_tsr(ctensor *);
165  cdef void pow_helper[dtype](ctensor * A, ctensor * B, ctensor * C, char * idx_A, char * idx_B, char * idx_C);
166  cdef void abs_helper[dtype](ctensor * A, ctensor * B);
167  cdef void all_helper[dtype](ctensor * A, ctensor * B_bool, char * idx_A, char * idx_B)
168  cdef void conj_helper[dtype](ctensor * A, ctensor * B);
169  cdef void any_helper[dtype](ctensor * A, ctensor * B_bool, char * idx_A, char * idx_B)
170  cdef void get_real[dtype](ctensor * A, ctensor * B)
171  cdef void get_imag[dtype](ctensor * A, ctensor * B)
172  cdef void set_real[dtype](ctensor * A, ctensor * B)
173  cdef void set_imag[dtype](ctensor * A, ctensor * B)
174  cdef void subsample(ctensor * A, double probability)
175  cdef void matrix_svd(ctensor * A, ctensor * U, ctensor * S, ctensor * VT, int rank)
176  cdef void matrix_svd_cmplx(ctensor * A, ctensor * U, ctensor * S, ctensor * VT, int rank)
177  cdef void matrix_qr(ctensor * A, ctensor * Q, ctensor * R)
178  cdef void matrix_qr_cmplx(ctensor * A, ctensor * Q, ctensor * R)
179  cdef void conv_type(int type_idx1, int type_idx2, ctensor * A, ctensor * B)
180 
181 cdef extern from "ctf.hpp" namespace "CTF":
182 
183  cdef cppclass World:
184  int rank, np;
185  World()
186  World(int)
187 
188  cdef cppclass Idx_Tensor(Term):
189  Idx_Tensor(ctensor *, char *);
190  void operator=(Term B);
191  void operator=(Idx_Tensor B);
192  void multeq(double scl);
193 
194  cdef cppclass Typ_Idx_Tensor[dtype](Idx_Tensor):
195  Typ_Idx_Tensor(ctensor *, char *)
196  void operator=(Term B)
197  void operator=(Idx_Tensor B)
198 
199  cdef cppclass Tensor[dtype](ctensor):
200  Tensor(int, bint, int *, int *)
201  Tensor(bool , ctensor)
202  void fill_random(dtype, dtype)
203  void fill_sp_random(dtype, dtype, double)
204  void read_sparse_from_file(char *, bool)
205  void write_sparse_to_file(char *, bool)
206  Typ_Idx_Tensor i(char *)
207  void read(int64_t, int64_t *, dtype *)
208  void read(int64_t, dtype, dtype, int64_t *, dtype *)
209  void read_local(int64_t *, int64_t **, dtype **)
210  void read_local_nnz(int64_t *, int64_t **, dtype **)
211  void write(int64_t, int64_t *, dtype *)
212  void write(int64_t, dtype, dtype, int64_t *, dtype *)
213  dtype norm1()
214  dtype norm2() # Frobenius norm
215  dtype norm_infty()
216 
217  cdef cppclass Vector[dtype](ctensor):
218  Vector()
219  Vector(Tensor[dtype] A)
220 
221  cdef cppclass Matrix[dtype](ctensor):
222  Matrix()
223  Matrix(Tensor[dtype] A)
224  Matrix(int, int)
225  Matrix(int, int, int)
226  Matrix(int, int, int, World)
227 
228  cdef cppclass contraction:
229  contraction(ctensor *, int *, ctensor *, int *, char *, ctensor *, int *, char *, bivar_function *)
230  void execute()
231 
232 
233 
234 #from enum import Enum
235 def _enum(**enums):
236  return type('Enum', (), enums)
237 
238 SYM = _enum(NS=0, SY=1, AS=2, SH=3)
239 
240 def _ord_comp(o1,o2):
241  i1 = 0
242  i2 = 0
243  if isinstance(o1,int):
244  i1 = o1
245  else:
246  i1 = ord(o1)
247  if isinstance(o2,int):
248  i2 = o2
249  else:
250  i2 = ord(o2)
251  return i1==i2
252 
253 def _get_np_div_dtype(typ1, typ2):
254  return (np.zeros(1,dtype=typ1)/np.ones(1,dtype=typ2)).dtype
255 
256 def _get_np_dtype(typs):
257  return np.sum([np.zeros(1,dtype=typ) for typ in typs]).dtype
258 
259 cdef char* char_arr_py_to_c(a):
260  cdef char * ca
261  dim = len(a)
262  ca = <char*> malloc(dim*sizeof(char))
263  if ca == NULL:
264  raise MemoryError()
265  for i in range(0,dim):
266  ca[i] = a[i]
267  return ca
268 
269 
270 cdef int64_t* int64_t_arr_py_to_c(a):
271  cdef int64_t * ca
272  dim = len(a)
273  ca = <int64_t*> malloc(dim*sizeof(int64_t))
274  if ca == NULL:
275  raise MemoryError()
276  for i in range(0,dim):
277  ca[i] = a[i]
278  return ca
279 
280 
281 cdef int* int_arr_py_to_c(a):
282  cdef int * ca
283  dim = len(a)
284  ca = <int*> malloc(dim*sizeof(int))
285  if ca == NULL:
286  raise MemoryError()
287  for i in range(0,dim):
288  ca[i] = a[i]
289  return ca
290 
291 #cdef char* interleave_py_pairs(a,b,typ):
292 # cdef cnp.ndarray buf = np.empty(len(a), dtype=[('a','i8'),('b',typ)])
293 # buf['a'] = a
294 # buf['b'] = b
295 # cdef char * dataptr = <char*>(buf.data.copy())
296 # return dataptr
297 #
298 #cdef void uninterleave_py_pairs(char * ca,a,b,typ):
299 # cdef cnp.ndarray buf = np.empty(len(a), dtype=[('a','i8'),('b',typ)])
300 # buf.data = ca
301 # a = buf['a']
302 # b = buf['b']
303 
304 cdef class comm:
305  cdef World * w
306  def __cinit__(self):
307  self.w = new World()
308 
309  def __dealloc__(self):
310  del self.w
311 
312  def rank(self):
313  return self.w.rank
314 
315  def np(self):
316  return self.w.np
317 
318 cdef class term:
319  cdef Term * tm
320  cdef cnp.dtype dtype
321  property dtype:
322  def __get__(self):
323  return self.dtype
324 
325  def scale(self, scl):
326  if isinstance(scl, (np.int, np.float, np.double, np.number)):
327  self.tm = (deref(self.tm) * <double>scl).clone()
328  else:
329  st = np.ndarray([],dtype=self.dtype).itemsize
330  beta = <char*>malloc(st)
331  b = np.asarray([scl],dtype=self.dtype)[0]
332  nb = np.array([b])
333  for j in range(0,st):
334  beta[j] = nb.view(dtype=np.int8)[j]
335  self.tm.mult_scl(beta)
336 
337  def __add__(self, other):
338  if other.dtype != self.dtype:
339  other = tensor(copy=other,dtype=self.dtype)
340  return sum_term(self,other)
341 
342  def __sub__(self, other):
343  if other.dtype != self.dtype:
344  other = tensor(copy=other,dtype=self.dtype)
345  other.scale(-1)
346  return sum_term(self,other)
347 
348 
349  def __mul__(first, second):
350  if (isinstance(first,term)):
351  if (isinstance(second,term)):
352  return contract_term(first,second)
353  else:
354  first.scale(second)
355  return first
356  else:
357  second.scale(first)
358  return second
359 
360  def __dealloc__(self):
361  del self.tm
362 
363  def conv_type(self, dtype):
364  raise ValueError("CTF PYTHON ERROR: in abstract conv_type function")
365 
366  def __repr__(self):
367  raise ValueError("CTF PYTHON ERROR: in abstract __repr__ function")
368 
369  def __lshift__(self, other):
370  if isinstance(other, term):
371  if other.dtype != self.dtype:
372  other.conv_type(self.dtype)
373  deref((<itensor>self).tm) << deref((<term>other).tm)
374  else:
375  tsr_copy = astensor(other,dtype=self.dtype)
376  deref((<itensor>self).tm) << deref(itensor(tsr_copy,"").it)
377 
378 
379 
380 cdef class contract_term(term):
381  cdef term a
382  cdef term b
383 
384  def __cinit__(self, term a, term b):
385  self.a = a
386  self.b = b
387  self.dtype = _get_np_dtype([a.dtype,b.dtype])
388  if self.dtype != a.dtype:
389  self.a.conv_type(self.dtype)
390  if self.dtype != b.dtype:
391  self.b.conv_type(self.dtype)
392  self.tm = new Contract_Term(self.a.tm.clone(), self.b.tm.clone())
393 
394  def conv_type(self, dtype):
395  self.a.conv_type(dtype)
396  self.b.conv_type(dtype)
397  self.dtype = dtype
398  del self.tm
399  self.tm = new Contract_Term(self.a.tm.clone(), self.b.tm.clone())
400 
401  def __repr__(self):
402  return "a is" + self.a.__repr__() + "b is" + self.b.__repr__()
403 
404 cdef class sum_term(term):
405  cdef term a
406  cdef term b
407 
408  def __cinit__(self, term a, term b):
409  self.a = a
410  self.b = b
411  self.dtype = _get_np_dtype([a.dtype,b.dtype])
412  if self.dtype != a.dtype:
413  self.a.conv_type(self.dtype)
414  if self.dtype != b.dtype:
415  self.b.conv_type(self.dtype)
416  self.tm = new Sum_Term(self.a.tm.clone(), self.b.tm.clone())
417 
418  def conv_type(self, dtype):
419  self.a.conv_type(dtype)
420  self.b.conv_type(dtype)
421  self.dtype = dtype
422  del self.tm
423  self.tm = new Sum_Term(self.a.tm.clone(), self.b.tm.clone())
424 
425  def __repr__(self):
426  return "a is" + self.a.__repr__() + "b is" + self.b.__repr__()
427 
428 
429 
430 cdef class itensor(term):
431  cdef Idx_Tensor * it
432  cdef tensor tsr
433  cdef str string
434 
435  property tsr:
436  def __get__(self):
437  return self.tsr
438  property string:
439  def __get__(self):
440  return self.string
441 
442  def conv_type(self, dtype):
443  self.tsr = tensor(copy=self.tsr,dtype=dtype)
444  self.it = new Idx_Tensor(self.tsr.dt, self.string.encode())
445  self.dtype = dtype
446  del self.tm
447  self.tm = self.it
448 
449  def __repr__(self):
450  return "tsr is" + self.tsr.__repr__()
451 
452  def __cinit__(self, tensor a, string):
453  self.it = new Idx_Tensor(a.dt, string.encode())
454  self.tm = self.it
455  self.tsr = a
456  self.string = string
457  self.dtype = a.dtype
458 
459  def __mul__(first, second):
460  if (isinstance(first,itensor)):
461  if (isinstance(second,term)):
462  return contract_term(first,second)
463  else:
464  first.scale(second)
465  return first
466  else:
467  if (isinstance(first,term)):
468  return contract_term(first,second)
469  else:
470  second.scale(first)
471  return second
472 
473  def scl(self, s):
474  self.it.multeq(<double>s)
475 
476 def _rev_array(arr):
477  if len(arr) == 1:
478  return arr
479  else:
480  arr2 = arr[::-1]
481  return arr2
482 
483 def _get_num_str(n):
484  allstr = "abcdefghijklmonpqrstuvwzyx0123456789,./;'][=-`"
485  return allstr[0:n]
486 
487 
488 cdef class tensor:
489  """
490  The class for CTF Python tensor.
491 
492  Attributes
493  ----------
494  nbytes: int
495  The number of bytes for the tensor.
496 
497  size: int
498  Total number of elements in the tensor.
499 
500  ndim: int
501  Number of dimensions.
502 
503  sp: int
504  0 indicates the tensor is not sparse tensor, 1 means the tensor is CTF sparse tensor.
505 
506  strides: tuple
507  Tuple of bytes for each dimension to traverse the tensor.
508 
509  shape: tuple
510  Tuple of each dimension.
511 
512  dtype: data-type
513  Numpy data-type, indicating the type of tensor.
514 
515  itemsize: int
516  One element in bytes.
517 
518  order: {'F','C'}
519  Bytes memory order for the tensor.
520 
521  sym: ndarray
522  ?
523 
524  Methods
525  -------
526 
527  T:
528  Transpose of tensor.
529 
530  all:
531  Whether all elements give an axis for a tensor is true.
532 
533  astype:
534  Copy the tensor to specified type.
535 
536  conj:
537  Return the self conjugate tensor element-wisely.
538 
539  copy:
540  Copy the tensor to a new tensor.
541 
542  diagonal:
543  Return the diagonal of the tensor if it is 2D. If the tensor is a higher order square tensor (same shape for every dimension), return diagonal of tensor determined by axis1=0, axis2=1.
544 
545  dot:
546  Return the dot product with tensor other.
547 
548  fill_random:
549  Fill random elements to the tensor.
550 
551  fill_sp_random:
552  Fill random elements to a sparse tensor.
553 
554  from_nparray:
555  Convert numpy ndarray to CTF tensor.
556 
557  get_dims:
558  Return the dims/shape of tensor.
559 
560  get_type:
561  Return the dtype of tensor.
562 
563  i:
564  Core function on summing the ctensor.
565 
566  imag:
567  Return imaginary part of a tensor or set its imaginary part to new value.
568 
569  norm1:
570  1-norm of the tensor.
571 
572  norm2:
573  2-norm of the tensor.
574 
575  norm_infty:
576  Infinity-norm of the tensor.
577 
578  permute:
579  Permute the tensor.
580 
581  prnt:
582  Function to print the non-zero elements and their indices of a tensor.
583 
584  ravel:
585  Return the flattened tensor.
586 
587  read:
588  Helper function on reading a tensor.
589 
590  read_all:
591  Helper function on reading a tensor.
592 
593  read_local:
594  Helper function on reading a tensor.
595 
596  read_local_nnz:
597  Helper function on reading a tensor.
598 
599  real:
600  Return real part of a tensor or set its real part to new value.
601 
602  reshape:
603  Return a new tensor with reshaped shape.
604 
605  sample:
606  Extract a sample of the entries (if sparse of the current nonzeros) by keeping each entry with probability p. Also transforms tensor into sparse format if not already.
607 
608  set_all:
609  Set all elements in a tensor to a value.
610 
611  set_zero:
612  Set all elements in a tensor to 0.
613 
614  sum:
615  Sum of elements in tensor or along specified axis.
616 
617  take:
618  Take elements from a tensor along axis.
619 
620  tensordot:
621  Return the tensor dot product of two tensors along axes.
622 
623  to_nparray:
624  Convert the tensor to numpy array.
625 
626  trace:
627  Return the sum over the diagonal of the tensor.
628 
629  transpose:
630  Return the transposed tensor with specified order of axes.
631 
632  write:
633  Helper function on writing a tensor.
634 
635  write_all:
636  Helper function on writing a tensor.
637  """
638  cdef ctensor * dt
639  cdef int order
640  cdef int sp
641  cdef cnp.ndarray sym
642  cdef int ndim
643  cdef size_t size
644  cdef int itemsize
645  cdef size_t nbytes
646  cdef tuple strides
647  cdef cnp.dtype dtype
648  cdef tuple shape
649 
650  property strides:
651  """
652  Attribute strides. Tuple of bytes for each dimension to traverse the tensor.
653  """
654  def __get__(self):
655  return self.strides
656 
657  property nbytes:
658  """
659  Attribute nbytes. The number of bytes for the tensor.
660  """
661  def __get__(self):
662  return self.nbytes
663 
664  property itemsize:
665  """
666  Attribute itemsize. One element in bytes.
667  """
668  def __get__(self):
669  return self.itemsize
670 
671  property size:
672  """
673  Attribute size. Total number of elements in the tensor.
674  """
675  def __get__(self):
676  return self.size
677 
678  property ndim:
679  """
680  Attribute ndim. Number of dimensions.
681  """
682  def __get__(self):
683  return self.ndim
684 
685  property shape:
686  """
687  Attribute shape. Tuple of each dimension.
688  """
689  def __get__(self):
690  return self.shape
691 
692  property dtype:
693  """
694  Attribute dtype. Numpy data-type, indicating the type of tensor.
695  """
696  def __get__(self):
697  return self.dtype
698 
699  property order:
700  """
701  Attribute order. Bytes memory order for the tensor.
702  """
703  def __get__(self):
704  return chr(self.order)
705 
706  property sp:
707  """
708  Attribute sp. 0 indicates the tensor is not sparse tensor, 1 means the tensor is CTF sparse tensor.
709  """
710  def __get__(self):
711  return self.sp
712 
713  property sym:
714  """
715  Attribute sym. ?
716  """
717  def __get__(self):
718  return self.sym
719 
720  def _bool_sum(tensor self):
721  return sum_bool_tsr(self.dt)
722 
723  # convert the type of self and store the elements in self to B
724  def _convert_type(tensor self, tensor B):
725  conv_type(type_index[self.dtype], type_index[B.dtype], <ctensor*>self.dt, <ctensor*>B.dt);
726 
727  # get "shape" or dimensions of the ctensor
728  def get_dims(self):
729  """
730  tensor.get_dims()
731  Return the dims/shape of tensor.
732 
733  Returns
734  -------
735  output: tuple
736  Dims or shape of the tensor.
737 
738  """
739  return self.shape
740 
741  def get_type(self):
742  """
743  tensor.get_type()
744  Return the dtype of tensor.
745 
746  Returns
747  -------
748  output: data-type
749  Dtype of the tensor.
750 
751  """
752  return self.dtype
753 
754  def __cinit__(self, lens=None, sp=None, sym=None, dtype=None, order=None, tensor copy=None):
755  if copy is None:
756  if lens is None:
757  lens = []
758  if sp is None:
759  sp = 0
760  if dtype is None:
761  dtype = np.float64
762  if order is None:
763  order = 'F'
764  else:
765  if isinstance(copy,tensor) == False:
766  copy = astensor(copy)
767  if lens is None:
768  lens = copy.shape
769  if sp is None:
770  sp = copy.sp
771  if sym is None:
772  sym = copy.sym
773  if dtype is None:
774  dtype = copy.dtype
775  if order is None:
776  order = copy.order
777  if isinstance(dtype,np.dtype):
778  dtype = dtype.type
779 
780  if dtype is int:
781  dtype = np.int64
782 
783  if dtype is float:
784  dtype = np.float64
785 
786  if dtype == np.complex:
787  dtype = np.complex128
788 
789 
790  if dtype == 'D':
791  self.dtype = <cnp.dtype>np.complex128
792  elif dtype == 'd':
793  self.dtype = <cnp.dtype>np.float64
794  else:
795  self.dtype = <cnp.dtype>dtype
796  if isinstance(lens,int):
797  lens = (lens,)
798  lens = [int(l) for l in lens]
799  self.shape = tuple(lens)
800  self.ndim = len(self.shape)
801  if isinstance(order,int):
802  self.order = order
803  else:
804  self.order = ord(order)
805  self.sp = sp
806  if sym is None:
807  self.sym = np.asarray([0]*self.ndim)
808  else:
809  self.sym = np.asarray(sym)
810  if self.dtype == np.bool:
811  self.itemsize = 1
812  else:
813  self.itemsize = np.dtype(self.dtype).itemsize
814  self.size = 1
815  for i in range(len(self.shape)):
816  self.size *= self.shape[i]
817  self.nbytes = self.size * self.itemsize
818  strides = [1] * len(self.shape)
819  for i in range(len(self.shape)-1, -1, -1):
820  if i == len(self.shape) -1:
821  strides[i] = self.itemsize
822  else:
823  strides[i] = self.shape[i+1] * strides[i+1]
824  self.strides = tuple(strides)
825  rlens = lens[:]
826  rsym = self.sym[:]
827  if _ord_comp(self.order, 'F'):
828  rlens = _rev_array(lens)
829  if self.ndim > 1:
830  rsym = _rev_array(self.sym)
831  rsym[0:-1] = rsym[1:]
832  rsym[-1] = SYM.NS
833  cdef int * clens
834  clens = int_arr_py_to_c(rlens)
835  cdef int * csym
836  csym = int_arr_py_to_c(rsym)
837  if copy is None:
838  if self.dtype == np.float64:
839  self.dt = new Tensor[double](self.ndim, sp, clens, csym)
840  elif self.dtype == np.complex64:
841  self.dt = new Tensor[complex64_t](self.ndim, sp, clens, csym)
842  elif self.dtype == np.complex128:
843  self.dt = new Tensor[complex128_t](self.ndim, sp, clens, csym)
844  elif self.dtype == np.bool:
845  self.dt = new Tensor[bool](self.ndim, sp, clens, csym)
846  elif self.dtype == np.int64:
847  self.dt = new Tensor[int64_t](self.ndim, sp, clens, csym)
848  elif self.dtype == np.int32:
849  self.dt = new Tensor[int32_t](self.ndim, sp, clens, csym)
850  elif self.dtype == np.int16:
851  self.dt = new Tensor[int16_t](self.ndim, sp, clens, csym)
852  elif self.dtype == np.int8:
853  self.dt = new Tensor[int8_t](self.ndim, sp, clens, csym)
854  elif self.dtype == np.float32:
855  self.dt = new Tensor[float](self.ndim, sp, clens, csym)
856  else:
857  raise ValueError('CTF PYTHON ERROR: bad dtype')
858  else:
859  if isinstance(copy, tensor):
860  if dtype is None or dtype == copy.dtype:
861  if np.all(sym == copy.sym):
862  self.dt = new ctensor(<ctensor*>copy.dt, True, True)
863  else:
864  self.dt = new ctensor(<ctensor*>copy.dt, csym)
865  else:
866  ccopy = tensor(self.shape, sp=self.sp, sym=self.sym, dtype=self.dtype, order=self.order)
867  copy._convert_type(ccopy)
868  self.dt = new ctensor(<ctensor*>ccopy.dt, True, True)
869  free(clens)
870  free(csym)
871 
872  def __dealloc__(self):
873  del self.dt
874 
875 
876  def T(self):
877  """
878  tensor.T(axes=None)
879  Permute the dimensions of the input tensor.
880 
881  Returns
882  -------
883  output: tensor
884  Tensor with permuted axes.
885 
886  See Also
887  --------
888  ctf: ctf.transpose
889 
890  Examples
891  --------
892  >>> import ctf
893  >>> a = ctf.zeros([3,4,5])
894  >>> a.shape
895  (3, 4, 5)
896  >>> a.T().shape
897  (5, 4, 3)
898  """
899  return transpose(self)
900 
901  def transpose(self, *axes):
902  """
903  tensor.transpose(*axes)
904  Return the transposed tensor with specified order of axes.
905 
906  Returns
907  -------
908  output: tensor
909  Tensor with permuted axes.
910 
911  See Also
912  --------
913  ctf: ctf.transpose
914 
915  Examples
916  --------
917  >>> import ctf
918  >>> a = ctf.zeros([3,4,5])
919  >>> a.shape
920  (3, 4, 5)
921  >>> a.transpose([2,1,0]).shape
922  (5, 4, 3)
923  """
924  if axes:
925  if isinstance(axes[0], (tuple, list, np.ndarray)):
926  return transpose(self, axes[0])
927  else:
928  return transpose(self, axes)
929  else:
930  return transpose(self)
931 
932  def _ufunc_interpret(self, tensor other, gen_tsr=True):
933  if self.order != other.order:
934  raise ValueError("Universal functions among tensors with different order, i.e. Fortran vs C are not currently supported")
935  out_order = self.order
936  out_dtype = _get_np_dtype([self.dtype, other.dtype])
937  out_dims = np.zeros(np.maximum(self.ndim, other.ndim), dtype=np.int)
938  out_sp = min(self.sp,other.sp)
939  out_sym = [SYM.NS]*len(out_dims)
940  ind_coll = _get_num_str(3*out_dims.size)
941  idx_C = ind_coll[0:out_dims.size]
942  idx_A = ""
943  idx_B = ""
944  red_idx_num = out_dims.size
945  for i in range(out_dims.size):
946  if i<self.ndim and i<other.ndim:
947  if self.shape[-i-1] == other.shape[-i-1]:
948  idx_A = idx_C[-i-1] + idx_A
949  idx_B = idx_C[-i-1] + idx_B
950  if i+1<self.ndim and i+1<other.ndim:
951  if self.sym[-i-2] == other.sym[-i-2]:
952  out_sym[-i-2] = self.sym[-i-2]
953  elif self.shape[-i-1] == 1:
954  idx_A = ind_coll[red_idx_num] + idx_A
955  red_idx_num += 1
956  idx_B = idx_C[-i-1] + idx_B
957  if i+1<other.ndim:
958  if i+1>=self.ndim or self.shape[-i-2] == 1:
959  out_sym[-i-2] = other.sym[-i-2]
960  elif other.shape[-i-1] == 1:
961  idx_A = idx_C[-i-1] + idx_A
962  idx_B = ind_coll[red_idx_num] + idx_B
963  red_idx_num += 1
964  if i+1<self.ndim:
965  if i+1>=other.ndim or other.shape[-i-2] == 1:
966  out_sym[-i-2] = self.sym[-i-2]
967  else:
968  raise ValueError("Invalid use of universal function broadcasting, tensor dimensions are both non-unit and don't match")
969  out_dims[-i-1] = np.maximum(self.shape[-i-1], other.shape[-i-1])
970  elif i<self.ndim:
971  idx_A = idx_C[-i-1] + idx_A
972  out_dims[-i-1] = self.shape[-i-1]
973  if i+1<self.ndim:
974  out_sym[-i-2] = self.sym[-i-2]
975  else:
976  idx_B = idx_C[-i-1] + idx_B
977  out_dims[-i-1] = other.shape[-i-1]
978  if i+1<other.ndim:
979  out_sym[-i-2] = other.sym[-i-2]
980  if gen_tsr is True:
981  out_tsr = tensor(out_dims, out_sp, out_sym, out_dtype, out_order)
982  else:
983  out_tsr = None
984  return [idx_A, idx_B, idx_C, out_tsr]
985 
986  # def __len__(self):
987  # if self.shape == ():
988  # raise TypeError("CTF PYTHON ERROR: len() of unsized object")
989  # return self.shape[0]
990 
991  def __abs__(self):
992  return abs(self)
993 
994  def __nonzero__(self):
995  if self.size != 1 and self.shape != ():
996  raise TypeError("CTF PYTHON ERROR: The truth value of a tensor with more than one element is ambiguous. Use ctf.any() or ctf.all()")
997  if int(self.to_nparray() == 0) == 1:
998  return False
999  else:
1000  return True
1001 
1002  def __int__(self):
1003  if self.size != 1 and self.shape != ():
1004  raise TypeError("CTF PYTHON ERROR: only length-1 tensors can be converted to Python scalars")
1005  return int(self.to_nparray())
1006 
1007  def __float__(self):
1008  if self.size != 1 and self.shape != ():
1009  raise TypeError("CTF PYTHON ERROR: only length-1 tensors can be converted to Python scalars")
1010  return float(self.to_nparray())
1011 
1012  # def __complex__(self, real, imag):
1013  # # complex() confliction in Cython?
1014  # return
1015 
1016  def __neg__(self):
1017  neg_one = astensor([-1], dtype=self.dtype)
1018  [tsr, otsr] = _match_tensor_types(self, neg_one)
1019  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
1020  out_tsr.i(idx_C) << tsr.i(idx_A)*otsr.i(idx_B)
1021  return out_tsr
1022 
1023  def __add__(self, other):
1024  [tsr, otsr] = _match_tensor_types(self,other)
1025 
1026  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
1027 
1028  out_tsr.i(idx_C) << tsr.i(idx_A)
1029  out_tsr.i(idx_C) << otsr.i(idx_B)
1030  return out_tsr
1031 
1032  def __iadd__(self, other_in):
1033  other = astensor(other_in)
1034  if np.result_type(self.dtype, other.dtype) != self.dtype:
1035  raise TypeError('CTF PYTHON ERROR: refusing to downgrade type within __iadd__ (+=), as done by numpy')
1036  [idx_A, idx_B, idx_C, out_tsr] = self._ufunc_interpret(other, False)
1037  if len(idx_C) != self.ndim:
1038  raise ValueError('CTF PYTHON ERROR: invalid call to __iadd__ (+=)')
1039  if self.dtype != other.dtype:
1040  [tsr, otsr] = _match_tensor_types(self,other) # solve the bug when np.float64 += np.int64
1041  self.i(idx_C) << otsr.i(idx_A)
1042  else:
1043  self.i(idx_C) << other.i(idx_A)
1044  return self
1045 
1046  def __mul__(self, other):
1047  [tsr, otsr] = _match_tensor_types(self,other)
1048 
1049  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
1050 
1051  out_tsr.i(idx_C) << tsr.i(idx_A)*otsr.i(idx_B)
1052  return out_tsr
1053 
1054  def __imul__(self, other_in):
1055  other = astensor(other_in)
1056  if np.result_type(self.dtype, other.dtype) != self.dtype:
1057  raise TypeError('CTF PYTHON ERROR: refusing to downgrade type within __imul__ (*=), as done by numpy')
1058  [idx_A, idx_B, idx_C, out_tsr] = self._ufunc_interpret(other, False)
1059  if len(idx_C) != self.ndim or idx_C != idx_A:
1060  raise ValueError('CTF PYTHON ERROR: invalid call to __imul__ (*=)')
1061  self_copy = tensor(copy=self)
1062  self.set_zero()
1063  self.i(idx_C) << self_copy.i(idx_A)*other.i(idx_B)
1064  return self
1065 
1066  def __sub__(self, other):
1067  [tsr, otsr] = _match_tensor_types(self,other)
1068 
1069  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
1070  out_tsr.i(idx_C) << tsr.i(idx_A)
1071  out_tsr.i(idx_C) << -1*otsr.i(idx_B)
1072  return out_tsr
1073 
1074  def __isub__(self, other_in):
1075  other = astensor(other_in)
1076  if np.result_type(self.dtype, other.dtype) != self.dtype:
1077  raise TypeError('CTF PYTHON ERROR: refusing to downgrade type within __isub__ (-=), as done by numpy')
1078  [idx_A, idx_B, idx_C, out_tsr] = self._ufunc_interpret(other, False)
1079  if len(idx_C) != self.ndim:
1080  raise ValueError('CTF PYTHON ERROR: invalid call to __isub__ (-=)')
1081  if self.dtype != other.dtype:
1082  [tsr, otsr] = _match_tensor_types(self,other) # solve the bug when np.float64 -= np.int64
1083  self.i(idx_C) << -1*otsr.i(idx_A)
1084  else:
1085  self.i(idx_C) << -1*other.i(idx_A)
1086  return self
1087 
1088  def __truediv__(self, other):
1089  return _div(self,other)
1090 
1091  def __itruediv__(self, other_in):
1092  other = astensor(other_in)
1093  if np.result_type(self.dtype, other.dtype) != self.dtype:
1094  raise TypeError('CTF PYTHON ERROR: refusing to downgrade type within __itruediv__ (/=), as done by numpy')
1095  [idx_A, idx_B, idx_C, out_tsr] = self._ufunc_interpret(other, False)
1096  if len(idx_C) != self.ndim or idx_C != idx_A:
1097  raise ValueError('CTF PYTHON ERROR: invalid call to __itruediv__ (/=)')
1098  if isinstance(other_in, tensor):
1099  otsr = tensor(copy=other)
1100  else:
1101  otsr = other
1102  otsr._invert_elements()
1103  self_copy = tensor(copy=self)
1104  self.set_zero()
1105  self.i(idx_C) << self_copy.i(idx_A)*otsr.i(idx_B)
1106  return self
1107 
1108  def __div__(self, other):
1109  return _div(self,other)
1110 
1111  def __idiv__(self, other_in):
1112  # same with __itruediv__
1113  other = astensor(other_in)
1114  if np.result_type(self.dtype, other.dtype) != self.dtype:
1115  raise TypeError('CTF PYTHON ERROR: refusing to downgrade type within __idiv__ (/=), as done by numpy')
1116  [idx_A, idx_B, idx_C, out_tsr] = self._ufunc_interpret(other, False)
1117  if len(idx_C) != self.ndim or idx_C != idx_A:
1118  raise ValueError('CTF PYTHON ERROR: invalid call to __idiv__ (/=)')
1119  if isinstance(other_in, tensor):
1120  otsr = tensor(copy=other)
1121  else:
1122  otsr = other
1123  otsr._invert_elements()
1124  self_copy = tensor(copy=self)
1125  self.set_zero()
1126  self.i(idx_C) << self_copy.i(idx_A)*otsr.i(idx_B)
1127  return self
1128 
1129  # def __floordiv__(self, other):
1130  # return
1131 
1132  # def __mod__(self, other):
1133  # return
1134 
1135  # def __divmod__(self):
1136  # return
1137 
1138  def __pow__(self, other, modulus):
1139  if modulus is not None:
1140  raise ValueError('CTF PYTHON ERROR: powering function does not accept third parameter (modulus)')
1141  return power(self,other)
1142 
1143  # def __ipow__(self, other_in):
1144  # [tsr, otsr] = _match_tensor_types(self, other)
1145 
1146  # [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
1147 
1148  # tensor_pow_helper(tsr, otsr, self, idx_A, idx_B, idx_C)
1149  # return self
1150 
1151 
1152  def _invert_elements(self):
1153  if self.dtype == np.float64:
1154  self.dt.true_divide[double](<ctensor*>self.dt)
1155  elif self.dtype == np.float32:
1156  self.dt.true_divide[float](<ctensor*>self.dt)
1157  elif self.dtype == np.complex64:
1158  self.dt.true_divide[complex64_t](<ctensor*>self.dt)
1159  elif self.dtype == np.complex128:
1160  self.dt.true_divide[complex128_t](<ctensor*>self.dt)
1161  elif self.dtype == np.int64:
1162  self.dt.true_divide[int64_t](<ctensor*>self.dt)
1163  elif self.dtype == np.int32:
1164  self.dt.true_divide[int32_t](<ctensor*>self.dt)
1165  elif self.dtype == np.int16:
1166  self.dt.true_divide[int16_t](<ctensor*>self.dt)
1167  elif self.dtype == np.int8:
1168  self.dt.true_divide[int8_t](<ctensor*>self.dt)
1169  elif self.dtype == np.bool:
1170  self.dt.true_divide[bool](<ctensor*>self.dt)
1171 
1172  def __matmul__(self, other):
1173  if not isinstance(other, tensor):
1174  raise ValueError("input should be tensors")
1175  return dot(self, other)
1176 
1177  def fill_random(self, mn=None, mx=None):
1178  """
1179  tensor.fill_random(mn=None, mx=None)
1180  Fill random elements to the tensor.
1181 
1182  Parameters
1183  ----------
1184  mn: int or float
1185  The range of random number from, default 0.
1186 
1187  mx: int or float
1188  The range of random number to, default 1.
1189 
1190  See Also
1191  --------
1192  ctf: ctf.tensor.fill_sp_random()
1193 
1194  Examples
1195  --------
1196  >>> import ctf
1197  >>> a = ctf.zeros([2, 2])
1198  >>> a
1199  array([[0., 0.],
1200  [0., 0.]])
1201  >>> a.fill_random(3,5)
1202  >>> a
1203  array([[3.31908598, 4.34013067],
1204  [4.5355426 , 4.6763659 ]])
1205  """
1206  if mn is None:
1207  mn = 0
1208  if mx is None:
1209  mx = 1
1210  if self.dtype == np.int32:
1211  (<Tensor[int32_t]*>self.dt).fill_random(mn,mx)
1212  elif self.dtype == np.int64:
1213  (<Tensor[int64_t]*>self.dt).fill_random(mn,mx)
1214  elif self.dtype == np.float32:
1215  (<Tensor[float]*>self.dt).fill_random(mn,mx)
1216  elif self.dtype == np.float64:
1217  (<Tensor[double]*>self.dt).fill_random(mn,mx)
1218  else:
1219  raise ValueError('CTF PYTHON ERROR: bad dtype')
1220 
1221  def fill_sp_random(self, mn=None, mx=None, frac_sp=None):
1222  """
1223  tensor.fill_sp_random(mn=None, mx=None, frac_sp=None)
1224  Fill random elements to a sparse tensor.
1225 
1226  Parameters
1227  ----------
1228  mn: int or float
1229  The range of random number from, default 0.
1230 
1231  mx: int or float
1232  The range of random number to, default 1.
1233 
1234  frac_sp: float
1235  The percent of non-zero elements.
1236 
1237  See Also
1238  --------
1239  ctf: ctf.tensor.fill_random()
1240 
1241  Examples
1242  --------
1243  >>> import ctf
1244  >>> a = ctf.tensor([3, 3], sp=1)
1245  >>> a.fill_sp_random(frac_sp=0.2)
1246  >>> a
1247  array([[0.96985989, 0. , 0. ],
1248  [0. , 0. , 0.10310342],
1249  [0. , 0. , 0. ]])
1250  """
1251  if mn is None:
1252  mn = 0
1253  if mx is None:
1254  mx = 1
1255  if frac_sp is None:
1256  frac_sp = .1
1257  if self.dtype == np.int32:
1258  (<Tensor[int32_t]*>self.dt).fill_sp_random(mn,mx,frac_sp)
1259  elif self.dtype == np.int64:
1260  (<Tensor[int64_t]*>self.dt).fill_sp_random(mn,mx,frac_sp)
1261  elif self.dtype == np.float32:
1262  (<Tensor[float]*>self.dt).fill_sp_random(mn,mx,frac_sp)
1263  elif self.dtype == np.float64:
1264  (<Tensor[double]*>self.dt).fill_sp_random(mn,mx,frac_sp)
1265  else:
1266  raise ValueError('CTF PYTHON ERROR: bad dtype')
1267 
1268  # read data from file, assumes different data storage format for sparse vs dense tensor
1269  # for dense tensor, file assumed to be binary, with entries stored in global order (no indices)
1270  # for sparse tensor, file assumed to be text, with entries stored as i_1 ... i_order val if with_vals=True
1271  # or i_1 ... i_order if with_vals=False
1272  def read_from_file(self, path, with_vals=True):
1273  if self.sp == True:
1274  if self.dtype == np.int32:
1275  (< Tensor[int32_t] * > self.dt).read_sparse_from_file(path, with_vals)
1276  elif self.dtype == np.int64:
1277  (< Tensor[int64_t] * > self.dt).read_sparse_from_file(path, with_vals)
1278  elif self.dtype == np.float32:
1279  (< Tensor[float] * > self.dt).read_sparse_from_file(path, with_vals)
1280  elif self.dtype == np.float64:
1281  (< Tensor[double] * > self.dt).read_sparse_from_file(path, with_vals)
1282  else:
1283  raise ValueError('CTF PYTHON ERROR: bad dtype')
1284  else:
1285  self.dt.read_dense_from_file(path)
1286 
1287  # write data to file, assumes different data storage format for sparse vs dense tensor
1288  # for dense tensor, file created is binary, with entries stored in global order (no indices)
1289  # for sparse tensor, file created is text, with entries stored as i_1 ... i_order val if with_vals=True
1290  # or i_1 ... i_order if with_vals=False
1291  def write_to_file(self, path, with_vals=True):
1292  if self.sp == True:
1293  if self.dtype == np.int32:
1294  (< Tensor[int32_t] * > self.dt).write_sparse_to_file(path, with_vals)
1295  elif self.dtype == np.int64:
1296  (< Tensor[int64_t] * > self.dt).write_sparse_to_file(path, with_vals)
1297  elif self.dtype == np.float32:
1298  (< Tensor[float] * > self.dt).write_sparse_to_file(path, with_vals)
1299  elif self.dtype == np.float64:
1300  (< Tensor[double] * > self.dt).write_sparse_to_file(path, with_vals)
1301  else:
1302  raise ValueError('CTF PYTHON ERROR: bad dtype')
1303  else:
1304  self.dt.write_dense_to_file(path)
1305 
1306 
1307  # the function that call the exp_helper in the C++ level
1308  def _exp_python(self, tensor A, cast = None, dtype = None):
1309  # when the casting is default that is "same kind"
1310  if cast is None:
1311  if A.dtype == np.int8:#
1312  self.dt.exp_helper[int8_t, double](<ctensor*>A.dt)
1313  elif A.dtype == np.int16:
1314  self.dt.exp_helper[int16_t, float](<ctensor*>A.dt)
1315  elif A.dtype == np.int32:
1316  self.dt.exp_helper[int32_t, double](<ctensor*>A.dt)
1317  elif A.dtype == np.int64:
1318  self.dt.exp_helper[int64_t, double](<ctensor*>A.dt)
1319  elif A.dtype == np.float16:#
1320  self.dt.exp_helper[int64_t, double](<ctensor*>A.dt)
1321  elif A.dtype == np.float32:
1322  self.dt.exp_helper[float, float](<ctensor*>A.dt)
1323  elif A.dtype == np.float64:
1324  self.dt.exp_helper[double, double](<ctensor*>A.dt)
1325  elif A.dtype == np.float128:#
1326  self.dt.exp_helper[double, double](<ctensor*>A.dt)
1327  else:
1328  raise ValueError("exponentiation not supported for these types")
1329 # elif A.dtype == np.complex64:
1330 # self.dt.exp_helper[complex64_t, complex64_t](<ctensor*>A.dt)
1331 # elif A.dtype == np.complex128:
1332 # self.dt.exp_helper[complex128_t, complex_128t](<ctensor*>A.dt)
1333  #elif A.dtype == np.complex256:#
1334  #self.dt.exp_helper[double complex, double complex](<ctensor*>A.dt)
1335  elif cast == 'unsafe':
1336  # we can add more types
1337  if A.dtype == np.int64 and dtype == np.float32:
1338  self.dt.exp_helper[int64_t, float](<ctensor*>A.dt)
1339  elif A.dtype == np.int64 and dtype == np.float64:
1340  self.dt.exp_helper[int64_t, double](<ctensor*>A.dt)
1341  else:
1342  raise ValueError("exponentiation not supported for these types")
1343  else:
1344  raise ValueError("exponentiation not supported for these types")
1345 
1346  # issue: when shape contains 1 such as [3,4,1], it seems that CTF in C++ does not support sum over empty dims -> sum over 1.
1347 
1348  def all(tensor self, axis=None, out=None, keepdims = None):
1349  """
1350  all(axis=None, out=None, keepdims = False)
1351  Return whether given an axis elements are True.
1352 
1353  Parameters
1354  ----------
1355  axis: None or int, optional
1356  Currently not supported in CTF Python.
1357 
1358  out: tensor, optional
1359  Currently not supported in CTF Python.
1360 
1361  keepdims : bool, optional
1362  Currently not supported in CTF Python.
1363 
1364  Returns
1365  -------
1366  output: tensor_like
1367  Output tensor or scalar.
1368 
1369  See Also
1370  --------
1371  ctf: ctf.all
1372 
1373  Examples
1374  --------
1375  >>> import ctf
1376  >>> a = ctf.astensor([[0, 1], [1, 1]])
1377  >>> a.all()
1378  False
1379  """
1380  if keepdims is None:
1381  keepdims = False
1382  if axis is None:
1383  if out is not None:
1384  if type(out) != np.ndarray:
1385  raise ValueError('CTF PYTHON ERROR: output must be an array')
1386  if out.shape != () and keepdims == False:
1387  raise ValueError('CTF PYTHON ERROR: output parameter has too many dimensions')
1388  if keepdims == True:
1389  dims_keep = []
1390  for i in range(len(self.shape)):
1391  dims_keep.append(1)
1392  dims_keep = tuple(dims_keep)
1393  if out.shape != dims_keep:
1394  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
1395  B = tensor((1,), dtype=np.bool)
1396  index_A = _get_num_str(self.ndim)
1397  if self.dtype == np.float64:
1398  all_helper[double](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1399  elif self.dtype == np.int64:
1400  all_helper[int64_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1401  elif self.dtype == np.int32:
1402  all_helper[int32_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1403  elif self.dtype == np.int16:
1404  all_helper[int16_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1405  elif self.dtype == np.int8:
1406  all_helper[int8_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1407  elif self.dtype == np.bool:
1408  all_helper[bool](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
1409  if out is not None:
1410  if out.dtype != B.get_type():
1411  if keepdims == True:
1412  dim_keep = np.ones(len(self.shape),dtype=np.int64)
1413  ret = reshape(B,dim_keep)
1414  C = tensor((1,), dtype=out.dtype)
1415  B._convert_type(C)
1416  vals = C.read([0])
1417  return vals.reshape(out.shape)
1418  else:
1419  raise ValueError("CTF PYTHON ERROR: invalid output dtype")
1420  #if keepdims == True:
1421  # dim_keep = np.ones(len(self.shape),dtype=np.int64)
1422  # ret = reshape(B,dim_keep)
1423  # return ret
1424  #inds, vals = B.read_local()
1425  #return vals.reshape(out.shape)
1426  if keepdims == True:
1427  dim_keep = np.ones(len(self.shape),dtype=np.int64)
1428  ret = reshape(B,dim_keep)
1429  return ret
1430  vals = B.read([0])
1431  return vals[0]
1432 
1433  # when the axis is not None
1434  dim = self.shape
1435  if isinstance(axis, (int, np.integer)):
1436  if axis < 0:
1437  axis += len(dim)
1438  if axis >= len(dim) or axis < 0:
1439  raise ValueError("'axis' entry is out of bounds")
1440  dim_ret = np.delete(dim, axis)
1441  if out is not None:
1442  if type(out) != np.ndarray:
1443  raise ValueError('CTF PYTHON ERROR: output must be an array')
1444  if len(dim_ret) != len(out.shape):
1445  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
1446  for i in range(len(dim_ret)):
1447  if dim_ret[i] != out.shape[i]:
1448  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
1449  dim_keep = None
1450  if keepdims == True:
1451  dim_keep = dim
1452  dim_keep[axis] = 1
1453  if out is not None:
1454  if tuple(dim_keep) != tuple(out.shape):
1455  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
1456  index_A = _get_num_str(self.ndim)
1457  index_temp = _rev_array(index_A)
1458  index_B = index_temp[0:axis] + index_temp[axis+1:len(dim)]
1459  index_B = _rev_array(index_B)
1460  B = tensor(dim_ret, dtype=np.bool)
1461  if self.dtype == np.float64:
1462  all_helper[double](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1463  elif self.dtype == np.int64:
1464  all_helper[int64_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1465  elif self.dtype == np.bool:
1466  all_helper[bool](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1467  elif self.dtype == np.int32:
1468  all_helper[int32_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1469  elif self.dtype == np.int16:
1470  all_helper[int16_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1471  elif self.dtype == np.int8:
1472  all_helper[int8_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1473  if out is not None:
1474  if out.dtype != B.get_type():
1475  if keepdims == True:
1476  C = tensor(dim_ret, dtype=out.dtype)
1477  B._convert_type(C)
1478  return reshape(C, dim_keep)
1479  else:
1480  C = tensor(dim_ret, dtype=out.dtype)
1481  B._convert_type(C)
1482  return C
1483  if keepdims == True:
1484  return reshape(B, dim_keep)
1485  return B
1486  elif isinstance(axis, (tuple, np.ndarray)):
1487  axis = np.asarray(axis, dtype=np.int64)
1488  dim_keep = None
1489  if keepdims == True:
1490  dim_keep = dim
1491  for i in range(len(axis)):
1492  dim_keep[axis[i]] = 1
1493  if out is not None:
1494  if tuple(dim_keep) is not tuple(out.shape):
1495  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
1496  for i in range(len(axis.shape)):
1497  if axis[i] < 0:
1498  axis[i] += len(dim)
1499  if axis[i] >= len(dim) or axis[i] < 0:
1500  raise ValueError("'axis' entry is out of bounds")
1501  for i in range(len(axis.shape)):
1502  if np.count_nonzero(axis==axis[i]) > 1:
1503  raise ValueError("duplicate value in 'axis'")
1504  dim_ret = np.delete(dim, axis)
1505  if out is not None:
1506  if type(out) is not np.ndarray:
1507  raise ValueError('CTF PYTHON ERROR: output must be an array')
1508  if len(dim_ret) is not len(out.shape):
1509  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
1510  for i in range(len(dim_ret)):
1511  if dim_ret[i] is not out.shape[i]:
1512  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
1513  B = tensor(dim_ret, dtype=np.bool)
1514  index_A = _get_num_str(self.ndim)
1515  index_temp = _rev_array(index_A)
1516  index_B = ""
1517  for i in range(len(dim)):
1518  if i not in axis:
1519  index_B += index_temp[i]
1520  index_B = _rev_array(index_B)
1521  if self.dtype == np.float64:
1522  all_helper[double](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1523  elif self.dtype == np.int64:
1524  all_helper[int64_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1525  elif self.dtype == np.int32:
1526  all_helper[int32_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1527  elif self.dtype == np.int16:
1528  all_helper[int16_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1529  elif self.dtype == np.int8:
1530  all_helper[int8_t](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1531  elif self.dtype == np.bool:
1532  all_helper[bool](<ctensor*>self.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
1533  if out is not None:
1534  if out.dtype is not B.get_type():
1535  if keepdims == True:
1536  C = tensor(dim_ret, dtype=out.dtype)
1537  B._convert_type(C)
1538  return reshape(C, dim_keep)
1539  else:
1540  C = tensor(dim_ret, dtype=out.dtype)
1541  B._convert_type(C)
1542  return C
1543  if keepdims == True:
1544  return reshape(B, dim_keep)
1545  return B
1546  else:
1547  raise ValueError("an integer is required")
1548 
1549  def i(self, string):
1550  """
1551  i(string)
1552  Core function on summing the ctensor.
1553 
1554  Parameters
1555  ----------
1556  string: string
1557  Dimensions for summation.
1558 
1559  Returns
1560  -------
1561  output: tensor_like
1562  Output tensor or scalar.
1563 
1564  Examples
1565  --------
1566  >>> import ctf
1567  >>> a = ctf.astensor([[1,2,3],[4,5,6]])
1568  >>> a.i("ij") << a.i("ij")
1569  >>> a
1570  array([[ 2, 4, 6],
1571  [ 8, 10, 12]])
1572  """
1573  if _ord_comp(self.order, 'F'):
1574  return itensor(self, _rev_array(string))
1575  else:
1576  return itensor(self, string)
1577 
1578  def prnt(self):
1579  """
1580  prnt()
1581  Function to print the non-zero elements and their indices of a tensor.
1582 
1583  Examples
1584  --------
1585  >>> import ctf
1586  >>> a = ctf.astensor([0,1,2,3,0])
1587  >>> a.prnt()
1588  Printing tensor ZYTP01
1589  [1](1, <1>)
1590  [2](2, <2>)
1591  [3](3, <3>)
1592  """
1593  self.dt.prnt()
1594 
1595  def real(self,tensor value = None):
1596  """
1597  real(value = None)
1598  Return real part of a tensor or set its real part to new value.
1599 
1600  Returns
1601  -------
1602  value: tensor_like
1603  The value tensor set real to the original tensor, current only support value tensor with dtype `np.float64` or `np.complex128`. Default is none.
1604 
1605  See Also
1606  --------
1607  ctf: ctf.reshape()
1608 
1609  Examples
1610  --------
1611  >>> import ctf
1612  >>> a = ctf.astensor([1+2j, 3+4j])
1613  >>> b = ctf.astensor([5,6], dtype=np.float64)
1614  >>> a.real(value = b)
1615  >>> a
1616  array([5.+2.j, 6.+4.j])
1617  """
1618  if value is None:
1619  if self.dtype == np.complex64:
1620  ret = tensor(self.shape, dtype=np.float32)
1621  get_real[float](<ctensor*>self.dt, <ctensor*>ret.dt)
1622  return self
1623  elif self.dtype == np.complex128:
1624  ret = tensor(self.shape, dtype=np.float64)
1625  get_real[double](<ctensor*>self.dt, <ctensor*>ret.dt)
1626  return ret
1627  else:
1628  return self.copy()
1629  else:
1630  if value.dtype != np.float64 and value.dtype != np.complex128:
1631  raise ValueError("CTF PYTHON ERROR: current CTF Python only support value in real function has the dtype np.float64 or np.complex128")
1632  if self.dtype == np.complex64:
1633  set_real[float](<ctensor*>value.dt, <ctensor*>self.dt)
1634  elif self.dtype == np.complex128:
1635  set_real[double](<ctensor*>value.dt, <ctensor*>self.dt)
1636  else:
1637  del self.dt
1638  self.__cinit__(copy=value)
1639 
1640  def imag(self,tensor value = None):
1641  """
1642  imag(value = None)
1643  Return imaginary part of a tensor or set its imaginary part to new value.
1644 
1645  Returns
1646  -------
1647  value: tensor_like
1648  The value tensor set imaginary to the original tensor, current only support value tensor with dtype `np.float64` or `np.complex128`. Default is none.
1649 
1650  See Also
1651  --------
1652  ctf: ctf.reshape()
1653 
1654  Examples
1655  --------
1656  >>> import ctf
1657  >>> a = ctf.astensor([1+2j, 3+4j])
1658  >>> b = ctf.astensor([5,6], dtype=np.float64)
1659  >>> a.imag(value = b)
1660  >>> a
1661  array([5.+2.j, 6.+4.j])
1662  """
1663  if value is None:
1664  if self.dtype == np.complex64:
1665  ret = tensor(self.shape, dtype=np.float32)
1666  get_imag[float](<ctensor*>self.dt, <ctensor*>ret.dt)
1667  return self
1668  elif self.dtype == np.complex128:
1669  ret = tensor(self.shape, dtype=np.float64)
1670  get_imag[double](<ctensor*>self.dt, <ctensor*>ret.dt)
1671  return ret
1672  elif self.dtype == np.float32:
1673  return zeros(self.shape, dtype=np.float32)
1674  elif self.dtype == np.float64:
1675  return zeros(self.shape, dtype=np.float64)
1676  else:
1677  raise ValueError("CTF ERROR: cannot call imag on non-complex/real single/double precision tensor")
1678  else:
1679  if value.dtype != np.float64 and value.dtype != np.complex128:
1680  raise ValueError("CTF PYTHON ERROR: current CTF Python only support value in imaginary function has the dtype np.float64 or np.complex128")
1681  if self.dtype == np.complex64:
1682  set_imag[float](<ctensor*>value.dt, <ctensor*>self.dt)
1683  elif self.dtype == np.complex128:
1684  set_imag[double](<ctensor*>value.dt, <ctensor*>self.dt)
1685  else:
1686  raise ValueError("CTF ERROR: cannot call imag with value on non-complex single/double precision tensor")
1687 
1688  def copy(self):
1689  """
1690  copy()
1691  Copy the tensor to a new tensor.
1692 
1693  Returns
1694  -------
1695  output: tensor_like
1696  Output copied tensor.
1697 
1698  Examples
1699  --------
1700  >>> import ctf
1701  >>> a = ctf.astensor([[1,2,3],[4,5,6]])
1702  >>> b = a.copy()
1703  >>> id(a) == id(b)
1704  False
1705  >>> a == b
1706  array([[ True, True, True],
1707  [ True, True, True]])
1708  """
1709  B = tensor(self.shape, dtype=self.dtype, copy=self)
1710  return B
1711 
1712  def reshape(self, *integer):
1713  """
1714  reshape(*integer)
1715  Return a new tensor with reshaped shape.
1716 
1717  Returns
1718  -------
1719  output: tensor_like
1720  Output reshaped tensor.
1721 
1722  See Also
1723  --------
1724  ctf: ctf.reshape()
1725 
1726  Examples
1727  --------
1728  >>> import ctf
1729  >>> a = ctf.astensor([[1,2,3],[4,5,6]])
1730  >>> a.reshape(6,1)
1731  array([[1],
1732  [2],
1733  [3],
1734  [4],
1735  [5],
1736  [6]])
1737  """
1738  dim = self.shape
1739  total_size = 1
1740  newshape = []
1741  if not isinstance(integer[0], (int, np.integer)):
1742  if len(integer)!=1:
1743  raise ValueError("CTF PYTHON ERROR: invalid shape argument to reshape")
1744  else:
1745  integer = integer[0]
1746 
1747  if isinstance(integer, (int, np.integer)):
1748  newshape.append(integer)
1749  elif isinstance(newshape, (tuple, list, np.ndarray)):
1750  for i in range(len(integer)):
1751  newshape.append(integer[i])
1752  else:
1753  raise ValueError("CTF PYTHON ERROR: invalid shape input to reshape")
1754  for i in range(len(dim)):
1755  total_size *= dim[i]
1756  newshape = np.asarray(newshape, dtype=np.int64)
1757  new_size = 1
1758  nega = 0
1759  for i in range(len(newshape)):
1760  if newshape[i] < 0:
1761  nega += 1
1762  if nega == 0:
1763  for i in range(len(newshape)):
1764  new_size *= newshape[i]
1765  if new_size != total_size:
1766  raise ValueError("CTF PYTHON ERROR: total size of new array must be unchanged")
1767  B = tensor(newshape,sp=self.sp,dtype=self.dtype)
1768  inds, vals = self.read_local_nnz()
1769  B.write(inds, vals)
1770  return B
1771  elif nega == 1:
1772  pos = 0
1773  for i in range(len(newshape)):
1774  if newshape[i] > 0:
1775  new_size *= newshape[i]
1776  else:
1777  pos = i
1778  nega_size = total_size / new_size
1779  if nega_size < 1:
1780  raise ValueError("can not reshape into this size")
1781  newshape[pos] = nega_size
1782  B = tensor(newshape,sp=self.sp,dtype=self.dtype)
1783  inds, vals = self.read_local_nnz()
1784  B.write(inds, vals)
1785  return B
1786  else:
1787  raise ValueError('CTF PYTHON ERROR: can only specify one unknown dimension')
1788  return None
1789 
1790  def ravel(self, order="F"):
1791  """
1792  ravel(order="F")
1793  Return the flattened tensor.
1794 
1795  Returns
1796  -------
1797  output: tensor_like
1798  Output flattened tensor.
1799 
1800  Examples
1801  --------
1802  >>> import ctf
1803  >>> a = ctf.astensor([[1,2,3],[4,5,6]])
1804  >>> a.ravel()
1805  array([1, 2, 3, 4, 5, 6])
1806  """
1807  return ravel(self, order)
1808 
1809  def read(self, init_inds, vals=None, a=None, b=None):
1810  """
1811  read(init_inds, vals=None, a=None, b=None)
1812  Helper function on reading a tensor.
1813  """
1814  inds = np.asarray(init_inds)
1815  #if each index is a tuple, we have a 2D array, convert it to 1D array of global indices
1816  if inds.ndim == 2:
1817  mystrides = np.ones(self.ndim,dtype=np.int32)
1818  for i in range(1,self.ndim):
1819  mystrides[self.ndim-i-1]=mystrides[self.ndim-i]*self.shape[self.ndim-i]
1820  inds = np.dot(inds, np.asarray(mystrides) )
1821  cdef char * ca
1822  if vals is not None:
1823  if vals.dtype != self.dtype:
1824  raise ValueError('CTF PYTHON ERROR: bad dtype of vals parameter to read')
1825  gvals = vals
1826  if vals is None:
1827  gvals = np.zeros(len(inds),dtype=self.dtype)
1828  #cdef cnp.ndarray buf = np.empty(len(inds), dtype=[('a','i8'),('b',self.dtype)],alignment=8)
1829  #buf['a'] = inds
1830  #buf['b'] = gvals
1831 
1832  cdef int64_t * cinds = int64_t_arr_py_to_c(inds)
1833  cdef char * cvals = char_arr_py_to_c(gvals.view(dtype=np.int8))
1834  cdef char * alpha
1835  cdef char * beta
1836  st = np.ndarray([],dtype=self.dtype).itemsize
1837  if a is None:
1838  alpha = <char*>self.dt.sr.mulid()
1839  else:
1840  alpha = <char*>malloc(st)
1841  na = np.array([a])
1842  for j in range(0,st):
1843  alpha[j] = na.view(dtype=np.int8)[j]
1844  if b is None:
1845  beta = <char*>self.dt.sr.addid()
1846  else:
1847  beta = <char*>malloc(st)
1848  nb = np.array([b])
1849  for j in range(0,st):
1850  beta[j] = nb.view(dtype=np.int8)[j]
1851  (<ctensor*>self.dt).read(len(inds),<char*>alpha,<char*>beta,cinds,cvals)
1852  for i in range(len(gvals.view(dtype=np.int8))):
1853  gvals.view(dtype=np.int8)[i]=cvals[i]
1854  if a is not None:
1855  free(alpha)
1856  if b is not None:
1857  free(beta)
1858  if vals is None:
1859  return gvals
1860 
1861  def astype(self, dtype, order='F', casting='unsafe'):
1862  """
1863  astype(dtype, order='F', casting='unsafe')
1864  Copy the tensor to specified type.
1865 
1866  Parameters
1867  ----------
1868  dtype: data-type
1869  Numpy data-type.
1870 
1871  order: {'F', 'C'}
1872  Bytes order for the tensor.
1873 
1874  casting: {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional
1875  Control the casting. Please refer to numpy.ndarray.astype, please refer to numpy.ndarray.astype for more information.
1876 
1877  Returns
1878  -------
1879  output: tensor
1880  Copied tensor with specified data-type.
1881 
1882  See Also
1883  --------
1884  numpy: numpy.ndarray.astype
1885 
1886  Examples
1887  --------
1888  >>> import ctf
1889  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
1890  >>> a.dtype
1891  <class 'numpy.int64'>
1892  >>> a.astype(np.float64).dtype
1893  <class 'numpy.float64'>
1894  """
1895  if dtype == 'D':
1896  return self.astype(np.complex128, order, casting)
1897  if dtype == 'd':
1898  return self.astype(np.float64, order, casting)
1899  if dtype == self.dtype:
1900  return self.copy()
1901  if casting == 'unsafe':
1902  # may add more types
1903  if dtype == int:
1904  dtype = np.int64
1905  if dtype == float:
1906  dtype = np.float64
1907  if str(dtype) == "<class 'bool'>":
1908  dtype = np.bool
1909  if str(dtype) == "<class 'complex'>":
1910  dtype = np.complex128
1911  B = tensor(self.shape, dtype = dtype)
1912  self._convert_type(B)
1913  return B
1914  elif casting == 'safe':
1915  if dtype == int:
1916  dtype = np.int64
1917  if dtype == float:
1918  dtype = np.float64
1919  # np.bool doesnot have itemsize
1920  if (self.dtype != np.bool and dtype != np.bool) and self.itemsize > dtype.itemsize:
1921  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'safe'".format(self.dtype,dtype))
1922  if dtype == np.bool and self.dtype != np.bool:
1923  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'safe'".format(self.dtype,dtype))
1924  str_self = str(self.dtype)
1925  str_dtype = str(dtype)
1926  if "float" in str_self and "int" in str_dtype:
1927  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'safe'".format(self.dtype,dtype))
1928  elif "complex" in str_self and ("int" in str_dtype or "float" in str_dtype):
1929  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'safe'".format(self.dtype,dtype))
1930  B = tensor(self.shape, dtype = dtype)
1931  self._convert_type(B)
1932  return B
1933  elif casting == 'equiv':
1934  # only allows byte-wise change
1935  if dtype == int:
1936  dtype = np.int64
1937  if dtype == float:
1938  dtype = np.float64
1939  if self.dtype != dtype:
1940  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'safe'".format(self.dtype,dtype))
1941  elif casting == 'no':
1942  if dtype == int:
1943  dtype = np.int64
1944  if dtype == float:
1945  dtype = np.float64
1946  if self.dtype != dtype:
1947  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'no'".format(self.dtype,dtype))
1948  B = tensor(self.shape, dtype = self.dtype, copy = self)
1949  return B
1950  elif casting == 'same_kind':
1951  if dtype == int:
1952  dtype = np.int64
1953  if dtype == float:
1954  dtype = np.float64
1955  str_self = str(self.dtype)
1956  str_dtype = str(dtype)
1957  if 'float' in str_self and 'int' in str_dtype:
1958  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'same_kind'".format(self.dtype,dtype))
1959  if 'complex' in str_self and ('int' in str_dtype or ('float' in str_dtype)):
1960  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'same_kind'".format(self.dtype,dtype))
1961  if self.dtype != np.bool and dtype == np.bool:
1962  raise ValueError("Cannot cast array from dtype({0}) to dtype({1}) according to the rule 'same_kind'".format(self.dtype,dtype))
1963  else:
1964  raise ValueError("casting must be one of 'no', 'equiv', 'safe', 'same_kind', or 'unsafe'")
1965 
1966  def read_local(self):
1967  """
1968  read_local()
1969  Helper function on reading a tensor.
1970  """
1971  cdef int64_t * cinds
1972  cdef char * cdata
1973  cdef int64_t n
1974  self.dt.read_local(&n,&cinds,&cdata)
1975  inds = np.empty(n, dtype=np.int64)
1976  vals = np.empty(n, dtype=self.dtype)
1977  for i in range(len(inds)):
1978  inds[i] = cinds[i]
1979  for i in range(len(vals.view(dtype=np.int8))):
1980  vals.view(dtype=np.int8)[i]=cdata[i]
1981  free(cinds)
1982  free(cdata)
1983 # cdef cnp.ndarray buf = np.empty(len(inds), dtype=[('a','i8'),('b',self.dtype)])
1984 # buf.data = data
1985 # vals = buf['b']
1986 # inds = buf['a']
1987  return inds, vals
1988 
1989  def dot(self, other, out=None):
1990  """
1991  dot(other, out=None)
1992  Return the dot product with tensor other.
1993 
1994  Parameters
1995  ----------
1996  other: tensor_like
1997  The other input tensor.
1998 
1999  out: tensor
2000  Currently not supported in CTF Python.
2001 
2002  Returns
2003  -------
2004  output: tensor
2005  Dot product of two tensors.
2006 
2007  See Also
2008  --------
2009  numpy: numpy.dot()
2010  ctf: ctf.dot()
2011 
2012  Examples
2013  --------
2014  >>> import ctf
2015  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
2016  >>> b = ctf.astensor([1,1,1])
2017  >>> a.dot(b)
2018  array([ 6, 15, 24])
2019  """
2020  return dot(self,other,out)
2021 
2022  def tensordot(self, other, axes):
2023  """
2024  tensordot(other, axes=2)
2025  Return the tensor dot product of two tensors along axes.
2026 
2027  Parameters
2028  ----------
2029  other: tensor_like
2030  Second input tensor.
2031 
2032  axes: int or array_like
2033  Sum over which axes.
2034 
2035  Returns
2036  -------
2037  output: tensor
2038  Tensor dot product of two tensors.
2039 
2040  See Also
2041  --------
2042  numpy: numpy.tensordot()
2043 
2044  Examples
2045  --------
2046  >>> import ctf
2047  >>> import numpy as np
2048  >>> a = np.arange(60.).reshape(3,4,5)
2049  >>> b = np.arange(24.).reshape(4,3,2)
2050  >>> a = ctf.astensor(a)
2051  >>> b = ctf.astensor(b)
2052  >>> a.tensordot(b, axes=([1,0],[0,1]))
2053  array([[4400., 4730.],
2054  [4532., 4874.],
2055  [4664., 5018.],
2056  [4796., 5162.],
2057  [4928., 5306.]])
2058  """
2059  return tensordot(self,other,axes)
2060 
2061 
2062  def read_local_nnz(self):
2063  """
2064  read_local_nnz()
2065  Helper function on reading a tensor.
2066  """
2067  cdef int64_t * cinds
2068  cdef char * cdata
2069  cdef int64_t n
2070  self.dt.read_local_nnz(&n,&cinds,&cdata)
2071  inds = np.empty(n, dtype=np.int64)
2072  vals = np.empty(n, dtype=self.dtype)
2073  for i in range(len(inds)):
2074  inds[i] = cinds[i]
2075  for i in range(len(vals.view(dtype=np.int8))):
2076  vals.view(dtype=np.int8)[i]=cdata[i]
2077  free(cinds)
2078  free(cdata)
2079 # cdef cnp.ndarray buf = np.empty(len(inds), dtype=[('a','i8'),('b',self.dtype)])
2080 # buf.data = data
2081 # vals = buf['b']
2082 # inds = buf['a']
2083  return inds, vals
2084 
2085  def _tot_size(self, unpack=True):
2086  return self.dt.get_tot_size(not unpack)
2087 
2088  def read_all(self, arr=None, unpack=True):
2089  """
2090  read_all(arr=None, unpack=True)
2091  Helper function on reading a tensor.
2092  """
2093  cdef char * cvals
2094  cdef int64_t sz
2095  sz = self.dt.get_tot_size(not unpack)
2096  tB = self.dtype.itemsize
2097  cvals = <char*> malloc(sz*tB)
2098  self.dt.allread(&sz, cvals, unpack)
2099  cdef cnp.ndarray buf = np.empty(sz, dtype=self.dtype)
2100  buf.data = cvals
2101  if arr is None:
2102  sbuf = np.asarray(buf)
2103  return buf
2104  else:
2105  arr[:] = buf[:]
2106  def write_all(self, arr):
2107  """
2108  write_all(arr)
2109  Helper function on writing a tensor.
2110  """
2111  cdef char * cvals
2112  cdef int64_t sz
2113  sz = self.dt.get_tot_size(False)
2114  tB = arr.dtype.itemsize
2115  self.dt.get_raw_data(&cvals, &sz)
2116  cdef cnp.ndarray buf = np.empty(sz, dtype=self.dtype)
2117  odata = buf.data
2118  buf.data = cvals
2119  rarr = arr.ravel()
2120  buf[:] = rarr[:]
2121  buf.data = odata
2122 
2123  def conj(self):
2124  """
2125  conj()
2126  Return the self conjugate tensor element-wisely.
2127 
2128  Returns
2129  -------
2130  output: tensor
2131  The element-wise complex conjugate of the tensor. If the tensor is not complex, just return a copy.
2132 
2133  Examples
2134  --------
2135  >>> import ctf
2136  >>> a = ctf.astensor([2+3j, 3-2j])
2137  >>> a
2138  array([2.+3.j, 3.-2.j])
2139  >>> a.conj()
2140  array([2.-3.j, 3.+2.j])
2141  """
2142  return conj(self)
2143 
2144  def permute(self, tensor A, p_A=None, p_B=None, a=None, b=None):
2145  """
2146  permute(self, tensor A, p_A=None, p_B=None, a=None, b=None)
2147  Permute the tensor.
2148  """
2149  if p_A is None and p_B is None:
2150  raise ValueError("CTF PYTHON ERROR: permute must be called with either p_A or p_B defined")
2151  if p_A is not None and p_B is not None:
2152  raise ValueError("CTF PYTHON ERROR: permute cannot be called with both p_A and p_B defined")
2153  cdef char * alpha
2154  cdef char * beta
2155  cdef int ** permutation_A = NULL
2156  cdef int ** permutation_B = NULL
2157  if p_A is not None:
2158 # p_A = np.asarray(p_A)
2159  permutation_A = <int**>malloc(sizeof(int*) * A.ndim)
2160  for i in range(self.ndim):
2161  if A.order == 'F':
2162  permutation_A[i] = <int*>malloc(sizeof(int) * A.shape[-i-1])
2163  for j in range(A.shape[-i-1]):
2164  permutation_A[i][j] = p_A[-i-1][j]
2165  else:
2166  permutation_A[i] = <int*>malloc(sizeof(int) * A.shape[i])
2167  for j in range(A.shape[i]):
2168  permutation_A[i][j] = p_A[i][j]
2169  if p_B is not None:
2170 # p_B = np.asarray(p_B)
2171  permutation_B = <int**>malloc(sizeof(int*) * self.ndim)
2172  for i in range(self.ndim):
2173  if self.order == 'F':
2174  permutation_B[i] = <int*>malloc(sizeof(int) * self.shape[-i-1])
2175  for j in range(self.shape[-i-1]):
2176  permutation_B[i][j] = p_B[-i-1][j]
2177  else:
2178  permutation_B[i] = <int*>malloc(sizeof(int) * self.shape[i])
2179  for j in range(self.shape[i]):
2180  permutation_B[i][j] = p_B[i][j]
2181  st = np.ndarray([],dtype=self.dtype).itemsize
2182  if a is None:
2183  alpha = <char*>self.dt.sr.mulid()
2184  else:
2185  alpha = <char*>malloc(st)
2186  na = np.array([a])
2187  for j in range(0,st):
2188  alpha[j] = na.view(dtype=np.int8)[j]
2189  if b is None:
2190  beta = <char*>self.dt.sr.addid()
2191  else:
2192  beta = <char*>malloc(st)
2193  nb = np.array([b])
2194  for j in range(0,st):
2195  beta[j] = nb.view(dtype=np.int8)[j]
2196  self.dt.permute(<ctensor*>A.dt, <int**>permutation_A, <char*>alpha, <int**>permutation_B, <char*>beta)
2197  if a is not None:
2198  free(alpha)
2199  if b is not None:
2200  free(beta)
2201  if p_A is not None:
2202  for i in range(0, sizeof(permutation_A), sizeof(int*)):
2203  free(permutation_A[i])
2204  free(permutation_A)
2205  if p_B is not None:
2206  for i in range(0, sizeof(permutation_B), sizeof(int*)):
2207  free(permutation_B[i])
2208  free(permutation_B)
2209 
2210  def write(self, init_inds, init_vals, a=None, b=None):
2211  """
2212  write(init_inds, init_vals, a=None, b=None)
2213  Helper function on writing a tensor.
2214  """
2215  inds = np.asarray(init_inds)
2216  vals = np.asarray(init_vals, dtype=self.dtype)
2217  #if each index is a tuple, we have a 2D array, convert it to 1D array of global indices
2218  if inds.ndim == 2:
2219  mystrides = np.ones(self.ndim,dtype=np.int32)
2220  for i in range(1,self.ndim):
2221  #mystrides[i]=mystrides[i-1]*self.shape[i-1]
2222  mystrides[self.ndim-i-1]=mystrides[self.ndim-i]*self.shape[self.ndim-i]
2223  inds = np.dot(inds, np.asarray(mystrides))
2224 
2225 # cdef cnp.ndarray buf = np.empty(len(inds), dtype=np.dtype([('a','i8'),('b',self.dtype)],align=False))
2226  cdef char * alpha
2227  cdef char * beta
2228  # if type is np.bool, assign the st with 1, since bool does not have itemsize in numpy
2229  if self.dtype == np.bool:
2230  st = 1
2231  else:
2232  st = self.itemsize
2233  if a is None:
2234  alpha = <char*>self.dt.sr.mulid()
2235  else:
2236  alpha = <char*>malloc(st)
2237  na = np.array([a])
2238  for j in range(0,st):
2239  alpha[j] = na.view(dtype=np.int8)[j]
2240  if b is None:
2241  beta = <char*>self.dt.sr.addid()
2242  else:
2243  beta = <char*>malloc(st)
2244  nb = np.array([b])
2245  for j in range(0,st):
2246  beta[j] = nb.view(dtype=np.int8)[j]
2247  cdef int64_t * cinds = int64_t_arr_py_to_c(inds)
2248  cdef char * cvals = char_arr_py_to_c(vals.view(dtype=np.int8))
2249  self.dt.write(len(inds),alpha,beta,cinds,cvals)
2250 
2251  if a is not None:
2252  free(alpha)
2253  if b is not None:
2254  free(beta)
2255 
2256  def _get_slice(self, offsets, ends):
2257  cdef char * alpha
2258  cdef char * beta
2259  alpha = <char*>self.dt.sr.mulid()
2260  beta = <char*>self.dt.sr.addid()
2261  if self.sp == 0:
2262  A = tensor(np.asarray(ends)-np.asarray(offsets), dtype=self.dtype)
2263  else:
2264  A = tensor(np.asarray(ends)-np.asarray(offsets), dtype=self.dtype, sp=1)
2265  cdef int * clens
2266  cdef int * coffs
2267  cdef int * cends
2268  if _ord_comp(self.order, 'F'):
2269  clens = int_arr_py_to_c(_rev_array(A.shape))
2270  coffs = int_arr_py_to_c(_rev_array(offsets))
2271  cends = int_arr_py_to_c(_rev_array(ends))
2272  czeros = int_arr_py_to_c(np.zeros(len(self.shape), dtype=np.int32))
2273  else:
2274  clens = int_arr_py_to_c(A.shape)
2275  coffs = int_arr_py_to_c(offsets)
2276  cends = int_arr_py_to_c(ends)
2277  czeros = int_arr_py_to_c(np.zeros(len(self.shape), dtype=np.int32))
2278  A.dt.slice(czeros, clens, beta, self.dt, coffs, cends, alpha)
2279  free(czeros)
2280  free(cends)
2281  free(coffs)
2282  free(clens)
2283  return A
2284 
2285  def _write_slice(self, offsets, ends, init_A, A_offsets=None, A_ends=None, a=None, b=None):
2286  cdef char * alpha
2287  cdef char * beta
2288  A = astensor(init_A)
2289  st = self.itemsize
2290  if a is None:
2291  alpha = <char*>self.dt.sr.mulid()
2292  else:
2293  alpha = <char*>malloc(st)
2294  na = np.array([a],dtype=self.dtype)
2295  for j in range(0,st):
2296  alpha[j] = na.view(dtype=np.int8)[j]
2297  if b is None:
2298  beta = <char*>self.dt.sr.addid()
2299  else:
2300  beta = <char*>malloc(st)
2301  nb = np.array([b])
2302  for j in range(0,st):
2303  beta[j] = nb.view(dtype=np.int8)[j]
2304  cdef int * caoffs
2305  cdef int * caends
2306 
2307  cdef int * coffs
2308  cdef int * cends
2309  if _ord_comp(self.order, 'F'):
2310  if A_offsets is None:
2311  caoffs = int_arr_py_to_c(_rev_array(np.zeros(len(self.shape), dtype=np.int32)))
2312  else:
2313  caoffs = int_arr_py_to_c(_rev_array(A_offsets))
2314  if A_ends is None:
2315  caends = int_arr_py_to_c(_rev_array(A.shape))
2316  else:
2317  caends = int_arr_py_to_c(_rev_array(A_ends))
2318  coffs = int_arr_py_to_c(_rev_array(offsets))
2319  cends = int_arr_py_to_c(_rev_array(ends))
2320  else:
2321  if A_offsets is None:
2322  caoffs = int_arr_py_to_c(np.zeros(len(self.shape), dtype=np.int32))
2323  else:
2324  caoffs = int_arr_py_to_c(A_offsets)
2325  if A_ends is None:
2326  caends = int_arr_py_to_c(A.shape)
2327  else:
2328  caends = int_arr_py_to_c(A_ends)
2329  coffs = int_arr_py_to_c(offsets)
2330  cends = int_arr_py_to_c(ends)
2331  #coffs = int_arr_py_to_c(offsets)
2332  #cends = int_arr_py_to_c(ends)
2333  self.dt.slice(coffs, cends, beta, (<tensor>A).dt, caoffs, caends, alpha)
2334  free(cends)
2335  free(coffs)
2336  if a is not None:
2337  free(alpha)
2338  if b is not None:
2339  free(beta)
2340  free(caends)
2341  free(caoffs)
2342 
2343  def __deepcopy__(self, memo):
2344  return tensor(self.shape, copy=self)
2345 
2346  # implements basic indexing and slicing as per numpy.ndarray
2347  # indexing can be done to different values with each process, as it produces a local scalar, but slicing must be the same globally, as it produces a global CTF ctensor
2348  def __getitem__(self, key_init):
2349  [key, is_everything, is_single_val, is_contig, inds, corr_shape, one_shape] = _setgetitem_helper(self, key_init)
2350 
2351  if is_everything:
2352  return self
2353 
2354  if is_single_val:
2355  vals = self.read([key])
2356  return vals[0]
2357 
2358  if is_contig:
2359  offs = [ind[0] for ind in inds]
2360  ends = [ind[1] for ind in inds]
2361  S = self._get_slice(offs,ends).reshape(corr_shape)
2362  return S
2363  else:
2364  pB = []
2365  for i in range(self.ndim):
2366  pB.append(np.arange(inds[i][0],inds[i][1],inds[i][2],dtype=int))
2367  if self.sp == 0:
2368  tsr = tensor(one_shape, dtype=self.dtype, order=self.order)
2369  else:
2370  tsr = tensor(one_shape, dtype=self.dtype, order=self.order, sp=1)
2371  tsr.permute(self, p_B=pB)
2372  return tsr.reshape(corr_shape)
2373 
2374  def set_zero(self):
2375  mystr = _get_num_str(self.ndim)
2376  self.i(mystr).scl(0.0)
2377 
2378  def set_zero(self):
2379  """
2380  set_zero()
2381  Set all elements in a tensor to zero.
2382 
2383  Examples
2384  --------
2385  >>> import ctf
2386  >>> a = ctf.astensor([1,2,3])
2387  >>> a.set_zero()
2388  >>> a
2389  array([0, 0, 0])
2390  """
2391  mystr = _get_num_str(self.ndim)
2392  self.i(mystr).scl(0.0)
2393 
2394  def set_all(self, value):
2395  """
2396  set_all(value)
2397  Set all elements in a tensor to a value.
2398 
2399  Parameters
2400  ----------
2401  value: scalar
2402  Value set to a tensor.
2403 
2404  Examples
2405  --------
2406  >>> import ctf
2407  >>> a = ctf.astensor([1,2,3])
2408  >>> a.set_all(3)
2409  >>> a
2410  array([3, 3, 3])
2411  """
2412  val = np.asarray([value],dtype=self.dtype)[0]
2413  cdef char * alpha
2414  st = self.itemsize
2415  alpha = <char*>malloc(st)
2416  na = np.array([val],dtype=self.dtype)
2417  for j in range(0,st):
2418  alpha[j] = na.view(dtype=np.int8)[j]
2419 
2420  self.dt.set(alpha)
2421 
2422  def __setitem__(self, key_init, value_init):
2423  value = deepcopy(value_init)
2424  [key, is_everything, is_single_val, is_contig, inds, corr_shape, one_shape] = _setgetitem_helper(self, key_init)
2425  if is_single_val:
2426  self.write([key],np.asarray(value,dtype=self.dtype))
2427  return
2428  if isinstance(value, (np.int, np.float, np.complex, np.number)):
2429  tval = np.asarray([value],dtype=self.dtype)[0]
2430  else:
2431  tval = astensor(value,dtype=self.dtype)
2432  if is_everything:
2433  #check that value is same everywhere, or this makes no sense
2434  if isinstance(tval,tensor):
2435  self.set_zero()
2436  self += value
2437  else:
2438  self.set_all(value)
2439  elif is_contig:
2440  offs = [ind[0] for ind in inds]
2441  ends = [ind[1] for ind in inds]
2442  tsr = tensor(corr_shape, dtype=self.dtype, order=self.order)
2443  if isinstance(tval,tensor):
2444  tsr += tval
2445  else:
2446  tsr.set_all(value)
2447  self._write_slice(offs,ends,tsr.reshape(one_shape))
2448  else:
2449  pA = []
2450  for i in range(self.ndim):
2451  pA.append(np.arange(inds[i][0],inds[i][1],inds[i][2],dtype=int))
2452  tsr = tensor(corr_shape, dtype=self.dtype, order=self.order)
2453  if isinstance(tval,tensor):
2454  tsr += tval
2455  else:
2456  tsr.set_all(value)
2457  self.permute(tsr.reshape(one_shape), pA)
2458 
2459  def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):
2460  """
2461  trace(offset=0, axis1=0, axis2=1, dtype=None, out=None)
2462  Return the sum over the diagonal of input tensor.
2463 
2464  Parameters
2465  ----------
2466  offset: int, optional
2467  Default is 0 which indicates the main diagonal.
2468 
2469  axis1: int, optional
2470  Default is 0 which indicates the first axis of 2-D tensor where diagonal is taken.
2471 
2472  axis2: int, optional
2473  Default is 1 which indicates the second axis of 2-D tensor where diagonal is taken.
2474 
2475  dtype: data-type, optional
2476  Numpy data-type, currently not supported in CTF Python trace().
2477 
2478  out: tensor
2479  Currently not supported in CTF Python trace().
2480 
2481  Returns
2482  -------
2483  output: tensor or scalar
2484  Sum along diagonal of input tensor.
2485 
2486  See Also
2487  --------
2488  ctf: ctf.trace()
2489 
2490  Examples
2491  --------
2492  >>> import ctf
2493  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
2494  >>> a.trace()
2495  15
2496  """
2497  return trace(self, offset, axis1, axis2, dtype, out)
2498 
2499  def diagonal(self, offset=0, axis1=0, axis2=1):
2500  """
2501  diagonal(offset=0, axis1=0, axis2=1)
2502  Return the diagonal of the tensor if it is 2D. If the tensor is a higher order square tensor (same shape for every dimension), return diagonal of tensor determined by axis1=0, axis2=1.
2503 
2504  Parameters
2505  ----------
2506  offset: int, optional
2507  Default is 0 which indicates the main diagonal.
2508 
2509  axis1: int, optional
2510  Default is 0 which indicates the first axis of 2-D tensor where diagonal is taken.
2511 
2512  axis2: int, optional
2513  Default is 1 which indicates the second axis of 2-D tensor where diagonal is taken.
2514 
2515  Returns
2516  -------
2517  output: tensor
2518  Diagonal of input tensor.
2519 
2520  Notes
2521  -----
2522  `ctf.diagonal` only supports diagonal of square tensor with order more than 2.
2523 
2524  Examples
2525  --------
2526  >>> import ctf
2527  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
2528  >>> a.diagonal()
2529  array([1, 5, 9])
2530  """
2531  return diagonal(self,offset,axis1,axis2)
2532 
2533  def sum(self, axis = None, dtype = None, out = None, keepdims = None):
2534  """
2535  sum(axis = None, dtype = None, out = None, keepdims = None)
2536  Sum of elements in tensor or along specified axis.
2537 
2538  Parameters
2539  ----------
2540  axis: None, int or tuple of ints
2541  Axis or axes where the sum of elements is performed.
2542 
2543  dtype: data-type, optional
2544  Data-type for the output tensor.
2545 
2546  out: tensor, optional
2547  Alternative output tensor.
2548 
2549  keepdims: None, bool, optional
2550  If set to true, axes summed over will remain size one.
2551 
2552  Returns
2553  -------
2554  output: tensor_like
2555  Output tensor.
2556 
2557  See Also
2558  --------
2559  numpy: numpy.sum()
2560 
2561  Examples
2562  --------
2563  >>> import ctf
2564  >>> a = ctf.ones([3,4], dtype=np.int64)
2565  >>> a.sum()
2566  12
2567  """
2568  return sum(self, axis, dtype, out, keepdims)
2569 
2570  def norm1(self):
2571  """
2572  norm1()
2573  1-norm of the tensor.
2574 
2575  Returns
2576  -------
2577  output: scalar
2578  1-norm of the tensor.
2579 
2580  Examples
2581  --------
2582  >>> import ctf
2583  >>> a = ctf.ones([3,4], dtype=np.float64)
2584  >>> a.norm1()
2585  12.0
2586  """
2587  if self.dtype == np.float64:
2588  return (<Tensor[double]*>self.dt).norm1()
2589  #if self.dtype == np.complex128:
2590  # return (<Tensor[double complex]*>self.dt).norm1()
2591  else:
2592  raise ValueError('CTF PYTHON ERROR: norm not present for this dtype')
2593 
2594  def norm2(self):
2595  """
2596  norm2()
2597  2-norm of the tensor.
2598 
2599  Returns
2600  -------
2601  output: scalar
2602  2-norm of the tensor.
2603 
2604  Examples
2605  --------
2606  >>> import ctf
2607  >>> a = ctf.ones([3,4], dtype=np.float64)
2608  >>> a.norm2()
2609  3.4641016151377544
2610  """
2611  if self.dtype == np.float64:
2612  return (<Tensor[double]*>self.dt).norm2()
2613  elif self.dtype == np.float32:
2614  return (<Tensor[float]*>self.dt).norm2()
2615  elif self.dtype == np.int64:
2616  return (<Tensor[int64_t]*>self.dt).norm2()
2617  elif self.dtype == np.int32:
2618  return (<Tensor[int32_t]*>self.dt).norm2()
2619  elif self.dtype == np.int16:
2620  return (<Tensor[int16_t]*>self.dt).norm2()
2621  elif self.dtype == np.int8:
2622  return (<Tensor[int8_t]*>self.dt).norm2()
2623 # elif self.dtype == np.complex128:
2624 # return (<Tensor[double complex]*>self.dt).norm2()
2625  else:
2626  raise ValueError('CTF PYTHON ERROR: norm not present for this dtype')
2627 
2628  def norm_infty(self):
2629  """
2630  norm_infty()
2631  Infinity norm of the tensor.
2632 
2633  Returns
2634  -------
2635  output: scalar
2636  Infinity norm of the tensor.
2637 
2638  Examples
2639  --------
2640  >>> import ctf
2641  >>> a = ctf.ones([3,4], dtype=np.float64)
2642  >>> a.norm_infty()
2643  1.0
2644  """
2645  if self.dtype == np.float64:
2646  return (<Tensor[double]*>self.dt).norm_infty()
2647 # elif self.dtype == np.complex128:
2648 # return (<Tensor[double complex]*>self.dt).norm_infty()
2649  else:
2650  raise ValueError('CTF PYTHON ERROR: norm not present for this dtype')
2651 
2652  def to_nparray(self):
2653  """
2654  to_nparray()
2655  Convert tensor to numpy ndarray.
2656 
2657  Returns
2658  -------
2659  output: ndarray
2660  Numpy ndarray of the tensor.
2661 
2662  Examples
2663  --------
2664  >>> import ctf
2665  >>> a = ctf.ones([3,4], dtype=np.float64)
2666  >>> a = ctf.ones([3,4])
2667  >>> a.to_nparray()
2668  array([[1., 1., 1., 1.],
2669  [1., 1., 1., 1.],
2670  [1., 1., 1., 1.]])
2671  """
2672  vals = np.zeros(self._tot_size(), dtype=self.dtype)
2673  self.read_all(vals)
2674  #return np.asarray(np.ascontiguousarray(np.reshape(vals, self.shape, order='F')),order='C')
2675  #return np.reshape(vals, _rev_array(self.shape)).transpose()
2676  return np.reshape(vals, self.shape)
2677  #return np.reshape(vals, self.shape, order='C')
2678 
2679  def __repr__(self):
2680  return repr(self.to_nparray())
2681 
2682  def from_nparray(self, arr):
2683  """
2684  from_nparray(arr)
2685  Convert numpy ndarray to CTF tensor.
2686 
2687  Returns
2688  -------
2689  output: tensor
2690  CTF tensor of the numpy ndarray.
2691 
2692  Examples
2693  --------
2694  >>> import ctf
2695  >>> import numpy as np
2696  >>> a = np.asarray([1.,2.,3.])
2697  >>> b = ctf.zeros([3, ])
2698  >>> b.from_nparray(a)
2699  >>> b
2700  array([1., 2., 3.])
2701  """
2702  if arr.dtype != self.dtype:
2703  raise ValueError('CTF PYTHON ERROR: bad dtype')
2704  if self.dt.wrld.np == 1:
2705  self.write_all(arr)
2706  elif self.dt.wrld.rank == 0:
2707  #self.write(np.arange(0,self._tot_size(),dtype=np.int64),np.asfortranarray(arr).flatten())
2708  #self.write(np.arange(0,self._tot_size(),dtype=np.int64),np.asfortranarray(arr).flatten())
2709  self.write(np.arange(0,self._tot_size(),dtype=np.int64),arr.ravel())
2710  else:
2711  self.write([], [])
2712 
2713  def take(self, indices, axis=None, out=None, mode='raise'):
2714  """
2715  take(indices, axis=None, out=None, mode='raise')
2716  Take elements from a tensor along axis.
2717 
2718  Parameters
2719  ----------
2720  indices: tensor_like
2721  Indices of the values wnat to be extracted.
2722 
2723  axis: int, optional
2724  Select values from which axis, default None.
2725 
2726  out: tensor
2727  Currently not supported in CTF Python take().
2728 
2729  mode: {‘raise’, ‘wrap’, ‘clip’}, optional
2730  Currently not supported in CTF Python take().
2731 
2732  Returns
2733  -------
2734  output: tensor or scalar
2735  Elements extracted from the input tensor.
2736 
2737  See Also
2738  --------
2739  numpy: numpy.take()
2740 
2741  Examples
2742  --------
2743  >>> import ctf
2744  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
2745  >>> a.take([0, 1, 2])
2746  array([1, 2, 3])
2747  """
2748  return take(self,indices,axis,out,mode)
2749 
2750  def __richcmp__(self, b, op):
2751  if isinstance(b,tensor):
2752  return self._compare_tensors(b,op)
2753  elif isinstance(b,np.ndarray):
2754  return self._compare_tensors(astensor(b),op)
2755  else:
2756  #A = tensor(self.shape,dtype=self.dtype)
2757  #A.set_all(b)
2758  #return self._compare_tensors(A,op)
2759  return self._compare_tensors(astensor(b,dtype=self.dtype),op)
2760 
2761  def sample(tensor self, p):
2762  """
2763  sample(p)
2764  Extract a sample of the entries (if sparse of the current nonzeros) by keeping each entry with probability p. Also transforms tensor into sparse format if not already.
2765 
2766  Parameters
2767  ----------
2768  p: float
2769  Probability that keep each entry.
2770 
2771  Returns
2772  -------
2773  output: tensor or scalar
2774  Elements extracted from the input tensor.
2775 
2776  Examples
2777  --------
2778  >>> import ctf
2779  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
2780  >>> a.sample(0.1)
2781  >>> a
2782  array([[0, 0, 3],
2783  [0, 0, 6],
2784  [0, 0, 0]])
2785  """
2786  subsample(self.dt, p)
2787 
2788  # change the operators "<","<=","==","!=",">",">=" when applied to tensors
2789  # also for each operator we need to add the template.
2790  def _compare_tensors(tensor self, tensor b, op):
2791  # <
2792  if op == 0:
2793  if self.dtype == np.float64:
2794  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2795  c.dt.smaller_than[double](<ctensor*>self.dt,<ctensor*>b.dt)
2796  elif self.dtype == np.bool:
2797  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2798  c.dt.smaller_than[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2799  else:
2800  raise ValueError('CTF PYTHON ERROR: bad dtype')
2801  return c
2802  # <=
2803  if op == 1:
2804  if self.dtype == np.float64:
2805  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2806  c.dt.smaller_equal_than[double](<ctensor*>self.dt,<ctensor*>b.dt)
2807  elif self.dtype == np.bool:
2808  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2809  c.dt.smaller_equal_than[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2810  else:
2811  raise ValueError('CTF PYTHON ERROR: bad dtype')
2812  return c
2813 
2814  # ==
2815  if op == 2:
2816  new_shape = []
2817  for i in range(min(self.ndim,b.ndim)):
2818  new_shape.append(self.shape[i])
2819  if b.shape[i] != new_shape[i]:
2820  raise ValueError('CTF PYTHON ERROR: bad dtype')
2821  for i in range(min(self.ndim,b.ndim),max(self.ndim,b.ndim)):
2822  if self.ndim > b.ndim:
2823  new_shape.append(self.shape[i])
2824  else:
2825  new_shape.append(b.shape[i])
2826 
2827  c = tensor(new_shape, dtype=np.bool, sp=self.sp)
2828  if self.dtype == np.float64:
2829  c.dt.compare_elementwise[double](<ctensor*>self.dt,<ctensor*>b.dt)
2830  elif self.dtype == np.float32:
2831  c.dt.compare_elementwise[float](<ctensor*>self.dt,<ctensor*>b.dt)
2832  elif self.dtype == np.complex64:
2833  c.dt.compare_elementwise[complex64_t](<ctensor*>self.dt,<ctensor*>b.dt)
2834  elif self.dtype == np.complex128:
2835  c.dt.compare_elementwise[complex128_t](<ctensor*>self.dt,<ctensor*>b.dt)
2836  elif self.dtype == np.int64:
2837  c.dt.compare_elementwise[int64_t](<ctensor*>self.dt,<ctensor*>b.dt)
2838  elif self.dtype == np.int32:
2839  c.dt.compare_elementwise[int32_t](<ctensor*>self.dt,<ctensor*>b.dt)
2840  elif self.dtype == np.int16:
2841  c.dt.compare_elementwise[int16_t](<ctensor*>self.dt,<ctensor*>b.dt)
2842  elif self.dtype == np.int8:
2843  c.dt.compare_elementwise[int8_t](<ctensor*>self.dt,<ctensor*>b.dt)
2844  elif self.dtype == np.bool:
2845  c.dt.compare_elementwise[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2846  else:
2847  raise ValueError('CTF PYTHON ERROR: bad dtype')
2848  return c
2849 
2850  # !=
2851  if op == 3:
2852  if self.dtype == np.float64:
2853  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2854  c.dt.not_equals[double](<ctensor*>self.dt,<ctensor*>b.dt)
2855  elif self.dtype == np.bool:
2856  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2857  c.dt.not_equals[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2858  else:
2859  raise ValueError('CTF PYTHON ERROR: bad dtype')
2860  return c
2861 
2862  # >
2863  if op == 4:
2864  if self.dtype == np.float64:
2865  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2866  print("shape is", c.shape)
2867  c.dt.larger_than[double](<ctensor*>self.dt,<ctensor*>b.dt)
2868  elif self.dtype == np.bool:
2869  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2870  print("shape is", c.shape)
2871  c.dt.larger_than[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2872  else:
2873  raise ValueError('CTF PYTHON ERROR: bad dtype')
2874  return c
2875 
2876  # >=
2877  if op == 5:
2878  if self.dtype == np.float64:
2879  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2880  c.dt.larger_equal_than[double](<ctensor*>self.dt,<ctensor*>b.dt)
2881  elif self.dtype == np.bool:
2882  c = tensor(self.shape, dtype=np.bool, sp=self.sp)
2883  c.dt.larger_equal_than[bool](<ctensor*>self.dt,<ctensor*>b.dt)
2884  else:
2885  raise ValueError('CTF PYTHON ERROR: bad dtype')
2886  return c
2887 
2888  #cdef int * inds
2889  #cdef function[equate_type] fbf
2890  #if op == 2:#Py_EQ
2891  #t = tensor(self.shape, np.bool)
2892  #inds = <int*>malloc(len(self.shape))
2893  #for i in range(len(self.shape)):
2894  #inds[i] = i
2895  #fbf = function[equate_type](equate)
2896  #f = Bivar_Transform[double,double,bool](fbf)
2897  #c = contraction(self.dt, inds, b.dt, inds, NULL, t.dt, inds, NULL, bf)
2898  #c.execute()
2899  #return t
2900  #if op == 3:#Py_NE
2901  # return not x.__is_equal(y)
2902  #else:
2903  #assert False
2904 
2905 def _trilSquare(tensor A):
2906  if not isinstance(A, tensor):
2907  raise ValueError('CTF PYTHON ERROR: A is not a tensor')
2908  if A.ndim != 2:
2909  raise ValueError('CTF PYTHON ERROR: A is not a matrix')
2910  if A.shape[0] != A.shape[1]:
2911  raise ValueError('CTF PYTHON ERROR: A is not a square matrix')
2912  cdef tensor B
2913  B = A.copy()
2914  cdef int * csym
2915  cdef int * csym2
2916  csym = int_arr_py_to_c(np.zeros([2], dtype=np.int32))
2917  csym2 = int_arr_py_to_c(np.asarray([2,0], dtype=np.int32))
2918  del B.dt
2919  cdef ctensor * ct
2920  ct = new ctensor(A.dt, csym2)
2921  B.dt = new ctensor(ct, csym)
2922  del ct
2923  return B
2924 
2925 def tril(A, k=0):
2926  """
2927  tril(A, k=0)
2928  Return lower triangle of a CTF tensor.
2929 
2930  Parameters
2931  ----------
2932  A: tensor_like
2933  2-D input tensor.
2934 
2935  k: int
2936  Specify last diagonal not zeroed. Default `k=0` which indicates elements under the main diagonal are zeroed.
2937 
2938  Returns
2939  -------
2940  output: tensor
2941  Lower triangular 2-d tensor of input tensor.
2942 
2943  Examples
2944  --------
2945  >>> import ctf
2946  >>> a = ctf.astensor([[1,2,3],[4,5,6],[7,8,9]])
2947  >>> ctf.tril(a, k=1)
2948  array([[1, 2, 0],
2949  [4, 5, 6],
2950  [7, 8, 9]])
2951  """
2952  k = -1-k
2953  if not isinstance(A, tensor):
2954  raise ValueError('CTF PYTHON ERROR: A is not a tensor')
2955  if A.ndim != 2:
2956  raise ValueError('CTF PYTHON ERROR: A is not a matrix')
2957  A = A.copy()
2958  if k >= 0:
2959  A[0:k,:] = 0
2960  if A.shape[0] != A.shape[1] or k != 0:
2961  B = A[ max(0, k) : min(k+A.shape[1],A.shape[0]), max(0, -k) : min(A.shape[1], A.shape[0] - k)]
2962  C = _trilSquare(B)
2963  A[ max(0, k) : min(k+A.shape[1],A.shape[0]), max(0, -k) : min(A.shape[1], A.shape[0] - k)] = C
2964  else:
2965  A = _trilSquare(A)
2966  return A
2967 
2968 def triu(A, k=0):
2969  """
2970  triu(A, k=0)
2971  Return upper triangle of a CTF tensor.
2972 
2973  Parameters
2974  ----------
2975  A: tensor_like
2976  2-D input tensor.
2977 
2978  k: int
2979  Specify last diagonal not zeroed. Default `k=0` which indicates elements under the main diagonal are zeroed.
2980 
2981  Returns
2982  -------
2983  output: tensor
2984  Upper triangular 2-d tensor of input tensor.
2985 
2986  Examples
2987  --------
2988  >>> import ctf
2989  >>> a = ctf.astensor([[1,2,3],[4,5,6],[7,8,9]])
2990  >>> ctf.triu(a, k=-1)
2991  array([[1, 2, 3],
2992  [4, 5, 6],
2993  [0, 8, 9]])
2994  """
2995  return transpose(tril(A.transpose(), -k))
2996 
2997 def real(tensor A):
2998  """
2999  real(A)
3000  Return the real part of the tensor elementwisely.
3001 
3002  Parameters
3003  ----------
3004  A: tensor_like
3005  Input tensor.
3006 
3007  Returns
3008  -------
3009  output: tensor
3010  A tensor with real part of the input tensor.
3011 
3012  See Also
3013  --------
3014  numpy : numpy.real()
3015 
3016  Notes
3017  -----
3018  The input should be a CTF tensor.
3019 
3020  Examples
3021  --------
3022  >>> import ctf
3023  >>> a = ctf.astensor([1+2j, 3+4j, 5+6j, 7+8j])
3024  >>> a
3025  array([1.+2.j, 3.+4.j, 5.+6.j, 7.+8.j])
3026  >>> ctf.real(a)
3027  array([1., 3., 5., 7.])
3028  """
3029  if not isinstance(A, tensor):
3030  raise ValueError('CTF PYTHON ERROR: A is not a tensor')
3031  if A.get_type() != np.complex64 and A.get_type() != np.complex128 and A.get_type() != np.complex256:
3032  return A
3033  else:
3034  ret = tensor(A.shape, dtype = np.float64)
3035  get_real[double](<ctensor*>A.dt, <ctensor*>ret.dt)
3036  return ret
3037 
3038 def imag(tensor A):
3039  """
3040  imag(A)
3041  Return the image part of the tensor elementwisely.
3042 
3043  Parameters
3044  ----------
3045  A: tensor_like
3046  Input tensor.
3047 
3048  Returns
3049  -------
3050  output: tensor
3051  A tensor with real part of the input tensor.
3052 
3053  See Also
3054  --------
3055  numpy : numpy.imag()
3056 
3057  Notes
3058  -----
3059  The input should be a CTF tensor.
3060 
3061  Examples
3062  --------
3063  >>> import ctf
3064  >>> a = ctf.astensor([1+2j, 3+4j, 5+6j, 7+8j])
3065  >>> a
3066  array([1.+2.j, 3.+4.j, 5.+6.j, 7.+8.j])
3067  >>> ctf.imag(a)
3068  array([2., 4., 6., 8.])
3069  """
3070  if not isinstance(A, tensor):
3071  raise ValueError('CTF PYTHON ERROR: A is not a tensor')
3072  if A.get_type() != np.complex64 and A.get_type() != np.complex128 and A.get_type() != np.complex256:
3073  return zeros(A.shape, dtype=A.get_type())
3074  else:
3075  ret = tensor(A.shape, dtype = np.float64)
3076  get_imag[double](<ctensor*>A.dt, <ctensor*>ret.dt)
3077  return ret
3078 
3079 def array(A, dtype=None, copy=True, order='K', subok=False, ndmin=0):
3080  """
3081  array(A, dtype=None, copy=True, order='K', subok=False, ndmin=0)
3082  Create a tensor.
3083 
3084  Parameters
3085  ----------
3086  A: tensor_like
3087  Input tensor like object.
3088 
3089  dtype: data-type, optional
3090  The desired data-type for the tensor. If the dtype is not specified, the dtype will be determined as `np.array()`.
3091 
3092  copy: bool, optional
3093  If copy is true, the object is copied.
3094 
3095  order: {‘K’, ‘A’, ‘C’, ‘F’}, optional
3096  Specify the memory layout for the tensor.
3097 
3098  subok: bool, optional
3099  Currently subok is not supported in `ctf.array()`.
3100 
3101  ndmin: int, optional
3102  Currently ndmin is not supported in `ctf.array()`.
3103 
3104  Returns
3105  -------
3106  output: tensor
3107  A tensor object with specified requirements.
3108 
3109  See Also
3110  --------
3111  ctf : ctf.astensor()
3112 
3113  Notes
3114  -----
3115  The input of ctf.array() should be tensor or numpy.ndarray
3116 
3117  Examples
3118  --------
3119  >>> import ctf
3120  >>> import numpy as np
3121  >>> a = np.array([1, 2, 3.])
3122  array([1., 2., 3.])
3123  >>> b = ctf.array(a)
3124  array([1., 2., 3.])
3125  """
3126  if ndmin != 0:
3127  raise ValueError('CTF PYTHON ERROR: ndmin not supported in ctf.array()')
3128  if dtype is None:
3129  dtype = A.dtype
3130  if _ord_comp(order, 'K') or _ord_comp(order, 'A'):
3131  if np.isfortran(A):
3132  B = astensor(A,dtype=dtype,order='F')
3133  else:
3134  B = astensor(A,dtype=dtype,order='C')
3135  else:
3136  B = astensor(A,dtype=dtype,order=order)
3137  if copy is False:
3138  B.set_zero()
3139  return B
3140 
3141 def diag(A, k=0, sp=False):
3142  """
3143  diag(A, k=0, sp=False)
3144  Return the diagonal tensor of A.
3145 
3146  Parameters
3147  ----------
3148  A: tensor_like
3149  Input tensor with 1-D or 2-D dimensions. If A is 1-D tensor, return a 2-D tensor with A on diagonal.
3150 
3151  k: int, optional
3152  `k=0` is the diagonal. `k<0`, diagnals below the main diagonal. `k>0`, diagonals above the main diagonal.
3153 
3154  sp: bool, optional
3155  If sp is true, the returned tensor is sparse.
3156 
3157  Returns
3158  -------
3159  output: tensor
3160  Diagonal tensor of A.
3161 
3162  Notes
3163  -----
3164  When the input tensor is sparse, returned tensor will also be sparse.
3165 
3166  See Also
3167  --------
3168  ctf : ctf.diagonal()
3169  ctf.triu()
3170  ctf.tril()
3171  ctf.trace()
3172  ctf.spdiag()
3173 
3174  Examples
3175  --------
3176  >>> import ctf
3177  >>> a = ctf.ones([3,])
3178  >>> ctf.diag(a, k=1)
3179  array([[0., 1., 0., 0.],
3180  [0., 0., 1., 0.],
3181  [0., 0., 0., 1.]])
3182  >>> b = ctf.zeros([4,4])
3183  >>> ctf.diag(b)
3184  array([0., 0., 0., 0.])
3185  """
3186  if not isinstance(A, tensor):
3187  raise ValueError('CTF PYTHON ERROR: A is not a tensor')
3188  dim = A.shape
3189  sp = A.sp | sp
3190  if len(dim) == 0:
3191  raise ValueError('CTF PYTHON ERROR: diag requires an array of at least 1 dimension')
3192  if len(dim) == 1:
3193  B = tensor((A.shape[0],A.shape[0]),dtype=A.dtype,sp=sp)
3194  B.i("ii") << A.i("i")
3195  absk = np.abs(k)
3196  if k>0:
3197  B2 = tensor((A.shape[0],A.shape[0]+absk),dtype=A.dtype,sp=sp)
3198  B2[:,absk:] = B
3199  return B2
3200  elif k < 0:
3201  B2 = tensor((A.shape[0]+absk,A.shape[0]),dtype=A.dtype,sp=sp)
3202  B2[absk:,:] = B
3203  return B2
3204  else:
3205  return B
3206 
3207  if k < 0 and dim[0] + k <=0:
3208  return tensor((0,))
3209  if k > 0 and dim[1] - k <=0:
3210  return tensor((0,))
3211  if len(dim) == 2:
3212  if k > 0:
3213  if dim[0] == dim[1]:
3214  up_left = np.zeros([2])
3215  up_left[0] += k
3216  down_right = np.array([dim[0], dim[1]])
3217  down_right[1] -= k
3218  else:
3219  up_left = np.zeros([2])
3220  m = min(dim[0], dim[1])
3221  down_right = np.array([m, m])
3222  up_left[0] += k
3223  down_right[0] += k
3224  if down_right[0] > dim[1]:
3225  down_right[1] -= (down_right[0] - dim[1])
3226  down_right[0] = dim[1]
3227  return einsum("ii->i",A._get_slice(up_left, down_right))
3228  elif k <= 0:
3229  if dim[0] == dim[1]:
3230  up_left = np.zeros([2])
3231  up_left[1] -= k
3232  down_right = np.array([dim[0], dim[1]])
3233  down_right[0] += k
3234  else:
3235  up_left = np.zeros([2])
3236  m = min(dim[0], dim[1])
3237  down_right = np.array([m, m])
3238  up_left[1] -= k
3239  down_right[1] -= k
3240  if down_right[1] > dim[0]:
3241  down_right[0] -= (down_right[1] - dim[0])
3242  down_right[1] = dim[0]
3243  return einsum("ii->i",A._get_slice(up_left, down_right))
3244  else:
3245  square = True
3246  # check whether the ctensor has all the same shape for every dimension -> [2,2,2,2] dims etc.
3247  for i in range(1,len(dim)):
3248  if dim[0] != dim[i]:
3249  square = False
3250  break
3251  if square == True:
3252  back = _get_num_str(len(dim)-1)
3253  front = back[len(back)-1]+back[len(back)-1]+back[0:len(back)-1]
3254  einsum_input = front + "->" + back
3255  return einsum(einsum_input,A)
3256  return None
3257 
3258 def spdiag(A, k=0):
3259  """
3260  spdiag(A, k=0)
3261  Return the sparse diagonal tensor of A.
3262 
3263  Parameters
3264  ----------
3265  A: tensor_like
3266  Input tensor with 1-D or 2-D dimensions. If A is 1-D tensor, return a 2-D tensor with A on diagonal.
3267 
3268  k: int, optional
3269  `k=0` is the diagonal. `k<0`, diagnals below the main diagonal. `k>0`, diagonals above the main diagonal.
3270 
3271  Returns
3272  -------
3273  output: tensor
3274  Sparse diagonal tensor of A.
3275 
3276  Notes
3277  -----
3278  Same with ctf.diag(A,k,sp=True)
3279 
3280  Examples
3281  --------
3282  >>> import ctf
3283  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
3284  >>> ctf.spdiag(a)
3285  array([1, 5, 9])
3286  """
3287  return diag(A,k,sp=True)
3288 
3289 def diagonal(init_A, offset=0, axis1=0, axis2=1):
3290  """
3291  diagonal(A, offset=0, axis1=0, axis2=1)
3292  Return the diagonal of tensor A if A is 2D. If A is a higher order square tensor (same shape for every dimension), return diagonal of tensor determined by axis1=0, axis2=1.
3293 
3294  Parameters
3295  ----------
3296  A: tensor_like
3297  Input tensor.
3298 
3299  offset: int, optional
3300  Default is 0 which indicates the main diagonal.
3301 
3302  axis1: int, optional
3303  Default is 0 which indicates the first axis of 2-D tensor where diagonal is taken.
3304 
3305  axis2: int, optional
3306  Default is 1 which indicates the second axis of 2-D tensor where diagonal is taken.
3307 
3308  Returns
3309  -------
3310  output: tensor
3311  Diagonal of input tensor.
3312 
3313  Notes
3314  -----
3315  `ctf.diagonal` only supports diagonal of square tensor with order more than 2.
3316 
3317  Examples
3318  --------
3319  >>> import ctf
3320  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
3321  >>> ctf.diagonal(a)
3322  array([1, 5, 9])
3323  """
3324  A = astensor(init_A)
3325  if axis1 == axis2:
3326  raise ValueError('CTF PYTHON ERROR: axis1 and axis2 cannot be the same')
3327  dim = A.shape
3328  if len(dim) == 1 or len(dim)==0:
3329  raise ValueError('CTF PYTHON ERROR: diagonal requires an array of at least two dimensions')
3330  if axis1 ==1 and axis2 == 0:
3331  offset = -offset
3332  if offset < 0 and dim[0] + offset <=0:
3333  return tensor((0,))
3334  if offset > 0 and dim[1] - offset <=0:
3335  return tensor((0,))
3336  if len(dim) == 2:
3337  if offset > 0:
3338  if dim[0] == dim[1]:
3339  up_left = np.zeros([2], dtype=np.int)
3340  up_left[0] += offset
3341  down_right = np.array([dim[0], dim[1]], dtype=np.int)
3342  down_right[1] -= offset
3343  else:
3344  up_left = np.zeros([2], dtype=np.int)
3345  m = min(dim[0], dim[1])
3346  down_right = np.array([m, m], dtype=np.int)
3347  up_left[0] += offset
3348  down_right[0] += offset
3349  if down_right[0] > dim[1]:
3350  down_right[1] -= (down_right[0] - dim[1])
3351  down_right[0] = dim[1]
3352  return einsum("ii->i",A._get_slice(up_left, down_right))
3353  elif offset <= 0:
3354  if dim[0] == dim[1]:
3355  up_left = np.zeros([2], dtype=np.int)
3356  up_left[1] -= offset
3357  down_right = np.array([dim[0], dim[1]], dtype=np.int)
3358  down_right[0] += offset
3359  else:
3360  up_left = np.zeros([2], dtype=np.int)
3361  m = min(dim[0], dim[1])
3362  down_right = np.array([m, m], dtype=np.int)
3363  up_left[1] -= offset
3364  down_right[1] -= offset
3365  if down_right[1] > dim[0]:
3366  down_right[0] -= (down_right[1] - dim[0])
3367  down_right[1] = dim[0]
3368  return einsum("ii->i",A._get_slice(up_left, down_right))
3369  else:
3370  square = True
3371  # check whether the ctensor has all the same shape for every dimension -> [2,2,2,2] dims etc.
3372  for i in range(1,len(dim)):
3373  if dim[0] != dim[i]:
3374  square = False
3375  break
3376  if square == True:
3377  back = _get_num_str(len(dim)-1)
3378  front = back[len(back)-1]+back[len(back)-1]+back[0:len(back)-1]
3379  einsum_input = front + "->" + back
3380  return einsum(einsum_input,A)
3381  else:
3382  raise ValueError('CTF PYTHON ERROR: diagonal requires a higher order (>2) tensor to be square')
3383  raise ValueError('CTF PYTHON ERROR: diagonal error')
3384 
3385 def trace(init_A, offset=0, axis1=0, axis2=1, dtype=None, out=None):
3386  """
3387  trace(A, offset=0, axis1=0, axis2=1, dtype=None, out=None)
3388  Return the sum over the diagonal of input tensor.
3389 
3390  Parameters
3391  ----------
3392  A: tensor_like
3393  Input tensor.
3394 
3395  offset: int, optional
3396  Default is 0 which indicates the main diagonal.
3397 
3398  axis1: int, optional
3399  Default is 0 which indicates the first axis of 2-D tensor where diagonal is taken.
3400 
3401  axis2: int, optional
3402  Default is 1 which indicates the second axis of 2-D tensor where diagonal is taken.
3403 
3404  dtype: data-type, optional
3405  Numpy data-type, currently not supported in CTF Python trace().
3406 
3407  out: tensor
3408  Currently not supported in CTF Python trace().
3409 
3410  Returns
3411  -------
3412  output: tensor or scalar
3413  Sum along diagonal of input tensor.
3414 
3415  Examples
3416  --------
3417  >>> import ctf
3418  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
3419  >>> ctf.trace(a)
3420  15
3421  """
3422  if dtype != None or out != None:
3423  raise ValueError('CTF PYTHON ERROR: CTF Python trace currently does not support dtype and out')
3424  A = astensor(init_A)
3425  dim = A.shape
3426  if len(dim) == 1 or len(dim)==0:
3427  raise ValueError('CTF PYTHON ERROR: diag requires an array of at least two dimensions')
3428  elif len(dim) == 2:
3429  return sum(diagonal(A, offset=offset, axis1 = axis1, axis2 = axis2))
3430  else:
3431  # this is the case when len(dims) > 2 and "square ctensor"
3432  return sum(diagonal(A, offset=offset, axis1 = axis1, axis2 = axis2), axis=len(A.shape)-2)
3433  return None
3434 
3435 def take(init_A, indices, axis=None, out=None, mode='raise'):
3436  """
3437  take(A, indices, axis=None, out=None, mode='raise')
3438  Take elements from a tensor along axis.
3439 
3440  Parameters
3441  ----------
3442  A: tensor_like
3443  Input tensor.
3444 
3445  indices: tensor_like
3446  Indices of the values wnat to be extracted.
3447 
3448  axis: int, optional
3449  Select values from which axis, default None.
3450 
3451  out: tensor
3452  Currently not supported in CTF Python take().
3453 
3454  mode: {‘raise’, ‘wrap’, ‘clip’}, optional
3455  Currently not supported in CTF Python take().
3456 
3457  Returns
3458  -------
3459  output: tensor or scalar
3460  Elements extracted from the input tensor.
3461 
3462  See Also
3463  --------
3464  numpy: numpy.take()
3465 
3466  Examples
3467  --------
3468  >>> import ctf
3469  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
3470  >>> ctf.take(a, [0, 1, 2])
3471  array([1, 2, 3])
3472  """
3473  if out is not None:
3474  raise ValueError("CTF Python Now ctf does not support to specify 'out' in functions")
3475  A = astensor(init_A)
3476  indices = np.asarray(indices)
3477 
3478  if axis == None:
3479  # if the indices is int
3480  if indices.shape == ():
3481  indices = indices.reshape(1,)
3482  if indices[0] < 0:
3483  indices[0] += A.shape[0]
3484  if indices[0] > 0 and indices[0] > A.shape[0]:
3485  error = "index "+str(indices[0])+" is out of bounds for size " + str(A.shape[0])
3486  error = "CTF PYTHON ERROR: " + error
3487  raise IndexError(error)
3488  if indices[0] < 0:
3489  error = "index "+str(indices[0]-A.shape[0])+" is out of bounds for size " + str(A.shape[0])
3490  error = "CTF PYTHON ERROR: " + error
3491  raise IndexError(error)
3492  return A.read(indices)[0]
3493  # if the indices is 1-D array
3494  else:
3495  total_size = 1
3496  for i in range(len(A.shape)):
3497  total_size *= A.shape[i]
3498  indices_ravel = np.ravel(indices)
3499  for i in range(len(indices_ravel)):
3500  if indices_ravel[i] < 0:
3501  indices_ravel[i] += total_size
3502  if indices_ravel[i] < 0:
3503  error = "index "+str(indices_ravel[i]-total_size)+" is out of bounds for size " + str(total_size)
3504  error = "CTF PYTHON ERROR: " + error
3505  raise IndexError(error)
3506  if indices_ravel[i] > 0 and indices_ravel[0] > total_size:
3507  error = "index "+str(indices_ravel[i])+" is out of bounds for size " + str(total_size)
3508  error = "CTF PYTHON ERROR: " + error
3509  raise IndexError(error)
3510  if len(indices.shape) == 1:
3511  B = astensor(A.read(indices_ravel))
3512  else:
3513  B = astensor(A.read(indices_ravel)).reshape(indices.shape)
3514  return B
3515  else:
3516  if type(axis) != int:
3517  raise TypeError("CTF PYTHON ERROR: the axis should be int type")
3518  if axis < 0:
3519  axis += len(A.shape)
3520  if axis < 0:
3521  raise IndexError("CTF PYTHON ERROR: axis out of bounds")
3522  if axis > len(A.shape):
3523  raise IndexError("CTF PYTHON ERROR: axis out of bounds")
3524  if indices.shape == () or indices.shape== (1,):
3525  total_size = 1
3526  for i in range(len(A.shape)):
3527  total_size *= A[i]
3528  if indices >= A.shape[axis]:
3529  raise IndexError("CTF PYTHON ERROR: index out of bounds")
3530  ret_shape = list(A.shape)
3531  if indices.shape == ():
3532  del ret_shape[axis]
3533  else:
3534  ret_shape[axis] = 1
3535  begin = 1
3536  for i in range(axis+1, len(A.shape),1):
3537  begin *= A.shape[i]
3538  next_slot = A.shape[axis] * begin
3539  start = indices * begin
3540  arange_times = 1
3541  for i in range(0, axis):
3542  arange_times *= A.shape[i]
3543  a = np.arange(start,start+begin)
3544  start += next_slot
3545  for i in range(1,arange_times,1):
3546  a = np.concatenate((a, np.arange(start,start+begin)))
3547  start += next_slot
3548  B = astensor(A.read(a)).reshape(ret_shape)
3549  return B.to_nparray()
3550  else:
3551  if len(indices.shape) > 1:
3552  raise ValueError("CTF PYTHON ERROR: current ctf does not support when specify axis and the len(indices.shape) > 1")
3553  total_size = 1
3554  for i in range(len(A.shape)):
3555  total_size *= A[i]
3556  for i in range(len(indices)):
3557  if indices[i] >= A.shape[axis]:
3558  raise IndexError("index out of bounds")
3559  ret_shape = list(A.shape)
3560  ret_index = 0
3561  ret_shape[axis] = len(indices)
3562  begin = np.ones(indices.shape)
3563  for i in range(axis+1, len(A.shape),1):
3564  begin *= A.shape[i]
3565  next_slot = A.shape[axis] * begin
3566  start = indices * begin
3567  arange_times = 1
3568  for i in range(0, axis):
3569  arange_times *= A.shape[i]
3570  a = np.arange(start[0],start[0]+begin[0])
3571  start[0] += next_slot[0]
3572  for i in range(1,len(indices),1):
3573  a = np.concatenate((a, np.arange(start[i],start[i]+begin[i])))
3574  start[i] += next_slot[i]
3575  for i in range(1,arange_times,1):
3576  for j in range(len(indices)):
3577  a = np.concatenate((a, np.arange(start[j],start[j]+begin[j])))
3578  start[j] += next_slot[j]
3579  B = astensor(A.read(a)).reshape(ret_shape)
3580  return B
3581  raise ValueError('CTF PYTHON ERROR: CTF error: should not get here')
3582 
3583 def copy(tensor A):
3584  """
3585  copy(A)
3586  Return a copy of tensor A.
3587 
3588  Parameters
3589  ----------
3590  A: tensor
3591  Input tensor.
3592 
3593  Returns
3594  -------
3595  output: tensor
3596  A tensor representation of A.
3597 
3598  Examples
3599  --------
3600  >>> a = ctf.astensor([1,2,3])
3601  >>> a
3602  array([1, 2, 3])
3603  >>> b = ctf.copy(a)
3604  >>> b
3605  array([1, 2, 3])
3606  >>> id(a) == id(b)
3607  False
3608  """
3609  B = tensor(A.shape, dtype=A.get_type(), copy=A)
3610  return B
3611 
3612 def reshape(A, newshape, order='F'):
3613  """
3614  reshape(A, newshape, order='F')
3615  Reshape the input tensor A to new shape.
3616 
3617  Parameters
3618  ----------
3619  A: tensor_like
3620  Input tensor.
3621 
3622  newshape: tuple of ints or int
3623  New shape where the input tensor is shaped to.
3624 
3625  order: {‘C’, ‘F’}, optional
3626  Currently not supported by CTF Python.
3627 
3628  Returns
3629  -------
3630  output: tensor
3631  Tensor with new shape of A.
3632 
3633  See Also
3634  --------
3635  ctf: ctf.tensor.reshape()
3636 
3637  Examples
3638  --------
3639  >>> import ctf
3640  a = ctf.astensor([1,2,3,4])
3641  >>> ctf.reshape(a, (2, 2))
3642  array([[1, 2],
3643  [3, 4]])
3644  """
3645  if A.order != order:
3646  raise ValueError('CTF PYTHON ERROR: CTF does not support reshape with a new element order (Fortran vs C)')
3647  return A.reshape(newshape)
3648 
3649 
3650 def astensor(A, dtype = None, order=None):
3651  """
3652  astensor(A, dtype = None, order=None)
3653  Convert the input data to tensor.
3654 
3655  Parameters
3656  ----------
3657  A: tensor_like
3658  Input data.
3659 
3660  dtype: data-type, optional
3661  Numpy data-type, if it is not specified, the function will return the tensor with same type as `np.asarray` returned ndarray.
3662 
3663  order: {‘C’, ‘F’}, optional
3664  C or Fortran memory order, default is 'F'.
3665 
3666  Returns
3667  -------
3668  output: tensor
3669  A tensor representation of A.
3670 
3671  See Also
3672  --------
3673  numpy: numpy.asarray()
3674 
3675  Examples
3676  --------
3677  >>> import ctf
3678  >>> a = ctf.astensor([1,2,3])
3679  >>> a
3680  array([1, 2, 3])
3681  """
3682  if isinstance(A,tensor):
3683  if order is not None and order != A.order:
3684  raise ValueError('CTF PYTHON ERROR: CTF does not support this type of order conversion in astensor()')
3685  if dtype is not None and dtype != A.dtype:
3686  return tensor(copy=A, dtype=dtype)
3687  return A
3688  if order is None:
3689  order = 'F'
3690  if dtype != None:
3691  narr = np.asarray(A,dtype=dtype,order=order)
3692  else:
3693  narr = np.asarray(A,order=order)
3694  t = tensor(narr.shape, dtype=narr.dtype)
3695  t.from_nparray(narr)
3696  return t
3697 
3698 def dot(tA, tB, out=None):
3699  """
3700  dot(A, B, out=None)
3701  Return the dot product of two tensors A and B.
3702 
3703  Parameters
3704  ----------
3705  A: tensor_like
3706  First input tensor.
3707 
3708  B: tensor_like
3709  Second input tensor.
3710 
3711  out: tensor
3712  Currently not supported in CTF Python.
3713 
3714  Returns
3715  -------
3716  output: tensor
3717  Dot product of two tensors.
3718 
3719  See Also
3720  --------
3721  numpy: numpy.dot()
3722 
3723  Examples
3724  --------
3725  >>> import ctf
3726  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
3727  >>> b = ctf.astensor([1,1,1])
3728  >>> ctf.dot(a, b)
3729  array([ 6, 15, 24])
3730  """
3731  if out is not None:
3732  raise ValueError("CTF PYTHON ERROR: CTF currently does not support output parameter.")
3733 
3734  if (isinstance(tA, (np.int, np.float, np.complex, np.number)) and
3735  isinstance(tB, (np.int, np.float, np.complex, np.number))):
3736  return tA * tB
3737 
3738  A = astensor(tA)
3739  B = astensor(tB)
3740 
3741  return tensordot(A, B, axes=([-1],[0]))
3742 
3743 def tensordot(tA, tB, axes=2):
3744  """
3745  tensordot(A, B, axes=2)
3746  Return the tensor dot product of two tensors A and B along axes.
3747 
3748  Parameters
3749  ----------
3750  A: tensor_like
3751  First input tensor.
3752 
3753  B: tensor_like
3754  Second input tensor.
3755 
3756  axes: int or array_like
3757  Sum over which axes.
3758 
3759  Returns
3760  -------
3761  output: tensor
3762  Tensor dot product of two tensors.
3763 
3764  See Also
3765  --------
3766  numpy: numpy.tensordot()
3767 
3768  Examples
3769  --------
3770  >>> import ctf
3771  >>> import numpy as np
3772  >>> a = np.arange(60.).reshape(3,4,5)
3773  >>> b = np.arange(24.).reshape(4,3,2)
3774  >>> a = ctf.astensor(a)
3775  >>> b = ctf.astensor(b)
3776  >>> c = ctf.tensordot(a,b, axes=([1,0],[0,1]))
3777  >>> c
3778  array([[4400., 4730.],
3779  [4532., 4874.],
3780  [4664., 5018.],
3781  [4796., 5162.],
3782  [4928., 5306.]])
3783  """
3784  A = astensor(tA)
3785  B = astensor(tB)
3786 
3787  if isinstance(axes, (int, np.integer)):
3788  if axes > len(A.shape) or axes > len(B.shape):
3789  raise ValueError("tuple index out of range")
3790  for i in range(axes):
3791  if A.shape[len(A.shape)-1-i] != B.shape[axes-1-i]:
3792  raise ValueError("shape-mismatch for sum")
3793  new_shape = A.shape[0:len(A.shape)-axes] + B.shape[axes:len(B.shape)]
3794 
3795  # following is to check the return tensor type
3796  new_dtype = _get_np_dtype([A.dtype, B.dtype])
3797 
3798  if axes <= 0:
3799  ret_shape = A.shape + B.shape
3800  C = tensor(ret_shape, dtype = new_dtype)
3801  A_new = None
3802  B_new = None
3803 
3804  # we need to add more template to conv_type
3805  if A.dtype != new_dtype:
3806  A_new = A.astype(dtype = new_dtype)
3807  if B.dtype != new_dtype:
3808  B_new = A.astype(dtype = new_dtype)
3809 
3810  string_index = 33
3811  A_str = ""
3812  B_str = ""
3813  C_str = ""
3814  for i in range(len(A.shape)):
3815  A_str += chr(string_index)
3816  string_index += 1
3817  for i in range(len(B.shape)):
3818  B_str += chr(string_index)
3819  string_index += 1
3820  C_str = A_str + B_str
3821  if A_new is not None and B_new is not None:
3822  C.i(C_str) << A_new.i(A_str) * B_new.i(B_str)
3823  elif A_new is not None:
3824  C.i(C_str) << A_new.i(A_str) * B.i(B_str)
3825  else:
3826  C.i(C_str) << A.i(A_str) * B.i(B_str)
3827  return C
3828 
3829  # start manage the string input for .i()
3830  string_index = 33
3831  A_str = ""
3832  B_str = ""
3833  C_str = ""
3834  for i in range(axes):
3835  A_str += chr(string_index)
3836  B_str += chr(string_index)
3837  string_index += 1
3838 
3839  # update the string of A
3840  for i in range(len(A.shape)-axes):
3841  A_str = chr(string_index) + A_str
3842  C_str = chr(string_index) + C_str
3843  string_index += 1
3844 
3845  # update the string of B
3846  for i in range(len(B.shape)-axes):
3847  B_str += chr(string_index)
3848  C_str += chr(string_index)
3849  string_index += 1
3850 
3851  if A.dtype == new_dtype and B.dtype == new_dtype:
3852  C = tensor(new_shape, dtype = new_dtype)
3853  C.i(C_str) << A.i(A_str) * B.i(B_str)
3854  return C
3855  else:
3856  C = tensor(new_shape, dtype = new_dtype)
3857  A_new = None
3858  B_new = None
3859 
3860  # we need to add more template to conv_type
3861  C.i(C_str) << A.i(A_str) * B_new.i(B_str)
3862  if A.dtype != new_dtype:
3863  A_new = A.astype(dtype = new_dtype)
3864  if B.dtype != new_dtype:
3865  B_new = A.astype(dtype = new_dtype)
3866 
3867  if A_new is not None and B_new is not None:
3868  C.i(C_str) << A_new.i(A_str) * B_new.i(B_str)
3869  elif A_new is not None:
3870  C.i(C_str) << A_new.i(A_str) * B.i(B_str)
3871  else:
3872  C.i(C_str) << A.i(A_str) * B_new.i(B_str)
3873  return C
3874  else:
3875  axes_arr = np.asarray(axes)
3876  if len(axes_arr.shape) != 2 or axes_arr.shape[0] != 2:
3877  raise ValueError("axes should be int or (2,) array like")
3878  if len(axes_arr[0]) != len(axes_arr[1]):
3879  raise ValueError("two sequences should have same length")
3880  for i in range(len(axes_arr[0])):
3881  if axes_arr[0][i] < 0:
3882  axes_arr[0][i] += len(A.shape)
3883  if axes_arr[0][i] < 0:
3884  raise ValueError("index out of range")
3885  if axes_arr[1][i] < 0:
3886  axes_arr[1][i] += len(B.shape)
3887  if axes_arr[1][i] < 0:
3888  raise ValueError("index out of range")
3889  # check whether there are same index
3890  for i in range(len(axes_arr[0])):
3891  if axes[0].count(axes_arr[0][i]) > 1:
3892  raise ValueError("repeated index")
3893  if axes[1].count(axes_arr[1][i]) > 1:
3894  raise ValueError("repeated index")
3895  for i in range(len(axes_arr[0])):
3896  if A.shape[axes_arr[0][i]] != B.shape[axes_arr[1][i]]:
3897  raise ValueError("shape mismatch")
3898  new_dtype = _get_np_dtype([A.dtype, B.dtype])
3899 
3900  # start manage the string input for .i()
3901  string_index = 33
3902  A_str = ""
3903  B_str = ""
3904  C_str = ""
3905  new_shape = ()
3906  # generate string for tensor A
3907  for i in range(len(A.shape)):
3908  A_str += chr(string_index)
3909  string_index += 1
3910  # generate string for tensor B
3911  for i in range(len(B.shape)):
3912  B_str += chr(string_index)
3913  string_index += 1
3914  B_str = list(B_str)
3915  for i in range(len(axes_arr[1])):
3916  B_str[axes_arr[1][i]] = A_str[axes_arr[0][i]]
3917  B_str = "".join(B_str)
3918  for i in range(len(A_str)):
3919  if i not in axes_arr[0]:
3920  C_str += A_str[i]
3921  new_shape += (A.shape[i],)
3922  for i in range(len(B_str)):
3923  if i not in axes_arr[1]:
3924  C_str += B_str[i]
3925  new_shape += (B.shape[i],)
3926  # that we do not need to change type
3927  if A.dtype == new_dtype and B.dtype == new_dtype:
3928  C = tensor(new_shape, dtype = new_dtype)
3929  C.i(C_str) << A.i(A_str) * B.i(B_str)
3930  return C
3931  else:
3932  C = tensor(new_shape, dtype = new_dtype)
3933  A_new = None
3934  B_new = None
3935 
3936  # we need to add more template to conv_type for type convert
3937  if A.dtype != new_dtype:
3938  A_new = A.astype(dtype = new_dtype)
3939  if B.dtype != new_dtype:
3940  B_new = B.astype(dtype = new_dtype)
3941 
3942  if A_new is not None and B_new is not None:
3943  C.i(C_str) << A_new.i(A_str) * B_new.i(B_str)
3944  elif A_new is not None:
3945  C.i(C_str) << A_new.i(A_str) * B.i(B_str)
3946  else:
3947  C.i(C_str) << A.i(A_str) * B_new.i(B_str)
3948  return C
3949 
3950 # the default order of exp in CTF is Fortran order
3951 # the exp not working when the type of x is complex, there are some problems when implementing the template in function _exp_python() function
3952 # not sure out and dtype can be specified together, now this is not allowed in this function
3953 # haven't implemented the out that store the value into the out, now only return a new tensor
3954 def exp(init_x, out=None, where=True, casting='same_kind', order='F', dtype=None, subok=True):
3955  """
3956  exp(A, out=None, where=True, casting='same_kind', order='F', dtype=None, subok=True)
3957  Exponential of all elements in input tensor A.
3958 
3959  Parameters
3960  ----------
3961  A: tensor_like
3962  Input tensor or tensor like array.
3963 
3964  out: tensor, optional
3965  Crrently not support by CTF Python.
3966 
3967  where: array_like, optional
3968  Crrently not support by CTF Python.
3969 
3970  casting: same_kind or unsafe
3971  Default same_kind.
3972 
3973  order: optional
3974  Crrently not support by CTF Python.
3975 
3976  dtype: data-type, optional
3977  Output data-type for the exp result.
3978 
3979  subok: bool
3980  Crrently not support by CTF Python.
3981 
3982  Returns
3983  -------
3984  output: tensor_like
3985  Output tensor for the exponential.
3986 
3987  See Also
3988  --------
3989  numpy: numpy.exp()
3990 
3991  Examples
3992  --------
3993  >>> import ctf
3994  >>> a = ctf.astensor([1,2,3])
3995  >>> ctf.exp(a)
3996  array([ 2.71828183, 7.3890561 , 20.08553692])
3997  """
3998  x = astensor(init_x)
3999 
4000  # delete this one and add for out
4001  if out is not None:
4002  raise ValueError("CTF PYTHON ERROR: current not support to specify out")
4003 
4004  if out is not None and out.shape != x.shape:
4005  raise ValueError("Shape does not match")
4006  if casting == 'same_kind' and (out is not None or dtype is not None):
4007  if out is not None and dtype is not None:
4008  raise TypeError("CTF PYTHON ERROR: out and dtype should not be specified together")
4009  type_list = [np.int8, np.int16, np.int32, np.int64]
4010  for i in range(4):
4011  if out is not None and out.dtype == type_list[i]:
4012  raise TypeError("CTF PYTHON ERROR: Can not cast according to the casting rule 'same_kind'")
4013  if dtype is not None and dtype == type_list[i]:
4014  raise TypeError("CTF PYTHON ERROR: Can not cast according to the casting rule 'same_kind'")
4015 
4016  # we need to add more templates initialization in _exp_python() function
4017  if casting == 'unsafe':
4018  # add more, not completed when casting == unsafe
4019  if out is not None and dtype is not None:
4020  raise TypeError("CTF PYTHON ERROR: out and dtype should not be specified together")
4021 
4022  if dtype is not None:
4023  ret_dtype = dtype
4024  elif out is not None:
4025  ret_dtype = out.dtype
4026  else:
4027  ret_dtype = None
4028  x_dtype = x.dtype
4029  if x_dtype == np.int8:
4030  ret_dtype = np.float16
4031  elif x_dtype == np.int16:
4032  ret_dtype = np.float32
4033  elif x_dtype == np.int32:
4034  ret_dtype = np.float64
4035  elif x_dtype == np.int64:
4036  ret_dtype = np.float64
4037  elif x_dtype == np.float16 or x_dtype == np.float32 or x_dtype == np.float64 or x_dtype == np.float128:
4038  ret_dtype = x_dtype
4039  elif x_dtype == np.complex64 or x_dtype == np.complex128 or x_dtype == np.complex256:
4040  ret_dtype = x_dtype
4041  if casting == "unsafe":
4042  ret = tensor(x.shape, dtype = ret_dtype, sp=x.sp)
4043  ret._exp_python(x, cast = 'unsafe', dtype = ret_dtype)
4044  return ret
4045  else:
4046  ret = tensor(x.shape, dtype = ret_dtype, sp=x.sp)
4047  ret._exp_python(x)
4048  return ret
4049 
4050 def to_nparray(t):
4051  """
4052  to_nparray(A)
4053  Convert the tensor to numpy array.
4054 
4055  Parameters
4056  ----------
4057  A: tensor_like
4058  Input tensor or tensor like array.
4059 
4060  Returns
4061  -------
4062  output: ndarray
4063  Numpy ndarray representation of tensor like input A.
4064 
4065  See Also
4066  --------
4067  numpy: numpy.asarray()
4068 
4069  Examples
4070  --------
4071  >>> import ctf
4072  >>> import numpy as np
4073  >>> a = ctf.zeros([3,4])
4074  >>> b = ctf.to_nparray(a)
4075  >>> b
4076  array([[0., 0., 0., 0.],
4077  [0., 0., 0., 0.],
4078  [0., 0., 0., 0.]])
4079  >>> type(b)
4080  <class 'numpy.ndarray'>
4081  """
4082  if isinstance(t,tensor):
4083  return t.to_nparray()
4084  else:
4085  return np.asarray(t)
4086 
4087 def from_nparray(arr):
4088  """
4089  from_nparray(A)
4090  Convert the numpy array to tensor.
4091 
4092  Parameters
4093  ----------
4094  A: ndarray
4095  Input numpy array.
4096 
4097  Returns
4098  -------
4099  output: tensor
4100  Tensor representation of input numpy array.
4101 
4102  See Also
4103  --------
4104  ctf: ctf.astensor()
4105 
4106  Examples
4107  --------
4108  >>> import ctf
4109  >>> import numpy as np
4110  >>> a = np.array([1,2,3])
4111  >>> b = ctf.from_nparray(a)
4112  >>> b
4113  array([1, 2, 3])
4114  >>> type(b)
4115  <class 'ctf.core.tensor'>
4116  """
4117  return astensor(arr)
4118 
4119 def zeros_like(init_A, dtype=None, order='F'):
4120  """
4121  zeros_like(A, dtype=None, order='F')
4122  Return the tensor of zeros with same shape and dtype of tensor A.
4123 
4124  Parameters
4125  ----------
4126  A: tensor_like
4127  Input tensor where the output tensor shape and dtype defined as.
4128 
4129  dtype: data-type, optional
4130  Output data-type for the empty tensor.
4131 
4132  order: {‘C’, ‘F’}, optional, default: ‘F’
4133  Currently not support by CTF Python.
4134 
4135  Returns
4136  -------
4137  output: tensor_like
4138  Output tensor.
4139 
4140  Examples
4141  --------
4142  >>> import ctf
4143  >>> import numpy as np
4144  >>> a = ctf.zeros([3,4], dtype=np.int64)
4145  >>> b = ctf.zeros_like(a)
4146  >>> b
4147  array([[0, 0, 0, 0],
4148  [0, 0, 0, 0],
4149  [0, 0, 0, 0]])
4150  """
4151  A = astensor(init_A)
4152  shape = A.shape
4153  if dtype is None:
4154  dtype = A.get_type()
4155  return zeros(shape, dtype, order)
4156 
4157 def zeros(shape, dtype=np.float64, order='F'):
4158  """
4159  zeros(shape, dtype=np.float64, order='F')
4160  Return the tensor with specified shape and dtype with all elements filled as zeros.
4161 
4162  Parameters
4163  ----------
4164  shape: int or tuple of int
4165  Shape of the empty tensor.
4166 
4167  dtype: data-type, optional
4168  Output data-type for the empty tensor.
4169 
4170  order: {‘C’, ‘F’}, optional, default: ‘F’
4171  Currently not support by CTF Python.
4172 
4173  Returns
4174  -------
4175  output: tensor_like
4176  Output tensor.
4177 
4178  Examples
4179  --------
4180  >>> import ctf
4181  >>> import numpy as np
4182  >>> a = ctf.zeros([3,4], dtype=np.int64)
4183  >>> a
4184  array([[0, 0, 0, 0],
4185  [0, 0, 0, 0],
4186  [0, 0, 0, 0]])
4187  """
4188  A = tensor(shape, dtype=dtype)
4189  return A
4190 
4191 def empty(shape, dtype=np.float64, order='F'):
4192  """
4193  empty(shape, dtype=np.float64, order='F')
4194  Return the tensor with specified shape and dtype without initialization. Currently not supported by CTF Python, this function same with the ctf.zeros().
4195 
4196  Parameters
4197  ----------
4198  shape: int or tuple of int
4199  Shape of the empty tensor.
4200 
4201  dtype: data-type, optional
4202  Output data-type for the empty tensor.
4203 
4204  order: {‘C’, ‘F’}, optional, default: ‘F’
4205  Currently not support by CTF Python.
4206 
4207  Returns
4208  -------
4209  output: tensor_like
4210  Output tensor.
4211 
4212  Examples
4213  --------
4214  >>> import ctf
4215  >>> import numpy as np
4216  >>> a = ctf.empty([3,4], dtype=np.int64)
4217  >>> a
4218  array([[0, 0, 0, 0],
4219  [0, 0, 0, 0],
4220  [0, 0, 0, 0]])
4221  """
4222  return zeros(shape, dtype, order)
4223 
4224 def empty_like(A, dtype=None):
4225  """
4226  empty_like(A, dtype=None)
4227  Return uninitialized tensor of with same shape and dtype of tensor A. Currently in CTF Python is same with ctf.zero_like.
4228 
4229  Parameters
4230  ----------
4231  A: tensor_like
4232  Input tensor where the output tensor shape and dtype defined as.
4233 
4234  dtype: data-type, optional
4235  Output data-type for the empty tensor.
4236 
4237  Returns
4238  -------
4239  output: tensor_like
4240  Output tensor.
4241 
4242  See Also
4243  --------
4244  ctf: ctf.zeros_like()
4245 
4246  Examples
4247  --------
4248  >>> import ctf
4249  >>> a = ctf.zeros([3,4], dtype=np.int64)
4250  >>> b = ctf.empty_like(a)
4251  >>> b
4252  array([[0, 0, 0, 0],
4253  [0, 0, 0, 0],
4254  [0, 0, 0, 0]])
4255  """
4256  if dtype is None:
4257  dtype = A.dtype
4258  return empty(A.shape, dtype=dtype)
4259 
4260 # Maybe there are issues that when keepdims, dtype and out are all specified.
4261 def sum(tensor init_A, axis = None, dtype = None, out = None, keepdims = None):
4262  """
4263  sum(A, axis = None, dtype = None, out = None, keepdims = None)
4264  Sum of elements in tensor or along specified axis.
4265 
4266  Parameters
4267  ----------
4268  A: tensor_like
4269  Input tensor.
4270 
4271  axis: None, int or tuple of ints
4272  Axis or axes where the sum of elements is performed.
4273 
4274  dtype: data-type, optional
4275  Data-type for the output tensor.
4276 
4277  out: tensor, optional
4278  Alternative output tensor.
4279 
4280  keepdims: None, bool, optional
4281  If set to true, axes summed over will remain size one.
4282 
4283  Returns
4284  -------
4285  output: tensor_like
4286  Output tensor.
4287 
4288  See Also
4289  --------
4290  numpy: numpy.sum()
4291 
4292  Examples
4293  --------
4294  >>> import ctf
4295  >>> a = ctf.ones([3,4], dtype=np.int64)
4296  >>> ctf.sum(a)
4297  12
4298  """
4299  A = astensor(init_A)
4300  if not isinstance(out,tensor) and out is not None:
4301  raise ValueError("CTF PYTHON ERROR: output must be a tensor")
4302 
4303  # if dtype not specified, assign np.float64 to it
4304  if dtype is None:
4305  dtype = A.get_type()
4306 
4307  # if keepdims not specified, assign false to it
4308  if keepdims is None :
4309  keepdims = False;
4310 
4311  # it keepdims == true and axis not specified
4312  if isinstance(out,tensor) and axis is None:
4313  raise ValueError("CTF PYTHON ERROR: output parameter for reduction operation add has too many dimensions")
4314 
4315  # get_dims of tensor A
4316  dim = A.shape
4317  # store the axis in a tuple
4318  axis_tuple = ()
4319  # check whether the axis entry is out of bounds, if axis input is positive e.g. axis = 5
4320  if isinstance(axis, (int, np.integer)):
4321  if axis is not None and (axis >= len(dim) or axis <= (-len(dim)-1)):
4322  raise ValueError("CTF PYTHON ERROR: 'axis' entry is out of bounds")
4323  elif axis is None:
4324  axis = None
4325  else:
4326  # check whether the axis parameter has the correct type, number etc.
4327  axis = np.asarray(axis, dtype=np.int64)
4328  if len(axis.shape) > 1:
4329  raise ValueError("CTF PYTHON ERROR: the object cannot be interpreted as integer")
4330  for i in range(len(axis)):
4331  if axis[i] >= len(dim) or axis[i] <= (-len(dim)-1):
4332  raise ValueError("CTF PYTHON ERROR: 'axis' entry is out of bounds")
4333  for i in range(len(axis)):
4334  if axis[i] < 0:
4335  axis[i] += len(dim)
4336  if axis[i] in axis_tuple:
4337  raise ValueError("CTF PYTHON ERROR: duplicate value in 'axis'")
4338  axis_tuple += (axis[i],)
4339 
4340  # if out has been specified, assign a outputdim
4341  if isinstance(out,tensor):
4342  outputdim = out.shape
4343  outputdim = np.ndarray.tolist(outputdim)
4344  outputdim = tuple(outputdim)
4345 
4346  # if there is no axis input, sum all the entries
4347  index = ""
4348  if axis is None:
4349  index_A = _get_num_str(len(dim))
4350  #ret_dim = []
4351  #for i in range(len(dim)):
4352  # ret_dim.append(1)
4353  #ret_dim = tuple(ret_dim)
4354  # dtype has the same type of A, we do not need to convert
4355  #if dtype == A.get_type():
4356  ret = tensor([], dtype = A.dtype)
4357  ret.i("") << A.i(index_A)
4358  if keepdims == True:
4359  return ret.reshape(np.ones(tensor.shape))
4360  else:
4361  return ret.read_all()[0]
4362 
4363  # is the axis is an integer
4364  if isinstance(axis, (int, np.integer)):
4365  ret_dim = ()
4366  if axis < 0:
4367  axis += len(dim)
4368  for i in range(len(dim)):
4369  if i == axis:
4370  continue
4371  else:
4372  ret_dim = list(ret_dim)
4373  ret_dim.insert(i+1,dim[i])
4374  ret_dim = tuple(ret_dim)
4375 
4376  # following specified when out, dtype is not none etc.
4377  B = tensor(ret_dim, dtype = dtype)
4378  C = None
4379  if dtype != A.get_type():
4380  C = tensor(A.shape, dtype = dtype)
4381  if isinstance(out,tensor):
4382  if(outputdim != ret_dim):
4383  raise ValueError("dimension of output mismatch")
4384  else:
4385  if keepdims == True:
4386  raise ValueError("Must match the dimension when keepdims = True")
4387  else:
4388  B = tensor(ret_dim, dtype = out.get_type())
4389  C = tensor(A.shape, dtype = out.get_type())
4390 
4391  index = _get_num_str(len(dim))
4392  index_A = index[0:len(dim)]
4393  index_B = index[0:axis] + index[axis+1:len(dim)]
4394  if isinstance(C, tensor):
4395  A._convert_type(C)
4396  B.i(index_B) << C.i(index_A)
4397  return B
4398  else:
4399  B.i(index_B) << A.i(index_A)
4400  return B
4401 
4402  # following is when axis is an tuple or nparray.
4403  C = None
4404  if dtype != A.get_type():
4405  C = tensor(A.shape, dtype = dtype)
4406  if isinstance(out,tensor):
4407  if keepdims == True:
4408  raise ValueError("Must match the dimension when keepdims = True")
4409  else:
4410  dtype = out.get_type()
4411  C = tensor(A.shape, dtype = out.get_type())
4412  if isinstance(C, tensor):
4413  A._convert_type(C)
4414  temp = C.copy()
4415  else:
4416  temp = A.copy()
4417  decrease_dim = list(dim)
4418  axis_list = list(axis_tuple)
4419  axis_list.sort()
4420  for i in range(len(axis)-1,-1,-1):
4421  index_removal = axis_list[i]
4422  temp_dim = list(decrease_dim)
4423  del temp_dim[index_removal]
4424  ret_dim = tuple(temp_dim)
4425  B = tensor(ret_dim, dtype = dtype)
4426  index = _get_num_str(len(decrease_dim))
4427  index_A = index[0:len(decrease_dim)]
4428  index_B = index[0:axis_list[i]] + index[axis_list[i]+1:len(decrease_dim)]
4429  B.i(index_B) << temp.i(index_A)
4430  temp = B.copy()
4431  del decrease_dim[index_removal]
4432  return B
4433 
4434 def ravel(init_A, order="F"):
4435  """
4436  ravel(A, order="F")
4437  Return flattened CTF tensor of input tensor A.
4438 
4439  Parameters
4440  ----------
4441  A: tensor_like
4442  Input tensor.
4443 
4444  order: {‘C’,’F’, ‘A’, ‘K’}, optional
4445  Currently not support by current CTF Python.
4446 
4447  Returns
4448  -------
4449  output: tensor_like
4450  Flattened tensor.
4451 
4452  Examples
4453  --------
4454  >>> import ctf
4455  >>> a = ctf.astensor([1,2,3,4,5,6,7,8]).reshape(2,2,2)
4456  >>> a
4457  array([[[1, 2],
4458  [3, 4]],
4459  [[5, 6],
4460  [7, 8]]])
4461  >>> ctf.ravel(a)
4462  array([1, 2, 3, 4, 5, 6, 7, 8])
4463 
4464  """
4465  A = astensor(init_A)
4466  if _ord_comp(order, A.order):
4467  return A.reshape(-1)
4468  else:
4469  return tensor(copy=A, order=order).reshape(-1)
4470 
4471 def any(tensor init_A, axis=None, out=None, keepdims=None):
4472  """
4473  any(A, axis=None, out=None, keepdims = False)
4474  Return whether given an axis any elements are True.
4475 
4476  Parameters
4477  ----------
4478  A: tensor_like
4479  Input tensor.
4480 
4481  axis: None or int, optional
4482  Axis along which logical OR is applied.
4483 
4484  out: tensor_like, optional
4485  Objects which will place the result.
4486 
4487  keepdims: bool, optional
4488  If keepdims is set to True, the reduced axis will remain 1 in shape.
4489 
4490  Returns
4491  -------
4492  output: tensor_like
4493  Output tensor or scalar.
4494 
4495  Examples
4496  --------
4497  >>> import ctf
4498  >>> a = ctf.astensor([[0, 0], [1, 1]])
4499  >>> ctf.any(a)
4500  True
4501  >>> ctf.any(a, axis=0)
4502  array([ True, True])
4503  >>> ctf.any(a, axis=1)
4504  array([False, True])
4505  """
4506  cdef tensor A = astensor(init_A)
4507 
4508  if keepdims is None:
4509  keepdims = False
4510 
4511  if axis is None:
4512  if out is not None and type(out) != np.ndarray:
4513  raise ValueError('CTF PYTHON ERROR: output must be an array')
4514  if out is not None and out.shape != () and keepdims == False:
4515  raise ValueError('CTF PYTHON ERROR: output parameter has too many dimensions')
4516  if keepdims == True:
4517  dims_keep = []
4518  for i in range(len(A.shape)):
4519  dims_keep.append(1)
4520  dims_keep = tuple(dims_keep)
4521  if out is not None and out.shape != dims_keep:
4522  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
4523  B = tensor((1,), dtype=np.bool)
4524  index_A = _get_num_str(len(A.shape))
4525  if A.get_type() == np.float64:
4526  any_helper[double](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4527  elif A.get_type() == np.int64:
4528  any_helper[int64_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4529  elif A.get_type() == np.int32:
4530  any_helper[int32_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4531  elif A.get_type() == np.int16:
4532  any_helper[int16_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4533  elif A.get_type() == np.int8:
4534  any_helper[int8_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4535  elif A.get_type() == np.bool:
4536  any_helper[bool](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), "".encode())
4537  if out is not None and out.get_type() != np.bool:
4538  C = tensor((1,), dtype=out.dtype)
4539  B._convert_type(C)
4540  vals = C.read([0])
4541  return vals[0]
4542  elif out is not None and keepdims == True and out.get_type() != np.bool:
4543  C = tensor(dims_keep, dtype=out.dtype)
4544  B._convert_type(C)
4545  return C
4546  elif out is None and keepdims == True:
4547  ret = reshape(B,dims_keep)
4548  return ret
4549  elif out is not None and keepdims == True and out.get_type() == np.bool:
4550  ret = reshape(B,dims_keep)
4551  return ret
4552  else:
4553  vals = B.read([0])
4554  return vals[0]
4555 
4556 
4557  dim = A.shape
4558  if isinstance(axis, (int, np.integer)):
4559  if axis < 0:
4560  axis += len(dim)
4561  if axis >= len(dim) or axis < 0:
4562  raise ValueError("'axis' entry is out of bounds")
4563  dim_ret = np.delete(dim, axis)
4564  if out is not None:
4565  if type(out) != np.ndarray:
4566  raise ValueError('CTF PYTHON ERROR: output must be an array')
4567  if len(dim_ret) != len(out.shape):
4568  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
4569  for i in range(len(dim_ret)):
4570  if dim_ret[i] != out.shape[i]:
4571  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
4572  dim_keep = None
4573  if keepdims == True:
4574  dim_keep = dim
4575  dim_keep[axis] = 1
4576  if out is not None:
4577  if tuple(dim_keep) != tuple(out.shape):
4578  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
4579  index_A = _get_num_str(len(dim))
4580  index_temp = _rev_array(index_A)
4581  index_B = index_temp[0:axis] + index_temp[axis+1:len(dim)]
4582  index_B = _rev_array(index_B)
4583  B = tensor(dim_ret, dtype=np.bool)
4584  if A.get_type() == np.float64:
4585  any_helper[double](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4586  elif A.get_type() == np.int64:
4587  any_helper[int64_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4588  elif A.get_type() == np.int32:
4589  any_helper[int32_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4590  elif A.get_type() == np.int16:
4591  any_helper[int16_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4592  elif A.get_type() == np.int8:
4593  any_helper[int8_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4594  elif A.get_type() == np.bool:
4595  any_helper[bool](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4596  if out is not None:
4597  if out.dtype != B.get_type():
4598  if keepdims == True:
4599  C = tensor(dim_ret, dtype=out.dtype)
4600  B._convert_type(C)
4601  return reshape(C, dim_keep)
4602  else:
4603  C = tensor(dim_ret, dtype=out.dtype)
4604  B._convert_type(C)
4605  return C
4606  if keepdims == True:
4607  return reshape(B, dim_keep)
4608  return B
4609  elif isinstance(axis, (tuple, np.ndarray)):
4610  axis = np.asarray(axis, dtype=np.int64)
4611  dim_keep = None
4612  if keepdims == True:
4613  dim_keep = dim
4614  for i in range(len(axis)):
4615  dim_keep[axis[i]] = 1
4616  if out is not None:
4617  if tuple(dim_keep) != tuple(out.shape):
4618  raise ValueError('CTF PYTHON ERROR: output must match when keepdims = True')
4619  for i in range(len(axis.shape)):
4620  if axis[i] < 0:
4621  axis[i] += len(dim)
4622  if axis[i] >= len(dim) or axis[i] < 0:
4623  raise ValueError("'axis' entry is out of bounds")
4624  for i in range(len(axis.shape)):
4625  if np.count_nonzero(axis==axis[i]) > 1:
4626  raise ValueError("duplicate value in 'axis'")
4627  dim_ret = np.delete(dim, axis)
4628  if out is not None:
4629  if type(out) != np.ndarray:
4630  raise ValueError('CTF PYTHON ERROR: output must be an array')
4631  if len(dim_ret) != len(out.shape):
4632  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
4633  for i in range(len(dim_ret)):
4634  if dim_ret[i] != out.shape[i]:
4635  raise ValueError('CTF PYTHON ERROR: output parameter dimensions mismatch')
4636  B = tensor(dim_ret, dtype=np.bool)
4637  index_A = _get_num_str(len(dim))
4638  index_temp = _rev_array(index_A)
4639  index_B = ""
4640  for i in range(len(dim)):
4641  if i not in axis:
4642  index_B += index_temp[i]
4643  index_B = _rev_array(index_B)
4644  if A.get_type() == np.float64:
4645  any_helper[double](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4646  elif A.get_type() == np.int64:
4647  any_helper[int64_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4648  elif A.get_type() == np.int32:
4649  any_helper[int32_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4650  elif A.get_type() == np.int16:
4651  any_helper[int16_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4652  elif A.get_type() == np.int8:
4653  any_helper[int8_t](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4654  elif A.get_type() == np.bool:
4655  any_helper[bool](<ctensor*>A.dt, <ctensor*>B.dt, index_A.encode(), index_B.encode())
4656  if out is not None:
4657  if out.dtype != B.get_type():
4658  if keepdims == True:
4659  C = tensor(dim_ret, dtype=out.dtype)
4660  B._convert_type(C)
4661  return reshape(C, dim_keep)
4662  else:
4663  C = tensor(dim_ret, dtype=out.dtype)
4664  B._convert_type(C)
4665  return C
4666  if keepdims == True:
4667  return reshape(B, dim_keep)
4668  return B
4669  else:
4670  raise ValueError("an integer is required")
4671  return None
4672 
4673 def _stackdim(in_tup, dim):
4674  if type(in_tup) != tuple:
4675  raise ValueError('CTF PYTHON ERROR: The type of input should be tuple')
4676  ttup = []
4677  max_dim = 0
4678  for i in range(len(in_tup)):
4679  ttup.append(astensor(in_tup[i]))
4680  if ttup[i].ndim == 0:
4681  ttup[i] = ttup[i].reshape([1])
4682  max_dim = max(max_dim,ttup[i].ndim)
4683  new_dtype = _get_np_dtype([t.dtype for t in ttup])
4684  tup = []
4685  for i in range(len(ttup)):
4686  tup.append(astensor(ttup[i],dtype=new_dtype))
4687  #needed for vstack/hstack
4688  if max_dim == 1:
4689  if dim == 0:
4690  for i in range(len(ttup)):
4691  tup[i] = tup[i].reshape([1,tup[i].shape[0]])
4692  else:
4693  dim = 0
4694  out_shape = np.asarray(tup[0].shape)
4695  out_shape[dim] = np.sum([t.shape[dim] for t in tup])
4696  out = tensor(out_shape, dtype=new_dtype)
4697  acc_len = 0
4698  for i in range(len(tup)):
4699  if dim == 0:
4700  out[acc_len:acc_len+tup[i].shape[dim],...] = tup[i]
4701  elif dim == 1:
4702  out[:,acc_len:acc_len+tup[i].shape[dim],...] = tup[i]
4703  else:
4704  raise ValueError('CTF PYTHON ERROR: ctf.stackdim currently only supports dim={0,1}, although this is easily fixed')
4705  acc_len += tup[i].shape[dim]
4706  return out
4707 
4708 
4709 def hstack(in_tup):
4710  """
4711  hstack(in_tup)
4712  Stack the tensor in column-wise.
4713 
4714  Parameters
4715  ----------
4716  in_tup: tuple of tensors
4717  Input tensor.
4718 
4719  Returns
4720  -------
4721  output: tensor_like
4722  Output horizontally stacked tensor.
4723 
4724  Examples
4725  --------
4726  >>> import ctf
4727  >>> a = ctf.astensor([1,2,3])
4728  >>> b = ctf.astensor([4,5,6])
4729  >>> ctf.hstack((a, b))
4730  array([1, 2, 3, 4, 5, 6])
4731  """
4732  return _stackdim(in_tup, 1)
4733 
4734 def vstack(in_tup):
4735  """
4736  vstack(in_tup)
4737  Stack the tensor in row-wise.
4738 
4739  Parameters
4740  ----------
4741  in_tup: tuple of tensors
4742  Input tensor.
4743 
4744  Returns
4745  -------
4746  output: tensor_like
4747  Output vertically stacked tensor.
4748 
4749  Examples
4750  --------
4751  >>> import ctf
4752  >>> a = ctf.astensor([1,2,3])
4753  >>> b = ctf.astensor([4,5,6])
4754  >>> ctf.vstack((a, b))
4755  array([[1, 2, 3],
4756  [4, 5, 6]])
4757  """
4758  return _stackdim(in_tup, 0)
4759 
4760 def conj(init_A):
4761  """
4762  conj(A)
4763  Return the conjugate tensor A element-wisely.
4764 
4765  Parameters
4766  ----------
4767  A: tensor_like
4768  Input tensor.
4769 
4770  Returns
4771  -------
4772  output: tensor
4773  The element-wise complex conjugate of input tensor A. If tensor A is not complex, just return a copy of A.
4774 
4775  Examples
4776  --------
4777  >>> import ctf
4778  >>> a = ctf.astensor([2+3j, 3-2j])
4779  array([2.+3.j, 3.-2.j])
4780  >>> ctf.conj(a)
4781  array([2.-3.j, 3.+2.j])
4782  """
4783  cdef tensor A = astensor(init_A)
4784  if A.get_type() == np.complex64:
4785  B = tensor(A.shape, dtype=A.get_type())
4786  conj_helper[float](<ctensor*> A.dt, <ctensor*> B.dt);
4787  return B
4788  elif A.get_type() == np.complex128:
4789  B = tensor(A.shape, dtype=A.get_type())
4790  conj_helper[double](<ctensor*> A.dt, <ctensor*> B.dt);
4791  return B
4792  else:
4793  return A.copy()
4794 
4795 def all(inA, axis=None, out=None, keepdims = False):
4796  """
4797  all(A, axis=None, out=None, keepdims = False)
4798  Return whether given an axis elements are True.
4799 
4800  Parameters
4801  ----------
4802  A: tensor_like
4803  Input tensor.
4804 
4805  axis: None or int, optional
4806  Currently not supported in CTF Python.
4807 
4808  out: tensor, optional
4809  Currently not supported in CTF Python.
4810 
4811  keepdims : bool, optional
4812  Currently not supported in CTF Python.
4813 
4814  Returns
4815  -------
4816  output: tensor_like
4817  Output tensor or scalar.
4818 
4819  Examples
4820  --------
4821  >>> import ctf
4822  >>> a = ctf.astensor([[0, 1], [1, 1]])
4823  >>> ctf.all(a)
4824  False
4825  """
4826  if isinstance(inA, tensor):
4827  return _comp_all(inA, axis, out, keepdims)
4828  else:
4829  if isinstance(inA, np.ndarray):
4830  return np.all(inA,axis,out,keepdims)
4831  if isinstance(inA, np.bool):
4832  return inA
4833  else:
4834  raise ValueError('CTF PYTHON ERROR: ctf.all called on invalid operand')
4835 
4836 
4837 def _comp_all(tensor A, axis=None, out=None, keepdims=None):
4838  if keepdims is None:
4839  keepdims = False
4840  if axis is not None:
4841  raise ValueError("'axis' not supported for all yet")
4842  if out is not None:
4843  raise ValueError("'out' not supported for all yet")
4844  if keepdims:
4845  raise ValueError("'keepdims' not supported for all yet")
4846  if axis is None:
4847  x = A._bool_sum()
4848  return x == A._tot_size()
4849 
4850 def transpose(init_A, axes=None):
4851  """
4852  transpose(A, axes=None)
4853  Permute the dimensions of the input tensor.
4854 
4855  Parameters
4856  ----------
4857  A: tensor_like
4858  Input tensor.
4859 
4860  axes: list of ints, optional
4861  If axes is None, the dimensions are inversed, otherwise permute the dimensions according to the axes value.
4862 
4863  Returns
4864  -------
4865  output: tensor
4866  Tensor with permuted axes of A.
4867 
4868  Examples
4869  --------
4870  >>> import ctf
4871  >>> a = ctf.zeros([3,4,5])
4872  >>> a.shape
4873  (3, 4, 5)
4874  >>> ctf.transpose(a, axes=[0, 2, 1]).shape
4875  (3, 5, 4)
4876  >>> ctf.transpose(a).shape
4877  (5, 4, 3)
4878  """
4879  A = astensor(init_A)
4880 
4881  dim = A.shape
4882  if axes is None:
4883  new_dim = []
4884  for i in range(len(dim)-1, -1, -1):
4885  new_dim.append(dim[i])
4886  new_dim = tuple(new_dim)
4887  B = tensor(new_dim, dtype=A.get_type())
4888  index = _get_num_str(len(dim))
4889  rev_index = str(index[::-1])
4890  B.i(rev_index) << A.i(index)
4891  return B
4892 
4893  # length of axes should match with the length of tensor dimension
4894  if len(axes) != len(dim):
4895  raise ValueError("axes don't match tensor")
4896  axes = np.asarray(axes,dtype=np.int)
4897  for i in range(A.ndim):
4898  if axes[i] < 0:
4899  axes[i] = A.ndim+axes[i]
4900  if axes[i] < 0:
4901  raise ValueError("axes too negative for CTF transpose")
4902 
4903  axes_list = list(axes)
4904  for i in range(len(axes)):
4905  # when any elements of axes is not an integer
4906  #if type(axes_list[i]) != int:
4907  # print(type(axes_list[i]))
4908  # raise ValueError("an integer is required")
4909  # change the negative axes to positive, which will be easier hangling
4910  if axes_list[i] < 0:
4911  axes_list[i] += len(dim)
4912  for i in range(len(axes)):
4913  # if axes out of bound
4914  if axes_list[i] >= len(dim) or axes_list[i] < 0:
4915  raise ValueError("invalid axis for this tensor")
4916  # if axes are repeated
4917  if axes_list.count(axes_list[i]) > 1:
4918  raise ValueError("repeated axis in transpose")
4919 
4920  index = _get_num_str(len(dim))
4921  rev_index = ""
4922  rev_dims = np.asarray(dim)
4923  for i in range(len(dim)):
4924  rev_index += index[axes_list[i]]
4925  rev_dims[i] = dim[axes_list[i]]
4926  B = tensor(rev_dims, dtype=A.get_type())
4927  B.i(rev_index) << A.i(index)
4928  return B
4929 
4930 def ones(shape, dtype = None, order='F'):
4931  """
4932  ones(shape, dtype = None, order='F')
4933  Return a tensor filled with ones with specified shape and dtype.
4934 
4935  Parameters
4936  ----------
4937  shape: int or sequence of ints
4938  Shape of the returned tensor.
4939 
4940  dtype: numpy data-type, optional
4941  The data-type for the tensor.
4942 
4943  order: {‘C’, ‘F’}, optional
4944  Not support by current CTF Python.
4945 
4946  Returns
4947  -------
4948  output: tensor
4949  Tensor with specified shape and dtype.
4950 
4951  Examples
4952  --------
4953  >>> import ctf
4954  >>> a = ctf.ones([2, 2])
4955  >>> a
4956  array([[1., 1.],
4957  [1., 1.]])
4958  """
4959  if isinstance(shape,int):
4960  shape = (shape,)
4961  shape = np.asarray(shape)
4962  if dtype is not None:
4963  ret = tensor(shape, dtype = dtype)
4964  string = ""
4965  string_index = 33
4966  for i in range(len(shape)):
4967  string += chr(string_index)
4968  string_index += 1
4969  if dtype == np.float64:
4970  ret.i(string) << 1.0
4971  elif dtype == np.complex128:
4972  ret.i(string) << 1.0
4973  elif dtype == np.int64:
4974  ret.i(string) << 1
4975  elif dtype == np.bool:
4976  ret.i(string) << 1
4977  return ret
4978  else:
4979  ret = tensor(shape, dtype = np.float64)
4980  string = ""
4981  string_index = 33
4982  for i in range(len(shape)):
4983  string += chr(string_index)
4984  string_index += 1
4985  ret.i(string) << 1.0
4986  return ret
4987 
4988 def eye(n, m=None, k=0, dtype=np.float64, sp=False):
4989  """
4990  eye(n, m=None, k=0, dtype=np.float64, sp=False)
4991  Return a 2D tensor with ones on the diagonal and zeros elsewhere.
4992 
4993  Parameters
4994  ----------
4995  n: int
4996  Number of rows.
4997 
4998  m: int, optional
4999  Number of columns, default set to n.
5000 
5001  k: int, optional
5002  Diagonal index, specify ones on main diagonal, upper diagonal or lower diagonal.
5003 
5004  dtype: data-type, optional
5005  Numpy data-type of returned tensor, default `np.float64`.
5006 
5007  sp: bool, optional
5008  If `true` the returned tensor will be sparse, default `sp=False`.
5009 
5010  Returns
5011  -------
5012  output: tensor
5013 
5014 
5015  Examples
5016  --------
5017  >>> import ctf
5018  >>> e = ctf.eye(3,m=4,k=-1)
5019  >>> e
5020  array([[0., 0., 0., 0.],
5021  [1., 0., 0., 0.],
5022  [0., 1., 0., 0.]])
5023  """
5024  mm = n
5025  if m is not None:
5026  mm = m
5027  l = min(mm,n)
5028  if k >= 0:
5029  l = min(l,mm-k)
5030  else:
5031  l = min(l,n+k)
5032 
5033  A = tensor([l, l], dtype=dtype, sp=sp)
5034  if dtype == np.float64 or dtype == np.complex128 or dtype == np.complex64 or dtype == np.float32:
5035  A.i("ii") << 1.0
5036  elif dtype == np.bool or dtype == np.int64 or dtype == np.int32 or dtype == np.int16 or dtype == np.int8:
5037  A.i("ii") << 1
5038  else:
5039  raise ValueError('CTF PYTHON ERROR: bad dtype')
5040  if m is None:
5041  return A
5042  else:
5043  B = tensor([n, m], dtype=dtype, sp=sp)
5044  if k >= 0:
5045  B._write_slice([0, k], [l, l+k], A)
5046  else:
5047  B._write_slice([-k, 0], [l-k, l], A)
5048  return B
5049 
5050 def identity(n, dtype=np.float64):
5051  """
5052  identity(n, dtype=np.float64)
5053  Return a squared 2-D tensor where the main diagonal contains ones and elsewhere zeros.
5054 
5055  Parameters
5056  ----------
5057  n: int
5058  Number of rows.
5059 
5060  dtype: data-type, optional
5061  Numpy data-type of returned tensor, default `np.float64`.
5062 
5063  Returns
5064  -------
5065  output: tensor
5066 
5067  See Also
5068  --------
5069  ctf : ctf.eye()
5070 
5071  Examples
5072  --------
5073  >>> import ctf
5074  >>> a = ctf.identity(3)
5075  >>> a
5076  array([[1., 0., 0.],
5077  [0., 1., 0.],
5078  [0., 0., 1.]])
5079  """
5080  return eye(n, dtype=dtype)
5081 
5082 def speye(n, m=None, k=0, dtype=np.float64):
5083  """
5084  speye(n, m=None, k=0, dtype=np.float64)
5085  Return a sparse 2D tensor with ones on the diagonal and zeros elsewhere.
5086 
5087  Parameters
5088  ----------
5089  n: int
5090  Number of rows.
5091 
5092  m: int, optional
5093  Number of columns, default set to n.
5094 
5095  k: int, optional
5096  Diagonal index, specify ones on main diagonal, upper diagonal or lower diagonal.
5097 
5098  dtype: data-type, optional
5099  Numpy data-type of returned tensor, default `np.float64`.
5100 
5101  Returns
5102  -------
5103  output: tensor
5104 
5105  See Also
5106  --------
5107  ctf : ctf.eye()
5108 
5109  Examples
5110  --------
5111  >>> import ctf
5112  >>> e = ctf.speye(3,m=4,k=-1)
5113  >>> e
5114  array([[0., 0., 0., 0.],
5115  [1., 0., 0., 0.],
5116  [0., 1., 0., 0.]])
5117 
5118  """
5119  return eye(n, m, k, dtype, sp=True)
5120 
5121 def einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe'):
5122  """
5123  einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe')
5124  Einstein summation on operands.
5125 
5126  Parameters
5127  ----------
5128  subscripts: str
5129  Subscripts for summation.
5130 
5131  operands: list of tensor
5132  List of tensors.
5133 
5134  out: tensor or None
5135  If the out is not None, calculated result will stored into out tensor.
5136 
5137  dtype: data-type, optional
5138  Numpy data-type of returned tensor, dtype of returned tensor will be specified by operand tensors.
5139 
5140  order: {‘C’, ‘F’, ‘A’, ‘K’}, optional
5141  Currently not supported by CTF Python.
5142 
5143  casting: {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional
5144  Currently not supported by CTF Python.
5145 
5146  Returns
5147  -------
5148  output: tensor
5149 
5150  See Also
5151  --------
5152  numpy : numpy.einsum()
5153 
5154  Examples
5155  --------
5156  >>> import ctf
5157  >>> a = ctf.astensor([[1,2,3], [4,5,6], [7,8,9]])
5158  >>> ctf.einsum("ii->i", a)
5159  array([1, 5, 9])
5160  """
5161  if order != 'K' or casting != 'safe':
5162  raise ValueError('CTF PYTHON ERROR: CTF Python einsum currently does not support order and casting')
5163  numop = len(operands)
5164  inds = []
5165  j=0
5166  dind_lens = dict()
5167  uniq_subs = set()
5168  all_inds = []
5169  for i in range(numop):
5170  inds.append('')
5171  while j < len(subscripts) and subscripts[j] != ',' and subscripts[j] != ' ' and subscripts[j] != '-':
5172  if dind_lens.has_key(subscripts[j]):
5173  uniq_subs.discard(subscripts[j])
5174  else:
5175  uniq_subs.add(subscripts[j])
5176  if operands[i].ndim <= len(inds[i]):
5177  raise ValueError("CTF PYTHON ERROR: einsum subscripts string contains too many subscripts for operand {0}".format(i))
5178  dind_lens[subscripts[j]] = operands[i].shape[len(inds[i])]
5179  inds[i] += subscripts[j]
5180  all_inds.append(subscripts[j])
5181  j += 1
5182  j += 1
5183  while j < len(subscripts) and subscripts[j] == ' ':
5184  j += 1
5185  out_inds = ''
5186  out_lens = []
5187  do_reduce = 0
5188  if j < len(subscripts) and subscripts[j] == '-':
5189  j += 1
5190  if j < len(subscripts) and subscripts[j] == '>':
5191  start_out = 1
5192  j += 1
5193  do_reduce = 1
5194  while j < len(subscripts) and subscripts[j] == ' ':
5195  j += 1
5196  while j < len(subscripts) and subscripts[j] != ' ':
5197  out_inds += subscripts[j]
5198  out_lens.append(dind_lens[subscripts[j]])
5199  j += 1
5200  if do_reduce == 0:
5201  for ind in all_inds:
5202  if ind in uniq_subs:
5203  out_inds += ind
5204  out_lens.append(dind_lens[ind])
5205  uniq_subs.remove(ind)
5206  if out is None:
5207  out_dtype = _get_np_dtype([x.dtype for x in operands])
5208  output = tensor(out_lens, dtype=out_dtype)
5209  else:
5210  output = out
5211  if numop == 1:
5212  output.i(out_inds) << operands[0].i(inds[0])
5213  elif numop == 2:
5214  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])
5215  elif numop == 3:
5216  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])
5217  elif numop == 4:
5218  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])
5219  elif numop == 5:
5220  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])
5221  elif numop == 6:
5222  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])*operands[5].i(inds[5])
5223  elif numop == 7:
5224  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])*operands[5].i(inds[5])*operands[6].i(inds[6])
5225  elif numop == 8:
5226  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])*operands[5].i(inds[5])*operands[6].i(inds[6])*operands[7].i(inds[7])
5227  elif numop == 9:
5228  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])*operands[5].i(inds[5])*operands[6].i(inds[6])*operands[7].i(inds[7])*operands[8].i(inds[8])
5229  elif numop == 10:
5230  output.i(out_inds) << operands[0].i(inds[0])*operands[1].i(inds[1])*operands[2].i(inds[2])*operands[3].i(inds[3])*operands[4].i(inds[4])*operands[5].i(inds[5])*operands[6].i(inds[6])*operands[7].i(inds[7])*operands[8].i(inds[8])*operands[9].i(inds[9])
5231  else:
5232  raise ValueError('CTF PYTHON ERROR: CTF einsum currently allows no more than 10 operands')
5233  return output
5234 
5235 def svd(tensor A, rank=None):
5236  """
5237  svd(A, rank=None)
5238  Compute Single Value Decomposition of tensor A.
5239 
5240  Parameters
5241  ----------
5242  A: tensor_like
5243  Input tensor 2-D dimensions.
5244 
5245  rank: int or None, optional
5246  Target rank for SVD, default `k=0`.
5247 
5248  Returns
5249  -------
5250  U: tensor
5251  A unitary CTF tensor with 2-D dimensions.
5252 
5253  S: tensor
5254  A 1-D tensor with singular values.
5255 
5256  VT: tensor
5257  A unitary CTF tensor with 2-D dimensions.
5258  """
5259  if not isinstance(A,tensor) or A.ndim != 2:
5260  raise ValueError('CTF PYTHON ERROR: SVD called on invalid tensor, must be CTF double matrix')
5261  if rank is None:
5262  rank = 0
5263  k = min(A.shape[0],A.shape[1])
5264  else:
5265  k = rank
5266  S = tensor(k,dtype=A.dtype)
5267  U = tensor([A.shape[0],k],dtype=A.dtype)
5268  VT = tensor([k,A.shape[1]],dtype=A.dtype)
5269  if A.dtype == np.float64 or A.dtype == np.float32:
5270  matrix_svd(A.dt, VT.dt, S.dt, U.dt, rank)
5271  elif A.dtype == np.complex128 or A.dtype == np.complex64:
5272  matrix_svd_cmplx(A.dt, VT.dt, S.dt, U.dt, rank)
5273  return [U, S, VT]
5274 
5275 def qr(tensor A):
5276  """
5277  qr(A)
5278  Compute QR factorization of tensor A.
5279 
5280  Parameters
5281  ----------
5282  A: tensor_like
5283  Input tensor 2-D dimensions.
5284 
5285  Returns
5286  -------
5287  Q: tensor
5288  A CTF tensor with 2-D dimensions and orthonormal columns.
5289 
5290  R: tensor
5291  An upper triangular 2-D CTF tensor.
5292  """
5293  if not isinstance(A,tensor) or A.ndim != 2:
5294  raise ValueError('CTF PYTHON ERROR: QR called on invalid tensor, must be CTF double matrix')
5295  B = tensor(copy=A.T())
5296  Q = tensor(B.shape,dtype=B.dtype)
5297  R = tensor([B.shape[0],B.shape[0]],dtype=B.dtype)
5298  if A.dtype == np.float64 or A.dtype == np.float32:
5299  matrix_qr(B.dt, Q.dt, R.dt)
5300  elif A.dtype == np.complex128 or A.dtype == np.complex64:
5301  matrix_qr_cmplx(B.dt, Q.dt, R.dt)
5302  return [Q.T(), R.T()]
5303 
5304 def vecnorm(A, ord=2):
5305  """
5306  vecnorm(A, ord=2)
5307  Return norm of tensor A.
5308 
5309  Parameters
5310  ----------
5311  A: tensor_like
5312  Input tensor with 1-D or 2-D dimensions. If A is 1-D tensor, return a 2-D tensor with A on diagonal.
5313 
5314  ord: {int 1, 2, inf}, optional
5315  Order of the norm.
5316 
5317  Returns
5318  -------
5319  output: tensor
5320  Norm of tensor A.
5321 
5322  Examples
5323  --------
5324  >>> import ctf
5325  >>> import ctf.linalg as la
5326  >>> a = ctf.astensor([3,4.])
5327  >>> la.vecnorm(a)
5328  5.0
5329  """
5330  if ord == 2:
5331  return A.norm2()
5332  elif ord == 1:
5333  return A.norm1()
5334  elif ord == np.inf:
5335  return A.norm_infty()
5336  else:
5337  raise ValueError('CTF PYTHON ERROR: CTF only supports 1/2/inf vector norms')
5338 
5339 def _match_tensor_types(first, other):
5340  if isinstance(first, tensor):
5341  tsr = first
5342  else:
5343  tsr = tensor(copy=astensor(first),sp=other.sp)
5344  if isinstance(other, tensor):
5345  otsr = other
5346  else:
5347  otsr = tensor(copy=astensor(other),sp=first.sp)
5348  out_dtype = _get_np_dtype([tsr.dtype, otsr.dtype])
5349  if tsr.dtype != out_dtype:
5350  tsr = tensor(copy=tsr, dtype = out_dtype)
5351  if otsr.dtype != out_dtype:
5352  otsr = tensor(copy=otsr, dtype = out_dtype)
5353  return [tsr, otsr]
5354 
5355 def _div(first, other):
5356  if isinstance(first, tensor):
5357  tsr = first
5358  else:
5359  tsr = tensor(copy=astensor(first))
5360  if isinstance(other, tensor):
5361  otsr = other
5362  else:
5363  otsr = tensor(copy=astensor(other))
5364  out_dtype = _get_np_div_dtype(tsr.dtype, otsr.dtype)
5365  if tsr.dtype != out_dtype:
5366  tsr = tensor(copy=tsr, dtype = out_dtype)
5367  if otsr.dtype != out_dtype:
5368  otsr = tensor(copy=otsr, dtype = out_dtype)
5369 
5370  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
5371 
5372  if otsr is other:
5373  otsr = tensor(copy=other)
5374 
5375  otsr._invert_elements()
5376 
5377  out_tsr.i(idx_C) << tsr.i(idx_A)*otsr.i(idx_B)
5378  return out_tsr
5379 
5380 def _tensor_pow_helper(tensor tsr, tensor otsr, tensor out_tsr, idx_A, idx_B, idx_C):
5381  if _ord_comp(tsr.order, 'F'):
5382  idx_A = _rev_array(idx_A)
5383  if _ord_comp(otsr.order, 'F'):
5384  idx_B = _rev_array(idx_B)
5385  if _ord_comp(out_tsr.order, 'F'):
5386  idx_C = _rev_array(idx_C)
5387  if out_tsr.dtype == np.float64:
5388  pow_helper[double](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5389  elif out_tsr.dtype == np.float32:
5390  pow_helper[float](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5391  elif out_tsr.dtype == np.complex64:
5392  pow_helper[complex64_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5393  elif out_tsr.dtype == np.complex128:
5394  pow_helper[complex128_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5395  elif out_tsr.dtype == np.int64:
5396  pow_helper[int64_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5397  elif out_tsr.dtype == np.int32:
5398  pow_helper[int32_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5399  elif out_tsr.dtype == np.int16:
5400  pow_helper[int16_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5401  elif out_tsr.dtype == np.int8:
5402  pow_helper[int8_t](<ctensor*>tsr.dt, <ctensor*>otsr.dt, <ctensor*>out_tsr.dt, idx_A.encode(), idx_B.encode(), idx_C.encode())
5403 
5404 def power(first, second):
5405  """
5406  power(A, B)
5407  Elementwisely raise tensor A to powers from the tensor B.
5408 
5409  Parameters
5410  ----------
5411  A: tensor_like
5412  Bases tensor.
5413 
5414  B: tensor_like
5415  Exponents tensor
5416 
5417  Returns
5418  -------
5419  output: tensor
5420  The output tensor containing elementwise bases A raise to exponents of B.
5421 
5422  Examples
5423  --------
5424  >>> import ctf
5425  >>> a = ctf.astensor([2., 3])
5426  array([2., 3.])
5427  >>> b = ctf.astensor([2., 3])
5428  array([2., 3.])
5429  >>> ctf.power(a, b)
5430  array([ 4., 27.])
5431  """
5432  [tsr, otsr] = _match_tensor_types(first,second)
5433 
5434  [idx_A, idx_B, idx_C, out_tsr] = tsr._ufunc_interpret(otsr)
5435 
5436  _tensor_pow_helper(tsr, otsr, out_tsr, idx_A, idx_B, idx_C)
5437 
5438  return out_tsr
5439 
5440 def abs(initA):
5441  """
5442  abs(A)
5443  Calculate the elementwise absolute value of a tensor.
5444 
5445  Parameters
5446  ----------
5447  A: tensor_like
5448  Input tensor.
5449 
5450  Returns
5451  -------
5452  output: tensor
5453  A tensor containing the absolute value of each element in input tensor. For complex number :math:`a + bi`, the absolute value is calculated as :math:`\sqrt{a^2 + b^2}`
5454 
5455  References
5456  ----------
5457 
5458  Examples
5459  --------
5460  >>> import ctf
5461  >>> a = ctf.astensor([-2, 3])
5462  array([-2, 3])
5463  >>> abs(a)
5464  array([2, 3])
5465 
5466  """
5467  cdef tensor A = astensor(initA)
5468  cdef tensor oA = tensor(copy=A)
5469  if A.dtype == np.float64:
5470  abs_helper[double](<ctensor*>A.dt, <ctensor*>oA.dt)
5471  elif A.dtype == np.float32:
5472  abs_helper[float](<ctensor*>A.dt, <ctensor*>oA.dt)
5473  elif A.dtype == np.complex64:
5474  abs_helper[complex64_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5475  elif A.dtype == np.complex128:
5476  abs_helper[complex128_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5477  elif A.dtype == np.int64:
5478  abs_helper[int64_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5479  elif A.dtype == np.int32:
5480  abs_helper[int32_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5481  elif A.dtype == np.int16:
5482  abs_helper[int16_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5483  elif A.dtype == np.int8:
5484  abs_helper[int8_t](<ctensor*>A.dt, <ctensor*>oA.dt)
5485  return oA
5486 
5487 def _setgetitem_helper(obj, key_init):
5488  is_everything = 1
5489  is_contig = 1
5490  inds = []
5491  lensl = 1
5492  key = deepcopy(key_init)
5493  corr_shape = []
5494  one_shape = []
5495  if isinstance(key,int):
5496  key = (key,)
5497  elif isinstance(key,slice):
5498  key = (key,)
5499  elif key is Ellipsis:
5500  key = (key,)
5501  else:
5502  if not isinstance(key, tuple):
5503  raise ValueError("CTF PYTHON ERROR: fancy indexing with non-slice/int/ellipsis-type indices is unsupported and can instead be done via take or read/write")
5504  for i in range(len(key)):
5505  if not isinstance(key[i], slice) and not isinstance(key[i],int) and key[i] is not Ellipsis:
5506  raise ValueError("CTF PYTHON ERROR: invalid __setitem__/__getitem__ tuple passed, type of elements not recognized")
5507  lensl = len(key)
5508  i=0
5509  is_single_val = 1
5510  saw_elips=False
5511  for s in key:
5512  if isinstance(s,int):
5513  if obj.shape[i] != 1:
5514  is_everything = 0
5515  inds.append((s,s+1,1))
5516  one_shape.append(1)
5517  i+=1
5518  elif s is Ellipsis:
5519  if saw_elips:
5520  raise ValueError('CTF PYTHON ERROR: Only one Ellipsis, ..., supported in __setitem__ and __getitem__')
5521  for j in range(lensl-1,obj.ndim):
5522  inds.append((0,obj.shape[i],1))
5523  corr_shape.append(obj.shape[i])
5524  one_shape.append(obj.shape[i])
5525  i+=1
5526  saw_elpis=True
5527  is_single_val = 0
5528  lensl = obj.ndim
5529  else:
5530  is_single_val = 0
5531  ind = s.indices(obj.shape[i])
5532  if ind[2] != 1:
5533  is_everything = 0
5534  is_contig = 0
5535  if ind[1] != obj.shape[i]:
5536  is_everything = 0
5537  if ind[0] != 0:
5538  is_everything = 0
5539  inds.append(ind)
5540  i+=1
5541  corr_shape.append(int((np.abs(ind[1]-ind[0])+np.abs(ind[2])-1)/np.abs(ind[2])))
5542  one_shape.append(int((np.abs(ind[1]-ind[0])+np.abs(ind[2])-1)/np.abs(ind[2])))
5543  if lensl != obj.ndim:
5544  is_single_val = 0
5545  for i in range(lensl,obj.ndim):
5546  inds.append((0,obj.shape[i],1))
5547  corr_shape.append(obj.shape[i])
5548  one_shape.append(obj.shape[i])
5549  return [key, is_everything, is_single_val, is_contig, inds, corr_shape, one_shape]
5550 
void permute(int order, int const *perm, int *arr)
permute an array
Definition: util.cxx:205
def astype(self, dtype, order='F', casting='unsafe')
Definition: core.pyx:1861
def permute(self, tensor, A, p_A=None, p_B=None, a=None, b=None)
Definition: core.pyx:2144
def ravel(init_A, order="F")
Definition: core.pyx:4434
def diagonal(self, offset=0, axis1=0, axis2=1)
Definition: core.pyx:2499
def __get__(self)
Definition: core.pyx:322
def get_type(self)
Definition: core.pyx:741
def get_dims(self)
Definition: core.pyx:728
def read(self, init_inds, vals=None, a=None, b=None)
Definition: core.pyx:1809
def sum(tensor, init_A, axis=None, dtype=None, out=None, keepdims=None)
Definition: core.pyx:4261
def norm2(self)
Definition: core.pyx:2594
def to_nparray(self)
Definition: core.pyx:2652
def reshape(A, newshape, order='F')
Definition: core.pyx:3612
def _compare_tensors(tensor, self, tensor, b, op)
Definition: core.pyx:2790
def _write_slice(self, offsets, ends, init_A, A_offsets=None, A_ends=None, a=None, b=None)
Definition: core.pyx:2285
def __add__(self, other)
Definition: core.pyx:337
def sample(tensor, self, p)
Definition: core.pyx:2761
def __dealloc__(self)
Definition: core.pyx:872
def norm1(self)
Definition: core.pyx:2570
def from_nparray(self, arr)
Definition: core.pyx:2682
def __float__(self)
Definition: core.pyx:1007
def __abs__(self)
Definition: core.pyx:991
def empty_like(A, dtype=None)
Definition: core.pyx:4224
def _ufunc_interpret(self, tensor, other, gen_tsr=True)
Definition: core.pyx:932
def rank(self)
Definition: core.pyx:312
def transpose(self, axes)
Definition: core.pyx:901
def __pow__(self, other, modulus)
Definition: core.pyx:1138
def real(tensor, A)
Definition: core.pyx:2997
int64_t sum_bool_tsr(tensor *A)
sum all 1 values in boolean tensor
Definition: ctf_ext.cxx:92
def T(self)
Definition: core.pyx:876
def read_all(self, arr=None, unpack=True)
Definition: core.pyx:2088
void matrix_svd(tensor *A, tensor *U, tensor *S, tensor *VT, int rank)
Definition: ctf_ext.cxx:175
def array(A, dtype=None, copy=True, order='K', subok=False, ndmin=0)
Definition: core.pyx:3079
def read_from_file(self, path, with_vals=True)
Definition: core.pyx:1272
def _convert_type(tensor, self, tensor, B)
Definition: core.pyx:724
int bivar_function(int n, World &dw)
def __cinit__(self)
Definition: core.pyx:306
def conv_type(self, dtype)
Definition: core.pyx:363
def conj(init_A)
Definition: core.pyx:4760
def vstack(in_tup)
Definition: core.pyx:4734
def conj(self)
Definition: core.pyx:2123
def __neg__(self)
Definition: core.pyx:1016
CTF::Vector Vector
Definition: back_comp.h:11
def __dealloc__(self)
Definition: core.pyx:309
def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None)
Definition: core.pyx:2459
def all(inA, axis=None, out=None, keepdims=False)
Definition: core.pyx:4795
def imag(tensor, A)
Definition: core.pyx:3038
def norm_infty(self)
Definition: core.pyx:2628
def copy(self)
Definition: core.pyx:1688
int endomorphism(int n, World &dw)
void matrix_qr_cmplx(tensor *A, tensor *Q, tensor *R)
Definition: ctf_ext.cxx:141
def any(tensor, init_A, axis=None, out=None, keepdims=None)
Definition: core.pyx:4471
def __idiv__(self, other_in)
Definition: core.pyx:1111
def from_nparray(arr)
Definition: core.pyx:4087
def tensordot(self, other, axes)
Definition: core.pyx:2022
def dot(tA, tB, out=None)
Definition: core.pyx:3698
def scl(self, s)
Definition: core.pyx:473
def __repr__(self)
Definition: core.pyx:366
def scale(self, scl)
Definition: core.pyx:325
def diag(A, k=0, sp=False)
Definition: core.pyx:3141
def power(first, second)
Definition: core.pyx:5404
CTF::Tensor Tensor
Definition: back_comp.h:9
CTF::World World
Definition: back_comp.h:7
void subsample(tensor *A, double probability)
extract a sample of the entries (if sparse of the current nonzeros)
Definition: ctf_ext.cxx:103
def identity(n, dtype=np.float64)
Definition: core.pyx:5050
def __cinit__(self, lens=None, sp=None, sym=None, dtype=None, order=None, tensor, copy=None)
Definition: core.pyx:754
def trace(init_A, offset=0, axis1=0, axis2=1, dtype=None, out=None)
Definition: core.pyx:3385
def __isub__(self, other_in)
Definition: core.pyx:1074
def __matmul__(self, other)
Definition: core.pyx:1172
def zeros_like(init_A, dtype=None, order='F')
Definition: core.pyx:4119
def ravel(self, order="F")
Definition: core.pyx:1790
def svd(tensor, A, rank=None)
Definition: core.pyx:5235
def __sub__(self, other)
Definition: core.pyx:1066
def prnt(self)
Definition: core.pyx:1578
def eye(n, m=None, k=0, dtype=np.float64, sp=False)
Definition: core.pyx:4988
def empty(shape, dtype=np.float64, order='F')
Definition: core.pyx:4191
def dot(self, other, out=None)
Definition: core.pyx:1989
def __imul__(self, other_in)
Definition: core.pyx:1054
def __getitem__(self, key_init)
Definition: core.pyx:2348
def all(tensor, self, axis=None, out=None, keepdims=None)
Definition: core.pyx:1348
def fill_random(self, mn=None, mx=None)
Definition: core.pyx:1177
def __deepcopy__(self, memo)
Definition: core.pyx:2343
def einsum(subscripts, operands, out=None, dtype=None, order='K', casting='safe')
Definition: core.pyx:5121
def vecnorm(A, ord=2)
Definition: core.pyx:5304
def __mul__(self, other)
Definition: core.pyx:1046
def real(self, tensor, value=None)
Definition: core.pyx:1595
def __iadd__(self, other_in)
Definition: core.pyx:1032
def abs(initA)
Definition: core.pyx:5440
def exp(init_x, out=None, where=True, casting='same_kind', order='F', dtype=None, subok=True)
Definition: core.pyx:3954
def __setitem__(self, key_init, value_init)
Definition: core.pyx:2422
def astensor(A, dtype=None, order=None)
Definition: core.pyx:3650
def copy(tensor, A)
Definition: core.pyx:3583
def _tot_size(self, unpack=True)
Definition: core.pyx:2085
def __repr__(self)
Definition: core.pyx:2679
def __mul__(first, second)
Definition: core.pyx:349
def zeros(shape, dtype=np.float64, order='F')
Definition: core.pyx:4157
CTF::Matrix Matrix
Definition: back_comp.h:10
def sum(self, axis=None, dtype=None, out=None, keepdims=None)
Definition: core.pyx:2533
def __nonzero__(self)
Definition: core.pyx:994
def __lshift__(self, other)
Definition: core.pyx:369
def fill_sp_random(self, mn=None, mx=None, frac_sp=None)
Definition: core.pyx:1221
def transpose(init_A, axes=None)
Definition: core.pyx:4850
def imag(self, tensor, value=None)
Definition: core.pyx:1640
def __int__(self)
Definition: core.pyx:1002
def tril(A, k=0)
Definition: core.pyx:2925
def write(self, init_inds, init_vals, a=None, b=None)
Definition: core.pyx:2210
def __richcmp__(self, b, op)
Definition: core.pyx:2750
void matrix_qr(tensor *A, tensor *Q, tensor *R)
Definition: ctf_ext.cxx:109
int univar_function(int n, World &dw)
def __get__(self)
Definition: core.pyx:654
def speye(n, m=None, k=0, dtype=np.float64)
Definition: core.pyx:5082
def set_zero(self)
Definition: core.pyx:2374
def reshape(self, integer)
Definition: core.pyx:1712
def diagonal(init_A, offset=0, axis1=0, axis2=1)
Definition: core.pyx:3289
def read_local_nnz(self)
Definition: core.pyx:2062
def __add__(self, other)
Definition: core.pyx:1023
def __div__(self, other)
Definition: core.pyx:1108
def MPI_Stop()
Definition: core.pyx:57
def triu(A, k=0)
Definition: core.pyx:2968
def take(self, indices, axis=None, out=None, mode='raise')
Definition: core.pyx:2713
def spdiag(A, k=0)
Definition: core.pyx:3258
def __sub__(self, other)
Definition: core.pyx:342
def i(self, string)
Definition: core.pyx:1549
def read_local(self)
Definition: core.pyx:1966
def hstack(in_tup)
Definition: core.pyx:4709
def __itruediv__(self, other_in)
Definition: core.pyx:1091
def write_to_file(self, path, with_vals=True)
Definition: core.pyx:1291
def _get_slice(self, offsets, ends)
Definition: core.pyx:2256
def take(init_A, indices, axis=None, out=None, mode='raise')
Definition: core.pyx:3435
def set_all(self, value)
Definition: core.pyx:2394
def write_all(self, arr)
Definition: core.pyx:2106
def tensordot(tA, tB, axes=2)
Definition: core.pyx:3743
def __truediv__(self, other)
Definition: core.pyx:1088
def to_nparray(t)
Definition: core.pyx:4050
def np(self)
Definition: core.pyx:315
void matrix_svd_cmplx(tensor *A, tensor *U, tensor *S, tensor *VT, int rank)
Definition: ctf_ext.cxx:213
def qr(tensor, A)
Definition: core.pyx:5275
def ones(shape, dtype=None, order='F')
Definition: core.pyx:4930