Edit or run this notebook
6.3 ms
Package initialization
183 μs
"utf-8"
74.3 s

Scientific computing with Julia

David Widmann (@devmotion )

Uppsala University, Sweden

American University in Bulgaria, 17 February 2022

77.4 ms

About me

4.7 ms

Outline

We will see examples from and I will discuss my relation to

  • SciML (a lot)

  • Turing (a bit)

  • my research (a bit)

This is a very opinionated choice, there are many other great packages and organizations in Julia for scientific computing.

Note

I use Julia a lot and generally I am very satisfied with it. But this means:

  • I am quite biased

  • You will hear mostly good things about Julia in this talk

Please interrupt me at any time if you have a question 🙂

546 μs

"Why we created Julia"

Bezanson, Karpinski, Shah, and Edelman (2012):

In short, because we are greedy.

We want a language that's open source, with a liberal license.

We want the speed of C with the dynamism of Ruby.

We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell.

Something that is dirt simple to learn, yet keeps the most serious hackers happy.

We want it interactive and we want it compiled.

346 μs

Why we use Julia, 10 years later

14 February 2022

20.3 ms

Why do I use Julia?

I was curious and excited early on:

  • a, supposedly fast and cool, programming language! 🎉

  • that is open source 📖

  • and has a nice math-like syntax 😍

At TUM I had to learn and use MATLAB and R...

...but I used the opportunity and tried to work and become familiar with it for a course project during my Erasmus exchange in Uppsala.

541 μs

Initial contributions

I had noticed some things that were missing and maybe could be improved.

After I was done with my exchange year, I had some time and started to make my first small contributions.

260 μs

Barabási-Albert random graphs

First PR (archived, use Graphs.jl nowadays)

252 μs
barabasi_albert(n, k)

Create a Barabási–Albert model random graph with n vertices. It is grown by adding new vertices to an initial graph with k vertices. Each new vertex is attached with k edges to k different vertices already present in the system by preferential attachment. Initial graphs are undirected and consist of isolated vertices by default.

Optional Arguments

  • is_directed=false: if true, return a directed graph.

  • complete=false: if true, use a complete graph for the initial graph.

  • seed=-1: set the RNG seed.

Examples

julia> barabasi_albert(50, 3)
{50, 141} undirected simple Int64 graph

julia> barabasi_albert(100, Int8(10), is_directed=true, complete=true, seed=123)
{100, 990} directed simple Int8 graph
barabasi_albert(n::Integer, n0::Integer, k::Integer)

Create a Barabási–Albert model random graph with n vertices. It is grown by adding new vertices to an initial graph with n0 vertices. Each new vertex is attached with k edges to k different vertices already present in the system by preferential attachment. Initial graphs are undirected and consist of isolated vertices by default.

Optional Arguments

  • is_directed=false: if true, return a directed graph.

  • complete=false: if true, use a complete graph for the initial graph.

  • seed=-1: set the RNG seed.

Examples

julia> barabasi_albert(10, 3, 2)
{10, 14} undirected simple Int64 graph

julia> barabasi_albert(100, Int8(10), 3, is_directed=true, seed=123)
{100, 270} directed simple Int8 graph
81.0 ms
86.9 s

Weighted sampling without replacement

Faster algorithms

242 μs
efraimidis_aexpj_wsample_norep!([rng], a::AbstractArray, wv::AbstractWeights, x::AbstractArray)

Implementation of weighted sampling without replacement using Efraimidis-Spirakis A-ExpJ algorithm.

Reference: Efraimidis, P. S., Spirakis, P. G. "Weighted random sampling with a reservoir." Information Processing Letters, 97 (5), 181-185, 2006. doi:10.1016/j.ipl.2005.11.003.

Noting k=length(x) and n=length(a), this algorithm takes O(klog(k)log(n/k)) processing time to draw k elements. It consumes O(klog(n/k)) random numbers.

14.7 ms

SciML

5.2 ms
93.0 μs

Excerpt from the NumFOCUS project page:

SciML is an open source software organization created to unify the packages for scientific machine learning. This includes the development of modular scientific simulation support software, such as differential equation solvers, along with the methodologies for inverse problems and automated model discovery. By providing a diverse set of tools with a common interface, we provide a modular, easily-extendable, and highly performant ecosystem for handling a wide variety of scientific simulations.

