text:
export sparse_row, change_ring, dot, scale_row!, add_scaled_row

################################################################################
#
#  Parent constructor
#
################################################################################

function SRowSpace(R::Ring; cached = true)
  T = elem_type(R)
  return SRowSpace{T}(R)
end

base_ring(A::SRow{fmpz}) = FlintZZ

base_ring(A::SRow{fmpq}) = FlintQQ

function base_ring(A::SRow)
  if length(A.values) == 0
    throw(error("Base ring of empty row not defined"))
  else
    return parent(A.values[1])
  end
end

@doc Markdown.doc"""
    ==(x::SRow, y::SRow)

Checks whether $x$ and $y$ are the same sparse row, that is, whether $x$ and
$y$ have the same non-zero entries.
"""
==(x::SRow{T}, y::SRow{T}) where {T} = (x.pos == y.pos) && (x.values == y.values)

################################################################################
#
#  Sparse row creation
#
################################################################################

@doc Markdown.doc"""
    sparse_row(R::Ring) -> SRow

Constructs an empty row with base ring $R$.
"""
function sparse_row(R::Ring)
  return SRow{elem_type(R)}()
end

function SRow(R::Ring)
  return SRow{elem_type(R)}()
end

const _sort = sort
@doc Markdown.doc"""
    sparse_row(R::Ring, J::Vector{Tuple{Int, T}}) -> SRow{T}

> Constructs the sparse row $(a_i)_i$ with $a_{i_j} = x_j$, where $J = (i_j, x_j)_j$.
> The elements $x_i$ must belong to the ring $R$.
"""
function sparse_row(R::Ring, A::Vector{Tuple{Int, T}}; sort::Bool = true) where T
  if sort
    A = _sort(A, lt=(a,b) -> isless(a[1], b[1]))
  end
  return SRow{T}(A)
end

@doc Markdown.doc"""
    sparse_row(R::Ring, J::Vector{Tuple{Int, Int}}) -> SRow

Constructs the sparse row $(a_i)_i$ over $R$ with $a_{i_j} = x_j$,
where $J = (i_j, x_j)_j$.
"""
function sparse_row(R::Ring, A::Vector{Tuple{Int, Int}}; sort::Bool = true)
  if sort
    A = _sort(A, lt=(a,b)->isless(a[1], b[1]))
  end
  return SRow{elem_type(R)}(A)
end

@doc Markdown.doc"""
    sparse_row(R::Ring, J::Vector{Int}, V::Vector{T}) -> SRow{T}

Constructs the sparse row $(a_i)_i$ over $R$ with $a_{i_j} = x_j$, where
$J = (i_j)_j$ and $V = (x_j)_j$.
"""
function sparse_row(R::Ring, pos::Vector{Int}, val::Vector{T}; sort::Bool = true) where T
  if sort
    p = sortperm(pos)
    pos = pos[p]
    val = val[p]
  end
  if T === elem_type(R)
    return SRow{T}(pos, val)
  else
    mapval = map(R, val)::Vector{elem_type(R)}
    return SRow{elem_type(R)}(pos, mapval)
  end
end

################################################################################
#
#  Hashing
#
################################################################################

function hash(A::SRow, h::UInt)
  return hash(A.pos, hash(A.values, h))
end

################################################################################
#
#  String I/O
#
################################################################################

function show(io::IO, A::SRow{T}) where T
  print(io, "Sparse row with positions $(A.pos) and values $(A.values)\n")
end

################################################################################
#
#  Copy
#
################################################################################

function copy(A::SRow{T}) where T
  sr = SRow{T}()
  for (p, v) = A
    push!(sr.pos, p)
    push!(sr.values, v)
  end
  return sr
end

################################################################################
#
#  Zero row testing
#
################################################################################

@doc Markdown.doc"""
    iszero(A::SRow)

Checks whether all entries of $A$ are zero.
"""
function iszero(A::SRow)
  return length(A.pos) == 0
end

################################################################################
#
#  Modular reduction
#
################################################################################

@doc Markdown.doc"""
    mod!(A::SRow{fmpz}, n::Integer) -> SRow{fmpz}

Inplace reduction of all entries of $A$ modulo $n$ to the positive residue
system.
"""
function mod!(A::SRow{fmpz}, n::Integer)
  i=1
  while i<= length(A.pos)
    v = mod(A.values[i], n)
    if v == 0
      deleteat!(A.pos, i)
      deleteat!(A.values, i)
    else
      A.values[i] = v
      i += 1
    end
  end
  return A
end

@doc Markdown.doc"""
    mod!(A::SRow{fmpz}, n::fmpz) -> SRow{fmpz}

Inplace reduction of all entries of $A$ modulo $n$ to the positive residue
system.
"""
function mod!(A::SRow{fmpz}, n::fmpz)
  i=1
  while i<= length(A.pos)
    v = mod(A.values[i], n)
    if v == 0
      deleteat!(A.pos, i)
      deleteat!(A.values, i)
    else
      A.values[i] = v
      i += 1
    end
  end
end

# Todo: Do not convert to fmpz
@doc Markdown.doc"""
    mod_sym!(A::SRow{fmpz}, n::Integer) -> SRow{fmpz}

Inplace reduction of all entries of $A$ modulo $n$ to the symmetric residue
system.
"""
function mod_sym!(A::SRow{fmpz}, n::Integer)
  mod_sym!(A, fmpz(n))
end

@doc Markdown.doc"""
    mod_sym!(A::SRow{fmpz}, n::fmpz) -> SRow{fmpz}

Inplace reduction of all entries of $A$ modulo $n$ to the symmetric residue
system.
"""
function mod_sym!(A::SRow{fmpz}, n::fmpz)
  i=1
  while i<= length(A.pos)
    v = mod_sym(A.values[i], n)
    if v == 0
      deleteat!(A.pos, i)
      deleteat!(A.values, i)
    else
      A.values[i] = v
      i += 1
    end
  end
end

################################################################################
#
#  Change ring
#
################################################################################

function change_ring(A::SRow, f)
  iszero(A) && error("Can change ring only for non-zero rows")
  T = typeof(f(A.values[1]))
  z = SRow{T}()
  for (i, v) in A
    nv = f(v)
    if iszero(nv)
      continue
    else
      push!(z.pos, i)
      push!(z.values, nv)
    end
  end
  return z
end

@doc Markdown.doc"""
    change_ring(A::SRow, R::Ring) -> SRow

Create a new sparse row by coercing all elements into the ring $R$.
"""
function change_ring(A::SRow{T}, R::S) where {T <: RingElem, S <: Ring}
  z = SRow{elem_type(R)}()
  for (i, v) in A
    nv = R(v)
    if iszero(nv)
      continue
    else
      push!(z.pos, i)
      push!(z.values, nv)
    end
  end
  return z
end

################################################################################
#
#  Getting and setting values
#
################################################################################

# TODO:
# The list of positions is ordered, so there should be a faster find function.
@doc Markdown.doc"""
    getindex(A::SRow, j::Int) -> RingElem

Given a sparse row $(a_i)_{i}$ and an index $j$ return $a_j$.
"""
function Base.getindex(A::SRow{T}, i::Int) where {T <: RingElem}
  i < 1 && error("Index must be positive")
  p = findfirst(isequal(i), A.pos)
  if p === nothing
    return zero(base_ring(A))
  else
    return A.values[p]
  end
end

################################################################################
#
#  Make sparse row iteratable
#
################################################################################

@doc Markdown.doc"""
    length(A::SRow)

Returns the number of nonzero entries of $A$.
"""
function length(A::SRow)
  return length(A.pos)
end

function endof(A::SRow)
  return length(A.pos)
end

function Base.iterate(A::SRow, st::Int = 1)
  if st > length(A.pos)
    return nothing
  end

  return (A.pos[st], A.values[st]), st + 1
end

Base.eltype(::Type{SRow{T}}) where T = Tuple{Int, T}

Base.IteratorSize(::SRow{T}) where T = Base.HasLength()

################################################################################
#
#  Dot product
#
################################################################################

@doc Markdown.doc"""
    dot(A::SRow, B::SRow) -> RingElem

Returns the dot product of $A$ and $B$.
"""
function dot(A::SRow{T}, B::SRow{T}) where T
  @assert length(A) != 0
  v = 0*A.values[1]
  b = 1
  for a=1:length(A.pos)
    while b<=length(B.values) && B.pos[b] < A.pos[a]
      b += 1
    end
    if b>length(B.values)
      return v
    end
    if B.pos[b] == A.pos[a]
      v += B.values[b] * A.values[a]
    end
  end
  return v
end

function dot(A::SRow{T}, b::AbstractVector{T}) where {T}
  if length(b) == 0 && length(A.pos) == 0
    error("One of the vectors must have non-zero length")
  end
  if length(b) == 0
    return zero(base_ring(A))
  end
  if length(A.pos) == 0
    return zero(parent(b[1]))
  end
  s = zero(base_ring(A))
  for j=1:length(A.pos)
    s += A.values[j] * b[A.pos[j]]
  end
  return s
end

function dot(A::SRow{T}, b::AbstractVector{T}, zero::T) where {T}
  s = zero
  for j=1:length(A.pos)
    s += A.values[j] * b[A.pos[j]]
  end
  return s
end

dot(b::AbstractVector{T}, A::SRow{T}) where {T} = dot(A, b)

dot(b::AbstractVector{T}, A::SRow{T}, zero::T) where {T} = dot(A, b)

function dot(A::SRow{T}, b::MatElem{T}, i::Int) where {T}
  s = zero(base_ring(b))
  for j=1:length(A.pos)
    s += A.values[j] * b[A.pos[j], i]
  end
  return s
end

function dot(A::SRow{T}, i::Int, b::MatElem{T}) where {T}
  s = zero(base_ring(b))
  for j=1:length(A.pos)
    s += A.values[j] * b[i, A.pos[j]]
  end
  return s
end

################################################################################
#
#  Inplace scaling
#
################################################################################

function scale_row!(a::SRow{T}, b::T) where T
  @assert !iszero(b)
  if isone(b)
    return
  end
  for i=1:length(a.pos)
    a.values[i] *= b
  end
end

################################################################################
#
#  Addition
#
################################################################################

@doc Markdown.doc"""
    +(A::SRow, B::SRow) -> SRow

Returns the sum of $A$ and $B$.
"""
function +(A::SRow{T}, B::SRow{T}) where T
  if length(A.values) == 0
    return B
  elseif length(B.values) == 0
    return A
  end
  return add_scaled_row(A, B, one(base_ring(A)))
end

@doc Markdown.doc"""
    -(A::SRow, B::SRow) -> SRow

Returns the difference of $A$ and $B$.
"""
function -(A::SRow{T}, B::SRow{T}) where T
  if length(A) == 0
    if length(B) == 0
      return A
    else
      return add_scaled_row(B, A, base_ring(B)(-1))
    end
  end
  return add_scaled_row(B, A, base_ring(A)(-1))
end

@doc Markdown.doc"""
    -(A::SRow) -> SRow

Returns the negative of $A$.
"""
function -(A::SRow{T}) where {T}
  B = SRow{T}()
  for (p, v) = A
    push!(B.pos, p)
    push!(B.values, -v)
  end
  return B
end

################################################################################
#
#  Scalar operations
#
################################################################################

@doc Markdown.doc"""
    *(b::T, A::SRow{T}) -> SRow

Return the sparse row obtained by multiplying all elements of $A$ by $b$.
"""
function *(b::T, A::SRow{T}) where T
  B = SRow{T}()
  if iszero(b)
    return B
  end
  for (p,v) = A
    nv = v*b
    if !iszero(nv)  # there are zero divisors - potentially
      push!(B.pos, p)
      push!(B.values, nv)
    end
  end
  return B
end

@doc Markdown.doc"""
    *(b::Integer, A::SRow{T}) -> SRow

Return the sparse row obtained by multiplying all elements of $A$ by $b$.
"""
function *(b::Integer, A::SRow{T}) where T
  if length(A.values) == 0
    return SRow{T}()
  end
  return base_ring(A)(b)*A
end

@doc Markdown.doc"""
    div(A::SRow{T}, b::T) -> SRow

Return the sparse row obtained by dividing all elements of $A$ by $b$ using
`div`.
"""
function div(A::SRow{T}, b::T) where T
  B = SRow{T}()
  if iszero(b)
    return error("Division by zero")
  end
  for (p,v) = A
    nv = div(v, b)
    if !iszero(nv)
      push!(B.pos, p)
      push!(B.values, nv)
    end
  end
  return B
end

