{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Numerical Integration\n",
"\n",
"**ScPo Computational Economics 2018**"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Numerical Approximation of Integrals\n",
"\n",
"* We will focus on methods that represent integrals as weighted sums.\n",
"* The typical representation will look like:\n",
"\t$$ E[G(\\epsilon)] = \\int_{\\mathbb{R}^N} G(\\epsilon) w(\\epsilon) d\\epsilon \\approx \\sum_{j=1}^J \\omega_j G(\\epsilon_j) $$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"$$ E[G(\\epsilon)] = \\int_{\\mathbb{R}^N} G(\\epsilon) w(\\epsilon) d\\epsilon \\approx \\sum_{j=1}^J \\omega_j G(\\epsilon_j) $$\n",
"\n",
"* $N$ is the dimensionality of the integration problem.\n",
"* $G:\\mathbb{R}^N \\mapsto \\mathbb{R}$ is the function we want to integrate wrt $\\epsilon \\in \\mathbb{R}^N$.\n",
"* $w$ is a density function s.t. $\\int_{\\mathbb{R}^n} w(\\epsilon) d\\epsilon = 1$.\n",
"* $\\omega$ are weights such that (most of the time) $\\sum_{j=1}^J \\omega_j = 1$.\n",
"* We will look at normal shocks $\\epsilon \\sim N(0_N,I_N)$\n",
"* in that case, $w(\\epsilon) = (2\\pi)^{-N/2} \\exp \\left(-\\frac{1}{2}\\epsilon^T \\epsilon \\right)$\n",
"* $I_N$ is the n by n identity matrix, i.e. there is no correlation among the shocks for now.\n",
"* Other random processes will require different weighting functions, but the principle is identical.\n",
"* For now, let's say that $N=1$\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Quadrature Rules\n",
"\n",
"* We focus exclusively on those and leave Simpson and Newton Cowtes formulas out.\n",
"\t* This is because Quadrature is the method that in many situations gives highes accuracy with lowest computational cost.\n",
"* Quadrature provides a rule to compute weights $w_j$ and nodes $\\epsilon_j$.\n",
"* There are many different quadrature rules.\n",
"* They differ in their domain and weighting function.\n",
"* [https://en.wikipedia.org/wiki/Gaussian_quadrature](https://en.wikipedia.org/wiki/Gaussian_quadrature)\n",
"* In general, we can convert our function domain to a rule-specific domain with change of variables.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Gauss-Hermite: Expectation of a Normally Distributed Variable\n",
"\n",
"* There are many different rules, all specific to a certain random process.\n",
"* Gauss-Hermite is designed for an integral of the form\n",
"\t$$ \\int_{-\\infty}^{+\\infty} e^{-x^2} G(x) dx $$\n",
"\tand where we would approximate \n",
"\t$$ \\int_{-\\infty}^{+\\infty} e^{-x^2} f(x) dx \\approx \\sum_{i=1}^n \\omega_i G(x_i) $$\n",
"* Now, let's say we want to approximate the expected value of function $f$ when it's argument $z\\sim N(\\mu,\\sigma^2)$:\n",
"\t$$ E[f(z)] = \\int_{-\\infty}^{+\\infty} \\frac{1}{\\sigma \\sqrt{2\\pi}} \\exp \\left( -\\frac{(z-\\mu)^2}{2\\sigma^2} \\right) f(z) dz $$\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"\n",
"## Gauss-Hermite: Expectation of a Normally Distributed Variable\n",
"\n",
"* The rule is defined for $x$ however. We need to transform $z$:\n",
"\t$$ x = \\frac{(z-\\mu)^2}{2\\sigma^2} \\Rightarrow z = \\sqrt{2} \\sigma x + \\mu $$\n",
"* This gives us now (just plug in for $z$)\n",
"\t$$ E[f(z)] = \\int_{-\\infty}^{+\\infty} \\frac{1}{ \\sqrt{\\pi}} \\exp \\left( -x^2 \\right) f(\\sqrt{2} \\sigma x + \\mu) dx $$\n",
"* And thus, our approximation to this, using weights $\\omega_i$ and nodes $x_i$ is\n",
"\t$$ E[f(z)] \\approx \\sum_{j=1}^J \\frac{1}{\\sqrt{\\pi}} \\omega_j f(\\sqrt{2} \\sigma x_j + \\mu)$$\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Using Quadrature in Julia\n",
"\n",
"* [https://github.com/ajt60gaibb/FastGaussQuadrature.jl](https://github.com/ajt60gaibb/FastGaussQuadrature.jl)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"attributes": {
"classes": [
"julia"
],
"id": ""
},
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1m\u001b[36mINFO: \u001b[39m\u001b[22m\u001b[36mPrecompiling module FastGaussQuadrature.\n",
"\u001b[39mWARNING: Method definition midpoints(Base.Range{T} where T) in module Base at deprecated.jl:56 overwritten in module StatsBase at /Users/florian.oswald/.julia/v0.6/StatsBase/src/hist.jl:535.\n",
"WARNING: Method definition midpoints(AbstractArray{T, 1} where T) in module Base at deprecated.jl:56 overwritten in module StatsBase at /Users/florian.oswald/.julia/v0.6/StatsBase/src/hist.jl:533.\n"
]
},
{
"data": {
"text/html": [
"
| Rule | nodes | weights |
---|
1 | lobatto | [-1.0, 0.0, 1.0] | [0.333333, 1.33333, 0.333333] |
---|
2 | hermite | [-1.22474, -8.88178e-16, 1.22474] | [0.295409, 1.18164, 0.295409] |
---|
3 | legendre | [-0.774597, 0.0, 0.774597] | [0.555556, 0.888889, 0.555556] |
---|
4 | chebyshev | [-0.866025, 6.12323e-17, 0.866025] | [1.0472, 1.0472, 1.0472] |
---|
"
],
"text/plain": [
"4×3 DataFrames.DataFrame. Omitted printing of 1 columns\n",
"│ Row │ Rule │ nodes │\n",
"├─────┼───────────┼────────────────────────────────────┤\n",
"│ 1 │ lobatto │ [-1.0, 0.0, 1.0] │\n",
"│ 2 │ hermite │ [-1.22474, -8.88178e-16, 1.22474] │\n",
"│ 3 │ legendre │ [-0.774597, 0.0, 0.774597] │\n",
"│ 4 │ chebyshev │ [-0.866025, 6.12323e-17, 0.866025] │"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Pkg.add(\"FastGaussQuadrature\")\n",
"\n",
"using FastGaussQuadrature\n",
"\n",
"np = 3\n",
"\n",
"rules = Dict(\"hermite\" => gausshermite(np),\n",
" \"chebyshev\" => gausschebyshev(np),\n",
" \"legendre\" => gausslegendre(np),\n",
" \"lobatto\" => gausslobatto(np))\n",
"\n",
"using DataFrames\n",
"\n",
"integ = DataFrame(Rule=Symbol[Symbol(x) for x in keys(rules)],nodes=[x[1] for x in values(rules)],weights=[x[2] for x in values(rules)])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Quadrature in more dimensions: Product Rule\n",
"\n",
"* If we have $N>1$, we can use the product rule: this just takes the *kronecker product* of all univariate rules.\n",
"* The what?\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4×2 Array{Int64,2}:\n",
" 1 2\n",
" 3 4\n",
" 10 20\n",
" 30 40"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = [1 2;3 4]\n",
"B = [1;10]\n",
"kron(A,B)\n",
"kron(B,A)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"* This works well as long as $N$ is not too large. The number of required function evaluations grows exponentially.\n",
"\t$$ E[G(\\epsilon)] = \\int_{\\mathbb{R}^N} G(\\epsilon) w(\\epsilon) d\\epsilon \\approx \\sum_{j_1=1}^{J_1} \\cdots \\sum_{j_N=1}^{J_N} \\omega_{j_1}^1 \\cdots \\omega_{j_N}^N G(\\epsilon_{j_1}^1,\\dots,\\epsilon_{j_N}^N) $$\n",
"\twhere $\\omega_{j_1}^1$ stands for weight index $j_1$ in dimension 1, same for $\\epsilon$.\n",
"* Total number of nodes: $J=J_1 J_2 \\cdots J_N$, and $J_i$ can differ from $J_k$.\n",
"\n",
"\n",
"\n",
"### Example for $N=3$\n",
"\n",
"* Suppose we have $\\epsilon^i \\sim N(0,1),i=1,2,3$ as three uncorrelated random variables.\n",
"* Let's take $J=3$ points in all dimensions, so that in total we have $J^N=27$ points.\n",
"* We have the nodes and weights from before in `rules[\"hermite\"]`."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27-element Array{Float64,1}:\n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" ⋮ \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 \n",
" -1.22474 \n",
" -8.88178e-16\n",
" 1.22474 "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rules[\"hermite\"][1]\n",
"repeat(rules[\"hermite\"][1],inner=[1],outer=[9])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"attributes": {
"classes": [
"julia"
],
"id": ""
},
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/html": [
" | weights | dim1 | dim2 | dim3 |
---|
1 | 0.0257793 | -1.22474 | -1.22474 | -1.22474 |
---|
2 | 0.103117 | -8.88178e-16 | -1.22474 | -1.22474 |
---|
3 | 0.0257793 | 1.22474 | -1.22474 | -1.22474 |
---|
4 | 0.103117 | -1.22474 | -8.88178e-16 | -1.22474 |
---|
5 | 0.412469 | -8.88178e-16 | -8.88178e-16 | -1.22474 |
---|
6 | 0.103117 | 1.22474 | -8.88178e-16 | -1.22474 |
---|
7 | 0.0257793 | -1.22474 | 1.22474 | -1.22474 |
---|
8 | 0.103117 | -8.88178e-16 | 1.22474 | -1.22474 |
---|
9 | 0.0257793 | 1.22474 | 1.22474 | -1.22474 |
---|
10 | 0.103117 | -1.22474 | -1.22474 | -8.88178e-16 |
---|
11 | 0.412469 | -8.88178e-16 | -1.22474 | -8.88178e-16 |
---|
12 | 0.103117 | 1.22474 | -1.22474 | -8.88178e-16 |
---|
13 | 0.412469 | -1.22474 | -8.88178e-16 | -8.88178e-16 |
---|
14 | 1.64987 | -8.88178e-16 | -8.88178e-16 | -8.88178e-16 |
---|
15 | 0.412469 | 1.22474 | -8.88178e-16 | -8.88178e-16 |
---|
16 | 0.103117 | -1.22474 | 1.22474 | -8.88178e-16 |
---|
17 | 0.412469 | -8.88178e-16 | 1.22474 | -8.88178e-16 |
---|
18 | 0.103117 | 1.22474 | 1.22474 | -8.88178e-16 |
---|
19 | 0.0257793 | -1.22474 | -1.22474 | 1.22474 |
---|
20 | 0.103117 | -8.88178e-16 | -1.22474 | 1.22474 |
---|
21 | 0.0257793 | 1.22474 | -1.22474 | 1.22474 |
---|
22 | 0.103117 | -1.22474 | -8.88178e-16 | 1.22474 |
---|
23 | 0.412469 | -8.88178e-16 | -8.88178e-16 | 1.22474 |
---|
24 | 0.103117 | 1.22474 | -8.88178e-16 | 1.22474 |
---|
25 | 0.0257793 | -1.22474 | 1.22474 | 1.22474 |
---|
26 | 0.103117 | -8.88178e-16 | 1.22474 | 1.22474 |
---|
27 | 0.0257793 | 1.22474 | 1.22474 | 1.22474 |
---|
"
],
"text/plain": [
"27×4 DataFrames.DataFrame\n",
"│ Row │ weights │ dim1 │ dim2 │ dim3 │\n",
"├─────┼───────────┼──────────────┼──────────────┼──────────────┤\n",
"│ 1 │ 0.0257793 │ -1.22474 │ -1.22474 │ -1.22474 │\n",
"│ 2 │ 0.103117 │ -8.88178e-16 │ -1.22474 │ -1.22474 │\n",
"│ 3 │ 0.0257793 │ 1.22474 │ -1.22474 │ -1.22474 │\n",
"│ 4 │ 0.103117 │ -1.22474 │ -8.88178e-16 │ -1.22474 │\n",
"│ 5 │ 0.412469 │ -8.88178e-16 │ -8.88178e-16 │ -1.22474 │\n",
"│ 6 │ 0.103117 │ 1.22474 │ -8.88178e-16 │ -1.22474 │\n",
"│ 7 │ 0.0257793 │ -1.22474 │ 1.22474 │ -1.22474 │\n",
"│ 8 │ 0.103117 │ -8.88178e-16 │ 1.22474 │ -1.22474 │\n",
"│ 9 │ 0.0257793 │ 1.22474 │ 1.22474 │ -1.22474 │\n",
"│ 10 │ 0.103117 │ -1.22474 │ -1.22474 │ -8.88178e-16 │\n",
"│ 11 │ 0.412469 │ -8.88178e-16 │ -1.22474 │ -8.88178e-16 │\n",
"⋮\n",
"│ 16 │ 0.103117 │ -1.22474 │ 1.22474 │ -8.88178e-16 │\n",
"│ 17 │ 0.412469 │ -8.88178e-16 │ 1.22474 │ -8.88178e-16 │\n",
"│ 18 │ 0.103117 │ 1.22474 │ 1.22474 │ -8.88178e-16 │\n",
"│ 19 │ 0.0257793 │ -1.22474 │ -1.22474 │ 1.22474 │\n",
"│ 20 │ 0.103117 │ -8.88178e-16 │ -1.22474 │ 1.22474 │\n",
"│ 21 │ 0.0257793 │ 1.22474 │ -1.22474 │ 1.22474 │\n",
"│ 22 │ 0.103117 │ -1.22474 │ -8.88178e-16 │ 1.22474 │\n",
"│ 23 │ 0.412469 │ -8.88178e-16 │ -8.88178e-16 │ 1.22474 │\n",
"│ 24 │ 0.103117 │ 1.22474 │ -8.88178e-16 │ 1.22474 │\n",
"│ 25 │ 0.0257793 │ -1.22474 │ 1.22474 │ 1.22474 │\n",
"│ 26 │ 0.103117 │ -8.88178e-16 │ 1.22474 │ 1.22474 │\n",
"│ 27 │ 0.0257793 │ 1.22474 │ 1.22474 │ 1.22474 │"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nodes = Any[]\n",
"push!(nodes,repeat(rules[\"hermite\"][1],inner=[1],outer=[9])) # dim1\n",
"push!(nodes,repeat(rules[\"hermite\"][1],inner=[3],outer=[3])) # dim2\n",
"push!(nodes,repeat(rules[\"hermite\"][1],inner=[9],outer=[1])) # dim3\n",
"weights = kron(rules[\"hermite\"][2],kron(rules[\"hermite\"][2],rules[\"hermite\"][2]))\n",
"df = hcat(DataFrame(weights=weights),DataFrame(nodes,[:dim1,:dim2,:dim3]))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"* Imagine you had a function $g$ defined on those 3 dims: in order to approximate the integral, you would have to evaluate $g$ at all combinations of `dimx`, multiply with the corresponding weight, and sum.\n",
"\n",
"\n",
"### Alternatives to the Product Rule\n",
"\n",
"* Monomial Rules: They grow only linearly.\n",
"* Please refer to [juddbook] for more details.\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Monte Carlo Integration\n",
"\n",
"* A widely used method is to just draw $N$ points randomly from the space of the shock $\\epsilon$, and to assign equal weights $\\omega_j=\\frac{1}{N}$ to all of them.\n",
"* The expectation is then\n",
"\t$$ E[G(\\epsilon)] \\approx \\frac{1}{N} \\sum_{j=1}^N G(\\epsilon_j) $$\n",
"* This in general a very inefficient method.\n",
"* Particularly in more than 1 dimensions, the number of points needed for good accuracy is very large.\n",
"* Monte Carlo has a rate of convergence of $\\mathcal{O}(n^{-0.5})$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Quasi Monte Carlo Integration\n",
"\n",
"* Uses non-product techniques to construct a grid of uniformly spaced points.\n",
"* The researcher controlls the number of points. \n",
"* We need to construct equidistributed points.\n",
"* Typically one uses a low-discrepancy sequence of points, e.g. the Weyl sequence:\n",
"* $x_n = {n v}$ where $v$ is an irrational number and `{}` stands for the fractional part of a number. for $v=\\sqrt{2}$,\n",
"\t$$ x_1 = \\{1 \\sqrt{2}\\} = \\{1.4142\\} = 0.4142, x_2 = \\{2 \\sqrt{2}\\} = \\{2.8242\\} = 0.8242,... $$\n",
"* Other low-discrepancy sequences are Niederreiter, Haber, Baker or Sobol.\n",
"* Quasi Monte Carlo has a rate of convergence of close to $\\mathcal{O}(n^{-1})$\n",
"* [The wikipedia entry is good](https://en.wikipedia.org/wiki/Quasi-Monte_Carlo_method)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"attributes": {
"classes": [
"julia"
],
"id": ""
},
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"ename": "LoadError",
"evalue": "\u001b[91mArgumentError: Module Sobol not found in current path.\nRun `Pkg.add(\"Sobol\")` to install the Sobol package.\u001b[39m",
"output_type": "error",
"traceback": [
"\u001b[91mArgumentError: Module Sobol not found in current path.\nRun `Pkg.add(\"Sobol\")` to install the Sobol package.\u001b[39m",
"",
"Stacktrace:",
" [1] \u001b[1m_require\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Symbol\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:428\u001b[22m\u001b[22m",
" [2] \u001b[1mrequire\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Symbol\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:398\u001b[22m\u001b[22m",
" [3] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m"
]
}
],
"source": [
"# Pkg.add(\"Sobol\")\n",
"using Sobol\n",
"using Plots\n",
"s = SobolSeq(2)\n",
"p = hcat([next(s) for i = 1:1024]...)'\n",
"scatter(p[:,1], p[:,2], m=(:red,:dot,1.0),legend=false)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
" ## Correlated Shocks\n",
"\n",
"* We often face situations where the shocks are in fact correlated.\n",
"\t* One very typical case is an AR1 process:\n",
"\t$$ z_{t+1} = \\rho z_t + \\varepsilon_t, \\varepsilon \\sim N(0,\\sigma^2) $$\n",
"* The general case is again:\n",
"\t$$ E[G(\\epsilon)] = \\int_{\\mathbb{R}^N} G(\\epsilon) w(\\epsilon) d\\epsilon \\approx \\sum_{j_1=1}^{J_1} \\cdots \\sum_{j_N=1}^{J_N} \\omega_{j_1}^1 \\cdots \\omega_{j_N}^N G(\\epsilon_{j_1}^1,\\dots,\\epsilon_{j_N}^N) $$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"* Now $\\epsilon \\sim N(\\mu,\\Sigma)$ where $\\Sigma$ is an N by N variance-covariance matrix.\n",
"* The multivariate density is\n",
"\t$$w(\\epsilon) = (2\\pi)^{-N/2} det(\\Sigma)^{-1/2} \\exp \\left(-\\frac{1}{2}(\\epsilon - \\mu)^T (\\epsilon - \\mu) \\right)$$\n",
"* We need to perform a change of variables before we can integrate this.\n",
"* Given $\\Sigma$ is symmetric and positive semi-definite, it has a Cholesky decomposition, \n",
"\t$$ \\Sigma = \\Omega \\Omega^T $$\n",
"\twhere $\\Omega$ is a lower-triangular with strictly positive entries.\n",
"* The linear change of variables is then\n",
"\t$$ v = \\Omega^{-1} (\\epsilon - \\mu) $$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"\n",
"\n",
"* Plugging this in gives\n",
"\t$$ \\sum_{j=1}^J \\omega_j G(\\Omega v_j + \\mu) \\equiv \\sum_{j=1}^J \\omega_j G(\\epsilon_j) $$\n",
"\twhere $v\\sim N(0,I_N)$.\n",
"* So, we can follow the exact same steps as with the uncorrelated shocks, but need to adapt the nodes.\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"\n",
"\n",
"\n",
"## References\n",
"\n",
"* The Integration part of these slides are based on [@maliar-maliar] chapter 5"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Julia 0.6.0",
"language": "julia",
"name": "julia-0.6"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.6.0"
}
},
"nbformat": 4,
"nbformat_minor": 1
}