This file is indexed.

/usr/lib/python2.7/dist-packages/csb/statistics/pdf/parameterized.py is in python-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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
"""
Probability density functions with support for shared and computed parameters.

This module extends the functionality of L{csb.statistics.pdf} with a specialized 
and more sophisticated L{AbstractDensity} -- the L{ParameterizedDensity}, which 
works with L{AbstractParameter} objects rather than simple floats. 

Each L{AbstractParameter} holds two properties - L{AbstractParameter.name} and
L{AbstractParameter.value}:

    >>> class Sigma(AbstractParameter):
    >>>     def _validate(self, value):
    >>>         return float(value)     
    >>>     def _compute(self, base_value):                
    >>>         return 1.0 / base_value ** 0.5
    >>>                            
    >>> sigma = Sigma(3)
    >>> sigma.name, sigma.value
    sigma, 3

L{AbstractParameter}s holding a single float value are indistinguishable from 
the simple float parameters used in L{csb.statistics.pdf.BaseDensity}. 
However, each L{AbstractParameter} supports the concept of binding:

    >>> sigma.is_virtual
    False
    >>> precision = Precision(1) 
    >>> sigma.bind_to(precision)
    >>> sigma.is_virtual
    True    
    >>> precision.set(2)  # triggers an implicit, lazy update in sigma
    >>> sigma.set(1)
    ParameterizationError: Virtual parameters can't be updated explicitly
    
The instance of Sigma is now a virtual parameter which receives automatic updates 
from another base parameter using a predefined rule (L{AbstractParameter._compute}).
This is a lazy, on demand process. As soon as Sigma's computed value is 
requested (via C{s.value}), Sigma will query the parameter it depends on 
(Precision), which in turn will get recomputed first based on its own base, etc. 
Thus, the L{AbstractParameter} model supports a parameter dependency chain with 
linear or tree-like topologies::
            
               sigma -- y   
              /              
    precision -- sigma2 -- x 
    
In this graph precision is a base (non-virtual) parameter and sigma, sigma2, x, and y
are all virtual (computed). Binding precision to another parameter will immediately
turn it into a virtual one. However, cycles are not allowed (e.g. precision can't 
be bound to sigma2 or x) and each virtual parameter must have exactly one base.   

Computed parameters can then be used to implement custom PDFs with dependent 
parameters within one PDF or spanning multiple PDFs.
"""

import csb.statistics.pdf as pdf

from abc import abstractmethod


class ParameterizationError(ValueError):
    pass

class ParameterValueError(pdf.ParameterValueError):
    pass


class ParameterizedDensity(pdf.AbstractDensity):
    """
    Base abstract class for all PDFs, which operate on simple or computed 
    (chained) parameters. Parameters of type different from L{AbstractParameter}
    will trigger TypeError-s.
    """
    
    def _set(self, param, value):
        
        if not isinstance(value, AbstractParameter):
            raise TypeError(value)
        
        super(ParameterizedDensity, self)._set(param, value)    
    
    
