text:
#################### Safe searches ####################

"""
    find_by_binary(tree::GeneralNode, bin::String)

Alias for `find_binary`.
"""
find_by_binary(tree::GeneralNode, bin::String) = find_binary(tree, bin)

"""
    find_by_name(tree::GeneralNode, name::AbstractString)

Alias for `find_name`.
"""
find_by_name(tree::GeneralNode, name::AbstractString) = find_name(tree, name)

"""
    find_by_num(tree::GeneralNode, num::Int64)

Alias for `find_num`.
"""
find_by_num(tree::GeneralNode, num::Int64) = find_num(tree, num)

#################### Unsafe searches ####################

"""
    find_num(root::T, num::Int64)  where T<:AbstractNode

Find a node by its number. The function assumes that the node is present in the
tree.

Do not use this function if you are unsure whether the node is in the tree at all.

Returns reference to Node.

* `root` : root Node of tree to be searched.

* `num` : number of desired Node.
"""
function find_num(root::T, num::I)::T  where {T<:AbstractNode, I<:Integer}
    store = T[]
    found = find_num(root, num, store)
    if length(store) == 0
        throw(ArgumentError("Node not found"))
    else
        return store[1]
    end
end

"""
    find_num(root::T, num::Int64, rn::Vector{T})::Bool  where T<:AbstractNode

Do a post order traversal to find the node corresponding to the `num`.

Returns true if node is found, false otherwise. Desired Node is pushed to rn.

* `root` : root Node of tree to be searched.

* `num` : number of desired Node.

* `rn` : Vector of Nodes; desired Node is pushed to this vector when found.
"""
function find_num(root::T, num::I, rn::Vector{T})::Bool  where {T<:AbstractNode, I<:Integer}
    # if the current node is the correct one store it in rn
    if root.num === num
        push!(rn, root)
        found = true
    else
        found = false
    end

    if !found
        # if the node is not yet found continue
        for child in root.children
            found = find_num(child, num,  rn)
            found && break
        end
    end # if
    return found
end

"""
    find_binary(root::T, bin::String)::T where T<:AbstractNode

Find a node by its binary representation. The function assumes that the node is
present in the tree.

Do not use this function if you are unsure whether the node is in the tree at all.

Returns a reference to the desired Node.

* `root` : root Node of tree to search.

* `bin` : binary representation of desired Node as a String.
"""
function find_binary(root::T, bin::String)::T where T<:AbstractNode
    rv = root
    for i in split(bin[1:end],",")[2:end]
        rv = rv.children[parse(Int64, i)+1]
    end
    rv
end

"""
    find_name(root::T, name::S)::T  where {T<:AbstractNode, S<:AbstractString}

Find a node by its name. Returns reference to Node.

* `root` : root Node of tree to be searched.

* `name` : name of desired Node.
"""
function find_name(root::T, name::S)::T  where {T<:AbstractNode, S<:AbstractString}
    store = T[]
    found = find_name(root, name, store)
    if length(store) == 0
        throw(ArgumentError("Node not found"))
    else
        return store[1]
    end
end

"""
    find_name(root::T, name::S, rn::Vector{T})::Bool where {T<:AbstractNode, S<:AbstractString}

Do a post order traversal to find the node corresponding to the `name`.

Returns true if node is found, false otherwise. Desired Node is pushed to rn.

* `root` : root Node of tree to be searched.

* `name` : name of desired Node.

* `rn` : Vector of Nodes; desired Node is pushed to this vector when found.
"""
function find_name(root::T, name::S, rn::Vector{T})::Bool where {T<:AbstractNode, S<:AbstractString}
    # if the current node is the correct one store it in rn
    if root.name === name
        push!(rn, root)
        found = true
    else
        found = false
    end

    if !found
        # if the node is not yet found continue
        for child in root.children
            found = find_name(child, name,  rn)
            found && break
        end
    end # if
    return found
end

"""
    find_root(node::T)::T where T <: GeneralNode

Finds the root of tree indicated by Node.

Returns reference to root Node of the tree.

* `node` : Node in Tree of interest.
"""
function find_root(node::T)::T where T <: GeneralNode
    while node.root == false
        node = get_mother(node)
    end # while
    return node
end


text:
using LinearAlgebra
using SparseArrays
import Distributions
using Statistics

export GainCache, GainPrior

abstract type RIMEModel <: AbstractModel end

basemodel(m::RIMEModel) = m.model
flux(m::RIMEModel) = flux(vismodel(m))
radialextent(m::RIMEModel) = radialextent(vismodel(m))

struct DesignMatrix{X,M<:AbstractMatrix{X},T,S} <: AbstractMatrix{X}
    matrix::M
    times::T
    stations::S
end

Base.getindex(m::DesignMatrix, i::Int) = getindex(m.matrix, i)
Base.size(m::DesignMatrix) = size(m.matrix)
Base.IndexStyle(::Type{<:DesignMatrix{X,M}}) where {X,M} = Base.IndexStyle(M)
Base.getindex(m::DesignMatrix, I::Vararg{Int,N}) where {N} = getindex(m.matrix, I)
Base.setindex!(m::DesignMatrix, v, i::Int) = setindex!(m.matrix, v, i)
Base.setindex!(m::DesignMatrix, v, i::Vararg{Int, N}) where {N} = setindex!(m.matrix, v, i)

Base.similar(m::DesignMatrix, ::Type{S}, dims::Dims) where {S} = DesignMatrix(similar(m.matrix, S, dims), m.times, m.stations)

function LinearAlgebra.mul!(y::AbstractArray, M::DesignMatrix, x::AbstractArray)
    LinearAlgebra.mul!(y, M.matrix, x)
end

struct GainPrior{S,T,G} <: Distributions.ContinuousMultivariateDistribution
    stations::S
    times::T
    dist::G
end

function GainPrior(dists, st::ScanTable)
    @argcheck Set(keys(dists)) == Set(stations(st))

    gtimes, gstat = gain_stations(st)

    gprior = Dists.product_distribution([getproperty(dists, g) for g in gstat])
    return GainPrior(gstat, gtimes, gprior)
end

HypercubeTransform.bijector(d::GainPrior) = HypercubeTransform.bijector(d.dist)
HypercubeTransform.asflat(d::GainPrior) = asflat(d.dist)
HypercubeTransform.ascube(d::GainPrior) = ascube(d.dist)

Distributions.sampler(d::GainPrior) = Distributions.sampler(d.dist)
Base.length(d::GainPrior) = length(d.dist)
Base.eltype(d::GainPrior) = eltype(d.dist)
function Distributions._rand!(rng::AbstractRNG, d::GainPrior, x::AbstractVector)
    Distributions._rand!(rng, d.dist, x)
end

function Distributions._logpdf(d::GainPrior, x::AbstractArray)
    return Distributions._logpdf(d.dist, x)
end

Statistics.mean(d::GainPrior) = mean(d.dist)
Statistics.var(d::GainPrior) = var(d.dist)
Distributions.entropy(d::GainPrior) = entropy(d.dist)
Statistics.cov(d::GainPrior) = cov(d.dist)

struct GainCache{D1<:DesignMatrix, D2<:DesignMatrix, T, S}
    m1::D1
    m2::D2
    times::T
    stations::S
end

function GainCache(st::ScanTable)
    gtime, gstat = gain_stations(st)
    m1, m2 = gain_design(st)
    return GainCache(m1, m2, gtime, gstat)
end

"""
    `GainModel`
Construct the corruption model for the telescope gains
"""
struct GainModel{C, G, M} <: RIMEModel
    cache::C
    gains::G
    model::M
end

function intensitymap!(img::IntensityMap, model::GainModel, args...)
    return intensitymap!(img, model.model, args...)
end

function visibilities(model::GainModel, u::AbstractArray, v::AbstractArray)
    vis = visibilities(model.model, u, v)
    return corrupt(vis, model.cache, model.gains)
end

function amplitudes(model::GainModel, u::AbstractArray, v::AbstractArray)
    amp = amplitudes(model.model, u, v)
    return abs.(corrupt(amp, model.cache, model.gains))
end

function closure_phases(model::GainModel, args::Vararg{<:AbstractArray, N}) where {N}
    return closure_phases(model.model, args...)
end

function logclosure_amplitudes(model::GainModel, args::Vararg{<:AbstractArray, N}) where {N}
    return logclosure_amplitudes(model.model, args...)
end

function corrupt(vis::AbstractArray, g::GainCache, gains::AbstractArray)
    g1 = g.m1*gains
    g2 = g.m2*gains
    return @. g1*vis*conj(g2)
end

function gain_stations(st::ScanTable)
    gainstat = Symbol[]
    times = eltype(st.times)[]
    for i in 1:length(st)
        s = stations(st[i])
        append!(gainstat, s)
        append!(times, fill(st[i].time, length(s)))
    end
    return times, gainstat
end

function gain_design(st::ScanTable)

    # Construct the indices that will tag where gains are
    rowInd1 = Int[]
    colInd1 = Int[]
    rowInd2 = Int[]
    colInd2 = Int[]
    times = st.obs[:time]
    bl = st.obs[:baseline]
    gaintime, gainstat = gain_stations(st)
    gts = collect(zip(gaintime, gainstat))
    for i in 1:length(times)
        t = times[i]
        s1, s2 = bl[i]
        # now get the columns that corresponds to the gain
        c1 = findall(x->((x[1]==t)&&(x[2]==s1)), gts)
        c2 = findall(x->((x[1]==t)&&(x[2]==s2)), gts)
        append!(colInd1, c1)
        append!(rowInd1, fill(i, length(c1)))
        append!(colInd2, c2)
        append!(rowInd2, fill(i, length(c2)))
    end
    z = fill(1, length(rowInd1))
    m1 = sparse(rowInd1, colInd1, z, length(times), length(gaintime))
    m2 = sparse(rowInd2, colInd2, z, length(times), length(gaintime))
    return DesignMatrix(m1, gaintime, gainstat), DesignMatrix(m2, gaintime, gainstat)
end

ext: jl


