├── core ├── maxvol │ ├── __init__.py │ ├── build │ │ ├── temp.macosx-10.5-x86_64-2.7 │ │ │ ├── maxvol.o │ │ │ ├── maxvolmodule.o │ │ │ └── build │ │ │ │ └── src.macosx-10.5-x86_64-2.7 │ │ │ │ └── fortranobject.o │ │ └── src.macosx-10.5-x86_64-2.7 │ │ │ ├── fortranobject.h │ │ │ └── fortranobject.c │ ├── _maxvol.py │ ├── setup.py │ ├── maxvol.pyf │ └── maxvol.f90 ├── __init__.py ├── .gitignore ├── mkl_fft.py └── tucker.py ├── __init__.py ├── examples ├── .DS_Store ├── test_basic.py └── test_crossconv.py ├── cross ├── __init__.py ├── .gitignore ├── conv.py ├── cross2d_full.py ├── cross3d.py └── multifun.py ├── LICENSE └── README.md /core/maxvol/__init__.py: -------------------------------------------------------------------------------- 1 | from ._maxvol import * 2 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | import tucker3d.cross 3 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | from .tucker import * 2 | from ..core import maxvol as mv 3 | -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rakhuba/tucker3d/HEAD/examples/.DS_Store -------------------------------------------------------------------------------- /core/maxvol/build/temp.macosx-10.5-x86_64-2.7/maxvol.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rakhuba/tucker3d/HEAD/core/maxvol/build/temp.macosx-10.5-x86_64-2.7/maxvol.o -------------------------------------------------------------------------------- /cross/__init__.py: -------------------------------------------------------------------------------- 1 | from .multifun import multifun 2 | from .conv import conv, toepl2circ, pad 3 | from .cross3d import cross3d 4 | from .cross2d_full import cross2d_full -------------------------------------------------------------------------------- /core/maxvol/build/temp.macosx-10.5-x86_64-2.7/maxvolmodule.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rakhuba/tucker3d/HEAD/core/maxvol/build/temp.macosx-10.5-x86_64-2.7/maxvolmodule.o -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.so 3 | *f2pywrappers2* 4 | tt/build/* 5 | .DS_STORE 6 | quadgauss/build/ 7 | *module.c* 8 | tt/doc/_build 9 | *~ 10 | *.mod 11 | *.a 12 | .ropeproject/ 13 | -------------------------------------------------------------------------------- /cross/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.so 3 | *f2pywrappers2* 4 | tt/build/* 5 | .DS_STORE 6 | quadgauss/build/ 7 | *module.c* 8 | tt/doc/_build 9 | *~ 10 | *.mod 11 | *.a 12 | .ropeproject/ 13 | -------------------------------------------------------------------------------- /core/maxvol/build/temp.macosx-10.5-x86_64-2.7/build/src.macosx-10.5-x86_64-2.7/fortranobject.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rakhuba/tucker3d/HEAD/core/maxvol/build/temp.macosx-10.5-x86_64-2.7/build/src.macosx-10.5-x86_64-2.7/fortranobject.o -------------------------------------------------------------------------------- /core/maxvol/_maxvol.py: -------------------------------------------------------------------------------- 1 | from .maxvol import dmaxvol, zmaxvol 2 | from numpy import arange, asanyarray, iscomplexobj 3 | 4 | 5 | def maxvol(a, nswp = 20, tol = 5e-2): 6 | a = asanyarray(a) 7 | if a.shape[0] <= a.shape[1]: 8 | return arange(a.shape[0]) 9 | if iscomplexobj(a): 10 | return zmaxvol(a, nswp, tol) - 1 11 | else: 12 | return dmaxvol(a, nswp, tol) - 1 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Maxim Rakhuba, Ivan Oseledets 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /core/maxvol/setup.py: -------------------------------------------------------------------------------- 1 | #This script will build the main subpackages 2 | def configuration(parent_package='',top_path=None): 3 | from numpy.distutils.misc_util import Configuration, get_info 4 | config = Configuration('maxvol', parent_package, top_path) 5 | #import ipdb; ipdb.set_trace() 6 | #config.add_library() 7 | src = ['maxvol.f90','maxvol.pyf'] 8 | config.add_extension('maxvol',sources=src) 9 | return config 10 | 11 | #from distutils.core import setup 12 | #from numpy.distutils.core import setup, Extension 13 | #src = ['tt_f90.f90','tt_f90.pyf'] 14 | #inc_dir = ['tt-fort'] 15 | #lib = ['tt-fort/mytt.a'] 16 | #ext = Extension('tt_f90', src, include_dirs=inc_dir) 17 | #setup(ext_modules = [ext]) 18 | 19 | 20 | if __name__ == '__main__': 21 | from numpy.distutils.core import setup 22 | setup(**configuration(top_path='').todict()) 23 | 24 | 25 | #, include_dirs=None, define_macros=None, undef_macros=None, library_dirs=None, libraries=None, runtime_library_dirs=None, extra_objects=None, extra_compile_args=None, extra_link_args=None, export_symbols=None, swig_opts=None, depends=None, language=None, f2py_options=None, module_dirs 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tucker3d (Ver. 0.1) 2 | =================== 3 | 4 | tucker3d is Python implementation of the Tucker format in the three-dimensional case. 5 | This implemetation includes 6 | - Basic linear algebra operations 7 | - New version of the cross approximation method (it allows to construct tucker representation 8 | of a tensor by using only few of its elements) 9 | - Element-wise functions (multifun in the cross module) 10 | - 3D convolutions (cross-conv algorithm, see http://arxiv.org/pdf/1402.5649.pdf for details) 11 | 12 | Tucker format 13 | ============= 14 | 15 | Tucker format is a low-parametric representation of multidimensional arrays (tensors). 16 | This representaion is based on the idea of separation of variables (so-called tensor format). 17 | 18 | If a Tucker representation of some tensors is given and it has low number of parameters, then basic linear algebra operations are fast to compute. 19 | 20 | 21 | Installation 22 | ============ 23 | 24 | First, to clone this repository run 25 | ``` 26 | git clone git://github.com/rakhuba/tucker3d 27 | ``` 28 | Then go to 'maxvol' directory: 29 | ``` 30 | cd tucker3d/core/maxvol 31 | ``` 32 | and run 33 | ``` 34 | python setup.py build_ext --inplace 35 | ``` 36 | -------------------------------------------------------------------------------- /examples/test_basic.py: -------------------------------------------------------------------------------- 1 | # Example: basic linear algebra operations 2 | import sys 3 | sys.path.append('../../') 4 | import numpy as np 5 | import tucker3d as tuck 6 | 7 | N = 2**12 8 | M = 2*N-1 9 | print('N = %s' % N) 10 | 11 | eps = 1e-5 12 | print('Accuracy: %s' % eps) 13 | 14 | a = -5. 15 | b = abs(a) 16 | h = (b-a)/(N-1) 17 | 18 | x = np.zeros(N) 19 | for i in range(N): 20 | x[i] = a + i*h 21 | 22 | def slater_fun(ind): 23 | return np.exp(-(x[ind[0]]**2 + x[ind[1]]**2 + x[ind[2]]**2)**0.5) 24 | 25 | def gaussian_fun(ind): 26 | return np.exp(-(x[ind[0]]**2 + x[ind[1]]**2 + x[ind[2]]**2)) 27 | 28 | print('Converting tensors in the Tucker format via cross approximation \n (may be slow due to python loops)...') 29 | a = tuck.cross.cross3d(slater_fun, N, eps) 30 | b = tuck.cross.cross3d(gaussian_fun, N, eps) 31 | print('Converting is done') 32 | print('tensor a: \n%s' % (a)) 33 | print('tensor b: \n%s' % (b)) 34 | print('tensor 2a: \n%s' % (2*a)) 35 | print('tensor a+a: \n%s' % (a + a)) 36 | print('tensor a+a after rounding: \n%s' % (tuck.round(a+a, eps))) 37 | print('relative Frobenius norm of a-a: \n%s' % (tuck.norm(a-a)/tuck.norm(a))) 38 | 39 | # Warning! for big mode sizes (N >~ 256) full tensors may be out of memory. 40 | # So, use tensor_full function carefully. 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /core/maxvol/maxvol.pyf: -------------------------------------------------------------------------------- 1 | ! -*- f90 -*- 2 | ! Note: the context of this file is case sensitive. 3 | 4 | python module maxvol ! in 5 | interface ! in :maxvol 6 | subroutine dmaxvol(a,n,r,ind,nswp,tol) ! in :maxvol:maxvol.f90 7 | real(kind=8) dimension(n,r),intent(in) :: a 8 | integer, optional,intent(in),check(shape(a,0)==n),depend(a) :: n=shape(a,0) 9 | integer, optional,intent(in),check(shape(a,1)==r),depend(a) :: r=shape(a,1) 10 | integer dimension(r),intent(out),depend(r) :: ind 11 | integer intent(in) :: nswp 12 | real(kind=8) intent(in) :: tol 13 | end subroutine dmaxvol 14 | 15 | subroutine zmaxvol(a,n,r,ind,nswp,tol) ! in :maxvol:maxvol.f90 16 | complex(kind=8) dimension(n,r),intent(in) :: a 17 | integer, optional,intent(in),check(shape(a,0)==n),depend(a) :: n=shape(a,0) 18 | integer, optional,intent(in),check(shape(a,1)==r),depend(a) :: r=shape(a,1) 19 | integer dimension(r),intent(out),depend(r) :: ind 20 | integer intent(in) :: nswp 21 | real(kind=8) intent(in) :: tol 22 | end subroutine zmaxvol 23 | end interface 24 | end python module maxvol 25 | 26 | ! This file was auto-generated with f2py (version:2). 27 | ! See http://cens.ioc.ee/projects/f2py2e/ 28 | -------------------------------------------------------------------------------- /examples/test_crossconv.py: -------------------------------------------------------------------------------- 1 | # 2 | # Computing Newton potential of a Slater function 3 | # 4 | 5 | import sys 6 | sys.path.append('../../') 7 | 8 | import numpy as np 9 | import time 10 | from math import pi 11 | import tucker3d as tuck 12 | import timeit 13 | 14 | np.random.seed(1) 15 | 16 | N = 2**9 17 | M = 2*N-1 18 | print('N= %s' % N) 19 | 20 | eps = 1e-7 21 | print('Accuracy: %s' % eps) 22 | 23 | a = -5. 24 | b = abs(a) 25 | h = (b-a)/(N-1) 26 | 27 | newton_const = 1./(4*pi)* h**3 28 | 29 | x = np.zeros(N) 30 | for i in range(N): 31 | x[i] = a + i*h 32 | 33 | def slater_func(ind): 34 | return np.exp(-(x[ind[0]]**2 + x[ind[1]]**2 + x[ind[2]]**2)**0.5) 35 | 36 | def newton_func(ind): 37 | return newton_const * 1./(x[ind[0]]**2 + x[ind[1]]**2 + x[ind[2]]**2)**0.5 38 | 39 | # Tucker representaition of the slater and newton functions 40 | 41 | print('WARNING!') 42 | print('Very slow part (cross approximation of Slater and Newton funs).') 43 | print('It does not influence cross-conv time performance.') 44 | print('In process...') 45 | slater = tuck.cross.cross3d(slater_func, N, eps, delta_add=1e-5) 46 | newton = tuck.cross.cross3d(newton_func, N, eps, delta_add=1e-5) 47 | newton_ext = tuck.cross.toepl2circ(newton) 48 | 49 | # Convolution part 50 | 51 | start = time.time() 52 | start_conv = time.time() 53 | conv = tuck.cross.conv(newton_ext, slater, eps) 54 | end_conv = time.time() 55 | print('Cross-conv Time: %s' % (end_conv - start_conv)) 56 | 57 | -------------------------------------------------------------------------------- /cross/conv.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import time 3 | from math import pi 4 | import copy 5 | from scipy.special import erf 6 | import tucker3d as tuck 7 | #from cross_multifun import cross_multifun 8 | 9 | 10 | def conv(c_g, f, delta_cross, r_add=4, pr=None, y0=None): 11 | # convolution of g and f tensors 12 | # c_g - generating a circulant subtensor (for symmetric g use toepl2circ func) 13 | 14 | aa = tuck.fft(c_g) 15 | bb = tuck.fft(pad(f)) 16 | 17 | ab = tuck.cross.multifun([aa, bb], delta_cross, lambda x: x[0]*x[1], r_add=r_add, pr=pr, y0=y0) 18 | 19 | ab = tuck.ifft(ab) 20 | 21 | conv = copy.copy(ab) 22 | conv.n = [ab.n[0]//2, ab.n[1]//2, ab.n[2]//2] 23 | conv.u[0] = ab.u[0][:conv.n[0], :] 24 | conv.u[1] = ab.u[1][:conv.n[1], :] 25 | conv.u[2] = ab.u[2][:conv.n[2], :] 26 | 27 | return conv 28 | 29 | 30 | def newton_galerkin(x, eps, ind): 31 | 32 | # galerkin tensor for convolution as a hartree potential 33 | 34 | if ind == 6: 35 | a, b, r = -15., 10, 80 36 | elif ind == 8: 37 | a, b, r = -20., 15, 145 38 | elif ind == 10: 39 | a, b, r = -25., 20, 220 40 | elif ind == 12: 41 | a, b, r = -30., 25, 320 42 | else: 43 | raise Exception("wrong ind parameter") 44 | 45 | N = x.shape 46 | 47 | hr = (b-a)/(r - 1) 48 | h = x[1]-x[0] 49 | 50 | s = np.array(range(r), dtype = np.complex128) 51 | s = a + hr * (s - 1) 52 | 53 | w = np.zeros(r, dtype = np.complex128) 54 | for alpha in range(r): 55 | w[alpha] = 2*hr * np.exp(s[alpha]) / np.sqrt(pi) 56 | w[0] = w[0]/2 57 | w[r-1] = w[r-1]/2 58 | 59 | 60 | U = np.zeros((N[0], r), dtype = np.complex128) 61 | for alpha in range(r): 62 | U[:, alpha] = ( func_int(x-h/2, x[0]-h/2, np.exp(2*s[alpha])) - 63 | func_int(x+h/2, x[0]-h/2, np.exp(2*s[alpha])) + 64 | func_int(x+h/2, x[0]+h/2, np.exp(2*s[alpha])) - 65 | func_int(x-h/2, x[0]+h/2, np.exp(2*s[alpha])) ) 66 | 67 | newton = can2tuck(w, U, U, U) 68 | newton = tuck.round(newton, eps) 69 | 70 | return (1./h**3) * newton 71 | 72 | 73 | def toepl2circ(T): 74 | 75 | # expands T - first columns of a symmetric multilevel 76 | # Toeplitz matrix to first columns of a multilevel circulant 77 | 78 | C = pad(T) 79 | 80 | U1 = T.u[0][1:, :] 81 | U2 = T.u[1][1:, :] 82 | U3 = T.u[2][1:, :] 83 | 84 | C.u[0][T.n[0]+1:, :] = U1[::-1, :] 85 | C.u[1][T.n[1]+1:, :] = U2[::-1, :] 86 | C.u[2][T.n[2]+1:, :] = U3[::-1, :] 87 | 88 | C.u[0][T.n[0], :] = T.u[0][0, :] 89 | C.u[1][T.n[1], :] = T.u[1][0, :] 90 | C.u[2][T.n[2], :] = T.u[2][0, :] 91 | 92 | return C 93 | 94 | 95 | def func_int(x, y, a): 96 | if (a*(2*np.max(x))**2 > 1e-10): 97 | f = -(np.exp(-a*(x-y)**2)-1)/(2*a) + np.sqrt(pi/a)/2 * ( 98 | (y - x) * erf(np.sqrt(a) * (x-y)) ) 99 | else: 100 | f = (-(x-y)**2/2) 101 | return f 102 | 103 | 104 | 105 | def pad(a): 106 | b = tuck.tensor() 107 | b.n = [2*a.n[0], 2*a.n[1], 2*a.n[2]] 108 | b.r = a.r 109 | b.u[0] = np.zeros((b.n[0], b.r[0]), dtype=np.complex128) 110 | b.u[1] = np.zeros((b.n[1], b.r[1]), dtype=np.complex128) 111 | b.u[2] = np.zeros((b.n[2], b.r[2]), dtype=np.complex128) 112 | b.u[0][:a.n[0], :] = a.u[0] 113 | b.u[1][:a.n[1], :] = a.u[1] 114 | b.u[2][:a.n[2], :] = a.u[2] 115 | b.core = a.core 116 | return b 117 | -------------------------------------------------------------------------------- /cross/cross2d_full.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import copy 3 | import tucker3d as tuck 4 | 5 | def pinv(A): 6 | try: 7 | return np.linalg.pinv(A) 8 | except: #LinAlgError 9 | try: 10 | print("PINV failded") 11 | return np.linalg.pinv(A + 1e-12*np.linalg.norm(A, 1)) 12 | except: 13 | print("PINV failded twice") 14 | return np.linalg.pinv(A + 1e-8*np.linalg.norm(A, 1)) 15 | 16 | def cross2d_full(func, eps, r0=4, rmax=100): 17 | 18 | 19 | #A = np.zeros((M1, M2), dtype = np.complex128) 20 | #for i in xrange(M1): 21 | # for j in xrange(M2): 22 | # A[i, j] = func(i, j) 23 | 24 | M1, M2 = func.shape 25 | 26 | r1_0 = r0 27 | r2_0 = r0 28 | 29 | r1 = r1_0 30 | r2 = r2_0 31 | 32 | U1 = np.zeros((M1, r1), dtype=np.complex128) 33 | U2 = np.zeros((M2, r2), dtype=np.complex128) 34 | 35 | U1[:, :] = np.random.random((M1,r1)) 36 | U2[:, :] = np.random.random((M2,r2)) 37 | 38 | U1, R = np.linalg.qr(U1) 39 | U2, R = np.linalg.qr(U2) 40 | 41 | eps_cross = 1 42 | 43 | row_order_U1 = tuck.mv.maxvol(U1) 44 | row_order_U2 = tuck.mv.maxvol(U2) 45 | 46 | u1 = func[:, row_order_U2] 47 | u2 = func[row_order_U1, :].T 48 | 49 | U1_hat = np.linalg.solve(U1[row_order_U1, :].T, U1.T).T 50 | U2_hat = np.linalg.solve(U2[row_order_U2, :].T, U2.T).T 51 | 52 | UU1, ind_update_1 = column_update(U1_hat, u1, row_order_U1) 53 | UU2, ind_update_2 = column_update(U2_hat, u2, row_order_U2) 54 | 55 | U1 = np.concatenate((U1, u1), 1) 56 | U2 = np.concatenate((U2, u2), 1) 57 | 58 | r1 = r1 + r1_0 59 | r2 = r2 + r2_0 60 | 61 | while True: 62 | 63 | row_order_U1 = np.concatenate((row_order_U1, ind_update_1)) 64 | row_order_U2 = np.concatenate((row_order_U2, ind_update_2)) 65 | 66 | Ar = func[row_order_U1, :][:, row_order_U2] 67 | 68 | u1 = func[:, ind_update_2] 69 | u2 = func[ind_update_1, :].T 70 | 71 | u1_approx = np.dot(np.dot(UU1, Ar), H(UU2[ind_update_2, :])) 72 | u2_approx = np.dot(np.dot(UU1[ind_update_1, :], Ar), H(UU2)).T 73 | 74 | #A_appr = np.dot(np.dot(UU1, Ar), H(UU2)) 75 | 76 | eps_cross = 1./2*( np.linalg.norm(u1_approx - u1)/ np.linalg.norm(u1) + np.linalg.norm(u2_approx - u2)/ np.linalg.norm(u2)) 77 | #print eps_cross, np.linalg.norm(A_appr - func)/np.linalg.norm(func) 78 | 79 | if eps_cross < eps: 80 | break 81 | if r1>rmax: 82 | print('Rank has exceeded rmax value') 83 | break 84 | 85 | 86 | UU1, ind_update_1 = column_update(UU1, u1, row_order_U1) 87 | UU2, ind_update_2 = column_update(UU2, u2, row_order_U2) 88 | 89 | U1 = np.concatenate((U1, u1), 1) 90 | U2 = np.concatenate((U2, u2), 1) 91 | 92 | r1 = r1 + r1_0 93 | r2 = r2 + r2_0 94 | 95 | #print r1, r2 96 | 97 | U1, R1 = np.linalg.qr(UU1) 98 | U2, R2 = np.linalg.qr(UU2) 99 | 100 | G = np.dot(np.dot(R1, Ar), H(R2)) 101 | 102 | u1, s, u2 = round_matrix(G, eps) 103 | #print s.shape 104 | 105 | U1 = np.dot(U1, u1) 106 | U2 = np.dot(U2, u2) 107 | 108 | return U1, U2 109 | #print np.linalg.norm(A - np.dot(U1,H(U2)))/np.linalg.norm(A) 110 | 111 | def H(A): 112 | return np.transpose(np.conjugate(A)) 113 | 114 | def round_matrix(A, eps): 115 | 116 | u, s, v = np.linalg.svd(A, full_matrices=False) 117 | 118 | N, M = A.shape 119 | r = 0 # r=rank 120 | 121 | # rank 122 | for i in range(min(N, M)): 123 | if s[i]>eps*s[0]: 124 | r+=1 125 | 126 | 127 | return u[:, :r], np.diag(s[:r]), H( np.dot(np.diag(s[:r]), v[:r, :]) ) 128 | 129 | 130 | def column_update(UU, u, ind): 131 | 132 | S = u - np.dot(UU, u[ind,:]) 133 | ind_add = tuck.mv.maxvol(S) 134 | 135 | SS = np.dot(pinv(S[ind_add, :].T), S.T).T # WARNING! pinv instead of solve! 136 | #np.linalg.solve(S[ind_add, :].T, S.T).T#np.dot(np.linalg.pinv(S[ind_add, :].T), S.T).T 137 | 138 | U1 = UU - np.dot(SS, UU[ind_add]) 139 | U2 = SS 140 | 141 | return np.concatenate((U1, U2), 1), ind_add -------------------------------------------------------------------------------- /core/maxvol/maxvol.f90: -------------------------------------------------------------------------------- 1 | subroutine dmaxvol(a, n, r, ind, nswp, tol) 2 | implicit none 3 | integer, intent(in) :: r 4 | integer, intent(in) :: n 5 | real(8), intent(in) :: a(n,r) 6 | integer, intent(out) :: ind(r) 7 | integer tmp_ind(r),p(n),ipiv(r) 8 | real(8) :: ba(r,n),c(n,r), u(n), v(r) 9 | real(8), intent(in) :: tol 10 | logical not_converged 11 | integer, intent(in) :: nswp 12 | integer info,i,j,swp, big_ind,i0,j0,tmp 13 | integer idamax 14 | external idamax 15 | !tol=5e-2 16 | !nswp=20 17 | !Generate initial approximation 18 | ba = transpose(a) 19 | call dcopy(n*r,a,1,c,1) 20 | do i = 1,n 21 | p(i) = i 22 | end do 23 | call dgetrf(n,r,c,n,ipiv,info) 24 | do i = 1,r 25 | j = ipiv(i) 26 | if ( j .ne. i ) then 27 | tmp = p(i) 28 | p(i) = p(j) 29 | p(j) = tmp 30 | end if 31 | end do 32 | ind(1:r) = p(1:r) 33 | if (info .ne. 0) then 34 | print *, 'Maxvol failed at dgetrf' 35 | end if 36 | do i = 1,r 37 | tmp_ind(i) = i 38 | end do 39 | call dgetrs('t',r,n,c,n,tmp_ind,ba,r,info) 40 | 41 | if (info .ne. 0) then 42 | print *,'Maxvol failed at dgetrs' 43 | end if 44 | not_converged = .true. 45 | swp = 1 46 | !Now start the main iteration 47 | do while (not_converged .and. swp <= nswp) 48 | big_ind = idamax(r*n,ba,1) 49 | j0 = mod(big_ind - 1,r) + 1 ! This value is from 1 to r 50 | i0 = (big_ind - j0)/ r + 1 ! This value seems OK: If it is smaller, it goes 51 | if ( i0 > n ) then 52 | print *,'aarrgh' 53 | print *,'big_ind=',big_ind, 'i0=',i0,'j0=',j0,'n=',n,'r=',r 54 | end if 55 | 56 | if ( dabs(ba(j0,i0)) <= 1 + tol ) then 57 | not_converged = .false. 58 | else 59 | 60 | u(1:n) = ba(j0,:) 61 | v(1:r) = ba(:,ind(j0)) - ba(:,i0) 62 | u(1:n) = u(1:n) / ba(j0,i0) 63 | call dger(r,n,1.d0,v,1,u,1,ba,r) 64 | swp = swp + 1 65 | ind(j0) = i0 66 | 67 | end if 68 | 69 | end do 70 | 71 | end subroutine dmaxvol 72 | 73 | subroutine zmaxvol(a, n, r, ind, nswp, tol) 74 | implicit none 75 | integer, intent(in) :: r 76 | integer, intent(in) :: n 77 | complex(8), intent(in) :: a(n,r) 78 | integer, intent(out) :: ind(r) 79 | integer tmp_ind(r),p(n),ipiv(r) 80 | complex(8) :: ba(r,n),c(n,r), u(n), v(r) 81 | real(8), intent(in) :: tol 82 | logical not_converged 83 | integer, intent(in) :: nswp 84 | integer info,i,j,swp, big_ind,i0,j0,tmp 85 | complex(8) :: ONE 86 | integer izamax 87 | external izamax 88 | !tol=5e-2 89 | !nswp=20 90 | !Generate initial approximation 91 | ONE = (1d0, 0d0) 92 | ba = transpose(a) 93 | call zcopy(n*r,a,1,c,1) 94 | do i = 1,n 95 | p(i) = i 96 | end do 97 | call zgetrf(n,r,c,n,ipiv,info) 98 | do i = 1,r 99 | j = ipiv(i) 100 | if ( j .ne. i ) then 101 | tmp = p(i) 102 | p(i) = p(j) 103 | p(j) = tmp 104 | end if 105 | end do 106 | ind(1:r) = p(1:r) 107 | if (info .ne. 0) then 108 | print *, 'Maxvol failed at zgetrf' 109 | end if 110 | do i = 1,r 111 | tmp_ind(i) = i 112 | end do 113 | call zgetrs('T',r,n,c,n,tmp_ind,ba,r,info) 114 | 115 | if (info .ne. 0) then 116 | print *,'Maxvol failed at zgetrs' 117 | end if 118 | not_converged = .true. 119 | swp = 1 120 | !Now start the main iteration 121 | do while (not_converged .and. swp <= nswp) 122 | big_ind = izamax(r*n,ba,1) 123 | j0 = mod(big_ind - 1,r) + 1 ! This value is from 1 to r 124 | i0 = (big_ind - j0)/ r + 1 ! This value seems OK: If it is smaller, it goes 125 | if ( i0 > n ) then 126 | print *,'aarrgh' 127 | print *,'big_ind=',big_ind, 'i0=',i0,'j0=',j0,'n=',n,'r=',r 128 | end if 129 | 130 | if ( zabs(ba(j0,i0)) <= 1 + tol ) then 131 | not_converged = .false. 132 | else 133 | 134 | u(1:n) = ba(j0,:) 135 | v(1:r) = ba(:,ind(j0)) - ba(:,i0) 136 | u(1:n) = u(1:n) / ba(j0,i0) 137 | call zgeru(r,n,ONE,v,1,u,1,ba,r) 138 | swp = swp + 1 139 | ind(j0) = i0 140 | 141 | end if 142 | 143 | end do 144 | 145 | end subroutine zmaxvol 146 | -------------------------------------------------------------------------------- /core/maxvol/build/src.macosx-10.5-x86_64-2.7/fortranobject.h: -------------------------------------------------------------------------------- 1 | #ifndef Py_FORTRANOBJECT_H 2 | #define Py_FORTRANOBJECT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include "Python.h" 8 | 9 | #ifdef FORTRANOBJECT_C 10 | #define NO_IMPORT_ARRAY 11 | #endif 12 | #define PY_ARRAY_UNIQUE_SYMBOL PyArray_API_F2PY 13 | #include "numpy/arrayobject.h" 14 | 15 | /* 16 | * Python 3 support macros 17 | */ 18 | #if PY_VERSION_HEX >= 0x03000000 19 | #define PyString_Check PyBytes_Check 20 | #define PyString_GET_SIZE PyBytes_GET_SIZE 21 | #define PyString_AS_STRING PyBytes_AS_STRING 22 | #define PyString_FromString PyBytes_FromString 23 | #define PyString_ConcatAndDel PyBytes_ConcatAndDel 24 | #define PyString_AsString PyBytes_AsString 25 | 26 | #define PyInt_Check PyLong_Check 27 | #define PyInt_FromLong PyLong_FromLong 28 | #define PyInt_AS_LONG PyLong_AsLong 29 | #define PyInt_AsLong PyLong_AsLong 30 | 31 | #define PyNumber_Int PyNumber_Long 32 | #endif 33 | 34 | #if (PY_VERSION_HEX < 0x02060000) 35 | #define Py_TYPE(o) (((PyObject*)(o))->ob_type) 36 | #define Py_REFCNT(o) (((PyObject*)(o))->ob_refcnt) 37 | #define Py_SIZE(o) (((PyVarObject*)(o))->ob_size) 38 | #endif 39 | 40 | /* 41 | #ifdef F2PY_REPORT_ATEXIT_DISABLE 42 | #undef F2PY_REPORT_ATEXIT 43 | #else 44 | 45 | #ifndef __FreeBSD__ 46 | #ifndef __WIN32__ 47 | #ifndef __APPLE__ 48 | #define F2PY_REPORT_ATEXIT 49 | #endif 50 | #endif 51 | #endif 52 | 53 | #endif 54 | */ 55 | 56 | #ifdef F2PY_REPORT_ATEXIT 57 | #include 58 | extern void f2py_start_clock(void); 59 | extern void f2py_stop_clock(void); 60 | extern void f2py_start_call_clock(void); 61 | extern void f2py_stop_call_clock(void); 62 | extern void f2py_cb_start_clock(void); 63 | extern void f2py_cb_stop_clock(void); 64 | extern void f2py_cb_start_call_clock(void); 65 | extern void f2py_cb_stop_call_clock(void); 66 | extern void f2py_report_on_exit(int,void*); 67 | #endif 68 | 69 | #ifdef DMALLOC 70 | #include "dmalloc.h" 71 | #endif 72 | 73 | /* Fortran object interface */ 74 | 75 | /* 76 | 123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 77 | 78 | PyFortranObject represents various Fortran objects: 79 | Fortran (module) routines, COMMON blocks, module data. 80 | 81 | Author: Pearu Peterson 82 | */ 83 | 84 | #define F2PY_MAX_DIMS 40 85 | 86 | typedef void (*f2py_set_data_func)(char*,npy_intp*); 87 | typedef void (*f2py_void_func)(void); 88 | typedef void (*f2py_init_func)(int*,npy_intp*,f2py_set_data_func,int*); 89 | 90 | /*typedef void* (*f2py_c_func)(void*,...);*/ 91 | 92 | typedef void *(*f2pycfunc)(void); 93 | 94 | typedef struct { 95 | char *name; /* attribute (array||routine) name */ 96 | int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS, 97 | || rank=-1 for Fortran routine */ 98 | struct {npy_intp d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */ 99 | int type; /* PyArray_ || not used */ 100 | char *data; /* pointer to array || Fortran routine */ 101 | f2py_init_func func; /* initialization function for 102 | allocatable arrays: 103 | func(&rank,dims,set_ptr_func,name,len(name)) 104 | || C/API wrapper for Fortran routine */ 105 | char *doc; /* documentation string; only recommended 106 | for routines. */ 107 | } FortranDataDef; 108 | 109 | typedef struct { 110 | PyObject_HEAD 111 | int len; /* Number of attributes */ 112 | FortranDataDef *defs; /* An array of FortranDataDef's */ 113 | PyObject *dict; /* Fortran object attribute dictionary */ 114 | } PyFortranObject; 115 | 116 | #define PyFortran_Check(op) (Py_TYPE(op) == &PyFortran_Type) 117 | #define PyFortran_Check1(op) (0==strcmp(Py_TYPE(op)->tp_name,"fortran")) 118 | 119 | extern PyTypeObject PyFortran_Type; 120 | extern int F2PyDict_SetItemString(PyObject* dict, char *name, PyObject *obj); 121 | extern PyObject * PyFortranObject_New(FortranDataDef* defs, f2py_void_func init); 122 | extern PyObject * PyFortranObject_NewAsAttr(FortranDataDef* defs); 123 | 124 | #if PY_VERSION_HEX >= 0x03000000 125 | 126 | PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)); 127 | void * F2PyCapsule_AsVoidPtr(PyObject *obj); 128 | int F2PyCapsule_Check(PyObject *ptr); 129 | 130 | #else 131 | 132 | PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)); 133 | void * F2PyCapsule_AsVoidPtr(PyObject *ptr); 134 | int F2PyCapsule_Check(PyObject *ptr); 135 | 136 | #endif 137 | 138 | #define ISCONTIGUOUS(m) ((m)->flags & NPY_CONTIGUOUS) 139 | #define F2PY_INTENT_IN 1 140 | #define F2PY_INTENT_INOUT 2 141 | #define F2PY_INTENT_OUT 4 142 | #define F2PY_INTENT_HIDE 8 143 | #define F2PY_INTENT_CACHE 16 144 | #define F2PY_INTENT_COPY 32 145 | #define F2PY_INTENT_C 64 146 | #define F2PY_OPTIONAL 128 147 | #define F2PY_INTENT_INPLACE 256 148 | #define F2PY_INTENT_ALIGNED4 512 149 | #define F2PY_INTENT_ALIGNED8 1024 150 | #define F2PY_INTENT_ALIGNED16 2048 151 | 152 | #define ARRAY_ISALIGNED(ARR, SIZE) ((size_t)(PyArray_DATA(ARR)) % (SIZE) == 0) 153 | #define F2PY_ALIGN4(intent) (intent & F2PY_INTENT_ALIGNED4) 154 | #define F2PY_ALIGN8(intent) (intent & F2PY_INTENT_ALIGNED8) 155 | #define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16) 156 | 157 | #define F2PY_GET_ALIGNMENT(intent) \ 158 | (F2PY_ALIGN4(intent) ? 4 : \ 159 | (F2PY_ALIGN8(intent) ? 8 : \ 160 | (F2PY_ALIGN16(intent) ? 16 : 1) )) 161 | #define F2PY_CHECK_ALIGNMENT(arr, intent) ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent)) 162 | 163 | extern PyArrayObject* array_from_pyobj(const int type_num, 164 | npy_intp *dims, 165 | const int rank, 166 | const int intent, 167 | PyObject *obj); 168 | extern int copy_ND_array(const PyArrayObject *in, PyArrayObject *out); 169 | 170 | #ifdef DEBUG_COPY_ND_ARRAY 171 | extern void dump_attrs(const PyArrayObject* arr); 172 | #endif 173 | 174 | 175 | #ifdef __cplusplus 176 | } 177 | #endif 178 | #endif /* !Py_FORTRANOBJECT_H */ 179 | -------------------------------------------------------------------------------- /cross/cross3d.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import time 3 | from math import pi 4 | import copy 5 | import tucker3d as tuck 6 | 7 | # 8 | # !!WARNING!! 9 | # 10 | # Very slow version of the Cross3D (will be updated). 11 | # Use cross_multifun to find a function of tensors in the Tucker format. 12 | 13 | def cross3d(func, M, eps_init, delta_add = 1e-5): 14 | 15 | N = int((M+1)/2) 16 | 17 | r1 = 2 18 | r2 = 2 19 | r3 = 2 20 | 21 | GG = np.zeros((r1,r2,r3),dtype=np.complex128) 22 | 23 | U1 = np.zeros((M,r1),dtype=np.complex128) 24 | U2 = np.zeros((M,r2),dtype=np.complex128) 25 | U3 = np.zeros((M,r3),dtype=np.complex128) 26 | 27 | U1[:N,:] = np.random.random((N,r1)) 28 | U2[:N,:] = np.random.random((N,r2)) 29 | U3[:N,:] = np.random.random((N,r3)) 30 | 31 | U1, R = np.linalg.qr(U1) 32 | U2, R = np.linalg.qr(U2) 33 | U3, R = np.linalg.qr(U3) 34 | 35 | eps_cross = 1 36 | 37 | while True: 38 | 39 | row_order_U1 = tuck.mv.maxvol(U1) 40 | row_order_U2 = tuck.mv.maxvol(U2) 41 | row_order_U3 = tuck.mv.maxvol(U3) 42 | 43 | Ar = np.zeros((r1,r2,r3),dtype=np.complex128) 44 | 45 | for i in range(r1): 46 | for j in range(r2): 47 | for k in range(r3): 48 | Ar[i,j,k] = func((row_order_U1[i],row_order_U2[j],row_order_U3[k])) 49 | 50 | 51 | U1_r = U1[row_order_U1,:] 52 | U2_r = U2[row_order_U2,:] 53 | U3_r = U3[row_order_U3,:] 54 | 55 | G_UV = np.linalg.solve(U3_r,np.reshape(np.transpose(Ar,[2,0,1]),(r3,r1*r2),order='f')) 56 | G_UV = np.reshape(G_UV,(r3,r1,r2),order='f') 57 | G_UV = np.transpose(G_UV,[1,2,0]) 58 | 59 | G_U = np.linalg.solve(U2_r,np.reshape(np.transpose(G_UV,[1,2,0]),(r2,r1*r3),order='f')) 60 | G_U = np.reshape(G_U,(r2,r3,r1),order='f') 61 | G_U = np.transpose(G_U,[2,0,1]) 62 | 63 | G = np.linalg.solve(U1_r,np.reshape(G_U,(r1,r2*r3),order='f')) 64 | G = np.reshape(G,(r1,r2,r3),order='f') 65 | 66 | norm = np.linalg.norm(G) 67 | eps_cross = (np.linalg.norm(GG-G))/norm 68 | #print 'relative accuracy = %s' % (eps_cross), 'ranks = %s' % r1, r2, r3 69 | G_Tucker = tuck.tensor(G, eps_init/10) 70 | 71 | G = G_Tucker.core 72 | 73 | U1 = np.dot(U1, G_Tucker.u[0]) 74 | U2 = np.dot(U2, G_Tucker.u[1]) 75 | U3 = np.dot(U3, G_Tucker.u[2]) 76 | 77 | (r1, r2, r3) = G_Tucker.r 78 | 79 | if eps_cross < eps_init: 80 | break 81 | 82 | row_order_U1 = tuck.mv.maxvol(U1) 83 | row_order_U2 = tuck.mv.maxvol(U2) 84 | row_order_U3 = tuck.mv.maxvol(U3) 85 | 86 | 87 | Ar = np.zeros((r1,r2,r3),dtype=np.complex128) 88 | 89 | for i in range(r1): 90 | for j in range(r2): 91 | for k in range(r3): 92 | Ar[i, j, k] = func((row_order_U1[i], row_order_U2[j], row_order_U3[k])) 93 | 94 | 95 | A1 = np.reshape(Ar, [r1,-1], order='f') 96 | A1_r = np.transpose(A1) 97 | A1_r,R = np.linalg.qr(A1_r) 98 | column_order_U1 = tuck.mv.maxvol(A1_r) 99 | 100 | 101 | A2 = np.reshape(np.transpose(Ar, [1,0,2]), [r2,-1], order='f') 102 | A2_r = np.transpose(A2) 103 | A2_r,R = np.linalg.qr(A2_r) 104 | column_order_U2 = tuck.mv.maxvol(A2_r) 105 | 106 | 107 | A3 = np.reshape(np.transpose(Ar, [2,0,1]), [r3,-1], order='f') 108 | A3_r = np.transpose(A3) 109 | A3_r,R = np.linalg.qr(A3_r) 110 | column_order_U3 = tuck.mv.maxvol(A3_r) 111 | 112 | 113 | u1 = np.zeros((M, r1), dtype=np.complex128) 114 | for i in range(r1): 115 | for ii in range(M): 116 | k1_order, j1_order = mod(column_order_U1[i], r2) 117 | u1[ii,i] = func((ii, row_order_U2[j1_order], row_order_U3[k1_order])) 118 | 119 | u2 = np.zeros((M, r2), dtype=np.complex128) 120 | for j in range(r2): 121 | for jj in range(M): 122 | k1_order, i1_order = mod(column_order_U2[j], r1) 123 | u2[jj,j] = func((row_order_U1[i1_order], jj, row_order_U3[k1_order])) 124 | 125 | u3 = np.zeros((M, r3), dtype=np.complex128) 126 | for k in range(r3): 127 | for kk in range(M): 128 | j1_order, i1_order = mod(column_order_U3[k], r1) 129 | u3[kk,k] = func((row_order_U1[i1_order], row_order_U2[j1_order], kk)) 130 | 131 | 132 | u1, v, r11 = round_matrix(u1, delta_add) 133 | u2, v, r22 = round_matrix(u2, delta_add) 134 | u3, v, r33 = round_matrix(u3, delta_add) 135 | 136 | u1 = u1[:,:r11] 137 | u2 = u2[:,:r22] 138 | u3 = u3[:,:r33] 139 | 140 | U1_0 = np.zeros((M,r1+r11),dtype=np.complex128) 141 | U2_0 = np.zeros((M,r2+r22),dtype=np.complex128) 142 | U3_0 = np.zeros((M,r3+r33),dtype=np.complex128) 143 | 144 | U1_0[:,:r1] = U1.copy() 145 | U2_0[:,:r2] = U2.copy() 146 | U3_0[:,:r3] = U3.copy() 147 | 148 | U1_0[:,r1:r1+r11] = u1 149 | U2_0[:,r2:r2+r22] = u2 150 | U3_0[:,r3:r3+r33] = u3 151 | 152 | 153 | U1 = U1_0.copy() 154 | U2 = U2_0.copy() 155 | U3 = U3_0.copy() 156 | 157 | r1 = r1+r11 158 | r2 = r2+r22 159 | r3 = r3+r33 160 | 161 | 162 | U1, R1 = np.linalg.qr(U1) 163 | U2, R2 = np.linalg.qr(U2) 164 | U3, R3 = np.linalg.qr(U3) 165 | 166 | 167 | GG = np.zeros((r1,r2,r3),dtype=np.complex128) 168 | GG[:(r1-r11),:(r2-r22),:(r3-r33)] = G.copy() 169 | 170 | 171 | GG = np.dot(np.transpose(GG,[2,1,0]),np.transpose(R1)) 172 | GG = np.dot(np.transpose(GG,[0,2,1]),np.transpose(R2)) 173 | GG = np.transpose(GG,[1,2,0]) 174 | GG = np.dot(GG,np.transpose(R3)) 175 | 176 | #print 'ranks after rounding = %s' % r1, r2, r3 177 | G_Tucker.n = (M, M, M) 178 | G_Tucker.u[0] = U1 179 | G_Tucker.u[1] = U2 180 | G_Tucker.u[2] = U3 181 | G_Tucker.r = [r1, r2, r3] 182 | 183 | 184 | return tuck.round(G_Tucker, eps_init) 185 | 186 | 187 | def mod(X,Y): 188 | return int(X/Y), X%Y 189 | 190 | 191 | def round_matrix(A, eps): 192 | 193 | u, s, v = np.linalg.svd(np.array(A), full_matrices = False) 194 | 195 | N1, N2 = A.shape 196 | 197 | eps_svd = eps*s[0]/np.sqrt(3) 198 | r = min(N1, N2) 199 | for i in range(min(N1, N2)): 200 | if s[i] <= eps_svd: 201 | r = i 202 | break 203 | #print s/s[0] 204 | u = u[:,:r].copy() 205 | v = v[:r,:].copy() 206 | s = s[:r].copy() 207 | 208 | return u, H(v), r 209 | 210 | def H(A): 211 | return np.transpose(np.conjugate(A)) 212 | -------------------------------------------------------------------------------- /core/mkl_fft.py: -------------------------------------------------------------------------------- 1 | ''' Wrapper to MKL FFT routines ''' 2 | 3 | import numpy as _np 4 | import ctypes as _ctypes 5 | 6 | mkl = _ctypes.cdll.LoadLibrary("/Users/maksim/anaconda/lib/libmkl_rt.dylib") 7 | _DFTI_COMPLEX = _ctypes.c_int64(32) 8 | _DFTI_DOUBLE = _ctypes.c_int64(36) 9 | _DFTI_PLACEMENT = _ctypes.c_int64(11) 10 | _DFTI_NOT_INPLACE = _ctypes.c_int64(44) 11 | _DFTI_INPUT_STRIDES = _ctypes.c_int64(12) 12 | _DFTI_OUTPUT_STRIDES = _ctypes.c_int64(13) 13 | _DFTI_NUMBER_OF_TRANSFORMS = _ctypes.c_int64(7) 14 | _DFTI_OUTPUT_DISTANCE = _ctypes.c_int64(15) 15 | _DFTI_INPUT_DISTANCE = _ctypes.c_int64(14) 16 | 17 | def fft(a, out=None): 18 | ''' 19 | Forward 1d FFT transform 20 | ''' 21 | 22 | assert a.dtype == _np.complex128 23 | 24 | inplace = False 25 | 26 | if out is a: 27 | inplace = True 28 | 29 | elif out is not None: 30 | assert out.dtype == _np.complex128 31 | assert a.shape == out.shape 32 | assert not _np.may_share_memory(a, out) 33 | 34 | else: 35 | out = _np.empty_like(a) 36 | 37 | Desc_Handle = _ctypes.c_void_p(0) 38 | dims = (_ctypes.c_int64)(a.shape[0]) 39 | 40 | mkl.DftiCreateDescriptor(_ctypes.byref(Desc_Handle), _DFTI_DOUBLE, _DFTI_COMPLEX, _ctypes.c_int64(1), dims ) 41 | 42 | #mkl.DftiSetValue(_ctypes.byref(Desc_Handle), _DFTI_INPUT_DISTANCE, _ctypes.c_int64(a.shape[0])) 43 | #mkl.DftiSetValue(_ctypes.byref(Desc_Handle), _DFTI_OUTPUT_DISTANCE, _ctypes.c_int64(a.shape[0])) 44 | #Set input strides if necessary 45 | #if not a.flags['C_CONTIGUOUS']: 46 | # in_strides = (_ctypes.c_int64*3)(0, a.strides[0]/16, a.strides[1]/16) 47 | # mkl.DftiSetValue(Desc_Handle, _DFTI_INPUT_STRIDES, _ctypes.byref(in_strides)) 48 | 49 | if inplace: 50 | #Inplace FFT 51 | mkl.DftiCommitDescriptor(Desc_Handle) 52 | mkl.DftiComputeForward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p)) 53 | 54 | else: 55 | # Not-inplace FFT 56 | mkl.DftiSetValue(Desc_Handle, _DFTI_PLACEMENT, _DFTI_NOT_INPLACE) 57 | 58 | # Set output strides if necessary 59 | #if not out.flags['C_CONTIGUOUS']: 60 | # out_strides = (_ctypes.c_int64*3)(0, out.strides[0]/16, 61 | # out.strides[1]/16), mkl.DftiSetValue(Desc_Handle, _DFTI_OUTPUT_STRIDES, _ctypes.byref(out_strides)) 62 | 63 | mkl.DftiCommitDescriptor(Desc_Handle) 64 | mkl.DftiComputeForward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p), 65 | out.ctypes.data_as(_ctypes.c_void_p)) 66 | 67 | mkl.DftiFreeDescriptor(_ctypes.byref(Desc_Handle)) 68 | return out 69 | 70 | def ifft(a, out=None): 71 | ''' 72 | Backward 1d FFT transform 73 | ''' 74 | 75 | assert a.dtype == _np.complex128 76 | 77 | inplace = False 78 | 79 | if out is a: 80 | inplace = True 81 | 82 | elif out is not None: 83 | assert out.dtype == _np.complex128 84 | assert a.shape == out.shape 85 | assert not _np.may_share_memory(a, out) 86 | 87 | else: 88 | out = _np.empty_like(a) 89 | 90 | Desc_Handle = _ctypes.c_void_p(0) 91 | dims = (_ctypes.c_int64)(a.shape[0]) 92 | 93 | mkl.DftiCreateDescriptor(_ctypes.byref(Desc_Handle), _DFTI_DOUBLE, _DFTI_COMPLEX, _ctypes.c_int64(1), dims ) 94 | 95 | #mkl.DftiSetValue(_ctypes.byref(Desc_Handle), _DFTI_INPUT_DISTANCE, _ctypes.c_int64(a.shape[0])) 96 | #mkl.DftiSetValue(_ctypes.byref(Desc_Handle), _DFTI_OUTPUT_DISTANCE, _ctypes.c_int64(a.shape[0])) 97 | #Set input strides if necessary 98 | #if not a.flags['C_CONTIGUOUS']: 99 | # in_strides = (_ctypes.c_int64*3)(0, a.strides[0]/16, a.strides[1]/16) 100 | # mkl.DftiSetValue(Desc_Handle, _DFTI_INPUT_STRIDES, _ctypes.byref(in_strides)) 101 | 102 | if inplace: 103 | #Inplace FFT 104 | mkl.DftiCommitDescriptor(Desc_Handle) 105 | mkl.DftiComputeBackward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p)) 106 | 107 | else: 108 | # Not-inplace FFT 109 | mkl.DftiSetValue(Desc_Handle, _DFTI_PLACEMENT, _DFTI_NOT_INPLACE) 110 | 111 | # Set output strides if necessary 112 | #if not out.flags['C_CONTIGUOUS']: 113 | # out_strides = (_ctypes.c_int64*3)(0, out.strides[0]/16, 114 | # out.strides[1]/16), mkl.DftiSetValue(Desc_Handle, _DFTI_OUTPUT_STRIDES, _ctypes.byref(out_strides)) 115 | 116 | mkl.DftiCommitDescriptor(Desc_Handle) 117 | mkl.DftiComputeBackward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p), 118 | out.ctypes.data_as(_ctypes.c_void_p)) 119 | 120 | mkl.DftiFreeDescriptor(_ctypes.byref(Desc_Handle)) 121 | return out 122 | 123 | 124 | def fft2(a, out=None): 125 | ''' 126 | Forward two-dimensional double-precision complex-complex FFT. 127 | Uses the Intel MKL libraries distributed with Enthought Python. 128 | Normalisation is different from Numpy! 129 | By default, allocates new memory like 'a' for output data. 130 | Returns the array containing output data. 131 | ''' 132 | 133 | assert a.dtype == _np.complex128 134 | assert len(a.shape) == 2 135 | 136 | inplace = False 137 | 138 | if out is a: 139 | inplace = True 140 | 141 | elif out is not None: 142 | assert out.dtype == _np.complex128 143 | assert a.shape == out.shape 144 | assert not _np.may_share_memory(a, out) 145 | 146 | else: 147 | out = _np.empty_like(a) 148 | 149 | Desc_Handle = _ctypes.c_void_p(0) 150 | dims = (_ctypes.c_int64*2)(*a.shape) 151 | 152 | mkl.DftiCreateDescriptor(_ctypes.byref(Desc_Handle), _DFTI_DOUBLE, _DFTI_COMPLEX, _ctypes.c_int64(2), dims ) 153 | 154 | #Set input strides if necessary 155 | if not a.flags['C_CONTIGUOUS']: 156 | in_strides = (_ctypes.c_int64*3)(0, a.strides[0]/16, a.strides[1]/16) 157 | mkl.DftiSetValue(Desc_Handle, _DFTI_INPUT_STRIDES, _ctypes.byref(in_strides)) 158 | 159 | if inplace: 160 | #Inplace FFT 161 | mkl.DftiCommitDescriptor(Desc_Handle) 162 | mkl.DftiComputeForward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p)) 163 | 164 | else: 165 | # Not-inplace FFT 166 | mkl.DftiSetValue(Desc_Handle, _DFTI_PLACEMENT, _DFTI_NOT_INPLACE) 167 | 168 | # Set output strides if necessary 169 | if not out.flags['C_CONTIGUOUS']: 170 | out_strides = (_ctypes.c_int64*3)(0, out.strides[0]/16, 171 | out.strides[1]/16), mkl.DftiSetValue(Desc_Handle, _DFTI_OUTPUT_STRIDES, _ctypes.byref(out_strides)) 172 | 173 | mkl.DftiCommitDescriptor(Desc_Handle) 174 | mkl.DftiComputeForward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p), 175 | out.ctypes.data_as(_ctypes.c_void_p)) 176 | 177 | mkl.DftiFreeDescriptor(_ctypes.byref(Desc_Handle)) 178 | return out 179 | 180 | 181 | def ifft2(a, out=None): 182 | ''' 183 | Backward two-dimensional double-precision complex-complex FFT. 184 | Uses the Intel MKL libraries distributed with Enthought Python. 185 | Normalisation is different from Numpy! 186 | By default, allocates new memory like 'a' for output data. 187 | Returns the array containing output data. 188 | ''' 189 | 190 | assert a.dtype == _np.complex128 191 | assert len(a.shape) == 2 192 | 193 | inplace = False 194 | 195 | if out is a: 196 | inplace = True 197 | 198 | elif out is not None: 199 | assert out.dtype == _np.complex128 200 | assert a.shape == out.shape 201 | assert not _np.may_share_memory(a, out) 202 | 203 | else: 204 | out = _np.empty_like(a) 205 | 206 | Desc_Handle = _ctypes.c_void_p(0) 207 | dims = (_ctypes.c_int64*2)(*a.shape) 208 | 209 | mkl.DftiCreateDescriptor(_ctypes.byref(Desc_Handle), _DFTI_DOUBLE, _DFTI_COMPLEX, _ctypes.c_int64(2), dims) 210 | 211 | #Set input strides if necessary 212 | if not a.flags['C_CONTIGUOUS']: 213 | in_strides = (_ctypes.c_int64*3)(0, a.strides[0]/16, a.strides[1]/16) 214 | mkl.DftiSetValue(Desc_Handle, _DFTI_INPUT_STRIDES, _ctypes.byref(in_strides)) 215 | 216 | if inplace: 217 | # Inplace FFT 218 | mkl.DftiCommitDescriptor(Desc_Handle) 219 | mkl.DftiComputeBackward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p)) 220 | 221 | else: 222 | # Not-inplace FFT 223 | mkl.DftiSetValue(Desc_Handle, _DFTI_PLACEMENT, _DFTI_NOT_INPLACE) 224 | 225 | # Set output strides if necessary 226 | if not out.flags['C_CONTIGUOUS']: 227 | out_strides = (_ctypes.c_int64*3)(0, out.strides[0]/16, out.strides[1]/16) 228 | mkl.DftiSetValue(Desc_Handle, _DFTI_OUTPUT_STRIDES, _ctypes.byref(out_strides)) 229 | 230 | mkl.DftiCommitDescriptor(Desc_Handle) 231 | mkl.DftiComputeBackward(Desc_Handle, a.ctypes.data_as(_ctypes.c_void_p), 232 | out.ctypes.data_as(_ctypes.c_void_p)) 233 | 234 | mkl.DftiFreeDescriptor(_ctypes.byref(Desc_Handle)) 235 | 236 | return out 237 | -------------------------------------------------------------------------------- /core/tucker.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import copy 3 | import scipy.interpolate as interpolate 4 | 5 | 6 | class tensor: 7 | 8 | def __init__(self, A=None, eps=1e-14): 9 | 10 | if A is None: 11 | self.core = 0 12 | self.u = [0, 0, 0] 13 | self.n = [0, 0, 0] 14 | self.r = [0, 0, 0] 15 | return 16 | 17 | N1, N2, N3 = A.shape 18 | 19 | B1 = np.reshape(A, (N1, -1), order='F') 20 | B2 = np.reshape(np.transpose(A, [1, 0, 2]), (N2, -1), order='F') 21 | B3 = np.reshape(np.transpose(A, [2, 0, 1]), (N3, -1), order='F') 22 | 23 | U1, V1, r1 = svd_trunc(B1, eps) 24 | U2, V2, r2 = svd_trunc(B2, eps) 25 | U3, V3, r3 = svd_trunc(B3, eps) 26 | 27 | G = np.tensordot(A, np.conjugate(U3), (2,0)) 28 | G = np.transpose(G, [2, 0, 1]) 29 | G = np.tensordot(G, np.conjugate(U2), (2,0)) 30 | G = np.transpose(G, [0, 2, 1]) 31 | G = np.tensordot(G, np.conjugate(U1), (2,0)) 32 | G = np.transpose(G, [2, 1, 0]) 33 | 34 | self.n = [N1, N2, N3] 35 | self.r = G.shape 36 | self.u = [U1, U2, U3] 37 | self.core = G 38 | 39 | def __getitem__(self, index): 40 | return [self.u[0], self.u[1], self.u[2], self.core][index] 41 | 42 | def __repr__(self): 43 | res = "This is a 3D tensor in the Tucker format with \n" 44 | r = self.r 45 | n = self.n 46 | for i in range(3): 47 | res = res + ("r(%d)=%d, n(%d)=%d \n" % (i, r[i], i, n[i])) 48 | return res 49 | 50 | def __add__(self, other): 51 | c = tensor() 52 | c.r = [self.r[0] + other.r[0], self.r[1] + other.r[1], self.r[2] + other.r[2] ] 53 | c.n = self.n 54 | c.u[0] = np.concatenate((self.u[0], other.u[0]), axis=1) 55 | c.u[1] = np.concatenate((self.u[1], other.u[1]), axis=1) 56 | c.u[2] = np.concatenate((self.u[2], other.u[2]), axis=1) 57 | 58 | if type(self.core[0,0,0]*other.core[0,0,0]*self.u[0][0,0]*other.u[0][0,0]) is np.complex128: 59 | dtype = np.complex128 60 | else: 61 | dtype = np.float64 62 | 63 | c.core = np.zeros(c.r, dtype=dtype) 64 | c.core[:self.r[0], :self.r[1], :self.r[2]] = self.core 65 | c.core[self.r[0]:, self.r[1]:, self.r[2]:] = other.core 66 | return c 67 | 68 | def __mul__(self, other): 69 | mult = tensor() 70 | mult.n = self.n 71 | mult.core = np.kron(self.core, other.core) 72 | mult.r = mult.core.shape 73 | for i in range(3): 74 | mult.u[i] = np.einsum('nk,nl->nkl', self.u[i], other.u[i]).reshape(self.u[i].shape[0], -1) 75 | return mult 76 | 77 | def __rmul__(self, const): # only a scalar by a tensor product! 78 | mult = copy.copy(self) 79 | mult.core = const * self.core 80 | return mult 81 | 82 | def __neg__(self): 83 | neg = copy.copy(self) 84 | neg.core = (-1.) * neg.core 85 | return neg 86 | 87 | def __sub__(self, other): 88 | a = copy.copy(self) 89 | b = copy.copy(other) 90 | b.core = (-1.) * b.core 91 | sub = a + b 92 | return sub 93 | 94 | def full(self): 95 | A = np.tensordot(self.core, np.transpose(self.u[2]), (2,0)) 96 | A = np.transpose(A, [2,0,1]) 97 | A = np.tensordot(A, np.transpose(self.u[1]), (2,0)) 98 | A = np.transpose(A, [0,2,1]) 99 | A = np.tensordot(A, np.transpose(self.u[0]), (2,0)) 100 | A = np.transpose(A, [2,1,0]) 101 | return A 102 | 103 | def round(a, eps): 104 | a = qr(a) 105 | b = tensor() 106 | b.n = a.n 107 | core = tensor(a.core, eps) 108 | b.core = core.core 109 | b.r = b.core.shape 110 | b.u[0] = np.dot(a.u[0], core.u[0]) 111 | b.u[1] = np.dot(a.u[1], core.u[1]) 112 | b.u[2] = np.dot(a.u[2], core.u[2]) 113 | return b 114 | 115 | def norm(a): 116 | q = qr(a) 117 | return np.linalg.norm(q.core) 118 | 119 | 120 | def round(a, eps): 121 | return a.round(eps) 122 | 123 | def can2tuck(g, U1, U2, U3): 124 | 125 | a = tensor() 126 | 127 | n, r1 = U1.shape 128 | n, r2 = U2.shape 129 | n, r3 = U3.shape 130 | 131 | if r1!=r2 or r2!=r3 or r1!=r3: 132 | raise Exception("Wrong factor sizes") 133 | 134 | r = r1 135 | if type(g[0]) is np.complex128: 136 | G = np.zeros((r, r, r), dtype = np.complex128) 137 | else: 138 | G = np.zeros((r, r, r), dtype = np.float64) 139 | for i in range(r): 140 | G[i, i, i] = g[i] 141 | 142 | a.r = (r1, r2, r3) 143 | a.n = (n, n, n) 144 | 145 | a.core = G 146 | a.u[0] = U1.copy() 147 | a.u[1] = U2.copy() 148 | a.u[2] = U3.copy() 149 | 150 | return a 151 | 152 | def real(a): # doubled ranks! 153 | 154 | b = tensor() 155 | 156 | b.n = a.n 157 | b.u[0] = np.concatenate((np.real(a.u[0]), np.imag(a.u[0])), 1) 158 | b.u[1] = np.concatenate((np.real(a.u[1]), np.imag(a.u[1])), 1) 159 | b.u[2] = np.concatenate((np.real(a.u[2]), np.imag(a.u[2])), 1) 160 | 161 | R1 = np.zeros((2*a.r[0], a.r[0]), dtype=np.complex128) 162 | R2 = np.zeros((2*a.r[1], a.r[1]), dtype=np.complex128) 163 | R3 = np.zeros((2*a.r[2], a.r[2]), dtype=np.complex128) 164 | 165 | R1[:a.r[0], :] = np.identity(a.r[0]) 166 | R1[a.r[0]:, :] = 1j*np.identity(a.r[0]) 167 | R2[:a.r[1], :] = np.identity(a.r[1]) 168 | R2[a.r[1]:, :] = 1j*np.identity(a.r[1]) 169 | R3[:a.r[2], :] = np.identity(a.r[2]) 170 | R3[a.r[2]:, :] = 1j*np.identity(a.r[2]) 171 | 172 | 173 | GG = np.tensordot(np.transpose(a.core,[2,1,0]),np.transpose(R1), (2,0)) 174 | GG = np.tensordot(np.transpose(GG,[0,2,1]),np.transpose(R2), (2,0)) 175 | GG = np.transpose(GG,[1,2,0]) 176 | b.core = np.real(np.tensordot(GG,np.transpose(R3), (2,0))) 177 | 178 | b.r = b.core.shape 179 | 180 | return b 181 | 182 | def full(a, ind=None): 183 | if ind == None: 184 | return a.full() 185 | else: 186 | b = tensor() 187 | b.r = a.r 188 | b.core = a.core 189 | b.u[0] = a.u[0][ind[0], :] 190 | b.u[1] = a.u[1][ind[1], :] 191 | b.u[2] = a.u[2][ind[2], :] 192 | b.n[0] = len(ind[0]) 193 | b.n[1] = len(ind[1]) 194 | b.n[2] = len(ind[2]) 195 | return b.full() 196 | 197 | def qr(a): 198 | 199 | b = tensor() 200 | 201 | b.core = a.core 202 | b.r = a.r 203 | b.n = a.n 204 | 205 | b.u[0], R1 = np.linalg.qr(a.u[0]) 206 | b.u[1], R2 = np.linalg.qr(a.u[1]) 207 | b.u[2], R3 = np.linalg.qr(a.u[2]) 208 | 209 | GG = np.tensordot(np.transpose(a.core,[2,1,0]),np.transpose(R1), (2,0)) 210 | GG = np.tensordot(np.transpose(GG,[0,2,1]),np.transpose(R2), (2,0)) 211 | GG = np.transpose(GG,[1,2,0]) 212 | b.core = np.tensordot(GG,np.transpose(R3), (2,0)) 213 | 214 | return b 215 | 216 | def conj(a): 217 | b = copy.copy(a) 218 | b.u[0] = np.conjugate(a.u[0]) 219 | b.u[1] = np.conjugate(a.u[1]) 220 | b.u[2] = np.conjugate(a.u[2]) 221 | b.core = np.conjugate(a.core) 222 | 223 | return b 224 | 225 | def dot(a, b): 226 | 227 | U0 = np.dot(H(a.u[0]), b.u[0]) # Gram matrices (size ra * rb) 228 | U1 = np.dot(H(a.u[1]), b.u[1]) 229 | U2 = np.dot(H(a.u[2]), b.u[2]) 230 | 231 | G = np.tensordot(b.core, U2.T, (2,0)) # b0 b1 a2 232 | G = np.transpose(G, [0, 2, 1]) # b0 a2 b1 233 | G = np.tensordot(G, U1.T, (2,0)) # b0 a2 a1 234 | G = np.transpose(G, [2, 1, 0]) # a1 a2 b0 235 | G = np.tensordot(G, U0.T, (2,0)) # a1 a2 a0 236 | G = np.transpose(G, [2, 0, 1]) 237 | 238 | G = np.conjugate(a.core) * G 239 | return sum(sum(sum(G))) 240 | 241 | def norm(a): 242 | return a.norm() 243 | 244 | 245 | def fft(a): 246 | 247 | b = tensor() 248 | 249 | b.core = a.core 250 | b.r = a.r 251 | b.n = a.n 252 | 253 | b.u[0] = np.fft.fft(a[0], axis=0) 254 | b.u[1] = np.fft.fft(a[1], axis=0) 255 | b.u[2] = np.fft.fft(a[2], axis=0) 256 | 257 | return b 258 | 259 | 260 | def ifft(a): 261 | 262 | b = tensor() 263 | 264 | b.core = a.core 265 | b.r = a.r 266 | b.n = a.n 267 | 268 | # try: 269 | # b.u[0] = mkl_ifft1d(a.u[0]) 270 | # b.u[1] = mkl_ifft1d(a.u[1]) 271 | # b.u[2] = mkl_ifft1d(a.u[2]) 272 | # 273 | # except: 274 | # print 'Standard np.fft.fft operation. May be slow if it is not from mkl' 275 | b.u[0] = np.fft.ifft(a[0], axis=0) 276 | b.u[1] = np.fft.ifft(a[1], axis=0) 277 | b.u[2] = np.fft.ifft(a[2], axis=0) 278 | 279 | 280 | 281 | return b 282 | 283 | def dst(a): 284 | 285 | b = tensor() 286 | 287 | b.core = a.core 288 | b.r = a.r 289 | b.n = a.n 290 | if type(np.imag(a[0][0,0])) is np.complex128: 291 | b.u[0] = dst1D(np.real(a[0])) + 1j * dst1D(np.imag(a[0])) 292 | b.u[1] = dst1D(np.real(a[1])) + 1j * dst1D(np.imag(a[1])) 293 | b.u[2] = dst1D(np.real(a[2])) + 1j * dst1D(np.imag(a[2])) 294 | 295 | else: 296 | b.u[0] = dst1D(np.real(a[0])) 297 | b.u[1] = dst1D(np.real(a[1])) 298 | b.u[2] = dst1D(np.real(a[2])) 299 | 300 | return b 301 | 302 | def idst(a): 303 | 304 | b = tensor() 305 | 306 | b.core = a.core 307 | b.r = a.r 308 | b.n = a.n 309 | if type(np.imag(a[0][0,0])) is np.complex128: 310 | b.u[0] = idst1D(np.real(a[0])) + 1j * idst1D(np.imag(a[0])) 311 | b.u[1] = idst1D(np.real(a[1])) + 1j * idst1D(np.imag(a[1])) 312 | b.u[2] = idst1D(np.real(a[2])) + 1j * idst1D(np.imag(a[2])) 313 | 314 | else: 315 | b.u[0] = idst1D(np.real(a[0])) 316 | b.u[1] = idst1D(np.real(a[1])) 317 | b.u[2] = idst1D(np.real(a[2])) 318 | 319 | return b 320 | 321 | def svd_trunc(A, eps = 1e-14): 322 | 323 | u, s, v = svd(A) 324 | 325 | N1, N2 = A.shape 326 | 327 | eps_svd = eps*s[0]/np.sqrt(3) 328 | r = min(N1, N2) 329 | for i in range(min(N1, N2)): 330 | if s[i] <= eps_svd: 331 | r = i 332 | break 333 | #print s/s[0] 334 | u = u[:,:r].copy() 335 | v = v[:r,:].copy() 336 | s = s[:r].copy() 337 | 338 | return u, H(v), r 339 | 340 | def H(A): 341 | return np.transpose(np.conjugate(A)) 342 | 343 | 344 | def ones(n, dtype = np.float64): 345 | a = tensor() 346 | 347 | a.u[0] = np.ones((n[0], 1), dtype=dtype) 348 | a.u[1] = np.ones((n[1], 1), dtype=dtype) 349 | a.u[2] = np.ones((n[2], 1), dtype=dtype) 350 | a.core = np.ones((1, 1, 1), dtype=dtype) 351 | a.r = (1, 1, 1) 352 | a.n = n 353 | 354 | return a 355 | 356 | def zeros(n, dtype=np.float64): 357 | a = tensor() 358 | 359 | a.u[0] = np.zeros((n[0], 1), dtype=dtype) 360 | a.u[1] = np.zeros((n[1], 1), dtype=dtype) 361 | a.u[2] = np.zeros((n[2], 1), dtype=dtype) 362 | a.core = np.ones((1, 1, 1), dtype=dtype) 363 | a.r = (1, 1, 1) 364 | a.n = n 365 | 366 | return a 367 | 368 | 369 | def dst1D(A): 370 | 371 | n = np.array(A.shape) 372 | new_size = n.copy() 373 | new_size[0] = 2*(n[0]+1) 374 | X = np.zeros(new_size, dtype=np.complex128) 375 | 376 | X[1: n[0] + 1, :] = A 377 | X = np.imag(np.fft.fft(X, axis=0)) 378 | return -X[1: n[0] + 1, :] * np.sqrt(2./(n[0] + 1)) 379 | 380 | def idst1D(A): 381 | 382 | n = np.array(A.shape) 383 | new_size = n.copy() 384 | new_size[0] = 2*(n[0]+1) 385 | X = np.zeros(new_size, dtype = np.complex128) 386 | 387 | X[1: n[0] + 1, :] = A 388 | X = (2*(n[0]+1))* np.imag(np.fft.ifft(X, axis=0)) 389 | return X[1: n[0] + 1, :] * np.sqrt(2./(n[0] + 1)) 390 | 391 | def dst3D(A): 392 | 393 | X = dst1D(A) # 0 1 2 394 | X = dst1D(np.transpose(X, [2, 0, 1])) # 2 0 1 395 | X = dst1D(np.transpose(X, [2, 1, 0])) # 1 0 2 396 | X = np.transpose(X, [1, 0, 2]) 397 | 398 | return X 399 | 400 | def mkl_fft1d(a): 401 | 402 | n,m = a.shape 403 | b = np.zeros((n,m),dtype=np.complex128) 404 | for i in range(m): 405 | b[:,i] = np.fft.fft(a[:,i]+0j, axis=0) 406 | return b 407 | 408 | def mkl_ifft1d(a): 409 | 410 | n,m = a.shape 411 | b = np.zeros((n,m),dtype=np.complex128) 412 | for i in range(m): 413 | b[:,i] = np.fft.ifft(a[:,i]+0j, axis=0)/n 414 | return b 415 | 416 | 417 | def interp(a, x_old, x_new): 418 | 419 | b = copy.deepcopy(a) 420 | n_new = len(x_new) 421 | b.n = [n_new]*3 422 | 423 | b.u[0] = np.zeros((n_new, b.r[0]), dtype = type(a.u[0][0,0])) 424 | b.u[1] = np.zeros((n_new, b.r[1]), dtype = type(a.u[1][0,0])) 425 | b.u[2] = np.zeros((n_new, b.r[2]), dtype = type(a.u[2][0,0])) 426 | 427 | 428 | for alpha in range(3): 429 | for i in range(a.r[alpha]): 430 | temp = copy.copy(a.u[alpha][:, i]) 431 | tck = interpolate.splrep(x_old, temp, s=0) 432 | b.u[alpha][:, i] = interpolate.splev(x_new, tck, der=0) 433 | 434 | return b 435 | 436 | 437 | def svd(A): 438 | try: 439 | return np.linalg.svd(A, full_matrices=False) 440 | except: #LinAlgError 441 | try: 442 | print("SVD failded") 443 | return np.linalg.svd(A + 1e-12*np.linalg.norm(A, 1), full_matrices=False) 444 | except: 445 | print("SVD failded twice") 446 | return np.linalg.svd(A + 1e-8*np.linalg.norm(A, 1), full_matrices=False) -------------------------------------------------------------------------------- /cross/multifun.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import time 3 | from math import pi 4 | import copy 5 | from scipy.special import erf 6 | import tucker3d as tuck 7 | 8 | 9 | def multifun(X, delta_cross, fun, r_add=4, y0=None, rmax=100, pr=None): 10 | 11 | # For X = [X_1,...,X_d], where X_i - tensors in the Tucker format 12 | # cross_func computes y = func(X) == func(x_1,...,x_d) in the Tucker format by using cross3d 13 | # 14 | # delta_cross - accuracy for cross3D 15 | # r_add - number of computed columns on each iteration of cross3d. May be used to improve time performing. 16 | 17 | d = len(X) 18 | if type(r_add) == int: 19 | r_add = [r_add, r_add, r_add] 20 | elif len(r_add) == 3: 21 | None 22 | else: 23 | raise Exception('r_add must be of type int or list of len = 3') 24 | 25 | eps_cross = 1 26 | 27 | if pr != None: 28 | print('cross multifun... \n') 29 | 30 | r = copy.copy(r_add) 31 | 32 | 33 | n = X[0].n 34 | N = int((min(n)+1)/2) 35 | 36 | # Type check 37 | list = [X[i].u[0][0,0] for i in range(len(X))] 38 | if type(np.sum(list)) is np.complex128: 39 | dtype = np.complex128 40 | else: 41 | dtype = np.float64 42 | 43 | if pr != None: 44 | print('data type is', dtype) 45 | 46 | # if there is initial guess 47 | if y0 != None: 48 | 49 | Q1, R = np.linalg.qr(y0.u[0]); 50 | row_order_U1 = np.sort(tuck.mv.maxvol(Q1)); 51 | Q2, R = np.linalg.qr(y0.u[1]); 52 | row_order_U2 = np.sort(tuck.mv.maxvol(Q2)); 53 | Q3, R = np.linalg.qr(y0.u[2]); 54 | row_order_U3 = np.sort(tuck.mv.maxvol(Q3)); 55 | 56 | r0 = [len(row_order_U1), len(row_order_U2), len(row_order_U3)] 57 | 58 | A = [None]*d 59 | 60 | 61 | for alpha in range(d): 62 | A[alpha] = np.tensordot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3,:]), (2, 0)) 63 | A[alpha] = np.tensordot(np.transpose(A[alpha], [2,0,1]), np.transpose(X[alpha].u[1][row_order_U2,:]), (2, 0)) 64 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[0][row_order_U1,:]), (2, 0)) 65 | A[alpha] = np.transpose(A[alpha], [2,1,0]) 66 | 67 | Ar = fun(A) 68 | 69 | 70 | A1 = np.reshape(Ar, [r0[0],-1], order='f') 71 | A1 = np.transpose(A1) 72 | Q_A1, R = np.linalg.qr(A1) 73 | column_order_U1 = tuck.mv.maxvol(Q_A1) 74 | A1_11 = A1[column_order_U1, :] 75 | 76 | 77 | A2 = np.reshape(np.transpose(Ar, [1,0,2]), [r0[1],-1], order='f') 78 | A2 = np.transpose(A2) 79 | Q_A2, R = np.linalg.qr(A2) 80 | column_order_U2 = tuck.mv.maxvol(Q_A2) 81 | A2_11 = A2[column_order_U2, :] 82 | 83 | 84 | A3 = np.reshape(np.transpose(Ar, [2,0,1]), [r0[2],-1], order='f') 85 | A3 = np.transpose(A3) 86 | Q_A3, R = np.linalg.qr(A3) 87 | column_order_U3 = tuck.mv.maxvol(Q_A3) 88 | A3_11 = A3[column_order_U3, :] 89 | 90 | 91 | u1 = np.zeros((n[0], r0[0]), dtype=dtype) 92 | for i in range(r0[0]): 93 | for alpha in range(d): 94 | k1_order, j1_order = mod(column_order_U1[i], r0[1]) 95 | A[alpha] = np.dot(X[alpha].core,np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 96 | A[alpha] = np.dot(np.transpose(A[alpha], [2,0,1]), np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 97 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[0]), (2,0)) 98 | A[alpha] = np.transpose(A[alpha], [2,1,0])[:, 0, 0] 99 | u1[:,i] = fun(A) 100 | 101 | 102 | u2 = np.zeros((n[1], r0[1]), dtype=dtype) 103 | for j in range(r0[1]): 104 | for alpha in range(d): 105 | k1_order, i1_order = mod(column_order_U2[j], r0[0]) 106 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 107 | A[alpha] = np.dot(np.transpose(A[alpha], [2,1,0]),np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 108 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[1]), (2, 0)) 109 | A[alpha] = np.transpose(A[alpha], [1,2,0])[0, :, 0] 110 | u2[:,j] = fun(A) 111 | 112 | 113 | u3 = np.zeros((n[2], r0[2]), dtype=dtype) 114 | for k in range(r0[2]): 115 | for alpha in range(d): 116 | j1_order, i1_order = mod(column_order_U3[k], r0[0]) 117 | A[alpha] = np.dot(np.transpose(X[alpha].core, [2,1,0]),np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 118 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 119 | A[alpha] = np.tensordot(np.transpose(A[alpha], [1,2,0]),np.transpose(X[alpha].u[2]), (2, 0))[0,0,:] 120 | u3[:,k] = fun(A) 121 | 122 | 123 | 124 | else: 125 | ############################################################ 126 | ############################################################ 127 | ############################################################ 128 | 129 | 130 | 131 | GG = np.zeros(r, dtype=dtype) 132 | 133 | u1 = np.zeros((n[0], r_add[0]), dtype=dtype) 134 | u2 = np.zeros((n[1], r_add[1]), dtype=dtype) 135 | u3 = np.zeros((n[2], r_add[2]), dtype=dtype) 136 | 137 | u1[:N,:] = np.random.random((N,r_add[0])) 138 | u2[:N,:] = np.random.random((N,r_add[1])) 139 | u3[:N,:] = np.random.random((N,r_add[2])) 140 | 141 | u1, R = np.linalg.qr(u1) 142 | u2, R = np.linalg.qr(u2) 143 | u3, R = np.linalg.qr(u3) 144 | 145 | row_order_U1 = tuck.mv.maxvol(u1) 146 | row_order_U2 = tuck.mv.maxvol(u2) 147 | row_order_U3 = tuck.mv.maxvol(u3) 148 | 149 | r0 = [len(row_order_U1), len(row_order_U1), len(row_order_U1)] 150 | 151 | 152 | A = [None]*d 153 | 154 | for alpha in range(d): 155 | A[alpha] = np.tensordot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3,:]), (2, 0)) 156 | A[alpha] = np.tensordot(np.transpose(A[alpha], [2,0,1]), np.transpose(X[alpha].u[1][row_order_U2,:]), (2, 0)) 157 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[0][row_order_U1,:]), (2, 0)) 158 | A[alpha] = np.transpose(A[alpha], [2,1,0]) 159 | Ar = fun(A) 160 | 161 | A1 = np.reshape(Ar, [r0[0],-1], order='f') 162 | A1 = np.transpose(A1) 163 | Q_A1, R = np.linalg.qr(A1) 164 | column_order_U1 = tuck.mv.maxvol(Q_A1) 165 | A1_11 = A1[column_order_U1, :] 166 | 167 | 168 | A2 = np.reshape(np.transpose(Ar, [1,0,2]), [r0[1],-1], order='f') 169 | A2 = np.transpose(A2) 170 | Q_A2, R = np.linalg.qr(A2) 171 | column_order_U2 = tuck.mv.maxvol(Q_A2) 172 | A2_11 = A2[column_order_U2, :] 173 | 174 | 175 | A3 = np.reshape(np.transpose(Ar, [2,0,1]), [r0[2],-1], order='f') 176 | A3 = np.transpose(A3) 177 | Q_A3, R = np.linalg.qr(A3) 178 | column_order_U3 = tuck.mv.maxvol(Q_A3) 179 | A3_11 = A3[column_order_U3, :] 180 | 181 | ################################################################################# 182 | 183 | 184 | U1 = u1 185 | U2 = u2 186 | U3 = u3 187 | 188 | U1_hat = np.linalg.solve(U1[row_order_U1, :].T, U1.T).T 189 | U2_hat = np.linalg.solve(U2[row_order_U2, :].T, U2.T).T 190 | U3_hat = np.linalg.solve(U3[row_order_U3, :].T, U3.T).T 191 | 192 | u1 = np.random.random((n[0],r_add[0])) 193 | u2 = np.random.random((n[1],r_add[1])) 194 | u3 = np.random.random((n[2],r_add[2])) 195 | 196 | 197 | UU1, ind_update_1 = column_update(U1_hat, u1, row_order_U1) 198 | UU2, ind_update_2 = column_update(U2_hat, u2, row_order_U2) 199 | UU3, ind_update_3 = column_update(U3_hat, u3, row_order_U3) 200 | 201 | U1 = np.concatenate((U1, u1), 1) 202 | U2 = np.concatenate((U2, u2), 1) 203 | U3 = np.concatenate((U3, u3), 1) 204 | 205 | A1_12 = np.zeros((r0[0], r_add[0]),dtype=dtype) 206 | for ii in range(r0[0]): 207 | for alpha in range(d): 208 | k1_order, j1_order = mod(column_order_U1[ii], r0[1]) 209 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 210 | A[alpha] = np.dot(np.transpose(A[alpha], [2,0,1]),np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 211 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[0][ind_update_1, :]), (2, 0)) 212 | A[alpha] = np.transpose(A[alpha], [2,1,0])[:,0,0] 213 | A1_12[ii,:] = fun(A) 214 | 215 | 216 | A2_12 = np.zeros((r0[1], r_add[1]),dtype=dtype) 217 | for ii in range(r0[1]): 218 | for alpha in range(d): 219 | k1_order, i1_order = mod(column_order_U2[ii], r0[0]) 220 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 221 | A[alpha] = np.dot(np.transpose(A[alpha], [2,1,0]), np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 222 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[1][ind_update_2, :]), (2, 0)) 223 | A[alpha] = np.transpose(A[alpha], [1,2,0])[0,:,0] 224 | A2_12[ii, :] = fun(A) 225 | 226 | 227 | A3_12 = np.zeros((r0[2], r_add[2]),dtype=dtype) 228 | for ii in range(r0[2]): 229 | for alpha in range(d): 230 | j1_order, i1_order = mod(column_order_U3[ii], r0[0]) 231 | A[alpha] = np.dot(np.transpose(X[alpha].core, [2,1,0]),np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 232 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 233 | A[alpha] = np.tensordot(np.transpose(A[alpha], [1,2,0]),np.transpose(X[alpha].u[2][ind_update_3, :]), (2, 0))[0,0,:] 234 | A3_12[ii, :] = fun(A) 235 | 236 | 237 | r[0] = r0[0]+r_add[0] 238 | r[1] = r0[1]+r_add[1] 239 | r[2] = r0[2]+r_add[2] 240 | 241 | 242 | 243 | while True: 244 | 245 | for alpha in range(d): 246 | A[alpha] = np.dot(np.transpose(X[alpha].core, [2,1,0]), np.transpose(X[alpha].u[0][ind_update_1,:])) 247 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[1][row_order_U2,:])) 248 | A[alpha] = np.dot(np.transpose(A[alpha], [1,2,0]), np.transpose(X[alpha].u[2][row_order_U3,:])) 249 | Ar_1 = np.concatenate((Ar, fun(A)), 0) 250 | 251 | row_order_U1 = np.concatenate((row_order_U1, ind_update_1)) 252 | 253 | for alpha in range(d): 254 | A[alpha] = np.dot(np.transpose(X[alpha].core, [0,2,1]), np.transpose(X[alpha].u[1][ind_update_2,:])) 255 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[2][row_order_U3,:])) 256 | A[alpha] = np.dot(np.transpose(A[alpha], [2,1,0]), np.transpose(X[alpha].u[0][row_order_U1,:])) 257 | A[alpha] = np.transpose(A[alpha], [2,1,0]) 258 | Ar_2 = np.concatenate((Ar_1, fun(A)), 1) 259 | 260 | row_order_U2 = np.concatenate((row_order_U2, ind_update_2)) 261 | 262 | for alpha in range(d): 263 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][ind_update_3,:])) 264 | A[alpha] = np.dot(np.transpose(A[alpha], [2,0,1]),np.transpose(X[alpha].u[1][row_order_U2,:])) 265 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[0][row_order_U1,:])) 266 | A[alpha] = np.transpose(A[alpha], [2,1,0]) 267 | Ar = np.concatenate((Ar_2, fun(A)), 2) 268 | 269 | row_order_U3 = np.concatenate((row_order_U3, ind_update_3)) 270 | 271 | 272 | 273 | A1 = np.reshape(Ar, [r[0],-1], order='f') 274 | A1 = np.transpose(A1) 275 | column_order_update_U1 = tuck.mv.maxvol( schur_comp(A1, A1_11, A1_12, dtype) ) 276 | r_add[0] = len(column_order_update_U1) 277 | 278 | A2 = np.reshape(np.transpose(Ar, [1,0,2]), [r[1],-1], order='f') 279 | A2 = np.transpose(A2) 280 | column_order_update_U2 = tuck.mv.maxvol( schur_comp(A2, A2_11, A2_12, dtype) ) 281 | r_add[1] = len(column_order_update_U2) 282 | 283 | A3 = np.reshape(np.transpose(Ar, [2,0,1]), [r[2],-1], order='f') 284 | A3 = np.transpose(A3) 285 | column_order_update_U3 = tuck.mv.maxvol( schur_comp(A3, A3_11, A3_12, dtype) ) 286 | r_add[2] = len(column_order_update_U3) 287 | 288 | 289 | 290 | u1_approx = np.zeros((n[0], r_add[0]), dtype=dtype) 291 | u1 = np.zeros((n[0], r_add[0]), dtype=dtype) 292 | for i in range(r_add[0]): 293 | for alpha in range(d): 294 | k1_order, j1_order = mod(column_order_update_U1[i], r[1]) 295 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 296 | A[alpha] = np.dot(np.transpose(A[alpha], [2,0,1]),np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 297 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[0]), (2, 0)) 298 | A[alpha] = np.transpose(A[alpha], [2,1,0])[:,0,0] 299 | u1[:,i] = fun(A) 300 | 301 | u1_approx_i = np.dot(Ar, np.transpose(UU3[row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 302 | u1_approx_i = np.dot(np.transpose(u1_approx_i,[2,0,1]),np.transpose(UU2[row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 303 | u1_approx_i = np.tensordot(np.transpose(u1_approx_i,[0,2,1]),np.transpose(UU1), (2, 0)) 304 | u1_approx_i = np.transpose(u1_approx_i,[2,1,0]) 305 | u1_approx[:,i] = u1_approx_i[:, 0, 0] 306 | 307 | 308 | u2_approx = np.zeros((n[1], r_add[1]), dtype=dtype) 309 | u2 = np.zeros((n[1], r_add[1]), dtype=dtype) 310 | for j in range(r_add[1]): 311 | for alpha in range(d): 312 | k1_order, i1_order = mod(column_order_update_U2[j], r[0]) 313 | A[alpha] = np.dot(X[alpha].core, np.transpose(X[alpha].u[2][row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 314 | A[alpha] = np.dot(np.transpose(A[alpha], [2,1,0]), np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 315 | A[alpha] = np.tensordot(np.transpose(A[alpha], [0,2,1]), np.transpose(X[alpha].u[1]), (2, 0)) 316 | A[alpha] = np.transpose(A[alpha], [1,2,0])[0,:,0] 317 | u2[:,j] = fun(A) 318 | 319 | u2_approx_j = np.dot(Ar,np.transpose(UU3[row_order_U3[k1_order]:row_order_U3[k1_order]+1,:])) 320 | u2_approx_j = np.dot(np.transpose(u2_approx_j,[2,1,0]),np.transpose(UU1[row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 321 | u2_approx_j = np.tensordot(np.transpose(u2_approx_j,[0,2,1]),np.transpose(UU2), (2, 0)) 322 | u2_approx[:,j] = u2_approx_j[0, 0, :] 323 | 324 | u3_approx = np.zeros((n[2], r_add[2]), dtype=dtype) 325 | u3 = np.zeros((n[2], r_add[2]), dtype=dtype) 326 | for k in range(r_add[2]): 327 | for alpha in range(d): 328 | j1_order, i1_order = mod(column_order_update_U3[k], r[0]) 329 | A[alpha] = np.dot(np.transpose(X[alpha].core, [2,1,0]),np.transpose(X[alpha].u[0][row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 330 | A[alpha] = np.dot(np.transpose(A[alpha], [0,2,1]),np.transpose(X[alpha].u[1][row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 331 | A[alpha] = np.tensordot(np.transpose(A[alpha], [1,2,0]),np.transpose(X[alpha].u[2]), (2, 0))[0,0,:] 332 | u3[:,k] = fun(A) 333 | 334 | u3_approx_k = np.dot(np.transpose(Ar,[2,1,0]),np.transpose(UU1[row_order_U1[i1_order]:row_order_U1[i1_order]+1,:])) 335 | u3_approx_k = np.dot(np.transpose(u3_approx_k,[0,2,1]),np.transpose(UU2[row_order_U2[j1_order]:row_order_U2[j1_order]+1,:])) 336 | u3_approx_k = np.tensordot(np.transpose(u3_approx_k,[1,2,0]),np.transpose(UU3), (2, 0)) 337 | u3_approx[:,k] = u3_approx_k[0, 0, :] 338 | 339 | 340 | eps_cross = 1./3*( np.linalg.norm(u1_approx - u1)/ np.linalg.norm(u1) + 341 | np.linalg.norm(u2_approx - u2)/ np.linalg.norm(u2) + 342 | np.linalg.norm(u3_approx - u3)/ np.linalg.norm(u3) ) 343 | if pr != None: 344 | print('relative accuracy = %s' % (eps_cross), 'ranks = %s' % r) 345 | 346 | if eps_cross < delta_cross: 347 | break 348 | elif r[0] > rmax: 349 | print('Rank has exceeded rmax value') 350 | break 351 | 352 | #print np.linalg.norm( full(G, U1, U2, U3) - C_toch )/np.linalg.norm(C_toch) 353 | 354 | 355 | UU1, ind_update_1 = column_update(UU1, u1, row_order_U1) 356 | UU2, ind_update_2 = column_update(UU2, u2, row_order_U2) 357 | UU3, ind_update_3 = column_update(UU3, u3, row_order_U3) 358 | 359 | 360 | U1 = np.concatenate((U1, u1), 1) 361 | U2 = np.concatenate((U2, u2), 1) 362 | U3 = np.concatenate((U3, u3), 1) 363 | 364 | 365 | A1_11 = np.concatenate((A1_11, A1_12), 1) 366 | A1_11 = np.concatenate((A1_11, A1[column_order_update_U1,:]) ) 367 | 368 | A2_11 = np.concatenate((A2_11, A2_12), 1) 369 | A2_11 = np.concatenate((A2_11, A2[column_order_update_U2,:]) ) 370 | 371 | A3_11 = np.concatenate((A3_11, A3_12), 1) 372 | A3_11 = np.concatenate((A3_11, A3[column_order_update_U3,:]) ) 373 | 374 | A1_12 = U1[ind_update_1, r_add[0]:].T 375 | A2_12 = U2[ind_update_2, r_add[1]:].T 376 | A3_12 = U3[ind_update_3, r_add[2]:].T 377 | 378 | r[0] = r[0]+r_add[0] 379 | r[1] = r[1]+r_add[1] 380 | r[2] = r[2]+r_add[2] 381 | 382 | 383 | 384 | U1, R1 = np.linalg.qr(UU1) 385 | U2, R2 = np.linalg.qr(UU2) 386 | U3, R3 = np.linalg.qr(UU3) 387 | 388 | 389 | GG = np.tensordot(np.transpose(Ar,[2,1,0]),np.transpose(R1), (2, 0)) 390 | GG = np.tensordot(np.transpose(GG,[0,2,1]),np.transpose(R2), (2, 0)) 391 | GG = np.transpose(GG,[1,2,0]) 392 | G = np.tensordot(GG,np.transpose(R3), (2, 0)) 393 | 394 | G_Tucker = tuck.tensor(G, delta_cross) 395 | if pr != None: 396 | print('ranks after rounding = %s' % G_Tucker.r[0], G_Tucker.r[1], G_Tucker.r[2]) 397 | 398 | 399 | fun = tuck.tensor() 400 | fun.core = G_Tucker.core 401 | fun.u[0] = np.dot(U1, G_Tucker.u[0]) 402 | fun.u[1] = np.dot(U2, G_Tucker.u[1]) 403 | fun.u[2] = np.dot(U3, G_Tucker.u[2]) 404 | fun.r = G_Tucker.r 405 | fun.n = n 406 | 407 | return fun 408 | 409 | 410 | def schur_comp(A, A11, A12, dtype): 411 | r, r0 = A12.shape 412 | R = r + r0 413 | 414 | #print np.linalg.solve(A11.T, A[:,:r].T).T 415 | S_hat = np.zeros((R,r0), dtype=dtype) 416 | 417 | S_hat[:r, :] = np.dot(pinv(A11), -A12)#np.linalg.solve(A11, -A12) 418 | S_hat[r:, :] = np.identity(r0) 419 | 420 | #print A[:,:] 421 | #uu, ss, vv = np.linalg.svd(np.dot(A, S_hat)) 422 | #'ss:', ss 423 | 424 | 425 | Q, R = np.linalg.qr(np.dot(A, S_hat)) 426 | #Q , trash1, trash2 = round_matrix(np.dot(A, S_hat), delta_tucker) 427 | 428 | return Q 429 | 430 | 431 | def mod(X,Y): 432 | return int(X/Y), X%Y 433 | 434 | 435 | def maxvol_update(A, ind, dtype): 436 | # finds new r0 good rows 437 | # [ A11 A12] 438 | # [ A21 A22] => S = A22 - A21 A11^(-1) A12 439 | 440 | N, R = A.shape 441 | r = len(ind) 442 | r0 = R - r 443 | 444 | S_hat = np.zeros((R, r0),dtype=dtype) 445 | 446 | S_hat[:r, :] = np.linalg.solve(A[ind, :r], -A[ind, r:]) 447 | S_hat[r:, :] = np.identity(r0) 448 | Q, R = np.linalg.qr(np.dot(A, S_hat)) 449 | 450 | ind_update = tuck.mv.maxvol(Q) 451 | 452 | 453 | return ind_update 454 | 455 | 456 | def column_update(UU, u, ind): 457 | 458 | S = u - np.dot(UU, u[ind,:]) 459 | ind_add = tuck.mv.maxvol(S) 460 | 461 | SS = np.dot(pinv(S[ind_add, :].T), S.T).T # WARNING! pinv instead of solve! 462 | #np.linalg.solve(S[ind_add, :].T, S.T).T#np.dot(np.linalg.pinv(S[ind_add, :].T), S.T).T 463 | 464 | U1 = UU - np.dot(SS, UU[ind_add]) 465 | U2 = SS 466 | 467 | return np.concatenate((U1, U2), 1), ind_add 468 | 469 | 470 | def H(A): 471 | return np.transpose(np.conjugate(A)) 472 | 473 | 474 | def pinv(A): 475 | try: 476 | return np.linalg.pinv(A) 477 | except: #LinAlgError 478 | try: 479 | print("PINV failded") 480 | return np.linalg.pinv(A + 1e-12*np.linalg.norm(A, 1)) 481 | except: 482 | print("PINV failded twice") 483 | return np.linalg.pinv(A + 1e-8*np.linalg.norm(A, 1)) 484 | -------------------------------------------------------------------------------- /core/maxvol/build/src.macosx-10.5-x86_64-2.7/fortranobject.c: -------------------------------------------------------------------------------- 1 | #define FORTRANOBJECT_C 2 | #include "fortranobject.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | This file implements: FortranObject, array_from_pyobj, copy_ND_array 10 | 11 | Author: Pearu Peterson 12 | $Revision: 1.52 $ 13 | $Date: 2005/07/11 07:44:20 $ 14 | */ 15 | 16 | int 17 | F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj) 18 | { 19 | if (obj==NULL) { 20 | fprintf(stderr, "Error loading %s\n", name); 21 | if (PyErr_Occurred()) { 22 | PyErr_Print(); 23 | PyErr_Clear(); 24 | } 25 | return -1; 26 | } 27 | return PyDict_SetItemString(dict, name, obj); 28 | } 29 | 30 | /************************* FortranObject *******************************/ 31 | 32 | typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *); 33 | 34 | PyObject * 35 | PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) { 36 | int i; 37 | PyFortranObject *fp = NULL; 38 | PyObject *v = NULL; 39 | if (init!=NULL) /* Initialize F90 module objects */ 40 | (*(init))(); 41 | if ((fp = PyObject_New(PyFortranObject, &PyFortran_Type))==NULL) return NULL; 42 | if ((fp->dict = PyDict_New())==NULL) return NULL; 43 | fp->len = 0; 44 | while (defs[fp->len].name != NULL) fp->len++; 45 | if (fp->len == 0) goto fail; 46 | fp->defs = defs; 47 | for (i=0;ilen;i++) 48 | if (fp->defs[i].rank == -1) { /* Is Fortran routine */ 49 | v = PyFortranObject_NewAsAttr(&(fp->defs[i])); 50 | if (v==NULL) return NULL; 51 | PyDict_SetItemString(fp->dict,fp->defs[i].name,v); 52 | } else 53 | if ((fp->defs[i].data)!=NULL) { /* Is Fortran variable or array (not allocatable) */ 54 | if (fp->defs[i].type == PyArray_STRING) { 55 | int n = fp->defs[i].rank-1; 56 | v = PyArray_New(&PyArray_Type, n, fp->defs[i].dims.d, 57 | PyArray_STRING, NULL, fp->defs[i].data, fp->defs[i].dims.d[n], 58 | NPY_FARRAY, NULL); 59 | } 60 | else { 61 | v = PyArray_New(&PyArray_Type, fp->defs[i].rank, fp->defs[i].dims.d, 62 | fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_FARRAY, 63 | NULL); 64 | } 65 | if (v==NULL) return NULL; 66 | PyDict_SetItemString(fp->dict,fp->defs[i].name,v); 67 | } 68 | Py_XDECREF(v); 69 | return (PyObject *)fp; 70 | fail: 71 | Py_XDECREF(v); 72 | return NULL; 73 | } 74 | 75 | PyObject * 76 | PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module routines */ 77 | PyFortranObject *fp = NULL; 78 | fp = PyObject_New(PyFortranObject, &PyFortran_Type); 79 | if (fp == NULL) return NULL; 80 | if ((fp->dict = PyDict_New())==NULL) return NULL; 81 | fp->len = 1; 82 | fp->defs = defs; 83 | return (PyObject *)fp; 84 | } 85 | 86 | /* Fortran methods */ 87 | 88 | static void 89 | fortran_dealloc(PyFortranObject *fp) { 90 | Py_XDECREF(fp->dict); 91 | PyMem_Del(fp); 92 | } 93 | 94 | 95 | #if PY_VERSION_HEX >= 0x03000000 96 | #else 97 | static PyMethodDef fortran_methods[] = { 98 | {NULL, NULL} /* sentinel */ 99 | }; 100 | #endif 101 | 102 | 103 | static PyObject * 104 | fortran_doc (FortranDataDef def) { 105 | char *p; 106 | /* 107 | p is used as a buffer to hold generated documentation strings. 108 | A common operation in generating the documentation strings, is 109 | appending a string to the buffer p. Earlier, the following 110 | idiom was: 111 | 112 | sprintf(p, "%s", p); 113 | 114 | but this does not work when _FORTIFY_SOURCE=2 is enabled: instead 115 | of appending the string, the string is inserted. 116 | 117 | As a fix, the following idiom should be used for appending 118 | strings to a buffer p: 119 | 120 | sprintf(p + strlen(p), ""); 121 | */ 122 | PyObject *s = NULL; 123 | int i; 124 | unsigned size=100; 125 | if (def.doc!=NULL) 126 | size += strlen(def.doc); 127 | p = (char*)malloc (size); 128 | p[0] = '\0'; /* make sure that the buffer has zero length */ 129 | if (sprintf(p,"%s - ",def.name)==0) goto fail; 130 | if (def.rank==-1) { 131 | if (def.doc==NULL) { 132 | if (sprintf(p+strlen(p),"no docs available")==0) 133 | goto fail; 134 | } else { 135 | if (sprintf(p+strlen(p),"%s",def.doc)==0) 136 | goto fail; 137 | } 138 | } else { 139 | PyArray_Descr *d = PyArray_DescrFromType(def.type); 140 | if (sprintf(p+strlen(p),"'%c'-",d->type)==0) { 141 | Py_DECREF(d); 142 | goto fail; 143 | } 144 | Py_DECREF(d); 145 | if (def.data==NULL) { 146 | if (sprintf(p+strlen(p),"array(%" NPY_INTP_FMT,def.dims.d[0])==0) 147 | goto fail; 148 | for(i=1;i0) { 155 | if (sprintf(p+strlen(p),"array(%"NPY_INTP_FMT,def.dims.d[0])==0) 156 | goto fail; 157 | for(i=1;isize) { 168 | fprintf(stderr,"fortranobject.c:fortran_doc:len(p)=%zd>%d(size):"\ 169 | " too long doc string required, increase size\n",\ 170 | strlen(p),size); 171 | goto fail; 172 | } 173 | #if PY_VERSION_HEX >= 0x03000000 174 | s = PyUnicode_FromString(p); 175 | #else 176 | s = PyString_FromString(p); 177 | #endif 178 | fail: 179 | free(p); 180 | return s; 181 | } 182 | 183 | static FortranDataDef *save_def; /* save pointer of an allocatable array */ 184 | static void set_data(char *d,npy_intp *f) { /* callback from Fortran */ 185 | if (*f) /* In fortran f=allocated(d) */ 186 | save_def->data = d; 187 | else 188 | save_def->data = NULL; 189 | /* printf("set_data: d=%p,f=%d\n",d,*f); */ 190 | } 191 | 192 | static PyObject * 193 | fortran_getattr(PyFortranObject *fp, char *name) { 194 | int i,j,k,flag; 195 | if (fp->dict != NULL) { 196 | PyObject *v = PyDict_GetItemString(fp->dict, name); 197 | if (v != NULL) { 198 | Py_INCREF(v); 199 | return v; 200 | } 201 | } 202 | for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); 203 | if (j==0) 204 | if (fp->defs[i].rank!=-1) { /* F90 allocatable array */ 205 | if (fp->defs[i].func==NULL) return NULL; 206 | for(k=0;kdefs[i].rank;++k) 207 | fp->defs[i].dims.d[k]=-1; 208 | save_def = &fp->defs[i]; 209 | (*(fp->defs[i].func))(&fp->defs[i].rank,fp->defs[i].dims.d,set_data,&flag); 210 | if (flag==2) 211 | k = fp->defs[i].rank + 1; 212 | else 213 | k = fp->defs[i].rank; 214 | if (fp->defs[i].data !=NULL) { /* array is allocated */ 215 | PyObject *v = PyArray_New(&PyArray_Type, k, fp->defs[i].dims.d, 216 | fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_FARRAY, 217 | NULL); 218 | if (v==NULL) return NULL; 219 | /* Py_INCREF(v); */ 220 | return v; 221 | } else { /* array is not allocated */ 222 | Py_INCREF(Py_None); 223 | return Py_None; 224 | } 225 | } 226 | if (strcmp(name,"__dict__")==0) { 227 | Py_INCREF(fp->dict); 228 | return fp->dict; 229 | } 230 | if (strcmp(name,"__doc__")==0) { 231 | #if PY_VERSION_HEX >= 0x03000000 232 | PyObject *s = PyUnicode_FromString(""), *s2, *s3; 233 | for (i=0;ilen;i++) { 234 | s2 = fortran_doc(fp->defs[i]); 235 | s3 = PyUnicode_Concat(s, s2); 236 | Py_DECREF(s2); 237 | Py_DECREF(s); 238 | s = s3; 239 | } 240 | #else 241 | PyObject *s = PyString_FromString(""); 242 | for (i=0;ilen;i++) 243 | PyString_ConcatAndDel(&s,fortran_doc(fp->defs[i])); 244 | #endif 245 | if (PyDict_SetItemString(fp->dict, name, s)) 246 | return NULL; 247 | return s; 248 | } 249 | if ((strcmp(name,"_cpointer")==0) && (fp->len==1)) { 250 | PyObject *cobj = F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data),NULL); 251 | if (PyDict_SetItemString(fp->dict, name, cobj)) 252 | return NULL; 253 | return cobj; 254 | } 255 | #if PY_VERSION_HEX >= 0x03000000 256 | if (1) { 257 | PyObject *str, *ret; 258 | str = PyUnicode_FromString(name); 259 | ret = PyObject_GenericGetAttr((PyObject *)fp, str); 260 | Py_DECREF(str); 261 | return ret; 262 | } 263 | #else 264 | return Py_FindMethod(fortran_methods, (PyObject *)fp, name); 265 | #endif 266 | } 267 | 268 | static int 269 | fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) { 270 | int i,j,flag; 271 | PyArrayObject *arr = NULL; 272 | for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); 273 | if (j==0) { 274 | if (fp->defs[i].rank==-1) { 275 | PyErr_SetString(PyExc_AttributeError,"over-writing fortran routine"); 276 | return -1; 277 | } 278 | if (fp->defs[i].func!=NULL) { /* is allocatable array */ 279 | npy_intp dims[F2PY_MAX_DIMS]; 280 | int k; 281 | save_def = &fp->defs[i]; 282 | if (v!=Py_None) { /* set new value (reallocate if needed -- 283 | see f2py generated code for more 284 | details ) */ 285 | for(k=0;kdefs[i].rank;k++) dims[k]=-1; 286 | if ((arr = array_from_pyobj(fp->defs[i].type,dims,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) 287 | return -1; 288 | (*(fp->defs[i].func))(&fp->defs[i].rank,arr->dimensions,set_data,&flag); 289 | } else { /* deallocate */ 290 | for(k=0;kdefs[i].rank;k++) dims[k]=0; 291 | (*(fp->defs[i].func))(&fp->defs[i].rank,dims,set_data,&flag); 292 | for(k=0;kdefs[i].rank;k++) dims[k]=-1; 293 | } 294 | memcpy(fp->defs[i].dims.d,dims,fp->defs[i].rank*sizeof(npy_intp)); 295 | } else { /* not allocatable array */ 296 | if ((arr = array_from_pyobj(fp->defs[i].type,fp->defs[i].dims.d,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) 297 | return -1; 298 | } 299 | if (fp->defs[i].data!=NULL) { /* copy Python object to Fortran array */ 300 | npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,arr->nd); 301 | if (s==-1) 302 | s = PyArray_MultiplyList(arr->dimensions,arr->nd); 303 | if (s<0 || 304 | (memcpy(fp->defs[i].data,arr->data,s*PyArray_ITEMSIZE(arr)))==NULL) { 305 | if ((PyObject*)arr!=v) { 306 | Py_DECREF(arr); 307 | } 308 | return -1; 309 | } 310 | if ((PyObject*)arr!=v) { 311 | Py_DECREF(arr); 312 | } 313 | } else return (fp->defs[i].func==NULL?-1:0); 314 | return 0; /* succesful */ 315 | } 316 | if (fp->dict == NULL) { 317 | fp->dict = PyDict_New(); 318 | if (fp->dict == NULL) 319 | return -1; 320 | } 321 | if (v == NULL) { 322 | int rv = PyDict_DelItemString(fp->dict, name); 323 | if (rv < 0) 324 | PyErr_SetString(PyExc_AttributeError,"delete non-existing fortran attribute"); 325 | return rv; 326 | } 327 | else 328 | return PyDict_SetItemString(fp->dict, name, v); 329 | } 330 | 331 | static PyObject* 332 | fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw) { 333 | int i = 0; 334 | /* printf("fortran call 335 | name=%s,func=%p,data=%p,%p\n",fp->defs[i].name, 336 | fp->defs[i].func,fp->defs[i].data,&fp->defs[i].data); */ 337 | if (fp->defs[i].rank==-1) {/* is Fortran routine */ 338 | if ((fp->defs[i].func==NULL)) { 339 | PyErr_Format(PyExc_RuntimeError, "no function to call"); 340 | return NULL; 341 | } 342 | else if (fp->defs[i].data==NULL) 343 | /* dummy routine */ 344 | return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,NULL); 345 | else 346 | return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw, 347 | (void *)fp->defs[i].data); 348 | } 349 | PyErr_Format(PyExc_TypeError, "this fortran object is not callable"); 350 | return NULL; 351 | } 352 | 353 | static PyObject * 354 | fortran_repr(PyFortranObject *fp) 355 | { 356 | PyObject *name = NULL, *repr = NULL; 357 | name = PyObject_GetAttrString((PyObject *)fp, "__name__"); 358 | PyErr_Clear(); 359 | #if PY_VERSION_HEX >= 0x03000000 360 | if (name != NULL && PyUnicode_Check(name)) { 361 | repr = PyUnicode_FromFormat("", name); 362 | } 363 | else { 364 | repr = PyUnicode_FromString(""); 365 | } 366 | #else 367 | if (name != NULL && PyString_Check(name)) { 368 | repr = PyString_FromFormat("", PyString_AsString(name)); 369 | } 370 | else { 371 | repr = PyString_FromString(""); 372 | } 373 | #endif 374 | Py_XDECREF(name); 375 | return repr; 376 | } 377 | 378 | 379 | PyTypeObject PyFortran_Type = { 380 | #if PY_VERSION_HEX >= 0x03000000 381 | PyVarObject_HEAD_INIT(NULL, 0) 382 | #else 383 | PyObject_HEAD_INIT(0) 384 | 0, /*ob_size*/ 385 | #endif 386 | "fortran", /*tp_name*/ 387 | sizeof(PyFortranObject), /*tp_basicsize*/ 388 | 0, /*tp_itemsize*/ 389 | /* methods */ 390 | (destructor)fortran_dealloc, /*tp_dealloc*/ 391 | 0, /*tp_print*/ 392 | (getattrfunc)fortran_getattr, /*tp_getattr*/ 393 | (setattrfunc)fortran_setattr, /*tp_setattr*/ 394 | 0, /*tp_compare/tp_reserved*/ 395 | (reprfunc)fortran_repr, /*tp_repr*/ 396 | 0, /*tp_as_number*/ 397 | 0, /*tp_as_sequence*/ 398 | 0, /*tp_as_mapping*/ 399 | 0, /*tp_hash*/ 400 | (ternaryfunc)fortran_call, /*tp_call*/ 401 | }; 402 | 403 | /************************* f2py_report_atexit *******************************/ 404 | 405 | #ifdef F2PY_REPORT_ATEXIT 406 | static int passed_time = 0; 407 | static int passed_counter = 0; 408 | static int passed_call_time = 0; 409 | static struct timeb start_time; 410 | static struct timeb stop_time; 411 | static struct timeb start_call_time; 412 | static struct timeb stop_call_time; 413 | static int cb_passed_time = 0; 414 | static int cb_passed_counter = 0; 415 | static int cb_passed_call_time = 0; 416 | static struct timeb cb_start_time; 417 | static struct timeb cb_stop_time; 418 | static struct timeb cb_start_call_time; 419 | static struct timeb cb_stop_call_time; 420 | 421 | extern void f2py_start_clock(void) { ftime(&start_time); } 422 | extern 423 | void f2py_start_call_clock(void) { 424 | f2py_stop_clock(); 425 | ftime(&start_call_time); 426 | } 427 | extern 428 | void f2py_stop_clock(void) { 429 | ftime(&stop_time); 430 | passed_time += 1000*(stop_time.time - start_time.time); 431 | passed_time += stop_time.millitm - start_time.millitm; 432 | } 433 | extern 434 | void f2py_stop_call_clock(void) { 435 | ftime(&stop_call_time); 436 | passed_call_time += 1000*(stop_call_time.time - start_call_time.time); 437 | passed_call_time += stop_call_time.millitm - start_call_time.millitm; 438 | passed_counter += 1; 439 | f2py_start_clock(); 440 | } 441 | 442 | extern void f2py_cb_start_clock(void) { ftime(&cb_start_time); } 443 | extern 444 | void f2py_cb_start_call_clock(void) { 445 | f2py_cb_stop_clock(); 446 | ftime(&cb_start_call_time); 447 | } 448 | extern 449 | void f2py_cb_stop_clock(void) { 450 | ftime(&cb_stop_time); 451 | cb_passed_time += 1000*(cb_stop_time.time - cb_start_time.time); 452 | cb_passed_time += cb_stop_time.millitm - cb_start_time.millitm; 453 | } 454 | extern 455 | void f2py_cb_stop_call_clock(void) { 456 | ftime(&cb_stop_call_time); 457 | cb_passed_call_time += 1000*(cb_stop_call_time.time - cb_start_call_time.time); 458 | cb_passed_call_time += cb_stop_call_time.millitm - cb_start_call_time.millitm; 459 | cb_passed_counter += 1; 460 | f2py_cb_start_clock(); 461 | } 462 | 463 | static int f2py_report_on_exit_been_here = 0; 464 | extern 465 | void f2py_report_on_exit(int exit_flag,void *name) { 466 | if (f2py_report_on_exit_been_here) { 467 | fprintf(stderr," %s\n",(char*)name); 468 | return; 469 | } 470 | f2py_report_on_exit_been_here = 1; 471 | fprintf(stderr," /-----------------------\\\n"); 472 | fprintf(stderr," < F2PY performance report >\n"); 473 | fprintf(stderr," \\-----------------------/\n"); 474 | fprintf(stderr,"Overall time spent in ...\n"); 475 | fprintf(stderr,"(a) wrapped (Fortran/C) functions : %8d msec\n", 476 | passed_call_time); 477 | fprintf(stderr,"(b) f2py interface, %6d calls : %8d msec\n", 478 | passed_counter,passed_time); 479 | fprintf(stderr,"(c) call-back (Python) functions : %8d msec\n", 480 | cb_passed_call_time); 481 | fprintf(stderr,"(d) f2py call-back interface, %6d calls : %8d msec\n", 482 | cb_passed_counter,cb_passed_time); 483 | 484 | fprintf(stderr,"(e) wrapped (Fortran/C) functions (acctual) : %8d msec\n\n", 485 | passed_call_time-cb_passed_call_time-cb_passed_time); 486 | fprintf(stderr,"Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n"); 487 | fprintf(stderr,"Exit status: %d\n",exit_flag); 488 | fprintf(stderr,"Modules : %s\n",(char*)name); 489 | } 490 | #endif 491 | 492 | /********************** report on array copy ****************************/ 493 | 494 | #ifdef F2PY_REPORT_ON_ARRAY_COPY 495 | static void f2py_report_on_array_copy(PyArrayObject* arr) { 496 | const long arr_size = PyArray_Size((PyObject *)arr); 497 | if (arr_size>F2PY_REPORT_ON_ARRAY_COPY) { 498 | fprintf(stderr,"copied an array: size=%ld, elsize=%d\n", 499 | arr_size, PyArray_ITEMSIZE(arr)); 500 | } 501 | } 502 | static void f2py_report_on_array_copy_fromany(void) { 503 | fprintf(stderr,"created an array from object\n"); 504 | } 505 | 506 | #define F2PY_REPORT_ON_ARRAY_COPY_FROMARR f2py_report_on_array_copy((PyArrayObject *)arr) 507 | #define F2PY_REPORT_ON_ARRAY_COPY_FROMANY f2py_report_on_array_copy_fromany() 508 | #else 509 | #define F2PY_REPORT_ON_ARRAY_COPY_FROMARR 510 | #define F2PY_REPORT_ON_ARRAY_COPY_FROMANY 511 | #endif 512 | 513 | 514 | /************************* array_from_obj *******************************/ 515 | 516 | /* 517 | * File: array_from_pyobj.c 518 | * 519 | * Description: 520 | * ------------ 521 | * Provides array_from_pyobj function that returns a contigious array 522 | * object with the given dimensions and required storage order, either 523 | * in row-major (C) or column-major (Fortran) order. The function 524 | * array_from_pyobj is very flexible about its Python object argument 525 | * that can be any number, list, tuple, or array. 526 | * 527 | * array_from_pyobj is used in f2py generated Python extension 528 | * modules. 529 | * 530 | * Author: Pearu Peterson 531 | * Created: 13-16 January 2002 532 | * $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $ 533 | */ 534 | 535 | static int 536 | count_nonpos(const int rank, 537 | const npy_intp *dims) { 538 | int i=0,r=0; 539 | while (ind; 561 | npy_intp size = PyArray_Size((PyObject *)arr); 562 | printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n", 563 | rank,arr->flags,size); 564 | printf("\tstrides = "); 565 | dump_dims(rank,arr->strides); 566 | printf("\tdimensions = "); 567 | dump_dims(rank,arr->dimensions); 568 | } 569 | #endif 570 | 571 | #define SWAPTYPE(a,b,t) {t c; c = (a); (a) = (b); (b) = c; } 572 | 573 | static int swap_arrays(PyArrayObject* arr1, PyArrayObject* arr2) { 574 | SWAPTYPE(arr1->data,arr2->data,char*); 575 | SWAPTYPE(arr1->nd,arr2->nd,int); 576 | SWAPTYPE(arr1->dimensions,arr2->dimensions,npy_intp*); 577 | SWAPTYPE(arr1->strides,arr2->strides,npy_intp*); 578 | SWAPTYPE(arr1->base,arr2->base,PyObject*); 579 | SWAPTYPE(arr1->descr,arr2->descr,PyArray_Descr*); 580 | SWAPTYPE(arr1->flags,arr2->flags,int); 581 | /* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */ 582 | return 0; 583 | } 584 | 585 | #define ARRAY_ISCOMPATIBLE(arr,type_num) \ 586 | ( (PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) \ 587 | ||(PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) \ 588 | ||(PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) \ 589 | ||(PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) \ 590 | ) 591 | 592 | extern 593 | PyArrayObject* array_from_pyobj(const int type_num, 594 | npy_intp *dims, 595 | const int rank, 596 | const int intent, 597 | PyObject *obj) { 598 | /* Note about reference counting 599 | ----------------------------- 600 | If the caller returns the array to Python, it must be done with 601 | Py_BuildValue("N",arr). 602 | Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). 603 | 604 | Note on intent(cache,out,..) 605 | --------------------- 606 | Don't expect correct data when returning intent(cache) array. 607 | 608 | */ 609 | char mess[200]; 610 | PyArrayObject *arr = NULL; 611 | PyArray_Descr *descr; 612 | char typechar; 613 | int elsize; 614 | 615 | if ((intent & F2PY_INTENT_HIDE) 616 | || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None)) 617 | || ((intent & F2PY_OPTIONAL) && (obj==Py_None)) 618 | ) { 619 | /* intent(cache), optional, intent(hide) */ 620 | if (count_nonpos(rank,dims)) { 621 | int i; 622 | sprintf(mess,"failed to create intent(cache|hide)|optional array" 623 | "-- must have defined dimensions but got ("); 624 | for(i=0;ielsize; 643 | typechar = descr->type; 644 | Py_DECREF(descr); 645 | if (PyArray_Check(obj)) { 646 | arr = (PyArrayObject *)obj; 647 | 648 | if (intent & F2PY_INTENT_CACHE) { 649 | /* intent(cache) */ 650 | if (PyArray_ISONESEGMENT(obj) 651 | && PyArray_ITEMSIZE((PyArrayObject *)obj)>=elsize) { 652 | if (check_and_fix_dimensions((PyArrayObject *)obj,rank,dims)) { 653 | return NULL; /*XXX: set exception */ 654 | } 655 | if (intent & F2PY_INTENT_OUT) 656 | Py_INCREF(obj); 657 | return (PyArrayObject *)obj; 658 | } 659 | sprintf(mess,"failed to initialize intent(cache) array"); 660 | if (!PyArray_ISONESEGMENT(obj)) 661 | sprintf(mess+strlen(mess)," -- input must be in one segment"); 662 | if (PyArray_ITEMSIZE(arr)descr->type,typechar); 710 | if (!(F2PY_CHECK_ALIGNMENT(arr, intent))) 711 | sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent)); 712 | PyErr_SetString(PyExc_ValueError,mess); 713 | return NULL; 714 | } 715 | 716 | /* here we have always intent(in) or intent(inplace) */ 717 | 718 | { 719 | PyArrayObject *retarr = (PyArrayObject *) \ 720 | PyArray_New(&PyArray_Type, arr->nd, arr->dimensions, type_num, 721 | NULL,NULL,0, 722 | !(intent&F2PY_INTENT_C), 723 | NULL); 724 | if (retarr==NULL) 725 | return NULL; 726 | F2PY_REPORT_ON_ARRAY_COPY_FROMARR; 727 | if (PyArray_CopyInto(retarr, arr)) { 728 | Py_DECREF(retarr); 729 | return NULL; 730 | } 731 | if (intent & F2PY_INTENT_INPLACE) { 732 | if (swap_arrays(arr,retarr)) 733 | return NULL; /* XXX: set exception */ 734 | Py_XDECREF(retarr); 735 | if (intent & F2PY_INTENT_OUT) 736 | Py_INCREF(arr); 737 | } else { 738 | arr = retarr; 739 | } 740 | } 741 | return arr; 742 | } 743 | 744 | if ((intent & F2PY_INTENT_INOUT) 745 | || (intent & F2PY_INTENT_INPLACE) 746 | || (intent & F2PY_INTENT_CACHE)) { 747 | sprintf(mess,"failed to initialize intent(inout|inplace|cache) array" 748 | " -- input must be array but got %s", 749 | PyString_AsString(PyObject_Str(PyObject_Type(obj))) 750 | ); 751 | PyErr_SetString(PyExc_TypeError,mess); 752 | return NULL; 753 | } 754 | 755 | { 756 | F2PY_REPORT_ON_ARRAY_COPY_FROMANY; 757 | arr = (PyArrayObject *) \ 758 | PyArray_FromAny(obj,PyArray_DescrFromType(type_num), 0,0, 759 | ((intent & F2PY_INTENT_C)?NPY_CARRAY:NPY_FARRAY) \ 760 | | NPY_FORCECAST, NULL); 761 | if (arr==NULL) 762 | return NULL; 763 | if (check_and_fix_dimensions(arr,rank,dims)) 764 | return NULL; /*XXX: set exception */ 765 | return arr; 766 | } 767 | 768 | } 769 | 770 | /*****************************************/ 771 | /* Helper functions for array_from_pyobj */ 772 | /*****************************************/ 773 | 774 | static 775 | int check_and_fix_dimensions(const PyArrayObject* arr,const int rank,npy_intp *dims) { 776 | /* 777 | This function fills in blanks (that are -1\'s) in dims list using 778 | the dimensions from arr. It also checks that non-blank dims will 779 | match with the corresponding values in arr dimensions. 780 | */ 781 | const npy_intp arr_size = (arr->nd)?PyArray_Size((PyObject *)arr):1; 782 | #ifdef DEBUG_COPY_ND_ARRAY 783 | dump_attrs(arr); 784 | printf("check_and_fix_dimensions:init: dims="); 785 | dump_dims(rank,dims); 786 | #endif 787 | if (rank > arr->nd) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */ 788 | npy_intp new_size = 1; 789 | int free_axe = -1; 790 | int i; 791 | npy_intp d; 792 | /* Fill dims where -1 or 0; check dimensions; calc new_size; */ 793 | for(i=0;ind;++i) { 794 | d = arr->dimensions[i]; 795 | if (dims[i] >= 0) { 796 | if (d>1 && dims[i]!=d) { 797 | fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT 798 | " but got %" NPY_INTP_FMT "\n", 799 | i,dims[i], d); 800 | return 1; 801 | } 802 | if (!dims[i]) dims[i] = 1; 803 | } else { 804 | dims[i] = d ? d : 1; 805 | } 806 | new_size *= dims[i]; 807 | } 808 | for(i=arr->nd;i1) { 810 | fprintf(stderr,"%d-th dimension must be %" NPY_INTP_FMT 811 | " but got 0 (not defined).\n", 812 | i,dims[i]); 813 | return 1; 814 | } else if (free_axe<0) 815 | free_axe = i; 816 | else 817 | dims[i] = 1; 818 | if (free_axe>=0) { 819 | dims[free_axe] = arr_size/new_size; 820 | new_size *= dims[free_axe]; 821 | } 822 | if (new_size != arr_size) { 823 | fprintf(stderr,"unexpected array size: new_size=%" NPY_INTP_FMT 824 | ", got array with arr_size=%" NPY_INTP_FMT " (maybe too many free" 825 | " indices)\n", new_size,arr_size); 826 | return 1; 827 | } 828 | } else if (rank==arr->nd) { 829 | npy_intp new_size = 1; 830 | int i; 831 | npy_intp d; 832 | for (i=0; idimensions[i]; 834 | if (dims[i]>=0) { 835 | if (d > 1 && d!=dims[i]) { 836 | fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT 837 | " but got %" NPY_INTP_FMT "\n", 838 | i,dims[i],d); 839 | return 1; 840 | } 841 | if (!dims[i]) dims[i] = 1; 842 | } else dims[i] = d; 843 | new_size *= dims[i]; 844 | } 845 | if (new_size != arr_size) { 846 | fprintf(stderr,"unexpected array size: new_size=%" NPY_INTP_FMT 847 | ", got array with arr_size=%" NPY_INTP_FMT "\n", new_size,arr_size); 848 | return 1; 849 | } 850 | } else { /* [[1,2]] -> [[1],[2]] */ 851 | int i,j; 852 | npy_intp d; 853 | int effrank; 854 | npy_intp size; 855 | for (i=0,effrank=0;ind;++i) 856 | if (arr->dimensions[i]>1) ++effrank; 857 | if (dims[rank-1]>=0) 858 | if (effrank>rank) { 859 | fprintf(stderr,"too many axes: %d (effrank=%d), expected rank=%d\n", 860 | arr->nd,effrank,rank); 861 | return 1; 862 | } 863 | 864 | for (i=0,j=0;ind && arr->dimensions[j]<2) ++j; 866 | if (j>=arr->nd) d = 1; 867 | else d = arr->dimensions[j++]; 868 | if (dims[i]>=0) { 869 | if (d>1 && d!=dims[i]) { 870 | fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT 871 | " but got %" NPY_INTP_FMT " (real index=%d)\n", 872 | i,dims[i],d,j-1); 873 | return 1; 874 | } 875 | if (!dims[i]) dims[i] = 1; 876 | } else 877 | dims[i] = d; 878 | } 879 | 880 | for (i=rank;ind;++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */ 881 | while (jnd && arr->dimensions[j]<2) ++j; 882 | if (j>=arr->nd) d = 1; 883 | else d = arr->dimensions[j++]; 884 | dims[rank-1] *= d; 885 | } 886 | for (i=0,size=1;ind); 891 | for (i=0;ind;++i) fprintf(stderr," %" NPY_INTP_FMT,arr->dimensions[i]); 894 | fprintf(stderr," ]\n"); 895 | return 1; 896 | } 897 | } 898 | #ifdef DEBUG_COPY_ND_ARRAY 899 | printf("check_and_fix_dimensions:end: dims="); 900 | dump_dims(rank,dims); 901 | #endif 902 | return 0; 903 | } 904 | 905 | /* End of file: array_from_pyobj.c */ 906 | 907 | /************************* copy_ND_array *******************************/ 908 | 909 | extern 910 | int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out) 911 | { 912 | F2PY_REPORT_ON_ARRAY_COPY_FROMARR; 913 | return PyArray_CopyInto(out, (PyArrayObject *)arr); 914 | } 915 | 916 | /*********************************************/ 917 | /* Compatibility functions for Python >= 3.0 */ 918 | /*********************************************/ 919 | 920 | #if PY_VERSION_HEX >= 0x03000000 921 | 922 | PyObject * 923 | F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)) 924 | { 925 | PyObject *ret = PyCapsule_New(ptr, NULL, dtor); 926 | if (ret == NULL) { 927 | PyErr_Clear(); 928 | } 929 | return ret; 930 | } 931 | 932 | void * 933 | F2PyCapsule_AsVoidPtr(PyObject *obj) 934 | { 935 | void *ret = PyCapsule_GetPointer(obj, NULL); 936 | if (ret == NULL) { 937 | PyErr_Clear(); 938 | } 939 | return ret; 940 | } 941 | 942 | int 943 | F2PyCapsule_Check(PyObject *ptr) 944 | { 945 | return PyCapsule_CheckExact(ptr); 946 | } 947 | 948 | #else 949 | 950 | PyObject * 951 | F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)) 952 | { 953 | return PyCObject_FromVoidPtr(ptr, dtor); 954 | } 955 | 956 | void * 957 | F2PyCapsule_AsVoidPtr(PyObject *ptr) 958 | { 959 | return PyCObject_AsVoidPtr(ptr); 960 | } 961 | 962 | int 963 | F2PyCapsule_Check(PyObject *ptr) 964 | { 965 | return PyCObject_Check(ptr); 966 | } 967 | 968 | #endif 969 | 970 | 971 | #ifdef __cplusplus 972 | } 973 | #endif 974 | /************************* EOF fortranobject.c *******************************/ 975 | --------------------------------------------------------------------------------