def QTTzerosvec(d, N, base): """ Returns the rank-1 multidimensional vector of zeros in Quantics Tensor Train format Args: d (int): number of dimensions N (int or list): If int then uniform sizes are used for all the dimensions, if list of int then len(N) == d and each dimension will use different size base (int): QTT base Returns: QTTvec The rank-1 multidim vector of zeros in Tensor Train format """ from TensorToolbox.core import Candecomp from TensorToolbox.core import zerosvec if isint(N): N = [N for i in range(d)] for sizedim in N: if np.remainder(math.log(sizedim) / math.log(base), 1.0) > np.spacing(1): raise NameError( "TensorToolbox.QTTvec.QTTzerosvec: base is not a valid base of N" ) L = int(np.around(math.log(np.prod(N)) / math.log(base))) tt = zerosvec(L, [base for i in range(L)]) return QTTvec(tt.TT, global_shape=N).build()
def bicgstab(A, b, x0=None, eps=1e-8, maxit=1000, eps_round=1e-10, ext_info=False): """ Solves the system :math:`Ax=b` using the Bi-Conjugate Gradient Stabilized method using Tensor Train format. :param TTmat A: Tensor train matrix :param TTvec b: Right hand side :param TTvec x0: [default == :py:func:`TensorToolbox.core.zerosvec`] initial guess of solution ``x`` :param float eps: [default == 1e-8] stop criteria for Bi-CGSTAB iterations :param int maxit: [default == 1000] maximum number of iterations for Bi-CGSTAB :param float eps_round: [default == 1e-10] accuracy for Tensor Train rounding operations :param bool ext_info: [default == False] whehter of not to have additional info returned :return: tuple :py:data:`(x,conv,info)` * :py:data:`x` (TTvec): solution of the linear system if converged or last iterate if not converged * :py:data:`conv` (bool): True -> converged, False -> Not converged / Zero Inner Product exeception * :py:data:`info` (dict): ``iter`` -> total number of iterations; ``r`` -> last residual in TT format; ``rho`` -> last value of dot(r0,r) must be bigger than np.spacing(1); ``r0v`` -> last value of dot(r0,v) must be bigger than np.spacing(1) """ logger = logging.getLogger(__name__) logger.propagate = False ch = logging.StreamHandler() formatter = logging.Formatter( "%(asctime)s %(levelname)s:%(name)s: %(message)s", "%Y-%m-%d %H:%M:%S") ch.setFormatter(formatter) logger.addHandler(ch) from TensorToolbox.core import TTvec from TensorToolbox.core import zerosvec from TensorToolbox.core import TTmat if not A.init or not b.init: raise NameError( "TensorToolbox.multilinalg.cg: TT not initialized correctly") if not (isinstance(A, TTmat) and isinstance(b, TTvec) and not isinstance(b, TTmat)): raise NameError( "TensorToolbox.multilinalg.cg: Conjugate gradient not implemented for the input types" ) if x0 == None: x0 = zerosvec(len(b.shape()), b.shape()) elif not isinstance(x0, TTvec) or b.shape() != x0.shape(): raise NameError( "TensorToolbox.multilinalg.cg: Initial guess must be in TT format and have the same shape of b" ) # Bi-CGSTAB init x = x0 i = 0 r = (b - dot(A, x)).rounding(eps_round) r0 = r.copy() delta_0 = norm(r0, 2) delta_new = delta_0 rho_old = 1. alpha = 1. omega = 1. v = zerosvec(len(b.shape()), b.shape()) p = zerosvec(len(b.shape()), b.shape()) while i < maxit and delta_new > eps**2. * delta_0: i += 1 rho_new = dot(r0, r) if np.abs(rho_new) < np.spacing(1): # Break computations conv = False if ext_info: info = {'iter': i, 'r': r, 'rho': rho_new, 'r0v': r0v} return (x, conv, info) else: return (x, conv) beta = (rho_new / rho_old) * (alpha / omega) p = r + (p - v * omega) * beta p.rounding(eps_round) v = dot(A, p).rounding(eps_round) r0v = dot(r0, v) if np.abs(r0v) < np.spacing(1): # Break computations conv = False if ext_info: info = {'iter': i, 'r': r, 'rho': rho_new, 'r0v': r0v} return (x, conv, info) else: return (x, conv) alpha = rho_new / r0v s = r - v * alpha s.rounding(eps_round) if norm( s, 2 ) <= eps**2. * delta_0: # Convergence already reached, update and break loop x = x + p * alpha conv = True if ext_info: info = {'iter': i, 's': r, 'rho': rho_new, 'r0v': r0v} return (x, conv, info) else: return (x, conv) t = dot(A, s).rounding(eps_round) omega = dot(t, s) / norm(t, 2) x = x + p * alpha + s * omega x.rounding(eps_round) # The exit was here, but we can postpone it ... r = s - t * omega r.rounding(eps_round) # Update new -> old delta_new = norm(r, 2) rho_old = rho_new logger.info("Bi-CGSTAB: err=%e" % (delta_new)) conv = (i < maxit) if ext_info: info = {'iter': i, 'r': r, 'rho': rho_new, 'r0v': r0v} return (x, conv, info) else: return (x, conv)
def gmres(A, b, x0=None, eps=1e-8, maxit=1000, restart=1000, eps_round=1e-10, ext_info=False): """ Solves the system :math:`Ax=b` using the Generalized Minimum Residual method with Modified Gram-Schmidt iterations using Tensor Train format. :param TTmat A: Tensor train matrix :param TTvec b: Right hand side :param TTvec x0: [default == :py:func:`TensorToolbox.core.zerosvec`] initial guess of solution ``x`` :param float eps: [default == 1e-8] stop criteria for GMRES iterations :param int maxit: [default == 1000] maximum number of iterations for GMRES :param int restart: [default == 1000] restart constant for GMRES (nothing is implemented to retain information, i.e. Hessemberg and Krylov space are reset) :param float eps_round: [default == 1e-10] accuracy for Tensor Train rounding operations :param bool ext_info: [default == False] whehter of not to have additional info returned :return: tuple :py:data:`(x,conv,info)` * :py:data:`x` (TTvec): solution of the linear system if converged or last iterate if not converged * :py:data:`conv` (bool): True -> converged, False -> Not converged / Zero Inner Product exeception * :py:data:`info` (dict): ``iter`` -> total number of iterations; ``TT_r`` -> last residual in TT format; ``res`` -> norm of last residual; ``err`` -> residual history per iteration :note: not optimized for symmetric A """ logger = logging.getLogger(__name__) logger.propagate = False ch = logging.StreamHandler() formatter = logging.Formatter( "%(asctime)s %(levelname)s:%(name)s: %(message)s", "%Y-%m-%d %H:%M:%S") ch.setFormatter(formatter) logger.addHandler(ch) from TensorToolbox.core import TTvec, TTmat, zerosvec if not A.init or not b.init: raise NameError( "TensorToolbox.multilinalg.cg: TT not initialized correctly") if not (isinstance(A, TTmat) and isinstance(b, TTvec) and not isinstance(b, TTmat)): raise NameError( "TensorToolbox.multilinalg.cg: Conjugate gradient not implemented for the input types" ) if x0 == None: x0 = zerosvec(len(b.shape()), b.shape()) elif not isinstance(x0, TTvec) or b.shape() != x0.shape(): raise NameError( "TensorToolbox.multilinalg.cg: Initial guess must be in TT format and have the same shape of b" ) logger.info("GMRES: Starting") # Iterate x = x0.copy() counter = 0 j = restart err = [] while counter < maxit: if j == restart: if counter > 0: # Compute y_m: Solve y_m = H^-1 g_m y = npla.solve(H[:-1, :], g[:-1]) # Compute for i in range(restart): x += v[i] * y[i] x.rounding(eps_round) Q = np.eye(restart + 1) H = np.zeros((restart + 1, restart)) g = np.zeros((restart + 1)) r = (b - dot(A, x)).rounding(eps_round) g[0] = norm(r, 2) # beta v = [r * 1. / g[0]] j = 0 w = dot(A, v[j]).rounding(eps_round) for i in range(j + 1): H[i, j] = dot(w, v[i]) w -= v[i] * H[i, j] w.rounding(eps_round) H[j + 1, j] = norm(w, 2) if np.abs(H[j + 1, j]) < np.spacing(1): # lucky break break v.append(w * 1. / H[j + 1, j]) # Apply old givens rotations to the new column H[:j + 2, j] = np.dot(Q[:j + 2, :j + 2], H[:j + 2, j]) # New Givens rotation omega = np.eye((j + 2)) c = H[j, j] / np.sqrt(H[j, j]**2. + H[j + 1, j]**2.) s = H[j + 1, j] / np.sqrt(H[j, j]**2. + H[j + 1, j]**2.) omega[j, j] = c omega[j + 1, j + 1] = c omega[j, j + 1] = s omega[j + 1, j] = -s # Apply to the Q, H and g Q[:j + 2, :j + 2] = np.dot(omega, Q[:j + 2, :j + 2]) H[:j + 2, :j + 1] = np.dot(omega, H[:j + 2, :j + 1]) g[j + 1] = -s * g[j] g[j] *= c err.append(np.abs(g[j + 1])) if isinstance(x, TTvec): logger.info("GMRES: err=%e ranks=%s" % (err[-1], x.ranks())) elif isinstance(x, np.ndarray): logger.info("GMRES: err=%e" % (err[-1])) if err[-1] < eps: # convergent break break counter += 1 j += 1 conv = (counter < maxit) # Compute y_j: Solve H y_j = g_j y = npla.solve(H[:j + 1, :j + 1], g[:j + 1]) # Compute solution for i in range(j + 1): x += v[i] * y[i] x.rounding(eps_round) r = (b - dot(A, x)).rounding(eps_round) logger.info("GMRES: Done ") if ext_info: info = {'iter': counter, 'TT_r': r, 'res': norm(r, 2), 'err': err} return (x, conv, info) else: return (x, conv)
def cg(A, b, x0=None, eps=1e-8, maxit=1000, eps_round=1e-10, ext_info=False): """ Solves the system :math:`Ax=b` using the Conjugate Gradient method in Tensor Train format. :param TTmat A: Tensor train matrix :param TTvec/ndarray b: Right hand side :param TTvec/ndarray x0: [default == :py:func:`TensorToolbox.core.zerosvec`] initial guess of solution ``x`` :param float eps: [default == 1e-8] stop criteria for Bi-CGSTAB iterations :param int maxit: [default == 1000] maximum number of iterations for Bi-CGSTAB :param float eps_round: [default == 1e-10] accuracy for Tensor Train rounding operations :param bool ext_info: [default == False] whehter of not to have additional info returned :return: tuple :py:data:`(x,conv,info)` * :py:data:`x` (TTvec): solution of the linear system if converged or last iterate if not converged * :py:data:`conv` (bool): True -> converged, False -> Not converged / Zero Inner Product exeception * :py:data:`info` (dict): ``iter`` -> total number of iterations; ``r`` -> last residual in TT format; ``res`` -> residual history """ logger = logging.getLogger(__name__) logger.propagate = False ch = logging.StreamHandler() formatter = logging.Formatter( "%(asctime)s %(levelname)s:%(name)s: %(message)s", "%Y-%m-%d %H:%M:%S") ch.setFormatter(formatter) logger.addHandler(ch) from TensorToolbox.core import TTvec, TTmat, zerosvec if isinstance(A, TTmat): if not A.init: raise NameError( "TensorToolbox.multilinalg.cg: TT not initialized correctly") if isinstance(b, TTvec) and not isinstance(b, TTmat): is_tt = True elif isinstance(b, np.ndarray): is_tt = False else: raise NameError("TensorToolbox.multilinalg.cg: invalid type of b") if is_tt: if not b.init: raise NameError( "TensorToolbox.multilinalg.cg: TT not initialized correctly" ) if x0 == None: if is_tt: x0 = zerosvec(len(b.shape()), b.shape()) else: x0 = np.zeros(b.shape) else: if is_tt: if not isinstance(x0, TTvec) or b.shape() != x0.shape(): raise NameError( "TensorToolbox.multilinalg.cg: Initial guess must be in TT format and have the same shape of b" ) else: if not isinstance(x0, np.ndarray) or b.shape != x0.shape: raise NameError( "TensorToolbox.multilinalg.cg: Initial guess must be in ndarray format and have the same shape of b" ) # CG init x = x0 i = 0 r = (b - dot(A, x)) if is_tt: r.rounding(eps_round) d = r res = [dot(r, r)] delta_0 = res[-1] while i < maxit and res[-1] > eps: # * delta_0: q = dot(A, d) if is_tt: q.rounding(eps_round) alpha = res[-1] / dot(d, q) x += d * alpha if is_tt: x.rounding(eps_round) if i % 5 == 0: r = (b - dot(A, x)) if is_tt: r.rounding(eps_round) else: r -= q * alpha if is_tt: r.rounding(eps_round) delta_old = res[-1] res.append(dot(r, r)) beta = res[-1] / delta_old d *= beta d += r if is_tt: d.rounding(eps_round) if isinstance(x, TTvec): logger.info("CG: err=%e ranks=%s" % (res[-1], x.ranks())) elif isinstance(x, np.ndarray): logger.info("CG: err=%e " % (res[-1])) i += 1 conv = (i < maxit) if ext_info: info = {'iter': i, 'r': r, 'res': res} return (x, conv, info) else: return (x, conv) else: raise NameError( "TensorToolbox.multilinalg.cg: Conjugate gradient not implemented for the input types" )