Created
May 2, 2013 14:30
-
-
Save cdeil/5502591 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "statistics" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "heading", | |
"level": 1, | |
"metadata": {}, | |
"source": [ | |
"Statistics" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## What is this?\n", | |
"\n", | |
"Here we compare significance and excess sensitivity and limits for an on-off measurement computed with the [Rolke](http://adsabs.harvard.edu/abs/2005NIMPA.551..493R) and [Li & Ma](http://adsabs.harvard.edu/abs/1983ApJ...272..317L) methods.\n", | |
"\n", | |
"* Given `n_on`, `n_off` and `alpha`, compute `significance(n_on, n_off, alpha)`.\n", | |
"* Given `n_off` and `alpha` and `significance`, compute `sensitivity(n_off, alpha, significance)`.\n", | |
"* Given `n_on`, `n_off` and `alpha`, compute `excess_limits(n_on, n_off, alpha, significance)`.\n", | |
"\n", | |
"Note that significance and p-value = confidence level are equivalent via the normal distribution:\n", | |
"\n", | |
" p_value = scipy.stats.norm.sf(significance)\n", | |
" significance = scipy.stats.norm.isf(p_value)\n", | |
" confidence_level = p_value\n", | |
"\n", | |
"## TODOs\n", | |
"\n", | |
"* In the Rolke TS profile below, why is the minimum at TS = 0, but in the Rolke paper at approx. 9?\n", | |
"* Check and document where p_values are one- or two-sided.\n", | |
"* Finish implementing the functions\n", | |
"* Check against HESS code.\n", | |
"* Compute the results with HESSE and MINOS instead of Rolke." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import numpy as np\n", | |
"from numpy import log, sqrt, abs" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 2 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Rolke Implementation" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Implements the formulae on page 6 of the Rolke 2005 paper:\n", | |
"http://adsabs.harvard.edu/abs/2005NIMPA.551..493R" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_mu_best(x, y, tau):\n", | |
" return x - y / tau\n", | |
"\n", | |
"def compute_b_best(y, tau):\n", | |
" return y / tau\n", | |
"\n", | |
"def compute_b_hat(x, y, tau, mu):\n", | |
" term1 = x + y - (1 + tau) * mu\n", | |
" term2 = term1 ** 2 + 4 * (1 + tau) * y * mu\n", | |
" term3 = 2 * (1 + tau)\n", | |
" return (term1 + sqrt(term2)) / term3\n", | |
"\n", | |
"def compute_L(x, y, tau, mu, b):\n", | |
" from scipy.stats import poisson\n", | |
" P1 = poisson.pmf(x, mu + b)\n", | |
" P2 = poisson.pmf(y, tau * b)\n", | |
" return P1 * P2\n", | |
"\n", | |
"def compute_lambda(x, y, tau, mu):\n", | |
" mu_best = compute_mu_best(x, y, tau)\n", | |
" b_best = compute_b_best(y, tau)\n", | |
" b_hat = compute_b_hat(x, y, tau, mu)\n", | |
" a = compute_L(x, y, tau, mu, b_hat)\n", | |
" b = compute_L(x, y, tau, mu_best, b_best)\n", | |
" return a / b\n", | |
"\n", | |
"def compute_TS(x, y, tau, mu):\n", | |
" lambda_ = compute_lambda(x, y, tau, mu)\n", | |
" return - 2 * log(lambda_)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 3 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Reproduce Figure 1 in the Rolke paper\n", | |
"x, y, tau, cl = 8, 15, 5.0, 0.95\n", | |
"mu = np.arange(0, 14, 0.1)\n", | |
"TS = compute_TS(x, y, tau, mu)\n", | |
"plot(mu, TS);" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"png": "iVBORw0KGgoAAAANSUhEUgAAAWsAAAD9CAYAAAB6DlaSAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X98zXX/x/HHMAkp5FdGRLIx5le6RA1RhMgqvyK/UnRd\nKv1y1VX6wbDLF1Fd5UKUUnGFhCKdSr6ShhTiYvs20SKMGWbb+f7xjiS2s7Nzzvt8znnebze3Rs7n\n88T22vu8Pu8fEW63242IiAS1YrYDiIhIwVSsRUQcQMVaRMQBVKxFRBxAxVpExAFUrEVEHKDAYn34\n8GESEhKIjo4mJiaGdevWBSKXiIicpURBv2HkyJF07tyZBQsWkJOTw7FjxwKRS0REzhKR36KYjIwM\nmjRpwu7duwOZSUREzpHvyDolJYVKlSoxcOBANm/eTLNmzZg6dSqlS5cGICIiIiAhRURCTWEXj+fb\ns87JySE5OZnhw4eTnJxMmTJlGD9+/J9u6NQfzzzzjPUMym8/h/I774eTs7vd3u3wkW+xjoqKIioq\nihYtWgCQkJBAcnKyVzcSERHv5Vusq1atSo0aNdixYwcAq1atokGDBgEJJiIivytwNsi0adPo27cv\n2dnZ1KlTh9mzZwciV0DEx8fbjlAkym+X8tvj5Ozeync2SIEvjojwuv8iIhKuvKmdWsEoIuIAKtYi\nIg6gYi0i4gAq1iIiDqBiLSLiACrWIiIBcvQoeDuBrsB51iIiUnRuN/TuDXfc4d3rNbIWEQmA//wH\ndu82BdsbWhQjIuJnR45ATAy89RbccIN3tVPFWkTEz0aOhMxMmDnT/Nyb2qmetYiIH23YAO+8A99/\nX7TrqGctIuInOTkwdCgkJUHFikW7loq1iIifTJliinS/fkW/lnrWIiJ+kJICLVrAunVQt+4f/592\n3RMRCQJuNwwfDqNG/blQe0vFWkTEx955B/bsgUce8d011QYREfGhQ4egQQOzCOa6687/ezTPWkTE\nsqFDoWRJeOmlC/8ezbMWEbHo889h+fKiz6k+H/WsRUR84ORJuPdeePFFuPRS319fxVpExAfGj4dr\nroEePfxzffWsRUSKaPt2aN0aNm6EGjUK/v2aZy0iEmB5eTBsGDz9tGeF2lsq1iIiRTB7Nhw/DiNG\n+Pc+aoOIiHgpPR1iY2HlSmjc2PPXaZ61iEgA9e5tWh8TJxbudZpnLSISIB98AF9//fuBAv6mYi0i\nUkgZGWajprlzoXTpwNyzwDZIrVq1KFeuHMWLFycyMpL169f//mK1QUQkDN1/vzlYYMYM717vlzZI\nREQELpeLChUqeJdKRCSEfP65aYF8911g7+vR1D2NnkVEzBS9IUNg+nS47LLA3tujkfVNN91E8eLF\nGTZsGEOHDv3D/x8zZsyZj+Pj44mPj/d1RhGRoPDcc2aKXvfuhXudy+XC5XIV6d4F9qz37dtHtWrV\n2L9/Px06dGDatGm0adPGvFg9axEJExs3wi23wObNULVq0a7ll+Xm1apVA6BSpUr06NHjDw8YRUTC\nQU4ODB4MEyYUvVB7K99inZWVxdGjRwE4duwYH3/8MbGxsQEJJiISLCZNgssvhwED7GXIt2ednp5O\nj9/2+8vJyaFv37507NgxIMFERILBzp2QlGQWwERE2Muh5eYiIheQlwft2pkHig8+6LvraotUEREf\nmjEDTpyAv/7VdhKNrEVEzuunnyAuDlwuc1q5L2lkLSLiA263WVI+YoTvC7W3tJGTiMg55s+H3bvh\nvfdsJ/md2iAiImdJT4dGjWDpUmjRwj/30OEDIiJFlJAAV18NiYn+u4cOHxARKYL33oOtW+HNN20n\n+TONrEVEgP37zXmKixdDy5b+vZfaICIiXrrrLrjyysKfp+gNtUFERLywcKHZTe/1120nuTCNrEUk\nrB04YNofCxdCq1aBuafaICIihdSnD1SrZnbWCxS1QURECmHRItiwATZtsp2kYBpZi0hYOngQGjaE\nd9+F1q0De2+1QUREPHT33VCxIkyZEvh7W2mDZGZC2bJFvYqISOB88AH87/+aGSBOUeRd92rUgCNH\nfBFFRMT/Dh0yO+rNnAllythO47kiF+vrroOPPvJFFBER/3vwQejRA2680XaSwilyse7SxbylEBEJ\ndosXw5df+neTJn8p8gPG1FQ3zZqZbQWLF/dlNBER39m/Hxo3tjP741xWToq58kqoXt0060VEgtHp\nk1/69bNfqL3lk2O9unZVK0REgtfbb8P27fDcc7aTeE/FWkRC2t695qHinDlQqpTtNN7zSbFu0cKs\nBtq1yxdXExHxDbcbBg82B982a2Y7TdH4pFgXKwa33qrRtYgElxkzzIPFv//ddpKi80mxBuje3UyL\nEREJBrt3myI9Zw5ERtpOU3Q+2xvk+HGoWtX8BVWs6LN8IiKFlpcHbdua52mPPGI7zZ9Zmbp32sUX\n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\n", | |
"text": [ | |
"<matplotlib.figure.Figure at 0x103568990>" | |
] | |
} | |
], | |
"prompt_number": 4 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Li & Ma Implementation" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"#@np.vectorize\n", | |
"def loglike_lima(on, off, alpha, signal, do_switch=True):\n", | |
" \"\"\"Taken from Utilities::Statistics::LiMa_LogLikelihood\n", | |
" from the HESS software.\"\"\"\n", | |
" #for _ in [on, off, alpha, signal]:\n", | |
" # _ = np.asarray(_)\n", | |
" # @todo Explain what the model is for negative signal\n", | |
" # Is there a source in the off region?\n", | |
" if do_switch:\n", | |
" positive = signal > 0\n", | |
" n1 = np.where(positive, on, off)\n", | |
" n2 = np.where(positive, off, on)\n", | |
" a = np.where(positive, alpha, 1.0 / alpha)\n", | |
" signal = np.where(positive, signal, -a * signal)\n", | |
" else:\n", | |
" n1 = on\n", | |
" n2 = off\n", | |
" a = alpha\n", | |
"\n", | |
" # Estimate background for the on region\n", | |
" # @note Some of the other functions compute background\n", | |
" # in the off region as the parameter\n", | |
" def case1(n1, a, signal):\n", | |
" \"\"\"Corresponds to Li & Ma formula (7)\"\"\"\n", | |
" # @todo Explain this formula better!\n", | |
" return n1 / (a + 1) - signal / a\n", | |
" def case2(n1, n2, a, signal):\n", | |
" # @todo Explain this formula!?\n", | |
" # Is it the same as nll()?\n", | |
" t = (1 + a) * signal - a * (n1 + n2)\n", | |
" delta = t * t + 4 * a * (1 + a) * signal * n2\n", | |
" return (sqrt(delta) - t) / (2 + 2 * a)\n", | |
" background = np.where(off == 0,\n", | |
" case1(n1, a, signal),\n", | |
" case2(n1, n2, a, signal))\n", | |
" #background = case2(n1, n2, a, signal)\n", | |
" np.where(background < 0, 0, background)\n", | |
" \n", | |
" # Compute Poisson nll for given signal / background:\n", | |
" # n1 ~ Pois(signal + background)\n", | |
" # n2 ~ Pois(background / a)\n", | |
" mu1 = signal + background\n", | |
" mu2 = background / a\n", | |
" l1 = np.where(n1 > 0, n1 * log(mu1), 0) - mu1\n", | |
" l2 = np.where(n2 > 0, n2 * log(mu2), 0) - mu2\n", | |
" l = l1 + l2\n", | |
" if 0:\n", | |
" print 'background', background\n", | |
" print 'signal', signal\n", | |
" print 'n1:', n1\n", | |
" print 'mu1:', mu1\n", | |
" print 'n2:', n2\n", | |
" print 'mu2:', mu2\n", | |
" print 'of interest', mu2[n2 > 0]\n", | |
" print 'l1', l1\n", | |
" print 'l2', l2\n", | |
" print 'l', l\n", | |
" return -1\n", | |
" #return -l, -l1, -l2\n", | |
"\n", | |
"@np.vectorize\n", | |
"def excess_error(on, off, alpha, nsig=1,\n", | |
" up=True, loglike=loglike_lima):\n", | |
" \"\"\"Statistical uncertainties on signal using the profile\n", | |
" likelihood method on a variant of the likelihood function\n", | |
" given in the Li & Ma paper.\n", | |
" \n", | |
" @param on: number of counts in on region\n", | |
" @param off: number of counts in off region\n", | |
" @param alpha: on / off exposure ratio\n", | |
" @param nsig: number of standard deviations of the error\n", | |
" @return: signal limit\n", | |
" \n", | |
" The profile likelihood method finds the signal for which\n", | |
" L(signal) = L0 + 0.5 * nsig, where\n", | |
" L0 = L(signal0) is the best-fit likelihood, which here is\n", | |
" signal0 = on - alpha * off, i.e. the signal.\"\"\"\n", | |
" from scipy.optimize import brentq\n", | |
" # Optimal signal and likelihood\n", | |
" signal0 = on - off * alpha\n", | |
" L0 = loglike(on, off, alpha, signal0)\n", | |
" # @todo Shouldn't dL scale with nsig^2\n", | |
" dL = nsig * 0.5\n", | |
" \n", | |
" # We want to use the brentq method to find a root of\n", | |
" # f(signal) = L0 - L(signal) - dL\n", | |
" # The brentq method needs a start interval\n", | |
" # (signal_low, signal_up)\n", | |
" # containing the solution.\n", | |
" # We use signal_low = signal0 and find a signal_up \n", | |
" # such that f(signal_up) is positive.\n", | |
" # The details of the following algorithm are not important,\n", | |
" # we start with an interval of 1 and increase by factors of 2.\n", | |
" signal = signal0 + 1 if up else signal0 - 1\n", | |
" for _ in range(100): # Avoid infinite loop (should never occur)\n", | |
" L = loglike(on, off, alpha, signal)\n", | |
" if (L0 - L < dL) & np.isfinite(L):\n", | |
" signal = signal0 + 2 * (signal - signal0)\n", | |
" else:\n", | |
" break \n", | |
"\n", | |
" # Now use brentq to find the signal\n", | |
" def f(signal):\n", | |
" L = loglike(on, off, alpha, signal)\n", | |
" return L0 - L - dL\n", | |
" signal_low = signal0 if up else signal\n", | |
" signal_up = signal if up else signal0\n", | |
" # @note The HESS software uses bisect\n", | |
" # (i.e. results will be different because we use brentq) \n", | |
" # with hardcoded xtol = 1e-4 and maxiter = 100\n", | |
" signal = brentq(f, signal_low, signal_up,\n", | |
" xtol=1e-4, maxiter=100)\n", | |
" \n", | |
" # Return difference to excess\n", | |
" return signal - signal0" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 76 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Significance" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_significance_lima(n_on, n_off, alpha):\n", | |
" \"\"\"The Li & Ma significance can be evaluated as a simple formula\"\"\"\n", | |
" n_sum = n_on + n_off\n", | |
" temp = (alpha + 1) / n_sum\n", | |
" l = n_on * log(n_on * temp / alpha)\n", | |
" m = n_off * log(n_off * temp)\n", | |
" sign = np.where(n_on - alpha * n_off > 0, 1, -1)\n", | |
" return sign * sqrt(abs(2 * (l + m)))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 5 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_significance_rolke(n_on, n_off, alpha):\n", | |
" # Translate symbols used in gamma-ray astronomy to those in the Rolke paper\n", | |
" x, y, tau = n_on, n_off, 1. / alpha\n", | |
" TS = compute_TS(x, y, tau, 0.)\n", | |
" return sqrt(TS)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 6 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Compare significance for one example -> Perfect agreement\n", | |
"n_on, n_off, alpha = 10, 10, 0.1\n", | |
"significance_lima = compute_significance_lima(n_on, n_off, alpha)\n", | |
"significance_rolke = compute_significance_rolke(n_on, n_off, alpha)\n", | |
"print significance_lima\n", | |
"print significance_rolke" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"4.70512718528\n", | |
"4.70512718528\n" | |
] | |
} | |
], | |
"prompt_number": 7 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Sensitivity" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_sensitivity_lima(n_off, alpha, significance, guess=1e-3):\n", | |
" \"\"\"Compute sensitivity using the Li & Ma formula for significance.\n", | |
" There is no formula, we have to find the solution numerically.\n", | |
"\n", | |
"\t@note: in weird cases (e.g. on=0.1, off=0.1, alpha=0.001)\n", | |
"\tfsolve does not find a solution.\n", | |
"\t@todo: Is it possible to find a better starting point or\n", | |
"\timplementation to make this robust and fast?\n", | |
"\tvalues < guess are often not found using this cost function.\"\"\"\n", | |
" # It would be better to find a range that always contains the solution\n", | |
" # and to then call brentq, which will be a bit slower, but always converge.\n", | |
" from scipy.optimize import fsolve\n", | |
" def f(n_on):\n", | |
" if n_on >= 0:\n", | |
" return compute_significance_lima(n_on, n_off, alpha) - significance\n", | |
" else:\n", | |
" return 1e100\n", | |
" n_on = fsolve(f, guess)[0]\n", | |
" return n_on - alpha * n_off" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 8 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# TODO: x must be int; results don't match\n", | |
"def compute_sensitivity_rolke(n_off, alpha, significance):\n", | |
" import ROOT\n", | |
" rolke = ROOT.TRolke()\n", | |
" rolke.SetCLSigmas(significance)\n", | |
" x, y, tau, e = int(alpha * n_off), int(n_off), 1. / alpha, 1\n", | |
" rolke.SetPoissonBkgKnownEff(x, y, tau, e)\n", | |
" low, high = ROOT.Double(0), ROOT.Double(0)\n", | |
" rolke.GetSensitivity(low, high)\n", | |
" return high" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 63 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Compute sensitivity for one example\n", | |
"n_off, alpha, significance = 10, 0.1, 3.\n", | |
"sensitivity_lima = compute_sensitivity_lima(n_off, alpha, significance)\n", | |
"sensitivity_rolke = compute_sensitivity_rolke(n_off, alpha, significance)\n", | |
"print sensitivity_lima\n", | |
"print sensitivity_rolke" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"4.81849708379\n", | |
"6.5305711766\n" | |
] | |
} | |
], | |
"prompt_number": 64 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Limits = Errors" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_limits_rolke(n_on, n_off, alpha, significance):\n", | |
" import ROOT\n", | |
" rolke = ROOT.TRolke()\n", | |
" rolke.SetCLSigmas(significance)\n", | |
" x, y, tau, e = int(n_on), int(n_off), 1. / alpha, 1\n", | |
" rolke.SetPoissonBkgKnownEff(x, y, tau, e)\n", | |
" low, high = ROOT.Double(0), ROOT.Double(0)\n", | |
" rolke.GetLimits(low, high)\n", | |
" return low, high" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 52 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def compute_limits_lima(n_on, n_off, alpha, significance):\n", | |
" # TODO: Doesn't work yet\n", | |
" return None, None\n", | |
" down = excess_error(n_on, n_off, alpha, significance, False, loglike_lima)\n", | |
" up = excess_error(n_on, n_off, alpha, significance, True, loglike_lima)\n", | |
" return down, up" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 78 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Look at three examples: Gaussian limit, small positive excess, small negative excess\n", | |
"examples = [(100, 0, 1, 1), # should roughly give excess 100 +- 10\n", | |
" (100, 0, 1, 2), # should roughly give excess 100 +- 20\n", | |
" (10, 10, 0.1, 1), # excess = 9\n", | |
" (10, 90, 0.1, 1), # excess = 1\n", | |
" (10, 110, 0.1, 1) # excess = -1\n", | |
" ]\n", | |
"for n_on, n_off, alpha, significance in examples:\n", | |
" limits_lima = compute_limits_lima(n_on, n_off, alpha, significance)\n", | |
" limits_rolke = compute_limits_rolke(n_on, n_off, alpha, significance)\n", | |
" print n_on, n_off, alpha, limits_lima, limits_rolke" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"100 0 1 (None, None) (90.33017981414673, 110.33660955973012)\n", | |
"100 0 1 (None, None) (81.31051153599459, 121.35596019830203)\n", | |
"10 10 0.1 (None, None) (6.141612917334355, 12.516769078804394)\n", | |
"10 90 0.1 (None, None) (0.0, 4.617504851826792)\n", | |
"10 110 0.1 (None, None) (0.0, 2.6423695593692913)\n" | |
] | |
} | |
], | |
"prompt_number": 79 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment