text:
### A Pluto.jl notebook ###
# v0.16.0

using Markdown
using InteractiveUtils

# ╔═╡ 0c76918a-1a2a-11ec-3670-0b5c1be7a8e3
begin
	using JSServe
	Page()
end

# ╔═╡ 6ada1e01-9486-4aff-99f3-5c7b54e47cd4
using LinearAlgebra, Distributions, WGLMakie

# ╔═╡ 146c4bd1-8935-48e8-9022-29d62762c86c
md"""

# Chapter 2: A moving robot

In the previous chapter, we looked at how to estimate the location of a stationary landmark using measurements of the landmark's location. We saw how we could easily compute the maximum likelihood estimate of the landmark's location, and we saw how we could incorporate information sequentially using Bayesian inference.

In this chapter, we will consider estimating the location of a moving robot. We'll derive Bayesian estimators of the robot's location using the techniques we learned in the first chapter. The propagation and update equations that implement Bayesian inference in this simple robot motion model form what's usually called a **Kalman filter**. We're going to develop the equations in a slightly different way from how they are usually introduced. My aim in building up the Kalman filter this way is to show that it is not some magical tool for tracking robots. It is a straightforward application of Bayesian inference to a particular model of dynamics and observations. **The model is the important thing** not the particular algorithm used to do inference using the model. Future chapters of these notes will introduce more and more complex models of a robot's interactions with its environment, and we'll have to develop more and more complex inference algorithms. But the algorithms always follow from the model.

## A simple motion model

The prior distribution that we developed for the stationary landmark in the previous chapter was simple:

```math
\mathbf{s} \sim \mathcal{N}(\boldsymbol{\mu}_0,\Sigma_0)
```

We interpreted this prior distribution as a statement about our uncertainty in the position of the landmark. We could also consider it a *generative model* for the location of the landmark. We could imagine, for example, that the landmark is a buoy dropped somewhere in the ocean. We think we dropped it in the ocean at ``\boldsymbol{\mu}_0``, but maybe our GPS was off a little bit or maybe some currents moved the buoy around a bit since we dropped it in. Those effects are modeled by the covariance matrix ``\Sigma_0``.

To construct a motion (or "kinematic") model for our robot, we'll develop a generative model with the same kind of thinking. Let's start by defining the robot's position as

```math
\mathbf{s}_t = \begin{bmatrix} x_t \\ y_t \end{bmatrix}
```

It is a position with an ``x`` and a ``y`` coordinate, just like the landmark's location, but this time the position has the subscript ``t``, to indicate that it is a position at a particular instance in time.

Our kinematic model tells us how the position of the robot evolves in time. We'll make two assumptions on the model. First, we only care about the robot's position at discrete time intervals -- ``t`` will be an integer, and we'll assume that the time step is 1. Second, we assume that the robot's movement is *Markovian*: the position at time ``t+1`` depends only on the position at time ``t`` and not on any times before ``t``. Non-Markovian models arise when you aren't considering all the possible degrees of freedom of the system. A common example in kinematics is if the robot's velocity changes in time. Then the future position depends not only on the current position but on the current velocity. You can get around this problem by modeling the position and the velocity together, and then the model is Markovian. But for now, we'll just consider Markovian models of the position.

Once again, we'll represent the model as a probability distribution

```math
\mathbf{s}_{t+1} | \mathbf{s}_t \sim f(\mathbf{s}_{t+1}|\mathbf{s}_t)
```

but unlike the prior distribution for the landmark location, this distribution is conditional on the location of the robot at the current time.

As a simple, concrete example of a motion model, let's first consider a two-dimensional Gaussian random walk:

```math
\mathbf{s}_{t+1} | \mathbf{s}_t \sim \mathcal{N}(\mathbf{s}_t,Q)
```

This model can also be written as the additive model

```math
\mathbf{s}_{t+1} = \mathbf{s}_t + Q^{1/2} \varepsilon_t
```

where ``Q^{1/2}`` is a matrix square root of the noise covariance ``Q`` and ``\varepsilon_t`` is an independent and identically distributed Gaussian noise vector.

One final detail that we need is a distribution over the initial position of the robot, ``\mathbf{s}_0``. Like in the location model, we'll take this to be a multivariate Gaussian distribution with mean ``\boldsymbol{\mu}_0`` and covariance ``\mathbf{\Sigma_0}``.

Let's implement this kinematic model and look at some realizations.
"""

# ╔═╡ 01a2c63a-deda-4b4c-b78b-76aacc6caa0b
# Motion model
function f(sₜ,Q)
	MvNormal(sₜ,Q)
end

# ╔═╡ df3273ca-f2bd-4fff-9c50-88e402806391
md"""
Let's define the initial position distribution
"""

# ╔═╡ 01050040-6137-484a-8db3-cb6057be103b
begin
	μ₀ = [0.0;0.0]
	Σ₀ = [10.0 0.0; 0.0 10.0]
	f₀ = MvNormal(μ₀,Σ₀)
end

# ╔═╡ a3617df0-c03e-4803-902c-6142606aa247
md"""
And the process noise covariance matrix.
"""

# ╔═╡ 1742dfda-e64c-495e-88b6-3b599fe0a779
Q = [0.1 0.0; 0.0 0.1]

# ╔═╡ 478d07b0-f1c7-45bf-a80e-c33e6c990dfd
md"""
We can generate realizations using the same `accumulate` pattern as we used in the last chapter. Another way to write this is

```julia
S = zeros(2,T+1)
S[:,1] = rand(f₀)
for i in 1:T
	S[:,i+1] = rand(f(S[:,i],Q))
end
```

The `accumulate` version is a little confusing, but we don't need to worry about allocating the right size array first, which can be easier when dealing with more complicated models.
"""

# ╔═╡ 0a55e363-ef40-4c21-a96c-e57abb5e9a00
begin
	T = 100
	s₀ = rand(f₀)
	S = [Point2(s₀),Point2.(accumulate((s,i)->rand(f(s,Q)),1:T,init=s₀))...]
end

# ╔═╡ d9ff5ffe-e6ba-40cc-80dc-39f9355eda9a
lines(S)

# ╔═╡ 8d64bd5a-fc2b-47f3-b85b-df8d544a374a
md"""
Now this random walk is a pretty bad model for robot motion. Technically, it could jump an infinite distance in a single time step, which is not physically possible. However, it is a simple model that lends itself to analysis and the algorithms that we'll look at in this chapter. We'll build up more complex and physically realistic models in further chapters.

## An observation model

Like in the landmark location problem, we'll assume that at each time step, we obtain noisy Gaussian observations of the robot's position:

```math
\mathbf{z}_t | \mathbf{s}_t \sim \mathcal{N}(\mathbf{s}_t,R)
```

The only difference between this observation model and the previous one is that the position depends on time. The observations conditional on the robot's position are independent, they are not independent from one another if we don't know the robot's position.

Let's generate a data set from our robot's track.

First, we'll start with the observation noise covariance matrix ``R``.
"""

# ╔═╡ 76d073f5-bfb9-44db-a93f-3a3d40815cfa
R = [0.1 0.0; 0.0 0.1]

# ╔═╡ 3b2a731a-a41c-4874-a4e3-652483adb01d
md"""
We construct the observation model.
"""

# ╔═╡ 600f394b-cae7-44c0-87d2-3cce741354f0
function g(sₜ,R)
	MvNormal(sₜ,R)
end

# ╔═╡ 83423791-6595-45d0-9979-19e7c11fb901
md"""
And we construct the data set. We assume that we have observations for ``t > 0``.
"""

# ╔═╡ 5744f7b1-49ba-43f0-b391-84ddec3ada9d
Z = Point2.(map(s->rand(g(s,R)),S[2:end]))

# ╔═╡ aa076f38-6b3a-4680-85c6-b7fa644ed2ba
begin
	fig1 = Figure()
	ax1 = Axis(fig1[1,1],xlabel="X",ylabel="Y")
	lines!(ax1,S)
	scatter!(ax1,Z)
	fig1
end