@doc Markdown.doc"""
    div(A::SRow{T}, b::Integer) -> SRow

Return the sparse row obtained by dividing all elements of $A$ by $b$ using
`div`.
"""
function div(A::SRow{T}, b::Integer) where T
  if length(A.values) == 0
    return SRow{T}()
  end
  return div(A, base_ring(A)(b))
end

@doc Markdown.doc"""
    divexact(A::SRow{T}, b::T) -> SRow

Return the sparse row obtained by dividing all elements of $A$ by $b$ using
`divexact`.
"""
function divexact(A::SRow{T}, b::T) where T
  B = SRow{T}()
  if iszero(b)
    return error("Division by zero")
  end
  for (p,v) = A
    nv = divexact(v, b)
    @assert !iszero(nv)
    push!(B.pos, p)
    push!(B.values, nv)
  end
  return B
end

@doc Markdown.doc"""
    divexact(A::SRow{T}, b::Integer) -> SRow

Return the sparse row obtained by dividing all elements of $A$ by $b$ using
`divexact`.
"""
function divexact(A::SRow{T}, b::Integer) where T
  if length(A.values) == 0
    return deepcopy(A)
  end
  return divexact(A, base_ring(A)(b))
end

################################################################################
#
#  Elementary row operation
#
################################################################################

@doc Markdown.doc"""
    add_scaled_row(A::SRow{T}, B::SRow{T}, c::T) -> SRow{T}

Returns the row $c A + B$.
"""
function add_scaled_row(Ai::SRow{T}, Aj::SRow{T}, c::T) where T
  sr = SRow{T}()
  pi = 1
  pj = 1
  @assert c != 0
  while pi <= length(Ai.pos) && pj <= length(Aj.pos)
    if Ai.pos[pi] < Aj.pos[pj]
      push!(sr.pos, Ai.pos[pi])
      push!(sr.values, c*Ai.values[pi])
      pi += 1
    elseif Ai.pos[pi] > Aj.pos[pj]
      push!(sr.pos, Aj.pos[pj])
      push!(sr.values, Aj.values[pj])
      pj += 1
    else
      n = c*Ai.values[pi] + Aj.values[pj]
      if n != 0
        push!(sr.pos, Ai.pos[pi])
        push!(sr.values, n)
      end
      pi += 1
      pj += 1
    end
  end
  while pi <= length(Ai.pos)
    push!(sr.pos, Ai.pos[pi])
    push!(sr.values, c*Ai.values[pi])
    pi += 1
  end
  while pj <= length(Aj.pos)
    push!(sr.pos, Aj.pos[pj])
    push!(sr.values, Aj.values[pj])
    pj += 1
  end
  return sr
end

################################################################################
#
#  Lifting
#
################################################################################

@doc Markdown.doc"""
    lift(A::SRow{nmod}) -> SRow{fmpz}

Return the sparse row obtained by lifting all entries in $A$.
"""
function lift(A::SRow{nmod})
  b = SRow{fmpz}()
  for (p,v) = A
    push!(b.pos, p)
    push!(b.values, lift(v))
  end
  return b
end

################################################################################
#
#  2-norm
#
################################################################################

@doc Markdown.doc"""
    norm2(A::SRow{T} -> T

Returns $A \cdot A^t$.
"""
function norm2(A::SRow{T}) where {T}
  return sum([x * x for x in A.values])
end

################################################################################
#
#  Maximum/minimum
#
################################################################################

@doc Markdown.doc"""
    maximum(abs, A::SRow{fmpz}) -> fmpz

Returns the largest, in absolute value, entry of $A$.
"""
function maximum(::typeof(abs), A::SRow{fmpz})
  if iszero(A)
    return zero(FlintZZ)
  end
  m = abs(A.values[1])
  for j in 2:length(A)
    if cmpabs(m, A.values[j]) < 0
      m = A.values[j]
    end
  end
  return abs(m)
end

@doc Markdown.doc"""
    maximum(A::SRow{T}) -> T

Returns the largest entry of $A$.
"""
function maximum(A::SRow)
  return maximum(A.values)
end

@doc Markdown.doc"""
    minimum(A::SRow{T}) -> T

Returns the smallest entry of $A$.
"""
function minimum(A::SRow)
  return minimum(A.values)
end


text:
# 管理不同worker上的任务，并给出进度
function auto_manger(task)
    # 总共的任务数量
    num_of_task = length(task)
    # println(num_of_task)
    # println(task[num_of_task])
    # 获取远程进程数量
    numof_workers = length(workers())
    # println(numof_workers)
    result = give_empty_dataframe_for_format()
    workersFuture = [Future(1) for i in 1:numof_workers]
    # 记录完成任务ID在列表中的位置
    c = Channel{Int64}(numof_workers)

    progress = 0.0

    # 同时启动numof_workers数量的进程
    for i in 1:numof_workers
        # println("$num_of_task")
        # @async put!(workersFuture[i], remotecall_fetch(cal_one_task, workers()[i], task[i])) & put!(c, i)
        @async begin; put!(workersFuture[i], remotecall_fetch(cal_one_task, workers()[i], task[i])); put!(c, i); end
        # println("first")
    end
    # print("？")
    # i记录了下次数据在result中存放的位置
    # (i - 1)即为已经记录的数据数量
    # 并且(i - 1 + numof_workers)为已经启动的进程数
    # 当已经启动的进程数量小于num_of_task时，不断记录已经完成任务的进程的结果，并在完成任务的进程再启动完成任务
    # 当启动num_of_task数量的进程后，等待剩余正在运行的进程并返回结果
    i = 1
    # while (i - 1 + numof_workers) < num_of_task
    test_num = 0
    while  true

        # yield()
        # 完成任务的进程序号
        j = take!(c)
        # 取出结果
        append!(result, fetch(workersFuture[j]))
        # println(result[i])
        workersFuture[j] = Future(1)
        # println("up $i #")
        # println(task[i + numof_workers].W)
        # println(workers()[j])
        # println((i - 1 + numof_workers) < num_of_task)
        # print(i + numof_workers)
        # print(", j $j \n")

        # 未启动过num_of_task的进程则继续启动
        if (i - 1 + numof_workers) < num_of_task
            # @async put!(workersFuture[j], remotecall_fetch(cal_one_task, workers()[j], task[i + numof_workers])) & put!(c, j)
            the_task = task[i + numof_workers]
            the_id::Int = workers()[j]
            the_j = j
            # k = i + numof_workers
            # println(the_task)
            # println(the_id)
            # @async begin; println(i); put!(workersFuture[j], remotecall_fetch(cal_one_task, workers()[j], task[i + numof_workers])); put!(c, j); end
            @async begin; put!(workersFuture[the_j], remotecall_fetch(cal_one_task, the_id, the_task)); put!(c, the_j); end
            test_num = test_num + 1
            # println(i)
            # println("test_num $test_num")
            # 进度条
            if (i - 1)/num_of_task > 0.001 + progress
                progress = i/num_of_task
                print("\r")
                print(round(progress*100, digits = 1))
                print("%")
            end
            # 进度条
        # 未记录num_of_task数量的数量则继续记录
        elseif i < num_of_task
            nothing
        else
            break
        end
        # println(length(result))
        # yield()
        i = i + 1

    end

    close(c)
    print("\r100.0%")
    print("  all done @")
    println(now())
    result

end

ext: jl


text:
##### OVERRIDES FOR EFFICIENCY / CORRECTNESS

