text:
# an implementation of Uniform Manifold Approximation and Projection
# for Dimension Reduction, L. McInnes, J. Healy, J. Melville, 2018.

# NOTE: unused for now
struct UMAP_{S <: Real, M <: AbstractMatrix{S}, N <: AbstractMatrix{S}}
    graph::M
    embedding::N

    function UMAP_{S, M, N}(graph, embedding) where {S<:Real,
                                                     M<:AbstractMatrix{S},
                                                     N<:AbstractMatrix{S}}
        issymmetric(graph) || isapprox(graph, graph') || error("UMAP_ constructor expected graph to be a symmetric matrix")
        new(graph, embedding)
    end
end
function UMAP_(graph::M, embedding::N) where {S <: Real,
                                              M <: AbstractMatrix{S},
                                              N <: AbstractMatrix{S}}
    return UMAP_{S, M, N}(graph, embedding)
end

const SMOOTH_K_TOLERANCE = 1e-5

"""
    umap(X::AbstractMatrix[, n_components=2]; <kwargs>) -> embedding

Embed the data `X` into a `n_components`-dimensional space. `n_neighbors` controls
how many neighbors to consider as locally connected.

# Keyword Arguments
- `n_neighbors::Integer = 15`: the number of neighbors to consider as locally connected. Larger values capture more global structure in the data, while small values capture more local structure.
- `metric::{SemiMetric, Symbol} = Euclidean()`: the metric to calculate distance in the input space. It is also possible to pass `metric = :precomputed` to treat `X` like a precomputed distance matrix.
- `n_epochs::Integer = 300`: the number of training epochs for embedding optimization
- `learning_rate::Real = 1`: the initial learning rate during optimization
- `init::Symbol = :spectral`: how to initialize the output embedding; valid options are `:spectral` and `:random`
- `min_dist::Real = 0.1`: the minimum spacing of points in the output embedding
- `spread::Real = 1`: the effective scale of embedded points. Determines how clustered embedded points are in combination with `min_dist`.
- `set_operation_ratio::Real = 1`: interpolates between fuzzy set union and fuzzy set intersection when constructing the UMAP graph (global fuzzy simplicial set). The value of this parameter should be between 1.0 and 0.0: 1.0 indicates pure fuzzy union, while 0.0 indicates pure fuzzy intersection.
- `local_connectivity::Integer = 1`: the number of nearest neighbors that should be assumed to be locally connected. The higher this value, the more connected the manifold becomes. This should not be set higher than the intrinsic dimension of the manifold.
- `repulsion_strength::Real = 1`: the weighting of negative samples during the optimization process.
- `neg_sample_rate::Integer = 5`: the number of negative samples to select for each positive sample. Higher values will increase computational cost but result in slightly more accuracy.
- `a = nothing`: this controls the embedding. By default, this is determined automatically by `min_dist` and `spread`.
- `b = nothing`: this controls the embedding. By default, this is determined automatically by `min_dist` and `spread`.
"""
function umap(args...; kwargs...)
    # this is just a convenience function for now
    return UMAP_(args...; kwargs...).embedding
end

function UMAP_(X::AbstractMatrix{S},
               n_components::Integer = 2;
               n_neighbors::Integer = 15,
               metric::Union{SemiMetric, Symbol} = Euclidean(),
               n_epochs::Integer = 300,
               learning_rate::Real = 1,
               init::Symbol = :spectral,
               min_dist::Real = 1//10,
               spread::Real = 1,
               set_operation_ratio::Real = 1,
               local_connectivity::Integer = 1,
               repulsion_strength::Real = 1,
               neg_sample_rate::Integer = 5,
               a::Union{Real, Nothing} = nothing,
               b::Union{Real, Nothing} = nothing
               ) where {S<:Real}
    # argument checking
    size(X, 2) > n_neighbors > 0|| throw(ArgumentError("size(X, 2) must be greater than n_neighbors and n_neighbors must be greater than 0"))
    size(X, 1) > n_components > 1 || throw(ArgumentError("size(X, 1) must be greater than n_components and n_components must be greater than 1"))
    n_epochs > 0 || throw(ArgumentError("n_epochs must be greater than 0"))
    learning_rate > 0 || throw(ArgumentError("learning_rate must be greater than 0"))
    min_dist > 0 || throw(ArgumentError("min_dist must be greater than 0"))
    0 ≤ set_operation_ratio ≤ 1 || throw(ArgumentError("set_operation_ratio must lie in [0, 1]"))
    local_connectivity > 0 || throw(ArgumentError("local_connectivity must be greater than 0"))

    # main algorithm
    graph = fuzzy_simplicial_set(X, n_neighbors, metric, local_connectivity, set_operation_ratio)

    embedding = initialize_embedding(graph, n_components, Val(init))

    embedding = optimize_embedding(graph, embedding, n_epochs, learning_rate, min_dist, spread, repulsion_strength, neg_sample_rate)
    # TODO: if target variable y is passed, then construct target graph
    #       in the same manner and do a fuzzy simpl set intersection

    return UMAP_(graph, embedding)
end

"""
    fuzzy_simplicial_set(X, n_neighbors, metric, local_connectivity, set_op_ratio) -> graph::SparseMatrixCSC

Construct the local fuzzy simplicial sets of each point in `X` by
finding the approximate nearest `n_neighbors`, normalizing the distances
on the manifolds, and converting the metric space to a simplicial set.
"""
function fuzzy_simplicial_set(X,
                              n_neighbors,
                              metric,
                              local_connectivity,
                              set_operation_ratio)

    knns, dists = knn_search(X, n_neighbors, metric)

    σs, ρs = smooth_knn_dists(dists, n_neighbors, local_connectivity)

    rows, cols, vals = compute_membership_strengths(knns, dists, σs, ρs)
    fs_set = sparse(rows, cols, vals, size(knns, 2), size(knns, 2))

    res = combine_fuzzy_sets(fs_set, set_operation_ratio)

    return dropzeros(res)
end

"""
    smooth_knn_dists(dists, k, local_connectivity; <kwargs>) -> knn_dists, nn_dists

Compute the distances to the nearest neighbors for a continuous value `k`. Returns
the approximated distances to the kth nearest neighbor (`knn_dists`)
and the nearest neighbor (nn_dists) from each point.
"""
function smooth_knn_dists(knn_dists::AbstractMatrix{S},
                          k::Real,
                          local_connectivity::Real;
                          niter::Integer=64,
                          bandwidth::Real=1) where {S <: Real}

    nonzero_dists(dists) = @view dists[dists .> 0.]
    ρs = zeros(S, size(knn_dists, 2))
    σs = Array{S}(undef, size(knn_dists, 2))
    for i in 1:size(knn_dists, 2)
        nz_dists = nonzero_dists(knn_dists[:, i])
        if length(nz_dists) >= local_connectivity
            index = floor(Int, local_connectivity)
            interpolation = local_connectivity - index
            if index > 0
                ρs[i] = nz_dists[index]
                if interpolation > SMOOTH_K_TOLERANCE
                    ρs[i] += interpolation * (nz_dists[index+1] - nz_dists[index])
                end
            else
                ρs[i] = interpolation * nz_dists[1]
            end
        elseif length(nz_dists) > 0
            ρs[i] = maximum(nz_dists)
        end
        @inbounds σs[i] = smooth_knn_dist(knn_dists[:, i], ρs[i], k, bandwidth, niter)
    end

    return ρs, σs
end

# calculate sigma for an individual point
@fastmath function smooth_knn_dist(dists::AbstractVector, ρ, k, bandwidth, niter)
    target = log2(k)*bandwidth
    lo, mid, hi = 0., 1., Inf
    for n in 1:niter
        psum = sum(exp.(-max.(dists .- ρ, 0.)./mid))
        if abs(psum - target) < SMOOTH_K_TOLERANCE
            break
        end
        if psum > target
            hi = mid
            mid = (lo + hi)/2.
        else
            lo = mid
            if hi == Inf
                mid *= 2.
            else
                mid = (lo + hi) / 2.
            end
        end
    end
    # TODO: set according to min k dist scale
    return mid
end

"""
    compute_membership_strengths(knns, dists, σs, ρs) -> rows, cols, vals

Compute the membership strengths for the 1-skeleton of each fuzzy simplicial set.
"""
function compute_membership_strengths(knns::AbstractMatrix{S},
                                      dists::AbstractMatrix{T},
                                      ρs::Vector{T},
                                      σs::Vector{T}) where {S <: Integer, T}
    # set dists[i, j]
    rows = sizehint!(S[], length(knns))
    cols = sizehint!(S[], length(knns))
    vals = sizehint!(T[], length(knns))
    for i in 1:size(knns, 2), j in 1:size(knns, 1)
        @inbounds if i == knns[j, i] # dist to self
            d = 0.
        else
            @inbounds d = exp(-max(dists[j, i] - ρs[i], 0.)/σs[i])
        end
        append!(cols, i)
        append!(rows, knns[j, i])
        append!(vals, d)
    end
    return rows, cols, vals
end

function initialize_embedding(graph::AbstractMatrix{T}, n_components, ::Val{:spectral}) where {T}
    local embed
    try
        embed = spectral_layout(graph, n_components)
        # expand
        expansion = 10 / maximum(embed)
        @. embed = (embed*expansion) + (1//10000)*randn(T, size(embed))
    catch e
        print("Error encountered in spectral_layout; defaulting to random layout\n")
        embed = initialize_embedding(graph, n_components, Val(:random))
    end
    return embed
end

function initialize_embedding(graph::AbstractMatrix{T}, n_components, ::Val{:random}) where {T}
    return 20 .* rand(T, n_components, size(graph, 1)) .- 10
end

"""
    optimize_embedding(graph, embedding, n_epochs, initial_alpha, min_dist, spread, gamma, neg_sample_rate) -> embedding

Optimize an embedding by minimizing the fuzzy set cross entropy between the high and low dimensional simplicial sets using stochastic gradient descent.

# Arguments
- `graph`: a sparse matrix of shape (n_samples, n_samples)
- `embedding`: a dense matrix of shape (n_components, n_samples)
- `n_epochs`: the number of training epochs for optimization
- `initial_alpha`: the initial learning rate
- `gamma`: the repulsive strength of negative samples
- `neg_sample_rate::Integer`: the number of negative samples per positive sample
"""
function optimize_embedding(graph,
                            embedding,
                            n_epochs,
                            initial_alpha,
                            min_dist,
                            spread,
                            gamma,
                            neg_sample_rate,
                            _a=nothing,
                            _b=nothing)
    a, b = fit_ab(min_dist, spread, _a, _b)

    alpha = initial_alpha
    for e in 1:n_epochs

        @inbounds for i in 1:size(graph, 2)
            for ind in nzrange(graph, i)
                j = rowvals(graph)[ind]
                p = nonzeros(graph)[ind]
                if rand() <= p
                    @views sdist = evaluate(SqEuclidean(), embedding[:, i], embedding[:, j])
                    if sdist > 0
                        delta = (-2 * a * b * sdist^(b-1))/(1 + a*sdist^b)
                    else
                        delta = 0
                    end
                    @simd for d in 1:size(embedding, 1)
                        grad = clamp(delta * (embedding[d,i] - embedding[d,j]), -4, 4)
                        embedding[d,i] += alpha * grad
                        embedding[d,j] -= alpha * grad
                    end

                    for _ in 1:neg_sample_rate
                        k = rand(1:size(graph, 2))
                        @views sdist = evaluate(SqEuclidean(),
                                                embedding[:, i], embedding[:, k])
                        if sdist > 0
                            delta = (2 * gamma * b) / ((1//1000 + sdist)*(1 + a*sdist^b))
                        elseif i == k
                            continue
                        else
                            delta = 0
                        end
                        @simd for d in 1:size(embedding, 1)
                            if delta > 0
                                grad = clamp(delta * (embedding[d, i] - embedding[d, k]), -4, 4)
                            else
                                grad = 4
                            end
                            embedding[d, i] += alpha * grad
                        end
                    end

                end
            end
        end
        alpha = initial_alpha*(1 - e//n_epochs)
    end

    return embedding
end

"""
    spectral_layout(graph, embed_dim) -> embedding

Initialize the graph layout with spectral embedding.
"""
function spectral_layout(graph::SparseMatrixCSC{T},
                         embed_dim::Integer) where {T<:Real}
    D_ = Diagonal(dropdims(sum(graph; dims=2); dims=2))
    D = inv(sqrt(D_))
    # normalized laplacian
    # TODO: remove sparse() when PR #30018 is merged
    L = sparse(Symmetric(I - D*graph*D))

    k = embed_dim+1
    num_lanczos_vectors = max(2k+1, round(Int, sqrt(size(L, 1))))
    # get the 2nd - embed_dim+1th smallest eigenvectors
    eigenvals, eigenvecs = eigs(L; nev=k,
                                   ncv=num_lanczos_vectors,
                                   which=:SR,
                                   tol=1e-4,
                                   v0=ones(T, size(L, 1)),
                                   maxiter=size(L, 1)*5)
    layout = permutedims(eigenvecs[:, 2:k])::Array{T, 2}
    return layout
end


text:
mutable struct arf_struct
    exponent::UInt      # fmpz
    size::UInt          # mp_size_t
    mantissa1::UInt     # mantissa_struct of length 128
    mantissa2::UInt

    function arf_struct()
        res = new()
        init!(res)
        finalizer(clear!, res)
        return res
    end

    function arf_struct(x::Union{UInt,Int})
        res = new()
        init_set!(res, x)
        finalizer(clear!, res)
        return res
    end
end

mutable struct mag_struct
    exponent::UInt       # fmpz
    mantissa::UInt       # mp_limb_t

    function mag_struct()
        res = new()
        init!(res)
        finalizer(clear!, res)
        return res
    end

    function mag_struct(x::Union{mag_struct,arf_struct,Ptr{arf_struct}})
        res = new()
        init_set!(res, x)
        finalizer(clear!, res)
        return res
    end
end

mutable struct arb_struct
    # ┌ arf_struct (midpoint)
    exponent::UInt      # │ fmpz
    size::UInt          # │ mp_size_t
    mantissa1::UInt     # │ mantissa_struct of length 128
    mantissa2::UInt     # │
    # └
    # ┌ mag_struct (radius)
    exponent_mag::UInt  # │ fmpz
    mantissa_mag::UInt  # │ mp_limb_t
    # └

    function arb_struct()
        res = new()
        init!(res)
        finalizer(clear!, res)
        return res
    end
end

mutable struct acb_struct
    # ┌ arb_struct (real)
    exponent_r::UInt      # │ fmpz
    size_r::UInt          # │ mp_size_t
    mantissa1_r::UInt     # │ mantissa_struct of length 128
    mantissa2_r::UInt     # │
    exp_mag_r::Int        # │ fmpz
    mantissa_mag_r::UInt  # │ mp_limb_t
    # └
    # ┌ arb_struct (imag)
    exponent_i::Int       # │ fmpz
    size_i::UInt          # │ mp_size_t
    mantissa1_i::UInt     # │ mantissa_struct of length 128
    mantissa2_i::UInt     # │
    exp_mag_i::Int        # │ fmpz
    mantissa_mag_i::UInt  # │ mp_limb_t
    # └
    function acb_struct()
        res = new()
        init!(res)
        finalizer(clear!, res)
        return res
    end
end

mutable struct arb_vec_struct
    entries::Ptr{arb_struct}
    n::Int

    function arb_vec_struct(n::Integer)
        v = new(ccall(@libarb(_arb_vec_init), Ptr{arb_struct}, (Int,), n), n)
        finalizer(clear!, v)
        return v
    end
end

mutable struct acb_vec_struct
    entries::Ptr{acb_struct}
    n::Int

    function acb_vec_struct(n::Integer)
        v = new(ccall(@libarb(_acb_vec_init), Ptr{acb_struct}, (Int,), n), n)
        finalizer(clear!, v)
        return v
    end
end

mutable struct arb_poly_struct
    coeffs::Ptr{arb_struct}
    length::Int
    alloc::Int

    function arb_poly_struct()
        poly = new()
        init!(poly)
        finalizer(clear!, poly)
        return poly
    end
end

mutable struct acb_poly_struct
    coeffs::Ptr{acb_struct}
    length::Int
    alloc::Int

    function acb_poly_struct()
        poly = new()
        init!(poly)
        finalizer(clear!, poly)
        return poly
    end
end

mutable struct arb_mat_struct
    entries::Ptr{arb_struct}
    r::Int
    c::Int
    rows::Ptr{Ptr{arb_struct}}

    function arb_mat_struct(r::Integer, c::Integer)
        A = new()
        init!(A, r, c)
        finalizer(clear!, A)
        return A
    end
end

mutable struct acb_mat_struct
    entries::Ptr{acb_struct}
    r::Int
    c::Int
    rows::Ptr{Ptr{acb_struct}}

    function acb_mat_struct(r::Integer, c::Integer)
        A = new()
        init!(A, r, c)
        finalizer(clear!, A)
        return A
    end
end

const ArbStructTypes = Union{
    arf_struct,
    arb_struct,
    acb_struct,
    arb_vec_struct,
    acb_vec_struct,
    arb_poly_struct,
    acb_poly_struct,
    arb_mat_struct,
    acb_mat_struct,
}

mutable struct calc_integrate_opt_struct
    deg_limit::Int
    eval_limit::Int
    depth_limit::Int
    use_heap::Cint
    verbose::Cint

    function calc_integrate_opt_struct(
        deg_limit::Integer,
        eval_limit::Integer,
        depth_limit::Integer,
        use_heap::Integer = 0,
        verbose::Integer = 0,
    )
        return new(deg_limit, eval_limit, depth_limit, use_heap, verbose)
    end

    function calc_integrate_opt_struct()
        opts = new()
        ccall(
            @libarb(acb_calc_integrate_opt_init),
            Cvoid,
            (Ref{calc_integrate_opt_struct},),
            opts,
        )
        return opts
    end
end

ext: jl


text:
const Vec = AbstractVector{<:Real}
const VecVec = AbstractVector{<:AbstractVector}
const NumOrVec = Union{Real, Vec}
const VecOrNum = NumOrVec
const Mat = AbstractMatrix{<:Real}

const Vec64 = Vector{Float64}
const NumOrVec64 = Union{Float64, Vec64}

const VecF = AbstractVector{<:AbstractFloat}
const NumOrVecF = Union{AbstractFloat, VecF}
const MIN_PRECISION = Float32

ensure_vec(x :: AbstractVector ) = x
ensure_vec(x :: Number) = [x,]


text:
using Base.Test
using MathProgComplex

## Application of the Moment–SOS Approach to Global Optimization of the OPF Problem
# C. Josz, J. Maeght, P. Panciatici, and J. Ch. Gilbert
# https://arxiv.org/pdf/1311.6370.pdf
# Data from table 1, p. 11.

@testset "WB2 real formulation - order 1" begin
    sols = SortedDict(0.976 => (2, 905.76, 905.76),
                      0.983 => (2, 905.73, 903.12),
                      0.989 => (2, 905.73, 900.84),
                      0.996 => (2, 905.73, 898.17),
                      1.002 => (2, 905.73, 895.86),
                      1.009 => (2, 905.73, 893.16),
                      1.015 => (2, 905.73, 890.82),
                      1.022 => (3, 905.73, 888.08),
                      1.028 => (3, 905.73, 885.71),
                      1.035 => (2, 882.97, 882.97))

    testfolder = joinpath(Pkg.dir("MathProgComplex"), "Mosek_runs", "tests")
    @testset "v2max=$v2max, rmeqs=$rmeqs" for (v2max, (dmax, obj_fixedphase, obj_rankrel)) in sols, rmeqs in Set([true, false])

        # info("Working on WB2, no eqs, v2max=$v2max, d=$d")
        problem = buildPOP_WB2(v2max=v2max, rmeqs=rmeqs)

        logpath = joinpath(testfolder, "WB2_v2max_$(v2max)_rankrel")
        ispath(logpath) && rm(logpath, recursive=true); mkpath(logpath)
        println("Saving file at $logpath")

        relax_ctx = set_relaxation(problem; hierarchykind=:Real,
                                            d = 1)

        primobj, dualobj = run_hierarchy(problem, relax_ctx, logpath, save_pbs=true);
        @test primobj ≈ obj_rankrel atol=1e-2
        @test dualobj ≈ primobj atol=mosek_optgap*min(abs(primobj), abs(dualobj))
    end
end


text:
################################################################################
# This set of functions houses OpenMendel's keyword's default values
# and processes the user-defined keywords that specify
# the external files to read and the analyses to perform.
################################################################################
#
# Required external packages.
#
# using Distributions
# using GLM
#
# Required OpenMendel packages and modules.
#
# using DataStructures
# using MendelSearch

const DOUBLE_QUOTE_CHAR = Char(34) # to avoid coloring bugs in editors
const MENDEL_COMMENTS = r"[#!]" # of type Regex; indicates either a ! or #

export process_keywords!, set_keyword_defaults!

"""
This function processes the keywords from the control file or command line.
"""
function process_keywords!(keyword::Dict{AbstractString, Any},
                           control_file::AbstractString, args)
  #
  # If the user did not specify any control file or keywords as command line
  # arguments, then simply write out a logo and quit.
  #
  if control_file == "" && length(args) == 0
    println("OpenMendel is a package for the statistical analysis of")
    println("genetic data.")
    println(" \nThe data input files can be listed either on the command")
    println("line or in a named control file.")
##    println(" \nFor more information, please see the documentation at")
##    println("http://www.genetics.ucla.edu/software/Mendel_current_doc.pdf")
    println(" \n")
    throw(ArgumentError(
      "No genetic data was specified, so no analysis was performed."))
    return nothing
  end
  #
  # Start the set of modified_keywords at the empty set.
  #
  set_of_modified_keywords = Set{AbstractString}()
  #
  # Modify the keywords using the commands in the Control file. This will
  # change the working directory to the directory containing the Control file.
  #
  if control_file != ""
    keyword["control_file"] = control_file
    push!(set_of_modified_keywords, "control_file")
    open_control_file!(keyword)
    read_control_file!(keyword, set_of_modified_keywords)
  end
  #
  # Modify the keywords using the function arguments.
  #
  if length(args) != 0
    read_args!(keyword, set_of_modified_keywords, args)
  end
  #
  # Make any necessary revisions of the keywords.
  #
  revise_keywords!(keyword, set_of_modified_keywords)
  #
  # Open the output file and list the user-modified keywords.
  #
  open_output_file!(keyword)
  list_modified_keywords(keyword, set_of_modified_keywords)
  #
  # Initialize the random number generator.
  #
  Random.seed!(keyword["seed"])
  return nothing
end # process_keywords!

"""
This function constructs a dictionary of the basic keywords
and assignes them their default values. Keywords specific
to an analysis option should be first declared at the marked position
in the source code for that analysis option.
"""
function set_keyword_defaults!(keyword::Dict{AbstractString, Any})
  #
  # Set the user-modifiable keywords using the format:
  # keyword["some_keyword_name"] = default_value
  #
  keyword["affected_designator"] = "1"
  keyword["allele_pseudo_count"] = 0.1
  keyword["allele_separator"] = "/\\" # first character is used in output
  keyword["analysis_option"] = ""
  keyword["complexity_threshold"] = 5e7
  keyword["control_file"] = ""
  keyword["eliminate_genotypes"] = false
  keyword["female"] = Set{Any}(["female", "f", 'f', "2", '2', 2])
  keyword["field_separator"] = ','
  keyword["genetic_map_function"] = "Haldane" # "Haldane" or "Kosambi"
  keyword["locus_file"] = ""
  keyword["lump_alleles"] = false
  keyword["male"] = Set{Any}(["male", "m", 'm', "1", '1', 1])
  keyword["missing_value"] = Set{AbstractString}(["NA"])
  keyword["mutation"] = "" # a vector of tuples:
   # example: mutation = [("rh","+","-",1e-6,1e-5), ("abo","a","o",1e-7,1e-7)]
   # Vector{Tuple{AbstractString, AbstractString, AbstractString, Real, Real}}()
  keyword["new_pedigree_file"] = ""
  keyword["ordered_allele_separator"] = "|" # first character is used in output
  keyword["output_file"] = "Mendel_Output.txt"
  keyword["pedigree_file"] = ""
  keyword["phenotype_file"] = ""
  keyword["plink_field_separator"] = ' '
  keyword["plink_input_basename"] = ""
  keyword["plink_missing_value"] = Set{AbstractString}(["NA"])
  keyword["plink_output_basename"] = ""
  keyword["populations"] = Set{AbstractString}()
  keyword["product_mode"] = true
##  keyword["shortblank_ismissingdata"] = true
  keyword["snpdata_file"] = ""
  keyword["snpdefinition_file"] = ""
  keyword["trait"] = ""
  keyword["output_field_separator"] = keyword["field_separator"]
  keyword["output_missing_value"] = "NA"
## For imputation:
##  keyword["gradient_provided"] = false
##  keyword["reference_haplotypes"] = 0
##  keyword["window_width"] = 200 # width of imputation window
  #
  # Set the default seed for the random number generator
  # based on the current time, that is, to a random number.
  #
  keyword["seed"] = Int(floor(mod(time()*10000, 100000)))
# keyword["seed"] = 1234
  #
  # Add default optimization keywords from package Search.
  #
  keyword = optimization_keywords!(keyword)
  #
  # Non-user-modifiable keywords.
  #
  keyword["keywords_naming_general_sets"] =
    Set{AbstractString}(["female", "male"])
  keyword["keywords_naming_string_sets"] =
    Set{AbstractString}(["populations", "missing_value", "plink_missing_value"])

  return keyword
end # function set_keyword_defaults!

"""
This function reads the keywords from the command line arguments.
"""
function read_args!(keyword::Dict{AbstractString, Any},
                    set_of_modified_keywords::Set{AbstractString}, args)
  for arg in args
    (keyword_symbol, value) = arg
    keyword_string = "$keyword_symbol"
    if !isascii(keyword_string)
      throw(ArgumentError(
        "The specified keyword $keyword_string is not recognized.\n \n"))
    end
    keyword_string = lowercase(keyword_string)
    keyword_string = replace(keyword_string, '-' => '_')
    if haskey(keyword, keyword_string)
      keyword[keyword_string] = value
      push!(set_of_modified_keywords, keyword_string)
    else
      throw(ArgumentError(
        "The specified keyword $keyword_string is not a known keyword.\n \n"))
    end
    #
    # If a Control file is listed at any point, immediately
    # modify the keywords using the commands in the Control file.
    #
    if keyword_string == "control_file"
      open_control_file!(keyword)
      read_control_file!(keyword, set_of_modified_keywords)
    end
  end
  return
end # function read_args!

"""
This function revises the keywords based on the set of modified keywords.
"""
function revise_keywords!(keyword::Dict{AbstractString, Any},
                          set_of_modified_keywords::Set{AbstractString})
  #
  # Turn strings containing the names of distribution or link functions
  # into the named functions themselves.
  #
  if "distribution" in set_of_modified_keywords
    distribution_name = keyword["distribution"]
    if isa(distribution_name, AbstractString)
      keyword["distribution"] =
        eval(Meta.parse(distribution_name, raise = false))
    end
  end
  if "link" in set_of_modified_keywords
    link_name = keyword["link"]
    if isa(link_name, AbstractString)
      keyword["link"] = eval(Meta.parse(link_name, raise = false))
    end
  end
  #
  # Turn each field separator into a character.
  #
  if "field_separator" in set_of_modified_keywords
    keyword["field_separator"] = keyword["field_separator"][1]
    if !("output_field_separator" in set_of_modified_keywords)
      keyword["output_field_separator"] = keyword["field_separator"]
    end
  end
  if "plink_field_separator" in set_of_modified_keywords
    keyword["plink_field_separator"] = keyword["plink_field_separator"][1]
  end
  if "output_field_separator" in set_of_modified_keywords
    keyword["output_field_separator"] = keyword["output_field_separator"][1]
  end
  #
  # If a Plink input files basename has been provided,
  # set the appropriate filenames.
  #
  if "plink_input_basename" in set_of_modified_keywords
    plink_basename = keyword["plink_input_basename"]
    if !("snpdefinition_file" in set_of_modified_keywords)
      keyword["snpdefinition_file"] = string(plink_basename, ".bim")
      push!(set_of_modified_keywords, "snpdefinition_file")
    end
    if !("snpdata_file" in set_of_modified_keywords)
      keyword["snpdata_file"] = string(plink_basename, ".bed")
      push!(set_of_modified_keywords, "snpdata_file")
    end
    if !("pedigree_file" in set_of_modified_keywords)
      keyword["pedigree_file"] = string(plink_basename, ".fam")
      push!(set_of_modified_keywords, "pedigree_file")
    end
  end
  #
  # If the affected designator has been modified, make sure it is a string.
  # If it's not been modified and the pedigree is a Plink .fam file,
  # then change the affected designator to "2".
  #
  if "affected_designator" in set_of_modified_keywords
    keyword["affected_designator"] = string(keyword["affected_designator"])
  elseif occursin(".fam", keyword["pedigree_file"])
    keyword["affected_designator"] = "2"
    push!(set_of_modified_keywords, "affected_designator")
  end
  #
  # If the user has modified any of the keywords that take a set of strings
  # as its value, then form the set from the list of comma separated strings
  # that should have been assigned as the keyword's value.
  # Note that each string is stripped of leading and trailing spaces.
  #
  for keyword_string in
    intersect(keyword["keywords_naming_string_sets"], set_of_modified_keywords)
    set_of_strings =
      Set{AbstractString}(split(keyword[keyword_string], ',';
                                keepempty = false))
    new_set = Set{AbstractString}()
    for element_string in set_of_strings
      element_string = strip(element_string, ' ')
      element_string = strip(element_string, DOUBLE_QUOTE_CHAR)
      element_string = strip(element_string, ' ')
      push!(new_set, element_string)
    end
    keyword[keyword_string] = new_set
  end
  #
  # If the user has modified any of the keywords that take a set of items
  # as its value, then form the set from the list of comma separated items
  # that should have been assigned as the keyword's value.
  # Note that the list of items can include strings, chars, and numbers.
  #
  for keyword_string in
    intersect(keyword["keywords_naming_general_sets"], set_of_modified_keywords)
    set_of_strings =
      Set{AbstractString}(split(keyword[keyword_string], ',';
                                keepempty = false))
    new_set = Set{Any}()
    for element_string in set_of_strings
      element_string = strip(element_string, ' ')
      if isa(Meta.parse(element_string, raise = false), Number)
        element_item = Meta.parse(element_string)
      elseif isa(Meta.parse(element_string, raise = false), Char)
        element_item = Meta.parse(element_string)
      else
        element_item = strip(element_string, DOUBLE_QUOTE_CHAR)
        element_item = strip(element_item, ' ')
      end
      push!(new_set, element_item)
    end
    keyword[keyword_string] = new_set
  end
  #
  # Make sure the field separator is not a missing value string.
  #
  if in(string(keyword["field_separator"]),
        keyword["missing_value"])
    throw(ArgumentError("Input field_separator is missing_value string.\n \n"))
  end
  if in(string(keyword["plink_field_separator"]),
        keyword["plink_missing_value"])
    throw(ArgumentError("Plink field_separator is missing_value string.\n \n"))
  end
  if string(keyword["output_field_separator"]) ==
        keyword["output_missing_value"]
    throw(ArgumentError("Output field_separator is missing_value string.\n \n"))
  end
  #
  # If the output missing value keyword was modified, make sure it is a string.
  #
##   if "missing_value" in set_of_modified_keywords
##     keyword["missing_value"] = string(keyword["missing_value"])
##     if !("output_missing_value" in set_of_modified_keywords)
##       keyword["output_missing_value"] = keyword["missing_value"]
##     end
##   end
##   if "plink_missing_value" in set_of_modified_keywords
##     keyword["plink_missing_value"] = string(keyword["plink_missing_value"])
##   end
  if "output_missing_value" in set_of_modified_keywords
    keyword["output_missing_value"] = string(keyword["output_missing_value"])
  end
  #
  # A named analysis option used to be mandatory.
  #
  # if !("analysis_option" in set_of_modified_keywords)
  #   throw(ArgumentError("No analysis option was specified.\n \n"))
  # end
  #
  # A pedigree file is mandatory.
  #
  if !("pedigree_file" in set_of_modified_keywords)
    throw(ArgumentError("No pedigree file was named.\n \n"))
  end
  return
end # function revise_keywords!

"""
This function reads the keywords from the Control file.
"""
function read_control_file!(keyword::Dict{AbstractString, Any},
                    set_of_modified_keywords::Set{AbstractString})
  #
  # Parse the Control file line by line.
  #
  control_unit = keyword["control_unit"]
  for keyline in eachline(control_unit)
    keyline = chomp(keyline) # remove trailing "newline" characters
    keyline = rstrip(keyline, '\r') # remove trailing "return" characters
    keyline = strip(keyline) # remove leading and trailing whitespace
    if length(keyline) == 0; continue; end
    #
    # Delete from comment characters to the end of the line.
    #
    comment_position = first(something(findfirst(MENDEL_COMMENTS, keyline), 0))
    if comment_position == 1
      keyline = ""
    elseif comment_position > 1
      keyline = keyline[1:comment_position-1]
    end
    keyline = strip(keyline) # remove leading and trailing whitespace
    if length(keyline) == 0; continue; end
    #
    # Split keyline into keyword_string and value_string.
    #
    equalsign_position = findfirst(isequal('='), keyline)
    if equalsign_position == nothing
      throw(ArgumentError(
        """The specified keyword line "$keyline" has no equals sign.\n \n"""))
    end
    keyword_string = strip(keyline[1:equalsign_position-1])
    value_string = strip(keyline[equalsign_position+1:end])
    if length(keyword_string) == 0
      throw(ArgumentError(
        """The specified keyword line "$keyline" contains no keyword.\n \n"""))
    end
    #
    # Test whether the keyword string is valid.
    #
    if !isascii(keyword_string)
      throw(ArgumentError(
        "The specified keyword $keyword_string is not recognized.\n \n"))
    end
    keyword_string = lowercase(keyword_string)
    keyword_string = replace(keyword_string, '-' => '_')
    if !haskey(keyword, keyword_string)
      throw(ArgumentError(
        "The specified keyword $keyword_string is not a known keyword.\n \n"))
    end
    #
    # Convert keyword value from a SubString{String} to a String,
    # which is the required type for some functions, e.g., CSV.write.
    # ?? Is this still necessary ??
    #
    value_string = replace(value_string, ' ' => ' ')
    #
    # Check whether the keyword value is valid,
    # allow a blank value at field separators and missing value strings.
    #
    if length(value_string) == 0
      if keyword_string == "field_separator" ||
         keyword_string == "plink_field_separator" ||
         keyword_string == "output_field_separator"
        value_string = " "
      elseif keyword_string == "missing_value" ||
             keyword_string == "plink_missing_value" ||
             keyword_string == "output_missing_value"
        value_string = ""
      else
        throw(ArgumentError(
        """The keyword line "$keyline" contains no key-value.\n \n"""))
      end
    end
    #
    # To prevent possible infinite loops, ignore the keyword control_file.
    #
    if keyword_string == "control_file"; continue; end
    #
    # Change the value_string into a boolean or number, if appropriate.
    # Strip value_string of any leading or trailing double-quote characters.
    # Record that value in the keyword dictionary. If the value parses as
    # a character, e.g., "'a'", change the assigned value to that character.
    #
    lc_value_string = lowercase(value_string)
    if lc_value_string == "true" || lc_value_string == "t"
      keyword[keyword_string] = true
    elseif lc_value_string == "false" || lc_value_string == "f"
      keyword[keyword_string] = false
    elseif isa(Meta.parse(value_string, raise = false), Number)
      keyword[keyword_string] = Meta.parse(value_string)
    elseif keyword_string in keyword["keywords_naming_string_sets"]
      keyword[keyword_string] = strip(value_string, ' ')
    elseif keyword_string in keyword["keywords_naming_general_sets"]
      keyword[keyword_string] = strip(value_string, ' ')
    else
      keyword[keyword_string] = strip(value_string, DOUBLE_QUOTE_CHAR)
      if isa(Meta.parse(keyword[keyword_string], raise = false), Char)
        keyword[keyword_string] = Meta.parse(keyword[keyword_string])
      end
    end
    #
    # Record this keyword as being modified by the user.
    #
    push!(set_of_modified_keywords, keyword_string)
  #
  # Procede to next line of the Control file.
  #
  end
  close(control_unit)
  return
end #function read_control_file!

"""
This function opens the Control file for reading.
It also sets the current working directory to
the directory that contains the Control file.
"""
function open_control_file!(keyword::Dict{AbstractString, Any})
  #
  # First, check that the named control file exists and is readable.
  #
  control_file = keyword["control_file"]
  if isfile(control_file)
    #
    # Second, close any previously opened control file.
    #
    if haskey(keyword, "control_unit")
      control_unit = keyword["control_unit"]
      if isopen(control_unit); close(control_unit); end
    end
    #
    # Finally, open the new control file and move to its directory.
    #
    control_unit = open(control_file, "r")
    keyword["control_unit"] = control_unit
    control_dir = dirname(control_file)
    if (isdir(control_dir)); cd(control_dir); end
  else
    throw(ArgumentError(
      """The named control file "$control_file" is not readable.\n \n"""))
  end
  return
end # function open_control_file!

"""
This function opens the output file.
"""
function open_output_file!(keyword::Dict{AbstractString, Any})
  #
  #  Check that the output file is writable. If so, open it.
  #
  output_file = keyword["output_file"]
  if output_file != ""
    output_unit = open(output_file, "w")
    keyword["output_unit"] = output_unit
  end
##  if isfile(output_file) && iswritable(output_file)
##    output_unit = open(output_file, "w")
##    keyword["output_unit"] = output_unit
##  elseif isfile(output_file) && !iswriteable(output_file)
##    throw(ArgumentError(
##      """The named output file "$output_file" is not writable.\n \n"""))
##  elseif iswritable(pwd())
##    output_unit = open(output_file, "w")
##    keyword["output_unit"] = output_unit
##  else
##    throw(ArgumentError(
##      """The named output file "$output_file" is not writable.\n \n"""))
##  end
  return
end # function open_output_file!

"""
This function outputs the list of user-modified keywords.
"""
function list_modified_keywords(keyword::Dict{AbstractString, Any},
                    set_of_modified_keywords::Set{AbstractString})

  output_unit = keyword["output_unit"]
  #
  # First output the current working directory.
  #
  working_dir = pwd()
  println("""The current working directory is "$working_dir".\n""")
  #
  # Output list of all the user-modified keywords.
  #
  if length(set_of_modified_keywords) != 0
    println("Keywords modified by the user:\n")
    for keyword_string in sort(collect(set_of_modified_keywords))
      value = keyword[keyword_string]
      println("  $keyword_string = $value")
    end
    print(" \n")
  else
    println(" OpenMendel is using all the keywords at their default values.\n")
  end
  return
end # function list_modified_keywords

max_stars_repo_name: OpenMendel/MendelBase

max_issues_repo_name: OpenMendel/MendelBase

max_forks_repo_name: OpenMendel/MendelBase


text:
struct HexagonalPrism{T} <: AbstractVolumePrimitive{T, 3} ## Only upright hexagons at the moment
    rInner::T
    rOuter::T
    h::T #total height
    translate::Union{CartesianVector{T}, Missing}#origin at middle of hexagonal prism
end

# You also have to implement the function to obtain the primitive from a config file (so an dic)
# You also should provide a example config file containing this new primitive
function HexagonalPrism{T}(dict::Union{Dict{Any, Any}, Dict{String, Any}}, inputunit_dict::Dict{String,Unitful.Units})::HexagonalPrism{T} where {T <: SSDFloat}
    # ... parse values from dict to NewPrimitive{T}(...)
    if haskey(dict, "translate")
        translate::CartesianPoint{T} = CartesianPoint{T}(
            haskey(dict["translate"],"x") ? geom_round(ustrip(uconvert(u"m", T(dict["translate"]["x"]) * inputunit_dict["length"] ))) : T(0),
            haskey(dict["translate"],"y") ? geom_round(ustrip(uconvert(u"m", T(dict["translate"]["y"]) * inputunit_dict["length"] ))) : T(0),
            haskey(dict["translate"],"z") ? geom_round(ustrip(uconvert(u"m", T(dict["translate"]["z"]) * inputunit_dict["length"] ))) : T(0))
    else
        translate = missing
    end
    rInner, rOuter = if haskey(dict["r"], "from")
        geom_round(ustrip(uconvert(u"m", T(dict["r"]["from"]) * inputunit_dict["length"] ))), geom_round(ustrip(uconvert(u"m", T(dict["r"]["to"]) * inputunit_dict["length"])))
    else
        geom_round(0), geom_round(ustrip(uconvert(u"m", T(dict["r"]["to"]) * inputunit_dict["length"])))
    end
    h::T = ustrip(uconvert(u"m", dict["h"] * inputunit_dict["length"]))
    return HexagonalPrism{T}(rInner, rOuter, h, translate)
end

# is a point inside the hexagonal prism?
function in(pt::CartesianPoint{T}, hp::HexagonalPrism{T})::Bool where {T}
    pt = ismissing(hp.translate) ? pt : pt - hp.translate
    cpt = CylindricalPoint(pt) #shift pt to prism's frame
    minRadInner = sqrt(3)/2*hp.rInner
    minRadOuter = sqrt(3)/2*hp.rOuter
    # Use hexagonal symmetry to sweep the point into a basic triangle
    angle = if (mod(cpt.φ ÷ (π/6), 2) > 0) π/6 - mod(cpt.φ, (π/6)) else mod(cpt.φ, (π/6)) end

    return abs(pt.z) <= hp.h/2 && # Within the height
            cpt.r <= hp.rOuter && # within outer radius
            if cpt.r >= minRadInner # Inside minimal inner radius
                ((cpt.r*cos(angle) >= minRadInner) && (cpt.r*cos(angle) <= minRadOuter))
            else # Inside inner radius
                false
            end
end

function in(pt::CylindricalPoint{T}, hp::HexagonalPrism{T})::Bool where {T}
    return in(CartesianPoint(pt), hp)
end

function Geometry(T::DataType, t::Val{:HexagonalPrism}, dict::Dict{Any, Any}, inputunit_dict::Dict{String,Unitful.Units})
    return HexagonalPrism{T}(dict, inputunit_dict)
end

# add a (+) method to shift the primitive
function (+)(hp::HexagonalPrism{T}, translate::Union{CartesianVector{T}, Missing})::HexagonalPrism{T} where {T <: SSDFloat}
    if ismissing(translate)
        return hp
    elseif ismissing(hp.translate)
        return HexagonalPrism(hp.rInner, hp.rOuter, hp.h, translate)
    else
        return HexagonalPrism(hp.rInner, hp.rOuter, hp.h, hp.translate + translate)
    end
end

# Also a plot recipe for this new primitive should be provided:
@recipe function f(hp::HexagonalPrism{T}) where {T <: SSDFloat}
    label --> "HexagonalPrism"
    @series begin
        pts_top_outer = []
        pts_bottom_outer = []
        pts_top_inner = []
        pts_bottom_inner = []

        #find all vertices, this loop has been tested and works
        for φ in [deg2rad(30),deg2rad(90), deg2rad(150), deg2rad(210), deg2rad(270), deg2rad(330)]
            pt_top_outer = CartesianPoint{T}(hp.translate.x + hp.rOuter * cos(φ), hp.translate.y + hp.rOuter * sin(φ), hp.translate.z + hp.h/2)
            push!(pts_top_outer, pt_top_outer)
            pt_top_inner = CartesianPoint{T}(hp.translate.x + hp.rInner * cos(φ), hp.translate.y + hp.rInner * sin(φ), hp.translate.z + hp.h/2)
            push!(pts_top_inner, pt_top_inner)
            pt_bottom_outer = CartesianPoint{T}(hp.translate.x + hp.rOuter * cos(φ), hp.translate.y + hp.rOuter * sin(φ), hp.translate.z -hp.h/2)
            push!(pts_bottom_outer, pt_bottom_outer)
            pt_bottom_inner = CartesianPoint{T}(hp.translate.x + hp.rInner * cos(φ), hp.translate.y + hp.rInner * sin(φ), hp.translate.z -hp.h/2)
            push!(pts_bottom_inner, pt_bottom_inner)
        end

        #create Linesegments connecting the vertices
        lines = LineSegment{T, 3, :cartesian}[]
        N = length(pts_top_outer)
        for i in 1:N
            push!(lines, LineSegment(pts_top_outer[i%N+1], pts_top_outer[i])) #top outer hexagon
            push!(lines, LineSegment(pts_bottom_outer[i%N+1], pts_bottom_outer[i])) #bottom outer hexagon
            push!(lines, LineSegment(pts_bottom_outer[i], pts_top_outer[i])) #lines connecting outer hexagons
            if hp.rInner > 0
                push!(lines, LineSegment(pts_bottom_inner[i%N+1], pts_bottom_inner[i])) #bottom inner hexagon
                push!(lines, LineSegment(pts_top_inner[i%N+1], pts_top_inner[i])) #top inner hexagon
                push!(lines, LineSegment(pts_bottom_inner[i], pts_top_inner[i])) #lines connecting inner hexagons
                push!(lines, LineSegment(pts_top_outer[i], pts_top_inner[i])) #lines connecting hexagons
                push!(lines, LineSegment(pts_bottom_outer[i], pts_bottom_inner[i])) #lines connecting hexagons
            end
        end
        lines
    end
end

# For proper grid creation we also need the function get_important_points:
# Radial
function get_important_points(hp::HexagonalPrism{T}, ::Val{:r})::Vector{T} where {T <: SSDFloat}
    return geom_round.(T[-hp.rOuter, -sqrt(3)/2*hp.rOuter, -hp.rInner, -sqrt(3)/2*hp.rInner, 0., sqrt(3)/2*hp.rInner, hp.rInner, sqrt(3)/2*hp.rOuter, hp.rOuter] .+ sqrt(hp.translate.x^2 + hp.translate.y^2))
end

# polar angle
function get_important_points(hp::HexagonalPrism{T}, ::Val{:φ})::Vector{T} where {T <: SSDFloat}
    return T[]
end
# Z
function get_important_points(hp::HexagonalPrism{T}, ::Val{:z})::Vector{T} where {T <: SSDFloat}
    return geom_round.(T[-hp.h/2, hp.h/2] .+ hp.translate.z)
end
# X
function get_important_points(hp::HexagonalPrism{T}, ::Val{:x})::Vector{T} where {T <: SSDFloat}
    return geom_round.(T[-hp.rOuter, -sqrt(3)/2*hp.rOuter, -hp.rInner, -sqrt(3)/2*hp.rInner, 0., sqrt(3)/2*hp.rInner, hp.rInner, sqrt(3)/2*hp.rOuter, hp.rOuter] .+ hp.translate.x)
end
# Y
function get_important_points(hp::HexagonalPrism{T}, ::Val{:y})::Vector{T} where {T <: SSDFloat}
    return geom_round.(T[-hp.rOuter, -sqrt(3)/2*hp.rOuter, -hp.rInner, -sqrt(3)/2*hp.rInner, 0., sqrt(3)/2*hp.rInner, hp.rInner, sqrt(3)/2*hp.rOuter, hp.rOuter] .+ hp.translate.y)
end

#and a sample function to paint the primitive on the grid (necessary if the object is small)
function sample(hp::HexagonalPrism{T}, stepsize::Vector{T})  where T
    samples = CartesianPoint{T}[]
    for x in -hp.rOuter : stepsize[1] : hp.rOuter
        for y in -hp.rOuter : stepsize[2]: hp.rOuter
            if CartesianPoint{T}(x, y, 0) in hp
                for z in -hp.h/2 : stepsize[3] : hp.h/2
                    push!(samples, CartesianPoint{T}(x, y, z))
                end
            end
        end
    end
    ismissing(hp.translate) ? nothing : samples = map(x -> x + hp.translate, samples)
    return samples
end


text:
using QuantumInfo
using Test

using LinearAlgebra: Diagonal
import LinearAlgebra
import QuantumInfo.eye

@time @testset "partial trace" begin
    for i=1:100
        da = round(Int,round(rand()*10))+1
        db = round(Int,round(rand()*10))+1
        ra = partialtrace(projector(randn(da*3)+1im*randn(da*3)),[da,3],2)
        rb = partialtrace(projector(randn(db*3)+1im*randn(db*3)),[db,3],2)
        @test isapprox(partialtrace(kron(ra,rb),[da,db],1),rb,atol=1e-15)
        @test isapprox(partialtrace(kron(ra,rb),[da,db],2),ra,atol=1e-15)
    end
end

alteye(m::AbstractMatrix) = Diagonal(ones(eltype(m), size(m, 1)))
alteye(n::Integer) = Diagonal(ones(n))
alteye(T::DataType, n::Integer) = Diagonal(ones(T, n))

for eyesym in (:eye, :alteye)
    println("identity matrix is $(string(eyesym))")
    @eval begin
        @time @testset "representation conversion" begin
            id_choi = 1/2 .* [1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1];
            deph_choi = 1/2 .* [1 0 0 0.99;0 0 0 0;0 0 0 0;0.99 0 0 1];
            deph_liou = [1 0 0 0;0 0.99 0 0;0 0 0.99 0;0 0 0 1];

            # Kraus operators for a dephasing channel
            ρ = 0.01;
            M_0 = sqrt(1-ρ)*($eyesym)(2);
            M_1 = sqrt(ρ)*Matrix{ComplexF64}([1.0 0.0; 0.0 0.0]);
            M_2 = sqrt(ρ)*Matrix{ComplexF64}([0.0 0.0;0.0 1.0]);

            @test liou(($eyesym)(2),($eyesym)(2)) == ($eyesym)(4)
            @test liou(($eyesym)(2)) == liou(($eyesym)(2),($eyesym)(2))
            @test mat(vec(($eyesym)(2))) == ($eyesym)(2)
            @test mat([1,2,3,4]) == [1 3;2 4]
            @test vec([1 2; 3 4]) == [1,3,2,4]

            @test choi_liou_involution(choi_liou_involution(($eyesym)(4)))==($eyesym)(4)

            @test isapprox(choi2liou(id_choi),($eyesym)(4))
            @test isapprox(liou2choi(($eyesym)(4)),id_choi)
            @test isapprox(choi2kraus(id_choi),Matrix{ComplexF64}[zeros(2,2), zeros(2,2), zeros(2,2), ($eyesym)(2)],atol=1e-7)
            @test isapprox(kraus2liou(Matrix{ComplexF64}[($eyesym)(2)]),($eyesym)(4))
            @test isapprox(liou2kraus(($eyesym)(4)),Matrix{ComplexF64}[zeros(2,2), zeros(2,2), zeros(2,2), ($eyesym)(2)],atol=1e-7)
            @test isapprox(kraus2choi(Matrix{ComplexF64}[($eyesym)(2)]),id_choi)

            @test isapprox(kraus2choi([M_0, M_1, M_2]),deph_choi)
            @test isapprox(kraus2liou([M_0, M_1, M_2]),deph_liou)

            @test isapprox(liou2pauliliou(($eyesym)(4)), ($eyesym)(4))
            @test isapprox(pauliliou2liou(($eyesym)(4)), ($eyesym)(4))
        end
    end
end

@testset "Pauli-Liouville" begin
    # we expect an X90 to transform +X => +X, +Z => -Y, +Y => +Z
    X90 = exp(-1im*π/4*[0 1;1 0])
    @test liou2pauliliou(liou(X90)) ≈ [1 0 0 0;
                                       0 1 0 0;
                                       0 0 0 -1;
                                       0 0 1 0]

    # liou2pauliliou and pauliliou2liou should be inverses
    @test pauliliou2liou(liou2pauliliou(liou(X90))) ≈ liou(X90)
end

@time @testset "depolarization" begin
    @test isapprox(depol(2),projector(vec(eye(2))),atol=1e-15)
    @test isapprox(depol(2),depol(2,1.))
    @test isapprox(depol(2,0.),eye(4),atol=1e-15)
end

@time @testset "density matrix properties" begin
  for i=1:100
    rrho = partialtrace(projector(randn(3^3)+1im*randn(3^3)),[3,9],2)
    @test isapprox(LinearAlgebra.tr(rrho),1.)
    @test QuantumInfo.ishermitian(rrho)
    @test ispossemidef(rrho)

    ru = LinearAlgebra.svd(randn(3,3)+1im*randn(3,3)).U
    @test isapprox(ru*ru',eye(3),atol=1e-13)
    @test isapprox(ru'*ru,eye(3),atol=1e-13)

    rv = LinearAlgebra.svd(randn(3,3)+1im*randn(3,3)).U
    re = (liou(ru)+liou(rv))/2
    @test ispossemidef(liou2choi(re),tol=1e-13)
    @test isapprox(partialtrace(liou2choi(re),[3,3],2),eye(3)/3,atol=1e-15)
  end
end


text:
module prata

# File Path to this file.
LIBRARY = string(@__DIR__,"/prata")

```
This connect to a master on IP and Port,
The IP will be a string
The Port will be a UInt16
Returns a pointer to the master
```
function connect(IP, Port)

    tmp = split(IP,".")
    tmp1 = parse(UInt32,tmp[1])
    tmp2 = parse(UInt32,tmp[2])
    tmp3 = parse(UInt32,tmp[3])
    tmp4 = parse(UInt32,tmp[4])
    ip = (tmp1 << 24) + (tmp2 << 16) + (tmp3 << 8) + (tmp4)

    return @eval ccall(
        (:connectJ, #function
        $LIBRARY), #lib
        Ptr{Cvoid}, #return
        (UInt32, UInt16), #input type
        $ip,$Port); #input

end

```
This will set the threading option on a master
m will be the object return from connect
thread is a boolean true for turning threading on
```
function setThreading(m, thread)
    @eval ccall(
        (:setThread, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Bool), #input type
        $m,$thread); #input
end

```
This will create a subscriber
m is the object returned from connect
Returns a pointer to the subscriber
```
function subscriber(m)
    return @eval ccall(
        (:subscriberJ, #function
        $LIBRARY), #lib
        Ptr{Cvoid}, #return
        (Ptr{Cvoid},), #input type
        $m) #input
end

```
This will create a publisher
m is the object returned from connect
Returns a pointer to the publisher
```
function publisher(m)
    return @eval ccall(
        (:publisherJ, #function
        $LIBRARY), #lib
        Ptr{Cvoid}, #return
        (Ptr{Cvoid},), #input type
        $m) #input
end

```
This will host a master starting a Prata network
m is the obejct returned from connect
```
function host(m)
    @eval ccall(
        (:hostJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid},), #input type
        $m); #input
end

```
This will terminate a master stopping a Prata network
m is the object returned from connect
```
function terminate(m)
    @eval ccall(
        (:terminateJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid},), #input type
        $m); #input
end

```
This will return the json of the Prata network m is attached to
this can be used to view what the network looks like without the GUI
m is the objet returned from connect
Returns the json as a string
```
function serialize(m)
    tmp = @eval ccall(
        (:serializeJ, #function
        $LIBRARY), #lib
        Cstring, #return
        (Ptr{Cvoid},), #input type
        $m);

    ret = unsafe_string(deepcopy(tmp))

    @eval ccall(
        (:freeString, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Cstring,), #input type
        $tmp);

    return ret #input
end

```
This will set the port ranges of a Prata network
m is the object return from connect
lower is the lower bounds of the range
upper is the upper bounds of the range
```
function setPortRanges(m, lower, upper)
    @eval ccall(
        (:setThread, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, UInt16, UInt16), #input type
        $m, $lower, $upper); #input
end

```
This will create a new channel
m is the object returned from connect
port is the port the channel will be hosted on
style is the style, either FIFO or BROADCAST
messageLimit is the amount of buffer size the channel has
```
function createChannel(m, port, name, style, messageLimit)
     @eval ccall(
        (:createChannelJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, UInt16, Cstring, Cstring, UInt32), #input type
        $m, $port, $name, $style, $messageLimit); #input
end

```
This will get all available channel types in a Prta network
m is the object returned from connect
```
function getChannelTypes(m)
     @eval ccall(
        (:getChannelTypesJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid},), #input type
        $m); #input
end

```
This will connect a publisher to a channel
p is the object returned from publisher
name is the channel to connect to
```
function publisherConnect(p, name)
     @eval ccall(
        (:connectPJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Cstring), #input type
        $p, $name); #input
end

```
This will connect a subscriber to a channel
s is the object returned from subscriber
name is the channel to connect to
```
function subscriberConnect(s, name)
     @eval ccall(
        (:connectSJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Cstring), #input type
        $s, $name); #input
end

```
This will disconnect a publiser from a channel
p is the object returned from publisher
name is the channel to disconnect from
```
function publisherDisconnect(p, name)
     @eval ccall(
        (:connectPJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Cstring), #input type
        $p, $name); #input
end

```
This will disconnect a subscriber from a channel
s is the object returned from subscriber
name is the channel to disconnect from
```
function subscriberDisconnect(s, name)
     @eval ccall(
        (:connectSJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Cstring), #input type
        $s, $name); #input
end

```
This will publish data to a channel
p is the publisher that will send the data
chan is the channel name to send to
msg is the data to be sent
```
function publish(p, chan, msg)
     @eval ccall(
        (:publishJ, #function
        $LIBRARY), #lib
        Cvoid, #return
        (Ptr{Cvoid}, Cstring, Cstring), #input type
        $p, $chan, $msg); #input
end

```
This will listen data from a channel
s is the susbcriber that will take the data
chan is the channel name to take from
returning a string for the message contents
```
function listen(s, chan)
        tmp = @eval ccall(
            (:listenJ, #function
            $LIBRARY), #lib
            Cstring, #return
            (Ptr{Cvoid}, Cstring), #input type
            $s, $chan);

        ret = unsafe_string(deepcopy(tmp))
        @eval ccall(
            (:freeString, #function
            $LIBRARY), #lib
            Cvoid, #return
            (Cstring,), #input type
            $tmp);

        return ret #input

end
end # module

max_stars_repo_name: roboscienceorg/Prata

max_issues_repo_name: roboscienceorg/Prata

max_forks_repo_name: roboscienceorg/Prata


text:
png_error_handler(::Ptr{Cvoid}, msg::Cstring) = error("Png error: $msg")
png_warn_handler(::Ptr{Cvoid}, msg::Cstring) = warn("Png warn: $msg")
const png_error_fn = @cfunction(png_error_handler, Cvoid, (Ptr{Cvoid}, Cstring))
const png_warn_fn = @cfunction(png_warn_handler, Cvoid, (Ptr{Cvoid}, Cstring))

# Returns the libpng version string
function get_libpng_version()
    ver = png_access_version_number()
    # Version in the format of xxyyzz, where x=major, yy=minor, z=release
    # But on the major version the first x is excluded if 0.
    dig = digits(ver)[end:-1:1]
    length(dig) == 5 ? prepend!(dig, 0) : error("Unknown libpng version: $ver")

    @inbounds major = dig[1] == 0 ? string(dig[2]) : string(dig[1], dig[2])
    @inbounds minor = dig[3] == 0 ? string(dig[4]) : string(dig[3], dig[4])
    @inbounds release = dig[5] == 0 ? string(dig[6]) : string(dig[5], dig[6])

    return "$major.$minor.$release"
end

function open_png(filename::String)
    fp = ccall(:fopen, Ptr{Cvoid}, (Cstring, Cstring), filename, "rb")
    fp == C_NULL && error("Failed to open $filename")

    header = zeros(UInt8, PNG_BYTES_TO_CHECK)
    header_size = ccall(:fread, Csize_t, (Ptr{UInt8}, Cint, Cint, Ptr{Cvoid}), header, 1, PNG_BYTES_TO_CHECK, fp)
    header_size != 8 && error("Failed to read header from $filename")

    is_png = png_sig_cmp(header, 0, PNG_BYTES_TO_CHECK)
    is_png != 0 && error("File $filename is not a png file")

    return fp
end

function create_read_struct()
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, C_NULL, png_error_fn, png_warn_fn)
    png_ptr == C_NULL && error("Failed to create png read struct")
    return png_ptr
end

function create_info_struct(png_ptr)
    info_ptr = png_create_info_struct(png_ptr)
    info_ptr == C_NULL && error("Failed to create png info struct")
    return info_ptr
end

close_png(fp::Ptr{Cvoid}) = ccall(:fclose, Cint, (Ptr{Cvoid},), fp)

# Write functions
function create_write_struct(png_error_fn::Ptr{Cvoid}, png_warn_fn::Ptr{Cvoid})
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, C_NULL, png_error_fn, png_warn_fn)
    png_ptr == C_NULL && error("Failed to create png write struct")
    return png_ptr
end


text:
#==============================================================================#
# IoT1ClickDevicesService.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/iot1click-devices-2018-05-14.normal.json
#==============================================================================#

__precompile__()

module IoT1ClickDevicesService

using AWSCore

"""
    using AWSSDK.IoT1ClickDevicesService.claim_devices_by_claim_code
    claim_devices_by_claim_code([::AWSConfig], arguments::Dict)
    claim_devices_by_claim_code([::AWSConfig]; claimCode=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "PUT", "/claims/{claimCode}", arguments::Dict)
    devices([::AWSConfig], "PUT", "/claims/{claimCode}", claimCode=)

# ClaimDevicesByClaimCode Operation

Adds device(s) to your account (i.e., claim one or more devices) if and only if you received a claim code with the device(s).

# Arguments

## `claimCode = ::String` -- *Required*
The claim code, starting with "C-", as provided by the device manufacturer.

# Returns

`ClaimDevicesByClaimCodeResponse`

# Exceptions

`InvalidRequestException`, `InternalFailureException` or `ForbiddenException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/ClaimDevicesByClaimCode)
"""
@inline claim_devices_by_claim_code(aws::AWSConfig=default_aws_config(); args...) = claim_devices_by_claim_code(aws, args)

@inline claim_devices_by_claim_code(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "PUT", "/claims/{claimCode}", args)

@inline claim_devices_by_claim_code(args) = claim_devices_by_claim_code(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.describe_device
    describe_device([::AWSConfig], arguments::Dict)
    describe_device([::AWSConfig]; deviceId=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "GET", "/devices/{deviceId}", arguments::Dict)
    devices([::AWSConfig], "GET", "/devices/{deviceId}", deviceId=)

# DescribeDevice Operation

Given a device ID, returns a DescribeDeviceResponse object describing the details of the device.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

# Returns

`DescribeDeviceResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/DescribeDevice)
"""
@inline describe_device(aws::AWSConfig=default_aws_config(); args...) = describe_device(aws, args)

@inline describe_device(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "GET", "/devices/{deviceId}", args)

@inline describe_device(args) = describe_device(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.finalize_device_claim
    finalize_device_claim([::AWSConfig], arguments::Dict)
    finalize_device_claim([::AWSConfig]; deviceId=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/finalize-claim", arguments::Dict)
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/finalize-claim", deviceId=)

# FinalizeDeviceClaim Operation

Given a device ID, finalizes the claim request for the associated device.

**Note**
> Claiming a device consists of initiating a claim, then publishing a device event, and finalizing the claim. For a device of type button, a device event can be published by simply clicking the device.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

# Returns

`FinalizeDeviceClaimResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException`, `InternalFailureException`, `PreconditionFailedException` or `ResourceConflictException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/FinalizeDeviceClaim)
"""
@inline finalize_device_claim(aws::AWSConfig=default_aws_config(); args...) = finalize_device_claim(aws, args)

@inline finalize_device_claim(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "PUT", "/devices/{deviceId}/finalize-claim", args)

@inline finalize_device_claim(args) = finalize_device_claim(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.get_device_methods
    get_device_methods([::AWSConfig], arguments::Dict)
    get_device_methods([::AWSConfig]; deviceId=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "GET", "/devices/{deviceId}/methods", arguments::Dict)
    devices([::AWSConfig], "GET", "/devices/{deviceId}/methods", deviceId=)

# GetDeviceMethods Operation

Given a device ID, returns the invokable methods associated with the device.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

# Returns

`GetDeviceMethodsResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/GetDeviceMethods)
"""
@inline get_device_methods(aws::AWSConfig=default_aws_config(); args...) = get_device_methods(aws, args)

@inline get_device_methods(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "GET", "/devices/{deviceId}/methods", args)

@inline get_device_methods(args) = get_device_methods(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.initiate_device_claim
    initiate_device_claim([::AWSConfig], arguments::Dict)
    initiate_device_claim([::AWSConfig]; deviceId=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/initiate-claim", arguments::Dict)
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/initiate-claim", deviceId=)

# InitiateDeviceClaim Operation

Given a device ID, initiates a claim request for the associated device.

**Note**
> Claiming a device consists of initiating a claim, then publishing a device event, and finalizing the claim. For a device of type button, a device event can be published by simply clicking the device.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

# Returns

`InitiateDeviceClaimResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException`, `InternalFailureException` or `ResourceConflictException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/InitiateDeviceClaim)
"""
@inline initiate_device_claim(aws::AWSConfig=default_aws_config(); args...) = initiate_device_claim(aws, args)

@inline initiate_device_claim(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "PUT", "/devices/{deviceId}/initiate-claim", args)

@inline initiate_device_claim(args) = initiate_device_claim(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.invoke_device_method
    invoke_device_method([::AWSConfig], arguments::Dict)
    invoke_device_method([::AWSConfig]; deviceId=, <keyword arguments>)

    using AWSCore.Services.devices
    devices([::AWSConfig], "POST", "/devices/{deviceId}/methods", arguments::Dict)
    devices([::AWSConfig], "POST", "/devices/{deviceId}/methods", deviceId=, <keyword arguments>)

# InvokeDeviceMethod Operation

Given a device ID, issues a request to invoke a named device method (with possible parameters). See the "Example POST" code snippet below.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

## `deviceMethod = [ ... ]`
The device method to invoke.
```
 deviceMethod = [
        "deviceType" =>  ::String,
        "methodName" =>  ::String
    ]
```

## `deviceMethodParameters = ::String`
A JSON encoded string containing the device method request parameters.

# Returns

`InvokeDeviceMethodResponse`

# Exceptions

`InvalidRequestException`, `PreconditionFailedException`, `InternalFailureException`, `ResourceNotFoundException`, `RangeNotSatisfiableException` or `ResourceConflictException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/InvokeDeviceMethod)
"""
@inline invoke_device_method(aws::AWSConfig=default_aws_config(); args...) = invoke_device_method(aws, args)

@inline invoke_device_method(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "POST", "/devices/{deviceId}/methods", args)

@inline invoke_device_method(args) = invoke_device_method(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.list_device_events
    list_device_events([::AWSConfig], arguments::Dict)
    list_device_events([::AWSConfig]; deviceId=, fromTimeStamp=, toTimeStamp=, <keyword arguments>)

    using AWSCore.Services.devices
    devices([::AWSConfig], "GET", "/devices/{deviceId}/events", arguments::Dict)
    devices([::AWSConfig], "GET", "/devices/{deviceId}/events", deviceId=, fromTimeStamp=, toTimeStamp=, <keyword arguments>)

# ListDeviceEvents Operation

Using a device ID, returns a DeviceEventsResponse object containing an array of events for the device.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

## `fromTimeStamp = timestamp` -- *Required*
The start date for the device event query, in ISO8061 format. For example, 2018-03-28T15:45:12.880Z

## `maxResults = ::Int`
The maximum number of results to return per request. If not set, a default value of 100 is used.

## `nextToken = ::String`
The token to retrieve the next set of results.

## `toTimeStamp = timestamp` -- *Required*
The end date for the device event query, in ISO8061 format. For example, 2018-03-28T15:45:12.880Z

# Returns

`ListDeviceEventsResponse`

# Exceptions

`ResourceNotFoundException`, `RangeNotSatisfiableException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/ListDeviceEvents)
"""
@inline list_device_events(aws::AWSConfig=default_aws_config(); args...) = list_device_events(aws, args)

@inline list_device_events(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "GET", "/devices/{deviceId}/events", args)

@inline list_device_events(args) = list_device_events(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.list_devices
    list_devices([::AWSConfig], arguments::Dict)
    list_devices([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.devices
    devices([::AWSConfig], "GET", "/devices", arguments::Dict)
    devices([::AWSConfig], "GET", "/devices", <keyword arguments>)

# ListDevices Operation

Lists the 1-Click compatible devices associated with your AWS account.

# Arguments

## `deviceType = ::String`
The type of the device, such as "button".

## `maxResults = ::Int`
The maximum number of results to return per request. If not set, a default value of 100 is used.

## `nextToken = ::String`
The token to retrieve the next set of results.

# Returns

`ListDevicesResponse`

# Exceptions

`RangeNotSatisfiableException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/ListDevices)
"""
@inline list_devices(aws::AWSConfig=default_aws_config(); args...) = list_devices(aws, args)

@inline list_devices(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "GET", "/devices", args)

@inline list_devices(args) = list_devices(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.unclaim_device
    unclaim_device([::AWSConfig], arguments::Dict)
    unclaim_device([::AWSConfig]; deviceId=)

    using AWSCore.Services.devices
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/unclaim", arguments::Dict)
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/unclaim", deviceId=)

# UnclaimDevice Operation

Disassociates a device from your AWS account using its device ID.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

# Returns

`UnclaimDeviceResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/UnclaimDevice)
"""
@inline unclaim_device(aws::AWSConfig=default_aws_config(); args...) = unclaim_device(aws, args)

@inline unclaim_device(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "PUT", "/devices/{deviceId}/unclaim", args)

@inline unclaim_device(args) = unclaim_device(default_aws_config(), args)

"""
    using AWSSDK.IoT1ClickDevicesService.update_device_state
    update_device_state([::AWSConfig], arguments::Dict)
    update_device_state([::AWSConfig]; deviceId=, <keyword arguments>)

    using AWSCore.Services.devices
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/state", arguments::Dict)
    devices([::AWSConfig], "PUT", "/devices/{deviceId}/state", deviceId=, <keyword arguments>)

# UpdateDeviceState Operation

Using a Boolean value (true or false), this operation enables or disables the device given a device ID.

# Arguments

## `deviceId = ::String` -- *Required*
The unique identifier of the device.

## `enabled = ::Bool`
If true, the device is enabled. If false, the device is disabled.

# Returns

`UpdateDeviceStateResponse`

# Exceptions

`ResourceNotFoundException`, `InvalidRequestException` or `InternalFailureException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/devices-2018-05-14/UpdateDeviceState)
"""
@inline update_device_state(aws::AWSConfig=default_aws_config(); args...) = update_device_state(aws, args)

@inline update_device_state(aws::AWSConfig, args) = AWSCore.Services.devices(aws, "PUT", "/devices/{deviceId}/state", args)

@inline update_device_state(args) = update_device_state(default_aws_config(), args)

end # module IoT1ClickDevicesService

#==============================================================================#
# End of file
#==============================================================================#


text:
import Base: IteratorSize, HasLength, IsInfinite, length

struct FinitePeriodTrigger <: AbstractFiniteTrigger
    td::Dates.Period
    n::Int
end

struct InfinitePeriodTrigger <: AbstractInfiniteTrigger
    td::Dates.Period
end

"""
    PeriodTrigger(t::Dates.Time[, n=number_of_times])

A trigger which should trigger a job after a given period (`DatePeriod` or `TimePeriod`)

# Optional parameter
- `n=1`: trigger once
- `n=-1` (default): trigger every day indefinitely
- `n=value`: trigger just a number of times
"""
function PeriodTrigger(td; n=-1)
    if n < 0
        InfinitePeriodTrigger(td)
    else
        FinitePeriodTrigger(td, n)
    end
end

"""
    Trigger(td::Dates.Period[, n=number_of_times])

Return an `PeriodTrigger` which should trigger a job after a given period (`DatePeriod` or `TimePeriod`).
"""
Trigger(td::Dates.Period; kwargs...) = PeriodTrigger(td; kwargs...)

function get_next_dt_fire(trigger::Union{FinitePeriodTrigger,InfinitePeriodTrigger}, dt_previous_fire, dt_now)
    if dt_previous_fire == DateTime(0)
        dt_now + trigger.td
    else
        dt_previous_fire + trigger.td
    end
end


text:
module EasyDataAugmentation

export substite_string
export easy_data_augmentation

include("generate_augmented_sentences.jl")

end


text:
"""
The `ZChop` module provides the functions `zchop`, `zchop!`, `nchop`, and `nchop!`.
"""
module ZChop

export zchop, zchop!
export nchop, nchop!

const PassAtom = Union{AbstractString, AbstractChar, Symbol, Number}

#### _copy

_copy(x) = deepcopy(x)
_copy(x::PassAtom) = x
_copy(x::Array{<:Number}) = copy(x)

#### applyf!

function applyf!(func, a::AbstractArray, args...; kwargs...)
    @inbounds for i in eachindex(a)
        a[i] = applyf!(func, a[i], args...; kwargs...)
    end
    return a
end

applyf!(func, x::Union{Real, Complex}, args...; kwargs...) = func(x, args...; kwargs...)
applyf!(func, x::PassAtom, args...; kwargs...) = x
applyf!(func, x::Expr, args...; kwargs...) = Expr(x.head, applyf!(func, x.args, args...; kwargs...)...)
applyf!(func, x::Tuple, args...; kwargs...) = Tuple(applyf!(func, y, args...; kwargs...) for y in x)
applyf!(func, x::Base.Generator, args...; kwargs...) = (applyf!(func, y, args...; kwargs...) for y in x)
applyf!(func, x, args...; kwargs...) = Base.isiterable(typeof(x)) ? map(y -> applyf!(func, y, args...; kwargs...) , x) : x
applyf!(func, x::Irrational, args...; kwargs...) = applyf!(func, float(x), args...; kwargs...)

"""
    ZEPS::Float64

The default lower threshold for a number to be replaced by zero.
"""
const ZEPS = 1e-14 # for zchop
const NDIGITS = 14 # for nchop

"""
    zchop!(x::T, eps::Real = ZEPS)

Perform `zchop` in place.
"""
zchop!(x, eps::Real=ZEPS) = applyf!(_zchop!, x, eps)
_zchop!(x::Real, eps::Real = ZEPS) = abs(x) > eps ? x : zero(x)
_zchop!(x::Complex, eps::Real = ZEPS) = complex(_zchop!(real(x), eps), _zchop!(imag(x), eps))

"""
    zchop(x, eps::Real = ZEPS)

Replace `x` by zero if `abs(x) < eps`.

`zchop` acts recursively on mappable objects. `zchop` acts
independently on each part of a complex number.
Objects whose components cannot be sensibly compared to a real
number are passed unaltered.

See also `zchop!`, `nchop`, and `nchop!`.
"""
zchop(x::Any, eps::Real=ZEPS) = zchop!(_copy(x), eps)

## nchop, nchop!

"""
    nchop!(x, args...; digits=14, kwargs...)

Mutating version of `nchop`.

See also `zchop` and `zchop!`.
"""
function nchop!(x, args...; digits=NDIGITS, sigdigits=nothing, kwargs...)
    if sigdigits != nothing
        digits = nothing
    end
    return applyf!(round, x, args...; digits=digits, sigdigits=sigdigits, kwargs...)
end

"""
    nchop(x, args...; digits=14, kwargs...)

Round `x` if it is a number, or elements in `x` if it is a, possibly nested, container.
`args` and `kwargs` are passed to `round`. `nchop` does not modify the input `x`.

Passing a type, for example `Int` as the first argument to `round` is not supported.

See also `zchop`, `zchop!`, and `nchop!`.
"""
nchop(x, args...; digits=NDIGITS, kwargs...) = nchop!(_copy(x), args...; digits=digits, kwargs...)

end # module ZChop


text:
using HTTP, CSV, DataFrames, Gnuplot, Random
using ColorSchemes, Colors, DataFramesMeta
url = "https://raw.githubusercontent.com/alstat/Julia-Data-Query/master/data-raw/flights.csv"
data = HTTP.download(url)
flights = CSV.read(data)
# @df flights plot(:Day, :NumFlights, group=:City)
#this is all the help you need
daily = groupby(flights, [:day, :dest]) # :origin, only 3 (boring)
per_day = @based_on(daily, flights = length(:day))
byCat = per_day.dest
categ = unique(byCat)
#some color
cmap = get(colorschemes[:plasma], LinRange(0,1,length(categ)))
# aesthetics
@gp xlab ="day" ylab = "number of flights" "set auto fix"
@gp :- title = "Flights" :-
@gp :- "set offsets graph .05, graph .05, graph .05, graph .05" :-
@gp :- "set key outside font ',8' title 'destination'" :-
@gp :- "set logscale y 2" yrange = (0.8,700)
# the actual plot
Random.seed!(213)
for (i,c) in enumerate(categ)
    indc = findall(x->x == c, byCat)
    x, y = per_day.day[indc], per_day.flights[indc]
    @gp :- x y "w p tit '$(c)' lc '#B3$(hex(cmap[i]))' pt $(rand(5:2:13)) ps 0.5"
end
save(term ="pdf size 4,5", output ="flights_points.pdf")

max_stars_repo_name: lazarusA/gnuplot-examples

max_issues_repo_name: lazarusA/gnuplot-examples

max_forks_repo_name: lazarusA/gnuplot-examples


text:
### Print a help message
println("Plot data for the photonreceptor model using:")
println(" pyplot_photonsequence()")
println(" pyplot_bump(timepoints,amplitude = 4.0,shape = 3.0,scale =2.5)")

### Plot the photon sequence data using the PyPlot package
function pyplot_photonsequence()

    #calculate the data
    photons = photonsequence(10:100,1000)
    timepoints = dataindex(photons)

    #plot the data
    fig = PyPlot.figure("functionality/photoreceptor")
    PyPlot.plot(timepoints,datavalues(photons))
    PyPlot.xlabel("Time (s)")
    PyPlot.ylabel("Photons")
    PyPlot.title("Photon Sequence")
    PyPlot.grid("on")

    #return the figure object
    fig
end

function pyplot_bump(timepoints,amplitude = 4.0,shape = 3.0,scale = 2.5)

    #calculate the data
    bmp = bump(collect(timepoints),amplitude,shape,scale)

    #plot the data
    fig = PyPlot.figure("functionality/bump")
    PyPlot.plot(timepoints/1000.0,bmp)
    PyPlot.xlabel("Time (s)")
    PyPlot.ylabel("Current (nA)")
    PyPlot.title("Photon-Induced Current")
    PyPlot.grid("on")
end

pyplot_photonsequence()
pyplot_bump(1.0:1.0:30.0)

# File return statement
nothing


text:
function answer1()
    former = -1
    ans = -1
    open("input") do file
        for line in eachline(file)
            # println(line, " ", ans)
            actual = parse(Int,line)
            if actual > former
                ans += 1
            end
            former = actual
        end
    end
    ans
end
@show answer1()

using DelimitedFiles
using Statistics
"This time is better to simply load the numbers into an array"
function answer2()
    former = -1
    ans = -1
    input = readdlm("input", Int)
    for i in eachindex(input[1:end-2])
        actual = mean(input[i:i+2])
        if actual > former
            ans += 1
        end
        former = actual
    end
    ans
end
@show answer2()


text:
begin
    x = "hoge!"
    for i = 1:5
        x = "moge!"
        println(x)
    end
    println("after for loop: ", x)
end

max_stars_repo_name: genkuroki/public

max_issues_repo_name: genkuroki/public

max_forks_repo_name: genkuroki/public