text:
function _FDEsolver(pos_args, opt_args, JF::Function, par...)

    # extract arguments from pos_args and opt_args structure fields
    β = pos_args.β

    # check compatibility size of the problem with number of fractional orders
    β_length = length(pos_args.β)
    problem_size = size(pos_args.y0, 1)

    if β_length > 1

        # println("Oh! Good! ODE system!")

    else

        β = pos_args.β * ones(problem_size, 1)
        β_length = problem_size

    end

    # Storage of initial conditions
    ic = initial_conditions(pos_args.tSpan[1], pos_args.y0, Int64.(map(ceil, β)), zeros(β_length, Int64.(ceil(maximum(β)))))

    for i in 1:β_length

        for j in 0:ic.m_β[i] - 1

            ic.m_β_factorial[i, j + 1] = factorial(j)

        end

    end

    # Storage of information on the problem
    Probl = JProblem(ic, pos_args.F, problem_size, par, β, β_length, JF)

    # Time discretization
    N = Int64.(cld(pos_args.tSpan[2] - pos_args.tSpan[1], opt_args.h))
    t = pos_args.tSpan[1] .+ collect(0:N) .* opt_args.h

    # Check compatibility size of the problem with size of the vector field
    f_temp = f_value(pos_args.F(t[1], pos_args.y0[:, 1], par...), Probl.problem_size)

    # Number of points in which to evaluate weights and solution
    r = 16
    Nr::Int64 = ceil((N + 1) / r) * r
    Qr::Int64 = ceil(log2(Nr / r)) - 1
    NNr::Int64 = 2^(Qr + 1) * r

    # Preallocation of some variables
    y = zeros(Probl.problem_size, N + 1)
    fy = zeros(Probl.problem_size, N + 1)
    zn = zeros(Probl.problem_size, NNr + 1)

    # Evaluation of coefficients of the PECE method
    nvett = 0:NNr + 1
    an = zeros(Probl.β_length, NNr + 1)
    a0 = zeros(Probl.β_length, NNr + 1)

    for i_β in 1:Probl.β_length

        find_β = findall(β[i_β] == β[1:i_β - 1])

        if !isempty(find_β) # it is for speeding up the computations; we can use multilpe distpach

            an[i_β, :] = an[find_β[1], :]
            a0[i_β, :] = a0[find_β[1], :]

        else

            nβ = nvett .^ β[i_β]
            nβ1 = nβ .* nvett
            an[i_β,:] = [ 1; (nβ1[1:end - 2] - 2 * nβ1[2:end - 1] + nβ1[3:end])]
            a0[i_β, :] = [0; (nβ1[1:end - 2] - nβ[2:end - 1] .* (nvett[2:end - 1] .- β[i_β] .- 1))]

        end

    end

    METH = JMethod(an, a0, opt_args.h .^ β ./ Γ(β .+ 1), opt_args.h .^ β ./ Γ(β .+ 2), opt_args.nc, opt_args.tol, r, opt_args.StopIt, opt_args.itmax)

    # Evaluation of FFT of coefficients of the PECE method
    if Qr >= 0

        index_fft = Int64.(zeros(2, Qr + 1)) # I have tried index_fft::Int64 = zeros(2,Qr+1) and I got an error for converting Type!

        for l in 1:Qr + 1

            if l == 1

                index_fft[1, l] = 1
                index_fft[2, l] = r * 2

            else

                index_fft[1, l] = index_fft[2, l - 1] + 1
                index_fft[2, l] = index_fft[2, l - 1] + 2^l * r

            end

        end

        an_fft =ComplexF64.(zeros(Probl.β_length, index_fft[2, Qr + 1]))

        for l in 1:Qr + 1

            coef_end = 2^l * r

            for i_β in 1:Probl.β_length

                find_β = findall(β[i_β] == β[1:i_β - 1])

                if !isempty(find_β)

                    an_fft[i_β, index_fft[1, l]:index_fft[2, l]] = an_fft[find_β[1], index_fft[1, l]:index_fft[2, l]]

                else

                    an_fft[i_β, index_fft[1, l]:index_fft[2, l]] = fft(METH.an[i_β, 1:coef_end])

                end

            end

        end

        METH_fft = JMethod_fft(an_fft, Int64.(index_fft))

    end

    # Initializing solution and proces of computation
    y[:, 1] = pos_args.y0[:, 1]
    fy[:, 1] = f_temp
    y, fy = JTriangolo(1, r - 1, t, y, fy, zn, N, METH, Probl)

    # Main process of computation by means of the FFT algorithm
    ff = zeros(1, 2^(Qr + 2))
    ff[1:2] = [0, 2]
    card_ff = 2

    nx0 = 0
    ny0 = 0

    for qr in 0:Qr

        L = 2^qr
        y, fy = JDisegnaBlocchi(L, ff, r, Nr, nx0 + L * r, ny0, t, y, fy, zn, N, METH, METH_fft, Probl)
        ff[1:2 * card_ff] = [ff[1:card_ff]; ff[1:card_ff]]
        card_ff = 2 * card_ff
        ff[card_ff] = 4 * L

    end

    # Evaluation solution in T when T is not in the mesh
    if pos_args.tSpan[2] < t[N + 1]

        c = [pos_args.tSpan[2] - t(N)] / opt_args.h
        t[N + 1] = pos_args.tSpan[2]
        y[:, N + 1] = (1 - c) * y[:, N] + c * y[:, N + 1]

    end

    t = t[1:N + 1]
    y = y[:, 1:N + 1]'

    return t, y

end


text:
## File containing different utility functions ##

## Jittering object adapting to the type of the GP ##
struct Jittering end;

const jitt = Jittering()

@inline Base.Float64(::Jittering) = Float64(1e-4)
@inline Base.Float32(::Jittering) = Float32(1e-3)
@inline Base.Float16(::Jittering) = Float16(1e-2)
@inline Base.convert(::Type{Float64}, ::Jittering) = Float64(1e-4)
@inline Base.convert(::Type{Float32}, ::Jittering) = Float32(1e-3)
@inline Base.convert(::Type{Float16}, ::Jittering) = Float16(1e-2)

# Compute expectation given the nodes
function expectation(f, μ::Real, σ²::Real)
    x = pred_nodes * sqrt(max(σ², zero(σ²))) .+ μ
    return dot(pred_weights, f.(x))
end

## delta function `(i,j)`, equal `1` if `i == j`, `0` else ##
@inline function δ(T, i::Integer, j::Integer)
    return ifelse(i == j, one(T), zero(T))
end
δ(i::Integer, j::Integer) = δ(Float64, i, j)

## Hadamard product between two arrays of same size ##
@inline function hadamard(A::AbstractArray{<:Real}, B::AbstractArray{<:Real})
    return A .* B
end

## Add on place the transpose of aZero Mean Prior matrix ##
@inline function add_transpose!(A::AbstractMatrix{<:Real})
    return A .+= A'
end

invquad(a::Cholesky, x::AbstractVector) = sum(abs2, a.L \ x)

## Return the trace of A*B' ##
@inline function trace_ABt(A::AbstractMatrix{<:Real}, B::AbstractMatrix{<:Real})
    return dot(A, B)
end

## Return the diagonal of A*B' ##
@inline function diag_ABt(A::AbstractMatrix, B::AbstractMatrix)
    return vec(sum(A .* B; dims=2))
end

## Return the multiplication of Diagonal(v)*B ##
function diagv_B(v::AbstractVector, B::AbstractMatrix)
    return v .* B
end

## Return the multiplication of κᵀ*Diagonal(θ)*κ
@inline function κdiagθκ(κ::AbstractMatrix{T}, θ::AbstractVector{T}) where {T<:Real}
    return transpose(θ .* κ) * κ
end

## Return the multiplication of ρ*κᵀ*Diagonal(θ)*κ
@inline function ρκdiagθκ(ρ::T, κ::AbstractMatrix{T}, θ::AbstractVector{T}) where {T<:Real}
    return transpose((ρ * θ) .* κ) * κ
end

## Return the addition of a diagonal to a symmetric matrix ##
function opt_add_diag_mat(v::AbstractVector{T}, B::AbstractMatrix{T}) where {T<:Real}
    A = copy(B)
    @inbounds for i in 1:size(A, 1)
        A[i, i] += v[i]
    end
    return A
end

## Compute exp(μ)/cosh(c) safely if there is an overflow ##
function safe_expcosh(μ::Real, c::Real)
    return isfinite(exp(μ) / cosh(c)) ? exp(μ) / cosh(c) : 2 * logistic(2.0 * max(μ, c))
end

## Return a safe version of log(cosh(c)) ##
function logcosh(c::Real)
    return log(exp(-2.0 * c) + 1.0) + c - logtwo
end

