Skip to content

Instantly share code, notes, and snippets.

@dmrd
Created April 29, 2016 01:14
Show Gist options
  • Save dmrd/84f53c04cf5b5d361a4dec13d7192c5e to your computer and use it in GitHub Desktop.
Save dmrd/84f53c04cf5b5d361a4dec13d7192c5e to your computer and use it in GitHub Desktop.
Notebook walking through a few Julia examples
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Outline\n",
"- Types\n",
"- Multiple dispatch\n",
"- Performance\n",
"- language interop\n",
" - C\n",
" - Python\n",
" - C++\n",
"- Macros\n",
"\n",
"\n",
"Julia is a dynamic, typed, JIT on LLVM language designed for technical computing. Familiar to users of python/matlab, but makes it much easier to go from initial prototyping to making it go fast.\n",
"\n",
"Yes, you often can make Python (with Cython/Numba/C/C++/Fortran) run as fast as Julia, but you're not going to enjoy it."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Types\n",
"- Dynamic & typed\n",
"- abstract & concrete types\n",
"- type inference by dataflow"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: Number isnumber LineNumberNode VersionNumber\n",
"\n"
]
},
{
"data": {
"text/latex": [
"No documentation found.\n",
"\\textbf{Summary:}\n",
"\\begin{verbatim}\n",
"abstract Number <: Any\n",
"\\end{verbatim}\n",
"\\textbf{Subtypes:}\n",
"\\begin{verbatim}\n",
"Complex{T<:Real}\n",
"Real\n",
"\\end{verbatim}\n"
],
"text/markdown": [
"No documentation found.\n",
"\n",
"**Summary:**\n",
"\n",
"```julia\n",
"abstract Number <: Any\n",
"```\n",
"\n",
"**Subtypes:**\n",
"\n",
"```julia\n",
"Complex{T<:Real}\n",
"Real\n",
"```\n"
],
"text/plain": [
"No documentation found.\n",
"\n",
"**Summary:**\n",
"\n",
"```julia\n",
"abstract Number <: Any\n",
"```\n",
"\n",
"**Subtypes:**\n",
"\n",
"```julia\n",
"Complex{T<:Real}\n",
"Real\n",
"```\n"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?Number"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Int64"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Int64"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Int64"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(1)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"super(Int64) = Signed\n",
"super(super(Int64)) = Integer\n"
]
},
{
"data": {
"text/plain": [
"Integer"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@show super(Int64)\n",
"@show super(super(Int64))"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Int64,1}:\n",
" 1\n",
" 2\n",
" 3"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"i64 = [1,2,3]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Float64,1}:\n",
" 1.0\n",
" 2.0\n",
" 3.0"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f64 = [1.0, 2.0, 3.0]"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Float16,1}:\n",
" 1.0\n",
" 2.0\n",
" 3.0"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f16 = Vector{Float16}([1, 2, 3])"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Any,1}:\n",
" \"test\"\n",
" 1 \n",
" 2 "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[\"test\", 1, 2]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"sizeof(i64) = 24\n",
"sizeof(f64) = 24\n",
"sizeof(f16) = 6\n"
]
},
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Ability to have relatively low level control\n",
"@show sizeof(i64)\n",
"@show sizeof(f64)\n",
"@show sizeof(f16)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2x5 Array{Int64,2}:\n",
" 1 3 5 7 9\n",
" 2 4 6 8 10"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Fortran / column major ordering\n",
"arr = reshape(collect(1:10), (2,5))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Yes, it's 1 indexed\n",
"arr[1]"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"10"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Use `end` instead of -1\n",
"arr[end]"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: AbstractArray AbstractSparseArray AbstractSparseMatrix\n",
"\n"
]
},
{
"data": {
"text/latex": [
"No documentation found.\n",
"\\textbf{Summary:}\n",
"\\begin{verbatim}\n",
"abstract AbstractArray{T,N} <: Any\n",
"\\end{verbatim}\n",
"\\textbf{Subtypes:}\n",
"\\begin{verbatim}\n",
"AbstractSparseArray{Tv,Ti,N}\n",
"Base.LinAlg.AbstractTriangular{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.HessenbergQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRCompactWYQ{S,M<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRPackedQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.SVDOperator{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},S}\n",
"Base.SparseMatrix.CHOLMOD.FactorComponent{Tv,S}\n",
"Bidiagonal{T}\n",
"Core.Inference.Range{T}\n",
"DenseArray{T,N}\n",
"Diagonal{T}\n",
"Hermitian{T,S<:AbstractArray{T,2}}\n",
"Range{T}\n",
"SubArray{T,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD}\n",
"SymTridiagonal{T}\n",
"Symmetric{T,S<:AbstractArray{T,2}}\n",
"Tridiagonal{T}\n",
"ZMQ.Message\n",
"\\end{verbatim}\n"
],
"text/markdown": [
"No documentation found.\n",
"\n",
"**Summary:**\n",
"\n",
"```julia\n",
"abstract AbstractArray{T,N} <: Any\n",
"```\n",
"\n",
"**Subtypes:**\n",
"\n",
"```julia\n",
"AbstractSparseArray{Tv,Ti,N}\n",
"Base.LinAlg.AbstractTriangular{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.HessenbergQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRCompactWYQ{S,M<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRPackedQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.SVDOperator{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},S}\n",
"Base.SparseMatrix.CHOLMOD.FactorComponent{Tv,S}\n",
"Bidiagonal{T}\n",
"Core.Inference.Range{T}\n",
"DenseArray{T,N}\n",
"Diagonal{T}\n",
"Hermitian{T,S<:AbstractArray{T,2}}\n",
"Range{T}\n",
"SubArray{T,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD}\n",
"SymTridiagonal{T}\n",
"Symmetric{T,S<:AbstractArray{T,2}}\n",
"Tridiagonal{T}\n",
"ZMQ.Message\n",
"```\n"
],
"text/plain": [
"No documentation found.\n",
"\n",
"**Summary:**\n",
"\n",
"```julia\n",
"abstract AbstractArray{T,N} <: Any\n",
"```\n",
"\n",
"**Subtypes:**\n",
"\n",
"```julia\n",
"AbstractSparseArray{Tv,Ti,N}\n",
"Base.LinAlg.AbstractTriangular{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.HessenbergQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRCompactWYQ{S,M<:AbstractArray{T,2}}\n",
"Base.LinAlg.QRPackedQ{T,S<:AbstractArray{T,2}}\n",
"Base.LinAlg.SVDOperator{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},S}\n",
"Base.SparseMatrix.CHOLMOD.FactorComponent{Tv,S}\n",
"Bidiagonal{T}\n",
"Core.Inference.Range{T}\n",
"DenseArray{T,N}\n",
"Diagonal{T}\n",
"Hermitian{T,S<:AbstractArray{T,2}}\n",
"Range{T}\n",
"SubArray{T,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD}\n",
"SymTridiagonal{T}\n",
"Symmetric{T,S<:AbstractArray{T,2}}\n",
"Tridiagonal{T}\n",
"ZMQ.Message\n",
"```\n"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?AbstractArray # Abstract types used to create the type hierarchy, but can't instantiate them "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Can talk about types, but don't have to\n",
"- Let's you write in a style closer to Python.\n",
"- Add types for:\n",
" - readability\n",
" - performance (e.g. use uint8 instead of int64 here)\n",
" - dispatching based on types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Multiple Dispatch\n",
"+ dispatch: choose method based on runtime types (not static types)\n",
"+ multiple: based on all arguments, not just first one\n",
"\n",
"`f(a,b,c)` vs. `a.f(b,c)`\n",
"\n",
"\n",
"## vs. overloading\n",
"- Method overloading done at compile time\n",
"- Multiple dispatch is done based on type at runtime\n",
"\n",
"## No \"classes\" - methods defined over data types"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"4 methods for generic function <b>eig</b>:<ul><li> eig<i>{T<:Real,S}</i>(A::<b>Union{Hermitian{Complex{T<:Real},S},Hermitian{T<:Real,S},Symmetric{T<:Real,S}}</b>, args...) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/linalg/symmetric.jl#L138\" target=\"_blank\">linalg/symmetric.jl:138</a><li> eig(A::<b>SparseMatrixCSC{Tv,Ti<:Integer}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/sparse/linalg.jl#L877\" target=\"_blank\">sparse/linalg.jl:877</a><li> eig(A::<b>Union{AbstractArray{T,2},Number}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/linalg/eigen.jl#L66\" target=\"_blank\">linalg/eigen.jl:66</a><li> eig(A::<b>Union{AbstractArray{T,2},Number}</b>, B::<b>Union{AbstractArray{T,2},Number}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/linalg/eigen.jl#L152\" target=\"_blank\">linalg/eigen.jl:152</a></ul>"
],
"text/plain": [
"# 4 methods for generic function \"eig\":\n",
"eig{T<:Real,S}(A::Union{Hermitian{Complex{T<:Real},S},Hermitian{T<:Real,S},Symmetric{T<:Real,S}}, args...) at linalg/symmetric.jl:138\n",
"eig(A::SparseMatrixCSC{Tv,Ti<:Integer}) at sparse/linalg.jl:877\n",
"eig(A::Union{AbstractArray{T,2},Number}) at linalg/eigen.jl:66\n",
"eig(A::Union{AbstractArray{T,2},Number}, B::Union{AbstractArray{T,2},Number}) at linalg/eigen.jl:152"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Each method may have many implementations for different combinations of arguments\n",
"methods(eig)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Implementing forward diff with dual numbers"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"importall Base"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"deriv (generic function with 1 method)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type Dual{T <: Real} <: Number\n",
" val::T\n",
" deriv::T\n",
"end\n",
"Dual(x::Real) = Dual(x, zero(x))\n",
"real(x::Dual) = x.val\n",
"deriv(x::Dual) = x.deriv"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"* (generic function with 139 methods)"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"+{T}(a::Dual{T}, b::Dual{T}) = Dual(real(a) + real(b), deriv(a) + deriv(b))\n",
"-{T}(a::Dual{T}, b::Dual{T}) = Dual(real(a) - real(b), deriv(a) - deriv(b))\n",
"function *{T}(a::Dual{T}, b::Dual{T})\n",
" av = real(a)\n",
" bv = real(b)\n",
" Dual(av * bv,\n",
" av * deriv(b) + bv * deriv(a)\n",
" )\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dual{Int64}(30,11)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = Dual(5, 1) # derivative w.r.t self is 1\n",
"x * x + x # 2x + 1 -> 11"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dual{Int64}(125,75)"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x ^ 3"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"^(x::<b>Number</b>, p::<b>Integer</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/intfuncs.jl#L107\" target=\"_blank\">intfuncs.jl:107</a>"
],
"text/plain": [
"^(x::Number, p::Integer) at intfuncs.jl:107"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@which x^2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Doesn't have a conversion from real -> Dual by default"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "LoadError",
"evalue": "LoadError: no promotion exists for Dual{Int64} and Int64\nwhile loading In[21], in expression starting on line 1",
"output_type": "error",
"traceback": [
"LoadError: no promotion exists for Dual{Int64} and Int64\nwhile loading In[21], in expression starting on line 1",
""
]
}
],
"source": [
"(x*3 + 5)^2"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dual{Int64}(400,120)"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(Dual(5) + x * Dual(3))^2 # d/dx = 6(3x + 5) -> 120"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"convert (generic function with 537 methods)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Can have Julia autoconvert instead of having to explicitly convert everything ourselves\n",
"convert{T<:Real}(::Type{Dual{T}}, x::Real) = Dual{T}(convert(T, x), zero(T))"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"promote_rule (generic function with 125 methods)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Julia automatically handles promotions for arithmetic between subtypes of Number\n",
"# This tells it what to do when asked to convert T -> Dual{T}\n",
"promote_rule{T <: Real}(::Type{Dual{T}}, ::Type{T}) = Dual{T}"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dual{Int64}(15,3)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3x"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dual{Int64}(400,120)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(5 + 3x)^2 # d/dx = 6(3x + 5) -> 120"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interacting with Other Languages\n",
"- Julia was built for the scientific programming world, which means it must be able to interface cleanly with existing code"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## FFI\n",
"FFI examples from the Julia docs illustrating basic cases"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: ccall c_calloc AbstractChannel\n",
"\n"
]
},
{
"data": {
"text/latex": [
"\\begin{verbatim}\n",
"ccall((symbol, library) or function_pointer, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)\n",
"\\end{verbatim}\n",
"Call function in C-exported shared library, specified by \\texttt{(function name, library)} tuple, where each component is a string or symbol.\n",
"Note that the argument type tuple must be a literal tuple, and not a tuple-valued variable or expression. Alternatively, \\texttt{ccall} may also be used to call a function pointer, such as one returned by \\texttt{dlsym}.\n",
"Each \\texttt{ArgumentValue} to the \\texttt{ccall} will be converted to the corresponding \\texttt{ArgumentType}, by automatic insertion of calls to \\texttt{unsafe_convert(ArgumentType, cconvert(ArgumentType, ArgumentValue))}. (See also the documentation for each of these functions for further details.) In most cases, this simply results in a call to \\texttt{convert(ArgumentType, ArgumentValue)}.\n"
],
"text/markdown": [
"```\n",
"ccall((symbol, library) or function_pointer, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)\n",
"```\n",
"\n",
"Call function in C-exported shared library, specified by `(function name, library)` tuple, where each component is a string or symbol.\n",
"\n",
"Note that the argument type tuple must be a literal tuple, and not a tuple-valued variable or expression. Alternatively, `ccall` may also be used to call a function pointer, such as one returned by `dlsym`.\n",
"\n",
"Each `ArgumentValue` to the `ccall` will be converted to the corresponding `ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType, cconvert(ArgumentType, ArgumentValue))`. (See also the documentation for each of these functions for further details.) In most cases, this simply results in a call to `convert(ArgumentType, ArgumentValue)`.\n"
],
"text/plain": [
"```\n",
"ccall((symbol, library) or function_pointer, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)\n",
"```\n",
"\n",
"Call function in C-exported shared library, specified by `(function name, library)` tuple, where each component is a string or symbol.\n",
"\n",
"Note that the argument type tuple must be a literal tuple, and not a tuple-valued variable or expression. Alternatively, `ccall` may also be used to call a function pointer, such as one returned by `dlsym`.\n",
"\n",
"Each `ArgumentValue` to the `ccall` will be converted to the corresponding `ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType, cconvert(ArgumentType, ArgumentValue))`. (See also the documentation for each of these functions for further details.) In most cases, this simply results in a call to `convert(ArgumentType, ArgumentValue)`.\n"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?ccall"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"f (generic function with 1 method)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f() = ccall( (:clock, \"libc\"), Int32, ())"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\t.section\t__TEXT,__text,regular,pure_instructions\n",
"Filename: In[28]\n",
"Source line: 1\n",
"\tpushq\t%rbp\n",
"\tmovq\t%rsp, %rbp\n",
"\tmovabsq\t$clock, %rax\n",
"Source line: 1\n",
"\tcallq\t*%rax\n",
"\tpopq\t%rbp\n",
"\tret\n"
]
}
],
"source": [
"@code_native f() # Just a low level function call"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"gethostname (generic function with 1 method)"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function gethostname()\n",
" hostname = Array(UInt8, 128)\n",
" ccall((:gethostname, \"libc\"), Int32,\n",
" (Ptr{UInt8}, Csize_t),\n",
" hostname, sizeof(hostname))\n",
" hostname[end] = 0; # ensure null-termination\n",
" return bytestring(pointer(hostname))\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"ddohan-mbp.corp.dropbox.com\""
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"gethostname()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Can pass Julia functions back to C"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: cfunction IntrinsicFunction broadcast_function broadcast!_function\n",
"\n"
]
},
{
"data": {
"text/latex": [
"\\begin{verbatim}\n",
"cfunction(function::Function, ReturnType::Type, (ArgumentTypes...))\n",
"\\end{verbatim}\n",
"Generate C-callable function pointer from Julia function. Type annotation of the return value in the callback function is a must for situations where Julia cannot infer the return type automatically.\n",
"For example:\n",
"\\begin{verbatim}\n",
"function foo()\n",
" # body\n",
"\n",
" retval::Float64\n",
"end\n",
"\n",
"bar = cfunction(foo, Float64, ())\n",
"\\end{verbatim}\n"
],
"text/markdown": [
"```\n",
"cfunction(function::Function, ReturnType::Type, (ArgumentTypes...))\n",
"```\n",
"\n",
"Generate C-callable function pointer from Julia function. Type annotation of the return value in the callback function is a must for situations where Julia cannot infer the return type automatically.\n",
"\n",
"For example:\n",
"\n",
"```\n",
"function foo()\n",
" # body\n",
"\n",
" retval::Float64\n",
"end\n",
"\n",
"bar = cfunction(foo, Float64, ())\n",
"```\n"
],
"text/plain": [
"```\n",
"cfunction(function::Function, ReturnType::Type, (ArgumentTypes...))\n",
"```\n",
"\n",
"Generate C-callable function pointer from Julia function. Type annotation of the return value in the callback function is a must for situations where Julia cannot infer the return type automatically.\n",
"\n",
"For example:\n",
"\n",
"```\n",
"function foo()\n",
" # body\n",
"\n",
" retval::Float64\n",
"end\n",
"\n",
"bar = cfunction(foo, Float64, ())\n",
"```\n"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?cfunction"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Ptr{Void} @0x00000003153f2570"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function mycompare{T}(a::T, b::T)\n",
" return convert(Cint, a < b ? -1 : a > b ? +1 : 0)::Cint\n",
"end\n",
"const mycompare_c = cfunction(mycompare, Cint, (Ref{Cdouble}, Ref{Cdouble}))"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4-element Array{Float64,1}:\n",
" -2.7\n",
" 1.3\n",
" 3.1\n",
" 4.4"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = [1.3, -2.7, 4.4, 3.1]\n",
"ccall(:qsort, Void, (Ptr{Cdouble}, Csize_t, Csize_t, Ptr{Void}),\n",
" A, length(A), sizeof(eltype(A)), mycompare_c)\n",
"A"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Python: PyCall\n",
"- Interop with Python is easy. Many Julia libraries (e.g. SymPy) wrap existing Python libs for simplicity\n",
"- A few crazy things, like defining Python classes IN JULIA (wut)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### SymPy example"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<script charset=\"utf-8\">(function ($, undefined) {\n",
"\n",
" function createElem(tag, attr, content) {\n",
"\t// TODO: remove jQuery dependency\n",
"\tvar el = $(\"<\" + tag + \"/>\").attr(attr);\n",
"\tif (content) {\n",
"\t el.append(content);\n",
"\t}\n",
"\treturn el[0];\n",
" }\n",
"\n",
" // A widget must expose an id field which identifies it to the backend,\n",
" // an elem attribute which is will be added to the DOM, and\n",
" // a getState() method which returns the value to be sent to the backend\n",
" // a sendUpdate() method which sends its current value to the backend\n",
" var Widget = {\n",
"\tid: undefined,\n",
"\telem: undefined,\n",
"\tlabel: undefined,\n",
"\tgetState: function () {\n",
"\t return this.elem.value;\n",
"\t},\n",
"\tsendUpdate: undefined\n",
" };\n",
"\n",
" var Slider = function (typ, id, init) {\n",
"\tvar attr = { type: \"range\",\n",
"\t\t value: init.value,\n",
"\t\t min: init.min,\n",
"\t\t max: init.max,\n",
"\t\t step: init.step },\n",
"\t elem = createElem(\"input\", attr),\n",
"\t self = this;\n",
"\n",
"\telem.onchange = function () {\n",
"\t self.sendUpdate();\n",
"\t}\n",
"\n",
"\tthis.id = id;\n",
"\tthis.elem = elem;\n",
"\tthis.label = init.label;\n",
"\n",
"\tInputWidgets.commInitializer(this); // Initialize communication\n",
" }\n",
" Slider.prototype = Widget;\n",
"\n",
" var Checkbox = function (typ, id, init) {\n",
"\tvar attr = { type: \"checkbox\",\n",
"\t\t checked: init.value },\n",
"\t elem = createElem(\"input\", attr),\n",
"\t self = this;\n",
"\n",
"\tthis.getState = function () {\n",
"\t return elem.checked;\n",
"\t}\n",
"\telem.onchange = function () {\n",
"\t self.sendUpdate();\n",
"\t}\n",
"\n",
"\tthis.id = id;\n",
"\tthis.elem = elem;\n",
"\tthis.label = init.label;\n",
"\n",
"\tInputWidgets.commInitializer(this);\n",
" }\n",
" Checkbox.prototype = Widget;\n",
"\n",
" var Button = function (typ, id, init) {\n",
"\tvar attr = { type: \"button\",\n",
"\t\t value: init.label },\n",
"\t elem = createElem(\"input\", attr),\n",
"\t self = this;\n",
"\tthis.getState = function () {\n",
"\t return null;\n",
"\t}\n",
"\telem.onclick = function () {\n",
"\t self.sendUpdate();\n",
"\t}\n",
"\n",
"\tthis.id = id;\n",
"\tthis.elem = elem;\n",
"\tthis.label = init.label;\n",
"\n",
"\tInputWidgets.commInitializer(this);\n",
" }\n",
" Button.prototype = Widget;\n",
"\n",
" var Text = function (typ, id, init) {\n",
"\tvar attr = { type: \"text\",\n",
"\t\t placeholder: init.label,\n",
"\t\t value: init.value },\n",
"\t elem = createElem(\"input\", attr),\n",
"\t self = this;\n",
"\tthis.getState = function () {\n",
"\t return elem.value;\n",
"\t}\n",
"\telem.onkeyup = function () {\n",
"\t self.sendUpdate();\n",
"\t}\n",
"\n",
"\tthis.id = id;\n",
"\tthis.elem = elem;\n",
"\tthis.label = init.label;\n",
"\n",
"\tInputWidgets.commInitializer(this);\n",
" }\n",
" Text.prototype = Widget;\n",
"\n",
" var Textarea = function (typ, id, init) {\n",
"\tvar attr = { placeholder: init.label },\n",
"\t elem = createElem(\"textarea\", attr, init.value),\n",
"\t self = this;\n",
"\tthis.getState = function () {\n",
"\t return elem.value;\n",
"\t}\n",
"\telem.onchange = function () {\n",
"\t self.sendUpdate();\n",
"\t}\n",
"\n",
"\tthis.id = id;\n",
"\tthis.elem = elem;\n",
"\tthis.label = init.label;\n",
"\n",
"\tInputWidgets.commInitializer(this);\n",
" }\n",
" Textarea.prototype = Widget;\n",
"\n",
" // RadioButtons\n",
" // Dropdown\n",
" // HTML\n",
" // Latex\n",
"\n",
" var InputWidgets = {\n",
"\tSlider: Slider,\n",
"\tCheckbox: Checkbox,\n",
"\tButton: Button,\n",
"\tText: Text,\n",
"\tTextarea: Textarea,\n",
"\tdebug: false,\n",
"\tlog: function () {\n",
"\t if (InputWidgets.debug) {\n",
"\t\tconsole.log.apply(console, arguments);\n",
"\t }\n",
"\t},\n",
"\t// a central way to initalize communication\n",
"\t// for widgets.\n",
"\tcommInitializer: function (widget) {\n",
"\t widget.sendUpdate = function () {};\n",
"\t}\n",
" };\n",
"\n",
" window.InputWidgets = InputWidgets;\n",
"\n",
"})(jQuery, undefined);\n",
"</script>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<div id=\"interact-js-shim\">\n",
" <script charset=\"utf-8\">\n",
"(function (IPython, $, _, MathJax, Widgets) {\n",
" $.event.special.destroyed = {\n",
"\tremove: function(o) {\n",
"\t if (o.handler) {\n",
"\t\to.handler.apply(this, arguments)\n",
"\t }\n",
"\t}\n",
" }\n",
"\n",
" var OutputArea = IPython.version >= \"4.0.0\" ? require(\"notebook/js/outputarea\").OutputArea : IPython.OutputArea;\n",
"\n",
" var redrawValue = function (container, type, val) {\n",
"\tvar selector = $(\"<div/>\");\n",
"\tvar oa = new OutputArea(_.extend(selector, {\n",
"\t selector: selector,\n",
"\t prompt_area: true,\n",
"\t events: IPython.events,\n",
"\t keyboard_manager: IPython.keyboard_manager\n",
"\t})); // Hack to work with IPython 2.1.0\n",
"\n",
"\tswitch (type) {\n",
"\tcase \"image/png\":\n",
" var _src = 'data:' + type + ';base64,' + val;\n",
"\t $(container).find(\"img\").attr('src', _src);\n",
"\t break;\n",
"\tdefault:\n",
"\t var toinsert = OutputArea.append_map[type].apply(\n",
"\t\toa, [val, {}, selector]\n",
"\t );\n",
"\t $(container).empty().append(toinsert.contents());\n",
"\t selector.remove();\n",
"\t}\n",
"\tif (type === \"text/latex\" && MathJax) {\n",
"\t MathJax.Hub.Queue([\"Typeset\", MathJax.Hub, toinsert.get(0)]);\n",
"\t}\n",
" }\n",
"\n",
"\n",
" $(document).ready(function() {\n",
"\tWidgets.debug = false; // log messages etc in console.\n",
"\tfunction initComm(evt, data) {\n",
"\t var comm_manager = data.kernel.comm_manager;\n",
" //_.extend(comm_manager.targets, require(\"widgets/js/widget\"))\n",
"\t comm_manager.register_target(\"Signal\", function (comm) {\n",
" comm.on_msg(function (msg) {\n",
" //Widgets.log(\"message received\", msg);\n",
" var val = msg.content.data.value;\n",
" $(\".signal-\" + comm.comm_id).each(function() {\n",
" var type = $(this).data(\"type\");\n",
" if (val[type]) {\n",
" redrawValue(this, type, val[type], type);\n",
" }\n",
" });\n",
" delete val;\n",
" delete msg.content.data.value;\n",
" });\n",
"\t });\n",
"\n",
"\t // coordingate with Comm and redraw Signals\n",
"\t // XXX: Test using Reactive here to improve performance\n",
"\t $([IPython.events]).on(\n",
"\t\t'output_appended.OutputArea', function (event, type, value, md, toinsert) {\n",
"\t\t if (md && md.reactive) {\n",
" // console.log(md.comm_id);\n",
" toinsert.addClass(\"signal-\" + md.comm_id);\n",
" toinsert.data(\"type\", type);\n",
" // Signal back indicating the mimetype required\n",
" var comm_manager = IPython.notebook.kernel.comm_manager;\n",
" var comm = comm_manager.comms[md.comm_id];\n",
" comm.then(function (c) {\n",
" c.send({action: \"subscribe_mime\",\n",
" mime: type});\n",
" toinsert.bind(\"destroyed\", function() {\n",
" c.send({action: \"unsubscribe_mime\",\n",
" mime: type});\n",
" });\n",
" })\n",
"\t\t }\n",
"\t });\n",
"\t}\n",
"\n",
"\ttry {\n",
"\t // try to initialize right away. otherwise, wait on the status_started event.\n",
"\t initComm(undefined, IPython.notebook);\n",
"\t} catch (e) {\n",
"\t $([IPython.events]).on('kernel_created.Kernel kernel_created.Session', initComm);\n",
"\t}\n",
" });\n",
"})(IPython, jQuery, _, MathJax, InputWidgets);\n",
"</script>\n",
" <script>\n",
" window.interactLoadedFlag = true\n",
" $(\"#interact-js-shim\").bind(\"destroyed\", function () {\n",
" if (window.interactLoadedFlag) {\n",
" console.warn(\"JavaScript required by Interact will be removed if you remove this cell or run using Interact more than once.\")\n",
" }\n",
" })\n",
" $([IPython.events]).on(\"kernel_starting.Kernel kernel_restarting.Kernel\", function () { window.interactLoadedFlag = false })\n",
" </script>\n",
"</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING: using Interact.select in module Main conflicts with an existing identifier.\n"
]
}
],
"source": [
"using SymPy\n",
"using Interact"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: symbols free_symbols symbol Symbol SymbolNode is_symbolic jacobi_symbol\n",
"\n"
]
},
{
"data": {
"text/latex": [
"Function to create one or more symbolic objects. These are specified with a string, with commas separating different variables.\n",
"This function allows the passing of assumptions about the variables such as \\texttt{positive=true}, \\texttt{real=true} or \\texttt{commutative=true}. See \\href{http://docs.sympy.org/dev/modules/core.html#module-sympy.core.assumptions}{SymPy Docs} for a complete list.\n",
"Example:\n",
"\\begin{verbatim}\n",
"x,y,z = symbols(\"x, y, z\", real=true)\n",
"\\end{verbatim}\n"
],
"text/markdown": [
"Function to create one or more symbolic objects. These are specified with a string, with commas separating different variables.\n",
"\n",
"This function allows the passing of assumptions about the variables such as `positive=true`, `real=true` or `commutative=true`. See [SymPy Docs](http://docs.sympy.org/dev/modules/core.html#module-sympy.core.assumptions) for a complete list.\n",
"\n",
"Example:\n",
"\n",
"```\n",
"x,y,z = symbols(\"x, y, z\", real=true)\n",
"```\n"
],
"text/plain": [
"Function to create one or more symbolic objects. These are specified with a string, with commas separating different variables.\n",
"\n",
"This function allows the passing of assumptions about the variables such as `positive=true`, `real=true` or `commutative=true`. See [SymPy Docs](http://docs.sympy.org/dev/modules/core.html#module-sympy.core.assumptions) for a complete list.\n",
"\n",
"Example:\n",
"\n",
"```\n",
"x,y,z = symbols(\"x, y, z\", real=true)\n",
"```\n"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?symbols"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [],
"text/plain": [
"Interact.Slider{Int64}(Signal{Int64}(5, nactions=0),\"n\",5,0:10,true)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [],
"text/plain": [
"Interact.Latex(\"\",\"\\$\\$8 x \\\\left(4 x^{4} \\\\cos{\\\\left (x^{2} \\\\right )} + 20 x^{2} \\\\sin{\\\\left (x^{2} \\\\right )} - 15 \\\\cos{\\\\left (x^{2} \\\\right )}\\\\right)\\$\\$\")"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"symx = symbols(\"x\")\n",
"\n",
"@manipulate for n = 0:10\n",
" latex(SymPy.diff(sin(symx^2), symx, n))\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [],
"text/plain": [
"Interact.Slider{Int64}(Signal{Int64}(5, nactions=0),\"n\",5,0:10,true)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 38,
"metadata": {
"comm_id": "54a7f1f8-ef88-4d25-967f-02866623647f",
"reactive": true
},
"output_type": "execute_result"
}
],
"source": [
"@manipulate for n = 0:10\n",
" n\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(let n = (Interact.widget)(0:10,\"n\")\n",
" display(n)\n",
" (map)(((n,)->begin # In[39], line 2:\n",
" n\n",
" end),(Interact.signal)(n))\n",
" end)"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"macroexpand(:(@manipulate for n = 0:10\n",
" n\n",
"end))"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"14 methods for generic function <b>sin</b>:<ul><li> sin(a::<b>Complex{Float16}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/float16.jl#L151\" target=\"_blank\">float16.jl:151</a><li> sin(z::<b>Complex{T<:Real}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/complex.jl#L548\" target=\"_blank\">complex.jl:548</a><li> sin(x::<b>Float64</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/math.jl#L137\" target=\"_blank\">math.jl:137</a><li> sin(x::<b>Float32</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/math.jl#L138\" target=\"_blank\">math.jl:138</a><li> sin(a::<b>Float16</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/float16.jl#L150\" target=\"_blank\">float16.jl:150</a><li> sin(x::<b>BigFloat</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/mpfr.jl#L610\" target=\"_blank\">mpfr.jl:610</a><li> sin(x::<b>Real</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/math.jl#L139\" target=\"_blank\">math.jl:139</a><li> sin<i>{Tv,Ti}</i>(A::<b>SparseMatrixCSC{Tv,Ti}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/sparse/sparsematrix.jl#L648\" target=\"_blank\">sparse/sparsematrix.jl:648</a><li> sin(a::<b>Array{SymPy.Sym,N}</b>) at <a href=\"https://github.com/jverzani/SymPy.jl/tree/d2f08e9d35f1fa84cfb5dc9427a31a4b19d51996/src/math.jl#L25\" target=\"_blank\">/Users/ddohan/.julia/v0.4/SymPy/src/math.jl:25</a><li> sin<i>{T<:Number}</i>(::<b>AbstractArray{T<:Number,1}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/operators.jl#L380\" target=\"_blank\">operators.jl:380</a><li> sin<i>{T<:Number}</i>(::<b>AbstractArray{T<:Number,2}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/operators.jl#L381\" target=\"_blank\">operators.jl:381</a><li> sin<i>{T<:Number}</i>(::<b>AbstractArray{T<:Number,N}</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/operators.jl#L383\" target=\"_blank\">operators.jl:383</a><li> sin<i>{T<:FixedSizeArrays.FixedArray{T,NDim,SIZE}}</i>(x::<b>T<:FixedSizeArrays.FixedArray{T,NDim,SIZE}</b>) at <a href=\"https://github.com/SimonDanisch/FixedSizeArrays.jl/tree/01bf5f5f1776111a5ca05ed88566ab90253d9e99/src/ops.jl#L55\" target=\"_blank\">/Users/ddohan/.julia/v0.4/FixedSizeArrays/src/ops.jl:55</a><li> sin(x::<b>SymPy.Sym</b>) at <a href=\"https://github.com/jverzani/SymPy.jl/tree/d2f08e9d35f1fa84cfb5dc9427a31a4b19d51996/src/math.jl#L22\" target=\"_blank\">/Users/ddohan/.julia/v0.4/SymPy/src/math.jl:22</a></ul>"
],
"text/plain": [
"# 14 methods for generic function \"sin\":\n",
"sin(a::Complex{Float16}) at float16.jl:151\n",
"sin(z::Complex{T<:Real}) at complex.jl:548\n",
"sin(x::Float64) at math.jl:137\n",
"sin(x::Float32) at math.jl:138\n",
"sin(a::Float16) at float16.jl:150\n",
"sin(x::BigFloat) at mpfr.jl:610\n",
"sin(x::Real) at math.jl:139\n",
"sin{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}) at sparse/sparsematrix.jl:648\n",
"sin(a::Array{SymPy.Sym,N}) at /Users/ddohan/.julia/v0.4/SymPy/src/math.jl:25\n",
"sin{T<:Number}(::AbstractArray{T<:Number,1}) at operators.jl:380\n",
"sin{T<:Number}(::AbstractArray{T<:Number,2}) at operators.jl:381\n",
"sin{T<:Number}(::AbstractArray{T<:Number,N}) at operators.jl:383\n",
"sin{T<:FixedSizeArrays.FixedArray{T,NDim,SIZE}}(x::T<:FixedSizeArrays.FixedArray{T,NDim,SIZE}) at /Users/ddohan/.julia/v0.4/FixedSizeArrays/src/ops.jl:55\n",
"sin(x::SymPy.Sym) at /Users/ddohan/.julia/v0.4/SymPy/src/math.jl:22"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Notice that the sin on SymPy is just added as another dispatch option\n",
"methods(sin)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Witchcraft: defining Python classes IN JULIA"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"using PyCall"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"PyObject <class 'Generator'>"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@pydef type Generator\n",
" __init__(self, vals) = (self[:vals] = vals; self[:i] = 1)\n",
" next(self) = begin\n",
" i = self[:i]\n",
" self[:i] = max((i + 1) % length(self[:vals]), 1)\n",
" return self[:vals][i]\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"10-element Array{Any,1}:\n",
" 1\n",
" 2\n",
" 3\n",
" 4\n",
" 1\n",
" 2\n",
" 3\n",
" 4\n",
" 1\n",
" 2"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyeval(\"[next(x) for i in range(0,10)]\", x=Generator([1,2,3,4,5]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Short interlude over to [`go.jl`](https://github.com/dmrd/go.jl/blob/master/src/policy.jl)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Calling Julia from Python\n",
"```\n",
"from julia import Julia\n",
"jl = Julia()\n",
"func = jl.eval(\"\"\"\n",
" function f(n)\n",
" ...\n",
" end\n",
" \"\"\")\n",
"func(5)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## C++: Cxx\n",
"[switch to Julia dev]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tools for writing simple scripts\n",
"- Julia makes it easy to write simple data munging and scripts that interact with filesystem\n",
"\n",
"- at repl, ; goes to command line mode"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cxx.ipynb\n",
"Intro to Julia.ipynb\n",
"images\n",
"julia5bak.ipynb\n",
"opencv.jl\n"
]
}
],
"source": [
";ls"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cxx.ipynb\n",
"Intro to Julia.ipynb\n",
"images\n",
"julia5bak.ipynb\n",
"opencv.jl\n"
]
}
],
"source": [
"run(`ls`)"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"images\n"
]
}
],
"source": [
"run(pipeline(`ls`, `grep image`))"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"hello\\n\""
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result = readall(`echo hello`)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"`rm -rf foo.aux foo.log foo.pdf bar.aux bar.log bar.pdf baz.aux baz.log baz.pdf qux.aux qux.log qux.pdf`"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"`rm -rf $[\"foo\",\"bar\",\"baz\",\"qux\"].$[\"aux\",\"log\",\"pdf\"]`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Designed for parallelism in mind"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"parallel_findpi (generic function with 1 method)"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# julia -p4 to launch with multiple workers\n",
"function findpi(n)\n",
" inside = 0\n",
" for i = 1:n\n",
" x, y = rand(2)\n",
" if (x^2 + y^2 <= 1.0)\n",
" inside += 1\n",
" end\n",
" end\n",
" 4.0 * inside / n\n",
"end\n",
"\n",
"function parallel_findpi(n)\n",
" inside = @parallel (+) for i = 1:n\n",
" x, y = rand(2)\n",
" x^2 + y^2 <= 1.0 ? 1 : 0\n",
" end\n",
" 4.0 * inside / n\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Performance\n",
"\n",
"## Benchmarks\n",
"- As with all benchmarks, read with caution, but gives the overall message: Julia can go fast\n",
"<img src=\"images/benchmarks.png\">"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"arraysum2 (generic function with 1 method)"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Type instability makes for slow code\n",
"# Dev tools exist to detect this\n",
"function arraysum1(x)\n",
" total = 0 # Here total is defined as an int\n",
" for i=1:length(x)\n",
" total += x[i]\n",
" end \n",
" total\n",
"end\n",
"\n",
"function arraysum2(x)\n",
" total = 0.0 # Here total is defined as a float\n",
" for i=1:length(x)\n",
" total += x[i]\n",
" end \n",
" total\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0.761832 seconds (20.00 M allocations: 305.307 MB, 23.13% gc time)\n",
" 0.024545 seconds (1.91 k allocations: 96.148 KB)\n"
]
}
],
"source": [
"arr = ones(10000000) # Ones creates floats\n",
"@time arraysum1(arr);\n",
"@time arraysum2(arr);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Going down the ladder of abstraction\n",
"- Julia lets you dive down into what your code is *actually* doing"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"sq (generic function with 1 method)"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Square the argument\"\n",
"sq(x) = x^2"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"search: sq sqr sqf sqrt sqrtm square squeeze sqf_part sqf_norm sqf_list\n",
"\n"
]
},
{
"data": {
"text/latex": [
"Square the argument\n"
],
"text/markdown": [
"Square the argument\n"
],
"text/plain": [
"Square the argument\n"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"?sq"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"define i64 @julia_sq_23257(i64) {\n",
"top:\n",
" %1 = mul i64 %0, %0\n",
" ret i64 %1\n",
"}\n",
"\n",
"define double @julia_sq_23262(double) {\n",
"top:\n",
" %1 = fmul double %0, %0\n",
" ret double %1\n",
"}\n"
]
}
],
"source": [
"# LLVM assembly\n",
"@code_llvm sq(5)\n",
"@code_llvm sq(5.0)"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\t.section\t__TEXT,__text,regular,pure_instructions\n",
"Filename: In[52]\n",
"Source line: 2\n",
"\tpushq\t%rbp\n",
"\tmovq\t%rsp, %rbp\n",
"Source line: 2\n",
"\timulq\t%rdi, %rdi\n",
"\tmovq\t%rdi, %rax\n",
"\tpopq\t%rbp\n",
"\tret\n",
"\t.section\t__TEXT,__text,regular,pure_instructions\n",
"Filename: In[52]\n",
"Source line: 2\n",
"\tpushq\t%rbp\n",
"\tmovq\t%rsp, %rbp\n",
"Source line: 2\n",
"\tmulsd\t%xmm0, %xmm0\n",
"\tpopq\t%rbp\n",
"\tret\n"
]
}
],
"source": [
"# Native assembly\n",
"@code_native sq(5)\n",
"@code_native sq(5.0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Julia is a Lisp with full macros\n",
"- Disclaimer: I am not a Lisper\n",
"- @macro syntax\n",
"<img src=\"images/macros.png\">"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Expr \n",
" head: Symbol call\n",
" args: Array(Any,(3,))\n",
" 1: Symbol +\n",
" 2: Int64 1\n",
" 3: Symbol b\n",
" typ: Any\n"
]
}
],
"source": [
"dump(:(1 + b))"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"+(x::<b>Number</b>, y::<b>Number</b>) at <a href=\"https://github.com/JuliaLang/julia/tree/a2f713dea5ac6320d8dcf2835ac4a37ea751af05/base/promotion.jl#L167\" target=\"_blank\">promotion.jl:167</a>"
],
"text/plain": [
"+(x::Number, y::Number) at promotion.jl:167"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Simple example: macro pulls apart expression to determine which method will be dispatched\n",
"@which 1 + 2.0"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0.515242 seconds (36.40 k allocations: 1.604 MB)\n"
]
}
],
"source": [
"@time rand(10000);"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(Base.code_native(sq,(Base.typesof)(5)))"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"macroexpand(:(@code_native sq(5)))"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"quote # util.jl, line 153:\n",
" local #106#stats = Base.gc_num() # util.jl, line 154:\n",
" local #108#elapsedtime = Base.time_ns() # util.jl, line 155:\n",
" local #107#val = rand(100000) # util.jl, line 156:\n",
" #108#elapsedtime = Base.-(Base.time_ns(),#108#elapsedtime) # util.jl, line 157:\n",
" local #109#diff = Base.GC_Diff(Base.gc_num(),#106#stats) # util.jl, line 158:\n",
" Base.time_print(#108#elapsedtime,#109#diff.allocd,#109#diff.total_time,Base.gc_alloc_count(#109#diff)) # util.jl, line 160:\n",
" #107#val\n",
"end"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"macroexpand(:(@time rand(100000)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Neat example application: [flow.jl](https://github.com/MikeInnes/Flow.jl)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Generated Functions "
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"foo (generic function with 1 method)"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Super simple example\n",
"# Generate a function body based on type of arguments\n",
"# Basically macros after type inference -> has type information\n",
"@generated function foo(x)\n",
" @show x\n",
" :(println(\"foo is \", x))\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x = Int64\n",
"foo is 1\n"
]
}
],
"source": [
"foo(1)"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"foo is 2\n"
]
}
],
"source": [
"# Note that the function is cached\n",
"foo(2)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x = Float64\n",
"foo is 1.0\n"
]
}
],
"source": [
"foo(1.0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"[Generated functions](https://groups.google.com/forum/#!topic/julia-users/a9PwoRvn4CU):\n",
"- Macros are functions evaluated at parse time, given the symbolic expressions (ASTs) of the arguments and returning a transformed expression\n",
"- Generated functions are functions evaluated at compile time, given the types of the arguments and returning a symbolic expression\n",
"- Ordinary functions are functions evaluated at runtime, given the values of the arguments and returning a value.\n",
"\n",
"\"\n",
"Keno's C++ interface (https://github.com/Keno/Cxx.jl) relies on generated functions. In order to call C++ functions, you need to know the argument types, and you don't generally know types until compile time. By allowing the C++ call to be computed at compile time via generated functions, you pay no runtime overhead for invoking the enormous Clang machinery to figure out C++.\n",
"\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# What's not so good?\n",
"- Still a young language\n",
" - still making breaking changes\n",
"- community isn't nearly as large as python\n",
" - not as much of a problem because it is so easy to wrap existing code\n",
"- Devtools aren't there yet\n",
" - Just getting a proper debugger\n",
" - IDE support isn't great"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.4.3",
"language": "julia",
"name": "julia-0.4"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment