Ejemplo n.º 1
0
    def __init__(self, x0, dynamics, potential, rng, **kwargs):
        super(Hybrid_Monte_Carlo, self).__init__()
        self.initArgs(locals())
        self.defaults = {
            'accept_kwargs': {  # kwargs to pass to accept
                'store_acceptance': False
            }
        }
        self.initDefaults(kwargs)

        # legacy support - need to update
        a = 'store_acceptance'
        if a in kwargs: self.accept_kwargs[a] = kwargs[a]

        self.momentum = Momentum(self.rng)
        self.accept = Accept_Reject(self.rng, **self.accept_kwargs)

        # Take the position in just for the shape
        # as note this is a fullRefresh so the return is
        # entirely gaussian noise. It is independent of X
        # so no need to preflip X before using as an input
        self.p0 = self.momentum.fullRefresh(self.x0)  # intial mom. sample
        shapes = (self.x0.shape, self.p0.shape)

        checks.tryAssertEqual(*shapes,
             error_msg=' x0.shape != p0.shape' \
             +'\n x0: {}, p0: {}'.format(*shapes))
        self.h_old = None
        pass
Ejemplo n.º 2
0
 def kineticEnergy(self, p):
     """n-dim KE
     
     Required Inputs
         p :: np.matrix (col vector) :: momentum vector
     """
     checks.tryAssertEqual(
         len(p.shape), 2, ' expected momentum dims = 2.\n> p: {}'.format(p))
     return .5 * (p**2).sum(axis=0)
Ejemplo n.º 3
0
def gradSquared(lattice, position, a_power=0):
    """lattice gradient^2 for a point with a periodic boundary
    
    The gradient is squared to be symmetric and avoid non differentiability
    in the continuum limit as a^2 -> 0
    -- See Feynman & Hibbs: Quantum Mechanics and Paths Integrals pg. 179
    
    Required Inputs
        lattice  :: Periodic_Lattice :: an overloaded numpy array
        position :: (integer,)       :: determines the position of the array
    
    Optional Inputs
        a_power  :: integer :: divide by (lattice spacing)^a_power
    
    Expectations
        position is a tuple that gives current point in the n-dim lattice
    """

    # check that a lattice is input
    checks.tryAssertEqual(
        type(lattice), Periodic_Lattice,
        "mismatch of lattice type...\ntype received: {}\ntype expected: {}".
        format(type(lattice), Periodic_Lattice))

    # as in laplacian()
    checks.tryAssertEqual(
        len(position), lattice.lattice_dim,
        "mismatch of dims...\ndim received: {}\ndim expected: {}".format(
            len(position), lattice.lattice_dim))

    # ___this is really cool___
    # firstly:  realise that we want True on each case
    #           where the index == the given axis to shift
    # secondly: fancy indexing will index the matrix
    #           for each row in the ndarray provided
    # so this:
    # forwards = np.empty(lattice.lattice_dim)
    # all_dims = range(len(position))
    # for axis in all_dims: # iterate through axes (lattice dimensions)
    #     mask = np.in1d(all_dims, axis) # boolean mask. True on the index = axis
    #     plus = position + mask                        # lattice shift operator
    #     forwards[axis] = lattice[plus] - lattice[pos] # forwards difference
    # is equivalent to:
    plus = position + np.identity(lattice.lattice_dim, dtype=int)
    # repeats the position across nxn matrix
    repeated_pos = np.asarray((position, ) * lattice.lattice_dim)
    forwards = lattice[plus] - lattice[repeated_pos]  # forwards difference
    # ___end cool section___

    grad = (forwards**2).sum()

    # lattice spacing
    if a_power: grad = grad / 1.0**a_power

    return grad
Ejemplo n.º 4
0
 def potentialEnergy(self, x):
     """n-dim potential
     
     Required Inputs
         x :: np.matrix (col vector) :: position vector
     """
     checks.tryAssertEqual(
         x.shape, self.mean.shape,
         ' expected x.shape = self.mean.shape\n> x: {}, mu: {}'.format(
             x.shape, self.mean.shape))
     x -= self.mean
     return .5 * (np.dot(x.T, self.cov_inv) * x).sum(axis=0)
Ejemplo n.º 5
0
    def gradPotentialEnergy(self, x):
        """n-dim gradient
        
        Notes
            discard just stores extra arguments passed for compatibility
            with the lattice versions
        """

        checks.tryAssertEqual(
            len(x.shape), 2, ' expected position dims = 2.\n> x: {}'.format(x))

        # this is constant irrelevent of the index
        return np.dot(self.cov_inv, x)
