This file is indexed.

/usr/share/pyshared/mvpa/mappers/metric.py is in python-mvpa 0.4.8-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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the PyMVPA package for the
#   copyright and license terms.
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""Classes and functions to provide sense of distances between sample points"""

__docformat__ = 'restructuredtext'

import numpy as N

from mvpa.clfs.distance import cartesianDistance

class Metric(object):
    """Abstract class for any metric.

    Subclasses abstract a metric of a dataspace with certain properties and can
    be queried for structural information. Currently, this is limited to
    neighborhood information, i.e. identifying the surround a some coordinate in
    the respective dataspace.

    At least one of the methods (getNeighbors, getNeighbor) has to be overriden
    in every derived class.  NOTE: derived #2 from derived class #1 has to
    override all methods which were overrident in class #1
    """

    def getNeighbors(self, *args, **kwargs):
        """Return the list of coordinates for the neighbors.

        By default it simply constracts the list based on
        the generator getNeighbor
        """
        return [ x for x in self.getNeighbor(*args, **kwargs) ]


    def getNeighbor(self, *args, **kwargs):
        """Generator to return coordinate of the neighbor.

        Base class contains the simplest implementation, assuming that
        getNeighbors returns iterative structure to spit out neighbors
        1-by-1
        """
        for neighbor in self.getNeighbors(*args, **kwargs):
            yield neighbor



class DescreteMetric(Metric):
    """Find neighboring points in descretized space

    If input space is descretized and all points fill in N-dimensional cube,
    this finder returns list of neighboring points for a given distance.

    For all `origin` coordinates this class exclusively operates on discretized
    values, not absolute coordinates (which are e.g. in mm).

    Additionally, this metric has the notion of compatible and incompatible
    dataspace metrics, i.e. the descrete space might contain dimensions for
    which computing an overall distance is not meaningful. This could, for
    example, be a combined spatio-temporal space (three spatial dimension,
    plus the temporal one). This metric allows to define a boolean mask
    (`compatmask`) which dimensions share the same dataspace metrics and for
    which the distance function should be evaluated. If a `compatmask` is
    provided, all cordinates are projected into the subspace of the non-zero
    dimensions and distances are computed within that space.

    However, by using a per dimension radius argument for the getNeighbor
    methods, it is nevertheless possible to define a neighborhood along all
    dimension. For all non-compatible axes the respective radius is treated
    as a one-dimensional distance along the respective axis.
    """

    def __init__(self, elementsize=1, distance_function=cartesianDistance,
                 compatmask=None):
        """
        :Parameters:
          elementsize: float | sequence
            The extent of a dataspace element along all dimensions.
          distance_function: functor
            The distance measure used to determine distances between
            dataspace elements.
          compatmask: 1D bool array | None
            A mask where all non-zero elements indicate dimensions
            with compatible spacemetrics. If None (default) all dimensions
            are assumed to have compatible spacemetrics.
        """
        Metric.__init__(self)
        self.__filter_radius = None
        self.__filter_coord = None
        self.__distance_function = distance_function
        self.__elementsize = N.array(elementsize, ndmin=1)
        self.__Ndims = len(self.__elementsize)
        self.compatmask = compatmask


    def _expandRadius(self, radius):
        # expand radius to be equal along all dimensions if just scalar
        # is provided
        if N.isscalar(radius):
            radius = N.array([radius] * len(self.__elementsize), dtype='float')
        else:
            radius = N.array(radius, dtype='float')

        return radius


    def _computeFilter(self, radius):
        """ (Re)compute filter_coord based on given radius
        """
        if not N.all(radius[self.__compatmask][0] == radius[self.__compatmask]):
            raise ValueError, \
                  "Currently only neighborhood spheres are supported, " \
                  "not ellipsoids."
        # store radius in compatible space
        compat_radius = radius[self.__compatmask][0]
        # compute radius in units of elementsize per axis
        elementradius_per_axis = radius / self.__elementsize

        # build prototype search space
        filter_radiuses = N.ceil(N.abs(elementradius_per_axis)).astype('int')
        filter_center = filter_radiuses
        comp_center = filter_center[self.__compatmask] \
                            * self.__elementsize[self.__compatmask]
        filter_mask = N.ones((filter_radiuses * 2) + 1, dtype='bool')

        # get coordinates of all elements
        f_coords = N.transpose(filter_mask.nonzero())

        # but start with empty mask
        filter_mask[:] = False

        # check all filter element
        for coord in f_coords:
            dist = self.__distance_function(
                        coord[self.__compatmask]
                            * self.__elementsize[self.__compatmask],
                        comp_center)
            # compare with radius
            if dist <= compat_radius:
                # zero too distant
                filter_mask[N.array(coord, ndmin=2).T.tolist()] = True


        self.__filter_coord = N.array( filter_mask.nonzero() ).T \
                                        - filter_center
        self.__filter_radius = radius


    def getNeighbors(self, origin, radius=0):
        """Returns coordinates of the neighbors which are within
        distance from coord.

        :Parameters:
          origin: 1D array
            The center coordinate of the neighborhood.
          radius: scalar | sequence
            If a scalar, the radius is treated as identical along all dimensions
            of the dataspace. If a sequence, it defines a per dimension radius,
            thus has to have the same number of elements as dimensions.
            Currently, only spherical neighborhoods are supported. Therefore,
            the radius has to be equal along all dimensions flagged as having
            compatible dataspace metrics. It is, however, possible to define
            variant radii for all other dimensions.
        """
        if len(origin) != self.__Ndims:
            raise ValueError("Obtained coordinates [%r] which have different "
                             "number of dimensions (%d) from known "
                             "elementsize" % (origin, self.__Ndims))

        # take care of postprocessing the radius the ensure validity of the next
        # conditional
        radius = self._expandRadius(radius)
        if N.any(radius != self.__filter_radius):
            self._computeFilter(radius)

        # for the ease of future references, it is better to transform
        # coordinates into tuples
        return origin + self.__filter_coord


    def _setFilter(self, filter_coord):
        """Lets allow to specify some custom filter to use
        """
        self.__filter_coord = filter_coord


    def _getFilter(self):
        """Lets allow to specify some custom filter to use
        """
        return self.__filter_coord

    def _setElementSize(self, v):
        # reset filter radius
        _elementsize = N.array(v, ndmin=1)
        # assure that it is read-only and it gets reassigned
        # only as a whole to trigger this house-keeping
        _elementsize.flags.writeable = False
        self.__elementsize = _elementsize
        self.__Ndims = len(_elementsize)
        self.__filter_radius = None


    def _getCompatMask(self):
        """Return compatmask

        .. note::
          Don't modify in place since it would need to require to reset
          __filter_radius whenever changed
        """
        return self.__compatmask

    def _setCompatMask(self, compatmask):
        """Set new value of compatmask
        """
        if compatmask is None:
            self.__compatmask = N.ones(self.__elementsize.shape, dtype='bool')
        else:
            self.__compatmask = N.array(compatmask, dtype='bool')
            if not self.__elementsize.shape == self.__compatmask.shape:
                raise ValueError, '`compatmask` is of incompatible shape ' \
                        '(need %s, got %s)' % (`self.__elementsize.shape`,
                                               `self.__compatmask.shape`)
        self.__filter_radius = None     # reset so filter gets recomputed


    filter_coord = property(fget=_getFilter, fset=_setFilter)
    elementsize = property(fget=lambda self: self.__elementsize,
                           fset=_setElementSize)
    compatmask = property(_getCompatMask, _setCompatMask)

# Template for future classes
#
# class MeshMetric(Metric):
#     """Return list of neighboring points on a mesh
#     """
#     def getNeighbors(self, origin, distance=0):
#         """Return neighbors"""
#         raise NotImplementedError