# ╔═╡ c693f411-1ffd-4035-b6a6-4dcd669492bd
md"""
To recap, our complete robot motion model is

```math
\begin{align}
\mathbf{s}_0 &\sim \mathcal{N}(\boldsymbol{\mu}_0,\Sigma_0) \\
\mathbf{s}_{t+1} | \mathbf{s}_t &\sim \mathcal{N}(\mathbf{s}_t,Q) \\
\mathbf{z}_t | \mathbf{s}_t &\sim \mathcal{N}(\mathbf{s}_t,R)
\end{align}
```

Our goal is to use the observations to estimate the position of the robot. We want the posterior distribution ``p(\mathbf{s}_{0:T}|\mathbf{z}_{1:T})``. This proves to be a little tricky to estimate, however, because observations after time ``t`` can inform the position of the robot at time ``t``. We essentially need to send information backwards in time. This is doable, and we'll see how to do it shortly, but first, we'll content ourselves with finding ``p(\mathbf{s}_T|\mathbf{z}_{1:T})``: the posterior distribution of the robot's location at the final time ``T`` given the observations up to and including ``\mathbf{z}_T``.

Recall our investigation of sequential inference in the landmark location problem. There, we figured out how ``p(\mathbf{s}|\mathbf{z}_{1:t+1})`` relates to ``p(\mathbf{s}|\mathbf{z}_{1:t})``, and we found using Bayes' rule that

```math
p(\mathbf{s}|\mathbf{z}_{1:t+1}) = \frac{p(\mathbf{z}_{t+1}|\mathbf{s})}{p(\mathbf{z}_{t+1})} p(\mathbf{s}|\mathbf{z}_{1:t})
```

At time ``t``, let's say that we know the distribution ``p(\mathbf{s}_t | \mathbf{z}_{1:t})`` and we want to find ``p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t+1})``. We need to do two things. First, we need to use our motion model to propagate the robot forward in time.

```math
p(\mathbf{s}_{t+1},\mathbf{s}_t | \mathbf{z}_{1:t}) = f(\mathbf{s}_{t+1}|\mathbf{s}_t)p(\mathbf{s}_t|\mathbf{z}_{1:t})
```

This is the joint distribution of ``\mathbf{s}_t`` and ``\mathbf{s}_{t+1}`` conditional on the observations ``\mathbf{z}_{1:t}``. To find the distribution of ``\mathbf{s}_{t+1}``, we integrate over (marginalize) ``\mathbf{s}_t``:

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t}) = \int f(\mathbf{s}_{t+1}|\mathbf{s}_t)p(\mathbf{s}_t|\mathbf{z}_{1:t})\ \mathrm{d}\mathbf{s}_t
```

Now we can incorporate the observation ``\mathbf{z}_{t+1}`` using Bayes' rule just as before

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t+1}) = \frac{p(\mathbf{z}_{t+1}|\mathbf{s}_{t+1})}{p(\mathbf{z}_{t+1})} p(\mathbf{s}_{t+1} | \mathbf{z}_{1:t})
```

These are our *filtering equations*, and they consist of two steps, the *propagation* step:

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t}) = \int f(\mathbf{s}_{t+1}|\mathbf{s}_t)p(\mathbf{s}_t|\mathbf{z}_{1:t})\ \mathrm{d}\mathbf{s}_t
```

and the *update* step:

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t+1}) = \frac{p(\mathbf{z}_{t+1}|\mathbf{s}_{t+1})}{p(\mathbf{z}_{t+1})} p(\mathbf{s}_{t+1} | \mathbf{z}_{1:t})
```

The update step is exactly the same update equation from the landmark location problem, and we'll compute it in the same way with Gaussian updates.

The propagation step is new, and we need to figure out how to compute ``p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t})``.

Start from the first time step. Here, we haven't used any observations at all, so our starting distribution is the initial distribution ``p(\mathbf{s}_0)``, which is multivariate normal with mean ``\boldsymbol{\mu}_0`` and covariance ``\Sigma_0``.

The additive model representation of this distribution is

```math
\mathbf{s}_0 = \boldsymbol{\mu}_0 + \Sigma_0^{1/2} \varepsilon_0
```

The additive model representation of the motion model is similar

```math
\mathbf{s}_1 = \mathbf{s}_0 + Q^{1/2} \varepsilon_1
```

Substituting the additive expression for ``\mathbf{s}_0`` into this expression, we can find that

```math
\mathbf{s}_1 \sim \mathcal{N}(\boldsymbol{\mu}_0,\Sigma_0 + Q)
```

This is the marginal distribution of ``\mathbf{s}_1``, which we saw earlier was given by the integral

```math
p(\mathbf{s}_1) = \int f(\mathbf{s}_1|\mathbf{s}_0) p(\mathbf{s}_0)\ \mathrm{d}\mathbf{s}_0
```

The nice properties of Gaussians mean that we don't need to do these integrals by hand. Instead we can use the additive model and figure out that the propagation equation at the first time step is

```math
p(\mathbf{s}_1) = \mathcal{N}(\boldsymbol{\mu}_0,\Sigma_0 + Q)
```

We'll see shortly that the posterior distribution of this model at any time step will be Gaussian, which means that we can represent it with a mean ``\boldsymbol{\mu}_t`` and covariance ``\Sigma_t``. The propagation equation then takes the same form

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t}) = \mathcal{N}(\boldsymbol{\mu}_t,\Sigma_t + Q)
```

This is the distribution that we need for the Bayesian update step:

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t+1}) = \frac{p(\mathbf{z}_{t+1}|\mathbf{s}_{t+1})}{p(\mathbf{z}_{t+1})} p(\mathbf{s}_{t+1} | \mathbf{z}_{1:t})
```

and we remember how to do this from the landmark location model. The only differences are that the covariance before we update is ``\Sigma_t + Q`` rather than ``\Sigma_t``, and we call our observation noise covariance ``R``. We get the update steps

```math
\begin{align}
\Sigma_{t+1} &= \left((\Sigma_t + Q)^{-1} + R^{-1}\right)^{-1}\\
\boldsymbol{\mu}_{t+1} &= \Sigma_{t+1}\left(R^{-1}\mathbf{z}_{t+1} + \left(\Sigma_t + Q\right)^{-1}\boldsymbol{\mu}_t\right)
\end{align}
```

Last time, we found that the update step was considerably simpler when using the canonical parameterization of the multivariate normal distribution. The parameterization looks like

```math
\begin{align}
\Lambda_t &= \Sigma_t^{-1} \\
\mathbf{j}_t &= \Sigma_t^{-1} \boldsymbol{\mu}_t
\end{align}
```

The propagation step in the canonical parameterization is

```math
p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t}) = \mathcal{N}((\Lambda_t^{-1} + Q)^{-1} \Lambda_t^{-1} \mathbf{j}_t,(\Lambda_t^{-1} + Q)^{-1}) = \mathcal{N}(\mathbf{j}_{t+1|t},\Lambda_{t+1|t})
```

where we have introduced some notation to indicate that ``\mathbf{j}_{t+1|t}`` is the potential vector of the distribution of ``\mathbf{s}_{t+1}`` conditioned on the observations up to time ``t`` and likewise for ``\Lambda``.

The update step is very simple

```math
\begin{align}
\Lambda_{t+1} &= \Lambda_{t+1|t} + R^{-1} \\
\mathbf{j}_{t+1} &= \mathbf{j}_{t+1|t} + R^{-1}\mathbf{z}_t
\end{align}
```

This illustrates the tradeoffs between the two parameterizations. In the traditional parameterization, marginalization is easy and conditioning is hard: the propagation step is simple and the update step is complicated. In the canonical parameterization, marginalization is hard and conditioning is easy: the propagation step is complicated and the update step is easy.

With all of that math out of the way, let's implement our filter. I'm going to do it in the canonical parameterization, but one could also do it in the traditional one.
"""

# ╔═╡ 0af7f865-2a2a-4a52-b8cd-61f85ce38081
function propagate(p::D,Q) where {D<: MvNormalCanon}
	jₜ,Λₜ = p.h,p.J
	Λ = inv(inv(Λₜ) + Q)
	j = Λ*(Λₜ\jₜ)
	MvNormalCanon(j,Λ)
end

# ╔═╡ 64116a20-3ae6-4513-af3b-7d68f162fd70
function update(p::D,z,Ri) where {D <: MvNormalCanon}
	# Note that Ri = inv(R) is the observation precision matrix

	jₜ,Λₜ = p.h,p.J

	Λ = Λₜ + Ri
	j = jₜ + Ri*z
	MvNormalCanon(j,Λ)
end

# ╔═╡ b1b1429e-2fba-4c86-8ae7-c02da3fe5dd4
function filter(p::D,z,Q,Ri) where {D <: MvNormalCanon}
	pn = propagate(p,Q)
	update(pn,z,Ri)
end

# ╔═╡ a03d277a-6c4b-477d-9da2-16235878eb16
# Set up our initial location distribution
p₀ = MvNormalCanon(Σ₀\μ₀,inv(Σ₀))

# ╔═╡ 6d411111-cee7-4ce6-a5c6-61c7b23b28db
# Observation precision matrix
Ri = inv(R)

# ╔═╡ ca7404de-630f-4a93-b094-a91476ba73f2
md"""
Now we have everything set up and we can run the filter.
"""

# ╔═╡ c56d78fd-8ada-4e8e-a7f4-9241d395ca42
ps = [p₀;accumulate((p,z)->filter(p,z,Q,Ri),Z,init=p₀)]

# ╔═╡ 311647ac-f5ba-4e6e-befc-ba602eddac42
begin
	fig2 = Figure()
	ax2 = Axis(fig2[1,1],xlabel="X",ylabel="Y")
	sl2 = Makie.Slider(fig2[2,1],range=0:T)

	xs = range(-10,10,length=256)

	P = lift(sl2.value) do idx
		[pdf(ps[idx+1],[x;y]) for x in xs, y in xs]
	end

	obs = lift(sl2.value) do idx
		if idx == 0
			[Point2(20.0,20.0)]
		else
			Z[1:idx]
		end
	end

	contour!(ax2,xs,xs,P)
	scatter!(ax2,obs,color=:black)

	xlims!(-10,10)
	ylims!(-10,10)
	fig2
end

