{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## A 5x5 Elimination Matrix, E (l=1, k=3)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "N = 5;\n", "l = 1;\n", "k = 3;" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " 1.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "el=eye(5)[:,l]" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " 0.0\n", " 0.0\n", " 1.0\n", " 0.0\n", " 0.0" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ek=eye(5)[:,k]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 0.0 0.0 1.0 0.0 0.0\n", " 0.0 0.0 0.0 0.0 0.0\n", " 0.0 0.0 0.0 0.0 0.0\n", " 0.0 0.0 0.0 0.0 0.0\n", " 0.0 0.0 0.0 0.0 0.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "el*ek'" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.0 0.0 3.0 0.0 0.0\n", " 0.0 1.0 0.0 0.0 0.0\n", " 0.0 0.0 1.0 0.0 0.0\n", " 0.0 0.0 0.0 1.0 0.0\n", " 0.0 0.0 0.0 0.0 1.0" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E=eye(5)+3*el*ek'" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 0.64764 0.416888 0.272297 0.829488 0.671648\n", " 0.209615 0.0758793 0.97854 0.808906 0.862265\n", " 0.291818 0.140414 0.385255 0.823593 0.618398\n", " 0.435921 0.248701 0.200266 0.179681 0.204089\n", " 0.540153 0.401282 0.632367 0.190665 0.341633" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B=rand(5,5)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 0.291818 0.140414 0.385255 0.823593 0.618398\n", " 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "el*ek' * B" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.52309 0.838129 1.42806 3.30027 2.52684 \n", " 0.209615 0.0758793 0.97854 0.808906 0.862265\n", " 0.291818 0.140414 0.385255 0.823593 0.618398\n", " 0.435921 0.248701 0.200266 0.179681 0.204089\n", " 0.540153 0.401282 0.632367 0.190665 0.341633" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E * B" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## LU Factorization Implementation: lufact()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.656412 0.88843 0.202747 \n", " 0.797951 0.222365 0.632138 \n", " 0.454066 0.277741 0.0591349" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A=rand(3,3) ## A random 3x3 matrix" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "search: \u001b[1ml\u001b[22m\u001b[1mu\u001b[22m\u001b[1mf\u001b[22m\u001b[1ma\u001b[22m\u001b[1mc\u001b[22m\u001b[1mt\u001b[22m \u001b[1ml\u001b[22m\u001b[1mu\u001b[22m\u001b[1mf\u001b[22m\u001b[1ma\u001b[22m\u001b[1mc\u001b[22m\u001b[1mt\u001b[22m!\n", "\n" ] }, { "data": { "text/markdown": [ "```\n", "lufact(A [,pivot=Val{true}]) -> F::LU\n", "```\n", "\n", "Compute the LU factorization of `A`.\n", "\n", "In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If pivoting is chosen (default) the element type should also support `abs` and `<`.\n", "\n", "The individual components of the factorization `F` can be accessed by indexing:\n", "\n", "| Component | Description |\n", "|:--------- |:----------------------------------- |\n", "| `F[:L]` | `L` (lower triangular) part of `LU` |\n", "| `F[:U]` | `U` (upper triangular) part of `LU` |\n", "| `F[:p]` | (right) permutation `Vector` |\n", "| `F[:P]` | (right) permutation `Matrix` |\n", "\n", "The relationship between `F` and `A` is\n", "\n", "`F[:L]*F[:U] == A[F[:p], :]`\n", "\n", "`F` further supports the following functions:\n", "\n", "| Supported function | `LU` | `LU{T,Tridiagonal{T}}` |\n", "|:-------------------------------- |:---- |:---------------------- |\n", "| [`/`](:func:`/`) | ✓ | |\n", "| [`\\`](:func:`\\`) | ✓ | ✓ |\n", "| [`cond`](:func:`cond`) | ✓ | |\n", "| [`det`](:func:`det`) | ✓ | ✓ |\n", "| [`logdet`](:func:`logdet`) | ✓ | ✓ |\n", "| [`logabsdet`](:func:`logabsdet`) | ✓ | ✓ |\n", "| [`size`](:func:`size`) | ✓ | ✓ |\n", "\n", "```\n", "lufact(A::SparseMatrixCSC) -> F::UmfpackLU\n", "```\n", "\n", "Compute the LU factorization of a sparse matrix `A`.\n", "\n", "For sparse `A` with real or complex element type, the return type of `F` is `UmfpackLU{Tv, Ti}`, with `Tv` = `Float64` or `Complex128` respectively and `Ti` is an integer type (`Int32` or `Int64`).\n", "\n", "The individual components of the factorization `F` can be accessed by indexing:\n", "\n", "| Component | Description |\n", "|:--------- |:----------------------------------- |\n", "| `F[:L]` | `L` (lower triangular) part of `LU` |\n", "| `F[:U]` | `U` (upper triangular) part of `LU` |\n", "| `F[:p]` | right permutation `Vector` |\n", "| `F[:q]` | left permutation `Vector` |\n", "| `F[:Rs]` | `Vector` of scaling factors |\n", "| `F[:(:)]` | `(L,U,p,q,Rs)` components |\n", "\n", "The relation between `F` and `A` is\n", "\n", "`F[:L]*F[:U] == (F[:Rs] .* A)[F[:p], F[:q]]`\n", "\n", "`F` further supports the following functions:\n", "\n", " * [`\\`](:func:`\\`)\n", " * [`cond`](:func:`cond`)\n", " * [`det`](:func:`det`)\n", "\n", "** Implementation note **\n", "\n", "`lufact(A::SparseMatrixCSC)` uses the UMFPACK library that is part of SuiteSparse. As this library only supports sparse matrices with `Float64` or `Complex128` elements, `lufact` converts `A` into a copy that is of type `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{Complex128}` as appropriate.\n" ], "text/plain": [ "```\n", "lufact(A [,pivot=Val{true}]) -> F::LU\n", "```\n", "\n", "Compute the LU factorization of `A`.\n", "\n", "In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If pivoting is chosen (default) the element type should also support `abs` and `<`.\n", "\n", "The individual components of the factorization `F` can be accessed by indexing:\n", "\n", "| Component | Description |\n", "|:--------- |:----------------------------------- |\n", "| `F[:L]` | `L` (lower triangular) part of `LU` |\n", "| `F[:U]` | `U` (upper triangular) part of `LU` |\n", "| `F[:p]` | (right) permutation `Vector` |\n", "| `F[:P]` | (right) permutation `Matrix` |\n", "\n", "The relationship between `F` and `A` is\n", "\n", "`F[:L]*F[:U] == A[F[:p], :]`\n", "\n", "`F` further supports the following functions:\n", "\n", "| Supported function | `LU` | `LU{T,Tridiagonal{T}}` |\n", "|:-------------------------------- |:---- |:---------------------- |\n", "| [`/`](:func:`/`) | ✓ | |\n", "| [`\\`](:func:`\\`) | ✓ | ✓ |\n", "| [`cond`](:func:`cond`) | ✓ | |\n", "| [`det`](:func:`det`) | ✓ | ✓ |\n", "| [`logdet`](:func:`logdet`) | ✓ | ✓ |\n", "| [`logabsdet`](:func:`logabsdet`) | ✓ | ✓ |\n", "| [`size`](:func:`size`) | ✓ | ✓ |\n", "\n", "```\n", "lufact(A::SparseMatrixCSC) -> F::UmfpackLU\n", "```\n", "\n", "Compute the LU factorization of a sparse matrix `A`.\n", "\n", "For sparse `A` with real or complex element type, the return type of `F` is `UmfpackLU{Tv, Ti}`, with `Tv` = `Float64` or `Complex128` respectively and `Ti` is an integer type (`Int32` or `Int64`).\n", "\n", "The individual components of the factorization `F` can be accessed by indexing:\n", "\n", "| Component | Description |\n", "|:--------- |:----------------------------------- |\n", "| `F[:L]` | `L` (lower triangular) part of `LU` |\n", "| `F[:U]` | `U` (upper triangular) part of `LU` |\n", "| `F[:p]` | right permutation `Vector` |\n", "| `F[:q]` | left permutation `Vector` |\n", "| `F[:Rs]` | `Vector` of scaling factors |\n", "| `F[:(:)]` | `(L,U,p,q,Rs)` components |\n", "\n", "The relation between `F` and `A` is\n", "\n", "`F[:L]*F[:U] == (F[:Rs] .* A)[F[:p], F[:q]]`\n", "\n", "`F` further supports the following functions:\n", "\n", " * [`\\`](:func:`\\`)\n", " * [`cond`](:func:`cond`)\n", " * [`det`](:func:`det`)\n", "\n", "** Implementation note **\n", "\n", "`lufact(A::SparseMatrixCSC)` uses the UMFPACK library that is part of SuiteSparse. As this library only supports sparse matrices with `Float64` or `Complex128` elements, `lufact` converts `A` into a copy that is of type `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{Complex128}` as appropriate.\n" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "?(lufact) ## help system -- yay!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Testing LU " ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "Base.LinAlg.LU{Float64,Array{Float64,2}}([0.797951 0.222365 0.632138; 0.822622 0.705507 -0.317264; 0.56904 0.214323 -0.23258],[2,2,3],0)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F=lufact(A) ## LU factorization with partial pivoting " ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 1.0 0.0 0.0\n", " 0.822622 1.0 0.0\n", " 0.56904 0.214323 1.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F[:L]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.797951 0.222365 0.632138\n", " 0.0 0.705507 -0.317264\n", " 0.0 0.0 -0.23258 " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F[:U]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Verifying result: A == LU ??" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.797951 0.222365 0.632138 \n", " 0.656412 0.88843 0.202747 \n", " 0.454066 0.277741 0.0591349" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F[:L]*F[:U]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.656412 0.88843 0.202747 \n", " 0.797951 0.222365 0.632138 \n", " 0.454066 0.277741 0.0591349" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A # A != LU --- need to include permutations" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 2\n", " 1\n", " 3" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F[:p] ## Don't forget to pivot!" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.797951 0.222365 0.632138 \n", " 0.656412 0.88843 0.202747 \n", " 0.454066 0.277741 0.0591349" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[F[:p], :] ## Same as L*U " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Solving Ax=b" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4×4 Array{Float64,2}:\n", " 0.786429 0.429332 0.0624521 0.745315\n", " 0.394092 0.425951 0.298966 0.619573\n", " 0.0249588 0.321087 0.156631 0.595137\n", " 0.88053 0.996113 0.560585 0.121093" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N = 4;\n", "A = rand(N,N)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4-element Array{Float64,1}:\n", " 0.540919 \n", " 0.724715 \n", " 0.0625126\n", " 0.752182 " ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = rand(N)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "Base.LinAlg.LU{Float64,Array{Float64,2}}([0.88053 0.996113 0.560585 0.121093; 0.893131 -0.460328 -0.438224 0.637163; 0.0283452 -0.63618 -0.138048 0.997055; 0.447562 0.0431673 -0.485238 1.02168],[4,4,3,4],0)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LU=lufact(A)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4-element Array{Float64,1}:\n", " 1.20634 \n", " -2.01231 \n", " 2.94371 \n", " 0.365381" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LU \\ b ## Performs backsubstitution" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4-element Array{Float64,1}:\n", " 1.20634 \n", " -2.01231 \n", " 2.94371 \n", " 0.365381" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inv(A)*b" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4.241383723240057e-16" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(LU \\ b - inv(A)*b)/norm(b)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2.220446049250313e-16" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eps()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1.9101494155519207" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(norm(LU \\ b - inv(A)*b)/norm(b)) / eps()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Timing lufact() and solve (\"LU \\ b\")" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false, "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10x10: elapsed time: 0.00909094 seconds\n", "20x20: elapsed time: 0.002258116 seconds\n", "50x50: elapsed time: 0.001473188 seconds\n", "100x100: elapsed time: 0.000483221 seconds\n", "170x170: elapsed time: 0.001493419 seconds\n", "260x260: elapsed time: 0.001952619 seconds\n", "370x370: elapsed time: 0.003409656 seconds\n", "500x500: elapsed time: 0.005378073 seconds\n", "650x650: elapsed time: 0.00813408 seconds\n", "820x820: elapsed time: 0.009829342 seconds\n", "1010x1010: elapsed time: 0.01726451 seconds\n", "1220x1220: elapsed time: 0.024421508 seconds\n", "1450x1450: elapsed time: 0.043789634 seconds\n", "1700x1700: elapsed time: 0.118542954 seconds\n", "1970x1970: elapsed time: 0.06170046 seconds\n", "2260x2260: elapsed time: 0.081508947 seconds\n", "2570x2570: elapsed time: 0.17162104 seconds\n", "2900x2900: elapsed time: 0.161139746 seconds\n", "3250x3250: elapsed time: 0.198088675 seconds\n", "3620x3620: elapsed time: 0.219999655 seconds\n", "4010x4010: elapsed time: 0.39649807 seconds\n", "4420x4420: elapsed time: 0.76679111 seconds\n", "4850x4850: elapsed time: 0.693487129 seconds\n", "5300x5300: elapsed time: 0.997214341 seconds\n", "5770x5770: elapsed time: 1.162193135 seconds\n", "6260x6260: elapsed time: 1.549786969 seconds\n", "6770x6770: elapsed time: 1.827127481 seconds\n", "7300x7300: elapsed time: 2.624738668 seconds\n", "7850x7850: elapsed time: 2.886459943 seconds\n", "8420x8420: elapsed time: 3.315852673 seconds\n" ] } ], "source": [ "n = 30\n", "N = 10\n", "timeLU = zeros(n)\n", "timeSolve = zeros(n)\n", "vecN = ones(n)\n", "for i = 1:n\n", " A = rand(N,N)\n", " b = rand(N)\n", " \n", " # Time LU factorization:\n", " tic()\n", " print(string(N,\"x\",N,\": \"))\n", " LU = lufact(A) ## \"!\" means compute LU 'in place' - overwrite A\n", " timeLU[i] = toc()\n", " vecN[i] = N\n", " \n", " # Time LU backsub solve:\n", " tic()\n", " x = LU \\ b\n", " timeSolve[i] = toq() # quiet toc() -- no printout\n", "\n", " # Increase size\n", " N = 10 + 10*round(i^2)\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Plotting Time vs N" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "using PyPlot" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "image/png": "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AF6LoAMAALwWQQcAAHgtgg4AAPBaBB0AAOC1CDoAAMBrEXQAAIDXIugAAACvZesSEHbInwg6IyPD5koAAEBp5X9uO7ugg88FnSNHjkiSoqKibK4EAAA468iRIwoNDS31+T631lVeXp7+/PNPBQcHy+FwuOx9MzIyFBUVpV27drGGlgfgenkOrpXn4Fp5Dk+8VpZl6ciRI6pZs6YqVSr9yBufa9GpVKmSateuXW7vHxIS4jF/acD18iRcK8/BtfIcnnatnGnJycdgZAAA4LUIOgAAwGv5DR8+fLjdRXgLPz8/tW/fXv7+Ptcj6JG4Xp6Da+U5uFaew1eulc8NRgYAAL6DrisAAOC1CDoAAMBrEXQAAIDXIugAAACvRdBxkXfffVfR0dGqUqWKYmNj9d1339ldkldLSEhQq1atFBwcrLCwMN11113atm1boXMsy9Lw4cNVs2ZNBQUFqX379vr5558LnZOZmam+ffuqRo0auuCCC9S1a1ft3r270DmHDh3SQw89pNDQUIWGhuqhhx7S4cOHy/1n9FajRo2Sw+HQgAEDCo5xrdzHnj179OCDD+riiy9W1apV1bx5c61du7bgea6V+8jOzlZ8fLzq1q2roKAg1atXTyNGjFBeXl7BOVwvSRbO24wZM6yAgADr/ffft7Zs2WL179/fuuCCC6zk5GS7S/NanTp1siZPnmz99NNP1oYNG6zbb7/duvTSS62jR48WnDNq1CgrJCTESkxMtDZv3mzdf//9VmRkpJWRkVFwTq9evaxatWpZixcvttatW2fdeOONVrNmzaycnJyCc2699VYrJibGWrVqlbVq1SorJibGuuOOOyr05/UWP/74o1W3bl2radOmVv/+/QuOc63cw8GDB606depYjz76qPXDDz9YO3bssL7++mvrt99+KziHa+U+hg8fbl188cXWvHnzrB07dliffvqpVa1aNWvMmDEF53C9LIug4wJXX3211atXr0LHGjZsaL3wwgs2VeR79u7da0myli9fblmWZeXl5VkRERHWqFGjCs45efKkFRoaao0fP96yLMs6fPiwFRAQYM2YMaPgnD179liVKlWyFi5caFmWZW3ZssWSZH3//fcF5yQlJVmSrF9++aUifjSvceTIEat+/frW4sWLrRtuuKEg6HCt3MfQoUOtNm3alPg818q93H777dbjjz9e6Fi3bt2s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", "text/plain": [ "PyPlot.Figure(PyObject )" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "PyObject " ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot(vecN, timeLU, \"r-\") \n", "plot(vecN, timeSolve, \"b-\")\n", "xlabel(\"N\")\n", "ylabel(\"Time (sec)\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Julia 0.5.1", "language": "julia", "name": "julia-0.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "0.5.1" } }, "nbformat": 4, "nbformat_minor": 1 }