Path: csiph.com!x330-a1.tempe.blueboxinc.net!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!news.stack.nl!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.002 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'subject:Python': 0.05; '"""': 0.07; 'calculating': 0.07; 'function,': 0.07; 'received:verizon.net': 0.07; 'python': 0.08; 'assert': 0.09; 'delta': 0.09; 'function:': 0.09; 'mentions': 0.09; 'def': 0.13; '"""use': 0.16; 'bouncing': 0.16; 'err': 0.16; 'received:10.20.18.7': 0.16; 'received:bosauthsmtp07.eigbox.net': 0.16; 'received:east.verizon.net': 0.16; 'skip:8 20': 0.16; 'values:': 0.16; 'wrote:': 0.18; 'this?': 0.19; "haven't": 0.20; '(most': 0.21; 'discussion': 0.22; 'header:In-Reply-To:1': 0.22; 'sunday,': 0.23; 'math': 0.24; 'traceback': 0.24; 'cc:2**0': 0.26; 'code': 0.26; 'function': 0.27; 'import': 0.27; 'raise': 0.28; "i'm": 0.28; 'example': 0.29; 'problem': 0.29; 'print': 0.29; 'correct': 0.29; '(the': 0.30; 'error': 0.30; 'anyone': 0.32; 'does': 0.32; 'break': 0.32; 'initial': 0.32; 'this.': 0.33; 'header:User-Agent:1': 0.33; 'it.': 0.33; 'file': 0.34; 'mostly': 0.34; 'steven': 0.34; 'rather': 0.34; 'last):': 0.34; 'routine': 0.34; 'stuck': 0.34; 'try:': 0.34; 'to:addr:python-list': 0.35; 'however,': 0.35; 'none': 0.35; 'be.': 0.35; 'received:71': 0.35; 'apply': 0.35; 'two': 0.36; 'but': 0.37; 'charset:us-ascii': 0.37; 'sometimes': 0.38; 'except': 0.39; 'might': 0.40; 'to:addr:python.org': 0.40; 'back': 0.60; 'header:Received:6': 0.61; 'subject': 0.61; 'improve': 0.62; 'received:10.20.55.2': 0.67; 'received:bosimpout02.eigbox.net': 0.67; '19,': 0.68; 'skip:2 20': 0.71; 'papers': 0.74; 'forth': 0.77; 'received:10.20.15.15': 0.84; 'received:66.96.187': 0.84; 'received:bosmailscan15.eigbox.net': 0.84; 'technique': 0.93 X-EN-OrigOutIP: 10.20.18.7 X-EN-IMPSID: Z3Nj1i001099BUA013Njpv From: inq1ltd To: python-list@python.org Subject: Re: Numeric root-finding in Python Date: Sun, 12 Feb 2012 10:20:17 -0500 User-Agent: KMail/4.7.2 (Linux/2.6.37.6-0.11-desktop; KDE/4.7.2; i686; ; ) In-Reply-To: <4f375f0f$0$29986$c3e8da3$5496439d@news.astraweb.com> References: <4f375f0f$0$29986$c3e8da3$5496439d@news.astraweb.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" X-EN-UserInfo: ea107384e720a598200e9790e8ca8002:9d89a6cbd5a73a41b134431a25286195 X-EN-AuthUser: inq1ltd@inqvista.com Sender: inq1ltd X-EN-OrigIP: 71.127.143.17 X-EN-OrigHost: pool-71-127-143-17.rcmdva.east.verizon.net Cc: Steven D'Aprano X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 92 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1329062119 news.xs4all.nl 6957 [2001:888:2000:d::a6]:44344 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:20275 I don't know the first thing about this math problem however, if I were to code this I might try ; except ZeroDivisionError: assert w = -1 rather than; except ZeroDivisionError: assert w == -1 jimonlinux On Sunday, February 12, 2012 06:41:20 AM Steven D'Aprano wrote: > This is only peripherally a Python problem, but in case anyone has any > good ideas I'm going to ask it. > > I have a routine to calculate an approximation of Lambert's W function, > and then apply a root-finding technique to improve the approximation. > This mostly works well, but sometimes the root-finder gets stuck in a > cycle. > > Here's my function: > > import math > def improve(x, w, exp=math.exp): > """Use Halley's method to improve an estimate of W(x) given > an initial estimate w. > """ > try: > for i in range(36): # Max number of iterations. > ew = exp(w) > a = w*ew - x > b = ew*(w + 1) > err = -a/b # Estimate of the error in the current w. > if abs(err) <= 1e-16: > break > print '%d: w= %r err= %r' % (i, w, err) > # Make a better estimate. > c = (w + 2)*a/(2*w + 2) > delta = a/(b - c) > w -= delta > else: > raise RuntimeError('calculation failed to converge', err) > except ZeroDivisionError: > assert w == -1 > return w > > > Here's an example where improve() converges very quickly: > > py> improve(-0.36, -1.222769842388856) > 0: w= -1.222769842388856 err= -2.9158979924038895e-07 > 1: w= -1.2227701339785069 err= 8.4638038491998997e-16 > -1.222770133978506 > > That's what I expect: convergence in only a few iterations. > > Here's an example where it gets stuck in a cycle, bouncing back and forth > between two values: > > py> improve(-0.36787344117144249, -1.0057222396915309) > 0: w= -1.0057222396915309 err= 2.6521238905750239e-14 > 1: w= -1.0057222396915044 err= -2.6521238905872001e-14 > 2: w= -1.0057222396915309 err= 2.6521238905750239e-14 > 3: w= -1.0057222396915044 err= -2.6521238905872001e-14 > 4: w= -1.0057222396915309 err= 2.6521238905750239e-14 > 5: w= -1.0057222396915044 err= -2.6521238905872001e-14 > [...] > 32: w= -1.0057222396915309 err= 2.6521238905750239e-14 > 33: w= -1.0057222396915044 err= -2.6521238905872001e-14 > 34: w= -1.0057222396915309 err= 2.6521238905750239e-14 > 35: w= -1.0057222396915044 err= -2.6521238905872001e-14 > Traceback (most recent call last): > File "", line 1, in > File "", line 19, in improve > RuntimeError: ('calculation failed to converge', -2.6521238905872001e-14) > > (The correct value for w is approximately -1.00572223991.) > > I know that Newton's method is subject to cycles, but I haven't found any > discussion about Halley's method and cycles, nor do I know what the best > approach for breaking them would be. None of the papers on calculating > the Lambert W function that I have found mentions this. > > Does anyone have any advice for solving this?