1  """ 
   2  Implements several extended-ensemble Monte Carlo sampling algorithms. 
   3   
   4  Here is a short example which shows how to sample from a PDF using the replica 
   5  exchange with non-equilibrium switches (RENS) method. It draws 5000 samples from 
   6  a 1D normal distribution using the RENS algorithm working on three Markov chains 
   7  being generated by the HMC algorithm: 
   8   
   9   
  10      >>> import numpy 
  11      >>> from numpy import sqrt 
  12      >>> from csb.io.plots import Chart 
  13      >>> from csb.statistics.pdf import Normal 
  14      >>> from csb.statistics.samplers import State 
  15      >>> from csb.statistics.samplers.mc.multichain import ThermostattedMDRENSSwapParameterInfo 
  16      >>> from csb.statistics.samplers.mc.multichain import ThermostattedMDRENS, AlternatingAdjacentSwapScheme 
  17      >>> from csb.statistics.samplers.mc.singlechain import HMCSampler 
  18   
  19      >>> # Pick some initial state for the different Markov chains: 
  20      >>> initial_state = State(numpy.array([1.])) 
  21   
  22      >>> # Set standard deviations: 
  23      >>> std_devs = [1./sqrt(5), 1. / sqrt(3), 1.] 
  24   
  25      >>> # Set HMC timesteps and trajectory length: 
  26      >>> hmc_timesteps = [0.6, 0.7, 0.6] 
  27      >>> hmc_trajectory_length = 20 
  28      >>> hmc_gradients = [lambda q, t: 1 / (std_dev ** 2) * q for std_dev in std_devs] 
  29   
  30      >>> # Set parameters for the thermostatted RENS algorithm: 
  31      >>> rens_trajectory_length = 30 
  32      >>> rens_timesteps = [0.3, 0.5] 
  33   
  34      >>> # Set interpolation gradients as a function of the work parameter l: 
  35      >>> rens_gradients = [lambda q, l, i=i: (l / (std_devs[i + 1] ** 2) + (1 - l) / (std_devs[i] ** 2)) * q  
  36                            for i in range(len(std_devs)-1)] 
  37   
  38      >>> # Initialize HMC samplers: 
  39      >>> samplers = [HMCSampler(Normal(sigma=std_devs[i]), initial_state, hmc_gradients[i], hmc_timesteps[i], 
  40                      hmc_trajectory_length) for i in range(len(std_devs))] 
  41   
  42      >>> # Create swap parameter objects: 
  43      params = [ThermostattedMDRENSSwapParameterInfo(samplers[0], samplers[1], rens_timesteps[0], 
  44                rens_trajectory_length, rens_gradients[0]), 
  45                ThermostattedMDRENSSwapParameterInfo(samplers[1], samplers[2], rens_timesteps[1], 
  46                rens_trajectory_length, rens_gradients[1])] 
  47   
  48      >>> # Initialize thermostatted RENS algorithm: 
  49      >>> algorithm = ThermostattedMDRENS(samplers, params) 
  50   
  51      >>> # Initialize swapping scheme: 
  52      >>> swapper = AlternatingAdjacentSwapScheme(algorithm) 
  53   
  54      >>> # Initialize empty list which will store the samples: 
  55      >>> states = [] 
  56      >>> for i in range(5000): 
  57              if i % 5 == 0: 
  58                  swapper.swap_all() 
  59              states.append(algorithm.sample()) 
  60   
  61      >>> # Print acceptance rates: 
  62      >>> print('HMC acceptance rates:', [s.acceptance_rate for s in samplers]) 
  63      >>> print('swap acceptance rates:', algorithm.acceptance_rates) 
  64   
  65      >>> # Create and plot histogram for first sampler and numpy.random.normal reference: 
  66      >>> chart = Chart() 
  67      >>> rawstates = [state[0].position[0] for state in states] 
  68      >>> chart.plot.hist([numpy.random.normal(size=5000, scale=std_devs[0]), rawstates], bins=30, normed=True) 
  69      >>> chart.plot.legend(['numpy.random.normal', 'RENS + HMC']) 
  70      >>> chart.show() 
  71   
  72   
  73  For L{ReplicaExchangeMC} (RE), the procedure is easier because apart from the 
  74  two sampler instances the corresponding L{RESwapParameterInfo} objects take 
  75  no arguments. 
  76   
  77  Every replica exchange algorithm in this module (L{ReplicaExchangeMC}, L{MDRENS}, 
  78  L{ThermostattedMDRENS}) is used in a similar way. A simulation is always 
  79  initialized with a list of samplers (instances of classes derived from 
  80  L{AbstractSingleChainMC}) and a list of L{AbstractSwapParameterInfo} objects 
  81  suited for the algorithm under consideration. Every L{AbstractSwapParameterInfo} 
  82  object holds all the information needed to perform a swap between two samplers. 
  83  The usual scheme is to swap only adjacent replicae in a scheme:: 
  84   
  85      1 <--> 2, 3 <--> 4, ... 
  86      2 <--> 3, 4 <--> 5, ... 
  87      1 <--> 2, 3 <--> 4, ... 
  88       
  89  This swapping scheme is implemented in the L{AlternatingAdjacentSwapScheme} class, 
  90  but different schemes can be easily implemented by deriving from L{AbstractSwapScheme}. 
  91  Then the simulation is run by looping over the number of samples to be drawn 
  92  and calling the L{AbstractExchangeMC.sample} method of the algorithm. By calling 
  93  the L{AbstractSwapScheme.swap_all} method of the specific L{AbstractSwapScheme} 
  94  implementation, all swaps defined in the list of L{AbstractSwapParameterInfo} 
  95  objects are performed according to the swapping scheme. The 
  96  L{AbstractSwapScheme.swap_all} method may be called for example after sampling 
  97  intervals of a fixed length or randomly. 
  98  """ 
  99   
 100  import numpy 
 101   
 102  import csb.numeric 
 103   
 104  from abc import ABCMeta, abstractmethod 
 105   
 106  from csb.statistics.samplers import EnsembleState 
 107  from csb.statistics.samplers.mc import AbstractMC, Trajectory, MCCollection, augment_state 
 108  from csb.statistics.samplers.mc.propagators import MDPropagator, ThermostattedMDPropagator 
 109  from csb.statistics.samplers.mc.neqsteppropagator import NonequilibriumStepPropagator 
 110  from csb.statistics.samplers.mc.neqsteppropagator import Protocol, Step, ReducedHamiltonian 
 111  from csb.statistics.samplers.mc.neqsteppropagator import ReducedHamiltonianPerturbation 
 112  from csb.statistics.samplers.mc.neqsteppropagator import HMCPropagation, HMCPropagationParam 
 113  from csb.statistics.samplers.mc.neqsteppropagator import HamiltonianSysInfo, NonequilibriumTrajectory 
 114  from csb.numeric.integrators import AbstractGradient, FastLeapFrog 
 118      """ 
 119      Abstract class for Monte Carlo sampling algorithms simulating several ensembles. 
 120   
 121      @param samplers: samplers which sample from their respective equilibrium distributions 
 122      @type samplers: list of L{AbstractSingleChainMC}     
 123      """ 
 124   
 125      __metaclass__ = ABCMeta 
 126   
 133   
 145   
 146      @property 
 148          """ 
 149          Total ensemble energy. 
 150          """  
 151          return sum([x.energy for x in self._samplers]) 
   152   
 155      """ 
 156      Abstract class for Monte Carlo sampling algorithms employing some replica exchange method. 
 157   
 158      @param samplers: samplers which sample from their respective equilibrium distributions 
 159      @type samplers: list of L{AbstractSingleChainMC} 
 160   
 161      @param param_infos: list of ParameterInfo instances providing information needed 
 162          for performing swaps 
 163      @type param_infos: list of L{AbstractSwapParameterInfo} 
 164      """ 
 165   
 166      __metaclass__ = ABCMeta 
 167   
 168 -    def __init__(self, samplers, param_infos): 
  177           
 181   
 182 -    def swap(self, index): 
  183          """ 
 184          Perform swap between sampler pair described by param_infos[index] 
 185          and return outcome (true = accepted, false = rejected). 
 186   
 187          @param index: index of swap pair in param_infos 
 188          @type index: int 
 189   
 190          @rtype: boolean 
 191          """ 
 192          param_info = self._param_infos[index] 
 193          swapcom = self._propose_swap(param_info) 
 194          swapcom = self._calc_pacc_swap(swapcom) 
 195          result = self._accept_swap(swapcom) 
 196           
 197          self.state = EnsembleState([x.state for x in self._samplers]) 
 198   
 199          self.statistics.stats[index].update(result) 
 200           
 201          return result 
  202   
 203      @abstractmethod 
 205          """ 
 206          Calculate proposal states for a swap between two samplers. 
 207           
 208          @param param_info: ParameterInfo instance holding swap parameters 
 209          @type param_info: L{AbstractSwapParameterInfo} 
 210           
 211          @rtype: L{AbstractSwapCommunicator} 
 212          """  
 213          pass 
  214   
 215      @abstractmethod 
 217          """ 
 218          Calculate probability to accept a swap given initial and proposal states. 
 219   
 220          @param swapcom: SwapCommunicator instance holding information to be communicated 
 221                          between distinct swap substeps 
 222          @type swapcom: L{AbstractSwapCommunicator} 
 223   
 224          @rtype: L{AbstractSwapCommunicator} 
 225          """ 
 226          pass 
  227   
 249   
 250      @property 
 258   
 259      @property 
 261          """ 
 262          List of SwapParameterInfo instances holding all necessary parameters. 
 263   
 264          @rtype: list of L{AbstractSwapParameterInfo} 
 265          """ 
 266          return self._param_infos 
  267       
 268      @property 
 270          return self._statistics 
  271   
 273          """ 
 274          Update statistics of a given swap process. 
 275           
 276          @param index: position of swap statistics to be updated 
 277          @type index: int 
 278           
 279          @param accepted: outcome of the swap 
 280          @type accepted: boolean 
 281          """ 
 282           
 283          self._stats[index][0] += 1 
 284          self._stats[index][1] += int(accepted) 
   285   
 288      """ 
 289      Subclass instances hold all parameters necessary for performing a swap 
 290      between two given samplers. 
 291      """ 
 292   
 293      __metaclass__ = ABCMeta 
 294   
 295 -    def __init__(self, sampler1, sampler2): 
  296          """ 
 297          @param sampler1: First sampler 
 298          @type sampler1: L{AbstractSingleChainMC} 
 299   
 300          @param sampler2: Second sampler 
 301          @type sampler2: L{AbstractSingleChainMC} 
 302          """ 
 303   
 304          self._sampler1 = sampler1 
 305          self._sampler2 = sampler2 
  306   
 307      @property 
 309          return self._sampler1 
  310   
 311      @property 
 313          return self._sampler2 
   314   
 317      """ 
 318      Holds all the information which needs to be communicated between 
 319      distinct swap substeps. 
 320   
 321      @param param_info: ParameterInfo instance holding swap parameters 
 322      @type param_info: L{AbstractSwapParameterInfo} 
 323   
 324      @param traj12: Forward trajectory 
 325      @type traj12: L{Trajectory} 
 326   
 327      @param traj21: Reverse trajectory 
 328      @type traj21: L{Trajectory} 
 329      """ 
 330   
 331      __metaclass__ = ABCMeta 
 332       
 333 -    def __init__(self, param_info, traj12, traj21): 
  345           
 346      @property 
 348          return self._sampler1 
  349   
 350      @property 
 352          return self._sampler2 
  353       
 354      @property 
 357   
 358      @property 
 361   
 362      @property 
 364          return self._acceptance_probability 
  365      @acceptance_probability.setter 
 367          self._acceptance_probability = value 
  368   
 369      @property 
 371          return self._accepted 
  372      @accepted.setter 
 374          self._accepted = value 
  375   
 376      @property 
 378          return self._param_info 
   379   
 382      """ 
 383      Replica Exchange (RE, Swendsen & Yang 1986) implementation. 
 384      """ 
 385           
 392       
  413   
 416      """ 
 417      Holds parameters for a standard Replica Exchange swap. 
 418      """ 
 419      pass 
  420   
 423      """ 
 424      Holds all the information which needs to be communicated between distinct 
 425      RE swap substeps. 
 426   
 427      See L{AbstractSwapCommunicator} for constructor signature. 
 428      """ 
 429      pass 
  430   
 433      """ 
 434      Abstract Replica Exchange with Nonequilibrium Switches 
 435      (RENS, Ballard & Jarzynski 2009) class. 
 436      Subclasses implement various ways of generating trajectories 
 437      (deterministic or stochastic). 
 438      """ 
 439   
 440      __metaclass__ = ABCMeta 
 441   
 454   
 456          """ 
 457          Sets the protocol lambda(t) to either the forward or the reverse protocol. 
 458   
 459          @param traj_info: TrajectoryInfo object holding information neccessary to 
 460                            calculate the rens trajectories. 
 461          @type traj_info: L{RENSTrajInfo} 
 462          """ 
 463   
 464          if traj_info.direction == "fw": 
 465              return traj_info.param_info.protocol 
 466          else: 
 467              return lambda t, tau: traj_info.param_info.protocol(tau - t, tau) 
 468           
 469          return protocol 
  470   
 472          """ 
 473          Determine the initial temperature of a RENS trajectory. 
 474   
 475          @param traj_info: TrajectoryInfo object holding information neccessary to 
 476                            calculate the RENS trajectory. 
 477          @type traj_info: L{RENSTrajInfo} 
 478          """ 
 479           
 480          if traj_info.direction == "fw": 
 481              return traj_info.param_info.sampler1.temperature 
 482          else: 
 483              return traj_info.param_info.sampler2.temperature 
  484   
 485      @abstractmethod 
 487          """ 
 488          Calculates the works expended during the nonequilibrium 
 489          trajectories. 
 490   
 491          @param swapcom: Swap communicator object holding all the 
 492                          neccessary information. 
 493          @type swapcom: L{RENSSwapCommunicator} 
 494   
 495          @return: The expended during the forward and the backward 
 496                   trajectory. 
 497          @rtype: 2-tuple of floats 
 498          """ 
 499           
 500          pass 
  501   
 508   
 509      @abstractmethod 
 511          """ 
 512          Factory method which produces the propagator object used to calculate 
 513          the RENS trajectories. 
 514   
 515          @param traj_info: TrajectoryInfo object holding information neccessary to 
 516                            calculate the rens trajectories. 
 517          @type traj_info: L{RENSTrajInfo} 
 518          @rtype: L{AbstractPropagator} 
 519          """ 
 520          pass 
  521   
 523          """ 
 524          Run the trajectory generator which generates a trajectory 
 525          of a given length between the states of two samplers. 
 526   
 527          @param traj_info: TrajectoryInfo instance holding information 
 528                            needed to generate a nonequilibrium trajectory    
 529          @type traj_info: L{RENSTrajInfo} 
 530           
 531          @rtype: L{Trajectory} 
 532          """ 
 533   
 534          init_temperature = self._get_init_temperature(traj_info) 
 535           
 536          init_state = traj_info.init_state.clone() 
 537           
 538          if init_state.momentum is None: 
 539              init_state = augment_state(init_state, 
 540                                         init_temperature, 
 541                                         traj_info.param_info.mass_matrix) 
 542               
 543          gen = self._propagator_factory(traj_info) 
 544          traj = gen.generate(init_state, int(traj_info.param_info.traj_length)) 
 545           
 546          return traj 
   547   
 550      """ 
 551      Holds parameters for a RENS swap. 
 552      """ 
 553   
 554      __metaclass__ = ABCMeta 
 555   
 556 -    def __init__(self, sampler1, sampler2, protocol): 
  567   
 568      @property 
 570          """ 
 571          Switching protocol determining the time dependence 
 572          of the switching parameter. 
 573          """ 
 574          return self._protocol 
  575      @protocol.setter 
 577          self._protocol = value 
   578   
 581      """ 
 582      Holds all the information which needs to be communicated between distinct 
 583      RENS swap substeps. 
 584   
 585      See L{AbstractSwapCommunicator} for constructor signature. 
 586      """ 
 587       
 588      pass 
  589   
 592      """ 
 593      Holds information necessary for calculating a RENS trajectory. 
 594   
 595      @param param_info: ParameterInfo instance holding swap parameters 
 596      @type param_info: L{AbstractSwapParameterInfo} 
 597   
 598      @param init_state: state from which the trajectory is supposed to start 
 599      @type init_state: L{State} 
 600   
 601      @param direction: Either "fw" or "bw", indicating a forward or backward 
 602                        trajectory. This is neccessary to pick the protocol or 
 603                        the reversed protocol, respectively. 
 604      @type direction: string, either "fw" or "bw" 
 605      """ 
 606       
 607 -    def __init__(self, param_info, init_state, direction): 
  612           
 613      @property 
 615          return self._param_info 
  616   
 617      @property 
 619          return self._init_state 
  620   
 621      @property 
 623          return self._direction 
   624   
 625   
 626 -class MDRENS(AbstractRENS): 
  627      """ 
 628      Replica Exchange with Nonequilibrium Switches (RENS, Ballard & Jarzynski 2009) 
 629      with Molecular Dynamics (MD) trajectories. 
 630   
 631      @param samplers: Samplers which sample their 
 632                           respective equilibrium distributions 
 633      @type samplers: list of L{AbstractSingleChainMC} 
 634   
 635      @param param_infos: ParameterInfo instance holding 
 636                          information required to perform a MDRENS swap 
 637      @type param_infos: list of L{MDRENSSwapParameterInfo} 
 638   
 639      @param integrator: Subclass of L{AbstractIntegrator} to be used to 
 640                         calculate the non-equilibrium trajectories 
 641      @type integrator: type 
 642      """ 
 643   
 650   
 662   
  693   
 696      """ 
 697      Holds parameters for a MDRENS swap. 
 698   
 699      @param sampler1: First sampler 
 700      @type sampler1: L{AbstractSingleChainMC} 
 701   
 702      @param sampler2: Second sampler 
 703      @type sampler2: L{AbstractSingleChainMC} 
 704   
 705      @param timestep: Integration timestep 
 706      @type timestep: float 
 707   
 708      @param traj_length: Trajectory length in number of timesteps 
 709      @type traj_length: int 
 710   
 711      @param gradient: Gradient which determines the dynamics during a trajectory 
 712      @type gradient: L{AbstractGradient} 
 713       
 714      @param protocol: Switching protocol determining the time dependence of the 
 715                       switching parameter. It is a function M{f} taking the running 
 716                       time t and the switching time tau to yield a value in M{[0, 1]} 
 717                       with M{f(0, tau) = 0} and M{f(tau, tau) = 1}. Default is a linear 
 718                       protocol, which is being set manually due to an epydoc bug 
 719      @type protocol: callable 
 720       
 721      @param mass_matrix: Mass matrix 
 722      @type mass_matrix: n-dimensional matrix of type L{InvertibleMatrix} with n being the dimension 
 723                                 of the configuration space, that is, the dimension of 
 724                                 the position / momentum vectors 
 725      """ 
 726   
 727 -    def __init__(self, sampler1, sampler2, timestep, traj_length, gradient, 
 728                   protocol=None, mass_matrix=None): 
  748       
 749      @property 
 751          """ 
 752          Integration timestep. 
 753          """ 
 754          return self._timestep 
  755      @timestep.setter 
 757          self._timestep = float(value) 
  758   
 759      @property 
 761          """ 
 762          Trajectory length in number of integration steps. 
 763          """ 
 764          return self._traj_length 
  765      @traj_length.setter 
 767          self._traj_length = int(value) 
  768   
 769      @property 
 771          """ 
 772          Gradient which governs the equations of motion. 
 773          """ 
 774          return self._gradient 
  775   
 776      @property 
 778          return self._mass_matrix 
  779      @mass_matrix.setter 
 781          self._mass_matrix = value 
  782   
 783      @property 
 785          """ 
 786          Switching protocol determining the time dependence 
 787          of the switching parameter. 
 788          """ 
 789          return self._protocol 
  790      @protocol.setter 
 792          self._protocol = value 
   793   
 796      """ 
 797      Replica Exchange with Nonequilibrium Switches (RENS, Ballard & Jarzynski, 2009) 
 798      with Andersen-thermostatted Molecular Dynamics (MD) trajectories. 
 799   
 800      @param samplers: Samplers which sample their 
 801                           respective equilibrium distributions 
 802      @type samplers: list of L{AbstractSingleChainMC} 
 803   
 804      @param param_infos: ParameterInfo instance holding 
 805                          information required to perform a MDRENS swap 
 806      @type param_infos: list of L{ThermostattedMDRENSSwapParameterInfo} 
 807   
 808      @param integrator: Subclass of L{AbstractIntegrator} to be used to 
 809                         calculate the non-equilibrium trajectories 
 810      @type integrator: type 
 811      """ 
 812   
 816   
  834   
 836      """ 
 837      @param sampler1: First sampler 
 838      @type sampler1: subclass instance of L{AbstractSingleChainMC} 
 839   
 840      @param sampler2: Second sampler 
 841      @type sampler2: subclass instance of L{AbstractSingleChainMC} 
 842   
 843      @param timestep: Integration timestep 
 844      @type timestep: float 
 845   
 846      @param traj_length: Trajectory length in number of timesteps 
 847      @type traj_length: int 
 848   
 849      @param gradient: Gradient which determines the dynamics during a trajectory 
 850      @type gradient: subclass instance of L{AbstractGradient} 
 851   
 852      @param mass_matrix: Mass matrix 
 853      @type mass_matrix: n-dimensional L{InvertibleMatrix} with n being the dimension 
 854                         of the configuration space, that is, the dimension of 
 855                         the position / momentum vectors 
 856   
 857      @param protocol: Switching protocol determining the time dependence of the 
 858                       switching parameter. It is a function f taking the running 
 859                       time t and the switching time tau to yield a value in [0, 1] 
 860                       with f(0, tau) = 0 and f(tau, tau) = 1 
 861      @type protocol: callable 
 862   
 863      @param temperature: Temperature interpolation function. 
 864      @type temperature: Real-valued function mapping from [0,1] to R. 
 865          T(0) = temperature of the ensemble sampler1 samples from, T(1) = temperature 
 866          of the ensemble sampler2 samples from 
 867   
 868      @param collision_probability: Probability for a collision with the heatbath during one timestep 
 869      @type collision_probability: float 
 870   
 871      @param collision_interval: Interval during which collision may occur with probability 
 872          collision_probability 
 873      @type collision_interval: int 
 874      """ 
 875           
 876 -    def __init__(self, sampler1, sampler2, timestep, traj_length, gradient, mass_matrix=None, 
 877                   protocol=None, temperature=lambda l: 1.0, 
 878                   collision_probability=0.1, collision_interval=1): 
  890   
 891      @property 
 893          """ 
 894          Probability for a collision with the heatbath during one timestep. 
 895          """ 
 896          return self._collision_probability 
  897      @collision_probability.setter 
 899          self._collision_probability = float(value) 
  900   
 901      @property 
 903          """ 
 904          Interval during which collision may occur with probability 
 905          C{collision_probability}. 
 906          """ 
 907          return self._collision_interval 
  908      @collision_interval.setter 
 910          self._collision_interval = int(value) 
  911   
 912      @property 
 914          return self._temperature 
   915   
 918      """ 
 919      Replica Exchange with Nonequilibrium Switches (RENS, Ballard & Jarzynski 2009) 
 920      with stepwise trajectories as described in Nilmeier et al., "Nonequilibrium candidate 
 921      Monte Carlo is an efficient tool for equilibrium simulation", PNAS 2011. 
 922      The switching parameter dependence of the Hamiltonian is a linear interpolation 
 923      between the PDFs of the sampler objects,  
 924      M{H(S{lambda}) = H_2 * S{lambda} + (1 - S{lambda}) * H_1}. 
 925      The perturbation kernel is a thermodynamic perturbation and the propagation is subclass 
 926      responsibility. 
 927      Note that due to the linear interpolations between the two Hamiltonians, the 
 928      log-probability has to be evaluated four times per perturbation step which can be 
 929      costly. In this case it is advisable to define the intermediate log probabilities 
 930      in _run_traj_generator differently. 
 931   
 932      @param samplers: Samplers which sample their respective equilibrium distributions 
 933      @type samplers: list of L{AbstractSingleChainMC} 
 934   
 935      @param param_infos: ParameterInfo instances holding 
 936                          information required to perform a HMCStepRENS swaps 
 937      @type param_infos: list of L{AbstractSwapParameterInfo} 
 938      """ 
 939   
 940      __metaclass__ = ABCMeta 
 941   
 942 -    def __init__(self, samplers, param_infos): 
  947   
 948      @abstractmethod 
 950          """ 
 951          Set up the propagation steps using the information about the current system 
 952          setup and parameters from the SwapParameterInfo object. 
 953   
 954          @param im_sys_infos: Information about the intermediate system setups 
 955          @type im_sys_infos: List of L{AbstractSystemInfo} 
 956   
 957          @param param_info: SwapParameterInfo object containing parameters for the 
 958                             propagations like timesteps, trajectory lengths etc. 
 959          @type param_info: L{AbstractSwapParameterInfo} 
 960          """ 
 961           
 962          pass 
  963   
 964      @abstractmethod 
 966          """ 
 967          If needed, set im_sys_infos.hamiltonian.gradient. 
 968   
 969          @param im_sys_infos: Information about the intermediate system setups 
 970          @type im_sys_infos: List of L{AbstractSystemInfo} 
 971   
 972          @param param_info: SwapParameterInfo object containing parameters for the 
 973                             propagations like timesteps, trajectory lengths etc. 
 974          @type param_info: L{AbstractSwapParameterInfo} 
 975   
 976          @param t_prot: Switching protocol defining the time dependence of the switching 
 977                         parameter. 
 978          @type t_prot: callable 
 979          """ 
 980           
 981          pass 
  982   