Ejemplo n.º 6
0
    def hamiltonian(self, p, x):
        """Returns the Hamiltonian
        
        Required Inputs
            p :: np.array (nd) :: momentum array
            x :: class :: see lattice.py for info
        """
        if not hasattr(self, 'debug'): self.debug = False
        if self.debug:
            h = self.kE(p) + self.uE(x)[0]
        else:
            h = self.kE(p) + self.uE(x)

        # check 1 dimensional
        checks.tryAssertEqual(
            h.shape, (1, ) * len(h.shape),
            ' hamiltonian() not scalar.\n> shape: {}'.format(h.shape))
        return h.reshape(1)
Ejemplo n.º 7
0
def laplacian(lattice, position, a_power=0):
    """lattice Laplacian for a point with a periodic boundary
    
    Required Inputs
        lattice  :: Periodic_Lattice :: an overloaded numpy array
        position :: (integer,)       :: determines the position of the array
    
    Optional Inputs
        a_power  :: integer          :: divide by (lattice spacing)^a_power
    
    Expectations
        position is a tuple that gives current point in the n-dim lattice
    """

    # check that a lattice is input
    checks.tryAssertEqual(
        type(lattice), Periodic_Lattice,
        "mismatch of lattice type...\ntype received: {}\ntype expected: {}".
        format(type(lattice), Periodic_Lattice))

    # check that the tuple recieved is the same length as the
    # shape of the target array: Should do gradient over all dims
    # gradient should be an array of the length of degrees of freedom
    checks.tryAssertEqual(
        len(position), lattice.lattice_dim,
        "mismatch of dims...\ndim received: {}\ndim expected: {}".format(
            len(position), lattice.lattice_dim))

    # ___this is really cool___
    # see gradSquared for explanation
    plus = position + np.identity(lattice.lattice_dim, dtype=int)
    minus = position - np.identity(lattice.lattice_dim, dtype=int)
    # repeats the position across nxn matrix
    repeated_pos = np.asarray((position, ) * lattice.lattice_dim)
    lap = lattice[plus] - 2. * lattice[repeated_pos] + lattice[minus]
    # ___end cool section___

    # euclidean space so trivial metric
    lap = lap.sum()

    # multiply by approciate power of lattice spacing
    if a_power: lap = lap / lattice.lattice_spacing**a_power

    return lap
Ejemplo n.º 8
0
    def potentialEnergy(self, positions):
        """n-dim potential
        
        This is the action. In HMC, the action
        is the potential in the shadow hamiltonian.
        
        Here the laplacian in the action is used with 1/a
        the potential is then Va
        
        Required Inputs
            positions :: class :: see lattice.py for info
        """
        lattice = positions  # shortcut for brevity

        x_sq_sum = (lattice**2).ravel().sum()

        v_sq_sum = np.array(0.)  # initiate velocity squared
        # sum (integrate) across euclidean-space (i.e. all lattice sites)
        for idx in np.ndindex(lattice.shape):

            # sum velocity squared
            v_sq = gradSquared(positions, idx, a_power=1)

            # gradient should be an array of the length of degrees of freedom
            checks.tryAssertEqual(v_sq.shape, (),
                 ' derivative^2 shape should be scalar' \
                 + '\n> v_sq shape: {}'.format(v_sq_sum.shape)
                 )

            # sum to previous
            v_sq_sum += v_sq

        #### free action S_0: m/2 \phi(v^2 + m)\phi
        kinetic = .5 * self.m0 * v_sq_sum
        u_0 = .5 * self.mu**2 * x_sq_sum
        ### End free action

        # Add interation terms if required
        if self.phi_3:  # phi^3 term
            x_3_sum = (lattice**3).sum()
            u_3 = self.phi_3 * x_3_sum / np.math.factorial(3)
        else:
            u_3 = 0.

        if self.phi_4:  # phi^4 term
            x_4_sum = (lattice**4).sum()
            u_4 = self.phi_4 * x_4_sum / np.math.factorial(4)
        else:
            u_4 = 0.

        # the potential terms in the action
        potential = u_0 + u_3 + u_4

        # multiply the potential by the lattice spacing as required
        euclidean_action = kinetic + positions.lattice_spacing * potential

        if self.debug:  # alows for debugging
            ret_val = [
                euclidean_action, kinetic,
                potential * positions.lattice_spacing
            ]
        else:
            ret_val = euclidean_action

        return ret_val