class AbstractParameter(object):
    """
    Abstract parameterization, which can exist independently or be coupled 
    to other parameters upon request. Virtual/coupled/derived parameters cannot
    be overwritten explicitly, but their values will get recomputed once their
    corresponding base parameters get updated. This is a lazy process - parameter
    recalculation happens only when an out of date parameter is requested. This 
    triggers a real-time cascaded update which affects all parameters from the
    nearest consistent base down to the current inconsistent node.
    
    Implementing subclasses must override L{AbstractParameter._validate} 
    and virtual parameters should additionally override L{AbstractParameter._compute}.
    
    @param value: initial value (defaults to None / AbstractParameter.NULL)
    @type value: object
    @param name: name of parameter (this is the name of the class by default)
    @type name: str
    @param base: optional base parameter to compute this instance from
    @type base: L{AbstractParameter}
    """
    
    NULL = None
    
    def __init__(self, value=NULL, name=None, base=None):
        
        self._derivatives = set()
        self._base = None
        self._consistent = True
        
        if name is None:
            name = self.__class__.__name__.lower()
        
        self._name = str(name)
        self._value = AbstractParameter.NULL
        
        self._update(value)
        
        if base is not None:
            self.bind_to(base)
    
    @property
    def name(self):
        """
        Parameter name
        """
        return self._name
    
    @property
    def value(self):
        """
        Parameter value (guaranteed to be up to date)
        """
        self._ensure_consistency()
        return self._value
    
    @property
    def is_virtual(self):
        """
        True if this parameter is virtual (computed)
        """
        return self._base is not None

    def set(self, value):
        """
        Update the value of this parameter. This is not possible for 
        virtual parameters.
        
        @param value: new value
        @type value: object
        
        @raise ParameterizationError: if this is a virtual parameter
        @raise ParameterValueError: on invalid value
        """
        if self.is_virtual:
            raise ParameterizationError(
                            "Virtual parameters can't be updated explicitly")
            
        self._update(value)
        
        self._invalidate()
        self._consistent = True

    def bind_to(self, parameter):
        """
        Bind the current parameter to a base parameter. This converts 
        the current parameter to a virtual one, whose value will get 
        implicitly updated to be consistent with its base.
        
        Note that virtual parameters must have exactly one base; computing a
        parameter from multiple bases is not allowed. Cycles are also not 
        allowed; the topology must always stay a tree with a non-virtual
        parameter at the root.        
        
        @param parameter: base parameter to compute this instance from
        @param parameter: L{AbstractParameter}
        
        @raise ParameterizationError: if this parameter is already virtual
        @raise ParameterizationError: on attempt to create a circular dependency
                                        
        """

        if not isinstance(parameter, AbstractParameter):
            raise TypeError(parameter)
        
        if parameter.find_base_parameter() is self:
            raise ParameterizationError("Circular dependency detected")
        
        if self.is_virtual:
            msg = "Parameter {0.name} is already bound to {1.name}"
            raise ParameterizationError(msg.format(self, self._base))
        
        self._set_base(parameter)
        self._base._add_derived(self)
        
        self._invalidate()
        
    def _set_base(self, parameter):
        self._base = parameter
        
    def _add_derived(self, parameter):
        self._derivatives.add(parameter) 
        
    def _invalidate(self):
        """
        Mark self and its virtual children as inconsistent
        """
        for p in self._derivatives: 
            p._invalidate()
            
        self._consistent = False                  
            
    def _update(self, value):
        """
        Overwrite the current value of the parameter. This triggers
        an abstract (custom) validation hook, but has no side effects 
        (i.e. it doesn't propagate!)
        """
        sanitized = self._validate(value)
        self._value = sanitized
        
    @abstractmethod
    def _validate(self, value):
        """
        Validate and sanitize the specified value before assignment.
        @return: sanitized value
        
        @raise ParameterValueError: on invalid value
        """
        return value
    
    def _compute(self, base_value):
        """
        Compute a new value for the current parameter given the value
        of a base parameter (assuming self.is_virtual). By default this returns
        the value of the base parameter (i.e. self just inherits the value 
        of its base untouched).
        """
        return base_value
            
    def _ensure_consistency(self):
        """
        Make sure that the current value is up to date. If it isn't,
        trigger a real-time cascaded update following the path from the 
        nearest consistent base down to self. Also mark all nodes consistent 
        in the course of doing this update. 
        """        
        if not self._consistent:
            path = self._nearest_consistent_base()
        
            for parameter in reversed(path):
                parameter._recompute(consistent=True)

    def _recompute(self, consistent=True):
        """
        If self is virtual, force the current parameter to recompute itself from 
        its immediate base. This operation has no side effects and does not 
        propagate.
        """
        if self.is_virtual:
            value = self._compute(self._base._value)
            self._update(value)
        
        if consistent:
            self._consistent = True
        
    def _recompute_derivatives(self):
        """
        Recompute all derived parameters starting from self and mark 
        them consistent.
        """
        self._recompute(consistent=True)
        
        for p in self._derivatives:
            p._recompute_derivatives()
            
    def _nearest_consistent_base(self):
        """
        Compute and return the path from self to the nearest consistent 
        base parameter.
        
        @return: path, leaf-to-root
        @rtype: list of L{AbstractParameter}
        """
        root = self
        path = [self]
        
        while not root._consistent:
            root = root._base
            path.append(root)
            
        return path        
        
    def find_base_parameter(self):
        """
        Find and return the non-virtual base parameter that is the root
        of the current hierarchy. If self is not virtual, return self.
        
        @return: base parameter
        @rtype: L{AbstractParameter}
        """
        root = self
        
        while root.is_virtual:
            root = root._base
            
        return root 


class Parameter(AbstractParameter):
    """
    Default parameter implementation which accepts float values only.
    """

    def __init__(self, value=0.0, name=None, base=None):
        super(Parameter, self).__init__(value, name, base)
            
    def _validate(self, value):
    
        try:
            return float(value)
        except (ValueError, TypeError):
            raise ParameterValueError(self.name, value)
        
        
class NonVirtualParameter(Parameter):
    """
    A float L{Parameter} that is explicitly non-computed and cannot be 
    bound to another L{Parameter}.
    """
    
    def bind_to(self, parameter):
        raise ParameterizationError(
                            "This parameter is explicitly non-computed")
    
    @property
    def is_virtual(self):
        return False