1024   
1031   
 1042   
1045      """ 
1046      Replica Exchange with Nonequilibrium Switches (RENS, Ballard & Jarzynski 2009) 
1047      with stepwise trajectories as described in Nilmeier et al., "Nonequilibrium candidate 
1048      Monte Carlo is an efficient tool for equilibrium simulation", PNAS 2011. 
1049      The switching parameter dependence of the Hamiltonian is a linear interpolation 
1050      between the PDFs of the sampler objects,  
1051      M{H(S{lambda}) = H_2 * S{lambda} + (1 - S{lambda}) * H_1}. 
1052      The perturbation kernel is a thermodynamic perturbation and the propagation is done using HMC. 
1053   
1054      Note that due to the linear interpolations between the two Hamiltonians, the 
1055      log-probability and its gradient has to be evaluated four times per perturbation step which 
1056      can be costly. In this case it is advisable to define the intermediate log probabilities 
1057      in _run_traj_generator differently. 
1058   
1059      @param samplers: Samplers which sample their respective equilibrium distributions 
1060      @type samplers: list of L{AbstractSingleChainMC} 
1061   
1062      @param param_infos: ParameterInfo instances holding 
1063                          information required to perform a HMCStepRENS swaps 
1064      @type param_infos: list of L{HMCStepRENSSwapParameterInfo} 
1065      """ 
1066   
1067 -    def __init__(self, samplers, param_infos): 
 1070   