# ╔═╡ e605bc20-c8b4-42ec-901f-47015b3a59ef
md"""
The contours represent the posterior probability distribution ``p(\mathbf{s}_t|\mathbf{z}_{1:t})`` as the observations are added sequentially by moving the slider to the right. The distribution quickly concentrates from the wide initial distribution to a much narrower distribution, but unlike the landmark location model, the distribution doesn't continue to narrow as we add observations. The noise of the kinematic model constantly injects uncertainty into the posterior distribution, which is partially but not completely canceled out by the information from new observations.

As I mentioned in the beginning, the way we have written the propagation and update equations is a little different from how they are usually presented. This way we see exactly what the Kalman filter equations are doing from a Bayesian inference perspective. The propagation equation computes the joint probability of the current position and the next position and then marginalizes out the current position, leaving the distribution ``p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t})``. The update equation applies a straightforward Bayesian update to this distribution with the observation ``\mathbf{z}_{t+1}`` to obtain the posterior distribution ``p(\mathbf{s}_{t+1}|\mathbf{z}_{1:t+1})```.

In the next few chapters, we will look at a more complex -- but still linear and Gaussian -- kinematic model and adapt our propagation and update equations to account for the additional parameters in the model. Then we'll start looking at nonlinear and non-Gaussian models, and we'll figure out how we need to modify the basic Kalman filtering algorithm to handle them.

"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
JSServe = "824d6782-a2ef-11e9-3a09-e5662e0c26f9"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
WGLMakie = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"

[compat]
Distributions = "~0.25.16"
JSServe = "~1.2.3"
WGLMakie = "~0.4.6"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[AbstractTrees]]
git-tree-sha1 = "03e0550477d86222521d254b741d470ba17ea0b5"
uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
version = "0.3.4"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[Animations]]
deps = ["Colors"]
git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d"
uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340"
version = "0.4.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "b8d49c34c3da35f220e7295659cd0bab8e739fed"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.33"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[Automa]]
deps = ["Printf", "ScanByte", "TranscodingStreams"]
git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe"
uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b"
version = "0.8.2"

[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.0"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "4ce9393e871aca86cc457d9f66976c3da6902ea7"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.4.0"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

[[ColorBrewer]]
deps = ["Colors", "JSON", "Test"]
git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4"
uuid = "a2cac450-b92f-5266-8821-25eda20663c8"
version = "0.4.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "9995eb3977fbf67b86d0a0a0508e83017ded03f2"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.14.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "a66a8e024807c4b3d186eb1cab2aff3505271f8e"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.6"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "4866e381721b30fac8dda4c8cb1d9db45c8d2994"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.37.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[DataAPI]]
git-tree-sha1 = "bec2532f8adb82005476c141ec23e921fc20971b"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.8.0"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[Distributions]]
deps = ["ChainRulesCore", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns"]
git-tree-sha1 = "f4efaa4b5157e0cdb8283ae0b5428bc9208436ed"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.16"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

[[EllipsisNotation]]
deps = ["ArrayInterface"]
git-tree-sha1 = "8041575f021cba5a099a456b4163c9a08b566a02"
uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
version = "1.1.0"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "463cb335fa22c4ebacfd1faba5fde14edb80d96c"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.5"

[[FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.10+0"

[[FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "3c041d2ac0a52a12a27af2782b34900d9c3ee68c"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.11.1"

[[FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"]
git-tree-sha1 = "caf289224e622f518c9dbfe832cdafa17d7c80a6"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.12.4"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[FreeType]]
deps = ["CEnum", "FreeType2_jll"]
git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4"
uuid = "b38be410-82b0-50bf-ab77-7b57e271db43"
version = "4.0.0"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[FreeTypeAbstraction]]
deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics", "StaticArrays"]
git-tree-sha1 = "19d0f1e234c13bbfd75258e55c52aa1d876115f5"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.9.2"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Graphics]]
deps = ["Colors", "LinearAlgebra", "NaNMath"]
git-tree-sha1 = "2c1cf4df419938ece72de17f368a021ee162762e"
uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
version = "1.1.0"

[[Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[GridLayoutBase]]
deps = ["GeometryBasics", "InteractiveUtils", "Match", "Observables"]
git-tree-sha1 = "e2f606c87d09d5187bb6069dab8cee0af7c77bdb"
uuid = "3955a311-db13-416c-9275-1d80ed98e5e9"
version = "0.6.1"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "60ed5f1643927479f845b0135bb369b031b541fa"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.14"

[[HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+0"

[[Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[IfElse]]
git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.0"

[[ImageCore]]
deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"]
git-tree-sha1 = "595155739d361589b3d074386f77c107a8ada6f7"
uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
version = "0.9.2"

[[ImageIO]]
deps = ["FileIO", "Netpbm", "OpenEXR", "PNGFiles", "TiffImages", "UUIDs"]
git-tree-sha1 = "13c826abd23931d909e4c5538643d9691f62a617"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.5.8"

[[ImageMagick]]
deps = ["FileIO", "ImageCore", "ImageMagick_jll", "InteractiveUtils", "Libdl", "Pkg", "Random"]
git-tree-sha1 = "5bc1cb62e0c5f1005868358db0692c994c3a13c6"
uuid = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
version = "1.2.1"

[[ImageMagick_jll]]
deps = ["JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "1c0a2295cca535fabaf2029062912591e9b61987"
uuid = "c73af94c-d91f-53ed-93a7-00f77d67a9d7"
version = "6.9.10-12+3"

[[Imath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e"
uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1"
version = "3.1.2+0"

[[IndirectArrays]]
git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "1.0.0"

[[Inflate]]
git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c"
uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
version = "0.1.2"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[IntelOpenMP_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c"
uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
version = "2018.0.3+2"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[Interpolations]]
deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
git-tree-sha1 = "61aa005707ea2cebf47c8d780da8dc9bc4e0c512"
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
version = "0.13.4"

[[IntervalSets]]
deps = ["Dates", "EllipsisNotation", "Statistics"]
git-tree-sha1 = "3cc368af3f110a767ac786560045dceddfc16758"
uuid = "8197267c-284f-5f27-9208-e0e47529a953"
version = "0.5.3"

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

[[Isoband]]
deps = ["isoband_jll"]
git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137"
uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4"
version = "0.1.1"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JSON3]]
deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"]
git-tree-sha1 = "b3e5984da3c6c95bcf6931760387ff2e64f508f3"
uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
version = "1.9.1"

[[JSServe]]
deps = ["Base64", "CodecZlib", "Colors", "HTTP", "Hyperscript", "JSON3", "LinearAlgebra", "Markdown", "MsgPack", "Observables", "SHA", "Sockets", "Tables", "Test", "UUIDs", "WebSockets", "WidgetsBase"]
git-tree-sha1 = "91101a4b8ac8eefeed6ca8eb4f663fc660e4d9f9"
uuid = "824d6782-a2ef-11e9-3a09-e5662e0c26f9"
version = "1.2.3"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[KernelDensity]]
deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"]
git-tree-sha1 = "591e8dc09ad18386189610acafb970032c519707"
uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
version = "0.6.3"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "34dc30f868e368f8a17b728a1238f3fcda43931a"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.3"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[MKL_jll]]
deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"]
git-tree-sha1 = "5455aef09b40e5020e1520f551fa3135040d4ed0"
uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
version = "2021.1.1+2"

[[Makie]]
deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "Observables", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "UnicodeFun"]
git-tree-sha1 = "7e49f989e7c7f50fe55bd92d45329c9cf3f2583d"
uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
version = "0.15.2"

[[MakieCore]]
deps = ["Observables"]
git-tree-sha1 = "7bcc8323fb37523a6a51ade2234eee27a11114c8"
uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
version = "0.1.3"

[[MappedArrays]]
git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.4.1"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[Match]]
git-tree-sha1 = "5cf525d97caf86d29307150fcba763a64eaa9cbe"
uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
version = "1.1.0"

[[MathTeXEngine]]
deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test"]
git-tree-sha1 = "f5c8789464aed7058107463e5cef53e6ad3f1f3e"
uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
version = "0.2.0"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MosaicViews]]
deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d"
uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
version = "0.3.3"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[MsgPack]]
deps = ["Serialization"]
git-tree-sha1 = "a8cbf066b54d793b9a48c5daa5d586cf2b5bd43d"
uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671"
version = "1.1.0"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[Netpbm]]
deps = ["FileIO", "ImageCore"]
git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.2"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Observables]]
git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
version = "0.4.0"

[[OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "c0e9e582987d36d5a61e650e6e543b9e44d9914b"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.7"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenEXR]]
deps = ["Colors", "FileIO", "OpenEXR_jll"]
git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633"
uuid = "52e1d378-f018-4a11-a4be-720524705ac7"
version = "0.3.2"

[[OpenEXR_jll]]
deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304"
uuid = "18a262bb-aa17-5467-a713-aee519bc75cb"
version = "3.1.1+0"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
git-tree-sha1 = "4dd403333bcf0909341cfe57ec115152f937d7d8"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.1"

[[PNGFiles]]
deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
git-tree-sha1 = "e14c485f6beee0c7a8dcf6128bf70b85f1fe201e"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.3.9"

[[Packing]]
deps = ["GeometryBasics"]
git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f"
uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566"
version = "0.4.2"

[[PaddedViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "646eed6f6a5d8df6708f15ea7e02a7a2c4fe4800"
uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
version = "0.5.10"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "438d35d2d95ae2c5e8780b330592b6de8494e779"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.3"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PkgVersion]]
deps = ["Pkg"]
git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37"
uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
version = "0.1.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "2537ed3c0ed5e03896927187f5f2ee6a4ab342db"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.14"

[[PolygonOps]]
git-tree-sha1 = "c031d2332c9a8e1c90eca239385815dc271abb22"
uuid = "647866c9-e3ac-4575-94e7-e3d426903924"
version = "0.1.1"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[ProgressMeter]]
deps = ["Distributed", "Printf"]
git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8"
uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
version = "1.7.1"

[[QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.4.2"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Ratios]]
deps = ["Requires"]
git-tree-sha1 = "01d341f502250e81f6fec0afe662aa861392a3aa"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.2"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[RelocatableFolders]]
deps = ["SHA", "Scratch"]
git-tree-sha1 = "0529f4188bc8efee85a7e580aca1c7dff6b103f8"
uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
version = "0.1.0"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rmath]]
deps = ["Random", "Rmath_jll"]
git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f"
uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
version = "0.7.0"

[[Rmath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7"
uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
version = "0.3.0+0"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[SIMD]]
git-tree-sha1 = "9ba33637b24341aba594a2783a502760aa0bff04"
uuid = "fdea26ae-647d-5447-a871-4b548cad5224"
version = "3.3.1"

[[ScanByte]]
deps = ["Libdl", "SIMD"]
git-tree-sha1 = "9cc2955f2a254b18be655a4ee70bc4031b2b189e"
uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb"
version = "0.3.0"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[ShaderAbstractions]]
deps = ["ColorTypes", "FixedPointNumbers", "GeometryBasics", "LinearAlgebra", "Observables", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "0d97c895406b552bed78f3a1fe9925248e908ae2"
uuid = "65257c39-d410-5151-9873-9b3e5be5013e"
version = "0.2.8"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[SignedDistanceFields]]
deps = ["Random", "Statistics", "Test"]
git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9"
uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96"
version = "0.4.0"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"]
git-tree-sha1 = "a322a9493e49c5f3a10b50df3aedaf1cdb3244b7"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.6.1"

[[StackViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
version = "0.1.1"

[[Static]]
deps = ["IfElse"]
git-tree-sha1 = "a8f30abc7c64a39d389680b74e749cf33f872a70"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.3.3"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "8cbbc098554648c84f79a463c9ff0fd277144b6c"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.10"

[[StatsFuns]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "46d7ccc7104860c38b11966dd1f72ff042f382e4"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "0.9.10"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.3"

[[StructTypes]]
deps = ["Dates", "UUIDs"]
git-tree-sha1 = "8445bf99a36d703a09c601f9a57e2f83000ef2ae"
uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
version = "1.7.3"

[[SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "1162ce4a6c4b7e31e0e6b14486a6986951c73be9"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.5.2"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[TensorCore]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
version = "0.1.1"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TiffImages]]
deps = ["ColorTypes", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "OffsetArrays", "OrderedCollections", "PkgVersion", "ProgressMeter"]
git-tree-sha1 = "632a8d4dbbad6627a4d2d21b1c6ebcaeebb1e1ed"
uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
version = "0.4.2"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.6"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[UnicodeFun]]
deps = ["REPL"]
git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
version = "0.4.1"

[[WGLMakie]]
deps = ["Colors", "FileIO", "FreeTypeAbstraction", "GeometryBasics", "Hyperscript", "ImageMagick", "JSServe", "LinearAlgebra", "Makie", "Observables", "ShaderAbstractions", "StaticArrays"]
git-tree-sha1 = "bafa1c4ab77626f8d8199209b740e097ae03805f"
uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"
version = "0.4.6"

[[WebSockets]]
deps = ["Base64", "Dates", "HTTP", "Logging", "Sockets"]
git-tree-sha1 = "f91a602e25fe6b89afc93cf02a4ae18ee9384ce3"
uuid = "104b5d7c-a370-577a-8038-80a2059c5097"
version = "1.5.9"

[[WidgetsBase]]
deps = ["Observables"]
git-tree-sha1 = "c1ef6e02bc457c3b23aafc765b94c3dcd25f174d"
uuid = "eead4739-05f7-45a1-878c-cee36b57321c"
version = "0.1.3"

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.3"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[isoband_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "a1ac99674715995a536bbce674b068ec1b7d893d"
uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4"
version = "0.2.2+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"
"""

