Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | |
| 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 | |
| 8 _LOG_ZERO = float('-inf') | |
| 9 | |
| 10 | |
| 11 def logsumexp(xs): | |
| 12 """Efficiently and accurately compute a log-domain sum. | |
|
inferno
2016/12/04 23:51:24
Where is this idea based off on ? Can you add a wi
wrengr
2016/12/05 19:12:59
This is common knowledge in the machine learning c
| |
| 13 | |
| 14 While ``math.log(math.fsum(math.exp(x) for x in xs)))`` accomplishes | |
| 15 the same end, it requires an additional ``len(xs) - 2`` logarithms | |
| 16 and introduces more opportunities for over/underflow and rounding | |
| 17 errors. Thus, this function is both more efficient and more accurate. | |
| 18 | |
| 19 Args: | |
| 20 xs (collection of float): the collection of log-domain numbers to be | |
| 21 summed. The order of the elements doesn't matter, nor does the | |
| 22 concrete type of the collection (it could be ``list``, ``set``, | |
| 23 ``frozenset``, etc); the collection just needs to support ``len``, | |
| 24 ``max``, and ``iter``. Because we need the maximum before we | |
| 25 can start the iteration, this function requires (in principle) | |
| 26 two passes over the data; therefore we cannot take an iterator nor | |
| 27 generator. The length should be computed in constant time (else it | |
| 28 will introduce an unnecessary third pass over the data). Ideally | |
| 29 the maximum can also be computed in constant time (in which case | |
| 30 this function only needs to pass over the data once), though none | |
| 31 of Python's builtin types support that. | |
| 32 | |
| 33 Returns: | |
| 34 The log-domain sum of ``xs``. | |
| 35 """ | |
| 36 if not xs: | |
| 37 return _LOG_ZERO | |
| 38 | |
| 39 maximum = max(xs) | |
| 40 if math.isinf(maximum): | |
| 41 return maximum | |
| 42 | |
| 43 total = math.fsum(math.expm1(x - maximum) for x in xs) | |
| 44 return maximum + math.log1p(total + float(len(xs) - 1)) | |
| OLD | NEW |