Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/ops/distributions/laplace.py: 57%

84 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 07:57 +0000

1# Copyright 2016 The TensorFlow Authors. All Rights Reserved. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14# ============================================================================== 

15"""The Laplace distribution class.""" 

16 

17import math 

18 

19import numpy as np 

20 

21from tensorflow.python.framework import constant_op 

22from tensorflow.python.framework import dtypes 

23from tensorflow.python.framework import ops 

24from tensorflow.python.framework import tensor_shape 

25from tensorflow.python.ops import array_ops 

26from tensorflow.python.ops import check_ops 

27from tensorflow.python.ops import math_ops 

28from tensorflow.python.ops import nn 

29from tensorflow.python.ops import random_ops 

30from tensorflow.python.ops.distributions import distribution 

31from tensorflow.python.ops.distributions import special_math 

32from tensorflow.python.util import deprecation 

33from tensorflow.python.util.tf_export import tf_export 

34 

35 

36__all__ = [ 

37 "Laplace", 

38 "LaplaceWithSoftplusScale", 

39] 

40 

41 

42@tf_export(v1=["distributions.Laplace"]) 

43class Laplace(distribution.Distribution): 

44 """The Laplace distribution with location `loc` and `scale` parameters. 

45 

46 #### Mathematical details 

47 

48 The probability density function (pdf) of this distribution is, 

49 

50 ```none 

51 pdf(x; mu, sigma) = exp(-|x - mu| / sigma) / Z 

52 Z = 2 sigma 

53 ``` 

54 

55 where `loc = mu`, `scale = sigma`, and `Z` is the normalization constant. 

56 

57 Note that the Laplace distribution can be thought of two exponential 

58 distributions spliced together "back-to-back." 

59 

60 The Lpalce distribution is a member of the [location-scale family]( 

61 https://en.wikipedia.org/wiki/Location-scale_family), i.e., it can be 

62 constructed as, 

63 

64 ```none 

65 X ~ Laplace(loc=0, scale=1) 

66 Y = loc + scale * X 

67 ``` 

68 

69 """ 

70 

71 @deprecation.deprecated( 

72 "2019-01-01", 

73 "The TensorFlow Distributions library has moved to " 

74 "TensorFlow Probability " 

75 "(https://github.com/tensorflow/probability). You " 

76 "should update all references to use `tfp.distributions` " 

77 "instead of `tf.distributions`.", 

78 warn_once=True) 

79 def __init__(self, 

80 loc, 

81 scale, 

82 validate_args=False, 

83 allow_nan_stats=True, 

84 name="Laplace"): 

85 """Construct Laplace distribution with parameters `loc` and `scale`. 

86 

87 The parameters `loc` and `scale` must be shaped in a way that supports 

88 broadcasting (e.g., `loc / scale` is a valid operation). 

89 

90 Args: 

91 loc: Floating point tensor which characterizes the location (center) 

92 of the distribution. 

93 scale: Positive floating point tensor which characterizes the spread of 

94 the distribution. 

95 validate_args: Python `bool`, default `False`. When `True` distribution 

96 parameters are checked for validity despite possibly degrading runtime 

97 performance. When `False` invalid inputs may silently render incorrect 

98 outputs. 

99 allow_nan_stats: Python `bool`, default `True`. When `True`, 

100 statistics (e.g., mean, mode, variance) use the value "`NaN`" to 

101 indicate the result is undefined. When `False`, an exception is raised 

102 if one or more of the statistic's batch members are undefined. 

103 name: Python `str` name prefixed to Ops created by this class. 

104 

105 Raises: 

106 TypeError: if `loc` and `scale` are of different dtype. 

107 """ 

108 parameters = dict(locals()) 

109 with ops.name_scope(name, values=[loc, scale]) as name: 

110 with ops.control_dependencies([check_ops.assert_positive(scale)] if 

111 validate_args else []): 

112 self._loc = array_ops.identity(loc, name="loc") 

113 self._scale = array_ops.identity(scale, name="scale") 

114 check_ops.assert_same_float_dtype([self._loc, self._scale]) 

115 super(Laplace, self).__init__( 

116 dtype=self._loc.dtype, 

117 reparameterization_type=distribution.FULLY_REPARAMETERIZED, 

118 validate_args=validate_args, 

119 allow_nan_stats=allow_nan_stats, 

120 parameters=parameters, 

121 graph_parents=[self._loc, self._scale], 

122 name=name) 

123 

124 @staticmethod 

125 def _param_shapes(sample_shape): 