# ╔═╡ Cell order:
# ╠═0c76918a-1a2a-11ec-3670-0b5c1be7a8e3
# ╠═6ada1e01-9486-4aff-99f3-5c7b54e47cd4
# ╟─146c4bd1-8935-48e8-9022-29d62762c86c
# ╠═01a2c63a-deda-4b4c-b78b-76aacc6caa0b
# ╟─df3273ca-f2bd-4fff-9c50-88e402806391
# ╠═01050040-6137-484a-8db3-cb6057be103b
# ╟─a3617df0-c03e-4803-902c-6142606aa247
# ╠═1742dfda-e64c-495e-88b6-3b599fe0a779
# ╟─478d07b0-f1c7-45bf-a80e-c33e6c990dfd
# ╠═0a55e363-ef40-4c21-a96c-e57abb5e9a00
# ╠═d9ff5ffe-e6ba-40cc-80dc-39f9355eda9a
# ╠═8d64bd5a-fc2b-47f3-b85b-df8d544a374a
# ╠═76d073f5-bfb9-44db-a93f-3a3d40815cfa
# ╟─3b2a731a-a41c-4874-a4e3-652483adb01d
# ╠═600f394b-cae7-44c0-87d2-3cce741354f0
# ╟─83423791-6595-45d0-9979-19e7c11fb901
# ╠═5744f7b1-49ba-43f0-b391-84ddec3ada9d
# ╟─aa076f38-6b3a-4680-85c6-b7fa644ed2ba
# ╟─c693f411-1ffd-4035-b6a6-4dcd669492bd
# ╠═0af7f865-2a2a-4a52-b8cd-61f85ce38081
# ╠═64116a20-3ae6-4513-af3b-7d68f162fd70
# ╠═b1b1429e-2fba-4c86-8ae7-c02da3fe5dd4
# ╠═a03d277a-6c4b-477d-9da2-16235878eb16
# ╠═6d411111-cee7-4ce6-a5c6-61c7b23b28db
# ╟─ca7404de-630f-4a93-b094-a91476ba73f2
# ╠═c56d78fd-8ada-4e8e-a7f4-9241d395ca42
# ╟─311647ac-f5ba-4e6e-befc-ba602eddac42
# ╟─e605bc20-c8b4-42ec-901f-47015b3a59ef
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: wkearn/SLAMNotes

max_issues_repo_name: wkearn/SLAMNotes

max_forks_repo_name: wkearn/SLAMNotes


text:
module ISMRMRD

__precompile__(true)

import Base: start, next, done, length, size, eltype;

# lots to export
export 	ISMRMRD_dataset,
	ISMRMRD_acquisition,
	ISMRMRD_acquisitionheader,
	ISMRMRD_EncodingCounters,
	read_xml_header,
	write_xml_header,
	append_dataset,
	read_acquisition,
	get_number_of_acquisitions,
	get_number_of_data_samples,
	get_number_of_trajectory_samples,
	get_data,
	get_trajectory,
	get_version,
	get_flags,
	get_meas_uid,
	get_scan_counter,
	get_acquisition_timestamp,
	get_physiology_timestamp,
	get_number_of_samples,
	get_available_channels,
	get_active_channels,
	get_channel_mask,
	get_discard_pre,
	get_discard_post,
	get_center_sample,
	get_encoding_space_ref,
	get_trajectory_dimensions,
	get_sample_time_us,
	get_position,
	get_read_dir,
	get_phase_dir,
	get_slice_dir,
	get_patient_table_position,
	get_encoding_counters,
	get_user_ints,
	get_user_floats,
	get_acquisitionheader,
	is_flag_set,
	length,
	size,
	start,
	done,
	next,
	eltype,
	get_field_strength,
	get_num_rx_channels,
	get_enc_fov,
	get_enc_matrix,
	get_recon_fov,
	get_recon_matrix,
	get_encoding_limits,
	get_tr,
	get_te,
	get_ti,
	get_flip_angle,
	read_all_data;

# I should find a way to do this better
const libismrmrdwrap="/home/knowles/src/my_src/utils/io/ISMRMRD.jl/src/libismrmrdwrapper.so";

# static array lengths
const	ISMRMRD_USER_INTS = 8;
const	ISMRMRD_USER_FLOATS = 8;
const	ISMRMRD_PHYS_STAMPS = 3;
const	ISMRMRD_CHANNEL_MASKS = 16;
const	ISMRMRD_NDARRAY_MAXDIM = 7;
const	ISMRMRD_POSITION_LENGTH = 3;
const	ISMRMRD_DIRECTION_LENGTH = 3;

#flags ::Type{UInt64}
const   ISMRMRD_ACQ_FIRST_IN_ENCODE_STEP1               = 0x0000000000000001;
const   ISMRMRD_ACQ_LAST_IN_ENCODE_STEP1                = 0x0000000000000002;
const   ISMRMRD_ACQ_FIRST_IN_ENCODE_STEP2               = 0x0000000000000003;
const   ISMRMRD_ACQ_LAST_IN_ENCODE_STEP2                = 0x0000000000000004;
const   ISMRMRD_ACQ_FIRST_IN_AVERAGE                    = 0x0000000000000005;
const   ISMRMRD_ACQ_LAST_IN_AVERAGE                     = 0x0000000000000006;
const   ISMRMRD_ACQ_FIRST_IN_SLICE                      = 0x0000000000000007;
const   ISMRMRD_ACQ_LAST_IN_SLICE                       = 0x0000000000000008;
const   ISMRMRD_ACQ_FIRST_IN_CONTRAST                   = 0x0000000000000009;
const   ISMRMRD_ACQ_LAST_IN_CONTRAST                    = 0x000000000000000A;
const   ISMRMRD_ACQ_FIRST_IN_PHASE                      = 0x000000000000000B;
const   ISMRMRD_ACQ_LAST_IN_PHASE                       = 0x000000000000000C;
const   ISMRMRD_ACQ_FIRST_IN_REPETITION                 = 0x000000000000000D;
const   ISMRMRD_ACQ_LAST_IN_REPETITION                  = 0x000000000000000E;
const   ISMRMRD_ACQ_FIRST_IN_SET                        = 0x000000000000000F;
const   ISMRMRD_ACQ_LAST_IN_SET                         = 0x0000000000000010;
const   ISMRMRD_ACQ_FIRST_IN_SEGMENT                    = 0x0000000000000011;
const   ISMRMRD_ACQ_LAST_IN_SEGMENT                     = 0x0000000000000012;
const   ISMRMRD_ACQ_IS_NOISE_MEASUREMENT                = 0x0000000000000013;
const   ISMRMRD_ACQ_IS_PARALLEL_CALIBRATION             = 0x0000000000000014;
const   ISMRMRD_ACQ_IS_PARALLEL_CALIBRATION_AND_IMAGING = 0x0000000000000015;
const   ISMRMRD_ACQ_IS_REVERSE                          = 0x0000000000000016;
const   ISMRMRD_ACQ_IS_NAVIGATION_DATA                  = 0x0000000000000017;
const   ISMRMRD_ACQ_IS_PHASECORR_DATA                   = 0x0000000000000018;
const   ISMRMRD_ACQ_LAST_IN_MEASUREMENT                 = 0x0000000000000019;
const   ISMRMRD_ACQ_IS_HPFEEDBACK_DATA                  = 0x000000000000001A;
const   ISMRMRD_ACQ_IS_DUMMYSCAN_DATA                   = 0x000000000000001B;
const   ISMRMRD_ACQ_IS_RTFEEDBACK_DATA                  = 0x000000000000001C;
const   ISMRMRD_ACQ_IS_SURFACECOILCORRECTIONSCAN_DATA   = 0x000000000000001D;

const   ISMRMRD_ACQ_COMPRESSION1                        = 0x0000000000000035;
const   ISMRMRD_ACQ_COMPRESSION2                        = 0x0000000000000036;
const   ISMRMRD_ACQ_COMPRESSION3                        = 0x0000000000000037;
const   ISMRMRD_ACQ_COMPRESSION4                        = 0x0000000000000038;
const   ISMRMRD_ACQ_USER1                               = 0x0000000000000039;
const   ISMRMRD_ACQ_USER2                               = 0x000000000000003A;
const   ISMRMRD_ACQ_USER3                               = 0x000000000000003B;
const   ISMRMRD_ACQ_USER4                               = 0x000000000000003C;
const   ISMRMRD_ACQ_USER5                               = 0x000000000000003D;
const   ISMRMRD_ACQ_USER6                               = 0x000000000000003E;
const   ISMRMRD_ACQ_USER7                               = 0x000000000000003F;
const   ISMRMRD_ACQ_USER8                               = 0x0000000000000040;

# Error codes
const ISMRMRD_BEGINERROR 	=-1;
const ISMRMRD_NOERROR		= 0;
const ISMRMRD_MEMORYERROR	= 1;
const ISMRMRD_FILEERROR		= 2;
const ISMRMRD_TYPEERROR		= 3;
const ISMRMRD_RUNTIMEERROR 	= 4;
const ISMRMRD_HDF5ERROR 	= 5;
const ISMRMRD_ENDERROR		= 6;

