text:
using FourierCore, FourierCore.Grid, FourierCore.Domain
using FFTW, LinearAlgebra, BenchmarkTools, Random, JLD2
using KernelAbstractions
# using CUDA
import FourierCore.OverEngineering: PointWiseSpectralOperator

include("ode.jl")

arraytype = Array
Ω = S¹(2π)^2
N = 2^7 # number of gridpoints
grid = FourierGrid(N, Ω, arraytype=arraytype)
(; nodes, wavenumbers) = grid

x = nodes[1]
y = nodes[2]
kˣ = wavenumbers[1]
kʸ = wavenumbers[2]

# construct filter
kxmax = maximum(kˣ)
kymax = maximum(kˣ)
filter = @. (kˣ)^2 + (kʸ)^2 ≤ ((kxmax / 2)^2 + (kymax / 2)^2)

# Operators
∂x = im * kˣ
∂y = im * kʸ

# to convert things to damping timescale of smallest wavelength
δ = min(x[2] - x[1], y[2] - y[1])

Δ = @. ∂x^2 + ∂y^2
Δᵞ = @. δ^2 * Δ - δ^4 * Δ^2 + δ^6 * Δ^3 - δ^8 * Δ^4 # δ^2 * Δ * exp(-2 * δ^2 * Δ)
# Δᵞ = @. δ^2 * Δ * exp(-δ^2 * Δ)

Δ⁻¹ = 1 ./ Δ
bools = (!).(isnan.(Δ⁻¹))
Δ⁻¹ .*= bools # hack in the fact that false * NaN = 0

kmax = maximum(kˣ)
kcutoff = floor(Int, kmax / 2)
s = 1
a = log(1 + 4π / N) / (kmax - kcutoff)^s
k = @. sqrt((kˣ)^2 + (kʸ)^2)
filter_mask = @. k ≤ kcutoff
expfilter = @. exp(-a * (k - kcutoff)^s) * (1 - filter_mask) + filter_mask

# Note that the first order derivative operators only return a smooth derivative
∂ˣ = PointWiseSpectralOperator(filter .* ∂x)
∂ʸ = PointWiseSpectralOperator(filter .* ∂y)
∇² = PointWiseSpectralOperator(Δ)
∇⁻² = PointWiseSpectralOperator(Δ⁻¹)
∇ᵞ = PointWiseSpectralOperator(Δᵞ)
Filter = PointWiseSpectralOperator(expfilter)

# Ics
ψ = @. sin(x) * sin(y) + 0im
ζ = @. -sin(x) * sin(y) + 0im
dζ = @. -sin(x) * sin(y) + 0im
q = @. sin(x) + 0im * y
u = @. sin(x) * cos(y) + 0im
v = @. -cos(x) * sin(y) + 0im

# Tests: Quick Check
norm(-∂ˣ(ψ) - v)
norm(∂ʸ(ψ) - u)

#=
random forcing prep
rng = MersenneTwister(1234)
# Random.seed!(123456789)
Random.seed!(12)
φ̇ = arraytype(zeros(12,12))
rng = MersenneTwister(1234)
randn!(rng, φ̇)
φ̇ .*= sqrt(1 / 12)
=#

function rhs!(dS, S, b)
    # unpack state
    ζ = view(S, :, :, 1)
    dζ = view(dS, :, :, 1)
    # q = view(S, :, :, 2)
    # dq = view(dS, :, :, 2)
    q₁ = view(S, :, :, 2)
    dq₁ = view(dS, :, :, 2)

    q₁ .= Filter(q₁)
    ζ .= Filter(ζ)

    τ = 1e-2
    γ = 1.0
    e = 0.1
    c = 1 / τ * q₁ .* (real.(q₁) .> 0)
    # compute rhs
    ψ .= ∇⁻²(ζ)
    dζ .= ∂ʸ(ψ) .* ∂ˣ(ζ) - ∂ʸ(ζ) .* ∂ˣ(ψ) - 0.03 * ζ + 0.00 .* ∇ᵞ(ζ)
    # should evolve q₁ = q - qₛ where qₛ = γ * y # q = ⟨q⟩ + q'
    # q = q₁ + qₛ
    # dq .= ∂ʸ(ψ) .* ∂ˣ(q) - ∂ʸ(q) .* ∂ˣ(ψ) + 0.01 .* ∇ᵞ(q)
    dq₁ .= ∂ʸ(ψ) .* ∂ˣ(q₁) - ∂ʸ(q₁) .* ∂ˣ(ψ) - γ * ∂ˣ(ψ) + 0.00 .* ∇ᵞ(q₁)
    dq₁ .+= e .- c

    dq₁ .= Filter(dq₁)
    dζ .= Filter(dζ)
    return nothing
end

function stochastic_update!(S, dt, x, y)
    ζ = view(S, :, :, 1)
    a = 1.0
    a1 = a * 0.3 * randn()
    a2 = a * 0.3 * randn()
    a3 = a * 0.3 * randn()
    a4 = a * 0.3 * randn()
    a5 = a * 0.3 * randn()
    a6 = a * 0.3 * randn()
    a7 = a * 0.3 * randn()
    a8 = a * 0.3 * randn()
    a9 = a * 0.3 * randn()
    forcing = @. a1 * cos(2 * x) * cos(2 * y) + a2 * cos(3 * x) * cos(3 * y) + a5 * cos(2 * x) * cos(3 * y) + a6 * cos(3 * x) * cos(2 * y)
    forcing = @. a3 * sin(1 * x) * sin(3 * y) + a4 * sin(3 * x) * sin(1 * y)
    forcing = @. a7 * sin(2 * x) * cos(2 * y) + a8 * cos(2 * x) * sin(2 * y) + a9 * sin(2 * x) * sin(2 * y)
    ζ .+= sqrt(dt) .* forcing
end

# Legit forcing from Shafer Smith! Not that legit of a description though!!!
# c = 0.99
# theta = 2\pi * rand()
# F̂\_n = c F_n−1 + (1 − c\^2)\^(1/2) * exp(i * \theta)
# F\_n = havg(\psi F̂\_n)\^-1 F̂\_n
# havg here denotes the horizontal average across the domain.

# Create State array and unpack
S = arraytype(zeros(ComplexF64, size(ψ)..., 2))
ζ = view(S, :, :, 1)
q = view(S, :, :, 2)

min_δ = min(x[2] - x[1], y[2] - y[1])
cfl = 0.05
wavespeed = 2.0
dt = cfl * min_δ / wavespeed
# rhs!(dζ, ζ, 0)

# odesolver = LSRK144(rhs!, ζ, dt; t0=0)
odesolver = LSRK144(rhs!, S, dt; t0=0)
@. ζ = -sin(1.0 * x) * sin(y) + -sin(2.0 * x) * sin(y) + 0im
@. q = -sin(1.0 * x) + sin(0.0 * y) + 0im

timeseries = []
timeend = 10
iterations = floor(Int, timeend / dt)
for i in 1:iterations
    dostep!(S, odesolver)
    stochastic_update!(S, dt, x, y)
    if i % 40 == 0
        push!(timeseries, Array(real.(copy(S))))
    end
    if i % 100 == 0
        println("done with iteration ", i)
        println("the extrema of vorticity are ", extrema(real.(ζ)))
        println("the extrema of the tracer are ", extrema(real.(q)))
    end
end

##
using GLMakie
fig = Figure()
ax = Axis(fig[1, 1], title="vorticity")
ax2 = Axis(fig[1, 3], title="saturation")

timeslider = Slider(fig[2, 1:2], range=1:1:length(timeseries), startvalue=1)
timeindex = timeslider.value
field1 = @lift(timeseries[$timeindex][:, :, 1])
field2 = @lift(timeseries[$timeindex][:, :, 2])
hm_ζ = heatmap!(ax, field1, colorrange=(-1, 1), colormap=:balance, interpolate=true)
Colorbar(fig[1, 2], hm_ζ, height=Relative(3 / 4), width=25, ticklabelsize=30, labelsize=30, ticksize=25, tickalign=1,)

hm_q = heatmap!(ax2, field2, colorrange=(-5, 0.02), colormap=:solar, interpolate=true)
Colorbar(fig[1, 4], hm_q, height=Relative(3 / 4), width=25, ticklabelsize=30, labelsize=30, ticksize=25, tickalign=1,)
display(fig)

max_stars_repo_name: sandreza/FourierCore

max_issues_repo_name: sandreza/FourierCore

max_forks_repo_name: sandreza/FourierCore


text:
using NRRD
using FactCheck, Images, ColorTypes, FixedPointNumbers, FileIO

testing_units = Int == Int64

if testing_units
    using SIUnits, SIUnits.ShortUnits
end

facts("Read NRRD") do
    workdir = joinpath(tempdir(), "Images")
    writedir = joinpath(workdir, "write")
    if !isdir(workdir)
        mkdir(workdir)
    end
    if !isdir(writedir)
        mkdir(writedir)
    end

    context("Gray, raw") do
        img = load(joinpath(dirname(@__FILE__), "io", "small.nrrd"))
        @fact colorspace(img) --> "Gray"
        @fact ndims(img) --> 3
        @fact colordim(img) --> 0
        @fact eltype(img) --> Float32
        outname = joinpath(writedir, "small.nrrd")
        save(outname, img)
        imgc = load(outname)
        @fact img.data --> imgc.data
    end

    context("Units") do
        img = load(joinpath(dirname(@__FILE__), "io", "units.nhdr"))
        ps = pixelspacing(img)
        @fact ps[1]/(0.1*Milli*Meter) --> roughly(1)
        @fact ps[2]/(0.2*Milli*Meter)  --> roughly(1)
        @fact ps[3]/(1*Milli*Meter)  --> roughly(1)
    end

    context("Gray, compressed (gzip)") do
        img = load(joinpath(dirname(@__FILE__), "io", "smallgz.nrrd"))
        @fact colorspace(img) --> "Gray"
        @fact ndims(img) --> 3
        @fact colordim(img) --> 0
        @fact eltype(img) --> Float32
        outname = joinpath(writedir, "smallgz.nrrd")
        save(outname, img)
        imgc = load(outname)
        @fact img.data --> imgc.data
    end

    context("Time is 4th dimension") do
        img = load(joinpath(dirname(@__FILE__), "io", "small_time.nrrd"))
        @fact timedim(img) --> 4
        outname = joinpath(writedir, "small_time.nrrd")
        save(outname, img)
        imgc = load(outname)
        @fact img.data --> imgc.data
    end
end

ext: jl


text:
include("prime-factors.jl")
using Test

@testset "no factors" begin
    @test prime_factors(1) == []
end

@testset "prime number" begin
    @test prime_factors(2) == [2]
end

@testset "square of a prime" begin
    @test prime_factors(9) == [3, 3]
end

@testset "cube of a prime" begin
    @test prime_factors(8) == [2, 2, 2]
end

@testset "product of primes and non-primes" begin
    @test prime_factors(12) == [2, 2, 3]
end

@testset "product of primes" begin
    @test prime_factors(901255) == [5, 17, 23, 461]
end

@testset "factors include a large prime" begin
    @test prime_factors(93819012551) == [11, 9539, 894119]
end


text:
@inline x_dot_g_b(i, j, k, grid, buoyancy, C) = ĝ_x(buoyancy) * buoyancy_perturbation(i, j, k, grid, buoyancy.model, C)
@inline y_dot_g_b(i, j, k, grid, buoyancy, C) = ĝ_y(buoyancy) * buoyancy_perturbation(i, j, k, grid, buoyancy.model, C)
@inline z_dot_g_b(i, j, k, grid, buoyancy, C) = ĝ_z(buoyancy) * buoyancy_perturbation(i, j, k, grid, buoyancy.model, C)

@inline x_dot_g_b(i, j, k, grid,  ::Buoyancy{M, ZDirection}, C) where M = 0
@inline y_dot_g_b(i, j, k, grid,  ::Buoyancy{M, ZDirection}, C) where M = 0
@inline z_dot_g_b(i, j, k, grid, b::Buoyancy{M, ZDirection}, C) where M = buoyancy_perturbation(i, j, k, grid, b.model, C)


text:
# Can perform inversion of synthetic scenarios.
# First, the seismic data are modeled as in the forward problem. Then the
# data are used to perform full waveform inversion (FWI). The inverse
# problem estimates
# the Earth models and the source and receiver filters
# that resulted from the data.
# This task is necessary to test the performance of the inversion algorithm
# in various geological scenarios using different acquisition parameters.

model = J.Gallery.Seismic(:acou_homo2);
J.Models.Seismic_addon!(model,randn_perc=1, fields=[:χvp,:χρ])

model0 = J.Gallery.Seismic(:acou_homo2);
J.Models.Seismic_addon!(model0, randn_perc=1, fields=[:χvp,:χρ])