126 return dict( 

127 zip(("loc", "scale"), ([ops.convert_to_tensor( 

128 sample_shape, dtype=dtypes.int32)] * 2))) 

129 

130 @property 

131 def loc(self): 

132 """Distribution parameter for the location.""" 

133 return self._loc 

134 

135 @property 

136 def scale(self): 

137 """Distribution parameter for scale.""" 

138 return self._scale 

139 

140 def _batch_shape_tensor(self): 

141 return array_ops.broadcast_dynamic_shape( 

142 array_ops.shape(self.loc), array_ops.shape(self.scale)) 

143 

144 def _batch_shape(self): 

145 return array_ops.broadcast_static_shape( 

146 self.loc.get_shape(), self.scale.get_shape()) 

147 

148 def _event_shape_tensor(self): 

149 return constant_op.constant([], dtype=dtypes.int32) 

150 

151 def _event_shape(self): 

152 return tensor_shape.TensorShape([]) 

153 

154 def _sample_n(self, n, seed=None): 

155 shape = array_ops.concat([[n], self.batch_shape_tensor()], 0) 

156 # Uniform variates must be sampled from the open-interval `(-1, 1)` rather 

157 # than `[-1, 1)`. In the case of `(0, 1)` we'd use 

158 # `np.finfo(self.dtype.as_numpy_dtype).tiny` because it is the smallest, 

159 # positive, "normal" number. However, the concept of subnormality exists 

160 # only at zero; here we need the smallest usable number larger than -1, 

161 # i.e., `-1 + eps/2`. 

162 uniform_samples = random_ops.random_uniform( 

163 shape=shape, 

164 minval=np.nextafter(self.dtype.as_numpy_dtype(-1.), 

165 self.dtype.as_numpy_dtype(0.)), 

166 maxval=1., 

167 dtype=self.dtype, 

168 seed=seed) 

169 return (self.loc - self.scale * math_ops.sign(uniform_samples) * 

170 math_ops.log1p(-math_ops.abs(uniform_samples))) 

171 

172 def _log_prob(self, x): 

173 return self._log_unnormalized_prob(x) - self._log_normalization() 

174 

175 def _prob(self, x): 

176 return math_ops.exp(self._log_prob(x)) 

177 

178 def _log_cdf(self, x): 

179 return special_math.log_cdf_laplace(self._z(x)) 

180 

181 def _log_survival_function(self, x): 

182 return special_math.log_cdf_laplace(-self._z(x)) 

183 

184 def _cdf(self, x): 

185 z = self._z(x) 

186 return (0.5 + 0.5 * math_ops.sign(z) * 

187 (1. - math_ops.exp(-math_ops.abs(z)))) 

188 

189 def _log_unnormalized_prob(self, x): 

190 return -math_ops.abs(self._z(x)) 

191 

192 def _log_normalization(self): 

193 return math.log(2.) + math_ops.log(self.scale) 

194 

195 def _entropy(self): 

196 # Use broadcasting rules to calculate the full broadcast scale. 

197 scale = self.scale + array_ops.zeros_like(self.loc) 

198 return math.log(2.) + 1. + math_ops.log(scale) 

199 

200 def _mean(self): 

201 return self.loc + array_ops.zeros_like(self.scale) 

202 

203 def _stddev(self): 

204 return math.sqrt(2.) * self.scale + array_ops.zeros_like(self.loc) 

205 

206 def _median(self): 

207 return self._mean() 

208 

209 def _mode(self): 

210 return self._mean() 

211 

212 def _z(self, x): 

213 return (x - self.loc) / self.scale 

214 

215 

216class LaplaceWithSoftplusScale(Laplace): 

217 """Laplace with softplus applied to `scale`.""" 

218 

219 @deprecation.deprecated( 

220 "2019-01-01", 

221 "Use `tfd.Laplace(loc, tf.nn.softplus(scale)) " 

222 "instead.", 

223 warn_once=True) 

224 def __init__(self, 

225 loc, 

226 scale, 

227 validate_args=False, 

228 allow_nan_stats=True, 

229 name="LaplaceWithSoftplusScale"): 

230 parameters = dict(locals()) 

231 with ops.name_scope(name, values=[loc, scale]) as name: 

232 super(LaplaceWithSoftplusScale, self).__init__( 

233 loc=loc, 

234 scale=nn.softplus(scale, name="softplus_scale"), 

235 validate_args=validate_args, 

236 allow_nan_stats=allow_nan_stats, 

237 name=name) 

238 self._parameters = parameters