Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | |
|
Martin Barbella
2016/12/02 20:07:02
Please run gpylint on these files.
wrengr
2016/12/02 21:00:58
Done.
| |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import math | |
| 6 | |
| 7 _LOG_ZERO = float('-inf') | |
| 8 | |
| 9 def logsumexp(xs): | |
| 10 """Efficiently and accurately compute a log-domain sum. | |
| 11 | |
| 12 While ``math.log(math.fsum(math.exp(x) for x in xs)))`` accomplishes | |
| 13 the same end, it requires an additional ``len(xs) - 2`` logarithms | |
| 14 and introduces more opportunities for over/underflow and rounding | |
| 15 errors. Thus, this function is both more efficient and more accurate. | |
| 16 | |
| 17 Args: | |
| 18 xs (collection of float): the collection of log-domain numbers to be | |
| 19 summed. The order of the elements doesn't matter, nor does the | |
| 20 concrete type of the collection (it could be ``list``, ``set``, | |
| 21 ``frozenset``, etc); the collection just needs to support ``len``, | |
| 22 ``max``, and ``iter``. Because we need the maximum before we | |
| 23 can start the iteration, this function requires (in principle) | |
| 24 two passes over the data; therefore we cannot take an iterator nor | |
| 25 generator. The length should be computed in constant time (else it | |
| 26 will introduce an unnecessary third pass over the data). Ideally | |
| 27 the maximum can also be computed in constant time (in which case | |
| 28 this function only needs to pass over the data once), though none | |
| 29 of Python's builtin types support that. | |
| 30 | |
| 31 Returns: | |
| 32 The log-domain sum of ``xs``. | |
| 33 """ | |
| 34 if not xs: | |
| 35 return _LOG_ZERO | |
| 36 | |
| 37 maximum = max(xs) | |
| 38 if math.isinf(maximum): | |
| 39 return maximum | |
| 40 | |
| 41 total = math.fsum(math.expm1(x - maximum) for x in xs) | |
| 42 return maximum + math.log1p(total + float(len(xs) - 1)) | |
| OLD | NEW |