acqgeom=J.Acquisition.Geom_fixed(model,1,10)
acqsrc=J.Acquisition.Src_fixed_mod(acqgeom.nss,1,[:P],mod=model, nλ=3, tmaxfrac=1.0)
tgrid=acqsrc.tgrid

parameterization=[:χvp, :χρ, :null]

mgrid=model.mgrid

@testset "test parallel implementation during gradient" begin
	for attrib_mod in [JF.ModFdtd(), JF.ModFdtdBorn()]
		pa=JF.Param(acqsrc, acqgeom, tgrid, attrib_mod, model0,
				     modm_obs=model,
				     modm0=model0,
				     igrid_interp_scheme=:B2,
				     igrid=broadcast(x->range(x[1],stop=x[end],step=300.),mgrid),
				     parameterization=parameterization,   verbose=false,
				     nworker=1)

		pa_parallel=JF.Param(acqsrc, acqgeom, tgrid, attrib_mod, model0,
				     modm_obs=model,
				     modm0=model0,
				     igrid_interp_scheme=:B2,
				     igrid=broadcast(x->range(x[1],stop=x[end],step=300.),mgrid),
				     parameterization=parameterization,   verbose=false,
				     nworker=nothing)

		result=JF.xfwi!(pa, JF.Migr(), attrib_mod)

		result_parallel=JF.xfwi!(pa_parallel, JF.Migr(), attrib_mod)

		@test result[2] ≈ result_parallel[2]
	end
end

@testset "Testing Born Modeling and its gradient" begin

	pa=JF.Param(acqsrc, acqgeom, tgrid, JF.ModFdtdBorn(), model0,
	     		     modm0=model0,
			     modm_obs=model,
			     igrid_interp_scheme=:B2,
			     igrid=broadcast(x->range(x[1],stop=x[end],step=350.),mgrid),
			     parameterization=parameterization,   verbose=false)

	JF.xfwi!(pa, JF.LS(), JF.ModFdtdBorn(),  bounded_flag=true, solver=:ipopt,
			ipopt_options=[["max_iter", 0],["derivative_test", "first-order"]])

	result=JF.xfwi!(pa, JF.Migr(), JF.ModFdtdBorn())

	pa_fd=deepcopy(pa);
	result_fd=JF.xfwi!(pa_fd, JF.Migr_fd(), JF.ModFdtdBorn())

	f=Misfits.error_squared_euclidean!(nothing, result[2], result_fd[2], nothing, norm_flag=true)

	@test f<1e-15
end

@testset "Testing gradient LS FWI" begin
	pa=JF.Param(acqsrc, acqgeom, tgrid, JF.ModFdtd(), model0,
			     modm_obs=model,
			     igrid_interp_scheme=:B2,
			     igrid=broadcast(x->range(x[1],stop=x[end],step=350.),mgrid),
			     parameterization=parameterization,   verbose=false)

	JF.xfwi!(pa, JF.LS(), JF.ModFdtd(),  bounded_flag=true, solver=:ipopt,
			ipopt_options=[["max_iter", 0],["derivative_test", "first-order"]])

	result=JF.xfwi!(pa, JF.Migr(), JF.ModFdtd())

	pa_fd=deepcopy(pa);
	result_fd=JF.xfwi!(pa_fd, JF.Migr_fd(), JF.ModFdtd())

	f=Misfits.error_squared_euclidean!(nothing, result[2], result_fd[2], nothing, norm_flag=true)

	@test f<1e-15
end


text:
# using JLD
# using PyPlot

#
path = "/home/emma/github/fit_behaviour_julia/scripts_emma/resultats/"
# data = JLD.load("/home/emma/github/fit_behaviour_julia/LLdata_fit3.jld")
# model = data["mod"]
# println(model)
# model1 = model["1"]
# parameters = model1["f"]
using JSON

###################
### Read data #####
###################
# create variable to write the information
data = Dict()
open(path*"fit_2par.json", "r") do f
    global data
    dicttxt = readstring(f)  # file information to string
    data=JSON.parse(dicttxt)  # parse and transform data
end
fitted_min = data["1"]["f"]
ind_min = 1.
par_fit = data["1"]["x_bf"]
x_bf_all = zeros(100,2)
println(size(x_bf_all))
minimum = zeros(100,1)
for i in 1:100
    x_bf_all[i] = data[string(i)]["x_bf"][1]
    x_bf_all[100+i] = data[string(i)]["x_bf"][2]
    minimum[i] = data[string(i)]["f"]
    if data[string(i)]["x_converged"] ==true & data[string(i)]["f_converged"] ==true & data[string(i)]["g_converged"] ==true
        println(i)
        if data[string(i)]["f"]<fitted_min
            println(par_fit)
            par_fit = data[string(i)]["x_bf"]
            fitted_min = data[string(i)]["f"]
            ind_min = i
            println(ind_min)
        end
    end
end
println(par_fit)
# figure()
# plot(1:100,minimum)
# title("history.minimum")
# xlabel("iteration")
# ylabel("history.minimum()")
# plot(ind_min,fitted_min,"o",label ="fitted minimum")
# legend()
# figure()
# plot(1:100,x_bf_all[1:100],label = "c2")
# plot(1:100,x_bf_all[101:200],label = "sigma")
# plot(ind_min,par_fit[1],"o",label = "fitted minimum c2")
# plot(ind_min,par_fit[2],"o",label = "fitted minimum sigma")
# legend()
# title("parameters for each iteration")
# ylabel("parameter value")
# xlabel("iteration")

# println(data[string(Int(ind_min))])
hessian = data[string(Int(ind_min))]["Hessian"]
println(hessian)
hess = zeros(5,5)
println(size(hess))
for a in 1:size(hessian)[1]
    for i in 1:size(hessian)[1]
        hess[a,i]=hessian[a][i]
    end
end
# hess = [hessian[1][1] hessian[2][1]; hessian[1][2] hessian[2][2]]
# hess = [hessian[1][1] hessian[1][2]; hessian[2][1] hessian[2][2]]

println(hess)
inv_hess = inv((hess))
println(diag(inv_hess))
ci = 2*(sqrt(diag(inv_hess)))
println(ci)
println(par_fit)

#fer el likelyhood
# fittejar una funció gaussiana i mirar que em dona allà la sigma_a
#l Copyright (c) 2018 Copyright Holder All Rights Reserved.

max_stars_repo_name: emmafdz/FinalDegreeProject

max_issues_repo_name: emmafdz/FinalDegreeProject

max_forks_repo_name: emmafdz/FinalDegreeProject


text:
# MIT License
#
# Copyright (c) 2020 Joshua E Gentry

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# =================================================================================================
"""
    pix_get_depth(
        pix::Pix
    )::Int32

Retrieves the color bit depth of the image.

__Arguments:__

| T | Name | Default  | Description
|---| :--- | :------- | :----------
| R | pix  |          | The image to get the bit depth from.

See also: [`pix_get_dimensions`](@ref)
"""
function pix_get_depth(
            pix::Pix
        )::Int32
    if is_valid(pix) == false
        @error "Pix has been freed."
        return 0
    end

    local result = ccall(
        (:pixGetDepth, LEPTONICA),
        Cint,
        (Ptr{Cvoid},),
        pix
    )

    return result
end

# =================================================================================================
"""
    pix_get_dimensions(
        pix::Pix
    )::Union{NamedTuple{(:w, :h, :d), Tuple{Int32, Int32, Int32}}, Nothing}

Retrieve the dimensions of the image.

__Arguments:__

| T | Name | Default  | Description
|---| :--- | :------- | :----------
| R | pix  |          | The image to get the dimensions of.

__Details:__

This method returns a named tuple:

  * w - Image width.
  * h - Image height.
  * d - Color depth.

See also: [`pix_get_depth`](@ref)
"""
function pix_get_dimensions(
            pix::Pix
        )::Union{NamedTuple{(:w, :h, :d), Tuple{Int32, Int32, Int32}}, Nothing}
    if is_valid(pix) == false
        @error "Pix has been freed."
        return nothing
    end

    local w = Ref{Cint}(0)
    local h = Ref{Cint}(0)
    local d = Ref{Cint}(0)

    local result = ccall(
        (:pixGetDimensions, LEPTONICA),
        Cint,
        (Ptr{Cvoid}, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}),
        pix,
        w,
        h,
        d
    )

    if result == 1
        return nothing
    end

    return (w = w[], h = h[], d = d[])
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 580dee74-b0f8-11eb-110f-9bf8b21d33fe
using simgym, Plots

# ╔═╡ 522f6955-4c71-41dc-92d7-8d01ea720664
function plot_em(s::Simulation, sparse_level)
	livingcellIDs = []
	totalsteps = s.steptotal[1]
	for i in 1:length(s.cells)
		if s.cells[i].d < totalsteps
			nothing
		else
			push!(livingcellIDs,i)
		end
	end
	coords = zeros(length(livingcellIDs),2)
	for i in 1:length(livingcellIDs)
		coords[i,1] = s.cells[livingcellIDs[i]].p[1]
		coords[i,2] = s.cells[livingcellIDs[i]].p[2]
	end
	myboy = scatter(coords[:,1],coords[:,2],legend=false, markersize=5, xlims=(-6*sparse_level,6*sparse_level), ylims=(-6*sparse_level,6*sparse_level))
	return myboy
end

# ╔═╡ 64aa8486-5367-4356-b973-16fb280f24cd
function giftime(s,nsteps,dim,sparsity_level,μ,ϵ)#dt
	anim = @animate for i=1:nsteps
		# timestep
		dt = .1

		integrate!(s,dt,10,ϵ,μ)

		l = layout = @layout([A{0.01h}; [B C]])
		ax1 = plot_em(s,sparsity_level)
		mask = pixelate(s,dim,sparsity_level,0.)
		ax2 = heatmap(mask, color=:grays, aspect_ratio=1, legend=false, xticks=false, yticks=false)
		header = string("nsteps=",nsteps,", dt=",dt,", ϵ=",ϵ,", μ=",μ)
		title = plot(title=header,grid=false,showaxis=false,bottom_margin=-50Plots.px)
		figure = plot(title,ax1,ax2,layout=l)
	end
	gif(anim,"example.gif",fps=10)
end

# ╔═╡ f78a6bf8-9b95-481c-8ceb-5b2de6e43b32
begin
	n_cells = 20
	sparsity = 1.5
	repro = 4000
	# dispersion energy constant
	ϵ = 0.001
	cellarray = makeCellArray(n_cells,sparsity,repro)
	s = Simulation(cellarray,len_jones)
end

# ╔═╡ bd234560-07a2-4e14-a75a-a8eee870ca91
begin
	nsteps=40
	anim = @animate for i=1:nsteps
		# timestep
		dt = .1

		integrate!(s,dt,10,ϵ,repro)

		plot_em(s,sparsity)
	end
	gif(anim, fps = 10)
end

# ╔═╡ b0506c7e-df79-4333-aeee-b9c469ca66e1
giftime(s,120,255,sparsity,repro,ϵ)

# ╔═╡ Cell order:
# ╠═580dee74-b0f8-11eb-110f-9bf8b21d33fe
# ╠═522f6955-4c71-41dc-92d7-8d01ea720664
# ╠═64aa8486-5367-4356-b973-16fb280f24cd
# ╠═f78a6bf8-9b95-481c-8ceb-5b2de6e43b32
# ╠═bd234560-07a2-4e14-a75a-a8eee870ca91
# ╠═b0506c7e-df79-4333-aeee-b9c469ca66e1

max_stars_repo_name: andi-bergeson/simgym

max_issues_repo_name: andi-bergeson/simgym

max_forks_repo_name: andi-bergeson/simgym


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

using Markdown
using InteractiveUtils

# ╔═╡ 6587e470-c705-11ea-3c9f-bd5e12b38372
md"# Characterizing Variability"

# ╔═╡ 378f4130-c714-11ea-061b-95ee80bdde32
md"Creating an experiment"

# ╔═╡ 9b1724c0-c714-11ea-26e4-cd293676b07b
md"transpose data:"

# ╔═╡ 75f7b4b0-c715-11ea-2ecb-3bbcde0507a6
md"Normalize data"

# ╔═╡ d1d10ac0-c715-11ea-384b-dfbdbc61178a
md"Theres no odd numbers in even number of steps"

# ╔═╡ 0b890b00-c716-11ea-04fa-0598a5f87993
md"## Spread away from mean"

# ╔═╡ 2accbf82-c71a-11ea-02bb-efee9cf0f6ba
md"`1e-17` is notation for $10^{-17}$"

# ╔═╡ d98635b0-c71a-11ea-0bff-8beb1eebbd1e
md"Now plot it with the mean:"