1071      @staticmethod 
1081   
1082      @staticmethod 
1097   
 1101   
1104      """ 
1105      Holds all required information for performing HMCStepRENS swaps. 
1106   
1107      @param sampler1: First sampler 
1108      @type sampler1: subclass instance of L{AbstractSingleChainMC} 
1109   
1110      @param sampler2: Second sampler 
1111      @type sampler2: subclass instance of L{AbstractSingleChainMC} 
1112   
1113      @param timestep: integration timestep 
1114      @type timestep: float 
1115   
1116      @param hmc_traj_length: HMC trajectory length 
1117      @type hmc_traj_length: int 
1118   
1119      @param hmc_iterations: number of HMC iterations in the propagation step 
1120      @type hmc_iterations: int 
1121   
1122      @param gradient: gradient governing the equations of motion, function of 
1123                       position array and switching protocol 
1124      @type gradient: callable 
1125       
1126      @param intermediate_steps: number of steps in the protocol; this is a discrete version 
1127                                 of the switching time in "continuous" RENS implementations 
1128      @type intermediate_steps: int 
1129   
1130      @param protocol: Switching protocol determining the time dependence of the 
1131                       switching parameter. It is a function f taking the running 
1132                       time t and the switching time tau to yield a value in [0, 1] 
1133                       with f(0, tau) = 0 and f(tau, tau) = 1 
1134      @type protocol: callable 
1135   
1136      @param mass_matrix: mass matrix for kinetic energy definition 
1137      @type mass_matrix: L{InvertibleMatrix} 
1138   
1139      @param integrator: Integration scheme to be utilized 
1140      @type integrator: l{AbstractIntegrator} 
1141      """ 
1142   
1143 -    def __init__(self, sampler1, sampler2, timestep, hmc_traj_length, hmc_iterations,  
1144                   gradient, intermediate_steps, parametrization=None, protocol=None, 
1145                   mass_matrix=None, integrator=FastLeapFrog): 
 1167       