SciML tools are used by many organizations, such as (but not limited to!) the CliMA: Climate Modeling Alliance, the New York Federal Reserve Bank, the Julia Robotics community, Pumas-AI: Pharmaceutical Modeling and Simulation, and the Brazilian National Institute for Space Research (INPE).

Disclaimer: I am a Github admin and member of the steering council of SciML, so I'm definitely biased 🙃

373 μs

Ordinary differential equation (ODE): Lotka-Volterra model

Differential equation model of predator-prey interaction:

ddt🐰=α🐰β🐰🦊ddt🦊=γ🦊+δ🐰🦊

238 μs
lotkavolterra! (generic function with 1 method)
1.1 ms

Problem formulation with initial value, integration time span, and default parameters:

185 μs
lotkavolterra_prob
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
timespan: (0.0, 10.0)
u0: 2-element Vector{Float64}:
 1.0
 1.0
983 ms

Solve problem:

195 μs
timestampvalue1value2
Float64Float64Float64
1
0.0
1.0
1.0
2
0.0776085
1.04549
0.857668
3
0.232645
1.17587
0.63946
4
0.429119
1.41968
0.456996
5
0.679082
1.87672
0.324733
6
0.944405
2.58825
0.263363
7
1.26746
3.86071
0.279446
8
1.61929
5.75081
0.522007
9
1.98698
6.81498
1.91778
10
2.26409
4.393
4.19467
more
6.0 s
161 ms
21.2 s
plot_lotkavolterra (generic function with 1 method)
308 ms

Different parameter choices:

205 μs
14.0 μs
6.1 s

Note

Many more details and explanations can be found in the official documentation. If you notice that anything is missing, unclear, or incorrect, it's great if you open an issue or pull request! 🙏

199 μs

Why don't we always use Euler's method?

Reference: Blog by Chris Rackauckas

A chaotic model of random neural networks (reference solution, computed with a high-order algorithm and very low tolerance):

398 μs
22.6 s
56.1 ms
13.3 s

A corresponding work-precision diagram:

Whenever someone in 2019 uses more code to internally implement a quick and dirty solver instead of running standard codes, a baby sheds a tear. It's not just about error or speed (or even accuracy: libraries undergo lots of tests!), it's about how much error you get with a certain speed. Euler's method (and even RK4) just don't scale well if you need non-trivial error on most equations.

45.8 ms

Comparison of different solvers

Lotka-Volterra (non-stiff)

ROBER (stiff)

356 μs

Only ODEs?!

Supported equations include

  • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations)

  • Ordinary differential equations (ODEs)

  • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods)

  • Stochastic ordinary differential equations (SODEs or SDEs)

  • Stochastic differential-algebraic equations (SDAEs)

  • Random differential equations (RODEs or RDEs)

  • Differential algebraic equations (DAEs)

  • Delay differential equations (DDEs)

  • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)

  • Stochastic delay differential equations (SDDEs)

  • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)

  • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions)

  • (Stochastic) partial differential equations ((S)PDEs) (with both finite difference and finite element methods)

955 μs

My relation to SciML

I wrote my master thesis about a mathematical model of quorum sensing of P. putida.

doi:10.3390/app6050149

Note

Often biological processes do not occur instantaneously but with some delay.

Here lactonase activity is regulated by PpuR-AHL complex with a specific time delay:

S(t)=D(S0S(t))γSS(t)nSKmnS+S(t)nSN(t)N(t)=N(t)(aS(t)nSKmnS+S(t)nSD)A(t)=(αA+βAC(t)n1C1n1+C(t)n1)N(t)γAA(t)DA(t)+γ3C(t)αC(RtotC(t))A(t)KEA(t)L(t)C(t)=αC(RtotC(t))A(t)γ3C(t)L(t)=αLC(tτ)n2C2n2+C(tτ)n2N(t)γLL(t)DL(t)

3.2 ms

Experimental data and numerical simulations:

doi:10.3390/app6050149 (adapted from doi:10.1007/s00216-014-8063-6)