# ╔═╡ e32e2cc0-c71b-11ea-0fb2-23944dc3467c
md"Using the squared value instead of absolute values"

# ╔═╡ 8c3fc89e-c721-11ea-041f-ed97a10dba20
md"Standard deviation"

# ╔═╡ 343c2820-c720-11ea-23c2-510cc66e7f1e
md"As a comprehension:"

# ╔═╡ 0dcef7d0-c720-11ea-0760-715583eb53db
md"With broadcast operators:"

# ╔═╡ bb1eaf60-c721-11ea-21e0-49467639fdbc
md"## Standard error of the mean"

# ╔═╡ c227d520-c721-11ea-1dd5-99ba663c4787
md" $N$ data points sampled from the same distribution, calculate the mean"

# ╔═╡ 11573fb0-c7da-11ea-3fcd-a9403ed3a3bd
md" $X_1 + X_2 + \cdots + X_N$"

# ╔═╡ 136a99de-c7db-11ea-23f1-73841a5ad2ae
md"## Defining new types in Julia"

# ╔═╡ 20ce7cf0-c7db-11ea-2a4a-575ae244517c
md"Random walker:"

# ╔═╡ 89d081d0-c7db-11ea-0378-699159bdd2a4
md"See also Distributions.jl"

# ╔═╡ 87680d50-c7db-11ea-38e6-7d1f9eb8c469
md"How write **generic** code? A single `walk` function to generate random walk that works with discrete and continuous distributions"

# ╔═╡ 4c6c5792-c7dd-11ea-2d2c-e921c7408c1a
md"## Custom types / user-defined types / composite types"

# ╔═╡ 760377a0-c7dd-11ea-2f93-b5bf4f4671a8
md"Julia has **objects** (of user-defined types), but **not** object-oriented prog lang"

# ╔═╡ c3a239b0-c7dd-11ea-1a8d-0303ba7767ba
md""" "Box with data inside" """

# ╔═╡ 24025060-c7de-11ea-0fa5-c1434afc8a36
md"Move the walker"

# ╔═╡ 2c3f6240-c7de-11ea-1e2d-451d6cfc9284
md"**Default Structs are not mutable**"

# ╔═╡ 3055c620-c7e4-11ea-2436-614b769333f0
md"This time Im using inner constructor methods because Pluto raises a `multiple definitions` error if using outer constructor methods"

# ╔═╡ b4503490-c714-11ea-3b18-d3bb49dd6888
using StatsBase

# ╔═╡ d2ffe340-c714-11ea-34eb-6398577fcd06
using Plots

# ╔═╡ 7f149f30-c7d9-11ea-1f46-85c7fc0d3e0c
using Statistics

# ╔═╡ be3ef130-c7dc-11ea-22eb-e95b0049dadd
using BenchmarkTools

# ╔═╡ 70b5386e-c705-11ea-0c42-b3cc97da2e8e
function walk(num_steps)
	x = 0

	for i ∈ 1:num_steps
		x += rand((-1, +1))
	end

	return x
end

# ╔═╡ 07180732-c714-11ea-3705-67c5611d6b89
begin
	local num_steps = 20
	walk(num_steps)
end

# ╔═╡ 2ebf1710-c714-11ea-1e48-c74089978b56
experiment(num_steps, num_walks) = [walk(num_steps) for i ∈ 1:num_walks]

# ╔═╡ 7b3e5f60-c714-11ea-2d7f-d1eed8761cdd
data = experiment(50, 1000)

# ╔═╡ 91157f80-c714-11ea-37a6-f5d490c937a5
data'

# ╔═╡ bd4af120-c714-11ea-0815-bbdb893f7000
counts = countmap(data)

# ╔═╡ def34660-c714-11ea-2eb2-79b095ff4eff
begin
	histogram(data, bins=10)
	xlabel!("position x")
end

# ╔═╡ 40f4ff20-c715-11ea-00a8-651fab3adfbe
h = fit(Histogram, data)

# ╔═╡ 640b8a60-c715-11ea-2cb8-c32ef51f6e6e
h.weights / sum(h.weights)

# ╔═╡ 85ff1970-c715-11ea-06c3-c9b1ec16a2b8
histogram(data, bins=30, normed=true)

# ╔═╡ cd75ee00-c715-11ea-09eb-7b5255c6dba7
mean(data)

# ╔═╡ 001eae02-c716-11ea-0afb-95675846f3bf
sum(data) / length(data)

# ╔═╡ db6a0650-c719-11ea-1938-e92ba35681cc
m = mean(data)

# ╔═╡ 3f545200-c716-11ea-243f-911a5683fde4
begin
	histogram(data, bins=30, normed=true)
	vline!([m], lw=3, ls=:dash, leg=false, c=:purple)
end

# ╔═╡ 44f1b2c0-c716-11ea-0147-d5b3b6cfb1e9
begin
	scatter(data)
	hline!([m], lw=3, ls=:dash, leg=false, c=:red)
end

# ╔═╡ 83e2f360-c719-11ea-39b4-add727183c56
centred_data = data .- m  #de-mead: substract

# ╔═╡ f8c7e09e-c719-11ea-0c55-fb8e3e42e41a
begin
	scatter(centred_data)
	hline!([mean(centred_data)], lw=3, ls=:dash, leg=false, c=:red)
end

# ╔═╡ 1f970710-c71a-11ea-15d3-3942522d1c74
mean(centred_data)

# ╔═╡ 5c7dd910-c71a-11ea-2d1e-5168dc0126c6
nextfloat(1.0) - 1.0 # machine epsilon for double precision numbers (Float64)

# ╔═╡ 8d765100-c71a-11ea-194e-19e35c42d727
abs_data = abs.(centred_data)

# ╔═╡ b6258210-c71a-11ea-1dae-0579fab1a2ec
scatter(abs_data)

# ╔═╡ c832c8f0-c71a-11ea-2a15-3b32d84e7d73
abs_data_mean = mean(abs_data)

# ╔═╡ d4bc518e-c71a-11ea-1722-4f70fe9b191a
begin
	scatter(abs_data, alpha=.25)
	hline!([abs_data_mean], lw=3, ls=:dash, leg=false)
end

# ╔═╡ 16141240-c71b-11ea-0688-0d20224c1149
count(abs_data .< abs_data_mean) /length(abs_data)

# ╔═╡ a078d7e0-c71b-11ea-336a-b3443c91e53a
count(abs_data .< 2abs_data_mean) /length(abs_data)

# ╔═╡ b5c36f70-c71b-11ea-1337-a78c70c711e5
begin
	scatter(abs_data, alpha=.25)
	hline!([2abs_data_mean], lw=3, ls=:dash, leg=false)
end

# ╔═╡ d40f5670-c71f-11ea-3add-f354146e1e4b
sqdata = experiment(50, 10^6)

# ╔═╡ ec1f9a80-c71b-11ea-2652-8df60f59cdc2
squared_data_variance = mean((sqdata .- mean(sqdata)) .^ 2)

# ╔═╡ 0ce10ad0-c71f-11ea-1bc9-8fb4152af2de
σ = √(squared_data_variance)

# ╔═╡ fa30fed0-c71f-11ea-031b-95fbce67caab
[(m - σ) < x < (m + σ) for x ∈ sqdata]

# ╔═╡ 4a208eb0-c720-11ea-1968-ed6c7fb5e0d9
(m - σ) .< sqdata .< (m + σ)

# ╔═╡ 581ce12e-c720-11ea-042e-63e1da29f9ca
count((m - σ) .< sqdata .< (m + σ)) / length(sqdata)

# ╔═╡ 6b2fd840-c720-11ea-383c-2d358e20e806
reduced_data = sqdata[1:5_000]

# ╔═╡ 9e202890-c720-11ea-201f-451a7d91f455
begin
	scatter(reduced_data, alpha=.2)
	hline!([mean(sqdata), m - σ, m + σ], lw=3, ls=:dash, leg=false)
end

# ╔═╡ c17e1d10-c720-11ea-0c67-abe08189032f
hline!([mean(sqdata), m - 2σ, m + 2σ], lw=3, ls=:dash, leg=false)

# ╔═╡ 7ba5e7e0-c721-11ea-13bd-d334185817f5
count((m - 2σ) .< sqdata .< (m + 2σ)) / length(sqdata)

# ╔═╡ df750da0-c721-11ea-2eca-d38cf069b0d9
begin
	local num_steps = 20
	local N = 100

	local data = experiment(num_steps, N)

	local m = mean(data)
end

# ╔═╡ 165bd850-c7d9-11ea-09b1-6988d7b094e4
begin
	num_steps = 20
	N = 1000

	data₁ = experiment(num_steps, N)

	local m = mean(data)
end

# ╔═╡ 30f143d2-c7d9-11ea-3a25-d1588cbbb8d6
import Pkg; Pkg.add("Statistics")

# ╔═╡ de739990-c7d9-11ea-1a06-a31c5a208ca6
σ₁ = std(data₁)

# ╔═╡ 442c8df0-c7da-11ea-1008-7150f2c2fee3
standard_error_of_mean = σ₁ / √N

# ╔═╡ 7ef5b012-c7da-11ea-28bb-731abcb67fa4
mean_data = [mean(experiment(num_steps, 4N)) for i ∈ 1:1000]

# ╔═╡ b766d86e-c7da-11ea-1f84-9f62a1e0aff9
std(mean_data)

# ╔═╡ eaccf500-c7da-11ea-3fb7-1b5680de8fcc
histogram(mean_data)

# ╔═╡ 389ab650-c7db-11ea-031a-0974d89217e8
histogram(randn(1000)) # ziggurat algortihm for normally distributed random numbers

# ╔═╡ bceaa140-c7db-11ea-0a47-3fdb70eb02a4
discrete_jump() = rand((-1, +1))

# ╔═╡ d5f8d080-c7db-11ea-0682-6ba3fc0ba193
continuous_jump() = randn()

# ╔═╡ e85b8a60-c7db-11ea-0c32-875cef8dd1c1
function walk_(N, jump)
	x = 0

	for i ∈ 1:N
		x += jump()
	end

	return x
end

# ╔═╡ 1549ebbe-c7dc-11ea-2668-7344f46f1a23
walk_(20, discrete_jump)

# ╔═╡ 80887320-c7dc-11ea-2efc-23dcade2a4f6
walk_(20, continuous_jump)

# ╔═╡ c49eb790-c7dc-11ea-0048-05c808b9bebd
Pkg.add("BenchmarkTools")

# ╔═╡ db5429c0-c7dc-11ea-03e7-db466d5fdebe
@btime walk_(20, discrete_jump)

# ╔═╡ f4c78370-c7dc-11ea-1570-51c8dad7a163
@btime walk_(20, continuous_jump)

# ╔═╡ a0f3e620-c7dd-11ea-0243-e98401e6fef5
struct DiscreteRandomWalker
	x::Int # type annotation
end

# ╔═╡ fc97ad40-c7dd-11ea-0261-452c927172dd
w = DiscreteRandomWalker(20)

# ╔═╡ 104a3fb0-c7de-11ea-0853-5b930aedd026
w.x # the variable x that lives inside the object

# ╔═╡ 4c180092-c7de-11ea-2be2-bdc22ebce3ca
mutable struct MutDiscreteRandomWalker
	x::Int # type annotation
	MutDiscreteRandomWalker() = new(0)
	MutDiscreteRandomWalker(x::Int) = new(x)
end

# ╔═╡ 5ecb7282-c7de-11ea-2d0b-3d87ee2c4364
mw = MutDiscreteRandomWalker(10)

# ╔═╡ 6fcec370-c7de-11ea-2d5c-2bdfdc31ee1c
mw.x += 1

# ╔═╡ 801cf530-c7de-11ea-3e93-e39583c80813
function jump!(w::MutDiscreteRandomWalker) # takes arg of custom type
	w.x += rand((-1, +1))
	return w
end

# ╔═╡ bda22a10-c7de-11ea-27db-5d30f28c6359
jump!(mw)

# ╔═╡ dd1d6620-c7de-11ea-1bee-cfdab81b600f
function walk!(w::MutDiscreteRandomWalker, N)
	for i ∈ 1:N
		jump!(w)
	end
end

# ╔═╡ 16ee93b2-c7df-11ea-3409-a75a9d695eba
mw0 = MutDiscreteRandomWalker()

# ╔═╡ 70c2d8b0-c7e4-11ea-2a96-6b2f0c3c1f77
methods(MutDiscreteRandomWalker)

# ╔═╡ a58020ce-c7e4-11ea-30f9-e1dd307847bf
walk!(mw, 1)

# ╔═╡ 12a801a0-c7e5-11ea-288c-23e64aa51666
mw.x

# ╔═╡ 14c8e5ce-c7e5-11ea-226c-61a248674352
mw0