1168      @property 
1170          """ 
1171          Integration timestep. 
1172          """ 
1173          return self._timestep 
 1174      @timestep.setter 
1176          self._timestep = float(value) 
 1177   
1178      @property 
1180          """ 
1181          HMC trajectory length in number of integration steps. 
1182          """ 
1183          return self._hmc_traj_length 
 1184      @hmc_traj_length.setter 
1186          self._hmc_traj_length = int(value) 
 1187   
1188      @property 
1190          """ 
1191          Gradient which governs the equations of motion. 
1192          """ 
1193          return self._gradient 
 1194      @gradient.setter 
1196          self._gradient = value 
 1197   
1198      @property 
1200          return self._mass_matrix 
 1201      @mass_matrix.setter 
1203          self._mass_matrix = value 
 1204   
1205      @property 
1207          return self._hmc_iterations 
 1208      @hmc_iterations.setter 
1210          self._hmc_iterations = value 
 1211   
1212      @property 
1215      @intermediate_steps.setter 
1218   
1219      @property 
1221          return self._integrator 
 1222      @integrator.setter 
1224          self._integrator = value 
  1225   
1228      """ 
1229      Provides the interface for classes defining schemes according to which swaps in 
1230      Replica Exchange-like simulations are performed. 
1231   
1232      @param algorithm: Exchange algorithm that performs the swaps 
1233      @type algorithm: L{AbstractExchangeMC} 
1234      """ 
1235   
1236      __metaclass__ = ABCMeta 
1237   
1239   
1240          self._algorithm = algorithm 
 1241   
