def binary_mse_multinomial(repeats, niterations, f_range, beta, nstates=2): """ Function to compute the mean-squared error of the SAMS binary update scheme when drawing samples from the multinomial distribution. Over many repeats, target free energies will be drawn randomly and uniformly from a specified range and SAMS will adapt to those free energies. Parameters ---------- repeats: int The number of repeats with which to draw target free energies and run SAMS ninterations: The number of state samples generated and SAMS adaptive steps f_range: float The interval over which target free energies will be drawn beta: float The exponent for the SAMS burn-in stage nstates: int The number of states and target free energies. """ binary_aggregate_msd = np.zeros((repeats, niterations)) for r in range(repeats): f_true = np.random.uniform(low=-f_range / 2.0, high=f_range / 2.0, size=nstates) f_true -= f_true[0] generator = IndependentMultinomialSamper(free_energies=f_true) adaptor = SAMSAdaptor(nstates=nstates, beta=beta) for i in range(niterations): noisy = generator.step() state = np.where(noisy != 0)[0][0] z = -adaptor.update(state=state, noisy_observation=noisy, histogram=generator.histogram) generator.zetas = z binary_aggregate_msd[r, i] = np.mean((f_true - z) ** 2) return binary_aggregate_msd
def test_slow_gain(self): """ Ensure the correct gain factor is correctly calculated in the absence of two stage procedure. """ # The system and SAMS parameters nstates = 10 # The number of discrete states in the system target_weights = np.repeat(1.0 / nstates, nstates) # The target probabilities initial_zeta = np.repeat( 1.0, nstates) # Initial estimate for the free energies initial_zeta -= initial_zeta[0] adaptor = SAMSAdaptor(nstates=nstates, two_stage=False, zetas=initial_zeta, target_weights=target_weights) # Generate a fake sample for the noisy variable: noisy = np.zeros(nstates) state = 3 # The imagined state of the sampler noisy[state] = 1.0 new_zetas = adaptor.update(state=state, noisy_observation=noisy) true_new_zeta = initial_zeta[state] + ( noisy[state] / target_weights[state]) / adaptor.time assert new_zetas[state] == true_new_zeta
def rb_mse_gaussian(sigmas, niterations, nmoves=1, save_freq=1, beta=0.6, flat_hist=0.2): """ Function to compute the mean-squared error from the Rao-Blackwellized update scheme in when sampling states with GaussianMixtureSampler. Parameters ---------- sigmas: numpy array The standard deviations of the Gaussians that are centered on zero niterations: int The number of iterations of mixture sampling and SAMS updates that will be performed nmoves: int The number of moves from the Gaussian Gibbs sampler. One position step and state step constitute one move. save_freq: int The frequency with which to save the state in the Gaussian mixture sampler, used to decorrelate trajectory beta: float The exponent in the burn-in phase of the two stage SAMS update scheme. flat_hist: float The average fractional difference between the target weights of the mixture and count frequency Returns ------- mse: numpy array the mean-squared error of the SAMS estimate for each iteration """ generator = GaussianMixtureSampler(sigmas=sigmas) nstates = len(sigmas) adaptor = SAMSAdaptor(nstates=nstates, beta=beta, flat_hist=flat_hist) # The target free energy f_true = -np.log(sigmas) f_true = f_true - f_true[0] mse = np.zeros((niterations)) for i in range(niterations): generator.step(nmoves, save_freq) state = generator.state noisy = generator.weights z = -adaptor.update(state=state, noisy_observation=noisy, histogram=generator.histogram) generator.zetas = z mse[i] = np.mean((f_true[1:] - z[1:]) ** 2) return mse
def test_sams_clock(self): """ Assess that the adaptor accurately logs the number of times it was called and its iteration stage. The SAMS internal clock is used to calculate the gain. Samples will be generated with numpy's multinomial sampler. """ # Initialize the SAMS adaptor nstates = 10 adaptor = SAMSAdaptor(nstates=nstates) # The probabilities for the discrete states probs = np.repeat(1.0 / nstates, nstates) # Iterating the sampler and adaptor for few steps niterations = 10 for i in range(niterations): noisy = np.random.multinomial(1, probs) state = np.where(noisy != 0)[0][0] adaptor.update(state=state, noisy_observation=noisy) assert adaptor.time == niterations
def test_burnin_termination(self): """ Tests whether the stopping criterion for the burn-in period is correctly implemented. """ nstates = 10 target_weights = np.repeat(1.0 / nstates, nstates) adaptor = SAMSAdaptor(nstates=nstates, two_stage=True, flat_hist=0.2, target_weights=target_weights) # Creating a histogram that matches the target weights. The burn-in should stop. histogram = 100 * target_weights noisy = np.zeros(nstates) state = 3 # The imagined state of the sampler noisy[state] = 1.0 adaptor.update(state=state, noisy_observation=noisy, histogram=histogram) assert adaptor.burnin == False
def test_burnin_continuation(self): """ Tests whether the burn-in does not stop prematurely """ nstates = 10 target_weights = np.repeat(1.0 / nstates, nstates) adaptor = SAMSAdaptor(nstates=nstates, two_stage=True, flat_hist=0.2, target_weights=target_weights) # Creating a histogram that is far from 'flat' and therefore should not stop the burn-in phase histogram = np.arange(nstates) # Creating a fake sample noisy = np.zeros(nstates) state = 3 # The imagined state of the sampler noisy[state] = 1.0 adaptor.update(state=state, noisy_observation=noisy, histogram=histogram) assert adaptor.burnin == True
def test_fast_gain(self): """ Ensures the gain during the burn-in stage is properly calculated. """ # The system and SAMS parameters nstates = 10 # The number of discrete states in the system beta = 0.7 # Exponent of gain factor during burn-in phase. target_weights = np.repeat(1.0 / nstates, nstates) # The target probabilities initial_zeta = np.repeat( 1.0, nstates) # Initial estimate for the free energies initial_zeta -= initial_zeta[0] adaptor = SAMSAdaptor(nstates=nstates, two_stage=True, zetas=initial_zeta, target_weights=target_weights, beta=beta) # Generate a fake sample for the noisy variable: noisy = np.zeros(nstates) state = 3 # The imagined state of the sampler noisy[state] = 1.0 new_zetas = adaptor.update(state=state, noisy_observation=noisy, histogram=np.arange(nstates)) if target_weights[state] < adaptor.time**(-beta): true_new_zeta = initial_zeta[state] + target_weights[state] * ( noisy[state] / target_weights[state]) else: true_new_zeta = initial_zeta[state] + adaptor.time**(-beta) * ( noisy[state] / target_weights[state]) assert new_zetas[state] == true_new_zeta
app.PDBFile.writeModel(wbox.topology, positions, file=pdbfile, modelIndex=0) pdbfile.close() # Create a DCD file system configurations dcdfile = open(args.out + '.dcd', 'wb') dcd = app.DCDFile(file=dcdfile, topology=wbox.topology, dt=timestep) # Initialize SAMS adaptor initial_guess = 317.0 # Initializing the bias using the free energy to insert a single salt molecule bias = np.arange(args.saltmax + 1) * initial_guess adaptor = SAMSAdaptor(nstates=args.saltmax + 1, zetas=bias, beta=0.6, flat_hist=0.1) state_counts = np.zeros(args.saltmax + 1) # Proposal mechanism for SAMS def gen_penalty(nsalt, bias, saltmax): if nsalt == saltmax: penalty = [0.0, bias[nsalt - 1] - bias[nsalt]] elif nsalt == 0: penalty = [bias[nsalt + 1] - bias[nsalt], 0.0] else: penalty = [ bias[nsalt + 1] - bias[nsalt], bias[nsalt - 1] - bias[nsalt] ] return penalty