# ╔═╡ ba99e460-c7e4-11ea-28eb-e11a1d87c941
walk!(mw0, 1)

# ╔═╡ 116177e0-c7e5-11ea-3e68-1916cb275da5
mw0.x

# ╔═╡ Cell order:
# ╟─6587e470-c705-11ea-3c9f-bd5e12b38372
# ╠═70b5386e-c705-11ea-0c42-b3cc97da2e8e
# ╠═07180732-c714-11ea-3705-67c5611d6b89
# ╟─378f4130-c714-11ea-061b-95ee80bdde32
# ╠═2ebf1710-c714-11ea-1e48-c74089978b56
# ╠═7b3e5f60-c714-11ea-2d7f-d1eed8761cdd
# ╟─9b1724c0-c714-11ea-26e4-cd293676b07b
# ╠═91157f80-c714-11ea-37a6-f5d490c937a5
# ╠═b4503490-c714-11ea-3b18-d3bb49dd6888
# ╠═bd4af120-c714-11ea-0815-bbdb893f7000
# ╠═d2ffe340-c714-11ea-34eb-6398577fcd06
# ╠═def34660-c714-11ea-2eb2-79b095ff4eff
# ╟─75f7b4b0-c715-11ea-2ecb-3bbcde0507a6
# ╠═40f4ff20-c715-11ea-00a8-651fab3adfbe
# ╠═640b8a60-c715-11ea-2cb8-c32ef51f6e6e
# ╟─d1d10ac0-c715-11ea-384b-dfbdbc61178a
# ╠═85ff1970-c715-11ea-06c3-c9b1ec16a2b8
# ╠═cd75ee00-c715-11ea-09eb-7b5255c6dba7
# ╠═001eae02-c716-11ea-0afb-95675846f3bf
# ╟─0b890b00-c716-11ea-04fa-0598a5f87993
# ╠═db6a0650-c719-11ea-1938-e92ba35681cc
# ╠═3f545200-c716-11ea-243f-911a5683fde4
# ╠═44f1b2c0-c716-11ea-0147-d5b3b6cfb1e9
# ╠═83e2f360-c719-11ea-39b4-add727183c56
# ╠═f8c7e09e-c719-11ea-0c55-fb8e3e42e41a
# ╟─2accbf82-c71a-11ea-02bb-efee9cf0f6ba
# ╠═1f970710-c71a-11ea-15d3-3942522d1c74
# ╠═5c7dd910-c71a-11ea-2d1e-5168dc0126c6
# ╠═8d765100-c71a-11ea-194e-19e35c42d727
# ╠═b6258210-c71a-11ea-1dae-0579fab1a2ec
# ╠═c832c8f0-c71a-11ea-2a15-3b32d84e7d73
# ╟─d98635b0-c71a-11ea-0bff-8beb1eebbd1e
# ╠═d4bc518e-c71a-11ea-1722-4f70fe9b191a
# ╠═16141240-c71b-11ea-0688-0d20224c1149
# ╠═a078d7e0-c71b-11ea-336a-b3443c91e53a
# ╠═b5c36f70-c71b-11ea-1337-a78c70c711e5
# ╟─e32e2cc0-c71b-11ea-0fb2-23944dc3467c
# ╠═d40f5670-c71f-11ea-3add-f354146e1e4b
# ╠═ec1f9a80-c71b-11ea-2652-8df60f59cdc2
# ╟─8c3fc89e-c721-11ea-041f-ed97a10dba20
# ╠═0ce10ad0-c71f-11ea-1bc9-8fb4152af2de
# ╟─343c2820-c720-11ea-23c2-510cc66e7f1e
# ╠═fa30fed0-c71f-11ea-031b-95fbce67caab
# ╟─0dcef7d0-c720-11ea-0760-715583eb53db
# ╠═4a208eb0-c720-11ea-1968-ed6c7fb5e0d9
# ╠═581ce12e-c720-11ea-042e-63e1da29f9ca
# ╠═6b2fd840-c720-11ea-383c-2d358e20e806
# ╠═9e202890-c720-11ea-201f-451a7d91f455
# ╠═c17e1d10-c720-11ea-0c67-abe08189032f
# ╠═7ba5e7e0-c721-11ea-13bd-d334185817f5
# ╟─bb1eaf60-c721-11ea-21e0-49467639fdbc
# ╟─c227d520-c721-11ea-1dd5-99ba663c4787
# ╠═df750da0-c721-11ea-2eca-d38cf069b0d9
# ╠═165bd850-c7d9-11ea-09b1-6988d7b094e4
# ╠═30f143d2-c7d9-11ea-3a25-d1588cbbb8d6
# ╠═7f149f30-c7d9-11ea-1f46-85c7fc0d3e0c
# ╠═de739990-c7d9-11ea-1a06-a31c5a208ca6
# ╟─11573fb0-c7da-11ea-3fcd-a9403ed3a3bd
# ╠═442c8df0-c7da-11ea-1008-7150f2c2fee3
# ╠═7ef5b012-c7da-11ea-28bb-731abcb67fa4
# ╠═b766d86e-c7da-11ea-1f84-9f62a1e0aff9
# ╠═eaccf500-c7da-11ea-3fb7-1b5680de8fcc
# ╟─136a99de-c7db-11ea-23f1-73841a5ad2ae
# ╟─20ce7cf0-c7db-11ea-2a4a-575ae244517c
# ╟─89d081d0-c7db-11ea-0378-699159bdd2a4
# ╠═389ab650-c7db-11ea-031a-0974d89217e8
# ╟─87680d50-c7db-11ea-38e6-7d1f9eb8c469
# ╠═bceaa140-c7db-11ea-0a47-3fdb70eb02a4
# ╠═d5f8d080-c7db-11ea-0682-6ba3fc0ba193
# ╠═e85b8a60-c7db-11ea-0c32-875cef8dd1c1
# ╠═1549ebbe-c7dc-11ea-2668-7344f46f1a23
# ╠═80887320-c7dc-11ea-2efc-23dcade2a4f6
# ╠═c49eb790-c7dc-11ea-0048-05c808b9bebd
# ╠═be3ef130-c7dc-11ea-22eb-e95b0049dadd
# ╠═db5429c0-c7dc-11ea-03e7-db466d5fdebe
# ╠═f4c78370-c7dc-11ea-1570-51c8dad7a163
# ╟─4c6c5792-c7dd-11ea-2d2c-e921c7408c1a
# ╟─760377a0-c7dd-11ea-2f93-b5bf4f4671a8
# ╠═a0f3e620-c7dd-11ea-0243-e98401e6fef5
# ╟─c3a239b0-c7dd-11ea-1a8d-0303ba7767ba
# ╠═fc97ad40-c7dd-11ea-0261-452c927172dd
# ╠═104a3fb0-c7de-11ea-0853-5b930aedd026
# ╟─24025060-c7de-11ea-0fa5-c1434afc8a36
# ╟─2c3f6240-c7de-11ea-1e2d-451d6cfc9284
# ╟─3055c620-c7e4-11ea-2436-614b769333f0
# ╠═4c180092-c7de-11ea-2be2-bdc22ebce3ca
# ╠═5ecb7282-c7de-11ea-2d0b-3d87ee2c4364
# ╠═6fcec370-c7de-11ea-2d5c-2bdfdc31ee1c
# ╠═801cf530-c7de-11ea-3e93-e39583c80813
# ╠═bda22a10-c7de-11ea-27db-5d30f28c6359
# ╠═dd1d6620-c7de-11ea-1bee-cfdab81b600f
# ╠═16ee93b2-c7df-11ea-3409-a75a9d695eba
# ╠═70c2d8b0-c7e4-11ea-2a96-6b2f0c3c1f77
# ╠═a58020ce-c7e4-11ea-30f9-e1dd307847bf
# ╠═12a801a0-c7e5-11ea-288c-23e64aa51666
# ╠═14c8e5ce-c7e5-11ea-226c-61a248674352
# ╠═ba99e460-c7e4-11ea-28eb-e11a1d87c941
# ╠═116177e0-c7e5-11ea-3e68-1916cb275da5

max_stars_repo_name: elihugarret/my-notebooks


text:
# This file was generated, do not modify it. # hide
iterated_pipe = IteratedModel(model=pipe2,
                              controls=controls,
                              measure=brier_loss,
                              resampling=Holdout(fraction_train=0.7))

max_stars_repo_name: alan-turing-institute/MLJTutorials

max_issues_repo_name: alan-turing-institute/MLJTutorials

max_forks_repo_name: alan-turing-institute/MLJTutorials


text:
import Base: +, -, *,/, reshape, broadcasted

"""
    Zeros()

Acts as a stand-in for an array of zeros that can be
used during training which is ignored by the optimisers.

Useful to turn bias off for a forward pass of a layer.

## Examples

```julia-repl
julia> bias_less_conv = Conv((2,2), 1=>3; bias = false)
Conv((2, 2), 1=>3)

julia> params(bias_less_conv) |> length
1

julia> bias_less_conv.bias
Flux.Zeros()
```
"""
struct Zeros end
# To allow for things like Dense(10, 2, initb = Zeros)
Zeros(args...) = Zeros()

Base.reshape(x::Zeros, dims...) = x

+(::Zeros, b::AbstractArray) = b
+(a::AbstractArray, ::Zeros) = a
+(a::Zeros, ::Zeros) = a

-(::Zeros, b::AbstractArray) = -b
-(a::AbstractArray, ::Zeros) = a
-(a::Zeros, ::Zeros) = a

# Some opportunities to avoid scalar indexing, intermediaries
# Since it replicates a little of what we expect Base to do,
# it should be possible to remove in the future, but for now,
# these help with performance.
broadcasted(::typeof(+), a::AbstractArray, b::Zeros) = a
broadcasted(::typeof(+), a::Zeros, b::AbstractArray) = b
broadcasted(::typeof(-), a::AbstractArray, b::Zeros) = a
broadcasted(::typeof(-), a::Zeros, b::AbstractArray) = -b
# Need adjoints for these or else the gradient w.r.t to the non-Zeros arg will be nothing as well
@adjoint broadcasted(::typeof(*), a::AbstractArray, b::Zeros) = zero(a), _ -> (nothing, zero(a), nothing)
@adjoint broadcasted(::typeof(*), a::Zeros, b::AbstractArray) = zero(b), _ -> (nothing, nothing, zero(b))
@adjoint broadcasted(::typeof(/), a::Zeros, b::AbstractArray) = zero(b), _ -> (nothing, nothing, zero(b))

# Pass-through for layer constructors
create_bias(weights::AbstractArray, bias::Flux.Zeros, dims::Integer...) = bias


text:
#=
# What are the characteristics of a SimpleNet?

This use-case is for explorations, might abuse the standard. The goal of PNML.jl
is to not constrain what can be parsed & represented in the
intermediate representation (IR). So many non-standard XML constructions are possible,
with the standars being a subset. It is the role of IR users to enforce semantics
upon the IR. SimpleNet takes liberties!

Assumptions about labels:
 place has numeric marking, default 0
 transition has numeric condition, default 0
 arc has source, target, numeric inscription value, default 0

# Non-simple Networks means what?

# SimpleNet

Created to be a end-to-end use case. And explore implementing something-that-works
while building upon and improving the IR. Does not try to conform to any standard.
Much of the complexity possible with pnml is ignored.

The first use is to recreate the lotka-volterra model from Petri.jl examples.
Find it in the examples folder. This is a stochastic Petri Net.

Liberties are taken with pnml, remember that standards-checking is not a goal.
A less-simple consumer of the IR can impose standards-checking.

=#

"""
$(TYPEDEF)
$(TYPEDFIELDS)

**TODO: Rename SimpleNet to TBD**
SimpleNet wraps one net. This is a `PetriNet` wrapping a `PnmlNet`.

Omits the page level of the pnml-defined hierarchy by flattening pages.
A multi-page net can be flattened by removing referenceTransitions & referencePlaces,
and merging pages into the first page.

Only selected fields are merged.
"""
struct SimpleNet{PNTD} <: PetriNet{PNTD}
    id::Symbol
    net::PnmlNet{PNTD}
end

"Construct from string of valid pnml XML using the first network"
SimpleNet(str::AbstractString) = SimpleNet(parse_str(str))
SimpleNet(model::PnmlModel)  = SimpleNet(first_net(model))
SimpleNet(node::XMLNode)  = SimpleNet(PnmlModel(node))

function SimpleNet(net::PnmlNet)
    netcopy = deepcopy(net) #TODO Is copy needed?
    flatten_pages!(netcopy)
    SimpleNet(netcopy.id, netcopy)
end