1242      @abstractmethod 
1244          """ 
1245          Advises the Replica Exchange-like algorithm to perform swaps according to 
1246          the schedule defined here. 
1247          """ 
1248           
1249          pass 
  1250   
1253      """ 
1254      Provides a swapping scheme in which tries exchanges between neighbours only 
1255      following the scheme 1 <-> 2, 3 <-> 4, ... and after a sampling period 2 <-> 3, 4 <-> 5, ... 
1256   
1257      @param algorithm: Exchange algorithm that performs the swaps 
1258      @type algorithm: L{AbstractExchangeMC} 
1259      """ 
1260   
1262   
1263          super(AlternatingAdjacentSwapScheme, self).__init__(algorithm) 
1264           
1265          self._current_swap_list = None 
1266          self._swap_list1 = [] 
1267          self._swap_list2 = [] 
1268          self._create_swap_lists() 
 1269       
1271   
1272          if len(self._algorithm.param_infos) == 1: 
1273              self._swap_list1.append(0) 
1274              self._swap_list2.append(0) 
1275          else: 
1276              i = 0 
1277              while i < len(self._algorithm.param_infos): 
1278                  self._swap_list1.append(i) 
1279                  i += 2 
1280                   
1281              i = 1 
1282              while i < len(self._algorithm.param_infos): 
1283                  self._swap_list2.append(i) 
1284                  i += 2 
1285   
1286          self._current_swap_list = self._swap_list1 
 1287   