#  ISMRMRD data types
const ISMRMRD_USHORT   = 1;# /**< corresponds to uint16_t */
const ISMRMRD_SHORT    = 2;# /**< corresponds to int16_t */
const ISMRMRD_UINT     = 3;# /**< corresponds to uint32_t */
const ISMRMRD_INT      = 4;# /**< corresponds to int32_t */
const ISMRMRD_FLOAT    = 5;# /**< corresponds to float */
const ISMRMRD_DOUBLE   = 6;# /**< corresponds to double */
const ISMRMRD_CXFLOAT  = 7;# /**< corresponds to complex float */
const ISMRMRD_CXDOUBLE = 8;# /**< corresponds to complex double */

# Image Types
const ISMRMRD_IMTYPE_MAGNITUDE = 1;
const ISMRMRD_IMTYPE_PHASE     = 2;
const ISMRMRD_IMTYPE_REAL      = 3;
const ISMRMRD_IMTYPE_IMAG      = 4;
const ISMRMRD_IMTYPE_COMPLEX   = 5;

# Image Flags
const ISMRMRD_IMAGE_IS_NAVIGATION_DATA =  1;
const ISMRMRD_IMAGE_USER1              = 57;
const ISMRMRD_IMAGE_USER2              = 58;
const ISMRMRD_IMAGE_USER3              = 59;
const ISMRMRD_IMAGE_USER4              = 60;
const ISMRMRD_IMAGE_USER5              = 61;
const ISMRMRD_IMAGE_USER6              = 62;
const ISMRMRD_IMAGE_USER7              = 63;
const ISMRMRD_IMAGE_USER8              = 64;

type ISMRMRD_dataset
	ptr::Ptr{Void};

	function ISMRMRD_dataset(filename::String,g::String="dataset",a::String="r")
	    if a == "w"
		create_file = 1;
	    else
		create_file = 0;
	    end

	    if (create_file == 0) && !isfile(filename)
	      error("Cannot open ", filename, " for reading. Does file exist?");
	    end

	    ptr = ccall((:jl_ismrmrd_create_dataset, libismrmrdwrap),
			Ptr{Void},(Cstring, Cstring, Cint), filename,g, create_file);

	    smart_ptr = new(ptr);
	    finalizer(smart_ptr,
	       obj -> ccall((:jl_ismrmrd_delete_dataset,libismrmrdwrap),
		    Void, (Ptr{Void},), obj.ptr));

	    return smart_ptr;
	end
end

type ISMRMRD_acquisition
	ptr::Ptr{Void};

	function ISMRMRD_acquisition()
		ptr = ccall((:jl_ismrmrd_create_acquisition, libismrmrdwrap),
	      		Ptr{Void},() );
		smart_ptr = new(ptr);
		finalizer(smart_ptr, obj ->
	    		ccall((:jl_ismrmrd_delete_acquisition,libismrmrdwrap),
			Void, (Ptr{Void},), obj.ptr));
		return smart_ptr;
	end

	function ISMRMRD_acquisition(acq::ISMRMRD_acquisition)
		ptr = ccall((:jl_ismrmrd_copy_acquisition, libismrmrdwrap),
			Ptr{Void},(Ptr{Void},), acq.ptr);
		smart_ptr = new(ptr);
		finalizer(smart_ptr, obj ->
	    		ccall((:jl_ismrmrd_delete_acquisition,libismrmrdwrap),
			Void, (Ptr{Void},), obj.ptr));
		return smart_ptr;
	end

	function ISMRMRD_acquisition(samples::Int32,
			      channels::Int32, traj_dims::Int32)
		ptr = ccall((:jl_ismrmrd_setup_acquisition, libismrmrdwrap),
			Ptr{Void},(Cint, Cint, Cint),
				samples, channels, traj_dims);
		smart_ptr = new(ptr);
		finalizer(smart_ptr, obj ->
	    		ccall((:jl_ismrmrd_delete_acquisition,libismrmrdwrap),
			Void, (Ptr{Void},), obj.ptr));
		return smart_ptr;
	end

	function ISMRMRD_acquisition(ptr::Ptr{Void})
		return new(ptr);
	end

end

"""
ISMRMRD_image type
"""
type ISMRMRD_image
  ptr::Ptr{Void}
  function ISMRMRD_image()
    ptr = ccall((:jl_ismrmrd_create_image,libismrmrdwrap),
		Ptr{Void},());
    smart_ptr = new(ptr);
    finalizer(smart_ptr,obj -> ccall((:jl_ismrmrmd_delete_image,libismrmrdwrap),
				      Void, (Ptr{Void},),obj.ptr));
    return smart_ptr;

  end

  function ISMRMRD_image(ptr::Ptr{Void})
    return new(ptr);
  end
end

type ISMRMRD_EncodingCounters
	kspace_encode_step_1::Int16
	kspace_encode_step_2::Int16
	average::Int16
	slice::Int16
	contrast::Int16
	phase::Int16
	repetition::Int16
	set::Int16
	segment::Int16
	user::Array{Int16,1};
end

type ISMRMRD_acquisitionheader
	version::Int64;
	flags::UInt64;
	measurement_uid::Int64;
	scan_counter::Int64;
	acquisition_time_stamp::Int64;
	physiology_time_stamp::Array{Int64,1};
	number_of_samples::Int64;
	available_channels::Int64;
	active_channels::Int64;
	channel_mask::Array{Int64,1};
	discard_pre::Int64;
	discard_post::Int64;
	center_sample::Int64;
	encoding_space_ref::Int64;
	trajectory_dimensions::Int64;
	sample_time_us::Float32;
	position::Array{Float32,1};
	read_dir::Array{Float32,1};
	phase_dir::Array{Float32,1};
	slice_dir::Array{Float32,1};
	patient_table_position::Array{Float32,1};
	idx::ISMRMRD_EncodingCounters;
	user_int::Array{Int32,1};
	user_float::Array{Int64,1};
end

#Methods:Dataset
"""
read_xml_header(dset::ISMRMRD_dataset)
- reads the ismrmrmd header file and returns the XML data as a string
"""
function read_xml_header(dset::ISMRMRD_dataset)
	buffer = Array{UInt8,1}(10000);

	sz = ccall((:jl_ismrmrd_read_header, libismrmrdwrap),
		Cint,
		(Ptr{Void},Ptr{UInt8}),
		dset.ptr,buffer);

	return unsafe_string(pointer(buffer),sz);
end

"""
write_xml_header(dset::ISMRMRD_dataset)
- writes an XML header to a ismrmrmd file
"""
function write_xml_header(dset::ISMRMRD_dataset, xml_hdr::String)
	ccall((:jl_ismrmrd_write_header, libismrmrdwrap),
		Void,
		(Ptr{Void},Cstring),
		dset.ptr,xml_hdr);
end

"""
append_dataset(dset::ISMRMRD_dataset, acq::ISMRMRD_acquisition)
- pushes an acquisition to the dataset
"""
function append_dataset(dset::ISMRMRD_dataset, acq::ISMRMRD_acquisition)
	ccall((:jl_ismrmrd_append_acquisition, libismrmrdwrap),
		Void,
		(Ptr{Void},Ptr{Void}),
		dset.ptr,acq.ptr);
end

"""
read_acquisition(dset::ISMRMRD_dataset, idx::Int32)
- returns an ISMRMRD_acquisition type from the dataset at index idx
- note that idx should be in the range of 1:nAcqs
"""
function read_acquisition(dset::ISMRMRD_dataset, idx::Int)
	#checks
	num_acqs = get_number_of_acquisitions(dset);
	if idx < 1 || idx > num_acqs
		error("idx $idx is not a valid index number");
	end

	#convert to c style as expected by libismrmrdwrap
	idx -= 1;

	ptr=ccall((:jl_ismrmrd_read_acquisition, libismrmrdwrap),
		Ptr{Void},
		(Ptr{Void},Cint),
		dset.ptr,idx);

	return ISMRMRD_acquisition(ptr);
end

"""
get_number_of_acquisitions(dset::ISMRMRD_dataset)
- returns the number of acquisitions in the dataset
"""
function get_number_of_acquisitions(dset::ISMRMRD_dataset)
	return ccall((:jl_ismrmrd_get_number_of_acquisitions, libismrmrdwrap),
		Cint,
		(Ptr{Void},),
		dset.ptr);
end

#
#methods: acquisition
#
function get_number_of_data_samples(acq::ISMRMRD_acquisition)
	return ccall((:jl_ismrmrd_get_number_of_data_elements, libismrmrdwrap),
		Cint,
		(Ptr{Void},),
		acq.ptr);
end

function get_number_of_trajectory_samples(acq::ISMRMRD_acquisition)
	return ccall((:jl_ismrmrd_get_number_of_traj_elements, libismrmrdwrap),
		Cint,
		(Ptr{Void},),
		acq.ptr);
end

function get_data(acq::ISMRMRD_acquisition)
	data_ptr=ccall((:jl_ismrmrd_get_data_pointer, libismrmrdwrap),
		Ptr{Complex{Float32}},
		(Ptr{Void},),
		acq.ptr);
	ns = get_number_of_data_samples(acq);

	data = [];
	try
		data = unsafe_wrap(Array{Complex{Float32},1},data_ptr,ns);
	catch
		error("failed to load data for $ns samples");
	end

	return data;
end

function get_trajectory(acq::ISMRMRD_acquisition)
	data_ptr=ccall((:jl_ismrmrd_get_traj_pointer, libismrmrdwrap),
		Ptr{Complex{Float32}},
		(Ptr{Void},),
		acq.ptr);
	nt = get_number_of_trajectory_samples(acq);

	traj = [];
	try
		traj = unsafe_wrap(Array{Float32,1},data_ptr,nt);
	catch
		error("failed to load for $nt samples");
	end

	return traj;
end

function get_version(acq::ISMRMRD_acquisition)
  x = ccall((:jl_ismrmrd_header_version, libismrmrdwrap), Culonglong,(Ptr{Void},),acq.ptr);
	return convert(Int64,x);
end

function get_flags(acq::ISMRMRD_acquisition)
	return ccall((:jl_ismrmrd_header_flags, libismrmrdwrap), Culonglong,(Ptr{Void},),acq.ptr);
