[SciPy-User] GMRES iteration number

Pascal Bugnion pascal at bugnion.org
Tue Jun 10 05:46:19 EDT 2014


The lightest way to make a callback that keeps track of the number of
times it is called is probably to use a closure:

def make_callback():
    closure_variables = dict(counter=0) # initialize variables in this
                                        # dict. The callback function
					# has access to this data.
    def callback(residuals):
        closure_variables["counter"] += 1
        print closure_variables["counter"]
    return callback

Then, generate the callback function using 

callback = make_callback()
callback() # prints 1
callback() # prints 2
callback() # prints 3

To give a full example using "gmres":

# -----------------------------------------------------------
import numpy as np
from scipy.sparse.linalg import gmres

# Generate random input data
A = 5*np.eye(10) + np.random.random(size=(10,10))
b = np.random.random(size=(10,))

# Callback generator
def make_callback():
    closure_variables = dict(counter=0, residuals=[]) 
    def callback(residuals):
        closure_variables["counter"] += 1
        closure_variables["residuals"].append(residuals)
        print closure_variables["counter"], residuals
    return callback

gmres(A,b,callback=make_callback())
# -----------------------------------------------------------

See also:
"http://eev.ee/blog/2011/04/24/gotcha-python-scoping-closures/#the-other-problem-mutating-outer-variables"
for other ways to use closures to implement a counter.

Pascal

On Mon, 09 Jun 2014 15:34:57 -0500
Eric Hermes <ehermes at chem.wisc.edu> wrote:

> Would it be possible to make the callback function an append
> operation on a list? e.g. create some list "residuals = []" and do 
> "callback=residuals.append".  Then the length of the list would tell
> you how many calls were made, and you would know what the residuals
> were along the way.  Alternatively, I imagine you could do something
> like this:
> 
> class Counter(object):
>      def __init__(self):
>          self.i = 0
>      def __str__(self):
>          return str(self.i)
>      def addone(self, OPTIONAL_IGNORED_INPUT=None):
>          self.i += 1
> 
> blah = Counter()
> 
> gmres(..., callback=blah.addone)
> 
> print blah
> 
> Eric
> 
> On 6/9/2014 3:18 PM, Jonathan Tu wrote:
> > Hi,
> >
> > Using a callback makes sense to me conceptually, but I have never 
> > implemented something like this.  Is there a standard way to do
> > such a thing?  I would like something lightweight, obviously.  I
> > can imagine defining a small class containing a counter attribute
> > and a parens function that updates this value.  This seems better
> > than doing something like defining a global variable that
> > callback() can modify. Since the callback function will be called
> > as callback(rk), where rk is the residual, I don't know how else to
> > have it update a value whose scope needs to lie outside the
> > callback function itself.
> >
> >
> >
> > Jonathan Tu
> >
> >
> > On May 30, 2014, at 1:47 AM, Ralf Gommers <ralf.gommers at gmail.com 
> > <mailto:ralf.gommers at gmail.com>> wrote:
> >
> >>
> >>
> >>
> >> On Fri, May 30, 2014 at 10:37 AM, Arun Gokule
> >> <arun.gokule at gmail.com <mailto:arun.gokule at gmail.com>> wrote:
> >>
> >>     AFAICT no.
> >>
> >>
> >>     On Thu, May 29, 2014 at 1:20 PM, Jonathan Tu
> >>     <jonathantu at gmail.com <mailto:jonathantu at gmail.com>> wrote:
> >>
> >>         Hi,
> >>
> >>         Is there any way to access the number of iterations it
> >> takes to complete a GMRES computation?  I've checked the
> >>         documentation at
> >>         http://docs.scipy.org/doc/scipy-0.13.0/reference/generated/scipy.sparse.linalg.gmres.html
> >> and it doesn't appear so.  I am doing some testing with passing
> >>         in initial guesses x0, and I am interested to know whether
> >> or not this significantly reduces the required number of
> >> iterations.
> >>
> >>
> >> There's no return value that tells you tells (and we can't add one
> >> in nice a backwards-compatible way), but you can use a callback
> >> function to do this. Just provide a callback that increments some
> >> counter each time it is called.
> >>
> >> Ralf
> >>
> >>
> >>
> >>
> >>
> >>         Thanks,
> >>         Jonathan Tu
> >>
> >>         _______________________________________________
> >>         SciPy-User mailing list
> >>         SciPy-User at scipy.org <mailto:SciPy-User at scipy.org>
> >>         http://mail.scipy.org/mailman/listinfo/scipy-user
> >>
> >>
> >>
> >>     _______________________________________________
> >>     SciPy-User mailing list
> >>     SciPy-User at scipy.org <mailto:SciPy-User at scipy.org>
> >>     http://mail.scipy.org/mailman/listinfo/scipy-user
> >>
> >>
> >> _______________________________________________
> >> SciPy-User mailing list
> >> SciPy-User at scipy.org <mailto:SciPy-User at scipy.org>
> >> http://mail.scipy.org/mailman/listinfo/scipy-user
> >
> >
> >
> > _______________________________________________
> > SciPy-User mailing list
> > SciPy-User at scipy.org
> > http://mail.scipy.org/mailman/listinfo/scipy-user
> 




More information about the SciPy-User mailing list