function add_vertices!(g::AbstractSimpleWeightedGraph, n::Integer)
    T = eltype(g)
    U = weighttype(g)
    (nv(g) + one(T) <= nv(g)) && return false       # test for overflow
    emptycols = spzeros(U, nv(g) + n, n)
    g.weights = hcat(g.weights, emptycols[1:nv(g), :])
    g.weights = vcat(g.weights, emptycols')
    return true
end

function adjacency_matrix(g::AbstractSimpleWeightedGraph, T::DataType=Int; dir::Symbol=:out)
    if dir == :out
        return SparseMatrixCSC(T.(LinearAlgebra.fillstored!(copy(g.weights), 1))')
    else
        return T.(LinearAlgebra.fillstored!(copy(g.weights), 1))
    end
end

function pagerank(g::SimpleWeightedDiGraph, α=0.85, n=100::Integer, ϵ=1.0e-6)
    A = weights(g)
    S = vec(sum(A, dims=1))
    S = 1 ./ S
    S[findall(S .== Inf)] .= 0.0
    M = A'  # need a separate line due to bug #17456 in julia
    # scaling the adjmat to stochastic adjacency matrix
    M = (Diagonal(S) * M)'
    N = Int(nv(g))
    # solution vector
    x = fill(1.0 / N, N)
    # personalization vector
    p = fill(1.0 / N, N)
    # temporary to hold the results of SpMV
    y = zeros(Float64, N)
    # adjustment for leaf nodes in digraph
    dangling_weights = p
    is_dangling = findall(S .== 0)
    # save some flops by precomputing this
    pscaled = (1 .- α) .* p
    for _ in 1:n
        xlast = x
        # in place SpMV to conserve memory
        mul!(y, M, x)
        # using broadcast to avoid temporaries
        x = α .* (y .+ sum(x[is_dangling]) .* dangling_weights) .+ pscaled
        # l1 change in solution convergence criterion
        err = sum(abs, (x .- xlast))
        if (err < N * ϵ)
            return x
        end
    end
    error("Pagerank did not converge after $n iterations.")
end

savegraph(fn::AbstractString, g::AbstractSimpleWeightedGraph, gname::AbstractString="graph"; compress=true) =
    savegraph(fn, g, gname, SWGFormat(), compress=compress)

savegraph(fn::AbstractString, d::Dict{T, U}; compress=true) where T <: AbstractString where U <: AbstractSimpleWeightedGraph =
    savegraph(fn, d, SWGFormat(), compress=compress)

# Connected Components on a Sparse Matrix

function _cc(g::SimpleWeightedGraph{T,U}) where T where U
    a = weights(g)
    comp = 0
    n = size(a, 1)
    marks = zeros(T, n)
    queue = Vector{T}()
    for i = 1:n
        if marks[i] == 0
            comp += 1
            push!(queue, i)
            while !isempty(queue)
                v = pop!(queue)
                marks[v] = comp
                for index in nzrange(a,v)
                    n = a.rowval[index]
                    if marks[n] == 0
                        push!(queue, n)
                    end
                end
            end
        end
    end
    marks, comp
end

function connected_components(g::SimpleWeightedGraph{T,U}) where T where U
    marks, num_cc = _cc(g)
    cc = [Vector{T}() for i = 1:num_cc]
    for (i,v) in enumerate(marks)
        push!(cc[v], i)
    end
    cc
end


text:
using ImplicitPlots
using Test
import Plots
using DynamicPolynomials: @polyvar
using HomotopyContinuation: @var

@testset "ImplicitPlots.jl" begin

    f(x,y) = (x^4 + y^4 - 1) * (x^2 + y^2 - 2) + x^5 * y
    @test implicit_plot(f; xlims=(-2,2), ylims=(-2,2)) isa Plots.Plot

    @polyvar x y
    f2 = (x^4 + y^4 - 1) * (x^2 + y^2 - 2) + x^5 * y
    @test implicit_plot(f2; xlims=(-2,2), ylims=(-2,2)) isa Plots.Plot

    @var x y
    f3 = (x^4 + y^4 - 1) * (x^2 + y^2 - 2) + x^5 * y
    @test implicit_plot(f3; xlims=(-2,2), ylims=(-2,2)) isa Plots.Plot
end

max_issues_repo_name: saschatimme/ImplicitPlots

max_forks_repo_name: saschatimme/ImplicitPlots


text:
# # Implement your own numerical methods to solve
#
# $$
# y'(t) = 1 - y(t),  t \in [0,5],  y(0) = 0.
# $$

# --

# ## Explicit Euler

euler(f, t, y, h) = t + h, y + h * f(t, y)

# ## Runge-Kutta 2nd order

rk2(f, t, y, h) = begin
    ỹ = y + h / 2 * f(t, y)
    t + h, y + h * f(t + h / 2, ỹ)
end

# ---

# ## Runge-Kutta 4th order

function rk4(f, t, y, dt)

    y₁ = dt * f(t, y)
    y₂ = dt * f(t + dt / 2, y + y₁ / 2)
    y₃ = dt * f(t + dt / 2, y + y₂ / 2)
    y₄ = dt * f(t + dt, y + y₃)

    t + dt, y + (y₁ + 2 * y₂ + 2 * y₃ + y₄) / 6

end

# ---

# ## Solve function

function dsolve(f, method, t₀, y₀, h, nsteps)

    t = zeros(Float64, nsteps)
    y = similar(t)

    t[1] = t₀
    y[1] = y₀

    for i = 2:nsteps
        t[i], y[i] = method(f, t[i-1], y[i-1], h)
    end

    t, y

end

# ---

# ## Plot solutions

using Plots

nsteps, tfinal = 7, 5.0
t₀, x₀ = 0.0, 0.0
dt = tfinal / (nsteps - 1)
f(t, x) = 1 - x

t, y_euler = dsolve(f, euler, t₀, x₀, dt, nsteps)

t, y_rk2 = dsolve(f, rk2, t₀, x₀, dt, nsteps)

t, y_rk4 = dsolve(f, rk4, t₀, x₀, dt, nsteps)

# ---

plot(t, y_euler; marker = :o, label = "Euler")
plot!(t, y_rk2; marker = :d, label = "RK2")
plot!(t, y_rk4; marker = :p, label = "RK4")
plot!(t -> 1 - exp(-t); line = 3, label = "true solution")
savefig("dsolve.png") #hide
# ![dsolve](dsolve.png)

# ---

# ## DifferentialEquations.jl

using DifferentialEquations

f(y, p, t) = 1.0 - y
y₀, t = 0.0, (0.0, 5.0)

prob = ODEProblem(f, y₀, t)

sol_euler = solve(prob, Euler(), dt = 1.0)
sol = solve(prob)

# ---

plot(sol_euler, label = "Euler")
plot!(sol, label = "default")
plot!(1:0.1:5, t -> 1.0 - exp(-t), lw = 3, ls = :dash, label = "True Solution!")

savefig("diffeq.png"); nothing #hide

# ![diffeq](diffeq.png)

# ---

# `sol.t` is the array of time points that the solution was saved at

sol.t

# `sol.u` is the array of solution values

sol.u

# ---

function lorenz(du, u, p, t)
    du[1] = 10.0 * (u[2] - u[1])
    du[2] = u[1] * (28.0 - u[3]) - u[2]
    du[3] = u[1] * u[2] - (8 / 3) * u[3]
end

u0 = [1.0; 0.0; 0.0]
tspan = (0.0, 100.0)
prob = ODEProblem(lorenz, u0, tspan)

sol = solve(prob)

# ---

plot(sol, vars = (1, 2, 3))

savefig("lorenz.png"); nothing #hide

# ![lorenz](lorenz.png)

# ---

using ParameterizedFunctions

lotka_volterra = @ode_def begin
  d🐁 = α*🐁  - β*🐁*🐈
  d🐈 = -γ*🐈 + δ*🐁*🐈
end α β γ δ

u0 = [1.0, 1.0] # Initial condition

tspan = (0.0, 10.0) # Simulation interval
tsteps = 0.0:0.1:10.0 # intermediary points

p = [1.5, 1.0, 3.0, 1.0] # equation parameters: p = [α, β, δ, γ]

prob = ODEProblem(lotka_volterra, u0, tspan, p)
sol = solve(prob)

# ---

# # Type-Dispatch Programming
#
# - Centered around implementing the generic template of the algorithm not around building representations of data.
# - The data type choose how to efficiently implement the algorithm.
# - With this feature share and reuse code is very easy
#
# [JuliaCon 2019 | The Unreasonable Effectiveness of Multiple Dispatch | Stefan Karpinski](https://youtu.be/kc9HwsxE1OY)

# ---

# Simple gravity pendulum

using DifferentialEquations, Plots

g = 9.79 # Gravitational constants
L = 1.00 # Length of the pendulum

#Initial Conditions
u₀ = [0, π / 60] # Initial speed and initial angle
tspan = (0.0, 6.3) # time domain

#Define the problem
function simplependulum(du, u, p, t)
    θ = u[1]
    dθ = u[2]
    du[1] = dθ
    du[2] = -(g/L)*θ
end

prob = ODEProblem(simplependulum, u₀, tspan)
sol = solve(prob, Tsit5(), reltol = 1e-6)

# ---

# Analytic and computed solution
u = u₀[2] .* cos.(sqrt(g / L) .* sol.t)

scatter(sol.t, getindex.(sol.u, 2), label = "Numerical")
plot!(sol.t, u, label = "Analytic")
savefig("pendulum1.svg"); nothing # hide

# ![](pendulum1.svg)

# ---

# [Numbers with Uncertainties](http://tutorials.juliadiffeq.org/html/type_handling/02-uncertainties.html)

using Measurements

g = 9.79 ± 0.02; # Gravitational constants
L = 1.00 ± 0.01; # Length of the pendulum

#Initial Conditions
u₀ = [0 ± 0, π / 60 ± 0.01] # Initial speed and initial angle

#Define the problem
function simplependulum(du, u, p, t)
    θ = u[1]
    dθ = u[2]
    du[1] = dθ
    du[2] = -(g/L)*θ
end

#Pass to solvers
prob = ODEProblem(simplependulum, u₀, tspan)
sol = solve(prob, Tsit5(), reltol = 1e-6);
nothing # hide

#md # ---

# Analytic solution
u = u₀[2] .* cos.(sqrt(g / L) .* sol.t)

plot(sol.t, getindex.(sol.u, 2), label = "Numerical")
plot!(sol.t, u, label = "Analytic")
savefig("pendulum2.svg"); nothing # hide

# ![](pendulum2.svg)

# ---


text:
# Main functions of adaptative MCL algorithms
# Berkeley 2015 - Maxime Legrand

#Pkg.add("Gadfly")
using Gadfly
include("../plot_tools.jl")
include("../matrix_tools.jl")
include("mcl.jl")

##########################
# r-adaptative algorithm #
##########################

"""r-adaptative MCL algorithm
Input : A, input of MCL
    e, expansion coefficient
    p, number of iterations
    rmin, rmax, resp, such that the r tested are those in rmin:resp:rmax
Output : rspot, Array{Any,2} such that for each i in size(rspot,1) :
    - rspot[i,1] is the r-value used for MCL
    - rspot[i,2] is the number of clusters spotted by MCL(r=rspot[i,1])
    - rspot[i,3] is the output of MCL(r=rspot[i,1])"""
function rad_mcl(A; e=2, p=20, rmin=2, rmax=10, resp=0.1)
    rrange = [rmin:resp:rmax]
    routput = map(r -> mcl(A, e=e, r=r, p=p), rrange)
    rspot = Array(Any,0,3)
    nclust2 = mcl_card(routput[1])
    for i = 1:(length(rrange)-1)
        nclust1, nclust2 = nclust2, mcl_card(routput[i+1])
        if nclust1 < nclust2
            temp = Array(Any, 1, 3)
            temp[1, 1:2] = [rrange[i] nclust1]
            temp[1,3] = routput[i]
            rspot = vcat(rspot, temp)
        end
    end
    temp = Array(Any, 1, 3)
    temp[1, 1:2] = [rrange[end] nclust2]
    temp[1,3] = routput[end]
    rspot = vcat(rspot, temp)
    return rspot
end

##########################
# e-adaptative algorithm #
##########################

"""e-adaptative MCL algorithm
Input : A, input of MCL
    r, inflation coefficient
    p, number of iterations
    emin, emax, eesp, such that the e tested are those in emin:eesp:emax (eesp needs to be an integer)
Output : espot, Array{Any,2} such that for each i in size(espot,1) :
    - espot[i,1] is the e-value used for MCL
    - espot[i,2] is the number of clusters spotted by MCL(e=espot[i,1])
    - espot[i,3] is the output of MCL(e=espot[i,1])"""
function ead_mcl(A; r=3, p=20, emin=2, emax=10, eesp=1)
    erange = [emin:eesp:emax]
    eoutput = map(e -> mcl(A, e=e, r=r, p=p), erange)
    espot = Array(Any, 1, 3)
    nclust2 = mcl_card(eoutput[1])
    espot[1, 1:2] = [erange[1] nclust2]
    espot[1, 3] = eoutput[1]
    for i = 1:(length(erange)-1)
        nclust1, nclust2 = nclust2, mcl_card(eoutput[i+1])
        if nclust1 > nclust2
            temp = Array(Any, 1, 3)
            temp[1, 1:2] = [erange[i+1] nclust2]
            temp[1,3] = eoutput[i+1]
            espot = vcat(espot, temp)
        end
    end
    return espot
end

#################
# Leave one out #
#################

##########################
# Arbitrary assignations #
##########################


text:
# To test new_model2.jl
include("test_header.jl")

function test_oracletest()

end

function load_data()
    d = load(language_model); v = create_vocab(d); wmodel = makewmodel(d);

    #corpus = load_conllu(small_data_file, v) # no need for train data

    dev    = load_conllu(small_dev_file, v);
    corpora = []; push!(corpora, dev); cc=vcat(corpora...)
    # push!(corpora, corpus); push!(corpora, dev); cc=vcat(corpora...);
    fillvecs!(wmodel, cc, v)

    # ppl = fillvecs!(wmodel, corpus, v) old
    # unk = unkrate(corpus)
    info("Caching lm vectors...")
    map(cachelmvec!,corpora)

    ss = filter(x->length(x)==8, corpora[1]);
    s1 = ss[1]; p1 = odict[:arctype](s1);
    return corpora, p1, s1
end

function test_pred()
    corpora, p1, s1 = load_data()
    #parsers = map(t->p1, 1:10)
    model, optims = initmodel1(odict, s1)

    # check-acts
    indx = [19, 115, 885, 62]
    sentences = corpora[1][indx]
    parsers = map(odict[:arctype], sentences)
    exp_sets = map(get_goldset, map(odict[:arctype],sentences))
    global omerdict = Dict{}()
    return model, sentences, exp_sets, corpora
end

function get_goldset(parser)
    p1 = copy(parser)
    ret = Int[]
    t = get_goldmove(parser)
    while t != typemax(Cost)
        move!(p1, t);push!(ret, t)
        t = get_goldmove(p1)
    end
    return ret
end

function get_goldmove(parser)
    mc1 = movecosts(parser , parser.sentence.head, parser.sentence.deprel)
    if minimum(mc1) != typemax(Cost)
        return indmin(mc1)
    end
    return typemax(Cost) # no more goldmoves
end

function get_validmove(parser)
    mc1 = movecosts(parser , parser.sentence.head, parser.sentence.deprel)
    valids = find(x->x!=typemax(Cost), mc1)
    (isempty(valids) && return false)
    return valids[rand(1:length(valids))]
end

# How to go along parser's stack
# 1. p.sptr index of the top word of stack, p.stack is the word for stack indices
# We need to find which words stays in the stack, be careful when the word reduced from the stack
# we can truncate the words in stack by p.stack[1:p.sptr]
# There are 3 types of words:
# The ones in the buffer, the ones in the stack and the ones come together with their heads (neither in stack nor in buffer)
# Related move action works with the word p.sptr
function vis_stack(parser)
    p1 = copy(parser)
end


text:
module REPL

using Revise, SHA, Dates, Pkg
using Genie, Genie.Loggers, Genie.Configuration, Genie.Generator, Genie.Tester, Genie.Util, Genie.FileTemplates

const JULIA_PATH = joinpath(Sys.BINDIR, "julia")

"""
    secret_token() :: String

Generates a random secret token to be used for configuring the SECRET_TOKEN const.
"""
function secret_token() :: String
  sha256("$(randn()) $(Dates.now())") |> bytes2hex
end

"""
    function newapp(path = "."; db_support = false, skip_dependencies = false) :: Nothing

Creates a new Genie app at the indicated path.
"""
function newapp(path::String; db_support = false, autostart = true) :: Nothing
  cp(joinpath(@__DIR__, "../", "files", "new_app"), abspath(path))

  chmod(joinpath(path, "bin", "server"), 0o700)
  chmod(joinpath(path, "bin", "repl"), 0o700)

  open(joinpath(path, "config", "secrets.jl"), "w") do f
    write(f, """const SECRET_TOKEN = "$(secret_token())" """)
  end

  moduleinfo = FileTemplates.appmodule(path)
  open(joinpath(path, moduleinfo[1] * ".jl"), "w") do f
    write(f, moduleinfo[2])
  end
  open(joinpath(path, "bootstrap.jl"), "w") do f
    write(f,
    """
      cd(@__DIR__)
      using Pkg
      pkg"activate ."

      function main()
        include("$(moduleinfo[1]).jl")
      end

      main()
    """)
  end

  log("Done! New app created at $(abspath(path))", :info)

  Sys.iswindows() && setup_windows_bin_files(path)

  log("Changing active directory to $path")
  cd(path)

  log("Installing app dependencies")
  pkg"activate ."
  pkg"instantiate"

  if autostart
    log("Starting your brand new Genie app - hang tight!", :info)
    load_app(".", autostart = autostart)
  else
    log("Your new Genie app is ready!
        Run \njulia> Genie.REPL.load_app() \nto load the app's environment
        and then \njulia> Genie.AppServer.startup() \nto start the web server on port 8000.")
  end

  nothing
end
const new_app = newapp

"""
"""
function loadapp(path = "."; autostart = false) :: Nothing
  Core.eval(Main, Meta.parse("using Revise"))
  Core.eval(Main, Meta.parse("""include(joinpath("$path", "bootstrap.jl"))"""))
  Core.eval(Main, Meta.parse("Revise.revise()"))
  Core.eval(Main, Meta.parse("using Genie"))

  Core.eval(Main.UserApp, Meta.parse("Revise.revise()"))
  Core.eval(Main.UserApp, Meta.parse("$autostart && Genie.AppServer.startup()"))

  nothing
end
const load_app = loadapp

"""

"""
function setup_windows_bin_files(path = ".")
  open(joinpath(path, "bin", "repl.bat"), "w") do f
    write(f, "$JULIA_PATH --color=yes --depwarn=no -q -i -- ../bootstrap.jl %*")
  end

  open(joinpath(path, "bin", "server.bat"), "w") do f
    write(f, "$JULIA_PATH --color=yes --depwarn=no -q -i -- ../bootstrap.jl s %*")
  end
end

"""
    write_secrets_file() :: Nothing

Generates a valid secrets.jl file with a random SECRET_TOKEN.
"""
function write_secrets_file() :: Nothing
  open(joinpath(Genie.CONFIG_PATH, "secrets.jl"), "w") do f
    write(f, """const SECRET_TOKEN = "$(secret_token())" """)
  end

  log("Generated secrets.jl file in $(Genie.CONFIG_PATH)", :info)

  nothing
end

end


text:
export connect_system, rename_vars, remove_superfluous_states, substitute_algebraic_states, substitute_derivatives, set_p, simplify_eqs

"""
$(SIGNATURES)

Recursively transform `IOSystems` to `IOBlocks`.

- substitute inputs with connected outputs
- try to eliminate equations for internal states which are not used to calculate the specified outputs of the system.
- try to eliminate explicit algebraic equations (i.e. outputs of internal blocks) by substituting each occurrence
  with their rhs. Explicit algebraic states which are marked as system outputs won't be removed.

Arguments:
- `ios`: system to connect
- `verbose=false`: toggle verbosity (show equations at different steps)
- `remove_superflous_states=true`: toggle whether the system should try to get rid of unused states
- `substitute_algebraic_states=true`: toggle whether the algorithm tries to get rid of explicit algebraic equations
- `substitute_derivatives=true`: toggle whether to expand all derivatives and try to substitute them
- `simplify_eqs=true`: toggle simplification of all equations at the end
"""
function connect_system(ios::IOSystem;
                        verbose=false,
                        simplify_eqs=true,
                        remove_superflous_states=false,
                        substitute_algebraic_states=true,
                        substitute_derivatives=true,
                        warn=true)
    # recursive connect all subsystems
    for (i, subsys) in enumerate(ios.systems)
        if subsys isa IOSystem
            ios.systems[i] = connect_system(subsys, verbose=verbose)
        end
    end
    eqs = vcat([namespace_equations(iob.system) for iob in ios.systems]...)
    removed_eqs = vcat([namespace_rem_eqs(iob) for iob in ios.systems]...)

    verbose && @info "Transform IOSystem $(ios.name) to IOBlock" ios.name ios.inputs ios.outputs ios.connections eqs

    # get rid of closed inputs by substituting output states
    substitutions = reverse.(ios.connections)
    for (i, eq) in enumerate(eqs)
        eqs[i] = eq.lhs ~ substitute(eq.rhs, substitutions)
    end
    for (i, eq) in enumerate(removed_eqs)
        removed_eqs[i] = eq.lhs ~ substitute(eq.rhs, substitutions)
    end

    verbose && @info "substitute inputs with outputs" eqs

    # apply the namespace transformations
    promotion_rules = ios.namespace_map
    eqs = map(eq->eqsubstitute(eq, promotion_rules), eqs)
    removed_eqs  = map(eq->eqsubstitute(eq, promotion_rules), removed_eqs)

    block = IOBlock(ios.name, eqs, ios.inputs, ios.outputs, removed_eqs; iv=get_iv(ios), warn)

    if remove_superflous_states
        block = BlockSystems.remove_superflous_states(block; verbose, warn)
    end

    if substitute_algebraic_states
        block = BlockSystems.substitute_algebraic_states(block; verbose, warn)
    end

    if substitute_derivatives
        block = BlockSystems.substitute_derivatives(block; verbose, warn)
    end

    if simplify_eqs
        block = BlockSystems.simplify_eqs(block; warn)
    end

    return block
end

"""
    remove_superfluous_states(iob::IOBlock; verbose=false, warn=true)

This function removes equations from block, which are not used in order to
generate the outputs. It looks for equations which have no path to the outputs
equations in the dependency graph. Returns a new IOBlock.

The removed equations will be not avaiblable as removed quations of the new IOBlock

TODO: Maybe we should try to reduce the inputs to.
"""
function remove_superfluous_states(iob::IOBlock; verbose=false, warn=true)
    iv = get_iv(iob)
    outputs = iob.outputs

    neweqs = deepcopy(equations(iob))
    sys = ODESystem(neweqs, iv; name=:tmp) # will be used for the dependency graph
    neweqs = get_eqs(sys) # the ODESystem might reorder the equations
    # generate dependency graph
    graph = eqeq_dependencies(asgraph(sys), variable_dependencies(sys))
    # find 'main' eq for each output
    output_idx = [findfirst(x->o ∈ Set(get_variables(x.lhs)), neweqs) for o in outputs]

    if any(isnothing, output_idx)
        verbose && @info "Can't remove souperflous states if outputs implicitly defined."
        return neweqs
    end

    # if there is no path from equation to output equation is not necessary
    removable = []
    for eq_node in 1:length(neweqs)
        if !any(has_path(graph, eq_node, out_node) for out_node in output_idx)
            push!(removable, eq_node)
        end
    end

    removed_eqs = neweqs[removable]
    deleteat!(neweqs, sort(removable))

    verbose && @info "Removed superflous states with equations" removed_eqs

    IOBlock(iob.name, neweqs, iob.inputs, iob.outputs, iob.removed_eqs; iv, warn)
end

"""
    substitute_algebraic_states(iob::IOBlock; verbose=false, warn=true)

Reduces the number of equations by substituting explicit algebraic equations.
Returns a new IOBlock with the reduced equations. The removed eqs are stored
together with the previous `removed_eqs` in the new IOBlock.
Won't reduce algebraic states which are labeld as `output`.
"""
function substitute_algebraic_states(iob::IOBlock; verbose=false, warn=true)
    reduced_eqs = deepcopy(equations(iob))

    (rules, removable) = _algebraic_substitution_rules(reduced_eqs; skip=Set(iob.outputs))

    # subsitute all the equations, remove substituted
    for (i, eq) in enumerate(reduced_eqs)
        neweqs = eq.lhs ~ recursive_substitute(eq.rhs, rules)
        type, lhs_var = eq_type(neweqs)
        if type == :implicit_algebraic && !isnothing(lhs_var)
            verbose && print("Algebraic substitution resulted in implicit equation...")
            # TODO: solve_for implicit algebraic equations
            # try
            #     neweqs = lhs_var ~ Symbolics.solve_for(neweqs, lhs_var)
            #     verbose && println("which could be solved: $neweqs")
            # catch e
            #   e isa AssertionError || rethrow(e)
                neweqs = 0 ~ neweqs.rhs - neweqs.lhs
                verbose && println("which was transformed to `0 ~ f(...)` form: $neweqs")
            # end
        end
        reduced_eqs[i] = neweqs
    end

    # also substitute in the allready removed_eqs
    removed_eqs = deepcopy(iob.removed_eqs)
    for (i, eq) in enumerate(removed_eqs)
        removed_eqs[i] = eq.lhs ~ recursive_substitute(eq.rhs, rules)
    end

    verbose && @info "Substituted algebraic states:" rules

    # append the knows removed wqs with the newly removed eqs
    append!(removed_eqs, reduced_eqs[removable])
    # remove removable equations from reduced_eqs
    deleteat!(reduced_eqs, sort(removable))

    IOBlock(iob.name, reduced_eqs, iob.inputs, iob.outputs, removed_eqs; iv=get_iv(iob), warn)
end

"""
    _algebraic_substitution_rules(eqs; skip=nothing)

Extract substition rules for explicit algebraic equations in given equations.
Makes sure that those substitutiosn are pairwise cycle free.

Returns Tuple of substitution dict and corresponding indices of algebraic equations
in the given equations.
"""
function _algebraic_substitution_rules(eqs; skip=nothing)
    # only consider states for reduction which are explicit algebraic and not in outputs
    condition = eq -> begin
        (type, var) = eq_type(eq)
        type == :explicit_algebraic && (skip===nothing || var ∉ skip)
    end
    algebraic_idx = findall(condition, eqs)

    # symbols of all algebraic eqs
    symbols = [eq.lhs for eq ∈ eqs[algebraic_idx]]

    # generate dependency graph
    g = SimpleDiGraph(length(algebraic_idx))
    for (i, eq) in enumerate(eqs[algebraic_idx])
        rhs_vars = get_variables(eq.rhs)
        for (isym, sym) in enumerate(symbols)
            if Set([sym]) ⊆ Set(rhs_vars)
                add_edge!(g, isym => i)
            end
        end
    end
    removable = algebraic_idx[_pairwise_cycle_free(g)]
    @assert allunique(removable)

    rules = Dict(eq.lhs => eq.rhs for eq in eqs[removable])
    return (rules, removable)
end

"""
    _pairwise_cycle_free(g:SimpleDiGraph)

Returns an array of vertices, which pairwise do not belong to any cycle in `g`.
Uses `simplecycles` from `Graphs`. The algorithm starts with all vertices
and iteratively removes the vertices is part of most cycles.
"""
function _pairwise_cycle_free(g::SimpleDiGraph)
    idx = collect(vertices(g))
    cycles = simplecycles(g)
    while true
        cycles_per_idx = zeros(Int, length(idx))
        for (i, id1) ∈ enumerate(idx)
            for (j, id2) ∈ enumerate(@view idx[i+1 : end])
                for c in cycles
                    if id1 ∈ c && id2 ∈ c
                        cycles_per_idx[i] += 1
                        cycles_per_idx[i+j] += 1
                    end
                end
            end
        end
        if sum(cycles_per_idx) > 0
            worst_idx = findmax(cycles_per_idx)[2]
            deleteat!(idx, worst_idx)
        else
            return idx
        end
    end
end

"""
    substitute_derivatives(iob::IOBlock; verbose=false, warn=true)

Expand all derivatives in the RHS of the system. Try to substitute
in the lhs with their definition.

I.e.

    D(o) ~ 1 + D(i)   =>  D(o) ~ 2 + a
    D(i) ~ 1 + a          D(i) ~ 1 + a

Process happens in multiple steps:
- try to find explicit equation for differential
- if none found try to recursivly substitute inside differential with known algebraic states
- expand derivatives and try again to substitute with known differentials

"""
function substitute_derivatives(iob::IOBlock; verbose=false, warn=true)
    diffs = rhs_differentials(iob)

    # if there are none just return the old block
    if isempty(diffs)
        verbose && @info "No rhs derivatives in block!"
        return iob
    end
    verbose && @info "Substitute rhs derivatives..."

    eqs = deepcopy(equations(iob))

    algebraic_subs = Dict{Symbolic, Any}()
    function lazy_alg_subs()
        if isempty(algebraic_subs)
            verbose && println("Lazily initilized algebraic substitutions for substituion of derivatives!")
            merge!(algebraic_subs, _algebraic_substitution_rules(eqs)[1])
        end
        return algebraic_subs
    end

    rules = Dict()
    known_differentials = Dict(eq.lhs => eq.rhs for eq in eqs if istree(eq.lhs) && operation(eq.lhs) isa Differential)
    for diff in diffs
        if haskey(known_differentials, diff)
            rules[diff] = known_differentials[diff]
            verbose && println("    ", diff, " => ", rules[diff])
        else
            substituted = recursive_substitute(diff, lazy_alg_subs())
            expanded = expand_derivatives(substituted)
            sub_known = substitute(expanded, known_differentials)

            rules[diff] = sub_known
            verbose && println("    ", diff, " => ", rules[diff])
            if verbose && !isempty(_collect_differentials(sub_known))
                println("        └ could not resolve this one!")
            end
        end
    end

    eqs = deepcopy(equations(iob))
    rem_eqs = deepcopy(iob.removed_eqs)

    for (i, eq) in enumerate(eqs)
        eqs[i] = eq.lhs ~ substitute(eq.rhs, rules)
    end
    for (i, eq) in enumerate(rem_eqs)
        rem_eqs[i] = eq.lhs ~ substitute(eq.rhs, rules)
    end

    newblock = IOBlock(iob.name, eqs, iob.inputs, iob.outputs, rem_eqs; iv=get_iv(iob), warn)

    return newblock
end

"""
    simplify_eqs(iob::IOBlock; verbose=false, warn=true)

Simplify eqs and removed eqs and return new IOBlock.
"""
function simplify_eqs(iob::IOBlock; verbose=false, warn=true)
    verbose && @info "Simplify iob equations..."
    simplified_eqs = simplify.(equations(iob))
    simplified_rem_eqs = simplify.(iob.removed_eqs)
    IOBlock(iob.name, simplified_eqs, iob.inputs, iob.outputs, simplified_rem_eqs; iv=get_iv(iob), warn)
end

"""
    rename_vars(blk::IOBLock; warn=true, kwargs...)
    rename_vars(blk::IOBlock, subs::Dict{Symbolic,Symbolic}; warn=true)

Returns new IOBlock which is similar to blk but with new variable names.
Variable renamings should be provided as keyword arguments, i.e.

    rename_vars(blk; x=:newx, k=:knew)

to rename `x(t)=>newx(t)` and `k=>knew`. Subsitutions can be also provided as
dict of `Symbolic` types (`Sym`s and `Term`s).
"""
function rename_vars(blk::IOBlock; warn=true, kwargs...)
    substitutions = Dict{Symbolic, Symbolic}()
    for pair in kwargs
        key = remove_namespace(blk.name, getproperty(blk, pair.first))
        val = rename(key, pair.second)
        substitutions[key] = val
    end
    rename_vars(blk, substitutions; warn)
end

function rename_vars(blk::IOBlock, subs::Dict{Symbolic,Symbolic}; warn=true)
    eqs     = map(eq->eqsubstitute(eq, subs), get_eqs(blk.system))
    rem_eqs = map(eq->eqsubstitute(eq, subs), blk.removed_eqs)
    inputs  = map(x->substitute(x, subs), blk.inputs)
    outputs = map(x->substitute(x, subs), blk.outputs)
    IOBlock(blk.name, eqs, inputs, outputs, rem_eqs; iv=get_iv(blk), warn)
end

"""
    set_p(blk::IOBlock, p::Dict; warn=true)
    set_p(blk::IOBlock, p::Pair; warn=true)

Substitutes certain parameters by actual Float values. Returns an IOBlock without those parameters.

Keys of dict can be either `Symbols` or the `Sybolic` subtypes. I.e. `blk.u => 1.0` is as valid as `:u => 1.0`.
"""
function set_p(blk::IOBlock, p::Dict; warn=true)
    subs = Dict{Symbolic, Float64}()
    validp = Set(blk.iparams)
    for k in keys(p)
        if k isa Symbol
            sym = getproperty(blk, k)
        elseif k isa Num
            sym = value(k)
        elseif k isa Symbolic
            sym = k
        else
            error("Can't use $k, wrong type $(typeof(k))")
        end
        sym = remove_namespace(blk.name, sym)
        @check sym ∈ validp "Symbol $sym is not iparam of block"
        @check p[k] isa Number "p value has to be a number! Maybe you are looking for `rename_vars` instead?"
        subs[sym] = p[k]
    end
    eqs     = map(eq->eqsubstitute(eq, subs), equations(blk))
    rem_eqs = map(eq->eqsubstitute(eq, subs), blk.removed_eqs)
    IOBlock(blk.name, eqs, blk.inputs, blk.outputs, rem_eqs; iv=get_iv(blk), warn)
end

set_p(blk::IOBlock, p...; warn=true) = length(p) > 1 ? set_p(blk, Dict(p); warn) : set_p(blk, Dict(only(p)); warn)


text:
# Utilities

## repeat each element in a vector

function repeach{T}(x::AbstractVector{T}, n::Integer)
    k = length(x)
    r = Array(T, k * n)
    p = 0
    @inbounds for i = 1:k
        xi = x[i]
        for j = 1:n
            r[p += 1] = xi
        end
    end
    return r
end

function repeach{T}(x::AbstractVector{T}, ns::IntegerVector)
    k = length(x)
    length(ns) == k || throw(DimensionMismatch("length(ns) should be equal to k."))
    r = Array(T, sum(ns))
    p = 0
    @inbounds for i = 1:k
        xi = x[i]
        ni = ns[i]
        for j = 1:ni
            r[p += 1] = xi
        end
    end
    return r
end

## repeat each column in a matrix

function repeachcol{T}(x::DenseArray{T,2}, n::Integer)
    m = size(x, 1)
    k = size(x, 2)
    r = Array(T, m, k * n)
    p = 0
    @inbounds for i = 1:k
        xi = view(x, :, i)
        for j = 1:n
            r[:, p += 1] = xi
        end
    end
    return r
end

function repeachcol{T}(x::DenseArray{T,2}, ns::IntegerVector)
    m = size(x, 1)
    k = size(x, 2)
    r = zeros(T, m, sum(ns))
    p = 0
    @inbounds for i = 1:k
        xi = view(x, :, i)
        ni = ns[i]
        for j = 1:ni
            r[:, p += 1] = xi
        end
    end
    return r
end

## repeat each row in a matrix

function repeachrow{T}(x::DenseArray{T,2}, n::Integer)
    k = size(x, 1)
    m = size(x, 2)
    r = Array(T, k * n, m)
    p = 0
    @inbounds for icol = 1:m
        p = 0
        for i = 1:k
            xi = x[i, icol]
            for j = 1:n
                r[p += 1, icol] = xi
            end
        end
    end
    return r
end

function repeachrow{T}(x::DenseArray{T,2}, ns::IntegerVector)
    k = size(x, 1)
    m = size(x, 2)
    r = Array(T, sum(ns), m)
    @inbounds for icol = 1:m
        p = 0
        for i = 1:k
            xi = x[i, icol]
            ni = ns[i]
            for j = 1:ni
                r[p += 1, icol] = xi
            end
        end
    end
    return r
end

## count the number of equal/non-equal pairs

function counteq(a::IntegerVector, b::IntegerVector)
    n = length(a)
    length(b) == n || throw(DimensionMismatch("Inconsistent lengths."))
    c = 0
    for i = 1:n
        if a[i] == b[i]
            c += 1
        end
    end
    return c
end

function countne(a::IntegerVector, b::IntegerVector)
    n = length(a)
    length(b) == n || throw(DimensionMismatch("Inconsistent lengths."))
    c = 0
    for i = 1:n
        if a[i] != b[i]
            c += 1
        end
    end
    return c
end


text:
#=move.jl - Updates the game file with a move, accepts 1 command line argument,<filename> => database
=#
include("AI.jl")
include("dParse.jl")
module move
using dParse
using BM
using AI
using SQLite

function moveAI(database,difficulty) #Makes a move with the AI, returns the move made

  #=----Parses the database and determines where pieces are on the board----=#

  #= ---- Opens the Database for reading ---- =#
  #database = ARGS[1] #/path/to/database/file {string}
  db = SQLite.DB(database) #Opens the database gamefile

  (board,gameType,seed,lastMoveID) = dParse.Parse(database)

  AI.init(gameType,board,seed,"normal")

  (sourcex,sourcey,targetx,targety) = AI.get_play()
  move_number = lastMoveID+1
  move_type = "move"
  SQLite.query(db,"""INSERT INTO moves (move_number, move_type, sourcex, sourcey, targetx, targety, i_am_cheating)
  VALUES ("$(move_number)","$(move_type)","$sourcex","$sourcey","$targetx","$targety", "false")""";)

return (sourcex,sourcey,targetx,targety)

end
export moveAI
end

max_stars_repo_name: kinoroy/Shogi

max_issues_repo_name: kinoroy/Shulia

max_forks_repo_name: kinoroy/Shulia


text:
using Pkg
Pkg.activate(".")

using Genie, HTTP
using Genie.Router, Genie.Responses

route("/responses", method = GET) do
  @show getstatus()
  @show getheaders()
  @show getbody()

  setstatus(301)
  setheaders(Dict("X-Foo-Bar"=>"Baz"))
  setheaders(Dict("X-A-B"=>"C", "X-Moo"=>"Cow"))
  setbody("Hello")

  @show getstatus()
  @show getheaders()
  @show getbody()

  getresponse()
end

route("/broken") do
 omg!()
end

Genie.AppServer.startup(verbose = true)

response = HTTP.request("GET", "http://localhost:8000/responses")
@show response

response = HTTP.request("GET", "http://localhost:8000/broken", ["Content-Type"=>"text/plain"])
@show response

exit(0)


text:
@testset "General --- type constructors" begin
    for FT in [Float32, Float64]
        # wavelength dataset
        _wls = WaveLengthSet{FT}();
        _wls = WaveLengthSet{FT}(collect(FT,400:5:2500));
        _wls = WaveLengthSet{FT}(collect(FT,400:5:2500); opti=Emerald.OPTI_2017);
        @test true;

        # create leaf biophysics
        _lbio = Emerald.LeafBiophysics{FT}();
        _lbio = Emerald.LeafBiophysics{FT}(collect(FT,400:5:2400.1));
        _lbio = Emerald.LeafBiophysics{FT}(collect(FT,400:5:2400.1); opti=Emerald.OPTI_2021);
        _lbio = Emerald.LeafBiophysics{FT}(WaveLengthSet{FT}());
        _lbio = Emerald.LeafBiophysics{FT}(WaveLengthSet{FT}(); opti=Emerald.OPTI_2021);
        @test true;

        # create leaf biophysics : warning expected here
        @info "A warning is expected here...";
        _lbio = Emerald.LeafBiophysics{FT}(collect(FT,400:5:2410.1));
        @test true;

        # create leaf
        _leaf = Leaf{FT}();
        _leaf = Leaf{FT}(collect(FT,400:5:2400.1));
        _leaf = Leaf{FT}(collect(FT,400:5:2400.1); opti=Emerald.OPTI_2021);
        _leaf = Leaf{FT}(WaveLengthSet{FT}());
        _leaf = Leaf{FT}(WaveLengthSet{FT}(); opti=Emerald.OPTI_2021);
        @test true;

        # create van Genuchten soil
        _vg = VanGenuchten{FT}("Loam");
        _vg = VanGenuchten{FT}("Silt");
        _vg = VanGenuchten{FT}("Test", FT(100), FT(2), FT(0.5), FT(0.1));
        @test true;

        # create van Genuchten soil : warning expected here
        @info "A warning is expected here...";
        _vg = VanGenuchten{FT}("Unsupported_Soil");
        @test true;

        # create Brooks Corey soil
        bc = BrooksCorey{FT}("Test", FT(5), FT(2), FT(0.5), FT(0.1));
        bc = BrooksCorey{FT}(VanGenuchten{FT}("Loam"));
        @test true;

        # create SoilAir struct
        sa = SoilAir{FT}(collect(FT,-2:0.2:0), collect(FT,0:0.2:4));
        @test true;
    end
end


text:
"""
Base type for an object defining how simulations should be carried out.
"""
abstract type Simulator end

"""
    simulate(simulator::Simulator, problem::POMDP{S,A,O}, policy::Policy, updater::Updater, initial_belief, initial_state::S)
    simulate(simulator::Simulator, problem::MDP{S,A}, policy::Policy, initial_state::S)

Run a simulation using the specified policy.

The return type is flexible and depends on the simulator. Simulations should adhere to the [Simulation Standard](http://juliapomdp.github.io/POMDPs.jl/latest/simulation.html#Simulation-Standard-1).
"""
function simulate end


text:
using BinaryBuilder

name = "cuQuantum"
version_string = "0.1.0.30"
version = let
    maj, min, patch, extra = parse.(Int, split(version_string, '.'))
    VersionNumber(maj, min, patch * 100 + extra)
end

sources = [
    ArchiveSource("https://developer.download.nvidia.com/compute/cuquantum/redist/cuquantum/linux-x86_64/cuquantum-linux-x86_64-0.1.0.30-archive.tar.xz",
                  "8ad8e98f14275ffe0de02574be5c86224af1c657c41baf02c16440301ffe0aae";
                  unpack_target="x86_64-linux-gnu"),
    ArchiveSource("https://developer.download.nvidia.com/compute/cuquantum/redist/cuquantum/linux-sbsa/cuquantum-linux-sbsa-0.1.0.30-archive.tar.xz",
                  "3dd04cf08f1323318e0e63a7e28bc904c426ced3367aca809fba7e7beef94063";
                  unpack_target="aarch64-linux-gnu"),
    ArchiveSource("https://developer.download.nvidia.com/compute/cuquantum/redist/cuquantum/linux-ppc64le/cuquantum-linux-ppc64le-0.1.0.30-archive.tar.xz",
                  "0eb84eef619a1cfab5870fb585200a9869a197866685252e4ca8187322809554";
                  unpack_target="powerpc64le-linux-gnu"),
]

# Bash recipe for building across all platforms
script = raw"""
cd ${WORKSPACE}/srcdir/${target}/cuquantum-*

mkdir -p ${prefix}
cp -var lib/ include/ ${prefix}/.
cp -var pkg-config/ ${prefix}/lib/.

# Fixup pkg-config files
sed -i \
    -e "s?^cudaroot=.*?cudaroot=${prefix}?" \
    -e "s?^libdir=.*?libdir=${libdir}?" \
    -e "s?^includedir=.*?includedir=${includedir}?" \
    ${prefix}/lib/pkg-config/*.pc

# Remove static libraries
rm ${libdir}/*.a

# Install license files
install_license LICENSE docs/*
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = [
    Platform("x86_64", "linux"; libc="glibc"),
    Platform("aarch64", "linux"; libc="glibc"),
    Platform("powerpc64le", "linux"; libc="glibc"),
]

# The products that we will ensure are always built
products = [
    LibraryProduct("libcustatevec", :libcustatevec; dont_dlopen=true),
    LibraryProduct("libcutensornet", :libcutensornet; dont_dlopen=true),
]

# Dependencies that must be installed before this package can be built
dependencies = Dependency[
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; julia_compat="1.6")

max_stars_repo_name: MichelJuillard/Yggdrasil

max_issues_repo_name: MichelJuillard/Yggdrasil

max_forks_repo_name: MichelJuillard/Yggdrasil


text:
using Mocking

using RecipesBase
using Test
using TimeZones
using TimeZones: PKG_DIR
using TimeZones.TZData: ARCHIVE_DIR, TZSource, compile, build
using Unicode

Mocking.activate()

const TZDATA_VERSION = "2016j"
const TZ_SOURCE_DIR = get(ENV, "TZ_SOURCE_DIR", joinpath(PKG_DIR, "test", "tzsource"))
const TZFILE_DIR = joinpath(PKG_DIR, "test", "tzfile")
const TEST_REGIONS = ["asia", "australasia", "europe", "northamerica"]

# https://github.com/JuliaLang/julia/pull/27900
if VERSION < v"1.2.0-DEV.642"
    const ProcessFailedException = ErrorException
end

isdir(ARCHIVE_DIR) || mkdir(ARCHIVE_DIR)
isdir(TZ_SOURCE_DIR) || mkdir(TZ_SOURCE_DIR)

# By default use a specific version of the tz database so we just testing for TimeZones.jl
# changes and not changes to the tzdata.
build(TZDATA_VERSION, TEST_REGIONS, ARCHIVE_DIR, TZ_SOURCE_DIR)

# For testing we'll reparse the tzdata every time to instead of using the serialized data.
# This should make the development/testing cycle simplier since you won't be forced to
# re-build the cache every time you make a change.
#
# Note: resolving only the time zones we want is much faster than running compile which
# recompiles all the time zones.
tzdata = Dict{String,TZSource}()
for name in TEST_REGIONS
    tzdata[name] = TZSource(joinpath(TZ_SOURCE_DIR, name))
end

include("helpers.jl")

@testset "TimeZones" begin
    include("utils.jl")
    include("indexable_generator.jl")

    include("class.jl")
    include(joinpath("tzdata", "timeoffset.jl"))
    include(joinpath("tzdata", "archive.jl"))
    include(joinpath("tzdata", "version.jl"))
    include(joinpath("tzdata", "download.jl"))
    include(joinpath("tzdata", "compile.jl"))
    Sys.iswindows() && include(joinpath("winzone", "WindowsTimeZoneIDs.jl"))
    include("utcoffset.jl")
    include(joinpath("types", "timezone.jl"))
    include(joinpath("types", "fixedtimezone.jl"))
    include(joinpath("types", "variabletimezone.jl"))
    include(joinpath("types", "zoneddatetime.jl"))
    include("exceptions.jl")
    include("interpret.jl")
    include("accessors.jl")
    include("arithmetic.jl")
    include("io.jl")
    include("tzfile.jl")
    include("adjusters.jl")
    include("conversions.jl")
    include("ranges.jl")
    include("tz_env.jl")
    include("local.jl")
    include("local_mocking.jl")
    include("discovery.jl")
    include("rounding.jl")
    include("parse.jl")
    include("plotting.jl")

    # Note: Run the build tests last to ensure that re-compiling the time zones files
    # doesn't interfere with other tests.
    if lowercase(get(ENV, "CI", "false")) == "true"
        include("ci.jl")
    end
end


text:
using Test

using DataGen

@testset "tsr" begin

@testset "gen_ts" begin
    x = gen_ts()
    @test size(x)  == (365, 4)
    @test names(x) == ["sample", "trends", "seasonality", "remainder"]
    @test isapprox(x.sample, x.trends + x.seasonality + x.remainder)

    x = gen_ts(365, 30; season_type = "random", anomaly_type = "dip", trend_type = "increase")
    @test size(x)  == (365, 4)
    @test isapprox(x.sample, x.trends + x.seasonality + x.remainder)
end

end # testset tsr


text:
@testset "Likelihood" begin

    kernD = Distributions.Exponential(1/0.5)
    bg = 0.5
    kappa = 0.5
    l = HawkesProcesses.likelihood(sort(rand(10)), bg, kappa, kernD, 1)

    @test length(l) == 1
    inferTests && @inferred HawkesProcesses.likelihood(sort(rand(10)), bg, kappa, kernD, 1)
end


text:
#these tests take way too long to be included in the normal unit tests

using JuliaPetra
include("TypeStability.jl")
include("TestUtil.jl")

println("starting csrmatrix stability tests")
#stability tests
lidCount = length(stableLIDs)
pidCount = length(stablePIDs)
gidRange = 1:length(stableGIDs)
for Data in stableDatas
    for i in gidRange
        @inbounds GID = stableGIDs[i]
        for j in i:lidCount
            @inbounds LID = stableLIDs[j]
            for k in j:pidCount
                @inbounds PID = stablePIDs[k]
                @test is_stable(check_method(apply!, (MultiVector{Data, GID, PID, LID},
                                                        CSRMatrix{Data, GID, PID, LID},
                                                        MultiVector{Data, GID, PID, LID},
                                                        TransposeMode,
                                                        Data,
                                                        Data)))
            end
        end
    end
end

println("finished with csrmatrix stability tests")

max_stars_repo_path: test/Slow Stability Tests.jl

max_issues_repo_path: test/Slow Stability Tests.jl

max_forks_repo_path: test/Slow Stability Tests.jl


text:
abstract type PriorMean{T} end

import Base: +, -, *, convert

include("constantmean.jl")
include("zeromean.jl")
include("empiricalmean.jl")
include("affinemean.jl")

function Base.convert(::Type{PriorMean},x::T) where {T<:Real}
    ConstantMean(x)
end

function Base.convert(::Type{PriorMean},x::AbstractVector{T}) where {T<:Real}
    EmpiricalMean(x)
end

get_opt(μ::PriorMean) = μ.opt


text:
function load_json(file, fix = true)
    try
        file = (endswith(file,".json")) ? JSON.parsefile(file) : JSON.parsefile(file*".json")
    catch y
        println(y)
        return
    end

    metabolites = get(file, "metabolites", Dict());
    description = get(file, "id", file);
    reactions = get(file, "reactions", Dict());
    metabolites = get(file, "metabolites", Dict());
    genes = get(file, "genes", Dict());
    constraints = get(file, "constraints", "");

    met_main_fields = ["id", "name", "formula"];
    getmets(x) = map(y -> get(y, x, ""), metabolites)
    met_formula = getmets("formula")
    met_name = getmets("name")
    mets = getmets("id")

    rxn_main_fields = ["name", "id", "rxn_subsystem", "gene_reaction_rule"];
    getrxns(x) = map(y -> get(y, x, ""), reactions)
    rxns = getrxns("id")
    rxn_name = getrxns("name")
    rxn_subsystem = getrxns("subsystem")
    rxn_rules = getrxns("gene_reaction_rule")

    gene_main_fields = ["name", "id"];
    getgenes(x) = map(y -> get(y, x, ""), genes)
    gene = getgenes("id")
    gene_name = getgenes("name")

    constraint_main_fields = ["b", "csense"];
    if constraints != ""
        b = constraints["b"]
        csense = constraints["csense"]
    else
        b = zeros(Float64, length(mets))
        csense = Dict(zip(["=", "<=", ">="], [collect(1:length(b)), [], []]))
    end

    stochiometric_fields = ["lower_bound", "upper_bound", "objective_coefficient", "metabolites"]
    lb = getrxns("lower_bound")
    ub = getrxns("upper_bound")
    c = map(x -> get(x, "objective_coefficient", 0.0), reactions)

    ###########
    # Creating the Stochiometric Sparse Matrix
    # for faster lookup, instead of searching an array for a met, search a dict
    tmpdict = Dict(zip(mets, collect(1:length(metabolites))))
    S = zeros(length(metabolites), length(reactions))

    for (i,reaction) in enumerate(reactions)
        for (key, val) in reaction["metabolites"]
            S[tmpdict[key], i] = val
        end
    end

    S = sparse(S)
    ###########

    ###########
    # Creating the Gene Reaction Matrix
    # for faster lookup, instead of searching an array for a gene, search a dict
    tmpdict = Dict(zip(gene, collect(1:length(gene))))

    # need to fix the rules for parsing efficiency
    rxn_rules = map(x -> replace(rxn_rules[x], " ( ", " ( "), 1:length(rxn_rules));
    rxn_rules = map(x -> replace(rxn_rules[x], " ) ", " ) "), 1:length(rxn_rules));
    rxn_rules = map(x -> replace(rxn_rules[x], " or ", " || "), 1:length(rxn_rules));
    rxn_rules = map(x -> replace(rxn_rules[x], " and ", " && "), 1:length(rxn_rules));

    # create tmprules to get rid of everything but gene ids
    tmprules = deepcopy(rxn_rules);
    tmprules = map(x -> replace(tmprules[x], "(", ""), 1:length(tmprules));
    tmprules = map(x -> replace(tmprules[x], ")", ""), 1:length(tmprules));
    tmprules = map(x -> replace(tmprules[x], "|", ""), 1:length(tmprules));
    tmprules = map(x -> replace(tmprules[x], "&", ""), 1:length(tmprules));
    tmprules = split.(tmprules)

    rxn_gene_mat = zeros(length(reactions), length(gene))

    for (i,v) in enumerate(tmprules)
        for k in v
            rxn_gene_mat[i, tmpdict[k]] = 1.0
        end
    end

    rxn_gene_mat = sparse(rxn_gene_mat)
    ######

    ############### All extra fields
    met_extra_keys = map(x -> collect(keys(x)), metabolites);
    met_extra_keys = map(x -> setdiff(x, met_main_fields), met_extra_keys);
    met_extra_keys = unique(vcat(met_extra_keys...));
    met_extra_values = map(x -> getmets(x), met_extra_keys);
    met_extra = Dict(zip(met_extra_keys, met_extra_values));

    rxn_extra_keys = map(x -> collect(keys(x)), reactions);
    rxn_extra_keys = map(x -> setdiff(x, rxn_main_fields), rxn_extra_keys);
    rxn_extra_keys = map(x -> setdiff(x, stochiometric_fields), rxn_extra_keys);
    rxn_extra_keys = unique(vcat(rxn_extra_keys...));
    rxn_extra_values = map(x -> getrxns(x), rxn_extra_keys);
    rxn_extra = Dict(zip(rxn_extra_keys, rxn_extra_values));

    gene_extra_keys = map(x -> collect(keys(x)), genes);
    gene_extra_keys = map(x -> setdiff(x, gene_main_fields), gene_extra_keys);
    gene_extra_keys = unique(vcat(gene_extra_keys...));
    gene_extra_values = map(x -> getgenes(x), gene_extra_keys);
    gene_extra = Dict(zip(gene_extra_keys, gene_extra_values));
    ###################

    floatconvert(x) = convert(Array{Float64}, x)
    stringconvert(x) = convert(Array{String}, x)

    lb = floatconvert(lb)
    ub = floatconvert(ub)
    c = floatconvert(c)
    b = floatconvert(b)

    rxns = stringconvert(rxns)
    mets = stringconvert(mets)
    gene = stringconvert(gene)
    rxn_name = stringconvert(rxn_name)
    rxn_rules = stringconvert(rxn_rules)
    rxn_subsystem = stringconvert(rxn_subsystem)
    met_formula = stringconvert(met_formula)
    met_name = stringconvert(met_name)
    gene_name = stringconvert(gene_name)

    model = Model(rxns,mets,gene,S,lb,ub,c,b,csense,rxn_gene_mat,rxn_name,rxn_rules,rxn_subsystem,rxn_extra,met_formula,met_name,met_extra,gene_name,gene_extra,description)

    if fix; fix_model(model); end

    return model
end

function load_matlab(filename; fix = true, model_key = "", x...)
    mat_file = matread(filename)
    # extract filename from full path, ie a/b/model.mat => model.mat
    model_name = filename[search(filename, r"\w*.mat")]

    # This is necessary because there exist inconsistend model.mat files
    if haskey(mat_file, "model")
        model_dict = mat_file["model"]
    elseif haskey(mat_file, model_name)
        model_dict = mat_file[model_name]
    elseif length(collect(keys(mat_file))) == 1
        model_dict = mat_file[collect(keys(mat_file))[1]]
    elseif model_key != ""
        model_dict = mat_file[model_key]
    else
        warn("Cannot determine which variable in " * model_name * ".mat is the model")
        warn("The keys stored in the file" * model_name * ".mat are:")
        counter = 0
        for (key,val) in mat_file
            counter += 1
            warn(string(counter) * " : " * key)
        end
        warn("Please call load_matlab(" * filename * ", X), where X is one of the keys")
        return
    end

    # need to check if the model_dict has every necessary key
    # note csense and description are optional so I dont check if they are in the model_dict
    model_keys = collect(keys(model_dict))
    extra_args = x
    extra_keys = map(y -> y[1], extra_args)
    extra_vals = map(y -> y[2], extra_args)

    fields = ["rxns","mets","genes","S","lb","ub","c","b","csense","rxnGeneMat","rxnNames","grRules","subSystems","metFormulas","metNames","description"]

    if !isempty(setdiff(fields, vcat(model_keys, ["csense", "description"])))
        missing = setdiff(fields, model_keys)
        warn("Not all necessary keys are present in the file")
        warn("Missing keys are: ")
        counter = 0
        for i in missing
            counter += 1
            warn(string(counter) * " : " * i)
        end

        println()

        warn("Unused keys in the matlab file are:")

        counter = 0

        for i in setdiff(vcat(model_keys, ["csense", "description"]), fields)
            counter += 1
            warn(string(counter) * " : " * i)
        end

        println()

        warn("You can run load_matlab(filename, " * (model_key != "" ? model_key : " ") * "X = \"Y\")")
        warn("Where X is the missing field, and Y is key of that field in the matlab file")
    end

    # create the model and start filling in
    model = Model([],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[])

    # intersect the fields array with the model_keys array and insert those values
    model_fields = ["rxns","mets","genes","S","lb","ub","c","b","csense","rxn_gene_mat","rxn_name","rxn_rules","rxn_subsystem","met_formula","met_name","description"]
    for (i,v) in enumerate(model_fields)
        setfield!(model, Symbol(v), get(model_dict, fields[i], [])[1:end])
    end

    # use the varargs fields, if there are any supplied
    for i in 1:length(extra_keys)
        if in(extra_keys[i], fields)
            idx = find(map(y -> extra_keys[i] == y, fields))[1]
            setfield!(model, Symbol(model_fields[i]), get(model_dict, extra_vals[i], [])[1:end])
        end
    end

    # get the rxn_extra, met_extra and gene_extra fields, if there are any in the model
    extra_fields = setdiff(model_keys, fields)
    rxn_extra = Dict()
    met_extra = Dict()
    gene_extra = Dict()

    for i in extra_fields
        extra = model_dict[i][1:end]

        if length(extra) == length(model.rxns)
            rxn_extra[i] = extra
        elseif length(extra) == length(model.mets)
            met_extra[i] = extra
        elseif length(extra) == length(model.genes)
            gene_extra[i] = extra
        end
    end

    model.rxn_extra = rxn_extra
    model.met_extra = met_extra
    model.gene_extra = gene_extra

    # check the csense field...tricky business
    if length(model.csense) == 0
        model.csense = Dict(zip(["=", "<=", ">="], [collect(1:length(model.b)), [], []]))
    elseif (typeof(model.csense) <: String)
        if length(model.csense) == length(model.rxns)
            L = []
            E = []
            U = []
            for i in 1:length(model.csense)
                if model.csense[i] == 'L'
                    push!(L, i)
                elseif model.csense[i] == 'U'
                    push!(U, i)
                else
                    push!(E, i)
                end
            end
            model.csense = Dict(zip(["<=", "=", ">="], [L, E, U]))
        else
            model.csense = Dict(zip(["=", "<=", ">="], [collect(1:length(model.b)), [], []]))
        end
    else
        model.csense = Dict(zip(["=", "<=", ">="], [collect(1:length(model.b)), [], []]))
    end

    # need to reshape this because of the [1:end] call everywhere
    # which flattens out the sparse matrix
    model.S = sparse(reshape(model.S, length(model.mets), length(model.rxns)))

    if fix; fix_model(model); end

    return model
end

function load_matlab_variable(file)
	return matread(file)
end

function load_matlab_array(file, variable_name)
	array = load_matlab_variable(file)[variable_name]
	array = array'
	array = array[:]

	try
		array = convert(Array{Int64}, array)
	catch
		array = convert(Array{Float64}, array)
	end
end

function write_matlab_variable(destination, variable_name, variable)
	file = matopen(destination, "w")
	try
		write(file, variable_name, variable)
	catch y
		warn("Error writing variable")
		warn(y)
	end
	close(file)
end

function convert_to_uft8!(array)
	return convert(Array{UTF8String}, array)
end
function load_table(filename, delimiter = ',', fix = true)
    rxn_table = readdlm(filename * "_rxns.csv", delimiter);
    met_table = readdlm(filename * "_mets.csv", delimiter);
    gene_table = readdlm(filename * "_genes.csv", delimiter);
    constraint_table = readdlm(filename * "_constraints.csv", delimiter);

    # Sometimes all elements in a column are type SubString{String}, so I locate these columns
    # and convert their elements to String
    #
    # Locate the columns
    rxn_substring_cols = find(map(x -> typeof(x) <: SubString, rxn_table[1,:]))
    met_substring_cols = find(map(x -> typeof(x) <: SubString, met_table[1,:]))
    gene_substring_cols = find(map(x -> typeof(x) <: SubString, gene_table[1,:]))
    constraint_table_substring_cols = find(map(x -> typeof(x) <: SubString, constraint_table[1,:]))
    #
    # Convert the columns elements
    map(x -> map(y -> rxn_table[y,x] = convert(String, rxn_table[y,x]), 1:size(rxn_table)[1]), rxn_substring_cols);
    map(x -> map(y -> met_table[y,x] = convert(String, met_table[y,x]), 1:size(met_table)[1]), met_substring_cols);
    map(x -> map(y -> gene_table[y,x] = convert(String, gene_table[y,x]), 1:size(gene_table)[1]), gene_substring_cols);
    map(x -> map(y -> constraint_table[y,x] = convert(String, constraint_table[y,x]), 1:size(constraint_table)[1]), constraint_table_substring_cols);

    model = Model([],[],[],sparse(zeros(size(met_table)[1],0)),[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[])

    # Metabolites
    ##########################
    model.mets = met_table[:,1]
    model.met_formula = met_table[:,2]
    model.met_name = met_table[:,3]
    ##########################

    # Reactions
    ##########################
    model.rxns = rxn_table[:,1]
    model.lb = rxn_table[:,2]
    model.ub = rxn_table[:,3]
    model.c = rxn_table[:,4]
    model.rxn_name = rxn_table[:,5]
    model.rxn_rules = rxn_table[:,6]
    model.rxn_subsystem = rxn_table[:,7]
    metdict = Dict(zip(model.mets, collect(1:length(model.mets))))
    for (i,v) in enumerate(rxn_table[:,8])
        model.S = addrxn(model.S, v, metdict)
    end
    ##########################

    # Genes
    ##########################
    model.genes = gene_table[:,1]
    model.gene_name = gene_table[:,2]
    ##########################

    # Constraints
    ##########################
    model.b = constraint_table[:,1]

    model.csense = Dict()
    model.csense["<="] = find(x -> x == "<=", constraint_table[:,2])
    model.csense[">="] = find(x -> x == "=>", constraint_table[:,2])
    model.csense["="] = find(x -> x == "=", constraint_table[:,2])
    ##########################

    if fix; fix_model(model); end

    return model
end

function addrxn(S, rxn, metdict)
    if contains(rxn, "<=>")
        middle = "<=>"
    elseif contains(rxn, "<=")
        middle = "<="
    elseif contains(rxn, "=>")
        middle = "=>"
    else
        warn("Reaction must contain '<=>', '<=' or '=>'")
        return
    end

    S = add_column(S)
    col = S.n

    sides = split(rxn, middle);
    left = sides[1];

    if length(left) != 0
        left_mets = split.(split(left, " + "))
        left_mets = map(y -> filter(x -> x != "", y), left_mets)
        left_mets = map(x -> convert(Array{Any}, x), left_mets)
        map(x -> length(x) == 1 ? unshift!(x, "1.0") : x, left_mets)
        left_mets = map(x -> [-parse(x[1]), metdict[x[2]]], left_mets)

        for i in left_mets
            S[Int(i[2]), col] = i[1]
        end
    end

    if length(sides) == 1
        return S
    end

    right = sides[2];
    if length(right) != 0
        right_mets = split.(split(right, " + "))
        right_mets = map(y -> filter(x -> x != "", y), right_mets)
        right_mets = map(x -> convert(Array{Any}, x), right_mets)
        map(x -> length(x) == 1 ? unshift!(x, "1.0") : x, right_mets)
        right_mets = map(x -> [parse(x[1]), metdict[x[2]]], right_mets)

        for i in right_mets
            S[Int(i[2]), col] = i[1]
        end
    end

    return S
end
function export_json(model, filename)
    model_dict = Dict()

    ####### Metabolites
    model_dict["metabolites"] = []
    for (i,v) in enumerate(model.mets)
        metabolite = Dict()
        metabolite["id"] = model.mets[i]
        metabolite["formula"] = model.met_formula[i]
        metabolite["name"] = model.met_name[i]

        for (key,val) in model.met_extra
            metabolite[key] = val[i]
        end

        push!(model_dict["metabolites"], metabolite)
    end

    ####### Description
    model_dict["id"] = model.description

    ####### Reaction
    model_dict["reactions"] = []
    for (i,v) in enumerate(model.rxns)
        reaction = Dict()
        reaction["id"] = model.rxns[i]
        reaction["name"] = model.rxn_name[i]
        reaction["subsystem"] = model.rxn_subsystem[i]
        reaction["gene_reaction_rule"] = model.rxn_rules[i]
        reaction["lower_bound"] = model.lb[i]
        reaction["upper_bound"] = model.ub[i]
        reaction["objective_coefficient"] = model.c[i]

        # get metabolites and coefficients from model.S
        idx = model.S.rowval[nzrange(model.S,i)] ;
        rxn_mets = model.mets[idx];
        met_coeffs = model.S.nzval[nzrange(model.S,i)];
        reaction["metabolites"] = Dict(zip(rxn_mets, met_coeffs));

        for (key,val) in model.rxn_extra
            reaction[key] = val[i]
        end

        push!(model_dict["reactions"], reaction)
    end

    ####### Genes
    model_dict["genes"] = []
    for (i,v) in enumerate(model.genes)
        gene = Dict()
        gene["id"] = model.genes[i]
        gene["name"] = model.gene_name[i]

        for (key,val) in model.gene_extra
            gene[key] = val[i]
        end

        push!(model_dict["genes"], gene)
    end

    ####### Constraints
    model_dict["constraints"] = Dict(zip(["b", "csense"], [model.b, model.csense]))

    ####### Make JSON string and write it to file
    jsonstring = json(model_dict)

    file = open(filename, "w")
    write(file, jsonstring)
    close(file)
end
function export_matlab(model, filename)
    matlab_model = Dict()

    matlab_model["mets"] = model.mets
    matlab_model["metNames"] = model.met_name
    matlab_model["metFormulas"] = model.met_formula
    matlab_model["rxns"] = model.rxns
    matlab_model["rxnNames"] = model.rxn_name
    matlab_model["subSystems"] = model.rxn_subsystem
    matlab_model["lb"] = model.lb
    matlab_model["ub"] = model.ub
    matlab_model["c"] = model.c
    matlab_model["b"] = model.b
    matlab_model["S"] = model.S
    matlab_model["rxnGeneMat"] = model.rxn_gene_mat
    matlab_model["grRules"] = model.rxn_rules
    matlab_model["genes"] = model.genes
    matlab_model["gene_name"] = model.gene_name

    # csense conversion from dictionary to array of L, E and U
    ###########################################################
    csense_length = length(model.csense["<="]) + length(model.csense["="]) + length(model.csense[">="]);
    csense = Array(Char, csense_length);
    csense[model.csense["<="]] = 'L';
    csense[model.csense["="]] = 'E';
    csense[model.csense[">="]] = 'U';
    csense = join(csense)
    matlab_model["csense"] = csense
    ###########################################################

    for (key,val) in model.rxn_extra
        matlab_model[key] = val
    end

    for (key,val) in model.met_extra
        matlab_model[key] = val
    end

    for (key,val) in model.gene_extra
        matlab_model[key] = val
    end

    exported_model = Dict(zip(["model"], [matlab_model]))

    MAT.matwrite(filename, exported_model)
end

function gene_rule_generator(model)
	tmp = deepcopy(model.rules)

	for (i,v) in enumerate(tmp)
		genes = genes_in_reaction(v)

		for gene in genes
			g = string("x(", find_gene(model, gene), ")")
			tmp[i] = replace(tmp[i], gene, g)
		end
	end
	return tmp
end

function sparse_gene_generator(model)
	sparse = spzeros(length(model.c), length(model.genes))

	for (i,v) in enumerate(model.genes)
		rxns = find_reactions_from_gene(model, v)

		for r in rxns
			sparse[r,i] = 1
		end
	end

	return sparse
end

function export_table(model, filename; delimiter = ',', overwrite = false )
    export_table(model, filename, delimiter, overwrite)
end

function export_table(model, filename, delimiter = ',', overwrite = false )
    println(filename)
    if !overwrite
        exists = false
        if isfile(filename * "_rxns.csv")
            warn("File " * filename * "_rxns.csv exists in this location")
            exists = true
        end
        if isfile(filename * "_mets.csv")
            warn("File " * filename * "_mets.csv exists in this location")
            exists = true
        end
        if isfile(filename * "_genes.csv")
            warn("File " * filename * "_genes.csv exists in this location")
            exists = true
        end
        if isfile(filename * "_constraints.csv")
            warn("File " * filename * "_constraints.csv exists in this location")
            exists = true
        end

        if exists
            warn("To overwrite call exp_table(model, " * filename * ", overwrite = true)")
            return
        end
    end

    ################# Reactions
    ##########################################
    rxn_data = deepcopy(model.rxns);
    rxn_data = hcat(rxn_data, model.lb);
    rxn_data = hcat(rxn_data, model.ub);
    rxn_data = hcat(rxn_data, model.c);
    rxn_data = hcat(rxn_data, model.rxn_name);
    rxn_data = hcat(rxn_data, model.rxn_rules);
    rxn_data = hcat(rxn_data, model.rxn_subsystem);

    ##### Create equations from model.S
    ###########################################################
    equations = []
    for i in 1:length(model.c)
        rxn_mets = model.mets[rowvals(model.S)[nzrange(model.S,i)]]
        coeffs = model.S.nzval[nzrange(model.S,i)]

        left = find(x -> x < 0, coeffs)
        if !isempty(left)
            leftside = map(x -> (coeffs[x] == -1 ? "" : string(abs(coeffs[x]))), left)
            leftside .*= " "
            leftside .*= rxn_mets[left]
            leftside = join(leftside, " + ")
        else
            leftside = ""
        end

        right = find(x -> x > 0, coeffs)
        if !isempty(right)
            rightside = map(x -> (coeffs[x] == 1 ? "" : string(coeffs[x])), right)
            rightside .*= " "
            rightside .*= rxn_mets[right]
            rightside = join(rightside, " + ")
        else
            rightside = ""
        end

        bounds = sign(model.lb[i]) + sign(model.ub[i])

        if bounds == 0.0
            direction = " <=> "
        elseif bounds == -1.0
            direction = " <= "
        else
            direction = " => "
        end

        equation = leftside * direction * rightside
        equation = rstrip(equation)
        equation = lstrip(equation)

        push!(equations, equation)
    end
    rxn_data = hcat(rxn_data, equations);
    ###########################################################

    ################### Metabolites
    ###########################################

    met_data = deepcopy(model.mets);
    met_data = hcat(met_data, model.met_formula);
    met_data = hcat(met_data, model.met_name);

    ################### Genes
    ###########################################

    gene_data = deepcopy(model.genes);
    gene_data = hcat(gene_data, model.gene_name);

    ################### Constraints
    ###########################################

    constraint_data = deepcopy(model.b)

    # csense conversion from dictionary to array of L, E and U
    ###########################################################
    csense_length = length(model.csense["<="]) + length(model.csense["="]) + length(model.csense[">="]);
    csense = Array(String, csense_length);
    csense[model.csense["<="]] = "<=";
    csense[model.csense["="]] = "=";
    csense[model.csense[">="]] = "=>";
    constraint_data = hcat(constraint_data, csense)
    ###########################################################

    writedlm(filename * "_rxns.csv",rxn_data , delimiter)
    writedlm(filename * "_mets.csv",met_data , delimiter)
    writedlm(filename * "_genes.csv",gene_data , delimiter)
    writedlm(filename * "_constraints.csv",constraint_data , delimiter)
    #write_delimiter_file(rxn_data, "_rxns", filename, delimiter)
    #write_delimiter_file(met_data, "_mets", filename, delimiter)
    #write_delimiter_file(gene_data, "_genes", filename, delimiter)
    #write_delimiter_file(constraint_data, "_constraints", filename, delimiter)
end

max_stars_repo_name: isebarn/CBM

max_issues_repo_name: isebarn/CBM

max_forks_repo_name: isebarn/CBM


text:
function foo()
    file = open("data/1.txt", "r")
    return sum(parse.(Int64, readlines(file)))
end

println(foo())


text:
@doc raw"""
    TranslationGroup{T<:Tuple,𝔽} <: GroupManifold{Euclidean{T,𝔽},AdditionOperation}

Translation group $\mathrm{T}(n)$ represented by translation arrays.

# Constructor
    TranslationGroup(n₁,...,nᵢ; field = 𝔽)

Generate the translation group on
$𝔽^{n₁,…,nᵢ}$ = `Euclidean(n₁,...,nᵢ; field = 𝔽)`, which is isomorphic to the group itself.
"""
const TranslationGroup{T<:Tuple,𝔽} = GroupManifold{𝔽,Euclidean{T,𝔽},AdditionOperation}

function TranslationGroup(n::Int...; field::AbstractNumbers=ℝ)
    return TranslationGroup{Tuple{n...},field}(
        Euclidean(n...; field=field),
        AdditionOperation(),
    )
end

invariant_metric_dispatch(::TranslationGroup, ::ActionDirection) = Val(true)

function default_metric_dispatch(
    ::MetricManifold{𝔽,<:TranslationGroup,EuclideanMetric},
) where {𝔽}
    return Val(true)
end

function Base.show(io::IO, ::TranslationGroup{N,𝔽}) where {N,𝔽}
    return print(io, "TranslationGroup($(join(N.parameters, ", ")); field = $(𝔽))")
end


text:
function Control()
    return Control(["0"])
end
function Control(args::Vector{String}, logger = C_NULL, logger_data=C_NULL, message_limit=20)
    p = Ref(Ptr{LibClingo.clingo_control}())
    @wraperror LibClingo.clingo_control_new(args, length(args), logger, logger_data, message_limit, p)
    return Control(p[])
end

function add(ctl::Control, program::String)
    add(ctl, "base", String[], program)
end

function add(ctl::Control, part::String, parameters::Vector{String}, program::String)
    @wraperror LibClingo.clingo_control_add(ctl.p, pointer(part), parameters, length(parameters), pointer(program))
end

function ground(ctl::Control, parts::Vector{LibClingo.clingo_part}=[LibClingo.clingo_part(pointer("base"),C_NULL, 0)], callback=C_NULL, callback_data=C_NULL)
    @wraperror LibClingo.clingo_control_ground(ctl.p, parts, length(parts), callback, callback_data)
end

function solve(ctl::Control)
    h = Ref(Ptr{LibClingo.clingo_solve_handle}())
    @wraperror LibClingo.clingo_control_solve(ctl.p, LibClingo.clingo_solve_mode_yield, C_NULL, 0, C_NULL, C_NULL, h)
    return Handle(h[])
end

function testsolve(str)
    ctl = Control()
    add(ctl, str)
    ground(ctl)
    h = solve(ctl)
    o = Vector{Vector{String}}()
    while true
        if !storemodelstr(h,o)
            break
        end
    end
    r = getresult(h)
    LibClingo.clingo_control_free(ctl.p)
    return r,o
end


text:
using Libtask
using Test

r = @testset "Broken Functions Tests" begin

    @testset "Error Test" begin
        function ftest()
            x = 1
            while true
                error("error test")
                produce(x)
                x += 1
            end
        end

        t = CTask(ftest)
        try
            consume(t)
        catch ex
            @test ex.etype == ErrorException
        end
        @test isa(t.exception, ErrorException)
    end

    @testset "OutOfBounds Test Before" begin
        function ftest()
            x = zeros(2)
            while true
                x[1] = 1
                x[2] = 2
                x[3] = 3
                produce(x[1])
            end
        end

        t = CTask(ftest)
        try
            consume(t)
        catch ex
            @test ex.etype == BoundsError
        end
        @test isa(t.exception, BoundsError)
    end

    @testset "OutOfBounds Test After `produce`" begin
        function ftest()
            x = zeros(2)
            while true
                x[1] = 1
                x[2] = 2
                produce(x[2])
                x[3] = 3
            end
        end

        t = CTask(ftest)
        @test consume(t) == 2
        try
            consume(t)
        catch ex
            @test ex.etype == BoundsError
        end
        @test isa(t.exception, BoundsError)
    end

    @testset "OutOfBounds Test After `copy`" begin
        function ftest()
            x = zeros(2)
            while true
                x[1] = 1
                x[2] = 2
                produce(x[2])
                x[3] = 3
            end
        end

        t = CTask(ftest)
        @test consume(t) == 2
        t_copy = copy(t)
        try
            consume(t_copy)
        catch ex
            @test ex.etype == BoundsError
        end
        @test isa(t_copy.exception, BoundsError)
    end
end
Test.print_test_results(r)


text:
# Test for GaussLobatto()
n = 2
x,w = gausslobatto(n)
@test x[1] ≈ -1.
@test x[2] ≈ 1.
@test w[1] ≈ 1.
@test w[2] ≈ 1.

n = 3
x,w = gausslobatto(n)
@test x[1] ≈ -1.
@test abs(x[2])<1e-15
@test x[3] ≈ 1.
@test w[1] ≈ 1/3
@test w[2] ≈ 4/3
@test w[3] ≈ 1/3

tol = 1e-14
n = 42
x,w = gausslobatto(n)
@test ( length(x) == n) && ( length(w) == n )
@test abs(x[37] - 0.922259214258616) < tol
@test abs(w[37] - 0.029306411216166) < tol
@test ( x[1] == -1 && x[n] == 1 )

@test dot( w,(x.^2)) ≈ 2/3
@test dot( w,exp.(x)) ≈ exp(1)-exp(-1)


text:
module TestUtils

using MLJBase
using Test

import LightGBM

@testset "mlj_to_kwargs removes classifier truncate_booster flag" begin
    # Arrange
    fixture = LightGBM.MLJInterface.LGBMClassifier()

    # Act
    output = LightGBM.MLJInterface.mlj_to_kwargs(fixture)

    # Assert
    @test :truncate_booster ∉ keys(output)
end

@testset "mlj_to_kwargs removes regressor truncate_booster flag" begin
    # Arrange
    fixture = LightGBM.MLJInterface.LGBMRegressor()

    # Act
    output = LightGBM.MLJInterface.mlj_to_kwargs(fixture)

    # Assert
    @test :truncate_booster ∉ keys(output)
end

@testset "mlj_to_kwargs adds classifier num_class" begin
    # Arrange
    fixture = LightGBM.MLJInterface.LGBMClassifier()

    # Act
    output = LightGBM.MLJInterface.mlj_to_kwargs(fixture, [0,1])

    # Assert
    @test :num_class in keys(output)
end

end # Module