20.6 ms

Simulation with MATLAB (dde23)

154 μs
22.7 ms

Simulation with DelayDiffEq.jl

Similar issues with default settings:

242 μs
19.8 s

Decreasing the step size improves the solution (also in MATLAB):

188 μs
121 ms

But this increases the number of steps and hence makes the computation slower! 😢

I really wanted to perform computations both efficiently and accurate.

So I decided to

  • work with Julia and improve DelayDiffEq

  • add support for more and also stiff methods based on the vast amount of existing methods for ODEs,

  • add callbacks that preserve domain constraints

455 μs

Stiff methods

Methods such as MethodOfSteps(Rosenbrock23()) can solve the DDE without restricting the step size:

229 μs
22.1 s

A simpler example: Mackey-Glass equation

Model of circulating blood cells x(t) at time t by Mackey and Glass

Given by

x(t)=βx(tτ)1+x(tτ)nγx(t),t0,x(t)=x0(t),t[τ,0]

  • Blood cells are destroyed at rate γ

  • Their production rate depends on concentration x(tτ) since

    [t]here is a significant delay τ between the initiation of cellular production in the bone marrow and the release of mature cells into the blood

500 μs
mackeyglass (generic function with 1 method)
651 μs
mackeyglass_history (generic function with 1 method)
326 μs
mackeyglass_prob
DDEProblem with uType Float64 and tType Float64. In-place: false
timespan: (0.0, 600.0)
u0: 0.5
136 ms

Define DDE problem with x0=0.5, β=2, γ=1, n=9.65, and τ=2 (values taken from here):

266 μs
7.4 s

Only differential equations?!

Core components are

  • Differential Equation Solving

  • Physics-Informed Model Discovery and Learning

  • Bridges to Python and R

  • Compiler-Assisted Model Analysis and Sparsity Acceleration

  • ML-Assisted Tooling for Model Acceleration

  • Differentiable Scientific Data Structures and Simulators

  • Tools for Accelerated Algorithm Development and Research

616 μs

Parameter estimation

Some noisy data:

204 μs
2.0 s
3.0 s

SciML supports many different packages for local and global optimization such as Optim.jl, LeastSquaresOptim.jl, JuMP, and any package that implements the MathProgBase interface such as NLOpt.jl.

The default evoluationary optimization algorithm in the package BlackBoxOptim.jl yields the following optimal parameters:

396 μs
blackbox_params
70.4 s

Optimized trajectories:

176 μs
86.3 ms

Neural ODEs

Example 1

Neural ODE:

ddt[🐰🦊]=NeuralNetwork([🐰🦊])

245 μs
291 s

Example 2

Physics-informed neural ODE model (or rather biology-informed in this case):

ddt[🐰🦊]=[🐰🦊]([softplus(c1)softplus(c2)]+NeuralNetwork([🐰🦊]))

215 μs
146 s

Probabilistic modelling

We only know noisy (i.e., slightly incorrect) number of predator and prey for some days but not parameters.

Idea: model uncertainty of unknown parameters with probability distributions

0 5 10 15 20 β 0.0 0.1 0.2 0.3 0.4 0.5 0.6 probability density function

Bayesian approach

Model uncertainty with conditional probability

pΘ|Y(θ|y)

of unknown parameters θ given observations y.

E.g.,

  • θ: unknown parameters α, β, γ, δ, and u(0) that we want to infer

  • y: number of observed predator and prey

Bayes' theorem

Conditional probability pΘ|Y(θ|y) can be calculated as

pΘ|Y(θ|y)=pY|Θ(y|θ)pΘ(θ)pY(y)

Workflow

  • Choose model pY|Θ(y|θ)

    • e.g., describes how daily cases of newly infected individuals depend on parameters

  • Choose prior pΘ(θ)

    • should incorporate initial beliefs and knowledge about θ

    • e.g., α, β, γ, δ, and u are non-negative

  • Compute

    pΘ|Y(θ|y)=pY|Θ(y|θ)pΘ(θ)pY(y)=pY|Θ(y|θ)pΘ(θ)pY|Θ(y|θ)pΘ(θ)dθ

5.3 s

⚠️ Issue