1289           
1290          for x in self._current_swap_list: 
1291              self._algorithm.swap(x) 
1292   
1293          if self._current_swap_list == self._swap_list1: 
1294              self._current_swap_list = self._swap_list2 
1295          else: 
1296              self._current_swap_list = self._swap_list1 
  1297   
1300      """ 
1301      Tracks swap statistics of a single sampler pair. 
1302   
1303      @param param_info: ParameterInfo instance holding swap parameters 
1304      @type param_info: L{AbstractSwapParameterInfo} 
1305      """ 
1306       
1308          self._total_swaps = 0 
1309          self._accepted_swaps = 0 
 1310   
1311      @property 
1313          return self._total_swaps 
 1314       
1315      @property 
1317          return self._accepted_swaps 
 1318       
1319      @property 
1321          """ 
1322          Acceptance rate of the sampler pair. 
1323          """ 
1324          if self.total_swaps > 0: 
1325              return float(self.accepted_swaps) / float(self.total_swaps) 
1326          else: 
1327              return 0. 
 1328   
1330          """ 
1331          Updates swap statistics. 
1332          """         
1333          self._total_swaps += 1 
1334          self._accepted_swaps += int(accepted) 
  1335   
1338      """ 
1339      Tracks swap statistics for an AbstractExchangeMC subclass instance. 
1340   
1341      @param param_infos: list of ParameterInfo instances providing information 
1342                          needed for performing swaps 
1343      @type param_infos: list of L{AbstractSwapParameterInfo} 
1344      """ 
1345       
1347          self._stats = [SingleSwapStatistics(x) for x in param_infos] 
 1348           