Base.summary(io::IO, spn::SimpleNet{P}) where {P} = print(io, summary(spn))
function Base.summary(spn::SimpleNet{P}) where {P}
    string(typeof(spn), " id ", pid(spn), ", ",
        length(places(spn)), " places, ",
        length(transitions(spn)), " transitions, ",
        length(arcs(spn)), " arcs")
end

function Base.show(io::IO, spn::SimpleNet{P}) where {P}
    println(io, summary(spn))
    println(io, "places")
    println(io, places(spn))
    println(io, "transitions")
    println(io, transitions(spn))
    println(io, "arcs")
    print(io, arcs(spn))
end

#-------------------------------------------------------------------------------
# Implement PNML Petri Net interface.
#TODO Where is the interface documented?
#-------------------------------------------------------------------------------

pid(spn::SimpleNet) = pid(spn.net)

places(spn::SimpleNet)         = firstpage(spn.net).places
transitions(spn::SimpleNet)    = firstpage(spn.net).transitions
arcs(spn::SimpleNet)           = firstpage(spn.net).arcs
refplaces(spn::SimpleNet)      = firstpage(spn.net).refPlaces
reftransitions(spn::SimpleNet) = firstpage(spn.net).refTransitions

#---------------------------------------------
# For Stochastic Nets, a transition is not labeled with a boolean condition,
# but with a  floating point rate.
#TODO Which can be turned into a boolean with a comparison.
#---------------------------------------------

"""
$(TYPEDSIGNATURES)

Return a transition-id labelled vector of rate values for transitions of net `s`.
"""
function rates end

rates(spn::N) where {T<:PnmlType, N<:PetriNet{T}} =
    rates(spn, transition_ids(spn))

function rates(spn::N, idvec::Vector{Symbol}) where {T<:PnmlType, N<:PetriNet{T}}
    LVector( (; [transitionid => rate(spn, transitionid) for transitionid in idvec]...))
end

"""
$(TYPEDSIGNATURES)

Return rate value of `transition`.  Mising rate labels are defaulted to 0.0.
"""
function rate end
function rate(transition)::Number #! where {T<:PnmlType, N<:PetriNet{T}}
    r = get_label(transition, :rate)
    if !isnothing(r)
        @assert tag(r) === :rate
        if haskey(r.dict, :text)
            !isnothing(r.dict[:text])
            # The unclaimed label mechanism adds a :content key for text elements.
            value = number_value(r.dict[:text][:content])
        elseif haskey(r.dict, :content)
            # When the text element is elided,, there is still a :content.
            value = number_value(r.dict[:content])
        else
            value = zero(Float64)
        end
        return isnothing(value) ? zero(Float64) : value #! specialize default value?
    else
        return zero(Float64)
    end
end

function rate(spn::N, tid::Symbol) where {T<:PnmlType, N<:PetriNet{T}}
    rate(transition(spn, tid))
end


text:
module DatasetProvider

using BSON
using CSV
using CodecZlib
using DataDeps
using DataFrames
using Dates
using HDF5
using InteractiveUtils
using Mmap
using Random
using Statistics
using StatsBase

import MLDatasets
import ZipFile

export load, loadraw, Dataset, Split, TrainTest, TrainValidTest
export listdatasets, remove, removeall

const DATADIR = normpath(joinpath(@__DIR__, "../data"))

# Includes
include("types.jl")
include("dataset.jl")
include("utilities.jl")
include("postprocessing.jl")

include("./tasks/classification.jl")
include("./tasks/regression.jl")

include("./formats/tabulardata.jl")
include("./formats/images.jl")

include("./splits/traintest.jl")
include("./splits/trainvalidtest.jl")

datasetfolder(args...) = joinpath(@__DIR__, "datasets", args...)

include.(filter(endswith(".jl"), readdir(datasetfolder("classification"); join = true)))
include.(filter(endswith(".jl"), readdir(datasetfolder("regression"); join = true)))

# constants
function subtypes_list(T)
    types = DataType[]
    for Ti in subtypes(T)
        if isconcretetype(Ti)
            push!(types, Ti)
        else
            push!(types, subtypes_list(Ti)...)
        end
    end
    return types
end

const DATASETS = Ref{Vector{DataType}}(DataType[])
const TASKS = Ref{Vector{DataType}}(DataType[])
const FORMATS = Ref{Vector{DataType}}(DataType[])

name_subtypes() = DATASETS[]
task_subtypes() = TASKS[]
format_subtypes() = FORMATS[]

function __init__()
    DATASETS[] = subtypes_list(Name)
    TASKS[] = subtypes_list(Task)
    FORMATS[] = subtypes_list(Format)

    for N in name_subtypes()
        dep = make_datadep(N)
        isnothing(dep) || register(dep)
    end
end

end # module


text:
me = MultipleEdge(1, 2, 3)
try
    MultipleEdge(1, 2, 0)
catch err
    @test err != nothing
end
@test src(me) == 1 && dst(me) == 2 && mul(me) == 3
e0 = LightGraphs.SimpleEdge(me)
MultipleEdge(e0)
@test MultipleEdge(1, 2) == e0
@test e0 == MultipleEdge(1, 2)
@test e0 == MultipleEdge([1, 2])
@test e0 == MultipleEdge([1, 2, 1])
@test e0 == MultipleEdge((1, 2))
@test e0 == MultipleEdge((1, 2, 1))
@test e0 == MultipleEdge(1 => 2)
@test reverse(me) == MultipleEdge(2, 1, 3)
@test eltype(me) == Int

@test iterate(me)[2] == 2
@test [e0 == e for e in me] == [true for i = 1:mul(me)]
@test Tuple(me) == (1,2,3)
length(me) == mul(me)


text:
"""
    `poly(vertices, indices; kwargs...)`
    `poly(points; kwargs...)`
    `poly(shape; kwargs...)`

Plots a polygon based on the arguments given.
When vertices and indices are given, it functions similarly to `mesh`.
When points are given, it draws one polygon that connects all the points in order.
When a shape is given (essentially anything decomposable by `GeometryTypes`), it will plot `decompose(shape)`.

    poly(coordinates, connectivity; kwargs...)

Plots polygons, which are defined by
`coordinates` (the coordinates of the vertices) and
`connectivity` (the edges between the vertices).

## Theme
$(ATTRIBUTES)
"""
@recipe(Poly) do scene
    Theme(;
        color = theme(scene, :color),
        visible = theme(scene, :visible),
        strokecolor = RGBAf0(0,0,0,0),
        colormap = theme(scene, :colormap),
        colorrange = automatic,
        strokewidth = 0.0,
        shading = false,
        linestyle = nothing,
        overdraw = false,
        transparency = false,
    )
end
convert_arguments(::Type{<: Poly}, v::AbstractVector{<: AbstractVector{<: VecTypes}}) = (v,)
convert_arguments(::Type{<: Poly}, v::AbstractVector{<: VecTypes}) = ([convert_arguments(Scatter, v)[1]],)
convert_arguments(::Type{<: Poly}, v::AbstractVector{<: Union{Circle, Rectangle, HyperRectangle}}) = (v,)
convert_arguments(::Type{<: Poly}, args...) = ([convert_arguments(Scatter, args...)[1]],)
convert_arguments(::Type{<: Poly}, vertices::AbstractArray, indices::AbstractArray) = convert_arguments(Mesh, vertices, indices)

function plot!(plot::Poly{<: Tuple{Union{AbstractMesh, GeometryPrimitive}}})
    mesh!(
        plot, plot[1],
        color = plot[:color], colormap = plot[:colormap], colorrange = plot[:colorrange],
        shading = plot[:shading], visible = plot[:visible], overdraw = plot[:overdraw]
    )
    wireframe!(
        plot, plot[1],
        color = plot[:strokecolor], linestyle = plot[:linestyle],
        linewidth = plot[:strokewidth], visible = plot[:visible], overdraw = plot[:overdraw]
    )
end

function plot!(plot::Poly{<: Tuple{<: AbstractVector{P}}}) where P <: AbstractVector{<: VecTypes}
    polygons = plot[1]
    color_node = plot[:color]
    attributes = Attributes()
    meshes = lift(polygons) do polygons
        polys = Vector{Point2f0}[]
        for poly in polygons
            s = GeometryTypes.split_intersections(poly)
            append!(polys, s)
        end
        GLNormalMesh.(polys)
    end
    mesh!(plot, meshes,
        visible = plot.visible,
        shading = plot.shading,
        color = plot.color,
        colormap = plot.colormap,
        colorrange = plot.colorrange,
        overdraw = plot.overdraw,
        transparency = plot.transparency
    )
    outline = lift(polygons) do polygons
        line = Point2f0[]
        for poly in polygons
            append!(line, poly)
            push!(line, poly[1])
            push!(line, Point2f0(NaN))
        end
        line
    end
    lines!(
        plot, outline, visible = plot.visible,
        color = plot.strokecolor, linestyle = plot.linestyle,
        linewidth = plot.strokewidth,
        overdraw = plot.overdraw, transparency = plot.transparency
    )
end

function plot!(plot::Mesh{<: Tuple{<: AbstractVector{P}}}) where P <: AbstractMesh
    meshes = plot[1]
    color_node = plot[:color]
    attributes = Attributes(
        visible = plot[:visible], shading = plot[:shading]
    )
    if haskey(plot, :colormap)
        attributes[:colormap] = plot[:colormap]
    end
    if haskey(plot, :colorrange)
        attributes[:colorrange] = plot[:colorrange]
    end
    bigmesh = if color_node[] isa Vector && length(color_node[]) == length(meshes[])
        lift(meshes, color_node) do meshes, colors
            meshes = GeometryTypes.add_attribute.(GLNormalMesh.(meshes), to_color.(colors))
            merge(meshes)
        end
    else
        attributes[:color] = color_node
        lift(meshes) do meshes
            merge(GLPlainMesh.(meshes))
        end
    end
    mesh!(plot, attributes, bigmesh)
end

function plot!(plot::Poly{<: Tuple{<: AbstractVector{T}}}) where T <: Union{Circle, Rectangle, Rect}
    positions = plot[1]
    position = lift(positions) do rects
        Point.(minimum.(rects))
    end
    markersize = lift(positions, name = "markersize") do rects
        widths.(rects)
    end
    scatter!(
        plot, position,
        marker = T, markersize = markersize, transform_marker = true,
        marker_offset = Vec2f0(0),
        color = plot[:color],
        strokecolor = plot[:strokecolor],
        colormap = plot[:colormap],
        colorrange = plot[:colorrange],
        strokewidth = plot[:strokewidth], visible = plot[:visible]
    )
end
function data_limits(p::Poly{<: Tuple{<: AbstractVector{T}}}) where T <: Union{Circle, Rectangle, Rect}
    xyz = p.plots[1][1][]
    msize = p.plots[1][:markersize][]
    xybb = FRect3D(xyz)
    mwidth = FRect3D(xyz .+ msize)
    union(mwidth, xybb)
end

"""
    `arrows(points, directions; kwargs...)`
    `arrows(x, y, u, v)`
    `arrows(x::AbstractVector, y::AbstractVector, u::AbstractMatrix, v::AbstractMatrix)`
    `arrows(x, y, z, u, v, w)`

Plots arrows at the specified points with the specified components.
`u` and `v` are interpreted as vector components (`u` being the x
and `v` being the y), and the vectors are plotted with the tails at
`x`, `y`.

If `x, y, u, v` are `<: AbstractVector`, then each 'row' is plotted
as a single vector.

If `u, v` are `<: AbstractMatrix`, then `x` and `y` are interpreted as
specifications for a grid, and `u, v` are plotted as arrows along the
grid.

`arrows` can also work in three dimensions.

## Theme
$(ATTRIBUTES)
"""
@recipe(Arrows, points, directions) do scene
    theme = Theme(
        arrowhead = automatic,
        arrowtail = nothing,
        linecolor = :black,
        linewidth = 1,
        arrowsize = 0.3,
        linestyle = nothing,
        scale = Vec3f0(1),
        normalize = false,
        lengthscale = 1.0f0
    )
    # connect arrow + linecolor by default
    get!(theme, :arrowcolor, theme[:linecolor])
    theme
end

# For the matlab/matplotlib users
const quiver = arrows
const quiver! = arrows!
export quiver, quiver!

arrow_head(N, marker) = marker
arrow_head(N, marker::Automatic) = N == 2 ? '▲' : Pyramid(Point3f0(0, 0, -0.5), 1f0, 1f0)

scatterfun(N) = N == 2 ? scatter! : meshscatter!

