Module cross_act: compute user-specified function of TT-tensors¶
Package teneva, module cross_act: compute function of TT-tensors.
This module contains the function “cross_act” which approximates the output of the given function in the TT-format with input parameters also specified in the TT-format. Modification of the cross approximation method in the TT-format (TT-cross) is used.
- teneva.cross_act.cross_act(f, X_list, Y0, e=1e-06, nswp=10, r=9999, dr=5, dr2=0, seed=None, log=False)[source]¶
Compute the output in the TT-format for the function of TT-tensors.
This is a draft (however, in most cases, the function already works successfully. There is a problem in the rank-1 case)!
This function computes the TT-approximation for the output of the given function in the TT-format with input parameters also specified in the TT-format. Modification of the cross approximation method in the TT-format (TT-cross) is used.
- Parameters:
f (function) – function f(X) which computes the output elements for the given set of input points X, where X is a 2D np.ndarray of the shape [samples, D], where D is a number of function inputs. The function should return 1D np.ndarray of the length equals to samples (i.e., it should be the values of the target function for all provided samples).
X_list (list of lists) – several (D) TT-tensors, which are the input for the target function (f). Each TT-tensor should be represented as a list of its TT-cores. The dimension (d) and mode sizes for all tensors must match.
Y0 (list) – TT-tensor, which is the initial approximation for algorithm. It may be, for example, random TT-tensor, which can be built by the “rand” function from teneva: Y0 = teneva.rand(n, r), where n is a size of tensor modes (e.g., n = [5, 6, 7, 8, 9] for the 5-dimensional tensor) and r is related TT-rank (e.g., r = 1). Note that the shape of this tensor should be same as for input tensors from X_list.
e (float) – accuracy for SVD truncation and convergence criterion for algorithm (> 0). If between iterations the relative rate of solution change is less than this value, then the operation of the algorithm will be interrupted.
nswp (int) – maximum number of iterations (sweeps) of the algorithm (>= 0). One sweep corresponds to a complete pass of all tensor TT-cores from right to left and then from left to right.
r (int) – maximum rank for SVD operation (> 0).
dr (int) – rank for AMEN iterations (kickrank; >= 0).
dr2 (int) – additional rank for AMEN iterations (kickrank2; >= 0).
seed (int) – random seed. It should be an integer number or a numpy Generator class instance.
log (bool) – if flag is set, then the information about the progress of the algorithm will be printed after each sweep.
- Returns:
TT-Tensor which approximates the output of the function.
- Return type:
list
Examples:
Let consider the simple operation in the TT-format “Y = X1 * X2 + X3”:
d = 10 # Dimension of the input tensors n = [20]*d # Mode sizes of the input tensors (it may be list) # Random TT-tensors (inputs): X1 = teneva.rand(n, r=3) X2 = teneva.rand(n, r=4) X3 = teneva.rand(n, r=5)
We can compute the exact result (output):
t = tpc() Y_real = teneva.add(teneva.mul(X1, X2), X3) Y_real = teneva.truncate(Y_real, e=1.E-16) t = tpc() - t teneva.show(Y_real) print(f'\nTime (sec) : {t:-7.3f}') # >>> ---------------------------------------- # >>> Output: # TT-tensor 10D : |20| |20| |20| |20| |20| |20| |20| |20| |20| |20| # <rank> = 17.0 : \17/ \17/ \17/ \17/ \17/ \17/ \17/ \17/ \17/ # # Time (sec) : 0.005 #
We set all parameters (note that only “f”, “X_list” and “Y0” are required):
def f(X): # Function should compute the output elements for the given set # of input points X (array "[samples, D]"; in our case, D=3). # The function should return 1D np.ndarray of the length "samples" # with values of the target function for all provided samples. return X[:, 0] * X[:, 1] + X[:, 2]
# The input of the function (note that the dimension # and mode sizes for all tensors must match): X_list = [X1, X2, X3] # Random initial approximation for the output (note that # the shape of this tensor should be same as for X1, X2, X3): Y0 = teneva.rand(n, r=1) e = 1.E-6 # Accuracy and convergence criterion (optional) nswp = 10 # Maximum number of iterations (optional) r = 9999 # Maximum rank for SVD operation (optional) dr = 3 # Rank ("kickrank") for AMEN (optional) dr2 = 1 # Additional rank for AMEN (optional) log = True # If true, then logs will be presented (optional)
And now we can run the function:
t = tpc() Y = teneva.cross_act(f, X_list, Y0, e, nswp, r, dr, dr2, seed=123, log=log) Y = teneva.truncate(Y, e=1.E-16) t = tpc() - t print('\nResult:') teneva.show(Y) # >>> ---------------------------------------- # >>> Output: # == cross-act # 1 | e: 1.4e+00 | r: 7.0 # == cross-act # 2 | e: 8.3e-01 | r: 13.0 # == cross-act # 3 | e: 4.3e-01 | r: 19.0 # == cross-act # 4 | e: 1.8e-01 | r: 20.0 # == cross-act # 5 | e: 3.5e-15 | r: 20.0 # # Result: # TT-tensor 10D : |20| |20| |20| |20| |20| |20| |20| |20| |20| |20| # <rank> = 18.4 : \18/ \17/ \19/ \20/ \17/ \18/ \19/ \19/ \18/ #
Finally, we can check the result:
eps = teneva.accuracy(Y, Y_real) print(f'Time (sec) : {t:-7.3f}') print(f'Error : {eps:-7.1e}') # >>> ---------------------------------------- # >>> Output: # Time (sec) : 0.213 # Error : 0.0e+00 #
Note that for this example, we do not have a gain in time, however, if we consider a more complex function of arguments in the TT-format, then the situation will change dramatically, since a general function cannot be calculated using simple operations in the TT-format. For example:
d = 5 # Dimension of the input tensors n = [10]*d # Mode sizes of the input tensors (it may be list) # Random TT-tensors (inputs): X1 = teneva.rand(n, r=3) X2 = teneva.rand(n, r=4) X3 = teneva.rand(n, r=5)
def f(X): return np.exp(-0.1 * X[:, 0]**2) + X[:, 1] + 0.42 * np.sin(X[:, 2]**2)
t = tpc() Y = teneva.rand(n, r=1) Y = teneva.cross_act(f, [X1, X2, X3], Y, log=True) Y = teneva.truncate(Y, e=1.E-10) t = tpc() - t print('\nResult:') teneva.show(Y) # >>> ---------------------------------------- # >>> Output: # == cross-act # 1 | e: 1.3e+00 | r: 10.8 # == cross-act # 2 | e: 3.5e-01 | r: 17.8 # == cross-act # 3 | e: 3.9e-01 | r: 23.9 # == cross-act # 4 | e: 3.9e-01 | r: 29.8 # == cross-act # 5 | e: 4.1e-01 | r: 35.7 # == cross-act # 6 | e: 3.8e-01 | r: 41.6 # == cross-act # 7 | e: 3.6e-01 | r: 47.4 # == cross-act # 8 | e: 2.9e-01 | r: 53.2 # == cross-act # 9 | e: 2.4e-01 | r: 59.1 # == cross-act # 10 | e: 1.5e-01 | r: 64.6 # == cross-act # 11 | e: 6.1e-02 | r: 65.7 # # Result: # TT-tensor 5D : |10| |10| |10| |10| |10| # <rank> = 63.0 : \10/ \100/ \100/ \10/ #
We can check the accuracy from comparison with the full tensor:
X1_full = teneva.full(X1).reshape(-1, order='F').reshape(-1, 1) X2_full = teneva.full(X2).reshape(-1, order='F').reshape(-1, 1) X3_full = teneva.full(X3).reshape(-1, order='F').reshape(-1, 1) Y_full = teneva.full(Y).reshape(-1, order='F') Y_real = f(np.hstack((X1_full, X2_full, X3_full))) e_nrm = np.linalg.norm(Y_full - Y_real) / np.linalg.norm(Y_real) e_max = np.max(np.abs(Y_full - Y_real)) print(f'Error norm : {e_nrm:-7.1e}') print(f'Error max : {e_max:-7.1e}') # >>> ---------------------------------------- # >>> Output: # Error norm : 3.0e-15 # Error max : 3.8e-14 #