Source code for convergence

"""
Module ``convergence.py`` is taking care of the convergence parameters for all
openMPS simulations.

Mapping for the dynamic simulations:

+-------------+---------+
| Method name | Integer |
+=============+=========+
| Krylov      | 0       |
+-------------+---------+
| TEBD_2      | 1       |
+-------------+---------+
| TEBD_4      | 2       |
+-------------+---------+
| TDVP_2      | 3       |
+-------------+---------+
| LRK_2       | 4       |
+-------------+---------+
| LRK_4       | 5       |
+-------------+---------+
| MPDO+ TEBD2 | 6       |
+-------------+---------+
| Expm, EDLib | 7       |
+-------------+---------+

"""
import numpy as np
from copy import deepcopy
import hashlib

__all__ = ['MPSConvParam', 'iMPSConvParam', 'KrylovConvParam', 'TEBDConvParam',
           'TDVPConvParam', 'LRKConvParam', 'MpdoplusConvParam',
           'FiniteTConvParam', 'ImagConvParam', 'MPDOConvParam']

[docs]class ConvParam(): """ Base class for the convergence parameters of all simulations of the MPSPyLib involving MPS. """
[docs] def AddModifiedConvergenceParameters(self, copywhich, modifywhich, whichparameters): """ Copy the parameters in element copywhich of the current MPSConvergenceParameters object and replace the parameters in modifywhich with the values in whichparameters. **Arguments** copywhich : integer Take these convergence parameters as basis and replace selected arguments before adding it to the list. Starts with 0. modifywhich : string or list key or keys of the dictionary with the convergence parameters. For possible keys see in the description of the class ``MPSConvergenceParameters`` whichparameters : single argument or list the new parameters for the convergence parameters. The length must match the length of `modifywhich`. The types must match the original argument types """ if(copywhich not in range(self.nconv)): raise Exception("Cannot access element " + str(copywhich) + " of the " + str(self.nconv) + "-element list of convergence parameters!") if(not isinstance(modifywhich, list)): modifywhich = [modifywhich] if(not isinstance(whichparameters, list)): whichparameters = [whichparameters] if(len(whichparameters) != len(modifywhich)): raise Exception("Lengths of convergence parameters to be changed" + " and changed values should be the same in" + " AddModifiedConvergenceParameters!") tmpdic = deepcopy(self.data[copywhich]) for i in range(len(whichparameters)): tmpdic[modifywhich[i]] = whichparameters[i] # Append, check and increase index (first check <==> python indexing) self.data.append(tmpdic) self.check(self.nconv) self.nconv += 1 return
[docs] def get_hash(self): """ Create a hash from the convergence parameters. Use the sorted keys for setting up the order. """ hstr = "" for ii in range(self.nconv): for key in sorted(self.data[ii].keys()): elem = self.data[ii][key] if(isinstance(elem, int)): hstr += '%16i'%elem elif(isinstance(elem, float)): hstr += '%30.15e'%elem else: hstr += str(elem) hh = hashlib.sha512() hh.update(str.encode(hstr)) return hh.hexdigest()
[docs] def write(self, filestub): """ Write out the data in the MPSConvergenceParameters object to the file object filehandle. Intended for internal use only. **Arguments** filestub : string filename where the information are written **Details** The order, line by line, in the file is the following: 1) Number of sets of convergence parameters 2) min_num_sweeps 3) max_num_sweeps 4) max_outer_sweeps 5) warmup_bond_dimension 6) max_bond_dimension 7) MaxnLanczosIterations 8) max_n_iMPS_iterations (dummy value) 9) warmup_tol 10) lanczos_tol 10) local_tol 11) variance_tol 12) 13) min_num_sweeps (of the next set) 14) ... """ fh = open(filestub, 'w') fh.write('%16i'%(self.nconv) + '\n') for ii in range(self.nconv): try: fh.write('%16i\n'%(self.data[ii]['min_num_sweeps'])) except KeyError: fh.write('%16i\n'%(0)) try: fh.write('%16i'%(self.data[ii]['max_num_sweeps']) + '\n') except KeyError: fh.write('%16i'%(0) + '\n') try: fh.write('%16i'%(self.data[ii]['max_outer_sweeps']) + '\n') except KeyError: fh.write('%16i'%(0) + '\n') try: fh.write('%16i'%(self.data[ii]['warmup_bond_dimension']) + '\n') except KeyError: fh.write('%16i'%(0) + '\n') try: fh.write('%16i'%(self.data[ii]['max_bond_dimension']) + '\n') except KeyError: fh.write('%16i'%(500) + '\n') try: fh.write('%16i'%(self.data[ii]['max_num_lanczos_iter']) + '\n') except KeyError: fh.write('%16i'%(0) + '\n') try: fh.write('%16i'%(self.data[ii]['max_num_imps_iter']) + '\n') except KeyError: fh.write('%16i'%(0) + '\n') try: fh.write('%30.15E'%(self.data[ii]['warmup_tol']) + '\n') except KeyError: fh.write('%30.15E'%(1.0) + '\n') try: fh.write('%30.15E'%(self.data[ii]['lanczos_tol']) + '\n') except KeyError: fh.write('%30.15E'%(0.0) + '\n') try: fh.write('%30.15E\n'%(self.data[ii]['local_tol'])) except KeyError: fh.write('%30.15E\n'%(0.0)) try: fh.write('%30.15E\n'%(self.data[ii]['variance_tol'])) except KeyError: fh.write('%30.15E\n'%(0.0)) # Dummies to be consistent with dynamics # hpsi_tol, hpsi_local_tol, psi_tol, psi_local_tol fh.write('%30.15E\n'%(0.0)) fh.write('%30.15E\n'%(0.0)) fh.write('%30.15E\n'%(0.0)) fh.write('%30.15E\n'%(0.0)) try: fh.write(self.data[ii]['method'] + '\n') except KeyError: fh.write('V\n') try: fh.write(self.data[ii]['tn_type'] + '\n') except KeyError: fh.write('D\n') try: fh.write('%16i\n'%(self.data[ii]['max_kappa'])) except KeyError: fh.write('%16i\n'%(500)) try: fh.write('%16i\n'%(self.data[ii]['max_num_isteps'])) except KeyError: fh.write('%16i\n'%(-1)) try: fh.write('%16i\n'%(self.data[ii]['steps_for_ijudge'])) except KeyError: fh.write('%16i\n'%(-1)) try: fh.write('%30.15E\n'%(self.data[ii]['idt'])) except KeyError: fh.write('%30.15E\n'%(0.01)) try: # False = 0, True = 1 fh.write('%16i\n'%(int(self.data[ii]['ktebd']))) except KeyError: fh.write('%16i\n'%(0)) # Error handling inside get_method fh.write('%16i\n'%(self.get_method(ii))) fh.close() return
[docs] def check(self, ii): """ Empty check. """ return
[docs] def get_method(self, ii=0): """ Return the integer specifying the method. **Arguments** ii : int Look in the ii-th set of convergence parameters. """ tmpdic = {'Krylov' : 0, 'TEBD2' : 1, 'TEBD4' : 2, 'TDVP' : 3, 'LRK2' : 4, 'LRK4' : 5} try: return tmpdic[self.data[ii]['imethod']] except: return -1
[docs]class MPSConvParam(ConvParam): """ Defines the convergence parameters for the static MPS algorithm for finite size systems. The following list contains all optional arguments for the algorithms, their meaning, and their default value. The variational algorithms, i.e., MPS and eMPS are controlled with the following arguments. +-----------------------+-------------------------------------+-----------+ | Parameter (MPS,eMPS) | Meaning | default | +=======================+=====================================+===========+ | variance_tol | Variance tolerance | 1e-10 | | | :math:`\epsilon_{\mathrm{v}}`. | | +-----------------------+-------------------------------------+-----------+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{\mathrm{max}}`. | | +-----------------------+-------------------------------------+-----------+ | local_tol | Local truncation tolerance | (-1)= var | | | :math:`\epsilon_{\mathrm{local}}`. | iance_tol | | | | / (4L) | +-----------------------+-------------------------------------+-----------+ | min_num_sweeps | The minimum number of inner sweeps. | 1 | +-----------------------+-------------------------------------+-----------+ | max_num_sweeps | The maximum number of inner sweeps. | 2 | +-----------------------+-------------------------------------+-----------+ | max_outer_sweeps | The maximum number of outer sweeps. | 3 | +-----------------------+-------------------------------------+-----------+ | lanczos_tol | The residual tolerance of the | 1e-12 | | | Lanczos iteration | | | | :math:`\epsilon_{\mathrm{l}}`. | | +-----------------------+-------------------------------------+-----------+ | max_num_lanczos_iter | The maximum number of | 100 | | | Lanczos iterations | | | | :math:`n_{\mathrm{l}}`. | | +-----------------------+-------------------------------------+-----------+ | method | Decides on the convergence method. | 'V' | | | Either variance ('V') or biggest | | | | difference of first singular values | | | | across all bipartitions ('S'). | | +-----------------------+-------------------------------------+-----------+ | warmup_bond_dimension | Maximum allowed bond dimension | 170 | | | :math:`\chi_{warmup}`. This is for | | | | the initial ansatz via iMPS. | | +-----------------------+-------------------------------------+-----------+ | warmup_tol | Local truncation tolerance | 1e-12 | | | :math:`\epsilon{\mathrm{warmup}}`. | | | | This is for the initial ansatz | | | | via iMPS. | | +-----------------------+-------------------------------------+-----------+ If you prefer to use imaginary time evolution, the following parameters are important (repeated ones are not inserted yet). +-----------------------+-------------------------------------+-----------+ | Parameter (initial) | Meaning | default | +=======================+=====================================+===========+ | max_num_isteps | Maximum number of steps in the | -1 | | | imaginary time evolution. This | | | | variable is used as switch for | | | | between variational search and | | | | imaginary time evolution. If | | | | negative, variational method is | | | | used. | | +-----------------------+-------------------------------------+-----------+ | steps_for_ijudge | Steps between checking convergence | 100 | | | criteria in imaginary time | | | | evolution. | | +-----------------------+-------------------------------------+-----------+ | idt | Size time step in imaginary time | 0.01 | | | evolution | | +-----------------------+-------------------------------------+-----------+ | imethod | Time evolution method for imaginary | ``TEBD2`` | | | time evolution. Options are TEBD2, | | | | TEBD4, or TDVP. Krylov, LRK2, and | | | | LRK4 not enabled. | | +-----------------------+-------------------------------------+-----------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters **Details** The convergence parameters for the initial ansatz via iMPS are only relevant in the first set of convergence parameters. This statement is valid for MPS (ground state) and eMPS (excited state) algorithm. The excited state search uses the iMPS warmup parameters to find the maximal energy state. """ def __init__(self, variance_tol=1e-10, max_bond_dimension=500, local_tol=-1, min_num_sweeps=1, max_num_sweeps=2, max_outer_sweeps=3, lanczos_tol=1e-12, max_num_lanczos_iter=100, warmup_bond_dimension=170, warmup_tol=1e-12, method='V', max_num_isteps=-1, steps_for_ijudge=100, idt=0.01, imethod='TEBD2'): self.data = [] self.nconv = 0 self.AddConvergenceParameters(variance_tol, max_bond_dimension, local_tol, min_num_sweeps, max_num_sweeps, max_outer_sweeps, lanczos_tol, max_num_lanczos_iter, warmup_bond_dimension, warmup_tol, method, max_num_isteps, steps_for_ijudge, idt, imethod) return
[docs] def AddConvergenceParameters(self, variance_tol=1e-10, max_bond_dimension=500, local_tol=-1, min_num_sweeps=1, max_num_sweeps=2, max_outer_sweeps=3, lanczos_tol=1e-12, max_num_lanczos_iter=100, warmup_bond_dimension=170, warmup_tol=1e-12, method='V', max_num_isteps=-1, steps_for_ijudge=100, idt=0.01, imethod='TEBD2'): """ Adding another set of convergence parameters iteratively executed after the previous one. For the optional arguments look into the table of :py:class:`MPSConvParam`. """ self.data.append({}) self.data[self.nconv]['variance_tol'] = variance_tol self.data[self.nconv]['max_bond_dimension'] = max_bond_dimension self.data[self.nconv]['local_tol'] = local_tol self.data[self.nconv]['min_num_sweeps'] = min_num_sweeps self.data[self.nconv]['max_num_sweeps'] = max_num_sweeps self.data[self.nconv]['max_outer_sweeps'] = max_outer_sweeps self.data[self.nconv]['lanczos_tol'] = lanczos_tol self.data[self.nconv]['max_num_lanczos_iter'] = max_num_lanczos_iter self.data[self.nconv]['warmup_bond_dimension'] = warmup_bond_dimension self.data[self.nconv]['warmup_tol'] = warmup_tol self.data[self.nconv]['method'] = method self.data[self.nconv]['max_num_isteps'] = max_num_isteps self.data[self.nconv]['steps_for_ijudge'] = steps_for_ijudge self.data[self.nconv]['idt'] = idt self.data[self.nconv]['imethod'] = imethod self.check(self.nconv) self.nconv += 1 return
[docs] def check(self, ii): """ Run some checks on ii-th convergent parameter. **Arguments** ii : int Check the ii-th set of convergence parameters. """ # Restrict warmup parameters self.data[ii]['warmup_bond_dimension'] = \ min(self.data[ii]['warmup_bond_dimension'], self.data[ii]['max_bond_dimension']) self.data[ii]['warmup_tol'] = min(self.data[ii]['warmup_tol'], self.data[ii]['variance_tol']) # Check sweeps if(self.data[ii]['min_num_sweeps'] > self.data[ii]['max_num_sweeps']): raise ValueError("Number of sweeps: min > max.") if(self.data[ii]['min_num_sweeps'] < 1): raise ValueError("min_number_sweeps: There must be at least 1.") if(self.data[ii]['max_outer_sweeps'] < 1): raise ValueError("max_outer_sweeps: There must be at least 1.") return
[docs]class MPDOConvParam(MPSConvParam): """ Defines the convergence parameters of a variational open system steady state search. """ def __init__(self, variance_tol=1e-10, max_bond_dimension=500, local_tol=-1, min_num_sweeps=1, max_num_sweeps=2, max_outer_sweeps=3, lanczos_tol=1e-12, max_num_lanczos_iter=100, warmup_bond_dimension=170, warmup_tol=1e-12, method='V', max_num_isteps=-1, steps_for_ijudge=100, idt=0.01, imethod='TEBD2'): self.data = [] self.nconv = 0 self.AddConvergenceParameters(variance_tol, max_bond_dimension, local_tol, min_num_sweeps, max_num_sweeps, max_outer_sweeps, lanczos_tol, max_num_lanczos_iter, warmup_bond_dimension, warmup_tol, method, max_num_isteps, steps_for_ijudge, idt, imethod) return
[docs] def AddConvergenceParameters(self, variance_tol=1e-10, max_bond_dimension=500, local_tol=-1, min_num_sweeps=1, max_num_sweeps=2, max_outer_sweeps=3, lanczos_tol=1e-12, max_num_lanczos_iter=100, warmup_bond_dimension=170, warmup_tol=1e-12, method='V', max_num_isteps=-1, steps_for_ijudge=100, idt=0.01, imethod='TEBD2'): """ Adding another set of convergence parameters iteratively executed after the previous one. For the optional arguments look into the table of :py:class:`MPSConvParam`. """ self.data.append({}) self.data[self.nconv]['variance_tol'] = variance_tol self.data[self.nconv]['max_bond_dimension'] = max_bond_dimension self.data[self.nconv]['local_tol'] = local_tol self.data[self.nconv]['min_num_sweeps'] = min_num_sweeps self.data[self.nconv]['max_num_sweeps'] = max_num_sweeps self.data[self.nconv]['max_outer_sweeps'] = max_outer_sweeps self.data[self.nconv]['lanczos_tol'] = lanczos_tol self.data[self.nconv]['max_num_lanczos_iter'] = max_num_lanczos_iter self.data[self.nconv]['warmup_bond_dimension'] = warmup_bond_dimension self.data[self.nconv]['warmup_tol'] = warmup_tol self.data[self.nconv]['method'] = method self.data[self.nconv]['max_num_isteps'] = max_num_isteps self.data[self.nconv]['steps_for_ijudge'] = steps_for_ijudge self.data[self.nconv]['idt'] = idt self.data[self.nconv]['imethod'] = imethod self.data[self.nconv]['tn_type'] = 'R' self.check(self.nconv) self.nconv += 1 return
[docs]class iMPSConvParam(ConvParam): """ Defines the convergence parameters for variational algorithm iMPS. The following list contains all optional arguments for the algorithm, their meaning, and their default values. +-----------------------+---------------------------------------+---------+ | Parameter (iMPS) | Meaning | default | +=======================+=======================================+=========+ | variance_tol | The orthogonality fidelity tolerance | 1e-12 | | | if the truncation error is zero. | | +-----------------------+---------------------------------------+---------+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{max}`. | | +-----------------------+---------------------------------------+---------+ | local_tol | Local truncation tolerance | 1e-12 | | | :math:`\epsilon_{\mathrm{local}}`. | | +-----------------------+---------------------------------------+---------+ | min_num_sweeps | Number of optimization sweeps | 1 | | | performed on unit cell. | | +-----------------------+---------------------------------------+---------+ | max_num_imps_iter | Maximum number of iMPS iterations. | 1000 | +-----------------------+---------------------------------------+---------+ | lanczos_tol | The residual tolerance of | 1e-12 | | | the Lanczos iteration | | | | :math:`\epsilon_{\mathrm{l}}`. | | +-----------------------+---------------------------------------+---------+ | max_num_lanczos_iter | The maximum number of Lanczos | 100 | | | iterations :math:`n_{\mathrm{l}}`. | | +-----------------------+---------------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters. """ def __init__(self, variance_tol=1e-12, max_bond_dimension=500, local_tol=1e-12, min_num_sweeps=1, max_num_imps_iter=1000, lanczos_tol=1e-12, max_num_lanczos_iter=100): self.data = [] self.nconv = 0 self.AddConvergenceParameters(variance_tol, max_bond_dimension, local_tol, min_num_sweeps, max_num_imps_iter, lanczos_tol, max_num_lanczos_iter) return
[docs] def AddConvergenceParameters(self, variance_tol=1e-12, max_bond_dimension=500, local_tol=1e-12, min_num_sweeps=1, max_num_imps_iter=1000, lanczos_tol=1e-12, max_num_lanczos_iter=100): """ Adding another set of convergence parameters iteratively executed after the previous one. For the optional arguments look into the table of :py:class:`MPSConvParam`. """ self.data.append({}) self.data[self.nconv]['variance_tol'] = variance_tol self.data[self.nconv]['max_bond_dimension'] = max_bond_dimension self.data[self.nconv]['local_tol'] = local_tol self.data[self.nconv]['min_num_sweeps'] = min_num_sweeps self.data[self.nconv]['max_num_imps_iter'] = max_num_imps_iter self.data[self.nconv]['lanczos_tol'] = lanczos_tol self.data[self.nconv]['max_num_lanczos_iter'] = max_num_lanczos_iter # Have to set something for initial guess self.data[self.nconv]['max_num_sweeps'] = 1 self.data[self.nconv]['max_outer_sweeps'] = 1 self.data[self.nconv]['warmup_tol'] = local_tol self.data[self.nconv]['warmup_bond_dimension'] = max_bond_dimension self.check(self.nconv) self.nconv += 1 return
[docs] def check(self, ii): """ Run some checks on ii-th convergent parameter. **Arguments** ii : int Check the ii-th set of convergence parameters. """ # Check sweeps if(self.data[ii]['min_num_sweeps'] < 1): raise ValueError("min_number_sweeps: There must be at least 1.") return
[docs]class FiniteTConvParam(ConvParam): """ Defines the convergence parameters for a finite temperature imaginary time evolution. The following list contains all optional arguments for the algorithm, their meaning and their default value. +-----------------------+-------------------------------------+-----------+ | Parameters | Meaning | default | +=======================+=====================================+===========+ | QL | Empty QuenchList object | required | +-----------------------+-------------------------------------+-----------+ | max_bond_dimension | Maximum allowed bond dimension | 100 | | | :math:`\chi_{\mathrm{max}}`. | | +-----------------------+-------------------------------------+-----------+ | local_tol | Local truncation tolerance | 1e-12 | | | :math:`\epsilon_{\mathrm{local}}`. | | +-----------------------+-------------------------------------+-----------+ | deltat | Time step of the imaginary time | 0.01 | | | evolution | | +-----------------------+-------------------------------------+-----------+ | start_temperature | First temperature to be measured | 1.0 | | | (highest temperature). | | +-----------------------+-------------------------------------+-----------+ | nmeas | Number of measurements including | 10 | | | Tstart and Tfinal. | | +-----------------------+-------------------------------------+-----------+ | final_temperature | Last temperature to be measured | 0.1 | | | (lowest temperature) | | +-----------------------+-------------------------------------+-----------+ | kb | Boltzmann constant | 1.0 | +-----------------------+-------------------------------------+-----------+ | tn_type | Choosing tensor network, MPDO is | 'D' | | | 'R' or LTPN ('L') | | +-----------------------+-------------------------------------+-----------+ | imethod | Time evolution method for imaginary | ``TDVP`` | | | time evolution. Options are TEBD2, | | | | TEBD4, TDVP, or Krylov. | | +-----------------------+-------------------------------------+-----------+ | Other key word | The convergence settings are passed | - | | arguments | to the corresponding class. | | +-----------------------+-------------------------------------+-----------+ **Variables** data : list list containing one dictionary containing a set of convergence parameters. nconv : int number of sets of convergence parameters (limited to 1). """ def __init__(self, QL, deltat=0.01, start_temperature=1.0, nmeas=10, final_temperature=0.1, tn_type='D', imethod='TEBD2', **kwargs): self.data = [{}] self.nconv = 1 self.data[0]['QL'] = QL self.QLset = False # Abuse other variables written anyway self.data[0]['deltat'] = deltat self.data[0]['Tstart'] = start_temperature self.data[0]['nmeas'] = nmeas self.data[0]['Tfinal'] = final_temperature self.data[0]['kb'] = 1.0 self.data[0]['tn_type'] = tn_type self.data[0]['imethod'] = imethod # All other arguments must be convergence parameters for # time evolution method self.data[0]['conv'] = kwargs self.check(0)
[docs] def AddModifiedConvergenceParameters(self, *args, **kwargs): """ Overwriting method. Not available for FiniteT. """ raise ValueError("Cannot add another set of convergence parameters " + "for finite-T evolutions.")
[docs] def get_nmeas(self): """ Return number of measurements. """ return self.data[0]['min_num_sweeps']
[docs] def get_Tgrid(self): """ Return the measured temperatures. """ return np.linspace(self.data[0]['Tstart'], self.data[0]['Tfinal'], self.data[0]['nmeas'])
[docs] def check(self, ii): """ Check if the final temperature is smaller than the first measured temperature. Further first time step should not shoot over the first measurement. """ Tstart = self.data[ii]['Tstart'] Tfinal = self.data[ii]['Tfinal'] if(Tstart < Tfinal): raise ValueError("Final temperature must be smaller than first " + "measured temperature.") Tonedt = 0.5 / self.data[ii]['kb'] / self.data[ii]['deltat'] if(Tonedt < Tstart): raise ValueError("Choose time step such that first measurement " + "is after one time step.") # To-do if(self.data[ii]['kb'] != 1.0): raise NotImplementedError("Cannot modify Boltzmann constant yet") return
[docs] def write(self, filestub): """ Write all files for a FiniteT time evolution. **Arguments** filestub : string filename where the information are written """ # That is a dummy probed for network type etc super(FiniteTConvParam, self).write(filestub) filestub_ = filestub.split('.dat')[0] if(not self.QLset): # Imaginary time time = 0.0 # Temperatures to be measures Tgrid = np.linspace(self.data[0]['Tstart'], self.data[0]['Tfinal'], self.data[0]['nmeas']) if(self.data[0]['imethod'] == 'TEBD2'): Conv = TEBDConvParam(tn_type=self.data[0]['tn_type'], order=2, **self.data[0]['conv']) elif(self.data[0]['imethod'] == 'TEBD4'): Conv = TEBDConvParam(tn_type=self.data[0]['tn_type'], order=4, **self.data[0]['conv']) elif(self.data[0]['imethod'] == 'TDVP'): Conv = TDVPConvParam(tn_type=self.data[0]['tn_type'], **self.data[0]['conv']) elif(self.data[0]['imethod'] == 'Krylov'): Conv = KrylovConvParam(tn_type=self.data[0]['tn_type'], **self.data[0]['conv']) else: raise ValueError('imethod "' + self.data[0]['imethod'] + '" not recognized.') for ii in range(Tgrid.shape[0]): ndt = 1.0 / (2 * Tgrid[ii] * self.data[0]['kb']) - time sfo = int(10 * ndt / self.data[0]['deltat']) self.data[0]['QL'].AddQuench([], ndt, self.data[0]['deltat'], [], ConvergenceParameters=Conv, stepsforoutput=sfo) time += ndt self.QLset = True # Now we can write the actual things: self.data[0]['QL'].write(filestub_) return
[docs]class ImagConvParam(ConvParam): """ Defines the convergence parameters for an imaginary time evolution. It is not meant to find the ground state (use variational search), but rather for checks or comparing to finite-T evolutions. +--------------------+-----------------------------------------+---------+ | Parameters | Meaning | default | +====================+=========================================+=========+ | max_bond_dimension | Maximum allowed bond dimension between | 100 | | | sites :math:`\chi_{\mathrm{max}}`. | | +--------------------+-----------------------------------------+---------+ | local_tol | Local truncation tolerance | 1e-12 | | | :math:`\epsilon_{\mathrm{local}}`. | | +--------------------+-----------------------------------------+---------+ | tolerance | Stop search if energy difference is | 1e-12 | | | below tolerance between two | | | | measurements. | | +--------------------+-----------------------------------------+---------+ | deltat | Time step for evolution | 0.01 | +--------------------+-----------------------------------------+---------+ | steps_meas | Steps between the measurements of | 10 | | | energy. | | +--------------------+-----------------------------------------+---------+ | max_num_steps | Maximal number of time steps. | 5000 | +--------------------+-----------------------------------------+---------+ **Variables** data : list list containing dictionaries with the set of convergence parameters. nconv : int number of sets of convergence parameters. """ def __init__(self, max_bond_dimension=100, local_tol=1e-12, tolerance=1e-12, deltat=0.01, steps_meas=10, max_num_steps=5000): self.data = [] self.nconv = 0 self.AddConvergenceParameters(max_bond_dimension, local_tol, tolerance, deltat, steps_meas, max_num_steps) return
[docs] def AddConvergenceParameters(self, max_bond_dimension=100, local_tol=1e-12, tolerance=1e-12, deltat=0.01, steps_meas=10, max_num_steps=5000): """ Adding another set of convergence parameters iteratively executed after the previous one. For the optional arguments look into the table of :py:class:`ImagConvParam`. """ self.data.append({}) self.data[self.nconv]['max_bond_dimension'] = max_bond_dimension self.data[self.nconv]['local_tol'] = local_tol self.data[self.nconv]['variance_tol'] = tolerance self.data[self.nconv]['warmup_tol'] = deltat self.data[self.nconv]['min_num_sweeps'] = steps_meas self.data[self.nconv]['max_outer_sweeps'] = max_num_steps self.data[self.nconv]['max_number_sweeps'] = -2 self.check(self.nconv) self.nconv += 1 return
[docs] def AddModifiedConvergenceParameters(self, *args, **kwargs): """ Overwriting method. Not available ImagConvParam due to dictionary keys. Use AddConvergenceParameters instead. """ raise ValueError("Add another set of convergence parameters with " + "AddModifiedConvergenceParameters.")
[docs]class DynConvParam(ConvParam): """ Base class for the convergence parameters of all time evolution methods. Overwrites methods from :py:class:`ConvParam`, which are never necessary for dynamic simulations. In addition it defines the write method for convergence parameters. """
[docs] def AddConvergenceParameters(self, *args, **kwargs): """ Overwriting default method not valid for time evolutions. """ raise ValueError("Cannot add another set of convergence parameters " + "for time evolutions.")
[docs] def AddModifiedConvergenceParameters(self, copywhich, modifywhich, whichparameters): """ Overwriting default method not valid for time evolutions. """ raise ValueError("Cannot add another set of modified convergence " + "parameters for time evolutions.")
[docs] def write(self, filestub): """ Write out the data in the KrylovConvergenceParameters object to the file object filehandle. Intended for internal use only. **Arguments** filestub : string filename for the Krylov convergence parameters **Details** The lines are written in this order: 1) Number of sets of convergence parameters (always 1) 2) min_num_sweeps 3) max_num_sweeps 4) max_outer_sweeps 5) warmup_bond_dimension (dummy) 6) max_bond_dimension 7) MaxnLanczosIterations 8) max_n_iMPS_iterations (dummy) 9) warmup_tol (dummy) 10) Hpsi_tol 11) Hlocal_tol 12) psi_tol 13) psilocal_tol 14) lanczos_tol """ if(self.nconv != 1): raise ValueError("Only nconv=1 allowed in Krylov.") fh = open(filestub, 'w') fh.write('%16i\n'%(1)) try: fh.write('%16i\n'%(self.data[0]['min_num_sweeps'])) except KeyError: fh.write('%16i\n'%(0)) try: fh.write('%16i\n'%(self.data[0]['max_num_sweeps'])) except KeyError: fh.write('%16i\n'%(0)) try: fh.write('%16i\n'%(self.data[0]['max_outer_sweeps'])) except KeyError: fh.write('%16i\n'%(0)) # Bond dimension (warmup is dummy for interface) fh.write('%16i\n'%(0)) fh.write('%16i\n'%(self.data[0]['max_bond_dimension'])) try: fh.write('%16i\n'%(self.data[0]['max_num_lanczos_iter'])) except KeyError: fh.write('%16i\n'%(100)) # Dummy for interface: max_n_iMPS_iterations, warmup_tol fh.write('%16i\n'%(0)) fh.write('%30.15E\n'%(0.0)) try: fh.write('%30.15E'%(self.data[0]['lanczos_tol']) + '\n') except KeyError: fh.write('%30.15E'%(1e-12) + '\n') # Two more dummies (local_tol, variance_tol) fh.write('%30.15E\n'%(0.0)) fh.write('%30.15E\n'%(0.0)) try: fh.write('%30.15E'%(self.data[0]['hpsi_tol']) + '\n') except KeyError: fh.write('%30.15E'%(0.0) + '\n') try: fh.write('%30.15E'%(self.data[0]['hpsi_local_tol']) + '\n') except KeyError: fh.write('%30.15E'%(0.0) + '\n') try: fh.write('%30.15E'%(self.data[0]['psi_tol']) + '\n') except KeyError: fh.write('%30.15E'%(1e-10) + '\n') try: fh.write('%30.15E'%(self.data[0]['psi_local_tol']) + '\n') except KeyError: fh.write('%30.15E'%(-1.0) + '\n') fh.write(str(self.data[0]['methodsmap']) + '\n') try: fh.write(self.data[0]['tn_type'] + '\n') except KeyError: fh.write('D\n') try: fh.write('%16i\n'%(self.data[0]['max_kappa'])) except KeyError: fh.write('%16i\n'%(500)) try: fh.write('%16i\n'%(self.data[0]['max_num_isteps'])) except KeyError: fh.write('%16i\n'%(-1)) try: fh.write('%16i\n'%(self.data[0]['steps_for_ijudge'])) except KeyError: fh.write('%16i\n'%(-1)) try: fh.write('%30.15E\n'%(self.data[0]['idt'])) except KeyError: fh.write('%30.15E\n'%(0.01)) try: # False = 0, True = 1 fh.write('%16i\n'%(int(self.data[0]['ktebd']))) except KeyError: fh.write('%16i\n'%(0)) # Error handling inside get_method fh.write('%16i\n'%(self.get_method())) fh.close() return
[docs] def get_TO(self): """ Return time ordering or default value for it. """ try: return self.data[0]['timeordering'] except KeyError: return '2'
[docs] def get_method(self): """ Return the integer specifying the method. """ try: return self.data[0]['methodsmap'] except: return -1
[docs]class KrylovConvParam(DynConvParam): """ Defines the convergence parameters for the Krylov time evolution. The following list contains all optional arguments, their meaning and their default value. +-----------------------+---------------------------------------+---------+ | Parameter (Krylov) | Meaning | default | +=======================+=======================================+=========+ | psi_tol | Tolerance | 1e-10 | | | :math:`\epsilon_{\mathrm{\psi}}` for | | | | fitting states. | | +-----------------------+---------------------------------------+---------+ | hpsi_tol | Tolerance | 1e-10 | | | :math:`\epsilon_{\mathrm{H}}` for | | | | fitting operators to states. | | +-----------------------+---------------------------------------+---------+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{max}`. | | +-----------------------+---------------------------------------+---------+ | psi_local_tol | Local truncation tolerance | -1 = | | | :math:`\epsilon_{\psi\mathrm{local}}` | psi_tol | | | for fitting states. | / (4L) | +-----------------------+---------------------------------------+---------+ | hpsi_local_tol | Local truncation tolerance | -1 | | | :math:`\epsilon_{\mathrm{Hlocal}}` | Hpsi_tol| | | for fitting operators to states | / (4L) | +-----------------------+---------------------------------------+---------+ | min_num_sweeps | Minimum number of optimization sweeps | 1 | +-----------------------+---------------------------------------+---------+ | max_num_sweeps | Maximum number of optimization sweeps | 6 | +-----------------------+---------------------------------------+---------+ | max_outer_sweeps | TBA | 3 | +-----------------------+---------------------------------------+---------+ | lanczos_tol | The residual tolerance of the Lanczos | 1e-12 | | | iteration :math:`\epsilon_1`. | | +-----------------------+---------------------------------------+---------+ | max_num_lanczos_iter | The maximum number of Lanczos | 100 | | | iterations :math:`n_1`. | | +-----------------------+---------------------------------------+---------+ | timeordering | the order (in \delta t) of the | '2' | | | commutator-free Magnus expansion used | (str) | | | for time ordering. Can be '2' which | | | | is one exponential, '4_2' or '4_3', | | | | which are fourth-order with 2 or 3 | | | | exponentials, or '6', which is | | | | sixth-order with 5 exponentials. | | +-----------------------+---------------------------------------+---------+ | edlibmode | Defines method for ED library within | -1 | | | OSMPS: automatic (-1), built-in | | | | scipy with complete operator (0), | | | | EDLib Krylov with complete operator | | | | (1), EDLib Krylov with MPO | v > (2), | | | | EDLib Krylov with MPO and saving | | | | Krylov vectors to hard disk (3) | | | | (No effect on tensor network methods) | | +-----------------------+---------------------------------------+---------+ | tn_type | Type of the tensor network. Either | 'D' | | | 'D' for default, 'M' for MPS, 'Q' | | | | for quantum trajectories with MPS, | | | | 'R' for MPDO, or 'L' for LPTN. The | | | | default setting depends on the MPO. | | +-----------------------+---------------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters. Limited to 1. """ def __init__(self, psi_tol=1e-10, hpsi_tol=1e-10, max_bond_dimension=500, psi_local_tol=-1, hpsi_local_tol=-1, min_num_sweeps=1, max_num_sweeps=6, max_outer_sweeps=3, lanczos_tol=1e-12, max_num_lanczos_iter=100, timeordering='2', tn_type='D', edlibmode=-1): self.data = [{}] self.data[0]['psi_tol'] = psi_tol self.data[0]['hpsi_tol'] = hpsi_tol self.data[0]['max_bond_dimension'] = max_bond_dimension self.data[0]['psi_local_tol'] = psi_local_tol self.data[0]['hpsi_local_tol'] = hpsi_local_tol self.data[0]['min_num_sweeps'] = min_num_sweeps self.data[0]['max_num_sweeps'] = max_num_sweeps self.data[0]['max_outer_sweeps'] = max_outer_sweeps self.data[0]['lanczos_tol'] = lanczos_tol self.data[0]['max_num_lanczos_iter'] = max_num_lanczos_iter self.data[0]['timeordering'] = timeordering self.data[0]['tn_type'] = tn_type self.check(0) self.nconv = 1 # Method integer for krylov is always 0 self.data[0]['methodsmap'] = 0 # For EDLib only self.data[0]['edlibmode'] = edlibmode return
[docs] def check(self, ii): """ Run some checks on ii-th convergent parameter. **Arguments** ii : int ii-th entry of the list is checked, since time evolution ii = 0. """ # Check sweeps if(self.data[ii]['min_num_sweeps'] > self.data[ii]['max_num_sweeps']): raise ValueError("Number of sweeps: min > max.") if(self.data[ii]['min_num_sweeps'] < 1): raise ValueError("min_number_sweeps: There must be at least 1.") if(self.data[ii]['max_outer_sweeps'] < 1): raise ValueError("max_outer_sweeps: There must be at least 1.") if(not self.data[ii]['timeordering'] in ['2','4_2','4_3','6']): raise ValueError('Time ordering not valid.') return
[docs]class TEBDConvParam(DynConvParam): """ Defines the convergence parameter for time evolution with TEBD methods. The following list contains all optional arguments, their meaning, and their default values. +-----------------------+---------------------------------------+---------+ | Parameter (TEBD) | Meaning | default | +=======================+=======================================+=========+ | psi_tol | Tolerance | 1e-10 | | | :math:`\epsilon_{\mathrm{\psi}}` for | | | | splitting states via an SVD if | | | | psi_local_tol < 0. Then divided by | | | | 4 L | | +-----------------------+---------------------------------------+---------+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{max}`. | | +-----------------------+---------------------------------------+---------+ | psi_local_tol | Local truncation tolerance | -1 = | | | :math:`\epsilon_{\psi\mathrm{local}}` | psi_tol | | | for fitting states. | / (4L) | +-----------------------+---------------------------------------+---------+ | lanczos_tol | The residual tolerance of the Lanczos | 1e-12 | | | iteration :math:`\epsilon_1`. | | +-----------------------+---------------------------------------+---------+ | max_num_lanczos_iter | The maximum number of Lanczos | 100 | | | iterations :math:`n_1`. | | +-----------------------+---------------------------------------+---------+ | order | Order of the Trotter decomposition | 4 | | | can be 2 or 4. | | +-----------------------+---------------------------------------+---------+ | timeordering | the order (in \delta t) of the | '2' | | | commutator-free Magnus expansion used | (str) | | | for time ordering. Can be '2' which | | | | is one exponential, '4_2' or '4_3', | | | | which are fourth-order with 2 or 3 | | | | exponentials, or '6', which is | | | | sixth-order with 5 exponentials. | | +-----------------------+---------------------------------------+---------+ | tn_type | Type of the tensor network. Either | 'D' | | | 'D' for default, 'M' for MPS, 'Q' | | | | for quantum trajectories with MPS, | | | | 'R' for MPDO, or 'L' for LPTN. The | | | | default setting depends on the MPO. | | +-----------------------+---------------------------------------+---------+ | max_kappa | For LPTN only : the maximal bond | 500 | | | dimension between :math:`X` and | | | | :math:`X^{\dagger}` on each site, | | | | where the density matrix is | | | | :math:`X X^{\dagger}`. | | +-----------------------+---------------------------------------+---------+ | ktebd | Switch to use local Krylov (True). | False | | | If false, matrix exponential is used | | +-----------------------+---------------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters """ def __init__(self, psi_tol=1e-10, max_bond_dimension=500, psi_local_tol=-1, lanczos_tol=1e-12, max_num_lanczos_iter=100, order=4, timeordering='2', tn_type='D', max_kappa=500, ktebd=False): self.data = [{}] self.data[0]['psi_tol'] = psi_tol self.data[0]['max_bond_dimension'] = max_bond_dimension self.data[0]['psi_local_tol'] = psi_local_tol self.data[0]['lanczos_tol'] = lanczos_tol self.data[0]['max_num_lanczos_iter'] = max_num_lanczos_iter self.data[0]['order'] = order self.data[0]['timeordering'] = timeordering self.data[0]['tn_type'] = tn_type self.data[0]['max_kappa'] = max_kappa self.data[0]['ktebd'] = ktebd self.check(0) self.nconv = 1 # Method integer for TEBD is either 1 or 2 self.data[0]['methodsmap'] = 1 if(order == 2) else 2 return
[docs] def check(self, ii): """ Run some checks on ii-th convergent parameter. **Arguments** ii : int ii-th entry of the list is checked, since time evolution ii = 0. """ if(not self.data[ii]['order'] in [2, 4]): raise ValueError("Order of Trotter decomposition has to be " + "either 2 or 4.") return
[docs]class TDVPConvParam(DynConvParam): """ Defining the convergence parameter for time evolution with TDVP method. The following list contains all optional arguments for the algorithm, their meaning, and their default values +-----------------------+---------------------------------------+---------+ | Parameter (TDVP) | Meaning | default | +=======================+=======================================+=========+ | psi_tol | Tolerance | 1e-10 | | | :math:`\epsilon_{\mathrm{\psi}}` for | | | | fitting states. | | +-----------------------+---------------------------------------+---------+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{max}`. | | +-----------------------+---------------------------------------+---------+ | psi_local_tol | Local truncation tolerance | -1 = | | | :math:`\epsilon_{\psi\mathrm{local}}` | psi_tol | | | for fitting states. | / (4L) | +-----------------------+---------------------------------------+---------+ | lanczos_tol | The residual tolerance of the Lanczos | 1e-12 | | | iteration :math:`\epsilon_1`. | | +-----------------------+---------------------------------------+---------+ | max_num_lanczos_iter | The maximum number of Lanczos | 100 | | | iterations :math:`n_1`. | | +-----------------------+---------------------------------------+---------+ | timeordering | the order (in \delta t) of the | '2' | | | commutator-free Magnus expansion used | (str) | | | for time ordering. Can be '2' which | | | | is one exponential, '4_2' or '4_3', | | | | which are fourth-order with 2 or 3 | | | | exponentials, or '6', which is | | | | sixth-order with 5 exponentials. | | +-----------------------+---------------------------------------+---------+ | tn_type | Type of the tensor network. Either | 'D' | | | 'D' for default, 'M' for MPS, 'Q' | | | | for quantum trajectories with MPS, | | | | 'R' for MPDO, or 'L' for LPTN. The | | | | default setting depends on the MPO. | | +-----------------------+---------------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters """ def __init__(self, psi_tol=1e-10, max_bond_dimension=500, psi_local_tol=-1, lanczos_tol=1e-12, max_num_lanczos_iter=100, timeordering='2', tn_type='D'): self.data = [{}] self.data[0]['psi_tol'] = psi_tol self.data[0]['max_bond_dimension'] = max_bond_dimension self.data[0]['psi_local_tol'] = psi_local_tol self.data[0]['lanczos_tol'] = lanczos_tol self.data[0]['max_num_lanczos_iter'] = max_num_lanczos_iter self.data[0]['timeordering'] = timeordering self.data[0]['tn_type'] = tn_type self.check(0) self.nconv = 1 # Method integer for TDVP is always 3 self.data[0]['methodsmap'] = 3 return
[docs]class LRKConvParam(DynConvParam): """ Defines the convergence parameter for time evolution with LRK method. The following list contains all optioinal arguments for the algorithms, their meaning, and their default value. +-----------------------+---------------------------------------+---------+ | Parameter (LRK) | Meaning | default | +=======================+=======================================+=========+ | max_bond_dimension | Maximum allowed bond dimension | 500 | | | :math:`\chi_{max}`. | | +-----------------------+---------------------------------------+---------+ | hpsi_tol | Tolerance for fitting operators to | 1e-10 | | | states :math:`\epsilon_{\mathrm{H}}` | | +-----------------------+---------------------------------------+---------+ | hpsi_local_tol | Local truncation tolerance | -1 | | | :math:`\epsilon_{\mathrm{Hlocal}}` | Hpsi_tol| | | for fitting operators to states | / (4L) | +-----------------------+---------------------------------------+---------+ | min_num_sweeps | Minimum number of optimization sweeps | 1 | +-----------------------+---------------------------------------+---------+ | max_num_sweeps | Maximum number of optimization sweeps | 6 | +-----------------------+---------------------------------------+---------+ | max_outer_sweeps | TBA | 3 | +-----------------------+---------------------------------------+---------+ | order | Order can be 2 or 4 | 4 | +-----------------------+---------------------------------------+---------+ | timeordering | the order (in \delta t) of the | '2' | | | commutator-free Magnus expansion used | (str) | | | for time ordering. Can be '2' which | | | | is one exponential, '4_2' or '4_3', | | | | which are fourth-order with 2 or 3 | | | | exponentials, or '6', which is | | | | sixth-order with 5 exponentials. | | +-----------------------+---------------------------------------+---------+ | tn_type | Type of the tensor network. Either | 'D' | | | 'D' for default, 'M' for MPS, 'Q' | | | | for quantum trajectories with MPS, | | | | 'R' for MPDO, or 'L' for LPTN. The | | | | default setting depends on the MPO. | | +-----------------------+---------------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters """ def __init__(self, max_bond_dimension=500, hpsi_tol=1e-10, hpsi_local_tol=-1, min_num_sweeps=1, max_num_sweeps=6, max_outer_sweeps=3, order=4, timeordering='2', tn_type='D'): self.data = [{}] self.data[0]['max_bond_dimension'] = max_bond_dimension self.data[0]['hpsi_tol'] = hpsi_tol self.data[0]['hpsi_local_tol'] = hpsi_local_tol self.data[0]['min_num_sweeps'] = min_num_sweeps self.data[0]['max_num_sweeps'] = max_num_sweeps self.data[0]['max_outer_sweeps'] = max_outer_sweeps self.data[0]['order'] = order self.data[0]['timeordering'] = timeordering self.data[0]['tn_type'] = tn_type self.check(0) self.nconv = 1 # Method integer for LRK is either 4 or 5 self.data[0]['methodsmap'] = 4 if(order == 2) else 5 return
[docs] def check(self, ii): """ Run some checks on ii-th convergent parameter. **Arguments** ii : int ii-th entry of the list is checked, since time evolution ii = 0. """ if(self.data[0]['tn_type'] == 'Q'): # LRK introduces a small error in the norm for Hamiltonians print('Warning : quantum trajectories are not recommanded with LRK.') return
[docs]class MpdoplusConvParam(DynConvParam): """ Defines the convergence parameter for the time evolution with TEBD methods for open systems using MPDO+. The following list contains all optional arguments, their meaning, and their default values. +----------------------------+-----------------------------------+---------+ | Parameter (TEBD for MPDO+) | Meaning | default | +============================+===================================+=========+ | max_bond_dimension | Maximum allowed bond dimension | 40 | | | between sites :math:`\chi_{max}`. | | +----------------------------+-----------------------------------+---------+ | max_kraus_dimension | Maximum allowed bond dimension | 20 | | | between layers. | | +----------------------------+-----------------------------------+---------+ | local_bond_tol | Local truncation tolerance | 1e-8 | | | between sites. | | +----------------------------+-----------------------------------+---------+ | local_kraus_tol | Local truncation tolerance | 1e-8 | | | between layers. | | +----------------------------+-----------------------------------+---------+ **Variables** data : list list of dictionaries where each dictionary contains one set of convergence parameters nconv : int number of sets of convergence parameters. Limited to 1. """ def __init__(self, max_bond_dimension=40, max_kraus_dimension=20, local_bond_tol=1e-8, local_kraus_tol=1e-8): self.data = [{}] self.data[0]['max_bond_dimension'] = max_bond_dimension # Abuse other flags written anyway self.data[0]['max_outer_sweeps'] = max_kraus_dimension self.data[0]['psi_local_tol'] = local_bond_tol self.data[0]['hpsi_local_tol'] = local_kraus_tol self.check(0) self.nconv = 1 # Method integer for MPDO+ TEBD is right now always 6 self.data[0]['methodsmap'] = 6 return
[docs]class ExpmConvParam(DynConvParam): """ This class purely used in the EDLib part of OSMPS, specifies to use the matrix exponential as time evolution method. """ def __init__(self): self.data = [{}] self.nconv = 1 # Set some flags necessary within this framework self.data[0]['methodsmap'] = 7 self.data[0]['max_bond_dimension'] = 1