end

function get_meas_uid(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_measurement_uid, libismrmrdwrap),Cuint,(Ptr{Void},),acq.ptr);
	return convert(Int64,x);
end

function get_scan_counter(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_scan_counter,libismrmrdwrap),Cuint,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_acquisition_timestamp(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_acquisition_time_stamp,libismrmrdwrap),Cuint,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_physiology_timestamp(acq::ISMRMRD_acquisition)
	pts = Array{UInt32,1}(3);
	pts[1] = ccall((:jl_ismrmrd_header_physiology_time_stamp,libismrmrdwrap),Cuint,(Ptr{Void},Cint),acq.ptr,0);
	pts[2] = ccall((:jl_ismrmrd_header_physiology_time_stamp,libismrmrdwrap),Cuint,(Ptr{Void},Cint),acq.ptr,1);
	pts[3] = ccall((:jl_ismrmrd_header_physiology_time_stamp,libismrmrdwrap),Cuint,(Ptr{Void},Cint),acq.ptr,2);
	return convert(Array{Int64,1},pts);
end

function get_number_of_samples(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_number_of_samples,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_available_channels(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_available_channels,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_active_channels(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_active_channels,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_channel_mask(acq::ISMRMRD_acquisition)
	cmask = Array{UInt64,1}(ISMRMRD_CHANNEL_MASKS);
	for c=1:ISMRMRD_CHANNEL_MASKS
		cmask[c] = ccall((:jl_ismrmrd_header_channel_mask,libismrmrdwrap),Cushort,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return convert(Array{Int64,1}, cmask);
end

function get_discard_pre(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_discard_pre,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_discard_post(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_discard_post,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_center_sample(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_center_sample,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_encoding_space_ref(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_encoding_space_ref,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_trajectory_dimensions(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_trajectory_dimensions,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	return convert(Int64, x);
end

function get_sample_time_us(acq::ISMRMRD_acquisition)
	x = ccall((:jl_ismrmrd_header_sample_time_us,libismrmrdwrap),Cfloat,(Ptr{Void},),acq.ptr);
	return convert(Float64, x)
end

function get_position(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_POSITION_LENGTH);
	for c=1:ISMRMRD_POSITION_LENGTH
		x[c] = ccall((:jl_ismrmrd_header_position,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

function get_read_dir(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_DIRECTION_LENGTH);
	for c=1:ISMRMRD_DIRECTION_LENGTH
		x[c] = ccall((:jl_ismrmrd_header_read_dir,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

function get_phase_dir(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_DIRECTION_LENGTH);
	for c=1:ISMRMRD_DIRECTION_LENGTH
		x[c] = ccall((:jl_ismrmrd_header_phase_dir,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

function get_slice_dir(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_DIRECTION_LENGTH);
	for c=1:ISMRMRD_DIRECTION_LENGTH
		x[c] = ccall((:jl_ismrmrd_header_slice_dir,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

function get_patient_table_position(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_DIRECTION_LENGTH);
	for c=1:ISMRMRD_DIRECTION_LENGTH
		x[c] = ccall((:jl_ismrmrd_header_patient_table_position,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

"""
  returns the encoding counter for a given acquisition type
  Note: encoding counter is converted to Julia style 1-index,
  from the C-style 0-idx
"""
function get_encoding_counters(acq::ISMRMRD_acquisition)
	k1 = ccall((:jl_ismrmrd_get_ec_kspace_encode_step_1,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	k2 = ccall((:jl_ismrmrd_get_ec_kspace_encode_step_2,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	a = ccall((:jl_ismrmrd_get_ec_average,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	sli = ccall((:jl_ismrmrd_get_ec_slice,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	co = ccall((:jl_ismrmrd_get_ec_contrast,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	p = ccall((:jl_ismrmrd_get_ec_phase,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	r = ccall((:jl_ismrmrd_get_ec_repetition,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	set = ccall((:jl_ismrmrd_get_ec_set,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	seg = ccall((:jl_ismrmrd_get_ec_segment,libismrmrdwrap),Cushort,(Ptr{Void},),acq.ptr);
	user = Array{Int16,1}(ISMRMRD_USER_INTS)
	for c=1:ISMRMRD_USER_INTS
		user[c] =  ccall((:jl_ismrmrd_get_ec_user,libismrmrdwrap),Cushort,(Ptr{Void},Cint),acq.ptr,c-1);
	end

	# convert to signed ints so we don't have to read hex
	return ISMRMRD_EncodingCounters(convert(Int16,k1+1),
					convert(Int16,k2)+1,
					convert(Int16,a+1),
					convert(Int16,sli+1),
					convert(Int16,co+1),
					convert(Int16,p+1),
					convert(Int16,r+1),
					convert(Int16,set+1),
					convert(Int16,seg+1),
					convert(Array{Int16,1},user.+1));
end

function get_user_ints(acq::ISMRMRD_acquisition)
	x = Array{Int32,1}(ISMRMRD_USER_INTS);
	for c=1:ISMRMRD_USER_INTS
		x[c] = ccall((:jl_ismrmrd_header_user_float,libismrmrdwrap),Cint,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end
function get_user_floats(acq::ISMRMRD_acquisition)
	x = Array{Float32,1}(ISMRMRD_USER_FLOATS);
	for c=1:ISMRMRD_USER_FLOATS
		x[c] = ccall((:jl_ismrmrd_header_user_float,libismrmrdwrap),Cfloat,(Ptr{Void},Cint),acq.ptr,c-1);
	end
	return x;
end

function get_acquisitionheader(acq::ISMRMRD_acquisition)
	version = get_version(acq);
	flags = get_flags(acq);
	measurement_uid = get_meas_uid(acq);
	scan_counter = get_scan_counter(acq);
	acquisition_time_stamp = get_acquisition_timestamp(acq);
	physiology_time_stamp = get_physiology_timestamp(acq);
	number_of_samples = get_number_of_samples(acq);
	available_channels = get_available_channels(acq);
	active_channels = get_active_channels(acq);
	channel_mask = get_channel_mask(acq);
	discard_pre = get_discard_pre(acq);
	discard_post = get_discard_post(acq);
	center_sample=get_center_sample(acq);
	encoding_space_ref = get_encoding_space_ref(acq);
	trajectory_dimensions = get_trajectory_dimensions(acq);
	sample_time_us=get_sample_time_us(acq);
	pos= get_position(acq);
	read_dir=get_read_dir(acq);
	phase_dir=get_phase_dir(acq);
	slice_dir=get_slice_dir(acq);
	patient_table_position= get_patient_table_position(acq);
	idx= get_encoding_counters(acq);
	user_int=get_user_ints(acq);
	user_float=get_user_floats(acq)

	return ISMRMRD_acquisitionheader(version,flags,measurement_uid,scan_counter,
	acquisition_time_stamp,physiology_time_stamp,number_of_samples,available_channels,
	active_channels, channel_mask, discard_pre, discard_post, center_sample,
	encoding_space_ref, trajectory_dimensions, sample_time_us, pos, read_dir,
	phase_dir, slice_dir, patient_table_position, idx, user_int, user_float);
end

#
# flags
#
function is_flag_set(acq::ISMRMRD_acquisition, flag_val::UInt64)
	flags = get_flags(acq);
	bitmask = UInt64(1) << (flag_val - 1);
	return (flags & bitmask) > 0;
end

function is_flag_set(acq::ISMRMRD_acquisition, flag_vals::Array{UInt64})
	b = broadcast((x)->is_flag_set(acq,x),flag_vals);
	return isempty(find((x)->x==true,b)) ? false : true;
end

#
# dataset iterator interface
#
function length(dset::ISMRMRD_dataset)
	return get_number_of_acquisitions(dset);
end

function size(dset::ISMRMRD_dataset)
	return (length(dset),)
end

function start(dset::ISMRMRD_dataset)
	return 1;
end

function done(dset::ISMRMRD_dataset, curr_idx::Int64)
	num_acqs = length(dset);
	return curr_idx > num_acqs;
end

function next(dset::ISMRMRD_dataset, curr_idx::Int64)
	acq=read_acquisition(dset,curr_idx)
	next_idx = curr_idx + 1;
	return (acq, next_idx);
end

function eltype(dset::ISMRMRD_dataset)
	return ISMRMRD_acquisition;
end

#
# regex searches of the XML header
# Warning: these may not be consistent with your header
#s
function get_field_strength(xmlhdr::String)
	pat = r"\<systemFieldStrength_T\>(\d\.?\d+)\<\/systemFieldStrength_T\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_num_rx_channels(xmlhdr::String)
	pat = r"\<receiverChannels\>(\d+)\<\/receiverChannels\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return broadcast((x)->parse(Int64,x,10),m.captures);
	end
end

function get_enc_fov(xmlhdr::String)
	pat = r"\<encodedSpace\>.*\<fieldOfView_mm\>\n\t+\<x\>(\w+\.?\w+?)\<\/x\>\n\t+\<y\>(\w+\.?\w+)\<\/y\>\n\t+\<z\>(\w+\.?\w+)\<\/z\>\n\t+\<\/fieldOfView_mm\>.*\<\/encodedSpace\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_enc_matrix(xmlhdr::String)
	pat = r"\<encodedSpace\>\n\t+\<matrixSize\>\n\t+\<x\>(\d+)\<\/x\>\n\t+\<y\>(\d+)\<\/y\>\n\t+\<z\>(\d+)\<\/z\>\n\t+\<\/matrixSize\>.*\<\/encodedSpace\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return broadcast((x)->parse(Int64,x,10),m.captures);
	end
end

function get_recon_fov(xmlhdr::String)
	pat = r"\<reconSpace\>.*\<fieldOfView_mm\>\n\t+\<x\>(\w+\.?\w+?)\<\/x\>\n\t+\<y\>(\w+\.?\w+)\<\/y\>\n\t+\<z\>(\w+\.?\w+)\<\/z\>\n\t+\<\/fieldOfView_mm\>.*\<\/reconSpace\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_recon_matrix(xmlhdr::String)
	pat = r"\<reconSpace\>\n\t+\<matrixSize\>\n\t+\<x\>(\d+)\<\/x\>\n\t+\<y\>(\d+)\<\/y\>\n\t+\<z\>(\d+)\<\/z\>\n\t+\<\/matrixSize\>.*\<\/reconSpace\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return broadcast((x)->parse(Int64,x,10),m.captures);
	end
end

function get_encoding_limits(xmlhdr::String)
	# i hope you like horrible looking regex!
	pat=r"\<encodingLimits\>\n\t+\<kspace_encoding_step_1\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/kspace_encoding_step_1\>\n\t+\<kspace_encoding_step_2\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/kspace_encoding_step_2\>\n\t+\<average\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/average\>\n\t+\<slice\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/slice\>\n\t+\<contrast\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/contrast\>\n\t+\<phase\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/phase\>\n\t+\<repetition\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/repetition\>\n\t+\<set\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/set\>\n\t+\<segment\>\n\t+\<minimum\>(\d+)\<\/minimum\>\n\t+\<maximum\>(\d+)\<\/maximum\>\n\t+\<center\>(\d+)\<\/center\>\n\t+\<\/segment\>\n\t+\<\/encodingLimits\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	end

	# sort
	lims = broadcast((x)->parse(Int64,x,10),m.captures); #float.(m.captures);
	minLims = lims[1:3:end];
	maxLims = lims[2:3:end];
	cenLims = lims[3:3:end];

	return (minLims,maxLims,cenLims);

end

function get_tr(xmlhdr::String)
	pat = r"\<TR\>(\d\.?\d+)\<\/TR\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_te(xmlhdr::String)
	pat = r"\<TE\>(\d\.?\d+)\<\/TE\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_ti(xmlhdr::String)
	pat = r"\<TI\>(\d\.?\d+)\<\/TI\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

function get_flip_angle(xmlhdr::String)
	pat = r"\<flipAngle_deg\>(\d\.?\d+)\<\/flipAngle_deg\>"s;

	m = match(pat,xmlhdr);

	#better way to check?
	if isa(m,Void)
		return [];
	else
		return float.(m.captures);
	end
end

"""
 quick solution to read all data into an array
 returns a 11D array [nkx,nc,nky,nkz,nave,nsli,ncont,nph,nrep,nset,nseg]
"""
function read_all_data(dset::ISMRMRD_dataset, skip_flags::Array{UInt64,1})

	num_acqs = get_number_of_acquisitions(dset);
	#create an array based on encoding limits / matrix size
	hdr = read_xml_header(dset);
	enc_mat = get_enc_matrix(hdr);
	ns = enc_mat[1];
	nc = get_num_rx_channels(hdr);
	nc = nc[1];
	(lmin,lmax,lcen)=get_encoding_limits(hdr);

	#create array
	sz  = (	ns*nc,
		lmax[1]-lmin[1]+1,
		lmax[2]-lmin[2]+1,
		lmax[3]-lmin[3]+1,
		lmax[4]-lmin[4]+1,
		lmax[5]-lmin[5]+1,
		lmax[6]-lmin[6]+1,
		lmax[7]-lmin[7]+1,
		lmax[8]-lmin[8]+1,
		lmax[9]-lmin[9]+1);

	data = zeros(Complex{Float32},ns*nc,num_acqs);
	for acq in dset
		acqdata = get_data(acq);

		#skip certain flags
		if  !is_flag_set(acq,skip_flags)
			#idx = get_encoding_counters(acq);
			idx = get_scan_counter(acq);
			data[:,idx]=acqdata;
			#data[	:,
			#	idx.kspace_encode_step_1+1,
			#	idx.kspace_encode_step_2+1,
			#	idx.average+1,
			#	idx.slice+1,
			#	idx.contrast+1,
			#	idx.phase+1,
			#	idx.repetition+1,
			#	idx.set+1,
			#	idx.segment+1] = acqdata;
		end
	end

	#reshape & return
	# TODO: permute data? It is quite memory intensive...
	data=reshape(data,(ns,nc,sz[2],sz[3],sz[4],sz[5],sz[6],sz[7],sz[8],sz[9],sz[10]));
	return data;
end

"""
"""
function read_all_data(dset::ISMRMRD_dataset)
	# default flags to skip
	skip_flags = 	[ISMRMRD_ACQ_IS_NOISE_MEASUREMENT,
			ISMRMRD_ACQ_IS_PARALLEL_CALIBRATION,
			ISMRMRD_ACQ_IS_NAVIGATION_DATA,
			ISMRMRD_ACQ_IS_PHASECORR_DATA,
			ISMRMRD_ACQ_IS_DUMMYSCAN_DATA,
			ISMRMRD_ACQ_IS_RTFEEDBACK_DATA,
			ISMRMRD_ACQ_IS_SURFACECOILCORRECTIONSCAN_DATA];

	return read_all_data(dset,skip_flags);
end

"""
reads in ISMRMRD images from a dataset
"""
function read_image(dset::ISMRMRD_dataset,group::String, idx::Int)
	#checks
	# TODO, add checks
	#num_acqs = get_number_of_acquisitions(dset);
	#if idx < 1 || idx > num_acqs
	#	error("idx $idx is not a valid index number");
	#end

	ptr=ccall((:jl_ismrmrd_read_image, libismrmrdwrap),
		Ptr{Void},
		(Ptr{Void},Cstring,Cint),
		dset.ptr,group,idx-1);

	return ISMRMRD_image(ptr);
end

"""
returns the type of image data

for reference:
ISMRMRD_USHORT   = 1;# /**< corresponds to uint16_t */
ISMRMRD_SHORT    = 2;# /**< corresponds to int16_t */
ISMRMRD_UINT     = 3;# /**< corresponds to uint32_t */
ISMRMRD_INT      = 4;# /**< corresponds to int32_t */
ISMRMRD_FLOAT    = 5;# /**< corresponds to float */
ISMRMRD_DOUBLE   = 6;# /**< corresponds to double */
ISMRMRD_CXFLOAT  = 7;# /**< corresponds to complex float */
ISMRMRD_CXDOUBLE = 8;# /**< corresponds to complex double */
"""
function get_image_data_type(img::ISMRMRD_image)
  data_type = ccall((:jl_ismrmrd_get_image_data_type,libismrmrdwrap),
		    Cint,
		    (Ptr{Void},),
		    img.ptr);
  return data_type;
end

"""
returns image dimensions
"""
function get_image_dimensions(img::ISMRMRD_image)
  dims = ccall((:jl_ismrmrd_get_image_dims,libismrmrdwrap),
	      Ptr{Cushort},
	      (Ptr{Void},),
	     img.ptr);

  return convert.(Int,unsafe_wrap(Array,dims,3,false));
end

"""
returns the image data pointeed to by the ISMRMRD_image type
"""
function get_data(img::ISMRMRD_image)
  data_type = get_image_data_type(img);
  dims = get_image_dimensions(img);

  if data_type == 1
    ptr = ccall((:jl_ismrmrd_get_ushort_data,libismrmrdwrap),
		Ptr{Cushort},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 2
    ptr = ccall((:jl_ismrmrd_get_short_data,libismrmrdwrap),
		Ptr{Cshort},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 3
    ptr = ccall((:jl_ismrmrd_get_uint_data,libismrmrdwrap),
		Ptr{Cuint},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 4
    ptr = ccall((:jl_ismrmrd_get_int_data,libismrmrdwrap),
		Ptr{Cint},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 5
    ptr = ccall((:jl_ismrmrd_get_float_data,libismrmrdwrap),
		Ptr{Cfloat},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 6
    ptr = ccall((:jl_ismrmrd_get_double_data,libismrmrdwrap),
		Ptr{Cdouble},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 7
    ptr = ccall((:jl_ismrmrd_get_complex_float_data,libismrmrdwrap),
		Ptr{Complex64},
		(Ptr{Void},),
		img.ptr);
  elseif data_type == 8
    ptr = ccall((:jl_ismrmrd_get_complex_double_data,libismrmrdwrap),
		Ptr{Complex128},
		(Ptr{Void},),
		img.ptr);
  else
    error("unknown data type");
  end

  # will return an array of type T, given a pointer of Ptr{T}
  return unsafe_wrap(Array,ptr,(dims[1],dims[2],dims[3]),true); # let julia take ownership of the memory

end

end #module

ext: jl


text:
module KernelOps
import Base.size, Base.getindex, Base.IndexStyle
export KernelOp

struct KernelOp{T,N,S,F<:Function} <: AbstractArray{T,N}
    parent::S
    op::F
    opdims::CartesianIndex{N}
    lowbound::CartesianIndex{N}
    upbound::CartesianIndex{N}
    @inline function KernelOp{T,N,S,F}(operation::F,A::S,dims::CartesianIndex{N}) where {T,N,S<:AbstractArray,F<:Function}
        l=minimum(CartesianIndices(A))
        h=maximum(CartesianIndices(A))
        new{T,N,S,F}(A,operation,dims,l,h)
    end
end

@inline function KernelOp(op::F,A::AbstractArray{T,N},dims::NTuple{N,Int}) where {T,N,F<:Function}
    v=CartesianIndices(ntuple(i->1,N))
    ### Just in case compiler policy changes
    ## testout=op(A,v,first(v))
    ## KernelOp{eltype(testout),ndims(A),typeof(A),F}(op,A,CartesianIndex(dims))
    type_A=typeof(A)
    type_v=typeof(v)
    type_elv=typeof(first(v))
    rtypes=Base.return_types(op,(type_A,type_v,type_elv))
    KernelOp{Union{rtypes...},ndims(A),typeof(A),F}(op,A,CartesianIndex(dims))
end

@inline IndexStyle(::KernelOp) = IndexCartesian()

@inline function size_parent(A::KernelOp)
    size(A.parent)
end

@inline function size(A::KernelOp)
    return size_parent(A)
end

@inline function getindex(A::KernelOp{T,N,S},Index::Vararg{Int,N}) where {T,N,S}
    I=CartesianIndex(Index)
    @boundscheck checkbounds(A,I)
    @inbounds begin
        lowI=max(I-A.opdims,A.lowbound)
        upI=min(I+A.opdims,A.upbound)
        return A.op(A.parent,lowI:upI,I)
    end
end

end # module


text:
function terminate(iter::Class_iterate, par::Class_parameters)
    y = iter.point.y
    fark_feas1 = farkas_certificate(iter, y)
    fark_feas2 = stationary_infeasible_measure(iter, y)

    max_vio = get_max_vio(iter) # ???

    comp_scaled = maximum(iter.point.s .* y) * dual_scale(iter, par)

    if scaled_dual_feas(iter, 0.0, par) < par.term.tol_opt && comp_scaled < par.term.tol_opt && max_vio < par.term.tol_opt
        return :Optimal
    elseif max_vio > par.term.tol_opt && fark_feas1 < par.term.tol_inf_1 && fark_feas2 < par.term.tol_inf_2  #&& norm(get_y(iter), Inf) > 1/tol #&& norm(get_y(iter),Inf) > 1/tol
        return :primal_infeasible
    elseif norm(iter.point.x,Inf) > 1.0 / par.term.tol_unbounded # TMP!!!
        return :dual_infeasible
    elseif norm(iter.cache.grad,Inf) > par.term.grad_max
        return :max_gradient
    else
        return false
    end
end


text:
# assume ix = 1 and incx = 1

calc(::BM_TEST, ::FUNT, x, v) = calc(BM_JBase1(), FUNT(), x, v)
calc(::BM_JBase1, ::FUNT, x, v) = scale!(x, v)
calc(::BM_JBase2, ::FUNT, x, v) = scale!(v, x)
calc(::BM_BLAS, ::FUNT, x, v) = BLAS.scal!(length(x), v, x, 1)
calc(::BM_Broadcast, ::FUNT, x, v) = broadcast!(*, x, x, v)
calc(::BM_Forloop, ::FUNT, x, v) = scaleloop1(x, v)
function scaleloop1(x::Array, v)
    @inbounds for i=1:length(x)
        x[i] *= v
    end
    return x
end
calc(::BM_FAO, ::FUNT, x, v) = unsafe_fast_scale!(x, 1, v, length(x))

Base.start{T}(p::BenchCase{T,FUNT}, n::Int) =
    (rand(n), convert(Float64,1+1e-8))

function Base.run{Op,FUNT}(p::BenchCase{Op,FUNT}, n::Int, s)  # bench type, config, start value
    calc(Op(), FUNT(), s...)
    return nothing
end


text:
using PAPI
using FactCheck

const JULIAEXE = joinpath(JULIA_HOME, Base.julia_exename())

facts("PAPI library") do
    context("initialized") do
        @fact PAPI.is_initialized() => true
    end
end

facts("PAPI counters") do
    @fact PAPI.num_counters() > 0 => true
end

facts("PAPI components") do
    @fact PAPI.num_components() > 0 => true
end

facts("PAPI examples") do
    exampledir = joinpath(dirname(@__FILE__), "../examples")
    for ex in readdir(exampledir)
        testfile = joinpath(exampledir, ex)
        @fact success(`$JULIAEXE $testfile`) => true
    end
end

println("This file is $(@__FILE__)")


text:
"""
Add explicit year, month, and dayofweek columns to the df
"""
function _precompute!(df::DataFrame)::DataFrame

    df[!, "year"] = [Dates.year(d) for d in df.date]
    df[!, "month"] = [Dates.month(d) for d in df.date]
    df[!, "dayofweek"] = [Dates.dayofweek(d) for d in df.date]

    return df
end

function aggregate(df::DataFrame, columns...)

    # precompute some utilities for dates
    _precompute!(df)

    # group by and combine
    gdf = groupby(df, [c for c in columns])
    res = combine(gdf, :amount => sum)

    return res

end

function months(df::DataFrame)::Float64

    dayinmonth = 365.25 / 12
    ndays = Dates.value(maximum(df.date) - minimum(df.date))
    return ndays / dayinmonth

end

function fill_zeros!(groups::DataFrame)

    if "month" in names(groups)
        return fill_zeros_ym!(groups)
    else
        return fill_zeros_y!(groups)
    end
end

function fill_zeros_y!(groups::DataFrame)

    # earliest and latest year
    e_year = minimum(groups.year)
    l_year = maximum(groups.year)

    for year in e_year:1:l_year
        for c in unique(groups.category)
            cut = (groups.year .== year) .& (groups.category .== c)
            if nrow(groups[cut, :]) == 0
                push!(groups, (year=year, category=c, amount_sum=0))
            end
        end
    end

end

function fill_zeros_ym!(groups::DataFrame)

    # get the earliest and latest months
    e_year = minimum(groups.year)
    e_month = minimum(groups.month[groups.year .== e_year])
    l_year = maximum(groups.year)
    l_month = maximum(groups.month[groups.year .== l_year])

    # get all distinct categories
    has_categories = "category" in names(groups)
    if has_categories
        categories = unique(groups.category)
    end

    # loop over all years and months
    for date in Date(e_year, e_month):Dates.Month(1):Date(l_year, l_month)

        # extract the year and date
        y, m = year(date), month(date)

        # if has categories treat them separately
        if has_categories
            for cat in categories
                cut = (groups.year.==y) .& (groups.month.==m) .& (groups.category.==cat)
                if nrow(groups[cut, :]) == 0
                    push!(groups, (year=y, month=m, category=cat, amount_sum=0))
                end
            end
        # otherwise just one
        else
            cut = (groups.year.==y).&(groups.month.==m)
            if nrow(groups[cut, :]) == 0
                push!(groups, (year=y, month=m, amount_sum=0))
            end
        end
    end

    sort!(groups)

end

function fill_zeros!(exp::DataFrame, inc::DataFrame)

    # construct dates from years and months
    dates1 = unique([Date(y, m) for (y, m) in zip(exp.year, exp.month)])
    dates2 = unique([Date(y, m) for (y, m) in zip(inc.year, inc.month)])

    # determine the earliest and latest date
    earliest = minimum(vcat(dates1, dates2))
    latest = maximum(vcat(dates1, dates2))

    # check each year month combination to see if it is in both arrays
    for date in earliest:Dates.Month(1):latest

        y, m = year(date), month(date)

        # fill in expenses
        cut1 = (exp.year.==y) .& (exp.month.==m)
        if nrow(exp[cut1, :]) == 0
            push!(exp, (year=y, month=m, category="sport", amount_sum=0))
        end

        # fill in incomes
        cut2 = (inc.year.==y) .& (inc.month.==m)
        if nrow(inc[cut2, :]) == 0
            push!(inc, (year=y, month=m, amount_sum=0))
        end

    end

    return nothing

end

max_stars_repo_name: mzgubic/exchequer

max_issues_repo_name: mzgubic/exchequer

max_forks_repo_name: mzgubic/exchequer


text:
module DoubleIntegrator

using MDPs, PGFPlots
using DelimitedFiles

export state_space, action_space, transition, reward, simulate,
       viz_policy, viz_trajectory
export XMIN, XMAX, VMIN, VMAX

# mdp
const MX = 50
const MV = 50
const N = 1000

# state
const XMIN = -3.
const XMAX = 3.
const VMIN = -3.
const VMAX = 3.

# action
const AMIN = -1.0
const AMAX = 1.0

# transition
const DT = 0.1

# reward
const K = -.5

# test
const T = 200

function state_space(mx::Int64=MX, mv::Int64=MV)
    xs = range(XMIN, stop=XMAX, length=mx)
    vs = range(VMIN, stop=VMAX, length=mv)
    return RectangleGrid(xs, vs)
end

function action_space(n::Int64=N)
    return range(AMIN, stop=AMAX, length=n)
end

function transition(state::Vector{Float64}, action::Float64)
    snext = zeros(length(state))
    snext[2] = state[2] + action * DT
    snext[2] = clip(snext[2], VMIN, VMAX)
    snext[1] = clip(state[1] + snext[2] * DT, XMIN, XMAX)
    return snext
end

function clip(val::Float64, minval::Float64, maxval::Float64)
    return min(maxval, max(minval, val))
end

function reward(state::Vector{Float64}, action::Float64)
    return K * (state[1]^2 + state[2]^2)
end

function simulate(mdp::MDP, policy::Policy, state::Vector{Float64})
    trajectory = zeros(T, dimensions(mdp.S))
    actions = zeros(T)
    for t = 1:T
        trajectory[t, :] = state
        if state[1] == 0.0
            trajectory = trajectory[1:t, :]
            actions = actions[1:t - 1]
            break
        end
        action = policy!(policy, get_belief(mdp, state))
        state = mdp.transition(state, action)
        actions[t] = action
    end
    return trajectory, actions
end

function viz_policy(mdp::MDP, policy::Policy, title::String="Policy heatmap", saveplot::Bool=false, name::String="")
    function getmap(x::Float64, v::Float64)
        return policy!(policy, get_belief(mdp, [x, v]))
    end

    p = Axis([Plots.Image(getmap, (XMIN, XMAX), (VMIN, VMAX),
                      xbins = 250, ybins = 250,
                      colormap = ColorMaps.Named("Blues"))],
          width="14cm", height="14cm",
          xlabel="position", ylabel="speed",
          title=title)
    p
    if saveplot
      PGFPlots.save(name, p)
    end
end

function viz_trajectory(trajectory::Matrix{Float64}, actions::Vector{Float64},
                        title1::String="position over time", title2::String="acceleration over time",
                        saveplot::Bool=false, name::String="")
    g = GroupPlot(2, 1, groupStyle="horizontal sep=1.5cm")
    push!(g, Axis([Plots.Linear(trajectory[:, 1])],
                  width="12cm", height="12cm",
                  xlabel="time", ylabel="position",
                  title=title1))
    push!(g, Axis([Plots.Linear(actions)],
                  width="12cm", height="12cm",
                  xlabel="time", ylabel="acceleration",
                  title=title2))
    g
    if saveplot
      PGFPlots.save(name, g)
    end
end

end

max_stars_repo_name: tsamtsam/SV-RL

max_issues_repo_name: tsamtsam/SV-RL

max_forks_repo_name: tsamtsam/SV-RL


text:
# Nothing here yet

module HalfSine

using BigCombinatorics, SimplePolynomials

export semisine

include("data.txt")  # get the b-values

ndata = length(b)
a = [ b[k]//big(2)^(k-1) // Factorial(2k-1) for k=1:ndata ]

"""
`semisine(x,terms=10)` gives the analytic (power series)
value of the half sine.
"""
function semisine(x::Real,terms=10)
    x = _reset(x)
    sum(  a[k]*x^(2k-1) for k=1:terms)
end

include("rufus.jl")

end