convert_arguments(::Type{<: Arrows}, x, y, u, v) = (Point2f0.(x, y), Vec2f0.(u, v))
function convert_arguments(::Type{<: Arrows}, x::AbstractVector, y::AbstractVector, u::AbstractMatrix, v::AbstractMatrix)
    (vec(Point2f0.(x, y')), vec(Vec2f0.(u, v)))
end
convert_arguments(::Type{<: Arrows}, x, y, z, u, v, w) = (Point3f0.(x, y, z), Vec3f0.(u, v, w))

function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) where {N, T, V}
    @extract arrowplot (points, directions, lengthscale, arrowhead, arrowsize, arrowcolor)
    headstart = lift(points, directions, lengthscale) do points, directions, s
        map(points, directions) do p1, dir
            dir = arrowplot[:normalize][] ? StaticArrays.normalize(dir) : dir
            Point{N, Float32}(p1) => Point{N, Float32}(p1 .+ (dir .* Float32(s)))
        end
    end
    linesegments!(
        arrowplot, headstart,
        color = arrowplot[:linecolor], linewidth = arrowplot[:linewidth],
        linestyle = arrowplot[:linestyle],
    )
    scatterfun(N)(
        arrowplot,
        lift(x-> last.(x), headstart),
        marker = lift(x-> arrow_head(N, x), arrowhead), markersize = arrowsize,
        color = arrowcolor, rotations = directions
    )
end

"""
    `wireframe(x, y, z)`, `wireframe(positions)`, or `wireframe(mesh)`

Draws a wireframe, either interpreted as a surface or as a mesh.

## Theme
$(ATTRIBUTES)
"""
@recipe(Wireframe) do scene
    default_theme(scene, LineSegments)
end

function argument_conversion(::Type{Wireframe}, x::AbstractVector, y::AbstractVector, z::AbstractMatrix)
    (ngrid(x, y)..., z)
end

xvector(x::AbstractVector, len) = x
xvector(x::ClosedInterval, len) = range(minimum(x), stop=maximum(x), length=len)
xvector(x::AbstractMatrix, len) = x

yvector(x, len) = xvector(x, len)'
yvector(x::AbstractMatrix, len) = x

function plot!(plot::Wireframe{<: Tuple{<: Any, <: Any, <: AbstractMatrix}})
    points_faces = lift(plot[1:3]...) do x, y, z
        T = eltype(z); M, N = size(z)
        points = vec(Point3f0.(xvector(x, M), yvector(y, N), z))
        # Connect the vetices with faces, as one would use for a 2D Rectangle
        # grid with M,N grid points
        faces = decompose(Face{2, GLIndex}, SimpleRectangle(0, 0, 1, 1), (M, N))
        view(points, faces)
    end
    linesegments!(plot, Theme(plot), points_faces)
end

function plot!(plot::Wireframe{Tuple{T}}) where T
    points = lift(plot[1]) do g
        # get the point representation of the geometry
        indices = decompose(Face{2, GLIndex}, g)
        points = decompose(Point3f0, g)
        view(points, indices)
    end
    linesegments!(plot, Theme(plot), points)
end

function sphere_streamline(linebuffer, ∇ˢf, pt, h, n)
    push!(linebuffer, pt)
    df = normalize(∇ˢf(pt[1], pt[2], pt[3]))
    push!(linebuffer, normalize(pt .+ h*df))
    for k=2:n
        cur_pt = last(linebuffer)
        push!(linebuffer, cur_pt)
        df = normalize(∇ˢf(cur_pt...))
        push!(linebuffer, normalize(cur_pt .+ h*df))
    end
    return
end

"""
    StreamLines

TODO add function signatures
TODO add descripton

## Theme
$(ATTRIBUTES)
"""
@recipe(StreamLines, points, directions) do scene
    Theme(
        h = 0.01f0,
        n = 5,
        color = :black,
        linewidth = 1
    )
end

# typeof(([1, 2, 3] |> vec, [1, 2, 3] |> vec)) <: Tuple{<: AbstractVector{T}, <: AbstractVector{T}} where T
# true
# streamlines([1, 2, 3] |> vec, [1, 2, 3] |> vec)
# ERROR: Plotting for the arguments (::Array{Int64,1}, ::Array{Int64,1}) not defined for AbstractPlotting.streamlines. If you want to support those arguments, overload plot!(plot::AbstractPlotting.streamlines{ <: Tuple{Array{Int64,1},Array{Int64,1}}})

# function plot!(plot::StreamLines) where T
#     @extract plot (points, directions)
#     linebuffer = T[]
#     lines = lift(directions, points, plot[:h], plot[:n]) do ∇ˢf, origins, h, n
#         empty!(linebuffer)
#         for point in origins
#             sphere_streamline(linebuffer, ∇ˢf, point, h, n)
#         end
#         linebuffer
#     end
#     linesegments!(plot, Theme(plot), lines)
# end

"""
    Series - ?

TODO add function signatures
TODO add description

## Theme
$(ATTRIBUTES)
"""
@recipe(Series, series) do scene
    Theme(
        seriescolors = :Set1,
        seriestype = :lines
    )
end
convert_arguments(::Type{<: Series}, A::AbstractMatrix{<: Number}) = (A,)
function plot!(sub::Series)
    A = sub[1]
    colors = map_once(sub[:seriescolors], A) do colors, A
        cmap = to_colormap(colors)
        if size(A, 2) > length(cmap)
            @info("Colormap doesn't have enough distinctive values. Please consider using another value for seriescolors")
            cmap = interpolated_getindex.((cmap,), range(0, stop=1, length=M))
        end
        cmap
    end
    map_once(A, sub[:seriestype]) do A, stype
        empty!(sub.plots)
        N, M = size(A)
        for i = 1:M
            c = lift(getindex, colors, i)
            attributes = Theme(color = c)
            a_view = view(A, :, i)
            if stype in (:lines, :scatter_lines)
                lines!(sub, attributes, a_view)
            end
            # if stype in (:scatter, :scatter_lines)
            #     scatter!(subsub, attributes, a_view)
            # end
            # subsub
        end
    end
    labels = get(sub, :labels) do
        map(i-> "y $i", 1:size(A[], 2))
    end
    legend!(sub, copy(sub.plots), labels)
    sub
end

"""
    `annotations(strings::Vector{String}, positions::Vector{Point})`

Plots an array of texts at each position in `positions`.

## Theme
$(ATTRIBUTES)
"""
@recipe(Annotations, text, position) do scene
    default_theme(scene, Text)
end

"""
Pushes an updates to all listeners of `node`
"""
function notify!(node::Node)
    node[] = node[]
end

function plot!(plot::Annotations)
    position = plot[2]
    sargs = (
        plot[:model], plot[:font],
        plot[1], position,
        getindex.(plot, (:color, :textsize, :align, :rotation))...,
    )
    N = to_value(position) |> eltype |> length
    atlas = get_texture_atlas()
    combinedpos = [Point3f0(0)]; colors = RGBAf0[RGBAf0(0,0,0,0)]
    scales = Vec2f0[(0,0)]; fonts = NativeFont[to_font("Dejavu Sans")]
    rotations = Quaternionf0[Quaternionf0(0,0,0,0)]

    tplot = text!(plot, "",
        align = Vec2f0(0), model = Mat4f0(I),
        position = combinedpos, color = colors,
        textsize = scales, font = fonts, rotation = rotations
    ).plots[end]

    onany(sargs...) do model, font, args...
        if length(args[1]) != length(args[2])
            error("For each text annotation, there needs to be one position. Found: $(length(t)) strings and $(length(p)) positions")
        end
        io = IOBuffer();
        empty!(combinedpos); empty!(colors); empty!(scales); empty!(fonts); empty!(rotations)

        broadcast_foreach(1:length(args[1]), args...) do idx, text, startpos, color, tsize, alignment, rotation
            # the fact, that Font == Vector{FT_FreeType.Font} is pretty annoying for broadcasting.
            # TODO have a better Font type!
            f = to_font(font)
            f = isa(f, NativeFont) ? f : f[idx]
            c = to_color(color)
            rot = to_rotation(rotation)
            pos, s = layout_text(text, startpos, tsize, f, alignment, rot, model)
            print(io, text)
            n = length(pos)
            append!(combinedpos, pos)
            append!(scales, s)
            append!(colors, repeated(c, n))
            append!(fonts, repeated(f, n))
            append!(rotations, repeated(rot, n))
        end
        str = String(take!(io))
        # update string the signals
        tplot[1] = str
        tplot[:scales] = scales
        tplot[:color] = colors
        tplot[:rotation] = rotations
        # fonts shouldn't need an update, since it will get udpated when listening on string
        #
        return
    end
    # update one time in the beginning, since otherwise the above won't run
    notify!(sargs[1])
    plot
end

"""
    arc(origin, radius, start_angle, stop_angle; kwargs...)

This function plots a circular arc, centered at `origin` with radius `radius`,
from `start_angle` to `stop_angle`.
`origin` must be a coordinate in 2 dimensions (i.e., a `Point2`); the rest of the arguments must be
`<: Number`.

Examples:

`arc(Point2f0(0), 1, 0.0, π)`
`arc(Point2f0(1, 2), 0.3. π, -π)`

## Theme
$(ATTRIBUTES)
"""
@recipe(Arc, origin, radius, start_angle, stop_angle) do scene
    Theme(;
        default_theme(scene, Lines)...,
        resolution = 361,
    )
end

function plot!(p::Arc)
    args = getindex.(p, (:origin, :radius, :start_angle, :stop_angle, :resolution))
    positions = lift(args...) do origin, radius, start_angle, stop_angle, resolution
        map(range(start_angle, stop=stop_angle, length=resolution)) do angle
            origin .+ Point2f0((sin(angle), cos(angle)) .* radius)
        end
    end
    lines!(p, Theme(p), positions)
end

function AbstractPlotting.plot!(plot::Plot(AbstractVector{<: Complex}))
    plot[:axis, :labels] = ("Re(x)", "Im(x)")
    lines!(plot, lift(im-> Point2f0.(real.(im), imag.(im)), x[1]))
end

"""
    barplot(x, y; kwargs...)

Plots a barplot; `y` defines the height.  `x` and `y` should be 1 dimensional.

## Theme
$(ATTRIBUTES)
"""
@recipe(BarPlot, x, y) do scene
    Theme(;
        fillto = 0.0,
        color = theme(scene, :color),
        colormap = theme(scene, :colormap),
        colorrange = automatic,
        marker = Rect,
        strokewidth = 0,
        strokecolor = :white,
        width = automatic
    )
end

function data_limits(p::BarPlot)
    xy = p.plots[1][1][]
    msize = p.plots[1][:markersize][]
    xstart, xend = first(msize)[1], last(msize)[1]
    xvals = first.(xy)
    # correct widths
    xvals[1] = xvals[1] - (xstart / 2)
    xvals[end] = xvals[end] + (xend / 2)
    xybb = FRect3D(xy)
    y = last.(msize) .+ last.(xy)
    bb = xyz_boundingbox(xvals, y)
    union(bb, xybb)
end

conversion_trait(::Type{<: BarPlot}) = PointBased()

function AbstractPlotting.plot!(p::BarPlot)
    pos_scale = lift(p[1], p[:fillto], p[:width]) do xy, fillto, hw
        # compute half-width of bars
        if hw === automatic
            hw = mean(diff(first.(xy))) # TODO ignore nan?
        end
        # make fillto a vector... default fills to 0
        positions = Point2f0.(first.(xy), Float32.(fillto))
        scales = Vec2f0.(abs.(hw), last.(xy))
        offset = Vec2f0.(hw ./ -2f0, 0)
        positions, scales, offset
    end

    scatter!(
        p, lift(first, pos_scale),
        marker = p[:marker], marker_offset = lift(last, pos_scale),
        markersize = lift(getindex, pos_scale, Node(2)),
        color = p[:color], colormap = p[:colormap], colorrange = p[:colorrange],
        transform_marker = true, strokewidth = p[:strokewidth],
        strokecolor = p[:strokecolor]
    )
end

function convert_arguments(P::PlotFunc, r::AbstractVector, f::Function)
    ptype = plottype(P, Lines)
    to_plotspec(ptype, convert_arguments(ptype, r, f.(r)))
end

function convert_arguments(P::PlotFunc, i::AbstractInterval, f::Function)
    convert_arguments(P, PlotUtils.adapted_grid(f, endpoints(i)), f)
end

to_tuple(t::Tuple) = t
to_tuple(t) = (t,)

function convert_arguments(P::PlotFunc, f::Function, args...; kwargs...)
    tmp = f(args...; kwargs...) |> to_tuple
    convert_arguments(P, tmp...)
end

"""
    scatterlines(xs, ys, [zs]; kwargs...)

Plots `lines` between sets of x and y coordinates provided,
as well as plotting those points using `scatter`.

## Theme
$(ATTRIBUTES)
"""
@recipe(ScatterLines) do scene
    merge(default_theme(scene, Scatter), default_theme(scene, Lines))
end

function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N
    plot!(p, Lines, Theme(p), p[1:N]...)
    plot!(p, Scatter, Theme(p), p[1:N]...)
end

"""
    band(x, ylower, yupper; kwargs...)

Plots a band from `ylower` to `yupper` along `x`.

## Theme
$(ATTRIBUTES)
"""
@recipe(Band, x, ylower, yupper) do scene
    Theme(;
        default_theme(scene, Mesh)...,
        color = RGBAf0(1.0,0,0,0.2)
    )
end

function band_connect(n)
    ns = 1:n-1
    ns2 = n+1:2n-1
    [GLTriangle.(ns, ns .+ 1, ns2); GLTriangle.(ns .+ 1, ns2 .+ 1, ns2)]
end

function plot!(plot::Band)
    coordinates = lift( (x, ylower, yupper) -> [Point2f0.(x, ylower); Point2f0.(x, yupper)], plot[1], plot[2], plot[3])
    connectivity = lift(x -> band_connect(length(x)), plot[1])
    mesh!(plot, coordinates, connectivity;
        color = plot[:color], colormap = plot[:colormap],
        colorrange = plot[:colorrange],
        shading = false, visible = plot[:visible]
    )
end

function fill_view(x, y1, y2, where::Nothing)
  x, y1, y2
end
function fill_view(x, y1, y2, where::Function)
  fill_view(x, y1, y2, where.(x, y1, y2))
end
function fill_view(x, y1, y2, bools::AbstractVector{<: Union{Integer, Bool}})
  view(x, bools), view(y1, bools), view(y2, bools)
end

"""
    fill_between!(x, y1, y2; where = nothing, scene = current_scene(), kw_args...)

fill the section between 2 lines with the condition `where`
"""
function fill_between!(x, y1, y2; where = nothing, scene = current_scene(), kw_args...)
  xv, ylow, yhigh = fill_view(x, y1, y2, where)
  band!(scene, xv, ylow, yhigh; kw_args...)
end

export fill_between!

"""
    contour(x, y, z)
Creates a contour plot of the plane spanning x::Vector, y::Vector, z::Matrix

## Theme
$(ATTRIBUTES)
"""
@recipe(Contour) do scene
    default = default_theme(scene)
    pop!(default, :color)
    Theme(;
        default...,
        color = nothing,
        colormap = theme(scene, :colormap),
        colorrange = AbstractPlotting.automatic,
        levels = 5,
        linewidth = 1.0,
        fillrange = false,
    )
end

"""
    contour3d(x, y, z)
Creates a 3D contour plot of the plane spanning x::Vector, y::Vector, z::Matrix,
with z-elevation for each level.

## Theme
$(ATTRIBUTES)
"""
@recipe(Contour3d) do scene
    default_theme(scene, Contour)
end

function contourlines(::Type{<: Contour}, contours, cols)
    result = Point2f0[]
    colors = RGBA{Float32}[]
    for (color, c) in zip(cols, Contours.levels(contours))
        for elem in Contours.lines(c)
            append!(result, elem.vertices)
            push!(result, Point2f0(NaN32))
            append!(colors, fill(color, length(elem.vertices) + 1))
        end
    end
    result, colors
end

function contourlines(::Type{<: Contour3d}, contours, cols)
    result = Point3f0[]
    colors = RGBA{Float32}[]
    for (color, c) in zip(cols, Contours.levels(contours))
        for elem in Contours.lines(c)
            for p in elem.vertices
                push!(result, Point3f0(p[1], p[2], c.level))
            end
            push!(result, Point3f0(NaN32))
            append!(colors, fill(color, length(elem.vertices) + 1))
        end
    end
    result, colors
end

to_levels(x::AbstractVector{<: Number}, cnorm) = x
function to_levels(n::Integer, cnorm)
    zmin, zmax = cnorm
    dz = (zmax - zmin) / (n + 1)
    range(zmin + dz; step = dz, length = n)
end
conversion_trait(::Type{<: Contour3d}) = SurfaceLike()
conversion_trait(::Type{<: Contour}) = SurfaceLike()
conversion_trait(::Type{<: Contour{<: Tuple{X, Y, Z, Vol}}}) where {X, Y, Z, Vol} = VolumeLike()
conversion_trait(::Type{<: Contour{<: Tuple{<: AbstractArray{T, 3}}}}) where T = VolumeLike()

function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol}
    x, y, z, volume = plot[1:4]
    @extract plot (colormap, levels, linewidth, alpha)
    valuerange = lift(nan_extrema, volume)
    cliprange = replace_automatic!(plot, :colorrange) do
        valuerange
    end
    cmap = lift(colormap, levels, linewidth, alpha, cliprange, valuerange) do _cmap, l, lw, alpha, cliprange, vrange
        levels = to_levels(l, vrange)
        nlevels = length(levels)
        N = nlevels * 50
        iso_eps = nlevels * ((vrange[2] - vrange[1]) / N) # TODO calculate this
        cmap = to_colormap(_cmap)
        v_interval = cliprange[1] .. cliprange[2]
        # resample colormap and make the empty area between iso surfaces transparent
        map(1:N) do i
            i01 = (i-1) / (N - 1)
            c = AbstractPlotting.interpolated_getindex(cmap, i01)
            isoval = vrange[1] + (i01 * (vrange[2] - vrange[1]))
            line = reduce(levels, init = false) do v0, level
                (isoval in v_interval) || return false
                v0 || (abs(level - isoval) <= iso_eps)
            end
            RGBAf0(Colors.color(c), line ? alpha : 0.0)
        end
    end
    volume!(
        plot, x, y, z, volume, colormap = cmap, colorrange = cliprange, algorithm = 7,
        transparency = plot[:transparency],
        overdraw = plot[:overdraw]
    )
end

function color_per_level(color, colormap, colorrange, alpha, levels)
    color_per_level(to_color(color), colormap, colorrange, alpha, levels)
end

function color_per_level(color::Colorant, colormap, colorrange, alpha, levels)
    fill(color, length(levels))
end

function color_per_level(colors::AbstractVector, colormap, colorrange, alpha, levels)
    color_per_level(to_colormap(colors), colormap, colorrange, alpha, levels)
end

function color_per_level(colors::AbstractVector{<: Colorant}, colormap, colorrange, alpha, levels)
    if length(levels) == length(colors)
        return colors
    else
        # TODO resample?!
        error("For a contour plot, `color` with an array of colors needs to
        have the same length as `levels`.
        Found $(length(colors)) colors, but $(length(levels)) levels")
    end
end

function color_per_level(::Nothing, colormap, colorrange, a, levels)
    cmap = to_colormap(colormap)
    map(levels) do level
        c = interpolated_getindex(cmap, level, colorrange)
        RGBAf0(color(c), alpha(c) * a)
    end
end

function plot!(plot::T) where T <: Union{Contour, Contour3d}
    x, y, z = plot[1:3]
    if to_value(plot[:fillrange])
        plot[:interpolate] = true
        # TODO normalize linewidth for heatmap
        plot[:linewidth] = map(x-> x ./ 10f0, plot[:linewidth])
        heatmap!(plot, Theme(plot), x, y, z)
    else
        zrange = lift(nan_extrema, z)
        levels = lift(plot[:levels], zrange) do levels, zrange
            if levels isa AbstractVector{<: Number}
                return levels
            elseif levels isa Integer
                to_levels(levels, zrange)
            else
                error("Level needs to be Vector of iso values, or a single integer to for a number of automatic levels")
            end
        end
        replace_automatic!(plot, :colorrange) do
            lift(nan_extrema, levels)
        end
        args = @extract plot (color, colormap, colorrange, alpha)
        level_colors = lift(color_per_level, args..., levels)
        result = lift(x, y, z, levels, level_colors) do x, y, z, levels, level_colors
            t = eltype(z)
            # Compute contours
            xv, yv = to_vector(x, size(z,1), t), to_vector(y, size(z,2), t)
            contours = Contours.contours(xv, yv, z,  convert(Vector{eltype(z)}, levels))
            contourlines(T, contours, level_colors)
        end
        lines!(
            plot, lift(first, result);
            color = lift(last, result), linewidth = plot[:linewidth]
        )
    end
    plot
end

function AbstractPlotting.data_limits(x::Contour{<: Tuple{X, Y, Z}}) where {X, Y, Z}
    AbstractPlotting.xyz_boundingbox(to_value.((x[1], x[2]))...)
end

"""
    VolumeSlices

TODO add function signatures
TODO add descripton

## Theme
$(ATTRIBUTES)
"""
@recipe(VolumeSlices, x, y, z, volume) do scene
    Theme(
        colormap = theme(scene, :colormap),
        colorrange = nothing,
        alpha = 0.1,
        contour = Theme(),
        heatmap = Theme(),
    )
end

convert_arguments(::Type{<: VolumeSlices}, x, y, z, volume) = convert_arguments(Contour, x, y, z, volume)
function plot!(vs::VolumeSlices)
    @extract vs (x, y, z, volume)
    replace_automatic!(vs, :colorrange) do
        map(extrema, volume)
    end
    keys = (:colormap, :alpha, :colorrange)
    contour!(vs, vs[:contour], x, y, z, volume)
    planes = (:xy, :xz, :yz)
    hattributes = vs[:heatmap]
    sliders = map(zip(planes, (x, y, z))) do plane_r
        plane, r = plane_r
        idx = node(plane, Node(1))
        vs[plane] = idx
        hmap = heatmap!(vs, hattributes, x, y, zeros(length(x[]), length(y[]))).plots[end]
        on(idx) do i
            transform!(hmap, (plane, r[][i]))
            indices = ntuple(Val(3)) do j
                planes[j] == plane ? i : (:)
            end
            hmap[3][] = view(volume[], indices...)
        end
        idx
    end
    plot!(scene, vs, rest)
end

"""
    showlibrary(lib::Symbol)::Scene

Shows all colour gradients in the given library.
Returns a Scene with these colour gradients arranged
as horizontal colourbars.
"""
function showlibrary(lib::Symbol)::Scene

    cgrads = sort(PlotUtils.cgradients(lib))

    PlotUtils.clibrary(lib)

    showgradients(cgrads)

end

"""
    showgradients(
        cgrads::AbstractVector{Symbol};
        h = 0.0, offset = 0.2, textsize = 0.7,
        resolution = (800, length(cgrads) * 84)
    )::Scene

Plots the given colour gradients arranged as horizontal colourbars.
If you change the offsets or the font size, you may need to change the resolution.
"""
function showgradients(
        cgrads::AbstractVector{Symbol};
        h = 0.0,
        offset = 0.4,
        textsize = 0.7,
        resolution = (800, length(cgrads) * 84),
        monospace = true
    )::Scene

    scene = Scene(resolution = resolution)

    map(collect(cgrads)) do cmap

         c = to_colormap(cmap)

         cbar = image!(
             scene,
             range(0, stop = 10, length = length(c)),
             range(0, stop = 1, length = length(c)),
             reshape(c, (length(c),1)),
             show_axis = false
         )[end]

         cmapstr = monospace ? UnicodeFun.to_latex("\\mono{$cmap}") : string(cmap, ":")

         text!(
             scene,
             cmapstr,
             position = Point2f0(-0.1, 0.5 + h),
             align = (:right, :center),
             show_axis = false,
             textsize = textsize
         )

         translate!(cbar, 0, h, 0)

         h -= (1 + offset)

    end

    scene

end

"""
    timeseries(x::Node{{Union{Number, Point2}}})

Plots a sampled signal.
Usage:
```julia
signal = Node(1.0)
scene = timeseries(signal)
display(scene)
# @async is optional, but helps to continue evaluating more code
@async while isopen(scene)
    # aquire data from e.g. a sensor:
    data = rand()
    # update the signal
    signal[] = data
    # sleep/ wait for new data/ whatever...
    # It's important to yield here though, otherwise nothing will be rendered
    sleep(1/30)
end

```
"""
@recipe(TimeSeries, signal) do scene
    Theme(
        history = 100;
        default_theme(scene, Lines)...
    )
end

signal2point(signal::Number, start) = Point2f0(time() - start, signal)
signal2point(signal::Point2, start) = signal
signal2point(signal, start) = error(""" Signal needs to be of type Number or Point.
Found: $(typeof(signal))
""")

function AbstractPlotting.plot!(plot::TimeSeries)
    # normal plotting code, building on any previously defined recipes
    # or atomic plotting operations, and adding to the combined `plot`:
    points = Node(fill(Point2f0(NaN), plot.history[]))
    buffer = copy(points[])
    lines!(plot, points)
    start = time()
    on(plot.signal) do x
        points[][end] = signal2point(x, start)
        circshift!(buffer, points[], 1)
        buff_ref = buffer
        buffer = points[]
        points[] = buff_ref
        update!(parent(plot))
    end
    plot
end

"""
    streamplot(f::function, xinterval, yinterval;
        kwargs...)
f must either accept `f(::Point)` or `f(x::Number, y::Number)`.
f must return a Point2.
Example:
```julia
using MakieGallery, Makie
run_example("streamplot")
```
## Theme
$(ATTRIBUTES)
"""
@recipe(StreamPlot, f, limits) do scene
    Theme(
        stepsize = 0.01,
        gridsize = (32, 32, 32),
        colormap = theme(scene, :colormap),
        arrow_size = 0.03
    )
end

function convert_arguments(::Type{<: StreamPlot}, f::Function, xrange, yrange)
    xmin, xmax = extrema(xrange)
    ymin, ymax = extrema(yrange)
    return (f, Rect(xmin, ymin, xmax - xmin, ymax - ymin))
end
function convert_arguments(::Type{<: StreamPlot}, f::Function, xrange, yrange, zrange)
    xmin, xmax = extrema(xrange)
    ymin, ymax = extrema(yrange)
    zmin, zmax = extrema(zrange)
    mini = Vec3f0(xmin, ymin, zmin)
    maxi = Vec3f0(xmax, ymax, zmax)
    return (f, Rect(mini, maxi .- mini))
end

function convert_arguments(::Type{<: StreamPlot}, f::Function, limits::Rect)
    return (f, limits)
end

"""
Code adapted from an example implementation by Moritz Schauer (@mschauer)
from https://github.com/JuliaPlots/Makie.jl/issues/355#issuecomment-504449775
"""
function streamplot_impl(CallType, f, limits::Rect{N, T}, resolutionND, stepsize) where {N, T}
    resolution = to_ndim(Vec{N, Int}, resolutionND, last(resolutionND))
    mask = trues(resolution...)
    arrow_pos = Point{N, Float32}[]
    arrow_dir = Vec{N, Float32}[]
    line_points = Point{N, Float32}[]
    colors = Float64[]
    line_colors = Float64[]
    dt = Point{N, Float32}(stepsize)
    mini, maxi = minimum(limits), maximum(limits)
    r = ntuple(N) do i
        LinRange(mini[i], maxi[i], resolution[i] + 1)
    end
    apply_f(x0, P) = if P <: Point
        f(x0)
    else
        f(x0...)
    end
    for c in CartesianIndices(mask)
        x0 = Point(ntuple(N) do i
            first(r[i]) + (c[i] - 0.5) * step(r[i])
        end)
        if mask[c]
            point = apply_f(x0, CallType)
            if !(point isa Point2 || point isa Point3)
                error("Function passed to streamplot must return Point2 or Point3")
            end
            pnorm = norm(point)
            push!(arrow_pos, x0)
            push!(arrow_dir, point ./ pnorm)
            push!(colors, pnorm)
            mask[c] == false
            for d in (-1, 1)
                n_linepoints = 1
                x = x0
                push!(line_points, Point{N, Float32}(NaN), x)
                push!(line_colors, 0.0, pnorm)
                while x in limits && n_linepoints < 500
                    point = apply_f(x, CallType)
                    pnorm = norm(point)
                    x = x .+ d .* dt .* point ./ pnorm
                    if !(x in limits)
                        break
                    end
                    # WHAT? Why does point behave different from tuple in this
                    # broadcast
                    idx = CartesianIndex(searchsortedlast.(r, Tuple(x)))
                    if idx != c
                        if !mask[idx]
                            break
                        end
                        mask[idx] = false
                        c = idx
                    end
                    push!(line_points, x)
                    push!(line_colors, pnorm)
                    n_linepoints += 1
                end
            end
        end
    end
    return (
        arrow_pos,
        arrow_dir,
        line_points,
        colors,
        line_colors,
    )
end

function plot!(p::StreamPlot)
    data = lift(p.f, p.limits, p.gridsize, p.stepsize) do f, limits, resolution, stepsize
        P = if applicable(f, Point2f0(0)) || applicable(f, Point3f0(0))
            Point
        else
            Number
        end
        streamplot_impl(P, f, limits, resolution, stepsize)
    end
    lines!(
        p,
        lift(x->x[3], data), color = lift(last, data), colormap = p.colormap
    )
    N = ndims(p.limits[])
    scatterfun(N)(
        p,
        lift(first, data), markersize = p.arrow_size, marker = arrow_head(N, automatic),
        color = lift(x-> x[4], data), rotations = lift(x-> x[2], data),
        colormap = p.colormap,
    )
end

"""
    spy(x::Range, y::Range, z::AbstractSparseArray)
Visualizes big sparse matrices.
Usage:
```julia
N = 200_000
x = sprand(Float64, N, N, (3(10^6)) / (N*N));
spy(x)
# or if you want to specify the range of x and y:
spy(0..1, 0..1, x)
```
## Theme
$(ATTRIBUTES)
"""
@recipe(Spy, x, y, z) do scene
    Theme(
        marker = automatic,
        markersize = automatic,
        colormap = theme(scene, :colormap),
        colorrange = automatic,
        framecolor = :black,
        framesize = 1,
    )
end

function convert_arguments(::Type{<: Spy}, x::SparseArrays.AbstractSparseArray)
    (0..size(x, 1), 0..size(x, 2), x)
end
function convert_arguments(::Type{<: Spy}, x, y, z::SparseArrays.AbstractSparseArray)
    (x, y, z)
end
function calculated_attributes!(::Type{<: Spy}, plot)
end

function plot!(p::Spy)
    rect = lift(p.x, p.y) do x, y
        xe = extrema(x)
        ye = extrema(y)
        FRect2D((xe[1], ye[1]), (xe[2] - xe[1], ye[2] - ye[1]))
    end
    # TODO FastPixel isn't accepting marker size in data coordinates
    # but instead in pixel - so we need to fix that in GLMakie for consistency
    # and make this nicer when redoing unit support
    markersize = lift(p.markersize, rect, p.z) do msize, rect, z
        if msize === automatic
            widths(rect) ./ Vec2f0(size(z))
        else
            msize
        end
    end
    # TODO correctly align marker
    xycol = lift(rect, p.z, markersize) do rect, z, markersize
        x, y, color = SparseArrays.findnz(z)
        points = map(x, y) do x, y
            (((Point2f0(x, y) .- 1) ./ Point2f0(size(z) .- 1)) .*
            widths(rect) .+ minimum(rect))
        end
        points, color
    end
    replace_automatic!(p, :colorrange) do
        lift(extrema_nan ∘ SparseArrays.nonzeros, p.z)
    end
    marker = lift(p.marker) do x
        if x === automatic
            # If we currently use GLMakie, we can go super fast!
            BackendModule = parentmodule(typeof(AbstractPlotting.current_backend[]))
            if nameof(BackendModule) == :GLMakie
                BackendModule.FastPixel()
            else
                :rect
            end
        else
            x
        end
    end

    scatter!(
        p,
        lift(first, xycol), color = lift(last, xycol),
        marker = marker, markersize = markersize, colorrange = p.colorrange
    )

    lines!(p, rect, color = p.framecolor, linewidth = p.framesize)
end


text:
using NeuralQuantum
using Test
using NeuralQuantum: LdagLSparseSuperopProblem, LRhoSparseOpProblem, LRhoKLocalOpProblem
using NeuralQuantum: init_lut!, HamiltonianGSEnergyProblem

Nsites = 4
T = Float64
lind = quantum_ising_lind(SquareLattice([Nsites],PBC=true), g=1.3, V=2.0, γ=1.0)
ham  = lind.H

net  = cached(RBM(T, Nsites, 2))

prob_sp = HamiltonianGSEnergyProblem(T, ham, operators=false);
prob_op = HamiltonianGSEnergyProblem(T, ham, operators=true);

v    = state(prob_sp, net)

H = DenseOperator(ham).data
ψ = ket(net, prob_sp, false).data
Clocs_ex = (H*ψ)./ψ

ic_sp   = NeuralQuantum.MCMCSREvaluationCache(net, prob_sp);  zero!(ic_sp)
ic_op   = NeuralQuantum.MCMCSREvaluationCache(net, prob_op);  zero!(ic_op)

for i=1:spacedimension(v)
    set_index!(v, i)
    NeuralQuantum.sample_network!(ic_sp, prob_sp, net, v);
    NeuralQuantum.sample_network!(ic_op, prob_op, net, v);
end

SREval_sp    = EvaluatedNetwork(SR(), net)
SREval_op    = EvaluatedNetwork(SR(), net)

evaluation_post_sampling!(SREval_sp,    ic_sp)
evaluation_post_sampling!(SREval_op,    ic_op)

@testset "LookUp table evaluation" begin
    @test ic_op.Evalues ≈ Clocs_ex
    @test ic_sp.Evalues ≈ Clocs_ex

    @test SREval_op.L ≈ SREval_sp.L
    @test ic_op.Evalues ≈ ic_sp.Evalues
    @test all([l≈r for (l,r)=zip(SREval_op.F, SREval_sp.F)])
    @test all([l≈r for (l,r)=zip(SREval_op.S, SREval_sp.S)])
end


text:
include("MolecularContainer.jl")
include("Atom.jl")
include("Molecule.jl")


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct DeploymentOperationProperties <: SwaggerModel
    provisioningState::Any # spec type: Union{ Nothing, String } # spec name: provisioningState
    timestamp::Any # spec type: Union{ Nothing, DateTime } # spec name: timestamp
    serviceRequestId::Any # spec type: Union{ Nothing, String } # spec name: serviceRequestId
    statusCode::Any # spec type: Union{ Nothing, String } # spec name: statusCode
    statusMessage::Any # spec type: Union{ Nothing, Any } # spec name: statusMessage
    targetResource::Any # spec type: Union{ Nothing, TargetResource } # spec name: targetResource
    request::Any # spec type: Union{ Nothing, HttpMessage } # spec name: request
    response::Any # spec type: Union{ Nothing, HttpMessage } # spec name: response

    function DeploymentOperationProperties(;provisioningState=nothing, timestamp=nothing, serviceRequestId=nothing, statusCode=nothing, statusMessage=nothing, targetResource=nothing, request=nothing, response=nothing)
        o = new()
        validate_property(DeploymentOperationProperties, Symbol("provisioningState"), provisioningState)
        setfield!(o, Symbol("provisioningState"), provisioningState)
        validate_property(DeploymentOperationProperties, Symbol("timestamp"), timestamp)
        setfield!(o, Symbol("timestamp"), timestamp)
        validate_property(DeploymentOperationProperties, Symbol("serviceRequestId"), serviceRequestId)
        setfield!(o, Symbol("serviceRequestId"), serviceRequestId)
        validate_property(DeploymentOperationProperties, Symbol("statusCode"), statusCode)
        setfield!(o, Symbol("statusCode"), statusCode)
        validate_property(DeploymentOperationProperties, Symbol("statusMessage"), statusMessage)
        setfield!(o, Symbol("statusMessage"), statusMessage)
        validate_property(DeploymentOperationProperties, Symbol("targetResource"), targetResource)
        setfield!(o, Symbol("targetResource"), targetResource)
        validate_property(DeploymentOperationProperties, Symbol("request"), request)
        setfield!(o, Symbol("request"), request)
        validate_property(DeploymentOperationProperties, Symbol("response"), response)
        setfield!(o, Symbol("response"), response)
        o
    end
end # type DeploymentOperationProperties

const _property_map_DeploymentOperationProperties = Dict{Symbol,Symbol}(Symbol("provisioningState")=>Symbol("provisioningState"), Symbol("timestamp")=>Symbol("timestamp"), Symbol("serviceRequestId")=>Symbol("serviceRequestId"), Symbol("statusCode")=>Symbol("statusCode"), Symbol("statusMessage")=>Symbol("statusMessage"), Symbol("targetResource")=>Symbol("targetResource"), Symbol("request")=>Symbol("request"), Symbol("response")=>Symbol("response"))
const _property_types_DeploymentOperationProperties = Dict{Symbol,String}(Symbol("provisioningState")=>"String", Symbol("timestamp")=>"DateTime", Symbol("serviceRequestId")=>"String", Symbol("statusCode")=>"String", Symbol("statusMessage")=>"Any", Symbol("targetResource")=>"TargetResource", Symbol("request")=>"HttpMessage", Symbol("response")=>"HttpMessage")
Base.propertynames(::Type{ DeploymentOperationProperties }) = collect(keys(_property_map_DeploymentOperationProperties))
Swagger.property_type(::Type{ DeploymentOperationProperties }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_DeploymentOperationProperties[name]))}
Swagger.field_name(::Type{ DeploymentOperationProperties }, property_name::Symbol) =  _property_map_DeploymentOperationProperties[property_name]

function check_required(o::DeploymentOperationProperties)
    true
end

function validate_property(::Type{ DeploymentOperationProperties }, name::Symbol, val)
end