From 318ca555c8d5c4a2d650ccfee7dcbe2cd3688ff2 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Thu, 7 Nov 2013 01:20:03 -0800 Subject: [PATCH] Stopping Criteria and Printers generalized in Optimize. --- SimPEG/inverse/Inversion.py | 30 +- SimPEG/inverse/Optimize.py | 144 ++++-- notebooks/Bound Constraint Problem.ipynb | 612 ++++++++++++++++++++--- 3 files changed, 665 insertions(+), 121 deletions(-) diff --git a/SimPEG/inverse/Inversion.py b/SimPEG/inverse/Inversion.py index 3aa8ce58..9b13dacd 100644 --- a/SimPEG/inverse/Inversion.py +++ b/SimPEG/inverse/Inversion.py @@ -9,11 +9,27 @@ class Inversion(object): name = 'SimPEG Inversion' def __init__(self, prob, reg, opt, **kwargs): + self.setKwargs(**kwargs) self.prob = prob self.reg = reg self.opt = opt self.opt.parent = self - self.setKwargs(**kwargs) + + # Check if we have inserted printers into the optimization + haveInserted = False + for printer in self.opt.printers: + haveInserted = haveInserted or printer["title"] == 'phi_d' + + if not haveInserted: + self.opt.printers.insert(1,{"title": "beta", + "value": lambda M: M.parent._beta, + "width": 13, "format": "%1.2e"}) + self.opt.printers.insert(2,{"title": "phi_d", + "value": lambda M: M.parent._phi_d_last, + "width": 13, "format": "%1.2e"}) + self.opt.printers.insert(3,{"title": "phi_m", + "value": lambda M: M.parent._phi_m_last, + "width": 13, "format": "%1.2e"}) def setKwargs(self, **kwargs): """Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist.""" @@ -23,13 +39,13 @@ class Inversion(object): else: raise Exception('%s attr is not recognized' % attr) - def printInit(self): - print "%s %s %s" % ('='*22, self.name, '='*22) - print " # beta phi_d phi_m f norm(dJ) #LS" - print "%s" % '-'*62 + # def printInit(self): + # print "%s %s %s" % ('='*22, self.name, '='*22) + # print " # beta phi_d phi_m f norm(dJ) #LS" + # print "%s" % '-'*62 - def printIter(self): - print "%3d %1.2e %1.2e %1.2e %1.2e %1.2e %3d" % (self.opt._iter, self._beta, self._phi_d_last, self._phi_m_last, self.opt.f, np.linalg.norm(self.opt.g), self.opt._iterLS) + # def printIter(self): + # print "%3d %1.2e %1.2e %1.2e %1.2e %1.2e %3d" % (self.opt._iter, self._beta, self._phi_d_last, self._phi_m_last, self.opt.f, np.linalg.norm(self.opt.g), self.opt._iterLS) @property def Wd(self): diff --git a/SimPEG/inverse/Optimize.py b/SimPEG/inverse/Optimize.py index a3b5cd16..f9345d90 100644 --- a/SimPEG/inverse/Optimize.py +++ b/SimPEG/inverse/Optimize.py @@ -33,17 +33,18 @@ class Minimize(object): tolX = 1e-1 tolG = 1e-1 eps = 1e-5 + debug = True def __init__(self, **kwargs): self._id = int(np.random.rand()*1e6) # create a unique identifier to this program to be used in pubsub self.stoppers = [{ "str": "%d : |fc-fOld| = %1.4e <= tolF*(1+|f0|) = %1.4e", - "left": lambda M: 1 if M._iter==0 else abs(M.f-M.fOld), + "left": lambda M: 1 if M._iter==0 else abs(M.f-M.f_last), "right": lambda M: 0 if M._iter==0 else M.tolF*(1+abs(M.f0)), "stopType": "optimal" },{ - "str": "%d : |xc-xOld| = %1.4e <= tolX*(1+|x0|) = %1.4e", - "left": lambda M: 1 if M._iter==0 else norm(M.xc-M.xOld), + "str": "%d : |xc-x_last| = %1.4e <= tolX*(1+|x0|) = %1.4e", + "left": lambda M: 1 if M._iter==0 else norm(M.xc-M.x_last), "right": lambda M: 0 if M._iter==0 else M.tolX*(1+norm(M.x0)), "stopType": "optimal" },{ @@ -57,17 +58,28 @@ class Minimize(object): "right": lambda M: 1e3*M.eps, "stopType": "critical" },{ - "str": "%d : maxIter = %3d\t <= iter\t = %3d", + "str": "%d : maxIter = %3d <= iter = %3d", "left": lambda M: M.maxIter, "right": lambda M: M._iter, "stopType": "critical" }] - # print "%3d\t%1.2e\t%1.2e\t%d" % (self._iter, self.f, norm(self.g), self._iterLS) + + self.stoppersLS = [{ + "str": "%d : ft = %1.4e <= alp*descent = %1.4e", + "left": lambda M: M._LS_ft, + "right": lambda M: M.f + self.LSreduction * M._LS_descent, + "stopType": "optimal" + },{ + "str": "%d : maxIterLS = %3d <= iterLS = %3d", + "left": lambda M: M.maxIterLS, + "right": lambda M: M._iterLS, + "stopType": "critical" + }] self.printers = [{ "title": "#", "value": lambda M: M._iter, - "width": 5, + "width": 10, "format": "%3d" },{ "title": "f", @@ -85,6 +97,29 @@ class Minimize(object): "width": 5, "format": "%d" }] + + self.printersLS = [{ + "title": "#", + "value": lambda M: (M._iter, M._iterLS), + "width": 10, + "format": "%3d.%d" + },{ + "title": "t", + "value": lambda M: M._LS_t, + "width": 14, + "format": "%0.5f" + },{ + "title": "ft", + "value": lambda M: M._LS_ft, + "width": 14, + "format": "%1.2e" + },{ + "title": "f + alp*g.T*p", + "value": lambda M: M.f + M.LSreduction*M._LS_descent, + "width": 16, + "format": "%1.2e" + }] + self.setKwargs(**kwargs) def setKwargs(self, **kwargs): @@ -157,7 +192,6 @@ class Minimize(object): while True: self.f, self.g, self.H = evalFunction(self.xc, return_g=True, return_H=True) if doPub: pub.sendMessage('Minimize.evalFunction', minimize=self, f=self.f, g=self.g, H=self.H) - self.printIter() if self.stoppingCriteria(): break p = self.findSearchDirection() if doPub: pub.sendMessage('Minimize.searchDirection', minimize=self, p=p) @@ -170,6 +204,7 @@ class Minimize(object): if not caught: return self.xc self.doEndIteration(xt) if doPub: pub.sendMessage('Minimize.endIteration', minimize=self, xt=xt) + self.printIter() self.printDone() @@ -215,10 +250,11 @@ class Minimize(object): x0 = self.projection(x0) # ensure that we start of feasible. self.x0 = x0 self.xc = x0 - self.xOld = x0 + self.f_last = np.nan + self.x_last = x0 - def printInit(self): + def printInit(self, inLS=False): """ **printInit** is called at the beginning of the optimization routine. @@ -226,20 +262,21 @@ class Minimize(object): parent.printInit function and call that. """ - if doPub: pub.sendMessage('Minimize.printInit', minimize=self) - if self.parent is not None and hasattr(self.parent, 'printInit'): - self.parent.printInit() - return + if doPub and not inLS: pub.sendMessage('Minimize.printInit', minimize=self) + pad = ' '*10 if inLS else '' + + printers = self.printers if not inLS else self.printersLS + name = self.name if not inLS else self.nameLS titles = '' widths = 0 - for printer in self.printers: + for printer in printers: titles += ('{:^%i}'%printer['width']).format(printer['title']) + '' widths += printer['width'] - print "{0} {1} {0}".format('='*((widths-1-len(self.name))/2), self.name) - print titles - print "%s" % '-'*widths + print pad + "{0} {1} {0}".format('='*((widths-1-len(name))/2), name) + print pad + titles + print pad + "%s" % '-'*widths - def printIter(self): + def printIter(self, inLS=False): """ **printIter** is called directly after function evaluations. @@ -247,18 +284,17 @@ class Minimize(object): parent.printIter function and call that. """ - if doPub: pub.sendMessage('Minimize.printIter', minimize=self) - if self.parent is not None and hasattr(self.parent, 'printIter'): - self.parent.printIter() - return + if doPub and not inLS: pub.sendMessage('Minimize.printIter', minimize=self) + pad = ' '*10 if inLS else '' + printers = self.printers if not inLS else self.printersLS values = '' - for printer in self.printers: + for printer in printers: values += ('{:^%i}'%printer['width']).format(printer['format'] % printer['value'](self)) - print values - # print "%3d\t%1.2e\t%1.2e\t%d" % (self._iter, self.f, norm(self.g), self._iterLS) + print pad + values + # print pad + "%3d\t%1.2e\t%1.2e\t%d" % (self._iter, self.f, norm(self.g), self._iterLS) - def printDone(self): + def printDone(self, inLS=False): """ **printDone** is called at the end of the optimization routine. @@ -266,19 +302,21 @@ class Minimize(object): parent.printDone function and call that. """ - if doPub: pub.sendMessage('Minimize.printDone', minimize=self) - print "%s STOP! %s" % ('-'*25,'-'*25) - # TODO: put controls on gradient value, min model update, and function value - for stopper in self.stoppers: + if doPub and not inLS: pub.sendMessage('Minimize.printDone', minimize=self) + pad = ' '*10 if inLS else '' + stop, done = (' STOP! ', ' DONE! ') if not inLS else ('----------------', ' End Linesearch ') + print pad + "%s%s%s" % ('-'*25,stop,'-'*25) + + stoppers = self.stoppers if not inLS else self.stoppersLS + for stopper in stoppers: l = stopper['left'](self) r = stopper['right'](self) - print stopper['str'] % (l<=r,l,r) + print pad + stopper['str'] % (l<=r,l,r) - print "%s DONE! %s\n" % ('='*25,'='*25) + print pad + "%s%s%s" % ('-'*25,done,'-'*25) - if self.parent is not None and hasattr(self.parent, 'printDone'): self.parent.printDone() - def stoppingCriteria(self): + def stoppingCriteria(self, inLS=False): if self._iter == 0: # Save this for stopping criteria self.f0 = self.f @@ -287,7 +325,9 @@ class Minimize(object): # check stopping rules optimal = [] critical = [] - for stopper in self.stoppers: + + stoppers = self.stoppers if not inLS else self.stoppersLS + for stopper in stoppers: l = stopper['left'](self) r = stopper['right'](self) if stopper['stopType'] == 'optimal': @@ -352,6 +392,8 @@ class Minimize(object): p = self.maxStep*p/np.abs(p.max()) return p + nameLS = "Armijo linesearch" + def modifySearchDirection(self, p): """ **modifySearchDirection** changes the search direction based on some sort of linesearch or trust-region criteria. @@ -371,20 +413,22 @@ class Minimize(object): :return: (xt, passLS) """ # Projected Armijo linesearch - t = 1 - iterLS = 0 - while iterLS < self.maxIterLS: - xt = self.projection(self.xc + t*p) - ft = self.evalFunction(xt, return_g=False, return_H=False) - descent = np.inner(self.g, xt - self.xc) # this takes into account multiplying by t, but is important for projection. - if ft < self.f + t*self.LSreduction*descent: - break - iterLS += 1 - t = self.LSshorten*t - # TODO: Check if t is tooo small. + self._LS_t = 1 + self._iterLS = 0 + while self._iterLS < self.maxIterLS: + self._LS_xt = self.projection(self.xc + self._LS_t*p) + self._LS_ft = self.evalFunction(self._LS_xt, return_g=False, return_H=False)[0] + self._LS_descent = np.inner(self.g, self._LS_xt - self.xc) # this takes into account multiplying by t, but is important for projection. + if self.stoppingCriteria(inLS=True): break + self._iterLS += 1 + self._LS_t = self.LSshorten*self._LS_t + if self.debug: + if self._iterLS == 1: self.printInit(inLS=True) + self.printIter(inLS=True) - self._iterLS = iterLS - return xt, iterLS < self.maxIterLS + if self.debug and self._iterLS > 0: self.printDone(inLS=True) + + return self._LS_xt, self._iterLS < self.maxIterLS def modifySearchDirectionBreak(self, p): """ @@ -431,8 +475,8 @@ class Minimize(object): # store old values - self.fOld = self.f - self.xOld, self.xc = self.xc, xt + self.f_last = self.f + self.x_last, self.xc = self.xc, xt self._iter += 1 diff --git a/notebooks/Bound Constraint Problem.ipynb b/notebooks/Bound Constraint Problem.ipynb index f641fbc9..44fc19fe 100644 --- a/notebooks/Bound Constraint Problem.ipynb +++ b/notebooks/Bound Constraint Problem.ipynb @@ -16,12 +16,13 @@ "from SimPEG.regularization import Regularization\n", "import SimPEG.inverse as inverse\n", "from SimPEG.inverse import Minimize\n", - "import numpy as np" + "import numpy as np\n", + "import scipy.sparse as sp" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 63 + "prompt_number": 1 }, { "cell_type": "code", @@ -33,8 +34,8 @@ "M = prob.mesh\n", "\n", "reg = Regularization(M)\n", - "opt = inverse.InexactGaussNewton(maxIter=20)\n", - "inv = inverse.Inversion(prob,reg,opt,beta0=1e-4)\n", + "opt = inverse.InexactGaussNewton(maxIter=100,debug=False,LSreduction=0.3,maxIterLS=50)\n", + "inv = inverse.Inversion(prob,reg,opt,beta0=1e-4,maxIter=1)\n", "m0 = np.zeros_like(m_true)\n", "\n", "mrec = inv.run(m0)\n", @@ -55,13 +56,12 @@ "output_type": "stream", "stream": "stdout", "text": [ - "====================== SimPEG Inversion ======================\n", - " # beta phi_d phi_m f norm(dJ) #LS\n", - "--------------------------------------------------------------\n", - " 0 1.00e-04 9.53e+02 0.00e+00 9.53e+02 8.95e+03 0\n", - " 1 1.00e-04 6.17e-01 2.65e+04 3.27e+00 1.58e+01 0\n", - " 2 1.00e-04 9.22e-02 2.30e+04 2.39e+00 1.33e+02 0\n", - " 3 1.00e-04 5.11e-02 2.29e+04 2.34e+00 1.02e+00 0" + "============================== Inexact Gauss Newton ==============================\n", + " # beta phi_d phi_m f |g| LS \n", + "----------------------------------------------------------------------------------\n", + " 1 1.00e-04 6.06e-01 2.68e+04 9.57e+02 1.01e+04 0 \n", + " 2 1.00e-04 8.27e-02 2.29e+04 3.29e+00 1.66e+01 0 \n", + " 3 1.00e-04 4.60e-02 2.28e+04 2.37e+00 1.61e+02 0 " ] }, { @@ -69,54 +69,132 @@ "stream": "stdout", "text": [ "\n", - " 4 1.00e-04 4.08e-02 2.28e+04 2.32e+00 1.38e+01 0\n", + " 4 1.00e-04 3.80e-02 2.28e+04 2.33e+00 8.23e-01 0 \n", + " 5 1.00e-04 3.09e-02 2.28e+04 2.31e+00 6.80e-01 0 \n", + " 6 1.00e-04 2.91e-02 2.27e+04 2.31e+00 5.15e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 7 1.00e-04 2.59e-02 2.27e+04 2.30e+00 3.81e-01 0 \n", + " 8 1.00e-04 2.53e-02 2.27e+04 2.30e+00 3.56e-01 0 \n", + " 9 1.00e-04 2.34e-02 2.27e+04 2.30e+00 2.73e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 10 1.00e-04 2.31e-02 2.27e+04 2.30e+00 2.72e-01 0 \n", + " 11 1.00e-04 2.17e-02 2.27e+04 2.30e+00 2.17e-01 0 \n", + " 12 1.00e-04 2.15e-02 2.27e+04 2.30e+00 2.25e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 13 1.00e-04 2.04e-02 2.27e+04 2.29e+00 1.84e-01 0 \n", + " 14 1.00e-04 2.03e-02 2.27e+04 2.29e+00 1.96e-01 0 \n", + " 15 1.00e-04 1.93e-02 2.27e+04 2.29e+00 1.59e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 16 1.00e-04 1.93e-02 2.27e+04 2.29e+00 1.78e-01 0 \n", + " 17 1.00e-04 1.85e-02 2.27e+04 2.29e+00 1.40e-01 0 \n", + " 18 1.00e-04 1.84e-02 2.27e+04 2.29e+00 1.50e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 19 1.00e-04 1.77e-02 2.27e+04 2.29e+00 1.24e-01 0 \n", + " 20 1.00e-04 1.77e-02 2.27e+04 2.29e+00 1.30e-01 0 \n", + " 21 1.00e-04 1.71e-02 2.27e+04 2.29e+00 1.08e-01 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 22 1.00e-04 1.72e-02 2.27e+04 2.29e+00 1.15e-01 0 \n", "------------------------- STOP! -------------------------\n", - "1 : |fc-fOld| = 1.4678e-02 <= tolF*(1+|fStop|) = 9.5423e+01\n", - "1 : |xc-xOld| = 5.5359e-02 <= tolX*(1+|x0|) = 1.0000e-01\n", - "1 : |g| = 1.3766e+01 <= tolG*(1+|fStop|) = 9.5423e+01\n", - "0 : |g| = 1.3766e+01 <= 1e3*eps = 1.0000e-02\n", - "0 : iter = 4\t <= maxIter\t = 20\n", - "========================= DONE! =========================\n", - "\n" + "1 : |fc-fOld| = 2.0822e-04 <= tolF*(1+|f0|) = 9.5809e+01\n", + "1 : |xc-x_last| = 7.3609e-03 <= tolX*(1+|x0|) = 1.0000e-01\n", + "1 : |g| = 9.5181e-02 <= tolG = 1.0000e-01\n", + "0 : |g| = 9.5181e-02 <= 1e3*eps = 1.0000e-02\n", + "0 : maxIter = 100 <= iter = 22\n", + "------------------------- DONE! -------------------------\n" ] }, { "metadata": {}, "output_type": "pyout", - "prompt_number": 16, + "prompt_number": 2, "text": [ - "[]" + "[]" ] }, { "metadata": {}, "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEACAYAAAC08h1NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XtcVHX+P/DXUQyvIYjX9RZoCgJCImBcvV9Ia3/6LbG0\n1drFS2qabfnNXbXatL6rlWRk33L9tl7yWqG2KdYCpol4x9JUAm29ggRqigLz+f3xydFxZpj79bye\nj8c8ambOnPPmeHjNh8/5nM9RhBACRESkGvVcXQARETkXg5+ISGUY/EREKsPgJyJSGQY/EZHKMPiJ\niFTG5uCfMGECWrdujfDwcIPv5+TkwM/PD1FRUYiKisLrr79u6yaJiMgGPrauYPz48Zg6dSrGjRtn\ndJnk5GRkZWXZuikiIrIDm1v8iYmJ8Pf3r3MZXiNGROQ+HN7HrygKdu/ejcjISMycORNFRUWO3iQR\nEdXB4cH/0EMP4eeff0ZBQQFCQ0Mxffp0R2+SiIjqIuyguLhYhIWFmVxOo9GIVq1aiaqqKr33goOD\nBQA++OCDDz4seAQHB1uc2Q5v8V+8eFHbx79582ZERETA19dXb7mioiIIIfgQAnPnznV5De7y4L7g\nvuC+qPthTfe5zaN60tLSkJubi7KyMnTo0AHz589HdXU1ACA9PR0bNmxAZmYmfHx8EBERgUWLFtm6\nSSIisoHNwb9mzZo6358yZQqmTJli62aIiMhOeOWuG0pJSXF1CW6D++IO7os7uC9sowghhKuLAOSw\nTzcphYjIY1iTnWzxExGpDIOfiEhlGPxERCrD4CciUhkGPxGRyjD4iYhUhsFPRKQyDH4iIpVh8BMR\nqQyDn4hIZRj8REQqw+AnIlIZBj8Rkcow+ImIVIbBT0SkMgx+IiKVYfATEakMg5+ISGUY/EREKsPg\nJyJSGQY/EZHK+Li6AFIZIYADB4DiYiA4GIiMBBTF1VURqQqDn5zn4EFgwgTg11+BHj2AwkIgMBBY\nvhwIDXV1dUSqwa4eco7sbGDQIGDmTODHH4HPPgNOnJBfBCkpwJ49rq6QSDUUIYRwdREAoCgK3KQU\nsrfCQqBfPxn2CQn672/dCjz7LPDdd0Dnzk4vj8iTWZOdDH5yrBs3ZD/+nDnA2LHGl3vrLeDLL4Fv\nvgHq8Q9RInNZk538DSPHeu01IDy87tAHgBdeAKqrgY8/dk5dRCrGFj85zvHjQGKi7Opp08b08vv2\nAY8+Ks8BNG3q+PqIvABb/ORe5swBZs0yL/QBIDoaSE4GFi92bF1EKscWPznG/v3AiBHAyZNA48bm\nf+7ECSA+HigpAZo0cVh5RN6CLX5yHwsWAC+9ZFnoA8CDD8qRPytWOKQsImKLnxyhuBjo3Vu22q3p\nq9+9W54MPnmSI3yITGCLn9zDkiXywixrT9A+/DDg5wd8/bV96yIiAGzxk71duQI88ABw6BDQoYP1\n61m6FNi5E/j0U/vVRuSFXNLinzBhAlq3bo3w8HCjy8yePRtBQUHo1asXjh8/busmyZ2tXStH5tgS\n+gAwZgzw1VfA5cv2qYuItGwO/vHjx+Orr74y+v7evXuxc+dO7Nu3D7NmzcKsWbNs3SS5s3/8Q3bz\n2MrfHxg6FFi3zvZ1EZEOm4M/MTER/v7+Rt/Pz8/HqFGjEBAQgLS0NBw7dszWTZK7OnZMntgdMsQ+\n63viCWD9evusi4i0HD4t8969ezH2rsv1W7ZsiaKiIgQHBzt602QljQb49ls5g4Ilunz4D4jkcSjK\ntc9hVc93CBIKxmPP+gu4FWDmRWD3CA7mvG9E93J48Ash9E48KEZuvDFv3jzt/6ekpCAlJcWBlZEx\nx44Bw4YBsbHmf0YRGny6axX+HJWN02/Yq5KGmN0kFd/P2YSs9pMt/nRZGdCpE5CVZa96iFwvJycH\nOTk5Nq3DLqN6SkpKMHz4cBQWFuq9l5GRgZqaGsyYMQMAEBwcjKKiIv1COKrHbRw+DIwbJ/9rtp07\ngSlTgCNH7FtMVpacwsGKA/3LL4H33pP/JfJWbjmOPzY2Fhs3bsTly5exevVqhISEOHqTZCMhrLgb\n4rp1sk/e3gYNknfuKi21/7qJVMrmrp60tDTk5uairKwMHTp0wPz581H9W+dweno6YmJikJCQgOjo\naAQEBGDlypU2F02OZXHw19YCGzYAeXn2L6ZhQ6B/fzm009TUzvdQFPmzEJEum4N/zZo1JpdZuHAh\nFi5caOumyEksDv6dO4G2bYGuXR1TUGoqsGULg5/ITjhlA+mxOPjXrgUef9xh9WDYMGD7dsuHGRGR\nQQx+0mNR8Gs08l66o0Y5rqC2beW4zN27LfoYW/xEhjH4SY9FYVlQALRoAXTp4rB6ANzp7rEQg59I\nH4Of9FjU4t+8Wd5wxdGGDJHdPRaweGQSkUow+EmPRcGflQUMH+7QegDcmd//0iWzP8KuHiLDGPyk\nx+zgLykBLlyw7BJfa/n4AElJwL//7fhtEXk5Bj/pMTv4N28GHnkEqF/f4TUBAAYMsOjmLGzxExnG\n4Cc9Zge/s7p5buvfn8FPZAcMftJjVvBfuQLk5wMDBzqlJgBAjx7Ar7/KqZ+JyGoMftJjVvB/8w0Q\nF2f9fXWtoSgWtfrZ4icyjMFPeswK/u3b5QRqzta/v/zSMQODn8gwBj/pMSv4s7Od281zW1KSnBuI\niU5kNQY/6TEZ/MXFwNWrQHi402rSCg4GamqA06dNLsoWP5FhDH7SYzL4s7Pl0Mp6Ljh8FAVISJD3\nhjQDg59IH4Of9JgV/K7o5rktMVF295jAKRuIDGPwk546g7+2Vp5cdWXwJySYHfxs8RPpY/CTnjqD\nf/9+OU1yu3ZOrUlHRARw9qy8m7oJDH4ifQx+0lNn8Lu6mweQ8/bExQG7dtW5GLt6iAxj8JMetw9+\nQPbzmzjBy64eIsMY/GSQweC/dk129SQnO70ePWb28xORPgY/6THa4s/NBaKjgSZNnF6TnthYoLAQ\nuH7d6CJs8RMZxuAnPUaD3126eQCgUSMgNBQ4cMDoIgx+IsMY/KSnzuB3xfw8xsTGyhlCicgiDH7S\nYzD4//Mf4OJFICrKJTUZFBcH7Nlj9G22+IkMY/CTHoPBv2MH0K+f8+62ZQ4TLX4GP5FhDH7SYzD4\n3al//7YuXeSNWc6dc3UlRB6FwU969FrJGo17Br+iyO4eI61+tviJDGPwkx69Fv+RI0Dz5kDnzq4q\nybjY2Dr7+Rn8RPoY/KRHL/jdsbV/m4kWPxHpY/CTHoPB707DOO8WEyOvJq6p0XuLXT1EhjH4SY9O\n8N+4AXz3HZCS4sqSjGveHGjfHjh61ODbDH4ifQx+0qMT/N9+K6dB9vNzaU11MjKsk109RIYx+EmP\nTvC7czfPbUYu5GJXD5FhDH7SoxP827e774nd22JigH37XF0Fkcdg8JMebfBfvAiUlMhgdWdhYUBR\nkbyY6y5s8RMZZnPw5+XlISQkBF27dkVGRobe+zk5OfDz80NUVBSioqLw+uuv27pJcjBt8H/9tTyp\n6+Pj6pLqdt99MvwPHdJ5mcFPZJjNv9HTp0/HsmXL0KlTJwwePBhpaWkIDAzUWSY5ORlZWVm2boqc\nRBv827e7f//+bdHRQEEBEB/v6kqI3J5NLf7KykoAQFJSEjp16oRBgwYh38DoCsFml0cRAlAg3PvC\nrXtFR+v187PFT2SYTcFfUFCA7t27a5+HhoZizz2jKxRFwe7duxEZGYmZM2eiqKjIlk2SEwgBtL96\nDGjQQE6E5gkMBD/A4CcyxOEndx966CH8/PPPKCgoQGhoKKZPn+7oTZKNhAB6XtwODB7sOYPhQ0Pl\nPQOuXNG+5CmlEzmbTX38vXv3xosvvqh9/v3332PIkCE6yzRr1kz7/8888wxeeeUV3Lx5E76+vnrr\nmzdvnvb/U1JSkOKuV4t6OSGAiIvbgUHPuLoU8/n4AD17ylsx/nbcsKuHvFFOTg5ycnJsWodNwe/3\n29WceXl56NixI7KzszF37lydZS5evIhWrVpBURRs3rwZERERBkMf0A1+ch3l1k10K/0W6LfK1aVY\n5nZ3z10NBgY/eZt7G8Xz58+3eB02j+p55513kJ6ejurqakybNg2BgYFYtmwZACA9PR0bNmxAZmYm\nfHx8EBERgUWLFtm6SXKwwB934axfD3T193d1KZaJjga2btU+ZVcPkWGKcJMhN4qicPSPmzj6yMs4\nccYX/++I5S0Jlzp2DBg+HDh1CoCct230aKPztxF5BWuyk1fukp52hdtwtK2HjN+/24MPApcuAb/8\non2JbQkifQx+0nXxIpqWFqO4pZtP02BI/fpAVJScnx/s6iEyhsFPunbswPmQvtDUb+DqSqxz13h+\njuohMozBT7q2b8fZHoM8t7V8z4VcDH4ifQx+ukMIGfyh3hH8HvszEDkYg5/uOHoUaNIEV1oGu7oS\n63XpAlRWAqWlANjiJzKEwU93bNsGDByof7N1T6IoQK9ewP79nvszEDkYg5/u+PJLYOhQAB4c/IC2\nu4cnd4kMY/CTVFkp+8b79/fsFj9wZ25+MPiJDGHwk7R9O5CQADRp4h3Bz64eIqMY/CRt3QqkpgKA\n5wd/p05AVRV8Ss+zxU9kAIOfAI1G9u97S/ArChAdjYbf72fwExnA4CfZH96qFdC5MwAvCH5ABv9R\n/TtyERGDnwBgyxbgkUe0T70i+Hv1gu/RfWzxExnA4Ced/n3AS4I/Ohq+hfsgNEx+onsx+NXu7Fng\n9GmgTx/tS14R/O3bA0KgTe1ZV1dC5HYY/Gr3+eeyte9z52ZsXhH8ioJb4dEIq2I/P9G9GPxqt2ED\nMHKkzkteEfwAboZHI/wmg5/oXgx+NSstBQ4eBAbp3m3LW4L/VkQ0Im4x+InuxeBXs88/BwYPBho1\n0nnZa4I/vBfCbu3nvA1E92Dwq9nGjXrdPID3BL+mTTtUK/cBZ864uhQit8LgV6tffgG++w4YNkzv\nLW8JfkUBjjTQvSMXETH41SsrC+jXD2jaVO8tbwl+ADhyH4Of6F4MfrX69FPgv/7L4FveEvyKAhxm\ni59ID4NfjS5cAPbsAR57zODb3hT8Rxr0ksHPE7xEWgx+NVqzBnj0UaBxY4Nve0vwA0BZvVZAs2bA\nTz+5uhQit8HgV6N//hMYO9bo294S/NqfIZrdPUR3Y/CrzdGjwKVLQEqK0UW8JfiB33p4GPxEOhj8\navPJJ8CTTwL16xtdxFuCX3uzdQY/kQ4f04uQ17h5E1ixAvj22zoX85bzoNovr169gAMH5J3G6rGt\nQ8TfAjXZtAmIiAAefLDOxbylxQ/89iXWooV8nDzp6nKI3AKDX00yM4FJk0wu5i3Br+3qAdjdQ3QX\nBr9aHD0KnDoFjBhhclFvCn6t6Ghg/36X1ULkThj8avH3vwNTpgANGphc1FuCH2CLn8gQntxVg59/\nlnPzFBWZtbi3BL/Oz/DQQ/LeA7W1dY5oIlIDBr8tLl4Edu8GTpyQU/9WVQG+vkCbNkCPHkBcHPC7\n37m6SuDtt4Hx4wF/f7MW96bg17b4mzeX/y4//giEhrq0LiJXszn48/LykJ6ejpqaGkybNg1Tp07V\nW2b27NlYu3Yt/P39sWrVKnTv3t3wysaPl0PvunUDBgxwz/QpKgJWrgTWrwfOnQMefhgICZGPhg1l\n+J8/D/zf/wHp6UBQEDB6NDBhggwfZ7twQdZy+LDZH/GW4AfuGZp6u7tHzcF/4wbw1VfAtm3AkSNA\ncbF8rX59oHVroHNnuZ9iYuRFfgZmb/VoN24AZ8/K39Fff5XPr1+XP3/DhvLRrJlsJLRta3RaE09n\nc/BPnz4dy5YtQ6dOnTB48GCkpaUhMDBQ+/7evXuxc+dO7Nu3D9u2bcOsWbOwZcsWwyuLiZEHY2am\nDNXHHgPGjZMHoCuTSAggLw944w3ZXfDEE8BHHwG9e9fdbVBTA+TkyOANCpLhP3u2HFroLK++Cvzh\nD0D79mZ/RAjvGO6ud8jcDv5x41xSj0uVlwNvvQV8/DHQsycwdCgwZow8Lps0kcfqxYtyAMC+ffKv\nxDFjgPh44Pe/Bx5/3DUNF2vduAHk58sGT2GhHNxw8qQM+3btZKg3bSqDvVEjeY1HVZV8VFTIfXH+\nPHDffXIfdesmH927yyHRISGe3WUobFBRUSEiIyO1z6dOnSq2bNmis8ySJUvE22+/rX0eFBRkcF06\npWg0Qpw+LcTbbwsRGipEjx5CLF8uxK1btpRrOY1GiK1bhYiPF6JLFyE++kiImzetW9eZM0JMmiRE\ny5ZCvPuuENXV9q3VkBMnhAgMFKKszKKPzZkjxLx5DqrJiUpLhQgIuOuFnBwh+vRxWT0uodEI8fHH\nQrRqJUR6uhCnTpn/2cpKIdatE2LUKCH8/IR44gkh/vUvIWpqHFevtWprhThwQIg33xRiwAAhmjYV\nIi5O/s69/74QO3cKcemS3B/m0miEKC8XYt8+IVauFOIvf5H7oksXuf6EBCGef16IVauE+Okny9Zt\nR9bEuE3Bn52dLUaPHq19npmZKebMmaOzzFNPPSW2bdumfR4bGytOGTj4jBav0QiRnS1E//5CtG8v\n/2F/+cWWsk2rqZEHfGSkEOHhQqxZY7+gLiwUol8/IXr1EuLoUfus0xCNRojhw4V44w2LPzpnjhDz\n5zugJicrKxPC3/+uFyorhWjc2Dlfuu7gyhUhRo8WIiJCiEOHbFvX5ctCLF0qRO/eQrRrJ8RLLwlx\n7Jh96rTWzz/LBmFammxQPfigEFOmCPHFF/Lf2pHKy4XYsUOIhQuFGDlSiDZthPjd72Qt778vf7dr\nax1bw2+sCX6Hn9wV8stF5zXFSLeN4ZGGCoABAAYgShzA8y8vxpCXgrBSGYeMetNRojxgt1obiFtI\nE6vxomYhrsAPC+rNx1blEYix9QDjk1laKAwQO/Cs+F+8FpaMRfVexNvKC6hV7PtP8XvNJszTnELv\nL9fj1l8t+2xtLfDuu3YtxyX0DrP77wc6dgR++EH+ue5B0tKADRvMX76luIQttUNxWInEtHp7UBXd\nyMYKAgBMBjAZIeIHjHtrBZ58sy9OozM+qfcHrFOeQKXi2K6gJuIakkUOBohs9BfZaIVL+Ebpj6+V\ngdihLMCZXzoByyAfDucPoP9vDwBCIBhFSFi7E4mf5iFeLII/fsEuJQE7lSR8qyThIKLs/ntu4iJ8\noxRxbypboLKyEikpKTh48CAAYOrUqRgyZAhSU1O1y2RkZKCmpgYzZswAAAQHB6PIwLBCRVEwZ85c\n7fPk5BQkJ6cY3vB//oN67y1BvRUfQ/TtD82MFyBiYq39MYCKCtRb/hHqZbwDERIKzayXIPr2c/x5\nhZIS1P/TBKCqCrXLPwG6dLHPei9ehE9MFGpXr4OIT7BqFT4+nn+Ct7wcCA6WtxfWGjtWnjN65hlX\nlWWVvn2B//7vOidVveP8efj0T4bmiTRo/jrPcf+QNTVQtm9DvU9WQPk6G2LgYGgeGQExeIh9zmNV\nVUHJ3wMl599Qcv8N5eABiN4xEP0HQgwYCBEZ5d797OfOQfl2J5Sduai3Mw/4z88QfR6GSEiCSEqG\n6BUtzyFYKDc3B7m5Odrnr78+X69xbZKtf2ZERkaK3NxcUVxcLLp16yZKS0t13s/Pzxfx8fGirKxM\nrFq1SqSmphpcj1WlXLkizwN06iT74desEaKiwrzP3rgh+yvHjJH9l2PGyD5CZ6utFeKdd4Ro0UKI\nzEzb+wlramQf5yuv2Kc+D1ZeLv9pdWRkCPHssy6pxxZJSfIUhUnl5bJ78rXXHF6TjrIyIT78UIhH\nHxWiWTPZvz5zpuwyPX5c/r7VpbJSdkd98okQM2YIkZws+9FjYoT485/l7+q1a075URymtFSITZuE\nmD5diKgo+fP16yf7VXNyTO8jI6zJTpta/PLbJxcTJ05EdXU1pk2bhmnTpmHZMvm3Vnp6OgDg5Zdf\nxtq1axEQEICVK1ciJCREbz2Kolj+rXVbTY2cgGz5cmDXLiAyUo7gCA0FWraUZ++vXwcuXwaOHwcO\nHQK++w4IC5NDLceMAe4aieQSx47J1mirVnLkRdu2lq9DCGDGDDmSITtbNttVrKJCjk6sqLjrxf37\n5SinwkIXVWWdxEQ5qCwxsY6FqquBQYPkqJ2333bdn2xVVfL6lvx8eYvPH36QFxG2aCFHBjVpIlu6\n16/LUTaXLsnaO3WSv5NRUfIRFwf4+bnmZ3CGigo5U25eHpCbC3z/vbzQMDlZPvr0kfvKBGuy0+bg\ntxebgv9u16/LnXn4sAzTy5eBq1flDmzeXA7JiogAEhKAgADbt2dP1dXA3/4mh7MuWSKH0Jn7yysE\n8Je/yCt08/I8a+idg1RUyCyprLzrxepqeSHb2bMeFSrx8XI0Znx8HQvNnCmP+S1b3K8LpLZWDtGu\nrJRhf+uWHErZpIlsdLVo4fl9i7a6elU2SHNz5ePQISA8XA4b79lTNma7dNH7MmDwe4uCAnkxW6tW\nwKJFsvVTlytX5Dw8x4/LX/rWrZ1Tp5urrAQ6dJC7R0dSkvySHDjQJXVZo08fYPFi+V+D1q6V14js\n2+d+DRqyzo0b8i+mgwfl48ABee/oVq3kl2ZQENCsGZS1ay3OTnX3Bbir3r3lt/1HHwHDhslv+z/9\nSQZVs2Z3lrtyRV5FvGABMHiwbCV46ZWG1jDagOzTR7asPCj467yHzJkzwHPPyatxGfreo1EjeVa/\nb987r9XWAiUl8q+m4mLZslm71uJVM/jdlY8PMHGi7I9euxZ4/33g6aflP3RAgOzHKC6Wgf/ppyb6\nANTLYEOoTx/gww+dXostjAa/RiNHKM2YIfuHybvVry+HqgE2DUlm8Lu7hg1l4D/9tDx/UVQkxyfe\nf7+8bNzX19UVui2dSdruFhcnp8/woFsxGi31gw9k3/Cf/+z0mshzMfg9SePG8mQP2aZNG3li98QJ\nOfeKBzAY/OfPA3/9qxzMoPIRXGQZz2juEFnBaIsfkN09e/Y4tR5baDQGzlm8+CLwxz96zJcXuQ8G\nP3mtOkcH3j7B6yH0ZkzNzZXDdufMcVlN5LkY/OTVjLb44+I8Kvh1unpqauQonsWLzbrAh+heDH7y\nWnV29fTsKcdEX73q1JqspRP8K1bIC55GjnRlSeTBGPzkters6rnvPnlh3N69TqvHFtrgv34dmDcP\nePNNXulKVmPwk1er84LGhx+WI2I8gDb4MzKA2Fj5ILISx4CR16qzqweQUzcsXuy0emyh0QA+V38B\n/v53YOdOV5dDHo4tfvJaJntC4uNlV8+tW06pxxYaDRDwv2/K+1Bz+CbZiC1+8mp1tvibNwe6dpUT\nmz38sNNqssb91ZfR7NMPgcLDri6FvABb/OS1THb1ALK7Jy/PKfXY4ukrGbgx+PdyriYiGzH4Sd2S\nk90/+K9dw7hrS3FtMufjIftg8JPXMqvFn5Ag79pWU+OUmqzy4YfYfV9f1Hbp5upKyEsw+MlrmRX8\nLVsC7dvLO7a5o5s3gcWLsaTJbE+ZSJQ8AA8louRkOfeNO/rnP4GwMBypH8XgJ7vhoURey6wWPyBP\n8Lpj8NfWyit0Z8/2pFsHkAfgoURey+wZDfr2lcHvbv38GzbIrqikJAY/2RUPJfJqZrX4W7cGOnd2\nr3l7hJD3Up49G1AUBj/ZFQ8l8loWzWE2cCCQne2wWiz21Vfyct3UVAAedZdI8gA8lMhreXTwL1gA\nvPyyNu0Z/GRPPJTI65nV3ZOYKId0Xrni8HpM2rULOHsWePxx7UsMfrInHkrk9cwK/kaN5FTHOTmO\nLse0BQvk/XTvuoE6g5/siYcS0W2DBgHbt7u2hsOHgQMHgD/8QedlgzdbJ7ISg5+8mtlj+QFg8GDg\nX/+y4AMOsHAh8PzzQMOGOi/r3WydyAY8lMirWRT8ERFyLP+xYw6tyahTp+QJ5okT9d5iVw/ZEw8l\notsUBRgxAvjiC9ds/3/+B5g0Cbj/fr23GPxkTzyUyKtZ1OIHZPBnZTmsHqPOnQPWrwemTdN7Swj5\nYB8/2QuDn7yaxcGfnCy7ei5ccFhNBi1eDIwdK6douMft0Gfwk70w+Inudt998iTvli3O22ZZGbB8\nuRzCaQC7ecjeeDiRV7O4xQ84v5//3XeBUaPkfQEMYPCTvSlCuHLs2h2KosBNSiEv4usrL8b19bXg\nQ5WVQMeOQEkJ4O/vqNKkigqgSxc5QVxQkMFFqqrkfeGrqhxbCnkma7KT7Qjyeha3J/z8gAEDgE2b\nHFKPjqVLgWHDjIY+wBY/2Z/Vh9PVq1fx6KOPomPHjnjsscdw7do1g8t17twZERERiIqKQkxMjNWF\nElnDqq4eABgzBli92u716Pj1V2DJEjn1ch141S7Zm9XBn5mZiY4dO+LkyZNo3749PvjgA4PLKYqC\nnJwcHDx4EHvdab5zoroMGyanTjh/3nHbyMyUd/8KCalzMV61S/Zm9eG0d+9ePPPMM/D19cWECROQ\nn59vdFn23ZOrWN3ib9QIeOwxx7X6KyuBt94C5s0zuSi7esjefEwvYlhBQQG6d+8OAOjevbvR1ryi\nKOjXrx8eeOABTJgwASNGjLB2k0QWUxR5B0OLTu7+JvCBZ9F70QT863cz7d7XErZuERqHDMXeoz2A\no3Uv++uvDH6yrzqDf+DAgbhg4EKWv/3tb2a34nft2oW2bdvi2LFjGD58OGJiYtCmTRuDy867q/WT\nkpKClJQUs7ZBZMyf/gRs3Wrlh8XD6HLdFz9+8G9837qf3Wq6v+oShn21FLMH7kepmeePn33Wbpsn\nD5eTk4McG6cPt3o458iRIzFnzhxERUVh//79WLBgATZs2FDnZ2bOnImQkBD88Y9/1C+EwznJHb3/\nvpyjf906+63z+edl/82SJfZbJ6mWU4dzxsbGYvny5bhx4waWL1+OuLg4vWWuX7+Oq1evAgBKS0ux\nbds2DBkyxNpNEjnfU08BO3bIO2LZw/HjwKpVwCuv2Gd9RFawOvgnTZqEM2fOoFu3bjh79iwm/jaV\n7Llz55D62w2iL1y4gMTERERGRmL06NF44YUX0KFDB/tUTuQM998vb4qyaJHt6xICmDoVmDMHaN3a\n9vURWYntpsLvAAAHgklEQVRX7hKZcu4cEBYGnDgBBAZav55Nm4C5c4GDB3Vuq0hkC2uyk8FPZI5J\nk4BmzeQQTGtUVMgbvXzyCcBBC2RHDH4iRzl/HggPB/LzgeBgyz8/dqycCuK99+xfG6ka5+ohcpS2\nbYEXXgBmzLD8irC1a+UXxptvOqY2Igsx+InMNXOmnLFzxQrzP1NYCDz3HLBmDdCkiaMqI7IIzzAR\nmcvXV07h0LcvEB0tu37qcvo0MHy4nG+/Vy/n1EhkBrb4iSwRFgZkZABDhwJFRcaX+/FHoF8/+VfC\nmDHOq4/IDAx+IkuNHi2HZcbHA59/rtvnX1srb6OYkCCnWzZw83QiV+OoHiJr5eYCkyfLCdzi44Fb\nt4BvvpG3UMzIAB56yNUVkgpwOCeRs2k0wJ49wOHDQIMGQGys6b5/Ijti8BMRqQzH8RMRkUkMfiIi\nlWHwExGpDIOfiEhlGPxERCrD4CciUhkGPxGRyjD4iYhUhsFPRKQyDH4iIpVh8BMRqQyDn4hIZRj8\nREQqw+AnIlIZBj8Rkcow+ImIVIbBT0SkMgx+IiKVYfATEakMg5+ISGUY/EREKsPgJyJSGQY/EZHK\nMPiJiFSGwU9EpDJWB//69evRo0cP1K9fHwcOHDC6XF5eHkJCQtC1a1dkZGRYuzkiIrITq4M/PDwc\nn332GZKSkupcbvr06Vi2bBl27NiBpUuXoqyszNpNqkZOTo6rS3Ab3Bd3cF/cwX1hG6uDv3v37njw\nwQfrXKayshIAkJSUhE6dOmHQoEHIz8+3dpOqwYP6Du6LO7gv7uC+sI1D+/gLCgrQvXt37fPQ0FDs\n2bPHkZskIiITfOp6c+DAgbhw4YLe62+88QaGDx/usKKIiMiBhI1SUlLE/v37Db5XUVEhIiMjtc+f\ne+45sWXLFoPLBgcHCwB88MEHH3xY8AgODrY4t+ts8ZtLCGHwdT8/PwByZE/Hjh2RnZ2NuXPnGlz2\n1KlT9iiFiIhMsLqP/7PPPkOHDh2wZ88epKamYujQoQCAc+fOITU1VbvcO++8g/T0dAwYMACTJ09G\nYGCg7VUTEZHVFGGsuU5ERF7JqVfumnMx1+zZsxEUFIRevXrh+PHjzizPqUzti1WrVqFnz57o2bMn\nxowZgxMnTrigSucw9yK/goIC+Pj4YNOmTU6szrnM2RcFBQXo3bs3QkJCkJKS4twCncjUvrhx4wae\nfvppREVFITk5GV988YULqnS8CRMmoHXr1ggPDze6jMW5afFZARtERkaK3NxcUVJSIrp16yZKS0t1\n3s/Pzxfx8fHi8uXLYvXq1SI1NdWZ5TmVqX2xe/duUVFRIYQQYsWKFeKpp55yRZlOYWpfCCFETU2N\n6Nu3r0hNTRUbNmxwQZXOYWpfaDQaERYWJrKzs4UQwuC+8ham9kVmZqaYNGmSEEKIkpISERQUJDQa\njStKdai8vDxx4MABERYWZvB9a3LTaS1+cy7mys/Px6hRoxAQEIC0tDQcO3bMWeU5lTn7ok+fPtqT\n46mpqcjNzXV6nc5g7kV+GRkZGDVqFFq2bOnsEp3GnH2xb98+REREYMCAAQDgtefMzNkXfn5+uHr1\nKqqrq1FeXo7GjRtDURRXlOtQiYmJ8Pf3N/q+NbnptOA352KuvXv3IjQ0VPu8ZcuWKCoqclaJTmPp\nhW0ffvih1143Yc6+OHv2LL744gtMmjQJALzylxswb19s27YNiqIgMTERw4cPx7Zt25xdplOYsy/S\n0tJQW1uLwMBAJCQkYNWqVc4u0y1Yk5t2Gc5pL0IIvaGh3vpLbq4dO3Zg5cqV2L17t6tLcZnnn38e\nCxcuhKIoBo8RNamqqsKhQ4ewY8cOXL9+HQMHDsTRo0fRqFEjV5fmdO+99x58fHxw/vx5FBYWIjU1\nFadPn0a9euqadNia3HTaHurdu7fOSYfvv/8ecXFxOsvExsbihx9+0D4vLS1FUFCQs0p0GnP2BQAc\nOXIEEydORFZWFpo3b+7MEp3GnH2xf/9+jB49Gg888AA2btyIyZMnIysry9mlOpw5+6JPnz4YOnQo\n2rRpg6CgIERHRyMvL8/ZpTqcOfsiLy8PTz75JBo3bozY2Fi0a9fOqwdBGGNNbjot+O++mKukpATZ\n2dmIjY3VWSY2NhYbN27E5cuXsXr1aoSEhDirPKcyZ1+cOXMGI0eOxKpVq9ClSxdXlOkU5uyLn376\nCcXFxSguLsaoUaOQmZmJESNGuKJchzJnX8TFxSE3NxfXr19HeXk5Dh48iPj4eFeU61Dm7Iv+/ftj\n8+bN0Gg0+Omnn1BeXq7TPaQW1uSmU7t6bl/MVV1djWnTpiEwMBDLli0DAKSnpyMmJgYJCQmIjo5G\nQEAAVq5c6czynMrUvnj11VdRXl6OiRMnAgAaNGiAvXv3urJkhzG1L9TE1L5o0aIFxo8fj+joaLRs\n2RKvvvoqmjZt6uKqHcPUvhg9ejR++OEH7b549913XVyxY6SlpSE3NxdlZWXo0KED5s+fj+rqagDW\n5yYv4CIiUhl1nQUhIiIGPxGR2jD4iYhUhsFPRKQyDH4iIpVh8BMRqQyDn4hIZRj8REQq8/8Beea0\nop6JcSoAAAAASUVORK5CYII=\n", + "png": "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\nXHrhBXjySXMtgQsKfvE3h2WFauxaSQ6HgwpSioSRGjXM7MY1anjwpNOnzc1Zdu2CGwJ816utWyEp\nCXJzoU4dl6ucPw/165uvItfyJjvVjpCw53F7ok4dczHX4sUBqaeE6dMhPb3U0Ae1+MX/vD6cTp06\nxV133UXz5s25++67OX36tMv1WrZsSVxcHPHx8SQmJnpdqIg3vOrqARg1ChYs8Hs9Jezcaa4UfvTR\nMlfTVbvib14H/6xZs2jevDk7duygadOmvPHGGy7XczgcZGRksGHDBrKzs70uVCSohg2D9evh0KHA\nbePFF03o16tX5mq6alf8zevDKTs7m4ceeogaNWowZswYssq4iYX67iVUvG7x16wJ99wDc+b4uyTj\nn/+EJUtMN0851NUj/hbh7RNzcnKIjY0FIDY2ttTWvMPhYODAgbRq1YoxY8YwYsQIbzcp4jGHAxYu\n9PDk7iWRLR+h18uj+Kjl7/yevL1e/ldODHqSrSsjy133zBkFv/hXmcE/aNAgDh8+7PTzF154we1W\n/FdffcWNN97I1q1bGT58OImJiTRu3NjlulOnTi3+d1JSEklJSW5tQ6Q0v/mND0PyrQTaXqjL9tmf\ns7nRbX6rqXX+OgZ99xV/aDKHC26eP374Yb9tXiq5jIwMMjIyfHoNr4dzjhw5kmeeeYb4+HjWr1/P\niy++yMKFC8t8zqRJk+jQoQOPPPKIcyEazikV0euvmzn633/ff685aBCkpEBamv9eU2wrqMM5e/To\nwdtvv825c+d4++236dmzp9M6Z8+e5dSlOxrl5eWxYsUKhg4d6u0mRYLv/vvhs89gzx7/vN5HH8G+\nfaVepSsSDF4H/7hx49i3bx/t27fnwIEDjB07FoCDBw+SnJwMwOHDh+nbty9dunRh1KhRPPnkkzRr\n1sw/lYsEw/XXm36Wl17y/bXOnYMJE2DmTJdz8ogEi67cFSnPoUPQsaMZidOwofevM3UqbNkS3Okg\nJOx5k50KfhF3pKdDYSG89pp3z9+2zdzQ/dtvoWlT/9YmtqbgFwmUY8cgNhbWrIF27Tx77oUL0KsX\nPPIIXOoSFfEXzdUjEihRUfD00zBunLmiyhPPPgtNmmgUj1QYCn4Rdz3+uJm5s5TpSVx6/32YNw/+\n53804Y5UGOrqEfHEtm3Qrx/87//CrbeWvW5mphmvv3IldOkSnPrEdtTVIxJosbHw17/CL38JGzaU\n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\n", "text": [ - "" + "" ] } ], - "prompt_number": 16 + "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ - "x = np.array([1,2,3])\n", - "l = 1*np.ones(x.shape)\n", - "u = 2*np.ones(x.shape)\n", "\n", - "activeSet = np.logical_or(x ==l, x == u)\n", "\n", - "import scipy.sparse as sp\n", - "shape = (x.size, np.sum(activeSet))\n", - "print shape\n", - "print (np.arange(shape[1]), np.where(activeSet)[0])\n", - "print (np.ones(shape[1]), (np.arange(shape[1]), np.where(activeSet)[0]))\n", - "rI = sp.csr_matrix((np.ones(shape[1]), (np.arange(shape[1]), np.where(activeSet)[0])), shape=shape)\n", - "print rI.todense()\n", - "\n" + "def Quadratic(x, return_g=True, return_H=True):\n", + " A = sp.identity(2)\n", + " b = np.array([-5,-5])\n", + " f = 0.5 * x.dot( A.dot(x)) + b.dot( x )\n", + " out = (f,)\n", + " if return_g:\n", + " g = A.dot(x) + b\n", + " out += (g,)\n", + " if return_H:\n", + " H = A\n", + " out += (H,)\n", + " return out\n", + "\n", + "\n", + "f = Quadratic(np.array([1,2]))\n", + "print f\n", + "n = 30\n", + "l = -10\n", + "u = 10\n", + "I = np.zeros((n,n))\n", + "X = np.linspace(l,u,n)\n", + "for i, x in enumerate(X):\n", + " for j, y in enumerate(X):\n", + " f, g, H = Quadratic(np.array([x,y]))\n", + " I[i,j] = f\n", + "\n", + "contourf(X,X, I.T)\n", + "\n", + "GN = inverse.GaussNewton()\n", + "xopt = GN.minimize(Quadratic,np.array([0,0]))\n", + "print xopt" ], "language": "python", "metadata": {}, @@ -125,16 +203,47 @@ "output_type": "stream", "stream": "stdout", "text": [ - "(3, 2)\n", - "(array([0, 1]), array([0, 1]))\n", - "(array([ 1., 1.]), (array([0, 1]), array([0, 1])))\n", - "[[ 1. 0.]\n", - " [ 0. 1.]\n", - " [ 0. 0.]]\n" + "(-12.5, array([-4., -3.]), <2x2 sparse matrix of type ''\n", + "\twith 2 stored elements (1 diagonals) in DIAgonal format>)\n", + "=============== Gauss Newton ===============" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " # f |g| LS \n", + "-------------------------------------------\n", + " 1 0.00e+00 7.07e+00 0 \n", + "------------------------- STOP! -------------------------\n", + "0 : |fc-fOld| = 2.5000e+01 <= tolF*(1+|f0|) = 1.0000e-01\n", + "0 : |xc-x_last| = 7.0711e+00 <= tolX*(1+|x0|) = 1.0000e-01\n", + "1 : |g| = 0.0000e+00 <= tolG = 1.0000e-01\n", + "1 : |g| = 0.0000e+00 <= 1e3*eps = 1.0000e-02\n", + "0 : maxIter = 20 <= iter = 1\n", + "------------------------- DONE! -------------------------\n", + "[ 5. 5.]\n" + ] + }, + { + "output_type": "stream", + "stream": "stderr", + "text": [ + "/Users/rowan/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/sparse/linalg/dsolve/linsolve.py:87: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n", + " warn('spsolve requires A be CSC or CSR matrix format', SparseEfficiencyWarning)\n" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAEACAYAAABWLgY0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAFEdJREFUeJzt3V9s1OWex/HPoIB7AUTUlCalYHrQFk9lq1vauFIRhVQN\nUM5erF5oAoQgNcGINHuBcR8v0GhigjQI9WjZq0M2JhDhgr/GhkhC21Uw55ASQSQkxn9oAjV6Lkh+\newEttJ1p58/vN8+f3/uVNDjTzjzflOY9D8/M1EwURZEAAEGaZHsAAEByiDwABIzIA0DAiDwABIzI\nA0DAiDwABKzkyK9Zs0YVFRWqr68fvm5wcFArV65UdXW12tra9Ntvv5W6DACgCCVHfvXq1Tp06NCI\n63bu3Knq6mqdO3dOVVVV2rVrV6nLAACKUHLkFy1apDvvvHPEdX19fVq7dq2mTp2qNWvWqLe3t9Rl\nAABFSORMvr+/X7W1tZKk2tpa9fX1JbEMAGACiUSe35QAAG64PYk7bWxs1MDAgBoaGjQwMKDGxsYx\nXzPrT/+iH7/5ZxLLA0CwampqdP78+by/PpHINzU1qbu7W++88466u7vV3Nw85mt+/Oaf+iRalvd9\n7tL6OEeMzcHjf7E9wnW7jbTaFHabAr88NT7rlfRXSetsTxIQvp9x+eabsT0dT8nHNc8995weeeQR\nff3115o9e7Z2796tDRs26NKlS7r//vv13Xff6cUXXyxpDQKfAGN7AAd91nsj8EA4St7J79mzJ+v1\nn3zySal37TQCHxjijkAlclwTJ1d38c7518X5fZ1JcggP5Yz7Q2UdI3x8P23h1xoUwcldfMNi2xP4\nZ9zd+8NlGyMd+H7a4nTk2cXHzNgewCEczyAlnI68i5zcxefD2B7AIQQeKeJs5NnFIxEEHinjbORd\nxC7ecwQeKeT8q2tQImN7AAcQd6SYkzt5F49qvN3Fpx2BR8o5GXnExNgewDICD7gXeXbxiAWBByQ5\nGHnExNgewCICDwwj8hPwchdvbA9gEYEHRnAq8i4e1QCAz5yKPGJgbA9gEbt4YAwiPw4vj2rSisAD\nWTkTeY5qYmBsD2AJgQdycibyrmEX7wkCD4yLyIfC2B4AgIuciDxHNSgKu3hgQk5E3jXeHdUY2wNY\nQOCBvBB5AAiY9chzVIOCsYsH8mY98q7hqMZxBB4oCJEHgIAReZ8Z2wOUGbt4oGBWI+/aebx3RzUA\nMAF28vADu3igKETeV8b2AGVE4IGiEXkACBiRv4HzeAAhIvJwG0c1QEmIvI+M7QEA+ILIw13s4oGS\nEXkACBiRl2dPuhrbAwDwCZGHmziqAWJB5AEgYEQeAAJG5AEgYEQe7uE8HogNkfeJsT0AAN+kPvJe\nvXwSAAqU+sgDQMiIPAAEjMjDLTzpCsSKyANAwIg8AATs9iTvfO7cuZo+fbpuu+02TZ48WX19fUku\nBwAYJdHIZzIZ9fT0aObMmUkuAwDIIfHjmiiKkl4CAJBDopHPZDJasmSJ2tratH///iSXAgBkkehx\nzYkTJ1RZWamBgQEtX75cCxcu1KxZs4Y/f8787/B/z1z8gO5a/OckxwEAD30h6cuib51o5CsrKyVJ\ndXV1WrFihQ4cOKB169YNf36e+c8klweAADx842PIRwXdOrHjmt9//12Dg4OSpJ9//lmHDx9Wa2tr\nUssBALJIbCf/448/atWqVZKku+66S6+++qpmz56d1HIAgCwSi/y9996r06dPJ3X3AIA88I5XAAgY\nkQeAgBF5AAgYkYdbHm+yPQEQFCIPAAEj8gAQsNRH/qmWvbZHAIDEpD7yXjG2BwDgGyIP9/DkKxAb\nIg8AASPyABAwIg83cWQDxILI+8bYHgCAT4i8eBklgHARebiLIxugZEQeAAJG5H1kbA8AwBdEHm7j\nyAYoCZG/gSdfAYSIyPvK2B6gjNjNA0Uj8gAQMCJ/C45sHMZuHiiK1ci/qC6bywNA8NjJ+8zYHqDM\n2M0DBSPyABAwIj+Kd+fyxvYAZcZuHiiI9chzLo+CEXogb9YjjxgY2wNYQOiBvBD5LLw7sgGAHJyI\nPEc2KAq7eWBCTkQeMTC2B7CE0APjIvI5cGQDIATORJ4jmxgY2wNYwm4eyMmZyLuI3bxHCD2QFZEP\njbE9gEWEHhjDqci7eGTj5W7e2B7AIkIPjOBU5IFYEHpgGJEPlbE9gGWEHpDkYOQ5sgGA+DgXecTI\n2B7AMnbzgJuRZzeP2DzeROyRak5GHjEytgdwBKFHSjkbeXbzMTK2B3AEoUcKORt5IBGEHilD5AvE\nbj4AhB4p4nTkXTyy8ZqxPYBDCD1SwunIu8rb3TxGIvRIgcQif/z4cdXV1WnevHnq7Ows+n5c3c17\nG3pjewDH8BJLBC6xyL/88svq6urSsWPHtGPHDl2+fDmppVAoY3sABxF6BCqRyF+5ckWS1NLSojlz\n5mjZsmXq7e0t+v7YzSfA2B7AQezqEaBEIt/f36/a2trhy/Pnz9fJkyeTWAqlMLYHcBShR0CsPvG6\nx5wf/vh7z6/jfi27+YQY2wM4il09nPGFpL9Kcw9e/yjQ7fEPJDU2Nqqjo2P48pkzZ9Ta2jrm654z\nf0pi+bJ7qmWvDh7/i+0xkITHm6TPij9qBEr3sPR4+82LF98o6NaJ7ORnzJgh6forbC5evKijR4+q\nqan0XZGru3nvGdsDOI5dPWyJ4WcvseOabdu2af369XryySfV3t6uu+++O6mlnMCxTQoQepRTTD9v\nmSiKoljuqdCFMxl9Ei0r6ra7tD7maeLj/bGNsT2AJzjCQVImivtnGRWSbS/f8cqxTYKM7QE8wREO\n4pbQz5SXkXeZ98c2EqEvBLFHqRL+GfLyuGYIxzYJM7YH8BDHOMhXsWFPw3GND9jRpxQ7e0ykzD8j\nXkees/kyMLYH8BSxx2iWfia8Pq4ZwrFNGRjbAwSAo5z0SSLqHNe4JYhjG4nIx4HdfXo49HcdxE5e\ncns3L7GjRw7s7sNRrqindSfP+XyZGNsDBMahHR+KMPT35/DfYTA7eYndfFkZ2wMEjh2+22xGvcCd\nfFCRlwh9WRnbA6QEwXeDK7v1tEdeIvRlZWwPkDIEv3xcifpoRN79yEuBhV4i9rYQ/fi4GvXRiPx1\nhN4CY3sAEP0C+RL2WxH5mwi9Bcb2ABiB6N/kY9CzIfIjEXoLjO0BMKGQ4x9KzHMpMPKJ/D9ekXJm\n1J9wz3ghdP0BIPSIxyz4nbzEbt4qY3sAJK6UBwWCXTiOa7Ij9BYZ2wMAAUnrrzWYiA+/9iCYX2Y2\nmhGhByxJTeQlQm+dsT0AkD6pirwvgg+9sTwDkCKpi7wPu3kp8NBLhB4ok9Q88TqaD0/EDgn2Cdkh\nxvYAgEd44jU/vuzoJXb1AIqX2shLhN4pRsQeSECqIy8ReucYEXsgRqmPvETonWRsDwCEgcjfQOgd\nZETsgRIR+VsQekcZEXugSFZfQhmdlvYvsPcyylx4eaXjjO0BAIt8+gVl0enr/03oS0fsgZTwMfIS\noY9DKkMvEXuki6+Rlwh9HFIbeonYIx18jrxE6ONC7IFA+R55idDHJdWhl4g9wsTvrkmGTy+vHJKq\nl1lmY0TokXpO7uQlN3fzkp87eold/TBjewCgRCEc1wwh9PEi9LcwtgcAihRS5CVCHzdCP4qxPQBQ\noNAiLxH6JBD7LIztAYA8hBh5idAngdCPw9geAMgh1MhLhD4pxH4CxvYAgG7+HD4WcOQld0Mv+R17\nQp8HY3sApI7Jcl3okZcIfZKIfZ6M7QEQLDPB59MQeYnQJ4nQF8HYHgBeMwV8bVoiLxH6pBH7Ihnb\nA8B5poTbuhB5Y4w+/PBD3XPPPZKkt956S62trSMXjiHyEqEvB2JfImN7AFhnYrwvFyL/xhtvaNq0\nadq0aVPuhWOKvOR26CVij1GM7QFQFiah+y0w8rcnNEZBQ5RqxVdHnA79i+oKIvRPtewl9HEwE1yG\nf4ztAXJLbCe/e/duzZo1S6tWrVJ7e7umTZs2cuEYd/JDXA69FM6OXmJXnyhjewBMyFhcu1zHNUuX\nLtUPP/ww5vqtW7equblZ99xzj65evaqOjg7dd9992rx588iFMxn99y3NW/xv0uLGYiYZyfXQS8Qe\nRTC2B0gxY3n9Uz3S6Z6bl//nDftn8rf66quv1N7erhMnToxcOIGd/BBCX37E3hJje4CAGNsD5MmF\nJ16///57VVZW6tq1a9qyZYumT5+uLVu2jFw4wcgPcT32oYVeIvZOMbYHcJCxPUAMXIj8Cy+8oNOn\nT2vKlClqaWnRa6+9ppkzZ45cuAyRl9wPvUTsYYmxPUACjO0BysCFyOe1cJkiLxF6m4h9gEyga/mC\nyGdH6O0i9kBMiHxuPoReIvYAxkHkJ+ZD7EMOvUTsgaIR+fz4EHqJ2AMYhcjnj9C7g9gDeSLyhfEl\n9FI6Yi8RfGBcRL5wPoVeIvZAqhH54vkU+7SEXiL2wAheRf45Sf9lY/XcfAq9lK7YSwQf8C/yEqGP\nQdpiLxF8pJSXkZecC73kX+zTGHqJ2CNlvI28ROhjktbYSwQfKeB15IcQ+1ikOfYSwUeggoi8ROhj\nlPbYSwQfAQkm8hKhjxGhv4ngw2tBRV5yMvQSsQ8FwYd3gou8ROgTQOyzI/pwXpCRH0LsY0fscyP4\ncM1TLXt1MPMfAUdeIvQJIfYTI/oot6da9o65LvzIS86GXiL2aUL0EbdsUR8tHZEf4mjsfQ+9ROyL\nQfRRqHyiPlq6Ii85G3qJ2IPw46Zigp5N+iIvOR16KYzYSwQ/LoQ/fHEFPZt0Rn6Iw7EPJfQSsU8C\n4fdXkkHPJt2Rl5wOvUTsURji745yxzwXIi85H3qJ2KN0PADEz5WQj4fI38rx2IcU+iEE3x08CIzl\nQ8QnQuRHczz0ErGHfT4/IIQQ7kIQ+VyIvTUEH4gPkR+PB6GXiD2A3Ih8Poi9dQQfKA6RzxehdwbB\nB/JH5AtF7J1B7IGJEflieBJ6KR2xlwg+kAuRLwWxdxLBB27yKvKfS/p3Ql+SNMVeIviAd5GXHAy9\nROw9QfSRNl5GfgixL11aYy8RfKSD15GXCH1c0hx7ieAjXN5Hfgixj0/agy8RfYQjmMhLjoZeIvYB\nIPrwVVCRH+Jk7D0NvUTsRyP48EmQkZccDb1E7ANF+OGqYCM/hNgng+CPj+jDlhfVNeLyysyRsCMv\nORx6idinCOFH3EYHPZtURH4IsU8OsS8O4Ue+8gl6NmWL/McffyxjjM6ePav+/n499NBDw5/bvn27\nOjs7NXnyZH3wwQd69NFHxy4cQ+QlQl8OBL80hB/FBj2bskX+7NmzmjRpktavX6933313OPI//fST\nWlpadOTIEX377bd65ZVX9OWXX45dOKbID0l77Hv6pcWNya+TluD/vedX1S+emegaaYr/Lz3/0F2L\n/2x7jMTFGfNcCo387cUuVFtbm/X63t5etba2qrq6WtXV1YqiSIODg5o2bVqxS+XlxB6HQ//2jT8T\njH3P/5Un8iu+OiIp/Nj/owyRHy8IoT0A/NpzJpjIlyPkcSo68rn09fWprq5u+PL999+vvr4+PfHE\nE3EvNcaJPdf/THPsy2Uo9lL4wbchTQ8ALvIt5OMZN/JLly7VDz/8MOb6N998U8uXL896m2z/jMhk\nMkWOVxynd/VSULGX0rO7d8VEAeJBID8hhXxcUYkWL14cffHFF8OX9+/fH23cuHH48oIFC6KrV6+O\nuV1NTU0kiQ8++OCDjwI+ampqCmp0LMc10S2794ULF6qjo0OXLl3ShQsXNGnSpKzn8efPn49jaQDA\nOIqO/L59+7Rx40ZdvnxZzzzzjBoaGnTw4EFVVFRow4YNWrJkiaZMmaKurpT8kwgAHGTtzVAAgORN\nKveCH3/8sR544AHddtttY14/v337ds2bN0/z58/X55/H+Sr6dDDGqKqqSg0NDWpoaNChQ4dsj+Sd\n48ePq66uTvPmzVNnZ6ftcbw3d+5cPfjgg2poaNDChQttj+OdNWvWqKKiQvX19cPXDQ4OauXKlaqu\nrlZbW5t+++23ce+j7JGvr6/Xvn371NLSMuL6n376Se+//74+/fRT7dy5Uxs3biz3aN7LZDLatGmT\nTp06pVOnTqm1tdX2SN55+eWX1dXVpWPHjmnHjh26fPmy7ZG8lslk1NPTo1OnTqmvr8/2ON5ZvXr1\nmM3azp07VV1drXPnzqmqqkq7du0a9z7KHvna2lrdd999Y66/9U1Ujz322PCbqFAYTt+Kd+XKFUlS\nS0uL5syZo2XLlqm3t9fyVP7jZ7J4ixYt0p133jniur6+Pq1du1ZTp07VmjVrJvwZLXvkc8n1JioU\nprOzU83NzXr77bd5kCxQf3//iHdyz58/XydPnrQ4kf8ymYyWLFmitrY27d+/3/Y4Qbj157S2tnbC\nTsb+jlfJ3zdR+SDX93br1q3asGGDXn/9dV29elUdHR3q6urS5s2bLUwJXHfixAlVVlZqYGBAy5cv\n18KFCzVr1izbY3mt0H8ZJRL5o0ePFnybpqYmHTt2bPjy2bNn1dhYhl/G4pl8vrczZszQSy+9pPb2\ndiJfgMbGRnV0dAxfPnPmDM9rlKiyslKSVFdXpxUrVujAgQNat26d5an81tjYqIGBATU0NGhgYGDC\nTlo9rhn9JqrDhw/r0qVL6unpyfkmKuT2/fffS5KuXbumv/3tb3r66actT+SXGTNmSLr+CpuLFy/q\n6NGjampqsjyVv37//ffhI8Off/5Zhw8f5kEzBk1NTeru7tYff/yh7u5uNTc3j3+Dgn+PQYn27t0b\nVVVVRXfccUdUUVERtba2Dn9u27ZtUU1NTVRXVxcdP3683KN57/nnn4/q6+ujhx9+OHrllVeiX375\nxfZI3unp6Ylqa2ujmpqa6L333rM9jtcuXLgQLViwIFqwYEG0ZMmS6KOPPrI9kneeffbZqLKyMpoy\nZUpUVVUVdXd3R1evXo1WrFgRzZ49O1q5cmU0ODg47n3wZigACJgzr64BAMSPyANAwIg8AASMyANA\nwIg8AASMyANAwIg8AASMyANAwP4fypiXapu5o/wAAAAASUVORK5CYII=\n", + "text": [ + "" ] } ], - "prompt_number": 61 + "prompt_number": 3 }, { "cell_type": "code", @@ -143,24 +252,72 @@ "\n", "\n", "class ProjectedGradient(Minimize):\n", - " name = 'InexactGaussNewton'\n", + " name = 'Projected Gradient'\n", "\n", " maxIterCG = 10\n", - " tolCG = 1e-5\n", + " tolCG = 1e-3\n", " \n", - " lower = -0.5\n", - " upper = 1. # ensure these are vectors that are the same size.\n", + " lower = -0.4\n", + " upper = 0.9\n", " \n", - " explore = False\n", + " def __init__(self,**kwargs):\n", + " super(ProjectedGradient, self).__init__(**kwargs)\n", + " \n", + " self.stoppers.append({\n", + " \"str\": \"%d : probSize = %3d <= bindingSet = %3d\",\n", + " \"left\": lambda M: M.xc.size,\n", + " \"right\": lambda M: np.sum(M.bindingSet(M.xc)),\n", + " \"stopType\": \"critical\"\n", + " })\n", + " \n", + " self.stoppersLS.append({\n", + " \"str\": \"%d : probSize = %3d <= bindingSet = %3d\",\n", + " \"left\": lambda M: M._LS_xt.size,\n", + " \"right\": lambda M: np.sum(M.bindingSet(M._LS_xt)),\n", + " \"stopType\": \"critical\"\n", + " })\n", + " \n", + " self.printers.append({\"title\": \"itType\",\n", + " \"value\": lambda M: M._itType,\n", + " \"width\": 8, \"format\": \"%s\"})\n", + " self.printers.append({\"title\": \"aSet\",\n", + " \"value\": lambda M: np.sum(M.activeSet(M.xc)),\n", + " \"width\": 8, \"format\": \"%d\"})\n", + " self.printers.append({\"title\": \"bSet\",\n", + " \"value\": lambda M: np.sum(M.bindingSet(M.xc)),\n", + " \"width\": 8, \"format\": \"%d\"})\n", + " self.printers.append({\"title\": \"Comment\",\n", + " \"value\": lambda M: M.projComment,\n", + " \"width\": 7, \"format\": \"%s\"})\n", + " \n", "\n", - " def projection(self, p):\n", + " def _startup(self, x0):\n", + " # ensure bound vectors are the same size as the model\n", + " if type(self.lower) is not np.ndarray:\n", + " self.lower = np.ones_like(x0)*self.lower\n", + " if type(self.upper) is not np.ndarray:\n", + " self.upper = np.ones_like(x0)*self.upper\n", + " \n", + " self.explorePG = True\n", + " self.exploreCG = False\n", + " self.stopDoingCG = False\n", + " \n", + " self._itType = 'SD'\n", + " \n", + " self.aSet_prev = self.activeSet(x0)\n", + " \n", + " def projection(self, x):\n", " \"\"\"Make sure we are feasible.\"\"\"\n", - " return np.median(np.c_[l,x,u],axis=1)\n", + " return np.median(np.c_[self.lower,x,self.upper],axis=1)\n", " \n", " def activeSet(self, x):\n", " \"\"\"If we are on a bound\"\"\"\n", " return np.logical_or(x == self.lower, x == self.upper)\n", " \n", + " def inactiveSet(self, x):\n", + " \"\"\"The free variables.\"\"\"\n", + " return np.logical_not(self.activeSet(x))\n", + " \n", " def bindingSet(self, x):\n", " \"\"\"\n", " If we are on a bound and the negative gradient points away from the feasible set. \n", @@ -174,34 +331,361 @@ " \n", " def findSearchDirection(self):\n", " self.aSet_prev = self.activeSet(self.xc)\n", + "# print 'fsd: stopDoingCG: ', self.stopDoingCG\n", " if self.explorePG or not self.exploreCG:\n", + "# print 'fsd: doingCG'\n", + " self._itType = 'SD'\n", " p = -self.g\n", " else:\n", - " Z = I_something\n", + " self.f_decrease_max = -np.inf # Reset the max decrease each time you do a CG iteration\n", + " self._itType = '.CG.'\n", + " iSet = self.inactiveSet(self.xc) # The inactive set (free variables)\n", + " aSet = self.activeSet(self.xc)\n", + " bSet = self.bindingSet(self.xc)\n", + " shape = (self.xc.size, np.sum(iSet))\n", + " v = np.ones(shape[1])\n", + " i = np.where(iSet)[0]\n", + " j = np.arange(shape[1])\n", + " Z = sp.csr_matrix((v, (i, j)), shape=shape)\n", " def reduceHess(v):\n", " # Z is tall and skinny\n", - " Z.T*self.H(Z*v)\n", - " \n", - " p, info = sp.linalg.cg(reduceHess, -Z.T*self.g, tol=self.tolCG, maxiter=self.maxIterCG)\n", - " p = Z*p # bring up to full size\n", + " return Z.T*(self.H*(Z*v))\n", + " operator = sp.linalg.LinearOperator( (shape[1], shape[1]), reduceHess, dtype=float )\n", + " p, info = sp.linalg.cg(operator, -Z.T*self.g, tol=self.tolCG, maxiter=self.maxIterCG)\n", + " p = Z*p # bring up to full size\n", " aSet_after = self.activeSet(self.xc+p)\n", " return p\n", " \n", - " def doEndIteration(self, xt):\n", - " aSet = self.activeSet(self.xc)\n", - " bSet = self.bindingSet(self.xc)\n", - " # implement 3.8\n", - " self.f_last - self.f <= self.eta_2 * max_decrease # where max decrease\n", - " # if true go to CG\n", - " # don't do too many steps of PG in a row.\n", + " def _doEndIteration(self, xt):\n", + " aSet = self.activeSet(xt)\n", + " bSet = self.bindingSet(xt)\n", " \n", " self.explorePG = not np.all(aSet == self.aSet_prev) # explore proximal gradient\n", - " self.exploreCG = np.all(aSet == bSet) # explore conjugate gradient" + " self.exploreCG = np.all(aSet == bSet) # explore conjugate gradient\n", + " \n", + " f_current_decrease = self.f_last - self.f\n", + " self.projComment = ''\n", + "# print f_current_decrease\n", + " if self._iter < 1:\n", + " self.f_decrease_max = -np.inf\n", + " else:\n", + " # Note that I reset this if we do a CG iteration.\n", + " self.f_decrease_max = max(self.f_decrease_max, f_current_decrease)\n", + " self.stopDoingCG = f_current_decrease < 0.25 * self.f_decrease_max\n", + "# print 'f_decrease_max: ', self.f_decrease_max\n", + "# print 'stopDoingCG: ', self.stopDoingCG\n", + " if self.stopDoingCG:\n", + " self.projComment = 'Stop SD'\n", + " self.explorePG = False\n", + " self.exploreCG = True\n", + " # implement 3.8, MoreToraldo91\n", + " #self.eta_2 * max_decrease # where max decrease\n", + " # if true go to CG\n", + " # don't do too many steps of PG in a row." ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 64 + "prompt_number": 12 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "opt = ProjectedGradient(maxIter=20,maxStep=0.2, maxIterLS=20)\n", + "\n", + "opt.lower = np.array([-1,-1])\n", + "opt.upper = np.array([1,1])\n", + "opt.minimize(Quadratic,np.array([0,0.2]))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "=========================== Projected Gradient ===========================\n", + " # f |g| LS itType aSet bSet Comment\n", + "--------------------------------------------------------------------------\n", + " 1 -9.80e-01 6.93e+00 0 SD 0 0 \n", + " 2 -2.86e+00 6.65e+00 0 .CG. 0 0 \n", + " 3 -4.67e+00 6.38e+00 0 .CG. 0 0 \n", + " 4 -6.40e+00 6.10e+00 0 .CG. 0 0 \n", + " 5 -8.05e+00 5.82e+00 0 .CG. 2 2 \n", + "------------------------- STOP! -------------------------\n", + "0 : |fc-fOld| = 9.4851e-01 <= tolF*(1+|f0|) = 1.9800e-01\n", + "0 : |xc-x_last| = 2.0254e-01 <= tolX*(1+|x0|) = 1.2000e-01\n", + "0 : |g| = 1.4142e+00 <= tolG = 1.0000e-01\n", + "0 : |g| = 5.6569e+00 <= 1e3*eps = 1.0000e-02\n", + "0 : maxIter = 20 <= iter = 5\n", + "1 : probSize = 2 <= bindingSet = 2\n", + "------------------------- DONE! -------------------------\n" + ] + }, + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 13, + "text": [ + "array([ 1., 1.])" + ] + } + ], + "prompt_number": 13 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "opt = ProjectedGradient(maxIter=50, maxStep=0.3,debug=False, maxIterLS=20, tolCG=1e-5, maxIterCG=1000)\n", + "opt.lower = -0.4\n", + "opt.upper = 0.9\n", + "inv = inverse.Inversion(prob,reg,opt,beta0=1e-4)\n", + "m0 = np.zeros_like(m_true)\n", + "\n", + "mrecB = inv.run(m0)\n", + "\n", + "\n", + "plt.figure(2)\n", + "\n", + "plt.plot(M.vectorCCx, m_true, 'b-')\n", + "plt.plot(M.vectorCCx, mrecB, 'r-')\n", + "\n", + "plt.figure(3)\n", + "\n", + "plt.plot(M.vectorCCx, m_true, 'b-')\n", + "plt.plot(M.vectorCCx, mrec, 'r-')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "=============================================== Projected Gradient ===============================================\n", + " # beta phi_d phi_m f |g| LS itType aSet bSet Comment\n", + "-----------------------------------------------------------------------------------------------------------------\n", + " 1 1.00e-04 9.56e+02 5.53e-03 9.57e+02 1.01e+04 10 SD 0 0 \n", + " 2 1.00e-04 5.34e+02 1.46e+03 9.56e+02 9.45e+03 0 .CG. 0 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 3 1.00e-04 2.33e+02 5.85e+03 5.34e+02 7.06e+03 0 .CG. 0 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 4 1.00e-04 1.35e+02 9.13e+03 2.34e+02 4.66e+03 1 .CG. 18 18 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 5 1.00e-04 1.29e+02 9.13e+03 1.36e+02 8.72e+03 10 SD 18 18 \n", + " 6 1.00e-04 1.10e+02 1.30e+04 1.30e+02 3.33e+03 1 .CG. 59 0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 7 1.00e-04 6.32e+01 1.30e+04 1.11e+02 2.29e+04 9 SD 59 59 \n", + " 8 1.00e-04 6.02e+01 1.34e+04 6.45e+01 1.14e+03 4 .CG. 79 9 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 9 1.00e-04 5.86e+01 1.34e+04 6.15e+01 4.44e+03 11 SD 77 77 Stop SD\n", + " 10 1.00e-04 4.10e+01 1.59e+04 6.00e+01 1.56e+03 2 .CG. 117 17 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 11 1.00e-04 4.06e+01 1.59e+04 4.26e+01 2.11e+03 12 SD 106 106 \n", + " 12 1.00e-04 4.06e+01 1.59e+04 4.22e+01 8.79e+02 14 SD 13 13 Stop SD\n", + " 13 1.00e-04 4.06e+01 1.59e+04 4.22e+01 3.39e+02 15 .CG. 117 116 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 14 1.00e-04 4.06e+01 1.59e+04 4.22e+01 3.61e+02 15 SD 116 116 Stop SD\n", + " 15 1.00e-04 3.03e+01 1.89e+04 4.22e+01 4.18e+01 2 .CG. 152 152 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 16 1.00e-04 2.86e+01 1.89e+04 3.22e+01 4.58e+03 11 SD 128 128 \n", + " 17 1.00e-04 2.85e+01 1.89e+04 3.05e+01 1.39e+03 13 SD 9 9 Stop SD\n", + " 18 1.00e-04 2.85e+01 1.89e+04 3.04e+01 1.06e+03 16 .CG. 30 30 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 19 1.00e-04 2.85e+01 1.89e+04 3.04e+01 1.06e+03 13 SD 131 131 Stop SD\n", + " 20 1.00e-04 2.84e+01 1.90e+04 3.04e+01 4.37e+02 8 .CG. 152 39 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 21 1.00e-04 2.84e+01 1.90e+04 3.03e+01 1.22e+03 13 SD 30 30 Stop SD\n", + " 22 1.00e-04 2.84e+01 1.90e+04 3.03e+01 1.22e+03 16 .CG. 37 17 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 23 1.00e-04 2.83e+01 1.90e+04 3.03e+01 1.22e+03 13 SD 131 131 \n", + " 24 1.00e-04 2.83e+01 1.90e+04 3.02e+01 2.77e+02 16 SD 34 34 \n", + " 25 1.00e-04 2.83e+01 1.90e+04 3.02e+01 4.10e+01 17 SD 146 146 Stop SD\n", + " 26 1.00e-04 2.74e+01 1.99e+04 3.02e+01 6.13e+01 4 .CG. 155 155 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 27 1.00e-04 2.60e+01 1.99e+04 2.94e+01 4.10e+03 12 SD 29 29 \n", + " 28 1.00e-04 2.60e+01 1.99e+04 2.80e+01 7.89e+02 13 SD 12 12 \n", + " 29 1.00e-04 2.59e+01 1.99e+04 2.80e+01 7.15e+02 14 SD 34 34 Stop SD\n", + " 30 1.00e-04 2.59e+01 1.99e+04 2.79e+01 5.00e+02 15 .CG. 46 29 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 31 1.00e-04 2.59e+01 1.99e+04 2.79e+01 5.00e+02 14 SD 118 118 Stop SD\n", + " 32 1.00e-04 1.27e+01 3.53e+04 2.79e+01 2.46e+02 0 .CG. 248 117 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 33 1.00e-04 1.25e+01 3.53e+04 1.63e+01 1.88e+03 12 SD 167 167 \n", + " 34 1.00e-04 1.24e+01 3.53e+04 1.61e+01 1.08e+03 14 SD 12 12 Stop SD\n", + " 35 1.00e-04 1.24e+01 3.53e+04 1.60e+01 1.45e+02 16 .CG. 148 148 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 36 1.00e-04 1.24e+01 3.53e+04 1.60e+01 1.49e+02 16 SD 156 156 Stop SD\n", + " 37 1.00e-04 1.24e+01 3.53e+04 1.60e+01 4.08e+01 14 .CG. 233 233 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 38 1.00e-04 1.24e+01 3.53e+04 1.60e+01 7.16e+01 18 SD 176 176 Stop SD\n", + " 39 1.00e-04 1.24e+01 3.53e+04 1.60e+01 2.20e+01 12 .CG. 243 241 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 40 1.00e-04 1.24e+01 3.53e+04 1.60e+01 1.63e+02 16 SD 185 185 \n", + " 41 1.00e-04 1.24e+01 3.53e+04 1.60e+01 2.89e+01 19 SD 206 206 \n", + " 42 1.00e-04 1.24e+01 3.53e+04 1.60e+01 2.48e+01 18 SD 221 221 Stop SD\n", + " 43 1.00e-04 1.23e+01 3.54e+04 1.60e+01 3.12e+01 6 .CG. 243 242 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 44 1.00e-04 1.23e+01 3.54e+04 1.59e+01 1.25e+03 13 SD 84 84 \n", + " 45 1.00e-04 1.22e+01 3.54e+04 1.59e+01 1.16e+03 13 SD 20 20 \n", + " 46 1.00e-04 1.22e+01 3.54e+04 1.58e+01 3.53e+02 15 SD 26 26 \n", + " 47 1.00e-04 1.22e+01 3.54e+04 1.58e+01 2.58e+02 15 SD 43 43 Stop SD\n", + " 48 1.00e-04 1.22e+01 3.54e+04 1.58e+01 1.18e+02 12 .CG. 211 100 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + " 49 1.00e-04 1.22e+01 3.54e+04 1.58e+01 1.04e+02 16 SD 187 187 \n", + " 50 1.00e-04 1.22e+01 3.54e+04 1.58e+01 7.87e+01 17 SD 137 137 Stop SD\n", + "------------------------- STOP! -------------------------\n", + "1 : |fc-fOld| = 1.6468e-04 <= tolF*(1+|f0|) = 9.5809e+01\n", + "1 : |xc-x_last| = 2.6492e-05 <= tolX*(1+|x0|) = 1.0000e-01\n", + "0 : |g| = 1.6964e+01 <= tolG = 1.0000e-01\n", + "0 : |g| = 7.2505e+01 <= 1e3*eps = 1.0000e-02\n", + "1 : maxIter = 50 <= iter = 50\n", + "0 : probSize = 1000 <= bindingSet = 120\n", + "------------------------- DONE! -------------------------\n" + ] + }, + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 17, + "text": [ + "[]" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "png": "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\nfiIim/l/mikG4O8fFLYAAAAASUVORK5CYII=\n", + "text": [ + "" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEACAYAAAC08h1NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8FGWex/FPQwC5BGICiNzhCCiBQAggV0C5jKAzxFky\nXi9QJ4BCFHFGZtwVHEVmd91V0UF0VpkRcFDA5XBHBDVBRZKAKIcwQDjlDESQU0JS+8cDgdCdpO9O\nur7v16teIenqrl+K6m+efuqppxyWZVmIiIhtVAl1ASIiElwKfhERm1Hwi4jYjIJfRMRmFPwiIjaj\n4BcRsRmfg3/MmDE0atSITp06uXw8IyODevXqER8fT3x8PM8//7yvmxQRER9E+PoCo0ePZsKECTzw\nwAOlrtO/f3+WLl3q66ZERMQPfG7x9+3blwYNGpS5jq4RExGpOALex+9wOFizZg1dunRh0qRJ5Obm\nBnqTIiJShoAHf9euXdm/fz85OTl07NiR9PT0QG9SRETKYvnB7t27rVtuuaXc9YqKiqyGDRta58+f\nd3osJibGArRo0aJFiwdLTEyMx5kd8Bb/kSNHivv4ly1bRlxcHDVq1HBaLzc3F8uytFgWzz77bMhr\nqCiL9oX2hfZF2Ys33ec+j+pJTU0lMzOTY8eO0axZM6ZNm0ZBQQEAaWlpLFy4kFmzZhEREUFcXBwv\nvfSSr5sUEREf+Bz87733XpmPP/roozz66KO+bkZERPxEV+5WQElJSaEuocLQvrhC++IK7QvfOCzL\nskJdBJhhnxWkFBGRSsOb7FSLX0TEZhT8IiI2o+AXEbEZBb+IiM0o+EVEbEbBLyJiMwp+ERGbUfCL\niNiMgl9ExGYU/CIiNqPgFxGxGQW/iIjNKPhFRGxGwS8iYjMKfhERm1Hwi4jYjIJfRMRmFPwiIjaj\n4BcRsRkFv4iIzSj4RURsJiLUBYjNnDkDy5fDzp3QogWMGAHXXx/qqkRsRS1+CZ4VK6B9e3jnHTh9\nGt5/33y/ZEmoKxOxFbX4JTgWLID0dHjvPRgw4MrPv/4aRo6En36C++8PXX0iNuKwLMsKdREADoeD\nClKK+Ft2Ntx5J6xaBXFxzo9v2wb9+pmWf69ewa9PpBLzJjvV1SOBdeoU/OpX8NZbrkMfIDYW/vIX\nuO8+OHs2uPWJ2JBa/BJY6emmG+edd8pf9957oVkzmDEj8HWJhAlvslPBL4GzcSMMGgTffw833FD+\n+ocOwS23wHffQdOmga9PJAwo+KViGTECBg6Exx93/zm/+x2cOAGzZweuLpEwouCXiiMrC+65B7Zv\nh+uuc/95+fnQpo35tKBWv0i5dHJXKo4ZM0zr3ZPQB4iMNCd5//znwNQlImrxSwDk5kKPHrB3L9Su\n7fnzd+yA3r1hzx6oVcvv5YmEE7X4pWJ49VV4+GHvQh+gbVtITDRX9oqI36nFL/518iS0auV7H/3i\nxeYPSEaG30oTCUchafGPGTOGRo0a0alTp1LXmTJlCq1bt6Zbt25s27bN101KRbZggZmSwdcTs3fe\nCVu2wK5d/qlLRIr5HPyjR4/m448/LvXx7OxsvvjiC9atW8fkyZOZPHmyr5uUiuydd2D0aN9fp3p1\nSE2Fv/3N99cSkRJ8Dv6+ffvSoEGDUh/PysoiJSWFyMhIUlNT2bp1q6+blIpq61ZzQnfoUP+83r33\nwt//DuoCFPGrgM/OmZ2dzf1XzboYHR1Nbm4uMTExgd60eKmoCL78EgoKPHtezFtzoN/95Gb66bAq\n6k7v/DN8+/b3nGl5s1cvERMDLVv6pxyRcBHw4Lcsy+nEg8PhcLnu1KlTi/+dlJREUlJSACuT0mzd\nCnfcYUZkusthFfHemnn8rssn7J3ur0qqML7GSE69sIh3W3ke/MeOmXu9LF3qr3pEQi8jI4MMHwc9\n+GVUz549exg+fDibNm1yemzmzJlcvHiRJ554AoCYmBhyc3OdC9Gongrju+/ggQfMV7d9+SWMH29G\n8/jTF1/Ao4969br/93/w2mvmq0i4qpDj+Hv06MGiRYs4fvw48+fPp0OHDoHepPjIsqCUD2Wle/99\nM/2yv916K+TlmakfRMQvfO7qSU1NJTMzk2PHjtGsWTOmTZtGwaXO4bS0NBITE+nTpw8JCQlERkYy\nd+5cn4uWwPI4+AsLYeFC+Pxz/xdTtSrcdRcsWwZPPunRUx0OnRcWccXn4H/vvffKXWfGjBnM0Bzr\nlYbHwf/VV9Cwobl/biDccQe88oqCX8RPNGWDOPE4+APVzXPZwIHm9o2nTgVuGyI2ouAXJx4Ff1GR\nmV4hJSVwBdWpAz17wqefevQ0tfhFXFPwixOPwnL9erj+emjXLmD1AKa7x4vhOQp+EWcKfnHiUYt/\n2TJzp61Auxz8HiS5xyOTRGxCwS9OPAr+pUuDE/zt2pkRPh4M61RXj4hrCn5x4nbw79sHBw5Ar14B\nrwmHw5zk/eyzwG9LJMwp+MWJ28G/bJnpgqlaNeA1AR4Hv1r8Iq4p+MWJR8E/fHjA6yk2YIC5SKyo\nyK3VFfwirin4xYlbwX/qFKxZA0OGBKUmwNzcJTISXMwJJSLuU/CLE7eC//PPoXt3qFs3KDUV86C7\nRy1+EdcU/OLEreBfuRIGDw5KPSUo+EV8puAXJxU6+JOSYPVquHgx+NsWCRMKfnFSbvDv2wf5+dC5\nc9BqKtawIdx0k1v9/Grxi7im4Bcn5Qb/ypVw221QJUSHT+/e5sYvblDwizhT8IsTt4I/FN08l/Xp\n41bwa8oGEdcU/OKkzOAvKoJVq2DQoKDWVMLl4C+nOa+uHhHXFPzipMzg37ABoqPNmPpQad3a/AHa\nu7fcVRX8Is4U/OKkzOD/5JPQdvOAKc6Nfn519Yi4puAXJ2UG/8qVoe3muaxPH3PLxzKoq0fENQW/\nuOQy+M+cgZwc6N8/6PU4cfMEr4g4U/CLk1Jb/KtXQ9euwZ+mwZXOnWHPHvjxx1JXUYtfxDUFvzgp\nNfgrSjcPQLVqkJhoJoorhYJfxDUFvzipFMEP5gYwWVmhrkKk0lHwixOXwX/woLnbVkJCSGpyKTGx\nzOBXi1/ENQW/OHEZ/KtWmZkxg3W3LXf06AHZ2aXemEXBL+Kagl+cuAz+itbNA9CoEdSrBzt3hroS\nkUpFwS9OnFrJlhX6+XlK06NHqd09avGLuKbgFydOLf5Nm6BOHWjVKmQ1laqcfn4Fv4gzBb84cQr+\nijBNQ2ku9/O7oCkbRFxT8IsTp+CviP37l3XtClu2wPnzTg+pq0fENQW/OCkR/OfPm4ukBgwIaU2l\nqlUL2reHb791+bCCX8SZgl+clAj+L7+ETp2gfv2Q1lSmxESX3T3q6hFxTcEvTkoEf0Xu5rmslJE9\n6uoRcU3BL07CJfhFxDUFvzgpDv6jR2HXLhOsFVlsLOTlwfHjJX6sFr+Iaz4H/+rVq+nQoQNt27Zl\n5syZTo9nZGRQr1494uPjiY+P5/nnn/d1kxJgxcH/6adm7v1q1UJdUtmqVDFzCF3Tz6/gF3EtwtcX\nSE9PZ/bs2bRo0YIhQ4aQmppKVFRUiXX69+/P0qVLfd2UBElx8FeGbp7LuneHdetg2LBQVyJS4fnU\n4j958iQA/fr1o0WLFgwePJgsF32tlppdlYplgQOrYl+4da2EBBP8V1GLX8Q1n4I/JyeH2NjY4u87\nduzI2rVrS6zjcDhYs2YNXbp0YdKkSeTm5vqySQkCy4Kmp7eZmTjbtg11Oe7p1g3Wr3f6sYJfxFnA\nT+527dqV/fv3k5OTQ8eOHUlPTw/0JsVHlgWdj1xq7VeWwfAtW8K5c3DoUPGPKkvpIsHmUx9/9+7d\neeqpp4q/37JlC0OHDi2xTt2r7s/60EMP8Yc//IGff/6ZGjVqOL3e1KlTi/+dlJREUlKSL+WJlywL\n4g6vgCFjQl2K+xyOK63+O+8s/pFa/BJuMjIyyMjI8Ok1fAr+evXqAWZkT/PmzVm5ciXPPvtsiXWO\nHDlCw4YNcTgcLFu2jLi4OJehDyWDX0LHceFnYvO+gIFzQ12KZxISSgQ/KPgl/FzbKJ42bZrHr+Hz\nqJ6XX36ZtLQ0CgoKmDhxIlFRUcyePRuAtLQ0Fi5cyKxZs4iIiCAuLo6XXnrJ101KgEX98ysO1LuZ\nNpGRoS7FM926wZw5xd+qq0fENYdVQYbcOBwOjf6pIDbf+Tu277uOX270vCURUnv3mhuwHzwIwObN\nMGqU+SoSrrzJTl25K06abPqEzTdWkmGcV2veHC5cKA5+UFePiCsKfinpyBFqH9vD7ujEUFfiOYfj\nSj8/6uoRKY2CX0pauZLDsQMoqlrBp2koTbduxRdyaVSPiGsKfinpk084cPPgyttavqrFDwp+EVcU\n/HKFZaZp+OHmIZU3+C+3+C2r8v4OIgGm4JcrNm6EunU5FdUq1JV4r1kzKCoqPsGrFr+IMwW/XHFp\nUjanm61XJpev4F23rvL+DiIBpuCXKz76CO64A6jEwQ/F/fw6uSvimoJfjB9/hG++gYEDK3eLH0qM\n7FHwizhT8IuxYoW521bNmpU/+C+3+FHqi7ii4Bdj+fLiyc0qffDfdBMA1Y78oBa/iAsKfoHCQvj4\nY0hOBsIg+C9dwVtj0zoFv4gLCn6BtWvNMMimTYEwCH6Abt24bovzHblERMEvUKKbB8Ik+BMSuG6z\nWvwirij4JWyDv8bm9VhFSn6Rayn47W7PHjhyBLp3L/5RWAR/kyZY1arR5OK+UFciUuEo+O1u8WIY\nMQKqXDkUwiL4gZ9v6Uann9eFugyRCkfBb3eLFkFKSokfhUvwX+iUoOAXcUHBb2cHDsC2bTBwYIkf\nh03wxyXQ6YKCX+RaCn47W7zYnNStXr3Ej8Mm+Dt1o9OF9Zq3QeQaCn47W7jQqZsHwif4ixo25qyj\nNuzeHepSRCoUBb9dHTli5t8fNMjpoXAJfocDNlW/MmGbiBgKfrv68EMYNgyuu87poXAJfoCN1RIU\n/CLXUPDb1fz58C//4vKhcAl+hwM2Vlfwi1xLwW9Hu3bB1q2mxe9COAX/dxHdzH0GiopCXY5IhaHg\nt6O5c2HUKKfRPJeFS/ADHK8SDfXrQ25uqEsRqTAU/HZjWfDuu/DAA2WuEg7BX/w7dNMJXpGrKfjt\nZu1aqFrV3KWqFOES/HBpCH+C+vlFrqbgt5s5c0xrv4xkD5fgL77ZuoJfpISIUBcgQXTyJLz/vjmx\nW4ZwudC1RFfPhg3mBG8VtXVE9C6wk3ffNRdsNW5c5mrh0uKHS3/EIiMhOhq2bw91OSIVgoLfLiwL\nZs2C8ePdWjUcgr+4qwd0glfkKgp+u/j8c5OC/fuXu2o4BX8x9fOLFFPw28Wf/gRPPulWoodL8MNV\nLX4Fv0gxndy1gw0bYPNmWLrUrdXDJfhL/A5du8K330JhoRnOKmJjCn5fFRaaaX8PHzajZmrUMCcT\n27SB668PdXXGn/4EkyaZ2twQTsFf3OKvXx+aNDE3nrn55pDWJRJqPgf/6tWrSUtL4+LFi0ycOJEJ\nEyY4rTNlyhQWLFhAgwYNmDdvHrGxsa5fbM8eaNas4rfINm2CZcvgH/8wremoKLjpJqhXD37+GY4f\nhx07zO8yeDDccw/07h2aoYTffQcZGfDWW24/JVyCH64Zmnr5BK/dg//QIXPOZ8sW2L/fNF6qVIEb\nb4SWLc1+io8vdUoPqfx8Dv709HRmz55NixYtGDJkCKmpqURFRRU/np2dzRdffMG6detYsWIFkydP\nZvny5a5frG9fOHYM2raFAQNg6FBzMrJWLV/L9F1Bgbk/7csvmzfOXXfBM89Az54m8K918aJ5Yy1b\nZkbSFBTAE0/Agw+6nAo5YJ5+2tRZt67bT7Gs8Bju7vTH63I//4MPhqSekCoshAULzMiuLVsgKQm6\ndDHvs+rVzfF68KBpyLz5JuzcCb16wd13w4gRphFTWV28aBpjeXmQn28aZwUF5ufVq5t8qV3bvEca\nNTKf1MOl5VMKn4L/5MmTAPTr1w+AwYMHk5WVRXJycvE6WVlZpKSkEBkZSWpqKs8880zpL7h/P5w5\nA99/D6tWwYwZ8Otfw8iRMHo03Hpr8P9D8vPNG+H11033zZQp5naF5X0qiYiAzp3N8oc/QGYm/Pu/\nm9/pxRfNlMiB/l0+/dS8gX/zG4+eFrYt/oQEc9cxu/nsM0hPNw2USZNg+HCoVq3s55w6BStXwpIl\n8G//Bu3bw/33m+M2MjI4dXvq3DnIyYHsbHPNxo4d5uvRo9CggbmWIzLSdHlWq2beoxcumMw5c8b8\nzkeOmD+SN95ougZbtzbv+7Ztzdc2bUy3YSXnU/Dn5OSU6Lbp2LEja9euLRH82dnZ3H///cXfR0dH\nk5ubS0xMjOsXrV0bunc3y5QppnX97rvw0EPmXfzww+aPwFWfKgJi61Z45RXTSrrrLtNy79LFu9dy\nOEwLKynJdLtMngwzZ8Jf/gIdOvix6Kv8/DNMmGD+2HjxkT0cgr9EHz+Y7ouNG01rr7zgCwcXLsDv\nf2+O4VdfNa13d/9j69aFX/7SLAUF8Mkn8Le/mU+Qt99upv0YNiy03UF5efDVV/Dll+brxo2mG69n\nT/N//atfmcBu2tSz7uPTp805uwMHzKyuO3eaT/s7d5qlRg1o184sbdte+XebNia/KoGAn9y1LAvr\nmjkAHKUcfK7fizcCvwXrKXrxNY/8bjbDf9uGjxzDmV1lHF/Ty28p5bCKGGytYIL1Cp2tb3nTMZY3\nq2zlyLzGMM8vmwCScFjZpFlv8GzHvrxa5XH+0/FbChz+fQP9a+GLxNGee+65GzzcPYWF5m9eZed0\nWFx/venD3rzZBEMlkprq2YeVetYJPij6JWepxUNVNnD8V740lKoByUAy9awTjPzfhdy3+CVieZgP\nHSNZ5Egh05FEoSOAcWJZtOef3Gp9dWn5koYcZa2jF2scvVnDdHIciZzdUBs2+LqxOkCbS8s1171Y\nFo3PHaZN9g7aZu2grbWdNrxHW2s7MeRynBvY4WjHTtqy3dGOHbRjv6M5h7iRY0RhOfzbh9qunXfP\nc1jXprIHTp48SVJSEhs2mD09YcIEhg4dWqLFP3PmTC5evMgTTzwBQExMDLku5kZ3OBw888yzxd/3\n759E//5Jrjd8/DhV/jaHKm+9ATVrUZQ2jqLUez3qxy7h2DGqzHmbKn+ZDdfXo/CxiVi/GhX4vvh9\n+6j62FgcBw5w8S/vQHxXv7ysY+3XVE25m4tZ35iTzl6IiKj8rf78fIiJgR9/vOqHDz1kunzGjQtZ\nXd4YMMA03pOS3Fg5L4+IIbdR1D+Jov/878ANlti9myqLPsCxeCGO3buwRtxN0bBkrH79fe8OOn0a\nx/p1OLLW4lj7NY61a6B2baxevbF696GoV2/Tuq9IA0EKC+GHH3Ds2I5j5w7Ysd38e/9+OHwIfvoJ\nGjbEatQYbrgB6tSFunWx6tY1/65d27zxqlY1S2GhOQ9xzZKxZzeZ+/aauadq1uSPqzOdGtfl8Sn4\nAeLj43nllVdo3rw5Q4cO5csvv3Q6uTtp0iSWLFnCihUrmD9/vsuTuw6Hw+PiKSoy/ZezZpn+yKQk\ncyJq4EBo1ar05LIs85Hts8/MR7isLPjFL0wYJCYGN/Euz48/eTI88ojpT3Vz2KVLeXkm2GbONPvC\nxn780RwGJ05c9cO33jJdA3/9a8jq8kb//vDcc25ceH3ihDn+77gD/vjH4B3Le/bA4sWmS2jNGtM3\nnphowrljR9MAiY42fe2XRw6cOWMGc+Tlwd698M9/muG2mzaZ92fnzqbbpkcPMyquadPg/C6BcuGC\nOYdw6JBplZw6dWX56SezPwoLzVJUZMI/IuLKcu33ERFwww047rsv+MGfmZnJ2LFjKSgoYOLEiUyc\nOJHZs2cDkJaWBsDTTz/NggULiIyMZO7cuXRw0a/tVfBf7ccfzfDKpUvNG/vsWejUyZykadDA7Mwz\nZ64cYLVqmVFEd99t+ipD3Td36JAZ/bN9O7z9tjnYPXXqlHnTDx1q3vQ2d+KE6dkpEfybNkFKijkG\nKpG+fWH6dPO1VAUFZhK+uDjTVxeqj2wFBbB+vVm2bDHnyw4dMgF/4sSVEy81a5o/BlFRJtQ7dIDY\nWPPHIi5Ow0nd5E12+hz8/uJz8F/r8GFz0B05Yg62iAhzoLVoYU7CNGniv235i2WZaZPT0+G++0zr\n392LwI4eNSehO3c2n4Aqez+NH5w4Yf67Lw0+MwoLTUNg927zcbuS6N3bnKfv3buMlSZMML/X0qXh\nMR5X3OJNdobvlbuNG5c7/XCF43CY4XIDB8JTT5kRA08/bUYylXX+4pNPzJDNBx6AqVMV+pc4jeoB\n83G5e3fTvXfHHSGpyxvl3kpgzhxzHGRlKfSlXOEb/JVZdLR5I2/aBNOmmW6bX/wChgwxLfr69U0f\nYVaW6aveuxfeeMN08UixUv/+9expbkEZLsG/Y4c5R7R6dViMMZfAU/BXZJ06mTF8P/xgvr77rrkY\n7ORJczFO166QlmbGWqs/1CWXn4B79jQnvyuRUoP/4kVzYdXUqeYkqogbwrePX2zv1Clzbv/06Wse\nOHrUDIDOz6803SLdupkLyLt1u+aB5583Lf2PP640v4v4l/r4RdzRsKE5sbttW6VpJbts8e/YYeaO\n2rBBoS8e0dEiYcvlyd3LLvfzVxJFRdecs7AseOwxM61JZZ5ATUJCwS9hq8zBTZUs+J1mTF240Mym\nOXFiyGqSykvBL2EtnFr8xcF/5oyZZXPWLHtMNid+p+CXsFVmV0/nzmbmxZ9+CmpN3ioR/P/1X9Cn\nj1lEvKDgl7BVZldP9epmTqOvvw5aPb4oDv6jR80J3RdeCHVJUokp+CWslTnKrW9f+OKLoNXii+Lg\nf/55uPdeMwmaiJc0nFPCVpldPQD9+pkgrQSKiqD6/lyYP99MeibiA7X4JWyVO2VRr17wzTdw/nxQ\n6vFFURFEvfKvZgK/6OhQlyOVnIJfwlqZLf66dc1UwDk5QavHWy1+3k7Nr1bC44+HuhQJAwp+CVvl\ndvVApenn/83Jf+f0/eO9v8ucyFUU/GJvlSH4f/iBYWcXc+YhXawl/qHgl7DlVou/Tx9zq8DCwqDU\n5JWXXmJBrdFYkZXnxjFSsSn4JWy5FfzR0eZ+sN99F5SaPJaXB3/9K2/UmqR52MRvdCiJ9OsHmZmh\nrsK1V1+FlBQOOm5S8Ivf6FCSsOVWix/gttvg008DXo/HfvrJzMfz29+Wf+tFEQ/oUJKw5fathwcM\nMCd4CwoCWo/H3ngDBg+GNm0U/OJXOpQkrLnV4o+KgjZtzD2MK4pz5+C//xuefhpw42brIh7QoSRh\ny+0WP8Dtt8OqVQGrxWPvvGMmkYuLAxT84l86lCRsVdrgLyiA//gP+P3vi3+k4Bd/0qEkYc+t7p4+\nfcyQzlOnAl5Puf7+d2jZ0swldImCX/xJh5KEPbeCv2ZNSEwM/bDOoiJ48cUSrf3LP1bwi7/oUBK5\nbMgQ+Mc/QlvD0qVQq5bperqK083WRXyg4Jew5vZYfoA774Tlyz14gp9ZFkyfblr716S8083WRXyg\nQ0nCmkfB36EDVK0KmzYFtKZSffqpOcdw991OD6mrR/xJh5LIZQ4HDB9uWv2hMH06TJniMuEV/OJP\nOpQkrHnU4gfT3bNsWcDqKdXatbBrF6SmOj1kWWZRH7/4i4JfwprHwd+/v7mn7dGjAavJpRdfhKee\ngmrVnB66HPoKfvEXBb/I1apXNyNqPvooeNv87jtz+8cxY1w+rG4e8TcdThLWPG7xA4wcCR98EJB6\nXHrhBXjySXMtgQsKfvE3h2WFauxaSQ6HgwpSioSRGjXM7MY1anjwpNOnzc1Zdu2CGwJ816utWyEp\nCXJzoU4dl6ucPw/165uvItfyJjvVjpCw53F7ok4dczHX4sUBqaeE6dMhPb3U0Ae1+MX/vD6cTp06\nxV133UXz5s25++67OX36tMv1WrZsSVxcHPHx8SQmJnpdqIg3vOrqARg1ChYs8Hs9Jezcaa4UfvTR\nMlfTVbvib14H/6xZs2jevDk7duygadOmvPHGGy7XczgcZGRksGHDBrKzs70uVCSohg2D9evh0KHA\nbePFF03o16tX5mq6alf8zevDKTs7m4ceeogaNWowZswYssq4iYX67iVUvG7x16wJ99wDc+b4uyTj\nn/+EJUtMN0851NUj/hbh7RNzcnKIjY0FIDY2ttTWvMPhYODAgbRq1YoxY8YwYsQIbzcp4jGHAxYu\n9PDk7iWRLR+h18uj+Kjl7/yevL1e/ldODHqSrSsjy133zBkFv/hXmcE/aNAgDh8+7PTzF154we1W\n/FdffcWNN97I1q1bGT58OImJiTRu3NjlulOnTi3+d1JSEklJSW5tQ6Q0v/mND0PyrQTaXqjL9tmf\ns7nRbX6rqXX+OgZ99xV/aDKHC26eP374Yb9tXiq5jIwMMjIyfHoNr4dzjhw5kmeeeYb4+HjWr1/P\niy++yMKFC8t8zqRJk+jQoQOPPPKIcyEazikV0euvmzn633/ff685aBCkpEBamv9eU2wrqMM5e/To\nwdtvv825c+d4++236dmzp9M6Z8+e5dSlOxrl5eWxYsUKhg4d6u0mRYLv/vvhs89gzx7/vN5HH8G+\nfaVepSsSDF4H/7hx49i3bx/t27fnwIEDjB07FoCDBw+SnJwMwOHDh+nbty9dunRh1KhRPPnkkzRr\n1sw/lYsEw/XXm36Wl17y/bXOnYMJE2DmTJdz8ogEi67cFSnPoUPQsaMZidOwofevM3UqbNkS3Okg\nJOx5k50KfhF3pKdDYSG89pp3z9+2zdzQ/dtvoWlT/9YmtqbgFwmUY8cgNhbWrIF27Tx77oUL0KsX\nPPIIXOoSFfEXzdUjEihRUfD00zBunLmiyhPPPgtNmmgUj1QYCn4Rdz3+uJm5s5TpSVx6/32YNw/+\n53804Y5UGOrqEfHEtm3Qrx/87//CrbeWvW5mphmvv3IldOkSnPrEdtTVIxJosbHw17/CL38JGzaU\n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\n", + "text": [ + "" + ] + } + ], + "prompt_number": 17 }, { "cell_type": "code",