Source code for teneva.act_two

"""Package teneva, module act_two: operations with a pair of TT-tensors.

This module contains the basic operations with a pair of TT-tensors "(Y1, Y2)",
including "add", "mul", "sub", etc.

"""
import numpy as np
import teneva


[docs]def accuracy(Y1, Y2): """Compute || Y1 - Y2 || / || Y2 || for tensors in the TT-format. Args: Y1 (list): TT-tensor. Y2 (list): TT-tensor. Returns: float: the relative difference between two tensors. Note: Also, for convenience, tensors in numpy format can be passed, in this case the norm will be calculated using the function "linalg.norm". """ if isinstance(Y1, np.ndarray): return np.linalg.norm(Y1 - Y2) / np.linalg.norm(Y2) z1, p1 = teneva.norm(sub(Y1, Y2), use_stab=True) z2, p2 = teneva.norm(Y2, use_stab=True) if p1 - p2 > 500: return 1.E+299 if p1 - p2 < -500: return 0. c = 2.**(p1 - p2) if np.isinf(c) or np.isinf(z1) or np.isinf(z2) or abs(z2) < 1.E-100: return -1 # TODO: check return c * z1 / z2
[docs]def add(Y1, Y2): """Compute Y1 + Y2 in the TT-format. Args: Y1 (int, float, list): TT-tensor (or it may be int/float). Y2 (int, float, list): TT-tensor (or it may be int/float). Returns: list: TT-tensor, which represents the element wise sum of Y1 and Y2. If both Y1 and Y2 are numbers, then result will be int/float number. """ if teneva._is_num(Y1) and teneva._is_num(Y2): return Y1 + Y2 elif teneva._is_num(Y1): Y1 = teneva.const(teneva.shape(Y2), Y1) elif teneva._is_num(Y2): Y2 = teneva.const(teneva.shape(Y1), Y2) n, r1, r2, Y = teneva.shape(Y1), teneva.ranks(Y1), teneva.ranks(Y2), [] for i, (G1, G2, k) in enumerate(zip(Y1, Y2, n)): if i == 0: G = np.concatenate([G1, G2], axis=2) elif i == len(n) - 1: G = np.concatenate([G1, G2], axis=0) else: r1_l, r1_r = r1[i:i+2] r2_l, r2_r = r2[i:i+2] Z1 = np.zeros([r1_l, k, r2_r]) Z2 = np.zeros([r2_l, k, r1_r]) L1 = np.concatenate([G1, Z1], axis=2) L2 = np.concatenate([Z2, G2], axis=2) G = np.concatenate([L1, L2], axis=0) Y.append(G) return Y
[docs]def mul(Y1, Y2): """Compute element wise product Y1 * Y2 in the TT-format. Args: Y1 (int, float, list): TT-tensor (or it may be int/float). Y2 (int, float, list): TT-tensor (or it may be int/float). Returns: list: TT-tensor, which represents the element wise product of Y1 and Y2. If both Y1 and Y2 are numbers, then result will be float number. """ if teneva._is_num(Y1) and teneva._is_num(Y2): return Y1 * Y2 if teneva._is_num(Y1): Y = teneva.copy(Y2) Y[0] *= Y1 return Y if teneva._is_num(Y2): Y = teneva.copy(Y1) Y[0] *= Y2 return Y Y = [] for G1, G2 in zip(Y1, Y2): G = G1[:, None, :, :, None] * G2[None, :, :, None, :] G = G.reshape([G1.shape[0]*G2.shape[0], -1, G1.shape[-1]*G2.shape[-1]]) Y.append(G) return Y
[docs]def mul_scalar(Y1, Y2, use_stab=False): """Compute scalar product for Y1 and Y2 in the TT-format. Args: Y1 (list): TT-tensor. Y2 (list): TT-tensor. use_stab (bool): if flag is set, then function will also return the second argument p, which is the factor of 2-power. Returns: float: the scalar product. """ v = None p = 0 for i, (G1, G2) in enumerate(zip(Y1, Y2)): G = G1[:, None, :, :, None] * G2[None, :, :, None, :] G = G.reshape([G1.shape[0]*G2.shape[0], -1, G1.shape[-1]*G2.shape[-1]]) G = np.sum(G, axis=1) v = G.copy() if i == 0 else v @ G if use_stab: v, p = teneva.core_stab(v, p) v = v.item() return (v, p) if use_stab else v
[docs]def outer(Y1, Y2): """Compute outer product of two TT-tensors. Args: Y1 (list): TT-tensor. Y2 (list): TT-tensor. Returns: list: TT-tensor, which is the outer product of Y1 and Y2. Note: See also "outer_many" function, which computes outer product of many given TT-tensors. """ Y = teneva.copy(Y1) Y.extend(teneva.copy(Y2)) return Y
[docs]def sub(Y1, Y2): """Compute Y1 - Y2 in the TT-format. Args: Y1 (int, float, list): TT-tensor (or it may be int/float). Y2 (int, float, list): TT-tensor (or it may be int/float). Returns: list: TT-tensor, which represents the result of the operation Y1-Y2. If both Y1 and Y2 are numbers, then result will be float number. """ if teneva._is_num(Y1) and teneva._is_num(Y2): return Y1 - Y2 if teneva._is_num(Y2): Y2 = teneva.const(teneva.shape(Y1), -1.*Y2) else: Y2 = teneva.copy(Y2) Y2[0] *= -1. return add(Y1, Y2)