This file is indexed.

/usr/lib/python3/dist-packages/csb/statmech/wham.py is in python3-csb 1.2.3+dfsg-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
"""
Estimate the free energy and density of states from tempered ensembles using
histogram re-weighting.
"""

import numpy

from csb.numeric import log, log_sum_exp
from csb.statistics import histogram_nd

from abc import abstractmethod, ABCMeta


class AbstractWHAM(object):
    """
    Abstract base class
    """
    __metaclass__ = ABCMeta

    def __init__(self, ensembles, raw_energies, n):
        
        self._f = numpy.zeros(len(ensembles))
        self._e = raw_energies
        self._n = n
        self._L = []
        self._log_g = None
        self._ensembles = ensembles

    def log_g(self, normalize=True):
        """
        Return the Density of states (DOS).

        @param normalize: Ensure that the density of states sums to one
        @rtype: float
        """
        if normalize:
            return self._log_g - log_sum_exp(self._log_g)
        else:
            return self._log_g 
    
    @property
    def free_energies(self):
        """
        Free energies
        """
        return self._f

    def _stop_criterium(self, tol=1e-10):
        """
        general stop criterium; if the relative difference between
        sequential negative log likelihoods is less than a predefined
        tolerance
        
        @param tol: tolerance
        @type tol: float

        @rtype: boolean
        """
        L = self._L
        return  tol is not None and len(L) > 1 and \
                   abs((L[-2] - L[-1]) / (L[-2] + L[-1])) < tol
        
    
    @abstractmethod
    def estimate(self, *params):
        """
        Estimate the density of states
        """
        pass

    @abstractmethod
    def log_z(self, beta=1., ensembles=None):
        """
        Compute the partition function for an ensemble at inverse temperature
        beta or for a defined ensemble

        @param beta: Inverse Temperature
        @type beta: float or list

        @param ensembles: List of ensembles for which the partition function should be evaluated
        @type ensembles: List of ensembles

        @rtype: float or array
        """
        pass
 
 
class WHAM(AbstractWHAM):
    """
    Implementation of the original WHAM methods based on histograms.
    """

    def __init__(self, ensembles, raw_energies, n):
        super(WHAM, self).__init__(ensembles, raw_energies, n)

        self._ex = None
        self._h = None
        
    def estimate(self, n_bins=100, n_iter=10000, tol=1e-10):

        self._L = []        
        h, e = histogram_nd(self._e, nbins=n_bins, normalize=False)
        self._ex = e = numpy.array(e)
        self._h = h
        f = self._f
        
        log_h = log(h)
        log_g = h * 0.0
        log_g -= log_sum_exp(log_g)
        log_n = log(self._n)

        e_ij = -numpy.squeeze(numpy.array([ensemble.energy(e)
                                           for ensemble in self._ensembles])).T

        for _i in range(n_iter):

            ## update density of states
            y = log_sum_exp(numpy.reshape((e_ij - f + log_n).T,
                                          (len(f), -1)), 0)
            log_g = log_h - numpy.reshape(y, log_g.shape)
            log_g -= log_sum_exp(log_g)

            ## update free energies
            f = log_sum_exp(numpy.reshape(e_ij.T + log_g.flatten(),
                                          (len(f), -1)).T, 0)
            self._L.append((self._n * f).sum() - (h * log_g).sum())

            self._log_g = log_g
            self._f = f

            if self._stop_criterium(tol):
                break

        return f, log_g

    def log_z(self, beta=1., ensembles=None):
        """
        Use trapezoidal rule to evaluate the partition function.
        """
        from numpy import array, multiply, reshape

        is_float = False

        if type(beta) == float:
            beta = reshape(array(beta), (-1,))
            is_float = True

        x = self._ex[0, 1:] - self._ex[0, :-1]
        y = self._ex[0]

        for i in range(1, self._ex.shape[0]):
            x = multiply.outer(x, self._ex[i, 1:] - self._ex[i, :-1])
            y = multiply.outer(y, self._ex[i])

        y = -multiply.outer(beta, y) + self._log_g
        y = reshape(array([y.T[1:], y.T[:-1]]), (2, -1))
        y = log_sum_exp(y, 0) - log(2)
        y = reshape(y, (-1, len(beta))).T + log(x)

        log_z = log_sum_exp(y.T, 0)

        if is_float:
            return float(log_z)
        else:
            return log_z

    
class NonparametricWHAM(AbstractWHAM):
    """
    Implementation of the nonparametric WHAM outlined in Habeck 2012, in which histograms
    are reduced to delta peaks, this allows to use energies samples at different orders 
    of magnitude, improving the accuracy of the DOS estimates.
    """

    def estimate(self, n_iter=10000, tol=1e-10):

        e_ij = numpy.array([ensemble.energy(self._e)
                            for ensemble in self._ensembles]).T

        f = self._f
        log_n = log(self._n)
        self._L = []
        for _i in range(n_iter):

            ## update density of states
            log_g = -log_sum_exp((-e_ij - f + log_n).T, 0)
            log_g -= log_sum_exp(log_g)

            ## update free energies            
            f = log_sum_exp((-e_ij.T + log_g).T, 0)
            self._L.append((self._n * f).sum() - log_g.sum())

            self._f = f
            self._log_g = log_g

            if self._stop_criterium(tol):
                break

        return f, log_g

    def log_g(self, normalize=True):

        e_ij = numpy.array([ensemble.energy(self._e)
                            for ensemble in self._ensembles]).T

        log_g = -log_sum_exp((-e_ij - self._f + log(self._n)).T, 0)

        if normalize:
            log_g -= log_sum_exp(log_g)

        return log_g

    def log_z(self, beta=1., ensembles=None):

        from numpy import multiply

        if ensembles is not None:
            e_ij_prime = numpy.array([ensemble.energy(self._e)
                                      for ensemble in ensembles])
        else:
            e_ij_prime = multiply.outer(beta, self._e)
        
        
        log_z = log_sum_exp((-e_ij_prime + self.log_g()).T, 0)

        return log_z