Often it is not possible to compute pΘ|Y(θ|y) exactly

163 μs

Discrete approximation

Idea: Approximate pΘ|Y(θ|y) with a weighted mixture of point measures

pΘ|Y(|y)iwiδθi()

where wi>0 and iwi=1.

This implies that

E(Θ|Y=y)iwiθi

and more generally

E(ϕ(Θ)|Y=y)iwiϕ(θi)

387 μs

number of samples: 500

161 ms
2.8 s

Probabilistic programming

Source: Lecture slides

Developing probabilistic models and inference algorithms is a time-consuming and error-prone process.

  • Probabilistic model written as a computer program

  • Automatic inference (integral part of the programming language)

Advantages:

  • Fast development of models

  • Expressive models

  • Widely applicable inference algorithms

3.5 ms

Turing

Turing is a probabilistic programming language (PPL).

Other PPLs

There are many other PPLs such as Stan, Birch, Gen, or Soss.

General design

  • Probabilistic models are implemented as a Julia function

  • One may use any Julia code inside of the model

  • Random variables and observations are declared with the ~ operator:

    @model function mymodel(x, y)
    ...
    # random variable `a` with prior distribution `dist_a`
    a ~ dist_a

    ...

    # observation `y` with data distribution `dist_y`
    y ~ dist_y
    ...
    end
  • PPL is implemented in DynamicPPL.jl, including @model macro

  • Turing.jl integrates and reexports different parts of the ecosystem such as the PPL, inference algorithms, and tools for automatic differentiation

722 μs

Bayesian inference of Lotka-Volterra model with Turing

A probabilistic model of the noisy observations of the Lotka-Volterra model:

αTruncatedNormal(1.5,0.52;0,5),βTruncatedNormal(1.0,0.52;0,5),γTruncatedNormal(3.0,0.52;0,5),δTruncatedNormal(1.0,0.52;0,5),σInverseGamma(10,1)[🐰n🦊n]Normal(LotkaVolterra(tn;α,β,γ,δ),σ2I2)for all n=1,,N,

where LotkaVolterra(t;α,β,γ,δ) is the solution of the Lotka-Volterra IVP at time t with initial value [1,1]T at time 0.

It can be implemented in the Turing probabilistic programming language (PPL):

405 μs
bayesian_lotkavolterra (generic function with 2 methods)
9.8 s

Prior distribution of trajectories

147 μs
11.6 s
898 ms

Markov chain Monte Carlo

154 μs
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
seriestype density has been moved to StatsPlots.  To use: `Pkg.add("StatsPlots"); using StatsPlots`
21.7 s
Found initial step size
ϵ
0.00625
Found initial step size
ϵ
0.025
The current proposal will be rejected due to numerical error(s).
isfinite.((θ, r, ℓπ, ℓκ))
The current proposal will be rejected due to numerical error(s).
isfinite.((θ, r, ℓπ, ℓκ))
The current proposal will be rejected due to numerical error(s).
isfinite.((θ, r, ℓπ, ℓκ))
Found initial step size
ϵ
0.05
Found initial step size
ϵ
0.05
The current proposal will be rejected due to numerical error(s).
isfinite.((θ, r, ℓπ, ℓκ))
The current proposal will be rejected due to numerical error(s).
isfinite.((θ, r, ℓπ, ℓκ))
197 s

Posterior distribution of trajectories

141 μs
12.4 s

Other frameworks

Again, the presentation is biased since I am part of the Turing team as well 🙃

However, SciML supports other PPLs (such as Stan) and "manual" (approximate) Bayesian inference with, e.g., DynamicHMC.jl and ApproxBayes.jl as well.

323 μs

Example: COVID-19 replication study

Links: Blog post, Github repo

19.3 ms

There is a lot more...

Many features of SciML and Turing and background information are not covered in this presentation.

Check out the SciML webpage https://sciml.ai, the Turing webpage https://turing.ml, and the documentation of the Julia packages.

You can also find a more detailed talks about DelayDiffEq, probabilistic modelling with Turing, and other research with Julia on my webpage: https://www.widmann.dev

381 μs
35.8 ms
36.7 ms
268 ms
Loading...
ii