1349      @property 
1351          return tuple(self._stats) 
 1352   
1353      @property 
1355          """ 
1356          Returns acceptance rates for all swaps. 
1357          """         
1358          return [x.acceptance_rate for x in self._stats] 
 1359           
1362      """ 
1363      Produces interpolations for functions changed during non-equilibrium 
1364      trajectories. 
1365       
1366      @param protocol: protocol to be used to generate non-equilibrium trajectories 
1367      @type protocol: function mapping t to [0...1] for fixed tau 
1368      @param tau: switching time 
1369      @type tau: float     
1370      """ 
1371       
1379           
1380      @property 
1382          return self._protocol 
 1383      @protocol.setter 
1385          if not hasattr(value, '__call__'): 
1386              raise TypeError(value) 
1387          self._protocol = value 
 1388                       
1389      @property 
1392      @tau.setter 
1393 -    def tau(self, value): 
 1394          self._tau = float(value) 
 1395           
1397          """ 
1398          Create a gradient instance with according to given protocol 
1399          and switching time. 
1400           
1401          @param gradient: gradient with G(0) = G_1 and G(1) = G_2 
1402          @type gradient: callable     
1403          """ 
1404          return Gradient(gradient, self._protocol, self._tau) 
 1405       
1407          """ 
1408          Create a temperature function according to given protocol and 
1409          switching time. 
1410   
1411          @param temperature: temperature with T(0) = T_1 and T(1) = T_2 
1412          @type temperature: callable         
1413          """ 
1414          return lambda t: temperature(self.protocol(t, self.tau)) 
  1415           
1418       
1419 -    def __init__(self, gradient, protocol, tau): 
 1424       
1426          return self._gradient(q, self._protocol(t, self._tau)) 
  1427   