function symcat(S::Symmetric, v::AbstractVector, vv::Real)
    S = vcat(S, v')
    S = hcat(S, vcat(v, vv))
    return Symmetric(S)
end

export make_grid
function make_grid(range1, range2)
    return hcat([i for i in range1, j in range2][:], [j for i in range1, j in range2][:])
end

Base.:*(x::Real, C::Cholesky) = Cholesky(sqrt(x) * C.factors, C.uplo, C.info)

Base.:*(C::Cholesky, x::AbstractVecOrMat) = C.L * (transpose(C.L) * x)

Base.:+(C::Cholesky, x::UniformScaling) = cholesky(Symmetric(Array(C) + x))


text:
function solve(case, N, X, A)
    AA = Channel{Tuple{Int,Int}}(N)
    foreach(x -> put!(AA, x), enumerate(A[]))
    dequeued = []
    while !isempty(AA)
        (i, person) = take!(AA)
        person -= X
        if person <= 0
            push!(dequeued, i)
        else
            put!(AA, (i, person))
        end
    end

    println("Case #$case: $(join(dequeued, " "))")
end

function main()
    T = parse(Int, readline(stdin))

    for case in 1:T
        N, X = parse.(Int, stdin |> readline |> split)
        A = parse.(Int, stdin |> readline |> split)
        solve(case, N, X, Ref(A))
    end
end

isinteractive() || main()

max_stars_repo_name: AnAverageHuman/competitive

max_issues_repo_name: AnAverageHuman/competitive

max_forks_repo_name: AnAverageHuman/competitive


text:
using CQL
using Base.Test

include("examples.jl")
# write your own tests here
@test cqltest01()
@test cqltest02()
@test cqltest03()


text:
##############################################################################
##
## We use SubDataTable's to maintain a reference to a subset of a DataTable
## without making copies.
##
##############################################################################

if VERSION >= v"0.6.0-dev.2643"
    include_string("""
        immutable SubDataTable{T <: AbstractVector{Int}} <: AbstractDataTable
            parent::DataTable
            rows::T # maps from subdt row indexes to parent row indexes

            function SubDataTable{T}(parent::DataTable, rows::T) where {T <: AbstractVector{Int}}
                if length(rows) > 0
                    rmin, rmax = extrema(rows)
                    if rmin < 1 || rmax > size(parent, 1)
                        throw(BoundsError())
                    end
                end
                new(parent, rows)
            end
        end
    """)
else
    @eval begin
        immutable SubDataTable{T <: AbstractVector{Int}} <: AbstractDataTable
            parent::DataTable
            rows::T # maps from subdt row indexes to parent row indexes

            function SubDataTable(parent::DataTable, rows::T)
                if length(rows) > 0
                    rmin, rmax = extrema(rows)
                    if rmin < 1 || rmax > size(parent, 1)
                        throw(BoundsError())
                    end
                end
                new(parent, rows)
            end
        end
    end
end

"""
A view of row subsets of an AbstractDataTable

A `SubDataTable` is meant to be constructed with `view`.  A
SubDataTable is used frequently in split/apply sorts of operations.

```julia
view(d::AbstractDataTable, rows)
```

### Arguments

* `d` : an AbstractDataTable
* `rows` : any indexing type for rows, typically an Int,
  AbstractVector{Int}, AbstractVector{Bool}, or a Range

### Notes

A `SubDataTable` is an AbstractDataTable, so expect that most
DataTable functions should work. Such methods include `describe`,
`dump`, `nrow`, `size`, `by`, `stack`, and `join`. Indexing is just
like a DataTable; copies are returned.

To subset along columns, use standard column indexing as that creates
a view to the columns by default. To subset along rows and columns,
use column-based indexing with `view`.

### Examples

```julia
dt = DataTable(a = repeat([1, 2, 3, 4], outer=[2]),
               b = repeat([2, 1], outer=[4]),
               c = randn(8))
sdt1 = view(dt, 1:6)
sdt2 = view(dt, dt[:a] .> 1)
sdt3 = view(dt[[1,3]], dt[:a] .> 1)  # row and column subsetting
sdt4 = groupby(dt, :a)[1]  # indexing a GroupedDataTable returns a SubDataTable
sdt5 = view(sdt1, 1:3)
sdt1[:,[:a,:b]]
```

"""
SubDataTable

function SubDataTable{T <: AbstractVector{Int}}(parent::DataTable, rows::T)
    return SubDataTable{T}(parent, rows)
end

function SubDataTable(parent::DataTable, row::Integer)
    return SubDataTable(parent, [Int(row)])
end

function SubDataTable{S <: Integer}(parent::DataTable, rows::AbstractVector{S})
    return SubDataTable(parent, convert(Vector{Int}, rows))
end

function SubDataTable(parent::DataTable, rows::AbstractVector{Bool})
    return SubDataTable(parent, find(rows))
end

function SubDataTable{T<:Integer}(sdt::SubDataTable, rowinds::Union{T, AbstractVector{T}})
    return SubDataTable(sdt.parent, sdt.rows[rowinds])
end

function Base.view{T<:Nullable}(adt::AbstractDataTable, rowinds::AbstractVector{T})
    # Vector{<:Nullable} need to be checked for nulls and the values lifted
    any(isnull, rowinds) && throw(NullException())
    return SubDataTable(adt, get.(rowinds))
end

function Base.view(adt::AbstractDataTable, rowinds::NullableVector)
    # convert for NullableVectors will throw NullException if nulls present
    return SubDataTable(adt, convert(Vector, rowinds))
end

function Base.view(adt::AbstractDataTable, rowinds::Any)
    return SubDataTable(adt, rowinds)
end

function Base.view(adt::AbstractDataTable, rowinds::Any, colinds::AbstractVector)
    return SubDataTable(adt[colinds], rowinds)
end

function Base.view(adt::AbstractDataTable, rowinds::Any, colinds::Any)
    return SubDataTable(adt[[colinds]], rowinds)
end

##############################################################################
##
## AbstractDataTable interface
##
##############################################################################

index(sdt::SubDataTable) = index(sdt.parent)

# TODO: Remove these
nrow(sdt::SubDataTable) = ncol(sdt) > 0 ? length(sdt.rows)::Int : 0
ncol(sdt::SubDataTable) = length(index(sdt))

function Base.getindex(sdt::SubDataTable, colinds::Any)
    return sdt.parent[sdt.rows, colinds]
end

function Base.getindex(sdt::SubDataTable, rowinds::Any, colinds::Any)
    return sdt.parent[sdt.rows[rowinds], colinds]
end

function Base.setindex!(sdt::SubDataTable, val::Any, colinds::Any)
    sdt.parent[sdt.rows, colinds] = val
    return sdt
end

function Base.setindex!(sdt::SubDataTable, val::Any, rowinds::Any, colinds::Any)
    sdt.parent[sdt.rows[rowinds], colinds] = val
    return sdt
end

##############################################################################
##
## Miscellaneous
##
##############################################################################

Base.map(f::Function, sdt::SubDataTable) = f(sdt) # TODO: deprecate

without(sdt::SubDataTable, c) = view(without(sdt.parent, c), sdt.rows)


text:
using DifferentialEquations
using LinearAlgebra
using Plots

struct Wave
    f
    g
    c
end

# Exercise

# Visualization

function plot_wave(y, file_name; fps = 60, kwargs...)
    anim = @animate for (i, y_row) in enumerate(eachrow(y))
        plot(
            y_row;
            title = "t = $(i-1)Δt",
            xlabel = "x",
            ylabel = "y(t, x)",
            legend = false,
            linewidth = 2,
            kwargs...
        )
    end
    gif(anim, file_name; fps, show_msg = false)

    return nothing
end

# Exercise

# DiferentialEquations

f(u,p,t) = 0.98*u

u0 = 1.0
tspan = (0.0, 1.0)

prob = ODEProblem(f, u0, tspan)

sol = solve(prob)

plot(sol; label="")

sol(0.8)

# Exercise

# Lorenz system

function lorenz(u, p, t)
    σ, ρ, β = p
    x_t = σ*(u[2]-u[1])
    y_t = u[1]*(ρ-u[3]) - u[2]
    z_t = u[1]*u[2] - β*u[3]
    return [x_t; y_t; z_t]
end

u0 = [1.0; 0.0; 0.0]
p = [10; 28; 8/3]

tspan = (0.0, 100.0)
prob = ODEProblem(lorenz, u0, tspan, p)

sol = solve(prob)

plot(sol)

plt1 = plot(sol, vars=(1,2,3), label="")

plot(sol, vars=(1,2,3), denseplot=false; label="")

traj = hcat(sol.u...)
plot(traj[1,:], traj[2,:], traj[3,:]; label="")

# Exercise

# Solution comparison

hcat(sol(tspan[2]), sol0(tspan[2]))

# Bisection setup

function bisection(f, a, b; tol=1e-6)
    fa = f(a)
    fb = f(b)
    fa == 0 && return a
    fb == 0 && return b
    fa*fb > 0 && error("Wrong initial values for bisection")
    while b-a > tol
        c = (a+b)/2
        fc = f(c)
        fc == 0 && return c
        if fa*fc > 0
            a = c
            fa = fc
        else
            b = c
            fb = fc
        end
    end
    return (a+b)/2
end

# PMSM structure

struct PMSM{T<:Real}
    ρ::T
    ω::T
    A::Matrix{T}
    invA::Matrix{T}

    function PMSM(ρ, ω)
        A = -ρ*[1 0; 0 1] -ω*[0 -1; 1 0]
        return new{eltype(A)}(ρ, ω, A, inv(A))
    end
end

function expA(p::PMSM, t)
    ρ, ω = p.ρ, p.ω
    return exp(-ρ*t)*[cos(ω*t) sin(ω*t); -sin(ω*t) cos(ω*t)]
end

ρ = 0.1
ω = 2
x0 = [0;-0.5]
q = [1;0]

ps = PMSM(ρ, ω)

# Exercise

# Exercise

# Plotting trajectory

ts = 0:0.0001:10

xs1 = trajectory_fin_diff(ps, x0, ts, q)
xs2 = trajectory_exact(ps, x0, ts, q)

plot(xs1[1,:], xs1[2,:], label="Finite differences")
plot!(xs2[1,:], xs2[2,:], label="True value")

# Exercise

# Plotting trajectory

function trajectory_control(p::PMSM, x0, ts, q, U_max, p0)
    xs = zeros(length(x0), length(ts))

    for (i, t) in enumerate(ts)
        eAt  = expA(p, t)
        emAt = expA(p, -t)
        xs[:, i] = eAt*(x0 + p.invA * (I - emAt)*q + U_max/ρ*(exp(ρ*t) - 1)*p0)
    end
    return xs
end

p0 = ps.ρ/(U_max*(exp(ps.ρ*τ)-1))*(expA(ps, -τ)*x_t - x0 - ps.invA*(I-expA(ps, -τ))*q)
p0 /= norm(p0)

ts = range(0, τ; length=100)

traj = trajectory_control(ps, x0, ts, q, U_max, p0)

plot(traj[1,:], traj[2,:], label="Optimal trajectory")
scatter!([x0[1]], [x0[2]], label="Starting point")
scatter!([x_t[1]], [x_t[2]], label="Target point")

# BONUS

ts = 0:0.01:10

plt = plot()
for α = 0:π/4:2*π
    trj = trajectory_control(ps, x0, ts, q, U_max, [sin(α); cos(α)])
    plot!(plt, trj[1,:], trj[2,:], label="")
end
display(plt)

max_stars_repo_name: petrmvala/JuliaCourse

max_issues_repo_name: petrmvala/JuliaCourse

max_forks_repo_name: petrmvala/JuliaCourse


text:
# Julia wrapper for header: /usr/local/include/arrayfire.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function af_sum(out,_in,dim)
    checkerror(ccall((:af_sum,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_sum_nan(out,_in,dim,nanval)
    checkerror(ccall((:af_sum_nan,libaf),af_err,(Ptr{af_array},af_array,Cint,Cdouble),out,_in,dim,nanval))
end

function af_product(out,_in,dim)
    checkerror(ccall((:af_product,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_product_nan(out,_in,dim,nanval)
    checkerror(ccall((:af_product_nan,libaf),af_err,(Ptr{af_array},af_array,Cint,Cdouble),out,_in,dim,nanval))
end

function af_min(out,_in,dim)
    checkerror(ccall((:af_min,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_max(out,_in,dim)
    checkerror(ccall((:af_max,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_all_true(out,_in,dim)
    checkerror(ccall((:af_all_true,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_any_true(out,_in,dim)
    checkerror(ccall((:af_any_true,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_count(out,_in,dim)
    checkerror(ccall((:af_count,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_sum_all(real,imag,_in)
    checkerror(ccall((:af_sum_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_sum_nan_all(real,imag,_in,nanval)
    checkerror(ccall((:af_sum_nan_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,Cdouble),real,imag,_in,nanval))
end

function af_product_all(real,imag,_in)
    checkerror(ccall((:af_product_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_product_nan_all(real,imag,_in,nanval)
    checkerror(ccall((:af_product_nan_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,Cdouble),real,imag,_in,nanval))
end

function af_min_all(real,imag,_in)
    checkerror(ccall((:af_min_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_max_all(real,imag,_in)
    checkerror(ccall((:af_max_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_all_true_all(real,imag,_in)
    checkerror(ccall((:af_all_true_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_any_true_all(real,imag,_in)
    checkerror(ccall((:af_any_true_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_count_all(real,imag,_in)
    checkerror(ccall((:af_count_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_imin(out,idx,_in,dim)
    checkerror(ccall((:af_imin,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,Cint),out,idx,_in,dim))
end

function af_imax(out,idx,_in,dim)
    checkerror(ccall((:af_imax,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,Cint),out,idx,_in,dim))
end

function af_imin_all(real,imag,idx,_in)
    checkerror(ccall((:af_imin_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},Ptr{UInt32},af_array),real,imag,idx,_in))
end

function af_imax_all(real,imag,idx,_in)
    checkerror(ccall((:af_imax_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},Ptr{UInt32},af_array),real,imag,idx,_in))
end

function af_accum(out,_in,dim)
    checkerror(ccall((:af_accum,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_where(idx,_in)
    checkerror(ccall((:af_where,libaf),af_err,(Ptr{af_array},af_array),idx,_in))
end

function af_diff1(out,_in,dim)
    checkerror(ccall((:af_diff1,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_diff2(out,_in,dim)
    checkerror(ccall((:af_diff2,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,dim))
end

function af_sort(out,_in,dim,isAscending)
    checkerror(ccall((:af_sort,libaf),af_err,(Ptr{af_array},af_array,UInt32,Bool),out,_in,dim,isAscending))
end

function af_sort_index(out,indices,_in,dim,isAscending)
    checkerror(ccall((:af_sort_index,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,UInt32,Bool),out,indices,_in,dim,isAscending))
end

function af_sort_by_key(out_keys,out_values,keys,values,dim,isAscending)
    checkerror(ccall((:af_sort_by_key,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,af_array,UInt32,Bool),out_keys,out_values,keys,values,dim,isAscending))
end

function af_set_unique(out,_in,is_sorted)
    checkerror(ccall((:af_set_unique,libaf),af_err,(Ptr{af_array},af_array,Bool),out,_in,is_sorted))
end

function af_set_union(out,first,second,is_unique)
    checkerror(ccall((:af_set_union,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,first,second,is_unique))
end

function af_set_intersect(out,first,second,is_unique)
    checkerror(ccall((:af_set_intersect,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,first,second,is_unique))
end

function af_add(out,lhs,rhs,batch)
    checkerror(ccall((:af_add,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_sub(out,lhs,rhs,batch)
    checkerror(ccall((:af_sub,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_mul(out,lhs,rhs,batch)
    checkerror(ccall((:af_mul,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_div(out,lhs,rhs,batch)
    checkerror(ccall((:af_div,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_lt(out,lhs,rhs,batch)
    checkerror(ccall((:af_lt,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_gt(out,lhs,rhs,batch)
    checkerror(ccall((:af_gt,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_le(out,lhs,rhs,batch)
    checkerror(ccall((:af_le,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_ge(out,lhs,rhs,batch)
    checkerror(ccall((:af_ge,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_eq(out,lhs,rhs,batch)
    checkerror(ccall((:af_eq,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_neq(out,lhs,rhs,batch)
    checkerror(ccall((:af_neq,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_and(out,lhs,rhs,batch)
    checkerror(ccall((:af_and,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_or(out,lhs,rhs,batch)
    checkerror(ccall((:af_or,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_not(out,_in)
    checkerror(ccall((:af_not,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_bitand(out,lhs,rhs,batch)
    checkerror(ccall((:af_bitand,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_bitor(out,lhs,rhs,batch)
    checkerror(ccall((:af_bitor,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_bitxor(out,lhs,rhs,batch)
    checkerror(ccall((:af_bitxor,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_bitshiftl(out,lhs,rhs,batch)
    checkerror(ccall((:af_bitshiftl,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_bitshiftr(out,lhs,rhs,batch)
    checkerror(ccall((:af_bitshiftr,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_cast(out,_in,_type)
    checkerror(ccall((:af_cast,libaf),af_err,(Ptr{af_array},af_array,af_dtype),out,_in,_type))
end

function af_minof(out,lhs,rhs,batch)
    checkerror(ccall((:af_minof,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_maxof(out,lhs,rhs,batch)
    checkerror(ccall((:af_maxof,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_rem(out,lhs,rhs,batch)
    checkerror(ccall((:af_rem,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_mod(out,lhs,rhs,batch)
    checkerror(ccall((:af_mod,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_abs(out,_in)
    checkerror(ccall((:af_abs,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_arg(out,_in)
    checkerror(ccall((:af_arg,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_sign(out,_in)
    checkerror(ccall((:af_sign,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_round(out,_in)
    checkerror(ccall((:af_round,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_trunc(out,_in)
    checkerror(ccall((:af_trunc,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_floor(out,_in)
    checkerror(ccall((:af_floor,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_ceil(out,_in)
    checkerror(ccall((:af_ceil,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_hypot(out,lhs,rhs,batch)
    checkerror(ccall((:af_hypot,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_sin(out,_in)
    checkerror(ccall((:af_sin,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_cos(out,_in)
    checkerror(ccall((:af_cos,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_tan(out,_in)
    checkerror(ccall((:af_tan,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_asin(out,_in)
    checkerror(ccall((:af_asin,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_acos(out,_in)
    checkerror(ccall((:af_acos,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_atan(out,_in)
    checkerror(ccall((:af_atan,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_atan2(out,lhs,rhs,batch)
    checkerror(ccall((:af_atan2,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_cplx2(out,lhs,rhs,batch)
    checkerror(ccall((:af_cplx2,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_cplx(out,_in)
    checkerror(ccall((:af_cplx,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_real(out,_in)
    checkerror(ccall((:af_real,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_imag(out,_in)
    checkerror(ccall((:af_imag,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_conjg(out,_in)
    checkerror(ccall((:af_conjg,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_sinh(out,_in)
    checkerror(ccall((:af_sinh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_cosh(out,_in)
    checkerror(ccall((:af_cosh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_tanh(out,_in)
    checkerror(ccall((:af_tanh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_asinh(out,_in)
    checkerror(ccall((:af_asinh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_acosh(out,_in)
    checkerror(ccall((:af_acosh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_atanh(out,_in)
    checkerror(ccall((:af_atanh,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_root(out,lhs,rhs,batch)
    checkerror(ccall((:af_root,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_pow(out,lhs,rhs,batch)
    checkerror(ccall((:af_pow,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,lhs,rhs,batch))
end

function af_pow2(out,_in)
    checkerror(ccall((:af_pow2,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_exp(out,_in)
    checkerror(ccall((:af_exp,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_sigmoid(out,_in)
    checkerror(ccall((:af_sigmoid,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_expm1(out,_in)
    checkerror(ccall((:af_expm1,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_erf(out,_in)
    checkerror(ccall((:af_erf,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_erfc(out,_in)
    checkerror(ccall((:af_erfc,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_log(out,_in)
    checkerror(ccall((:af_log,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_log1p(out,_in)
    checkerror(ccall((:af_log1p,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_log10(out,_in)
    checkerror(ccall((:af_log10,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_log2(out,_in)
    checkerror(ccall((:af_log2,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_sqrt(out,_in)
    checkerror(ccall((:af_sqrt,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_cbrt(out,_in)
    checkerror(ccall((:af_cbrt,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_factorial(out,_in)
    checkerror(ccall((:af_factorial,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_tgamma(out,_in)
    checkerror(ccall((:af_tgamma,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_lgamma(out,_in)
    checkerror(ccall((:af_lgamma,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_iszero(out,_in)
    checkerror(ccall((:af_iszero,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_isinf(out,_in)
    checkerror(ccall((:af_isinf,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_isnan(out,_in)
    checkerror(ccall((:af_isnan,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_make_seq(_begin,_end,step)
    ccall((:af_make_seq,libaf),af_seq,(Cdouble,Cdouble,Cdouble),_begin,_end,step)
end

function af_print_array(arr)
    checkerror(ccall((:af_print_array,libaf),af_err,(af_array,),arr))
end

function af_print_array_gen(exp,arr,precision)
    checkerror(ccall((:af_print_array_gen,libaf),af_err,(Ptr{UInt8},af_array,Cint),exp,arr,precision))
end

function af_save_array(index,key,arr,filename,append)
    checkerror(ccall((:af_save_array,libaf),af_err,(Ptr{Cint},Ptr{UInt8},af_array,Ptr{UInt8},Bool),index,key,arr,filename,append))
end

function af_read_array_index(out,filename,index)
    checkerror(ccall((:af_read_array_index,libaf),af_err,(Ptr{af_array},Ptr{UInt8},UInt32),out,filename,index))
end

function af_read_array_key(out,filename,key)
    checkerror(ccall((:af_read_array_key,libaf),af_err,(Ptr{af_array},Ptr{UInt8},Ptr{UInt8}),out,filename,key))
end

function af_read_array_key_check(index,filename,key)
    checkerror(ccall((:af_read_array_key_check,libaf),af_err,(Ptr{Cint},Ptr{UInt8},Ptr{UInt8}),index,filename,key))
end

function af_array_to_string(output,exp,arr,precision,transpose)
    checkerror(ccall((:af_array_to_string,libaf),af_err,(Ptr{Ptr{UInt8}},Ptr{UInt8},af_array,Cint,Bool),output,exp,arr,precision,transpose))
end

function af_example_function(out,_in,param)
    checkerror(ccall((:af_example_function,libaf),af_err,(Ptr{af_array},af_array,af_someenum_t),out,_in,param))
end

function af_get_version(major,minor,patch)
    checkerror(ccall((:af_get_version,libaf),af_err,(Ptr{Cint},Ptr{Cint},Ptr{Cint}),major,minor,patch))
end

function af_index(out,_in,ndims,index)
    checkerror(ccall((:af_index,libaf),af_err,(Ptr{af_array},af_array,UInt32,Ptr{af_seq}),out,_in,ndims,index))
end

function af_lookup(out,_in,indices,dim)
    checkerror(ccall((:af_lookup,libaf),af_err,(Ptr{af_array},af_array,af_array,UInt32),out,_in,indices,dim))
end

function af_assign_seq(out,lhs,ndims,indices,rhs)
    checkerror(ccall((:af_assign_seq,libaf),af_err,(Ptr{af_array},af_array,UInt32,Ptr{af_seq},af_array),out,lhs,ndims,indices,rhs))
end

function af_index_gen(out,_in,ndims,indices)
    checkerror(ccall((:af_index_gen,libaf),af_err,(Ptr{af_array},af_array,dim_t,Ptr{af_index_t}),out,_in,ndims,indices))
end

function af_assign_gen(out,lhs,ndims,indices,rhs)
    checkerror(ccall((:af_assign_gen,libaf),af_err,(Ptr{af_array},af_array,dim_t,Ptr{af_index_t},af_array),out,lhs,ndims,indices,rhs))
end

function af_create_indexers(indexers)
    checkerror(ccall((:af_create_indexers,libaf),af_err,(Ptr{Ptr{af_index_t}},),indexers))
end

function af_set_array_indexer(indexer,idx,dim)
    checkerror(ccall((:af_set_array_indexer,libaf),af_err,(Ptr{af_index_t},af_array,dim_t),indexer,idx,dim))
end

function af_set_seq_indexer(indexer,idx,dim,is_batch)
    checkerror(ccall((:af_set_seq_indexer,libaf),af_err,(Ptr{af_index_t},Ptr{af_seq},dim_t,Bool),indexer,idx,dim,is_batch))
end

function af_set_seq_param_indexer(indexer,_begin,_end,step,dim,is_batch)
    checkerror(ccall((:af_set_seq_param_indexer,libaf),af_err,(Ptr{af_index_t},Cdouble,Cdouble,Cdouble,dim_t,Bool),indexer,_begin,_end,step,dim,is_batch))
end

function af_release_indexers(indexers)
    checkerror(ccall((:af_release_indexers,libaf),af_err,(Ptr{af_index_t},),indexers))
end

function af_create_array(arr,data,ndims,dims,_type)
    checkerror(ccall((:af_create_array,libaf),af_err,(Ptr{af_array},Ptr{Void},UInt32,Ptr{dim_t},af_dtype),arr,data,ndims,dims,_type))
end

function af_create_handle(arr,ndims,dims,_type)
    checkerror(ccall((:af_create_handle,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},af_dtype),arr,ndims,dims,_type))
end

function af_copy_array(arr,_in)
    checkerror(ccall((:af_copy_array,libaf),af_err,(Ptr{af_array},af_array),arr,_in))
end

function af_write_array(arr,data,bytes,src)
    checkerror(ccall((:af_write_array,libaf),af_err,(af_array,Ptr{Void},Csize_t,af_source),arr,data,bytes,src))
end

function af_get_data_ptr(data,arr)
    checkerror(ccall((:af_get_data_ptr,libaf),af_err,(Ptr{Void},af_array),data,arr))
end

function af_release_array(arr)
    checkerror(ccall((:af_release_array,libaf),af_err,(af_array,),arr))
end

function af_retain_array(out,_in)
    checkerror(ccall((:af_retain_array,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_get_data_ref_count(use_count,_in)
    checkerror(ccall((:af_get_data_ref_count,libaf),af_err,(Ptr{Cint},af_array),use_count,_in))
end

function af_eval(_in)
    checkerror(ccall((:af_eval,libaf),af_err,(af_array,),_in))
end

function af_get_elements(elems,arr)
    checkerror(ccall((:af_get_elements,libaf),af_err,(Ptr{dim_t},af_array),elems,arr))
end

function af_get_type(_type,arr)
    checkerror(ccall((:af_get_type,libaf),af_err,(Ptr{af_dtype},af_array),_type,arr))
end

function af_get_dims(d0,d1,d2,d3,arr)
    checkerror(ccall((:af_get_dims,libaf),af_err,(Ptr{dim_t},Ptr{dim_t},Ptr{dim_t},Ptr{dim_t},af_array),d0,d1,d2,d3,arr))
end

function af_get_numdims(result,arr)
    checkerror(ccall((:af_get_numdims,libaf),af_err,(Ptr{UInt32},af_array),result,arr))
end

function af_is_empty(result,arr)
    checkerror(ccall((:af_is_empty,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_scalar(result,arr)
    checkerror(ccall((:af_is_scalar,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_row(result,arr)
    checkerror(ccall((:af_is_row,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_column(result,arr)
    checkerror(ccall((:af_is_column,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_vector(result,arr)
    checkerror(ccall((:af_is_vector,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_complex(result,arr)
    checkerror(ccall((:af_is_complex,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_real(result,arr)
    checkerror(ccall((:af_is_real,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_double(result,arr)
    checkerror(ccall((:af_is_double,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_single(result,arr)
    checkerror(ccall((:af_is_single,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_realfloating(result,arr)
    checkerror(ccall((:af_is_realfloating,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_floating(result,arr)
    checkerror(ccall((:af_is_floating,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_integer(result,arr)
    checkerror(ccall((:af_is_integer,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_is_bool(result,arr)
    checkerror(ccall((:af_is_bool,libaf),af_err,(Ptr{Bool},af_array),result,arr))
end

function af_set_backend(bknd)
    checkerror(ccall((:af_set_backend,libaf),af_err,(af_backend,),bknd))
end

function af_get_backend_count(num_backends)
    checkerror(ccall((:af_get_backend_count,libaf),af_err,(Ptr{UInt32},),num_backends))
end

function af_get_available_backends(backends)
    checkerror(ccall((:af_get_available_backends,libaf),af_err,(Ptr{Cint},),backends))
end

function af_get_backend_id(backend,_in)
    checkerror(ccall((:af_get_backend_id,libaf),af_err,(Ptr{af_backend},af_array),backend,_in))
end

function af_matmul(out,lhs,rhs,optLhs,optRhs)
    checkerror(ccall((:af_matmul,libaf),af_err,(Ptr{af_array},af_array,af_array,af_mat_prop,af_mat_prop),out,lhs,rhs,optLhs,optRhs))
end

function af_dot(out,lhs,rhs,optLhs,optRhs)
    checkerror(ccall((:af_dot,libaf),af_err,(Ptr{af_array},af_array,af_array,af_mat_prop,af_mat_prop),out,lhs,rhs,optLhs,optRhs))
end

function af_transpose(out,_in,conjugate)
    checkerror(ccall((:af_transpose,libaf),af_err,(Ptr{af_array},af_array,Bool),out,_in,conjugate))
end

function af_transpose_inplace(_in,conjugate)
    checkerror(ccall((:af_transpose_inplace,libaf),af_err,(af_array,Bool),_in,conjugate))
end

function af_constant(arr,val,ndims,dims,_type)
    checkerror(ccall((:af_constant,libaf),af_err,(Ptr{af_array},Cdouble,UInt32,Ptr{dim_t},af_dtype),arr,val,ndims,dims,_type))
end

function af_constant_complex(arr,real,imag,ndims,dims,_type)
    checkerror(ccall((:af_constant_complex,libaf),af_err,(Ptr{af_array},Cdouble,Cdouble,UInt32,Ptr{dim_t},af_dtype),arr,real,imag,ndims,dims,_type))
end

function af_constant_long(arr,val,ndims,dims)
    checkerror(ccall((:af_constant_long,libaf),af_err,(Ptr{af_array},intl,UInt32,Ptr{dim_t}),arr,val,ndims,dims))
end

function af_constant_ulong(arr,val,ndims,dims)
    checkerror(ccall((:af_constant_ulong,libaf),af_err,(Ptr{af_array},uintl,UInt32,Ptr{dim_t}),arr,val,ndims,dims))
end

function af_range(out,ndims,dims,seq_dim,_type)
    checkerror(ccall((:af_range,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},Cint,af_dtype),out,ndims,dims,seq_dim,_type))
end

function af_iota(out,ndims,dims,t_ndims,tdims,_type)
    checkerror(ccall((:af_iota,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},UInt32,Ptr{dim_t},af_dtype),out,ndims,dims,t_ndims,tdims,_type))
end

function af_randu(out,ndims,dims,_type)
    checkerror(ccall((:af_randu,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},af_dtype),out,ndims,dims,_type))
end

function af_randn(out,ndims,dims,_type)
    checkerror(ccall((:af_randn,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},af_dtype),out,ndims,dims,_type))
end

function af_set_seed(seed)
    checkerror(ccall((:af_set_seed,libaf),af_err,(uintl,),seed))
end

function af_get_seed(seed)
    checkerror(ccall((:af_get_seed,libaf),af_err,(Ptr{uintl},),seed))
end

function af_identity(out,ndims,dims,_type)
    checkerror(ccall((:af_identity,libaf),af_err,(Ptr{af_array},UInt32,Ptr{dim_t},af_dtype),out,ndims,dims,_type))
end

function af_diag_create(out,_in,num)
    checkerror(ccall((:af_diag_create,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,num))
end

function af_diag_extract(out,_in,num)
    checkerror(ccall((:af_diag_extract,libaf),af_err,(Ptr{af_array},af_array,Cint),out,_in,num))
end

function af_join(out,dim,first,second)
    checkerror(ccall((:af_join,libaf),af_err,(Ptr{af_array},Cint,af_array,af_array),out,dim,first,second))
end

function af_join_many(out,dim,n_arrays,inputs)
    checkerror(ccall((:af_join_many,libaf),af_err,(Ptr{af_array},Cint,UInt32,Ptr{af_array}),out,dim,n_arrays,inputs))
end

function af_tile(out,_in,x,y,z,w)
    checkerror(ccall((:af_tile,libaf),af_err,(Ptr{af_array},af_array,UInt32,UInt32,UInt32,UInt32),out,_in,x,y,z,w))
end

function af_reorder(out,_in,x,y,z,w)
    checkerror(ccall((:af_reorder,libaf),af_err,(Ptr{af_array},af_array,UInt32,UInt32,UInt32,UInt32),out,_in,x,y,z,w))
end

function af_shift(out,_in,x,y,z,w)
    checkerror(ccall((:af_shift,libaf),af_err,(Ptr{af_array},af_array,Cint,Cint,Cint,Cint),out,_in,x,y,z,w))
end

function af_moddims(out,_in,ndims,dims)
    checkerror(ccall((:af_moddims,libaf),af_err,(Ptr{af_array},af_array,UInt32,Ptr{dim_t}),out,_in,ndims,dims))
end

function af_flat(out,_in)
    checkerror(ccall((:af_flat,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_flip(out,_in,dim)
    checkerror(ccall((:af_flip,libaf),af_err,(Ptr{af_array},af_array,UInt32),out,_in,dim))
end

function af_lower(out,_in,is_unit_diag)
    checkerror(ccall((:af_lower,libaf),af_err,(Ptr{af_array},af_array,Bool),out,_in,is_unit_diag))
end

function af_upper(out,_in,is_unit_diag)
    checkerror(ccall((:af_upper,libaf),af_err,(Ptr{af_array},af_array,Bool),out,_in,is_unit_diag))
end

function af_select(out,cond,a,b)
    checkerror(ccall((:af_select,libaf),af_err,(Ptr{af_array},af_array,af_array,af_array),out,cond,a,b))
end

function af_select_scalar_r(out,cond,a,b)
    checkerror(ccall((:af_select_scalar_r,libaf),af_err,(Ptr{af_array},af_array,af_array,Cdouble),out,cond,a,b))
end

function af_select_scalar_l(out,cond,a,b)
    checkerror(ccall((:af_select_scalar_l,libaf),af_err,(Ptr{af_array},af_array,Cdouble,af_array),out,cond,a,b))
end

function af_replace(a,cond,b)
    checkerror(ccall((:af_replace,libaf),af_err,(af_array,af_array,af_array),a,cond,b))
end

function af_replace_scalar(a,cond,b)
    checkerror(ccall((:af_replace_scalar,libaf),af_err,(af_array,af_array,Cdouble),a,cond,b))
end

function af_info()
    checkerror(ccall((:af_info,libaf),af_err,()))
end

function af_init()
    checkerror(ccall((:af_init,libaf),af_err,()))
end

function af_device_info(d_name,d_platform,d_toolkit,d_compute)
    checkerror(ccall((:af_device_info,libaf),af_err,(Ptr{UInt8},Ptr{UInt8},Ptr{UInt8},Ptr{UInt8}),d_name,d_platform,d_toolkit,d_compute))
end

function af_get_device_count(num_of_devices)
    checkerror(ccall((:af_get_device_count,libaf),af_err,(Ptr{Cint},),num_of_devices))
end

function af_get_dbl_support(available,device)
    checkerror(ccall((:af_get_dbl_support,libaf),af_err,(Ptr{Bool},Cint),available,device))
end

function af_set_device(device)
    checkerror(ccall((:af_set_device,libaf),af_err,(Cint,),device))
end

function af_get_device(device)
    checkerror(ccall((:af_get_device,libaf),af_err,(Ptr{Cint},),device))
end

function af_sync(device)
    checkerror(ccall((:af_sync,libaf),af_err,(Cint,),device))
end

function af_alloc_device(ptr,bytes)
    checkerror(ccall((:af_alloc_device,libaf),af_err,(Ptr{Ptr{Void}},dim_t),ptr,bytes))
end

function af_alloc_pinned(ptr,bytes)
    checkerror(ccall((:af_alloc_pinned,libaf),af_err,(Ptr{Ptr{Void}},dim_t),ptr,bytes))
end

function af_free_device(ptr)
    checkerror(ccall((:af_free_device,libaf),af_err,(Ptr{Void},),ptr))
end

function af_free_pinned(ptr)
    checkerror(ccall((:af_free_pinned,libaf),af_err,(Ptr{Void},),ptr))
end

function af_device_array(arr,data,ndims,dims,_type)
    checkerror(ccall((:af_device_array,libaf),af_err,(Ptr{af_array},Ptr{Void},UInt32,Ptr{dim_t},af_dtype),arr,data,ndims,dims,_type))
end

function af_device_mem_info(alloc_bytes,alloc_buffers,lock_bytes,lock_buffers)
    checkerror(ccall((:af_device_mem_info,libaf),af_err,(Ptr{Csize_t},Ptr{Csize_t},Ptr{Csize_t},Ptr{Csize_t}),alloc_bytes,alloc_buffers,lock_bytes,lock_buffers))
end

function af_device_gc()
    checkerror(ccall((:af_device_gc,libaf),af_err,()))
end

function af_set_mem_step_size(step_bytes)
    checkerror(ccall((:af_set_mem_step_size,libaf),af_err,(Csize_t,),step_bytes))
end

function af_get_mem_step_size(step_bytes)
    checkerror(ccall((:af_get_mem_step_size,libaf),af_err,(Ptr{Csize_t},),step_bytes))
end

function af_lock_device_ptr(arr)
    checkerror(ccall((:af_lock_device_ptr,libaf),af_err,(af_array,),arr))
end

function af_unlock_device_ptr(arr)
    checkerror(ccall((:af_unlock_device_ptr,libaf),af_err,(af_array,),arr))
end

function af_get_device_ptr(ptr,arr)
    checkerror(ccall((:af_get_device_ptr,libaf),af_err,(Ptr{Ptr{Void}},af_array),ptr,arr))
end

function af_get_last_error(msg,len)
    ccall((:af_get_last_error,libaf),Void,(Ptr{Ptr{UInt8}},Ptr{dim_t}),msg,len)
end

function af_err_to_string(err)
    ccall((:af_err_to_string,libaf),Ptr{UInt8},(af_err,),err)
end

function af_create_features(feat,num)
    checkerror(ccall((:af_create_features,libaf),af_err,(Ptr{af_features},dim_t),feat,num))
end

function af_retain_features(out,feat)
    checkerror(ccall((:af_retain_features,libaf),af_err,(Ptr{af_features},af_features),out,feat))
end

function af_get_features_num(num,feat)
    checkerror(ccall((:af_get_features_num,libaf),af_err,(Ptr{dim_t},af_features),num,feat))
end

function af_get_features_xpos(out,feat)
    checkerror(ccall((:af_get_features_xpos,libaf),af_err,(Ptr{af_array},af_features),out,feat))
end

function af_get_features_ypos(out,feat)
    checkerror(ccall((:af_get_features_ypos,libaf),af_err,(Ptr{af_array},af_features),out,feat))
end

function af_get_features_score(score,feat)
    checkerror(ccall((:af_get_features_score,libaf),af_err,(Ptr{af_array},af_features),score,feat))
end

function af_get_features_orientation(orientation,feat)
    checkerror(ccall((:af_get_features_orientation,libaf),af_err,(Ptr{af_array},af_features),orientation,feat))
end

function af_get_features_size(size,feat)
    checkerror(ccall((:af_get_features_size,libaf),af_err,(Ptr{af_array},af_features),size,feat))
end

function af_release_features(feat)
    checkerror(ccall((:af_release_features,libaf),af_err,(af_features,),feat))
end

function af_create_window(out,width,height,title)
    checkerror(ccall((:af_create_window,libaf),af_err,(Ptr{af_window},Cint,Cint,Ptr{UInt8}),out,width,height,title))
end

function af_set_position(wind,x,y)
    checkerror(ccall((:af_set_position,libaf),af_err,(af_window,UInt32,UInt32),wind,x,y))
end

function af_set_title(wind,title)
    checkerror(ccall((:af_set_title,libaf),af_err,(af_window,Ptr{UInt8}),wind,title))
end

function af_set_size(wind,w,h)
    checkerror(ccall((:af_set_size,libaf),af_err,(af_window,UInt32,UInt32),wind,w,h))
end

function af_draw_image(wind,_in,props)
    checkerror(ccall((:af_draw_image,libaf),af_err,(af_window,af_array,Ptr{af_cell}),wind,_in,props))
end

function af_draw_plot(wind,X,Y,props)
    checkerror(ccall((:af_draw_plot,libaf),af_err,(af_window,af_array,af_array,Ptr{af_cell}),wind,X,Y,props))
end

function af_draw_plot3(wind,P,props)
    checkerror(ccall((:af_draw_plot3,libaf),af_err,(af_window,af_array,Ptr{af_cell}),wind,P,props))
end

function af_draw_hist(wind,X,minval,maxval,props)
    checkerror(ccall((:af_draw_hist,libaf),af_err,(af_window,af_array,Cdouble,Cdouble,Ptr{af_cell}),wind,X,minval,maxval,props))
end

function af_draw_surface(wind,xVals,yVals,S,props)
    checkerror(ccall((:af_draw_surface,libaf),af_err,(af_window,af_array,af_array,af_array,Ptr{af_cell}),wind,xVals,yVals,S,props))
end

function af_grid(wind,rows,cols)
    checkerror(ccall((:af_grid,libaf),af_err,(af_window,Cint,Cint),wind,rows,cols))
end

function af_show(wind)
    checkerror(ccall((:af_show,libaf),af_err,(af_window,),wind))
end

function af_is_window_closed(out,wind)
    checkerror(ccall((:af_is_window_closed,libaf),af_err,(Ptr{Bool},af_window),out,wind))
end

function af_destroy_window(wind)
    checkerror(ccall((:af_destroy_window,libaf),af_err,(af_window,),wind))
end

function af_gradient(dx,dy,_in)
    checkerror(ccall((:af_gradient,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array),dx,dy,_in))
end

function af_load_image(out,filename,isColor)
    checkerror(ccall((:af_load_image,libaf),af_err,(Ptr{af_array},Ptr{UInt8},Bool),out,filename,isColor))
end

function af_save_image(filename,_in)
    checkerror(ccall((:af_save_image,libaf),af_err,(Ptr{UInt8},af_array),filename,_in))
end

function af_load_image_memory(out,ptr)
    checkerror(ccall((:af_load_image_memory,libaf),af_err,(Ptr{af_array},Ptr{Void}),out,ptr))
end

function af_save_image_memory(ptr,_in,format)
    checkerror(ccall((:af_save_image_memory,libaf),af_err,(Ptr{Ptr{Void}},af_array,af_image_format),ptr,_in,format))
end

function af_delete_image_memory(ptr)
    checkerror(ccall((:af_delete_image_memory,libaf),af_err,(Ptr{Void},),ptr))
end

function af_load_image_native(out,filename)
    checkerror(ccall((:af_load_image_native,libaf),af_err,(Ptr{af_array},Ptr{UInt8}),out,filename))
end

function af_save_image_native(filename,_in)
    checkerror(ccall((:af_save_image_native,libaf),af_err,(Ptr{UInt8},af_array),filename,_in))
end

function af_resize(out,_in,odim0,odim1,method)
    checkerror(ccall((:af_resize,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,af_interp_type),out,_in,odim0,odim1,method))
end

function af_transform(out,_in,transform,odim0,odim1,method,inverse)
    checkerror(ccall((:af_transform,libaf),af_err,(Ptr{af_array},af_array,af_array,dim_t,dim_t,af_interp_type,Bool),out,_in,transform,odim0,odim1,method,inverse))
end

function af_rotate(out,_in,theta,crop,method)
    checkerror(ccall((:af_rotate,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Bool,af_interp_type),out,_in,theta,crop,method))
end

function af_translate(out,_in,trans0,trans1,odim0,odim1,method)
    checkerror(ccall((:af_translate,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,dim_t,dim_t,af_interp_type),out,_in,trans0,trans1,odim0,odim1,method))
end

function af_scale(out,_in,scale0,scale1,odim0,odim1,method)
    checkerror(ccall((:af_scale,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,dim_t,dim_t,af_interp_type),out,_in,scale0,scale1,odim0,odim1,method))
end

function af_skew(out,_in,skew0,skew1,odim0,odim1,method,inverse)
    checkerror(ccall((:af_skew,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,dim_t,dim_t,af_interp_type,Bool),out,_in,skew0,skew1,odim0,odim1,method,inverse))
end

function af_histogram(out,_in,nbins,minval,maxval)
    checkerror(ccall((:af_histogram,libaf),af_err,(Ptr{af_array},af_array,UInt32,Cdouble,Cdouble),out,_in,nbins,minval,maxval))
end

function af_dilate(out,_in,mask)
    checkerror(ccall((:af_dilate,libaf),af_err,(Ptr{af_array},af_array,af_array),out,_in,mask))
end

function af_dilate3(out,_in,mask)
    checkerror(ccall((:af_dilate3,libaf),af_err,(Ptr{af_array},af_array,af_array),out,_in,mask))
end

function af_erode(out,_in,mask)
    checkerror(ccall((:af_erode,libaf),af_err,(Ptr{af_array},af_array,af_array),out,_in,mask))
end

function af_erode3(out,_in,mask)
    checkerror(ccall((:af_erode3,libaf),af_err,(Ptr{af_array},af_array,af_array),out,_in,mask))
end

function af_bilateral(out,_in,spatial_sigma,chromatic_sigma,isColor)
    checkerror(ccall((:af_bilateral,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,Bool),out,_in,spatial_sigma,chromatic_sigma,isColor))
end

function af_mean_shift(out,_in,spatial_sigma,chromatic_sigma,iter,is_color)
    checkerror(ccall((:af_mean_shift,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,UInt32,Bool),out,_in,spatial_sigma,chromatic_sigma,iter,is_color))
end

function af_medfilt(out,_in,wind_length,wind_width,edge_pad)
    checkerror(ccall((:af_medfilt,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,af_border_type),out,_in,wind_length,wind_width,edge_pad))
end

function af_minfilt(out,_in,wind_length,wind_width,edge_pad)
    checkerror(ccall((:af_minfilt,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,af_border_type),out,_in,wind_length,wind_width,edge_pad))
end

function af_maxfilt(out,_in,wind_length,wind_width,edge_pad)
    checkerror(ccall((:af_maxfilt,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,af_border_type),out,_in,wind_length,wind_width,edge_pad))
end

function af_regions(out,_in,connectivity,ty)
    checkerror(ccall((:af_regions,libaf),af_err,(Ptr{af_array},af_array,af_connectivity,af_dtype),out,_in,connectivity,ty))
end

function af_sobel_operator(dx,dy,img,ker_size)
    checkerror(ccall((:af_sobel_operator,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,UInt32),dx,dy,img,ker_size))
end

function af_rgb2gray(out,_in,rPercent,gPercent,bPercent)
    checkerror(ccall((:af_rgb2gray,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,Cfloat),out,_in,rPercent,gPercent,bPercent))
end

function af_gray2rgb(out,_in,rFactor,gFactor,bFactor)
    checkerror(ccall((:af_gray2rgb,libaf),af_err,(Ptr{af_array},af_array,Cfloat,Cfloat,Cfloat),out,_in,rFactor,gFactor,bFactor))
end

function af_hist_equal(out,_in,hist)
    checkerror(ccall((:af_hist_equal,libaf),af_err,(Ptr{af_array},af_array,af_array),out,_in,hist))
end

function af_gaussian_kernel(out,rows,cols,sigma_r,sigma_c)
    checkerror(ccall((:af_gaussian_kernel,libaf),af_err,(Ptr{af_array},Cint,Cint,Cdouble,Cdouble),out,rows,cols,sigma_r,sigma_c))
end

function af_hsv2rgb(out,_in)
    checkerror(ccall((:af_hsv2rgb,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_rgb2hsv(out,_in)
    checkerror(ccall((:af_rgb2hsv,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_color_space(out,image,to,from)
    checkerror(ccall((:af_color_space,libaf),af_err,(Ptr{af_array},af_array,af_cspace_t,af_cspace_t),out,image,to,from))
end

function af_unwrap(out,_in,wx,wy,sx,sy,px,py,is_column)
    checkerror(ccall((:af_unwrap,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,dim_t,dim_t,dim_t,dim_t,Bool),out,_in,wx,wy,sx,sy,px,py,is_column))
end

function af_wrap(out,_in,ox,oy,wx,wy,sx,sy,px,py,is_column)
    checkerror(ccall((:af_wrap,libaf),af_err,(Ptr{af_array},af_array,dim_t,dim_t,dim_t,dim_t,dim_t,dim_t,dim_t,dim_t,Bool),out,_in,ox,oy,wx,wy,sx,sy,px,py,is_column))
end

function af_sat(out,_in)
    checkerror(ccall((:af_sat,libaf),af_err,(Ptr{af_array},af_array),out,_in))
end

function af_ycbcr2rgb(out,_in,standard)
    checkerror(ccall((:af_ycbcr2rgb,libaf),af_err,(Ptr{af_array},af_array,af_ycc_std),out,_in,standard))
end

function af_rgb2ycbcr(out,_in,standard)
    checkerror(ccall((:af_rgb2ycbcr,libaf),af_err,(Ptr{af_array},af_array,af_ycc_std),out,_in,standard))
end

function af_svd(u,s,vt,_in)
    checkerror(ccall((:af_svd,libaf),af_err,(Ptr{af_array},Ptr{af_array},Ptr{af_array},af_array),u,s,vt,_in))
end

function af_svd_inplace(u,s,vt,_in)
    checkerror(ccall((:af_svd_inplace,libaf),af_err,(Ptr{af_array},Ptr{af_array},Ptr{af_array},af_array),u,s,vt,_in))
end

function af_lu(lower,upper,pivot,_in)
    checkerror(ccall((:af_lu,libaf),af_err,(Ptr{af_array},Ptr{af_array},Ptr{af_array},af_array),lower,upper,pivot,_in))
end

function af_lu_inplace(pivot,_in,is_lapack_piv)
    checkerror(ccall((:af_lu_inplace,libaf),af_err,(Ptr{af_array},af_array,Bool),pivot,_in,is_lapack_piv))
end

function af_qr(q,r,tau,_in)
    checkerror(ccall((:af_qr,libaf),af_err,(Ptr{af_array},Ptr{af_array},Ptr{af_array},af_array),q,r,tau,_in))
end

function af_qr_inplace(tau,_in)
    checkerror(ccall((:af_qr_inplace,libaf),af_err,(Ptr{af_array},af_array),tau,_in))
end

function af_cholesky(out,info,_in,is_upper)
    checkerror(ccall((:af_cholesky,libaf),af_err,(Ptr{af_array},Ptr{Cint},af_array,Bool),out,info,_in,is_upper))
end

function af_cholesky_inplace(info,_in,is_upper)
    checkerror(ccall((:af_cholesky_inplace,libaf),af_err,(Ptr{Cint},af_array,Bool),info,_in,is_upper))
end

function af_solve(x,a,b,options)
    checkerror(ccall((:af_solve,libaf),af_err,(Ptr{af_array},af_array,af_array,af_mat_prop),x,a,b,options))
end

function af_solve_lu(x,a,piv,b,options)
    checkerror(ccall((:af_solve_lu,libaf),af_err,(Ptr{af_array},af_array,af_array,af_array,af_mat_prop),x,a,piv,b,options))
end

function af_inverse(out,_in,options)
    checkerror(ccall((:af_inverse,libaf),af_err,(Ptr{af_array},af_array,af_mat_prop),out,_in,options))
end

function af_rank(rank,_in,tol)
    checkerror(ccall((:af_rank,libaf),af_err,(Ptr{UInt32},af_array,Cdouble),rank,_in,tol))
end

function af_det(det_real,det_imag,_in)
    checkerror(ccall((:af_det,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),det_real,det_imag,_in))
end

function af_norm(out,_in,_type,p,q)
    checkerror(ccall((:af_norm,libaf),af_err,(Ptr{Cdouble},af_array,af_norm_type,Cdouble,Cdouble),out,_in,_type,p,q))
end

function af_approx1(out,_in,pos,method,offGrid)
    checkerror(ccall((:af_approx1,libaf),af_err,(Ptr{af_array},af_array,af_array,af_interp_type,Cfloat),out,_in,pos,method,offGrid))
end

function af_approx2(out,_in,pos0,pos1,method,offGrid)
    checkerror(ccall((:af_approx2,libaf),af_err,(Ptr{af_array},af_array,af_array,af_array,af_interp_type,Cfloat),out,_in,pos0,pos1,method,offGrid))
end

function af_fft(out,_in,norm_factor,odim0)
    checkerror(ccall((:af_fft,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t),out,_in,norm_factor,odim0))
end

function af_fft_inplace(_in,norm_factor)
    checkerror(ccall((:af_fft_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_fft2(out,_in,norm_factor,odim0,odim1)
    checkerror(ccall((:af_fft2,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t),out,_in,norm_factor,odim0,odim1))
end

function af_fft2_inplace(_in,norm_factor)
    checkerror(ccall((:af_fft2_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_fft3(out,_in,norm_factor,odim0,odim1,odim2)
    checkerror(ccall((:af_fft3,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t,dim_t),out,_in,norm_factor,odim0,odim1,odim2))
end

function af_fft3_inplace(_in,norm_factor)
    checkerror(ccall((:af_fft3_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_ifft(out,_in,norm_factor,odim0)
    checkerror(ccall((:af_ifft,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t),out,_in,norm_factor,odim0))
end

function af_ifft_inplace(_in,norm_factor)
    checkerror(ccall((:af_ifft_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_ifft2(out,_in,norm_factor,odim0,odim1)
    checkerror(ccall((:af_ifft2,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t),out,_in,norm_factor,odim0,odim1))
end

function af_ifft2_inplace(_in,norm_factor)
    checkerror(ccall((:af_ifft2_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_ifft3(out,_in,norm_factor,odim0,odim1,odim2)
    checkerror(ccall((:af_ifft3,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t,dim_t),out,_in,norm_factor,odim0,odim1,odim2))
end

function af_ifft3_inplace(_in,norm_factor)
    checkerror(ccall((:af_ifft3_inplace,libaf),af_err,(af_array,Cdouble),_in,norm_factor))
end

function af_fft_r2c(out,_in,norm_factor,pad0)
    checkerror(ccall((:af_fft_r2c,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t),out,_in,norm_factor,pad0))
end

function af_fft2_r2c(out,_in,norm_factor,pad0,pad1)
    checkerror(ccall((:af_fft2_r2c,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t),out,_in,norm_factor,pad0,pad1))
end

function af_fft3_r2c(out,_in,norm_factor,pad0,pad1,pad2)
    checkerror(ccall((:af_fft3_r2c,libaf),af_err,(Ptr{af_array},af_array,Cdouble,dim_t,dim_t,dim_t),out,_in,norm_factor,pad0,pad1,pad2))
end

function af_fft_c2r(out,_in,norm_factor,is_odd)
    checkerror(ccall((:af_fft_c2r,libaf),af_err,(Ptr{af_array},af_array,Cdouble,Bool),out,_in,norm_factor,is_odd))
end

function af_fft2_c2r(out,_in,norm_factor,is_odd)
    checkerror(ccall((:af_fft2_c2r,libaf),af_err,(Ptr{af_array},af_array,Cdouble,Bool),out,_in,norm_factor,is_odd))
end

function af_fft3_c2r(out,_in,norm_factor,is_odd)
    checkerror(ccall((:af_fft3_c2r,libaf),af_err,(Ptr{af_array},af_array,Cdouble,Bool),out,_in,norm_factor,is_odd))
end

function af_convolve1(out,signal,filter,mode,domain)
    checkerror(ccall((:af_convolve1,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode,af_conv_domain),out,signal,filter,mode,domain))
end

function af_convolve2(out,signal,filter,mode,domain)
    checkerror(ccall((:af_convolve2,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode,af_conv_domain),out,signal,filter,mode,domain))
end

function af_convolve3(out,signal,filter,mode,domain)
    checkerror(ccall((:af_convolve3,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode,af_conv_domain),out,signal,filter,mode,domain))
end

function af_convolve2_sep(out,col_filter,row_filter,signal,mode)
    checkerror(ccall((:af_convolve2_sep,libaf),af_err,(Ptr{af_array},af_array,af_array,af_array,af_conv_mode),out,col_filter,row_filter,signal,mode))
end

function af_fft_convolve1(out,signal,filter,mode)
    checkerror(ccall((:af_fft_convolve1,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode),out,signal,filter,mode))
end

function af_fft_convolve2(out,signal,filter,mode)
    checkerror(ccall((:af_fft_convolve2,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode),out,signal,filter,mode))
end

function af_fft_convolve3(out,signal,filter,mode)
    checkerror(ccall((:af_fft_convolve3,libaf),af_err,(Ptr{af_array},af_array,af_array,af_conv_mode),out,signal,filter,mode))
end

function af_fir(y,b,x)
    checkerror(ccall((:af_fir,libaf),af_err,(Ptr{af_array},af_array,af_array),y,b,x))
end

function af_iir(y,b,a,x)
    checkerror(ccall((:af_iir,libaf),af_err,(Ptr{af_array},af_array,af_array,af_array),y,b,a,x))
end

function af_mean(out,_in,dim)
    checkerror(ccall((:af_mean,libaf),af_err,(Ptr{af_array},af_array,dim_t),out,_in,dim))
end

function af_mean_weighted(out,_in,weights,dim)
    checkerror(ccall((:af_mean_weighted,libaf),af_err,(Ptr{af_array},af_array,af_array,dim_t),out,_in,weights,dim))
end

function af_var(out,_in,isbiased,dim)
    checkerror(ccall((:af_var,libaf),af_err,(Ptr{af_array},af_array,Bool,dim_t),out,_in,isbiased,dim))
end

function af_var_weighted(out,_in,weights,dim)
    checkerror(ccall((:af_var_weighted,libaf),af_err,(Ptr{af_array},af_array,af_array,dim_t),out,_in,weights,dim))
end

function af_stdev(out,_in,dim)
    checkerror(ccall((:af_stdev,libaf),af_err,(Ptr{af_array},af_array,dim_t),out,_in,dim))
end

function af_cov(out,X,Y,isbiased)
    checkerror(ccall((:af_cov,libaf),af_err,(Ptr{af_array},af_array,af_array,Bool),out,X,Y,isbiased))
end

function af_median(out,_in,dim)
    checkerror(ccall((:af_median,libaf),af_err,(Ptr{af_array},af_array,dim_t),out,_in,dim))
end

function af_mean_all(real,imag,_in)
    checkerror(ccall((:af_mean_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_mean_all_weighted(real,imag,_in,weights)
    checkerror(ccall((:af_mean_all_weighted,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,af_array),real,imag,_in,weights))
end

function af_var_all(realVal,imagVal,_in,isbiased)
    checkerror(ccall((:af_var_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,Bool),realVal,imagVal,_in,isbiased))
end

function af_var_all_weighted(realVal,imagVal,_in,weights)
    checkerror(ccall((:af_var_all_weighted,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,af_array),realVal,imagVal,_in,weights))
end

function af_stdev_all(real,imag,_in)
    checkerror(ccall((:af_stdev_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),real,imag,_in))
end

function af_median_all(realVal,imagVal,_in)
    checkerror(ccall((:af_median_all,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array),realVal,imagVal,_in))
end

function af_corrcoef(realVal,imagVal,X,Y)
    checkerror(ccall((:af_corrcoef,libaf),af_err,(Ptr{Cdouble},Ptr{Cdouble},af_array,af_array),realVal,imagVal,X,Y))
end

function af_fast(out,_in,thr,arc_length,non_max,feature_ratio,edge)
    checkerror(ccall((:af_fast,libaf),af_err,(Ptr{af_features},af_array,Cfloat,UInt32,Bool,Cfloat,UInt32),out,_in,thr,arc_length,non_max,feature_ratio,edge))
end

function af_harris(out,_in,max_corners,min_response,sigma,block_size,k_thr)
    checkerror(ccall((:af_harris,libaf),af_err,(Ptr{af_features},af_array,UInt32,Cfloat,Cfloat,UInt32,Cfloat),out,_in,max_corners,min_response,sigma,block_size,k_thr))
end

function af_orb(feat,desc,_in,fast_thr,max_feat,scl_fctr,levels,blur_img)
    checkerror(ccall((:af_orb,libaf),af_err,(Ptr{af_features},Ptr{af_array},af_array,Cfloat,UInt32,Cfloat,UInt32,Bool),feat,desc,_in,fast_thr,max_feat,scl_fctr,levels,blur_img))
end

function af_sift(feat,desc,_in,n_layers,contrast_thr,edge_thr,init_sigma,double_input,intensity_scale,feature_ratio)
    checkerror(ccall((:af_sift,libaf),af_err,(Ptr{af_features},Ptr{af_array},af_array,UInt32,Cfloat,Cfloat,Cfloat,Bool,Cfloat,Cfloat),feat,desc,_in,n_layers,contrast_thr,edge_thr,init_sigma,double_input,intensity_scale,feature_ratio))
end

function af_gloh(feat,desc,_in,n_layers,contrast_thr,edge_thr,init_sigma,double_input,intensity_scale,feature_ratio)
    checkerror(ccall((:af_gloh,libaf),af_err,(Ptr{af_features},Ptr{af_array},af_array,UInt32,Cfloat,Cfloat,Cfloat,Bool,Cfloat,Cfloat),feat,desc,_in,n_layers,contrast_thr,edge_thr,init_sigma,double_input,intensity_scale,feature_ratio))
end

function af_hamming_matcher(idx,dist,query,train,dist_dim,n_dist)
    checkerror(ccall((:af_hamming_matcher,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,af_array,dim_t,UInt32),idx,dist,query,train,dist_dim,n_dist))
end

function af_nearest_neighbour(idx,dist,query,train,dist_dim,n_dist,dist_type)
    checkerror(ccall((:af_nearest_neighbour,libaf),af_err,(Ptr{af_array},Ptr{af_array},af_array,af_array,dim_t,UInt32,af_match_type),idx,dist,query,train,dist_dim,n_dist,dist_type))
end

function af_match_template(out,search_img,template_img,m_type)
    checkerror(ccall((:af_match_template,libaf),af_err,(Ptr{af_array},af_array,af_array,af_match_type),out,search_img,template_img,m_type))
end

function af_susan(out,_in,radius,diff_thr,geom_thr,feature_ratio,edge)
    checkerror(ccall((:af_susan,libaf),af_err,(Ptr{af_features},af_array,UInt32,Cfloat,Cfloat,Cfloat,UInt32),out,_in,radius,diff_thr,geom_thr,feature_ratio,edge))
end

function af_dog(out,_in,radius1,radius2)
    checkerror(ccall((:af_dog,libaf),af_err,(Ptr{af_array},af_array,Cint,Cint),out,_in,radius1,radius2))
end

function af_homography(H,inliers,x_src,y_src,x_dst,y_dst,htype,inlier_thr,iterations,otype)
    checkerror(ccall((:af_homography,libaf),af_err,(Ptr{af_array},Ptr{Cint},af_array,af_array,af_array,af_array,af_homography_type,Cfloat,UInt32,af_dtype),H,inliers,x_src,y_src,x_dst,y_dst,htype,inlier_thr,iterations,otype))
end


text:
module Design

using OffsetArrays

const Float = Float64

#==============================================================================
Polynomials
==============================================================================#

# DONE
struct VarLinForm{T}
    form ::Dict{Int, T}
end

#DONE
function add!(dest<:VarLinForm, source<:VarLinForm, factor=1) end

#DONE
function add_conjugated!(dest<:VarLinForm, source<:VarLinForm, factor=1) end

#DONE
function mul!(form<:VarLinForm, factor) end

#######################################

struct PolynomialForm{N <: Number}
    terms ::OffsetVector{ VarLinForm{N} }
end

function add!(dest<:PolynomialForm, source<:PolynomialForm, factor=1) end

function mul!(poly<:PolynomialForm, factor) end

function mul_by_power!(poly<:PolynomialForm, factor) end

function conjugate(poly<:PolynomialForm) end

function z_conj_diff(poly<:PolynomialForm) end

function matrix_form(poly<:PolynomialForm) end

#######################################

struct NormedPolynomial{N <: Number, FL <: AbstractFloat}
    poly ::PolynomialForm{N}
    r_norm ::FL
end

function add!(dest<:NormedPolynomial, source<:NormedPolynomial, factor=1) end

function empty!(normed_poly<:NormedPolynomial) end

function conjugate(normed_poly<:NormedPolynomial, r_contour) end

function re_conjugate!(normed_poly<:NormedPolynomial, r_old, r_new) end

function z_conj_diff(normed_poly<:NormedPolynomial, r_contour) end

function matrix_form(normed_poly<:NormedPolynomial) end

#######################################

struct PlaneLayer
    E       ::Float
    ν       ::Float
    r_inner ::Float
    r_outer ::Float
    ϕ       ::NormedPolynomial{Complex{Float}, Float}
    z_bar_Φ ::NormedPolynomial{Complex{Float}, Float}
    bar_ψ   ::NormedPolynomial{Complex{Float}, Float}
end

function couple!(dest::PlaneLayer, source::PlaneLayer) end

function displacements(layer::PlaneLayer) end

function forces(layer::PlaneLayer) end

#######################################

struct PlaneFiber
    layers ::Vector{PlaneLayer{Float}}
    var_indices ::UnitRange{Int}
    max_power ::Int
end

displacements(fiber::PlaneFiber) = displacements(fiber.layers[end])

forces(fiber::PlaneFiber) = forces(fiber.layers[end])

#######################################

struct PlaneCohesive end

function displacements(cohesive::PlaneCohesive) end

function forces(cohesive::PlaneCohesive) end

#######################################

struct PlaneCell
    fibers ::Vector{ PlaneFiber{Float} }
    cohesive ::PlaneCohesive{Float}
    slae_A ::Matrix{Float}
end

function fill_slae_from_fibers!(cell::PlaneCell)

end

###############################################################################
###############################################################################
###############################################################################

struct Contour
    center    ::Complex{ Rational{Int} }
    radius    ::Float
    max_power ::Int
end

abstract type ProblemType end

abstract type Fiber{P <: ProblemType} end

abstract type Cohesive{P <: ProblemType} end

abstract type SubMatrixType{P <: ProblemType} end

struct SubMatrix_Zero{P <: ProblemType} <: SubMatrixType{P}
    contour ::Contour
end

struct SubMatrix_Fiber{P <: ProblemType} <: SubMatrixType{P}
    contour ::Contour
    fiber   ::Fiber{P}
end

struct SubMatrix_Cohesive{P <: ProblemType} <: SubMatrixType{P}
    contour  ::Contour
    cohesive ::Cohesive{P}
end

abstract type SubMatrix_Averaging{P <: ProblemType} <: SubMatrixType{P} end

struct ReferenceMatrix{P <: ProblemType}
    matrix ::Matrix{ SubMatrixType{P} }
end

#==============================================================================
Ellipticals
==============================================================================#

struct EllipticPraecursor{FL <: AbstractFloat}
    terms :: OffsetVector{ Complex{FL} }
end

end # module Design


text:
# This file is a part of SimilaritySearch.jl

"""
    mutable struct RandomHints

Indicates that hints are a random sample of the dataset
"""
@with_kw mutable struct RandomHints <: Callback
    logbase::Float32 = 1.1
end

"""
    executed_callback(opt::RandomHints, index)

SearchGraph's callback for selecting hints at random
"""
function execute_callback(opt::RandomHints, index)
    n = length(index)
    m = ceil(Int, log(opt.logbase, n))
    empty!(index.hints)
    V = Set{Int}()

    for i in 1:m
        p = rand(1:n)
        if !(p in V)
            push!(V, p)
            push!(index.hints, p)
        end
    end
end

function callback__(opt::RandomHints, index)
    empty!(index.hints)
    push!(index.hints, 1)
end

"""
    mutable struct DisjointHints

Indicates that hints are a small disjoint (untouched neighbors) subsample
"""
@with_kw mutable struct DisjointHints <: Callback
    logbase::Float32 = 1.1
end

function execute_callback(opt::DisjointHints, index)
    n = length(index)
    m = ceil(Int, log(opt.logbase, n))
    empty!(index.hints)
    meansize = mean(length(index.links[i]) for i in 1:n)
    res = KnnResult(m)
    for i in 1:n
        push!(res, i, abs(length(index.links[i]) - meansize))
    end

    V = Set{Int}()
    for i in res.id
        i in V && continue
        push!(index.hints, i)
        push!(V, i)
        union!(V, index.links[i])
    end
end
"""
    struct KDisjointHints

Indicates that hints are selected to have a disjoint neighborhood
"""
@with_kw struct KDisjointHints <: Callback
    logbase::Float32 = 1.1
    disjoint::Int32 = 3
    expansion::Int32 = 4
end

"""
    execute_callback(opt::KDisjointHints, index)

SearchGraph's callback for selecting hints at random
"""
function execute_callback(opt::KDisjointHints, index)
    n = length(index)
    m = ceil(Int, log(opt.logbase, length(index)))
    sample = unique(rand(1:n, opt.expansion * m))
    m = min(length(sample), m)
    sort!(sample, by=i->length(index.links[i]), rev=true)

    visited = Set{Int32}()
    empty!(index.hints)
    E = Pair{Int32,Int32}[]
    i = 1
    while length(index.hints) < m && i < length(sample)
        # p = rand(1:n)
        p = sample[i]
        i += 1
        p in visited && continue
        push!(index.hints, p)
        push!(visited, p)
        # visit the neighborhood with some expansion factor
        push!(E, p => 0)
        while length(E) > 0
            parent, e = pop!(E)
            for child in keys(index.links[parent])
                if !(child in visited)
                    push!(visited, child)
                    e + 1 <= opt.expansion && push!(E, child => e + 1)
                end
            end
        end
    end

    # @info "disjoint hints $m --> $(length(index.hints))"
end

max_stars_repo_name: sadit/SimilaritySearch

max_issues_repo_name: sadit/NNS

max_forks_repo_name: sadit/SimilaritySearch


text:
@testset "filter" begin
  N = 347
  for T ∈ (Float32, Float64, Int32, Int64)
    @show T, @__LINE__
    if T <: Integer
      x = rand(T(-100):T(100), N)
    else
      x = rand(T, N)
    end
    y1 = filter(a -> a > 0.7, x)
    y2 = vfilter(a -> a > 0.7, x)
    @test y1 == y2
    y1 = filter(a -> a ≤ 0.7, x)
    y3 = vfilter(a -> a ≤ 0.7, x)
    @test y1 == y3
    @test length(y2) + length(y3) == N
  end
end


text:
module TimeseriesSurrogates

# TODO: I think it is more clear when each file uses the packages it needs instead of
# the global usage here. It makes it easier to understand how each algorithm works
# and what it needs
using Distributions
using StatsBase
using InplaceOps
using AbstractFFTs
using DSP
using Interpolations
using Wavelets
using Requires

include("api.jl")

include("utils/testsystems.jl")

# Periodogram interpolation
include("utils/interpolation.jl")

# The different surrogate routines
include("methods/randomshuffle.jl")
include("methods/large_shuffle.jl")
include("methods/randomfourier.jl")
include("methods/aaft.jl")
include("methods/iaaft.jl")
include("methods/truncated_fourier.jl")
include("methods/wavelet_based.jl")
include("methods/pseudoperiodic.jl")
include("methods/multidimensional.jl")
include("methods/ar.jl")

# Visualization routine for time series + surrogate + periodogram/acf/histogram
using Requires
function __init__()
    @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" begin
        include("plotting/surrogate_plot.jl")
    end
    @require UncertainData="dcd9ba68-c27b-5cea-ae21-829cd07325bf" begin
        include("utils/uncertaindatasets.jl")
    end
end

end # module


text:
export ModuleProvider, dispose

# TODO: use this class implicitly? ie. when passing Modules to functions expecting a
#       ModuleProvider. Especially because dispose(mp) destroys the underlying mod.

@checked struct ModuleProvider
    ref::API.LLVMModuleProviderRef
end

Base.unsafe_convert(::Type{API.LLVMModuleProviderRef}, mp::ModuleProvider) = mp.ref

ModuleProvider(mod::Module) =
    ModuleProvider(API.LLVMCreateModuleProviderForExistingModule(mod))

function ModuleProvider(f::Core.Function, args...)
    mp = ModuleProvider(args...)
    try
        f(mp)
    finally
        dispose(mp)
    end
end

# NOTE: this destroys the underlying module
dispose(mp::ModuleProvider) = API.LLVMDisposeModuleProvider(mp)


text:
export Lambertian, Metal, Dielectric

reflect(v, n) =  v - 2dot(v,n)*n

struct Lambertian <: Material
	albedo::Color
	Lambertian(c::Color) = new(c)
	Lambertian(r,g,b) = new(Color(r,g,b))
	Lambertian() = Lambertian(Color(rand()*rand(), rand()*rand(), rand()*rand()))
end

function scatter(l::Lambertian, ray::Ray, hit::Hit)
	scatter_direction = hit.normal + random_unit_vector()
	if near_zero(scatter_direction)
		scatter_direction = hit.normal
	end
	Ray(hit.p, scatter_direction), l.albedo
end

struct Metal <: Material
	albedo::Color
	fuzz::Float64
	Metal(a, f) = new(a, f)
	Metal(r,g,b,f) = Metal(Color(r,g,b), f)
end

function scatter(m::Metal, ray::Ray, hit::Hit)
	reflected = reflect(ray.udirection, hit.normal)
    scattered = Ray(hit.p, reflected + m.fuzz * random_in_unit_sphere())
	dot(scattered.direction, hit.normal) > 0 ? (scattered, m.albedo) : (Ray(), zero(Color))
end

struct Dielectric <: Material
	ir::Float64
end

function scatter(d::Dielectric, ray::Ray, hit::Hit)

	function reflectance(cosine, ratio)
		r = ((1-ratio) / (1+ratio))^2
		r + (1-r)*(1 - cosine)^5
	end

	refraction_ratio = hit.front_face ? (1.0/d.ir) : d.ir

	cos_theta = min(dot(-ray.udirection, hit.normal), 1.0)
	sin_theta = sqrt(1.0 - cos_theta^2)
	cannot_refract = refraction_ratio * sin_theta > 1.0
	direction = if cannot_refract || reflectance(cos_theta, refraction_ratio) > rand()
			reflect(ray.udirection, hit.normal)
		else
			refract(ray.udirection, hit.normal, refraction_ratio)
		end

	Ray(hit.p, direction), Color(1,1,1)
end


text:
"""
    DensityMatrix

Density matrix, represented with respect to identity and Pauli basis (σ_j/2) by storing
4 real coefficients for each qubit, i.e., a real vector of length `4^N` for `N` qubits.
"""
struct DensityMatrix
    "coefficients with respect to identity and Pauli basis"
    v::Vector{Float64}
    "number of qubits"
    N::Int

    @doc """
        DensityMatrix(v::AbstractVector{<:Real}, N::Integer)

    Density matrix representation given Pauli-vector dotted with with vector of coefficients
    """
    function DensityMatrix(v::AbstractVector{<:Real}, N::Integer)
        length(v) == 4^N || error("Expected length of coefficient vector for density matrix is `4^N`.")
        new(v, N)
    end

    @doc """
        DensityMatrix(v::AbstractVector{<:Real})

    Density matrix representation given Pauli-vector dotted with with vector of coefficients
    """
    function DensityMatrix(v::AbstractVector{<:Real})
        N = intlog2(length(v)) ÷ 2
        length(v) == 4^N || error("Expected length of coefficient vector for density matrix is `4^N` for some integer `N`.")
        new(v, N)
    end
end

"""
    matrix(ρ::DensityMatrix)

Matrix representation of density matrix `ρ`.
"""
function matrix(ρ::DensityMatrix)
    # Pauli matrix basis (including identity matrix)
    halfpauli = SparseMatrixCSC{ComplexF64,Int}[
        0.5 * sparse(one(ComplexF64)*I, 2, 2),
        0.5 * sparse_matrix(X),
        0.5 * sparse_matrix(Y),
        0.5 * sparse_matrix(Z),
    ]
    mat = zeros(ComplexF64, 2^ρ.N, 2^ρ.N)
    m = quaternary_digits(ρ.N, 0)
    for i in 1:4^ρ.N
        mat += ρ.v[i] * kron([halfpauli[p + 1] for p in reverse(quaternary_digits!(m, i - 1))]...)
    end
    return mat
end

"""
    density_from_statevector(ψ::Vector)

Construct density matrix |ψ⟩⟨ψ| (Pauli representation) corresponding to quantum state `ψ`.
```jldoctest
julia> ψ = 1/sqrt(2)[1, -1]; # create ket - state.
julia> ρ = density_from_statevector(ψ)
DensityMatrix([0.9999999999999998, -0.9999999999999998, 0.0, 0.0], 1)
```
"""
function density_from_statevector(ψ::Vector)
    N = intlog2(length(ψ))
    2^N == length(ψ) || error("Length of input vector must be a power to 2.")
    pauli = SparseMatrixCSC{ComplexF64,Int}[
        sparse(one(ComplexF64)*I, 2, 2),
        sparse_matrix(X),
        sparse_matrix(Y),
        sparse_matrix(Z),
    ]
    v = zeros(4^N)
    m = quaternary_digits(N, 0)
    for i in 1:4^N
        v[i] = real(dot(ψ, kron([pauli[p + 1] for p in reverse(quaternary_digits!(m, i - 1))]...) * ψ))
    end
    return DensityMatrix(v, N)
end

"""
    density_from_matrix(ρmat::AbstractMatrix)

Construct density matrix in Pauli representation from matrix `ρmat`.
```jldoctest
julia> ρmat = 0.15 .*[ 1 -1; -1  1] + 0.35 .* [1 1; 1 1]; # create mixed state of + and -.
julia> ρ = density_from_matrix(ρmat)
DensityMatrix([1.0, 0.39999999999999997, 0.0, 0.0], 1)
```
"""
function density_from_matrix(ρmat::AbstractMatrix)
    N = intlog2(size(ρmat, 1))
    (2^N == size(ρmat, 1) && 2^N == size(ρmat, 2)) || error("Input must be a square `2^N × 2^N` matrix.")
    pauli = SparseMatrixCSC{ComplexF64,Int}[
        sparse(one(ComplexF64)*I, 2, 2),
        sparse_matrix(X),
        sparse_matrix(Y),
        sparse_matrix(Z),
    ]
    v = zeros(4^N)
    m = quaternary_digits(N, 0)
    for i in 1:4^N
        v[i] = real(tr(kron([pauli[p + 1] for p in reverse(quaternary_digits!(m, i - 1))]...) * ρmat))
    end
    return DensityMatrix(v, N)
end

"""
    pauli_group_matrix(ipauli)

Construct a Pauli group matrix (N-fold tensor products of identity and Pauli matrices)
encoded as `DensityMatrix`. `ipauli[j]` specifies the j-th matrix as integer 0,...,3.
"""
function pauli_group_matrix(ipauli::AbstractVector{<:Integer})
    i4 = Matrix{Int}(I, 4, 4)
    DensityMatrix(kron([2 * i4[i + 1, :] for i in reverse(ipauli)]...), length(ipauli))
end

function pauli_group_matrix(paulistring::String)
    pd = Dict('I' => 0, 'X' => 1, 'Y' => 2, 'Z' => 3)
    pauli_group_matrix([pd[s] for s in paulistring])
end