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