1428   
1429 -class ReplicaHistory(object): 
 1430      ''' 
1431      Replica history object, works with both RE and RENS for 
1432      the AlternatingAdjacentSwapScheme. 
1433   
1434      @param samples: list holding ensemble states 
1435      @type samples: list 
1436   
1437      @param swap_interval: interval with which swaps were attempted, e.g., 
1438                            5 means that every 5th regular MC step is replaced 
1439                            by a swap 
1440      @type swap_interval: int 
1441   
1442      @param first_swap: sample index of the first sample generated by a swap attempt. 
1443                         If None, the first RE sampled is assumed to have sample index 
1444                         swap_interval. If specified, it has to be greater than zero 
1445      @type first_swap: int 
1446      ''' 
1447       
1448 -    def __init__(self, samples, swap_interval, first_swap=None): 
 1449          self.samples = samples 
1450          self.swap_interval = swap_interval 
1451          if first_swap == None: 
1452              self.first_swap = swap_interval - 1 
1453          elif first_swap > 0: 
1454              self.first_swap = first_swap - 1 
1455          else: 
1456              raise(ValueError("Sample index of first swap has to be greater than zero!")) 
1457          self.n_replicas = len(samples[0]) 
 1458   
1459      @staticmethod 
1461          if x == 1: 
1462              return -1 
1463          if x == -1: 
1464              return 1 
 1465   
1466 -    def calculate_history(self, start_ensemble): 
 1467          ''' 
1468          Calculates the replica history of the first state of ensemble #start_ensemble. 
1469   
1470          @param start_ensemble: index of the ensemble to start at, zero-indexed 
1471          @type start_ensemble: int 
1472   
1473          @return: replica history as a list of ensemble indices 
1474          @rtype: list of ints 
1475          ''' 
1476           
1477          sample_counter = 0 
1478   
1479           
1480           
1481          if start_ensemble % 2 == 0: 
1482              direction = +1 
1483          else: 
1484              direction = -1 
1485   
1486           
1487           
1488          if start_ensemble % 2 == 0 and start_ensemble == self.n_replicas - 1: 
1489              direction = -1 
1490   
1491           
1492          history = [] 
1493   
1494           
1495          ens = start_ensemble 
1496           
1497          while sample_counter < len(self.samples): 
1498              if self.n_replicas == 2: 
1499                  if (sample_counter - self.first_swap - 1) % self.swap_interval == 0 and \ 
1500                     sample_counter >= self.first_swap: 
1501                       
1502                       
1503                      current_sample = self.samples[sample_counter][ens] 
1504   
1505                       
1506                      previous_sample = self.samples[sample_counter - 1][history[-1]] 
1507   
1508                       
1509                       
1510                       
1511                      swap_accepted = not numpy.all(current_sample.position ==  
1512                                                    previous_sample.position) 
1513   
1514                      if swap_accepted: 
1515                          if ens == 0: 
1516                              ens = 1 
1517                          else: 
1518                              ens = 0 
1519                      history.append(ens)                     
1520                  else: 
1521                      history.append(ens) 
1522   
1523              else: 
1524                   
1525                  if (sample_counter - self.first_swap - 1) % self.swap_interval == 0 and \ 
1526                     sample_counter >= self.first_swap: 
1527                       
1528                      current_sample = self.samples[sample_counter][ens] 
1529   
1530                       
1531                      previous_sample = self.samples[sample_counter - 1][ens] 
1532   
1533                       
1534                       
1535                       
1536                      swap_accepted = not numpy.all(current_sample.position == previous_sample.position) 
1537   
1538                      if swap_accepted: 
1539                          ens += direction 
1540                      else: 
1541                          if ens == self.n_replicas - 1: 
1542                               
1543                              direction = -1 
1544                          elif ens == 0: 
1545                               
1546                              direction = +1 
1547                          else: 
1548                               
1549                               
1550                              direction = self._change_direction(direction) 
1551   
1552                  history.append(ens) 
1553   
1554              sample_counter += 1 
1555   
1556          return history 
 1557   
1559          ''' 
1560          Calculates sequentially correlated trajectories projected on a specific ensemble. 
1561   
1562          @param ensemble: ensemble index of ensemble of interest, zero-indexed 
1563          @type ensemble: int 
1564   
1565          @return: list of Trajectory objects containg sequentially correlated trajectories 
1566          @rtype: list of L{Trajectory} objects. 
1567          ''' 
1568           
1569          trajectories = [] 
1570   
1571          for i in range(self.n_replicas): 
1572              history = self.calculate_history(i) 
1573              traj = [x[ensemble] for k, x in enumerate(self.samples) if history[k] == ensemble] 
1574              trajectories.append(Trajectory(traj)) 
1575   
1576          return trajectories 
 1577   
1579          ''' 
1580          Calculates sequentially correlated trajectories. 
1581   
1582          @return: list of Trajectory objects containg sequentially correlated trajectories 
1583          @rtype: list of L{Trajectory} objects. 
1584          ''' 
1585           
1586          trajectories = [] 
1587   
1588          for i in range(self.n_replicas): 
1589              history = self.calculate_history(i) 
1590              traj = [x[history[k]] for k, x in enumerate(self.samples)] 
1591              trajectories.append(Trajectory(traj)) 
1592   
1593          return trajectories 
  1594