text:
_round(v::AbstractArray) = _round.(v)
_round(x::Integer) = x
_round(x) = round(x; digits=2)


text:
struct CompileError
  transform
  args
  err
end

struct Self end
const self = Self()

# S -> function signature
# I -> lambda index
# T -> environment type
struct Lambda{S,I,T}
  data::T
end

Lambda{D,S}(data...) where {D,S} =
  Lambda{D,S,typeof(data)}(data)

@inline Base.getindex(l::Lambda, i::Integer) = l.data[i]

Base.show(io::IO, l::Lambda) = print(io, "λ")

function Base.showerror(io::IO, err::CompileError)
  println(io, "Error compiling @dynamo $(err.transform) on $(err.args):")
  showerror(io, err.err)
end

function transform end
function refresh end

function fallthrough(args...)
  Expr(:block,
       Expr(:meta, :inline),
       Expr(:call, [:(args[$i]) for i = 1:length(args)]...))
end

function lambdalift!(ir, S, I = ())
  i = 0
  for (v, st) in ir
    isexpr(st.expr, :lambda) || continue
    ir[v] = Expr(:call, Lambda{S,(I...,i+=1)}, st.expr.args[2:end]...)
  end
  return ir
end

function getlambda(ir, I)
  isempty(I) && return ir
  i = 0
  for (v, st) in ir
    isexpr(st.expr, :lambda) || continue
    (i += 1) == I[1] && return getlambda(st.expr.args[1], Base.tail(I))
  end
  error("Something has gone wrong in IRTools; couldn't find lambda in IR")
end

# Used only for its CodeInfo
dummy(args...) = nothing

function dynamo(cache, f, args...)
  try
    ir = transform(f, args...)::Union{IR,Expr,Nothing}
  catch e
    rethrow(CompileError(f, args, e))
  end
  ir isa Expr && return ir
  ir == nothing && return fallthrough(args...)
  cache[args] = ir
  ir = lambdalift!(copy(ir), Tuple{f,args...})
  if ir.meta isa Meta
    m = ir.meta
    ir = varargs!(m, ir)
    argnames!(m, :args)
    pushfirst!(m.code.slotnames, Symbol("#self#"))
  else
    m = @meta dummy(1)
    m.code.method_for_inference_limit_heuristics = nothing
  end
  _self = splicearg!(ir)
  prewalk!(x -> x === self ? _self : x, ir)
  return update!(m.code, ir)
end

function dynamo_lambda(cache, f::Type{<:Lambda{S,I}}) where {S,I}
  ir = cache[(S.parameters[2:end]...,)]
  ir = getlambda(ir, I)
  ir = lambdalift!(copy(ir), S, I)
  closureargs!(ir)
  m = @meta dummy(1)
  m.code.method_for_inference_limit_heuristics = nothing
  return update!(m.code, ir)
end

unesc(x) = prewalk(x -> isexpr(x, :escape) ? x.args[1] : x, x)

function lifttype(x)
  isexpr(x, :(::)) || return x
  named = length(x.args) == 2
  T = named ? x.args[2] : x.args[1]
  T = :(Type{$T})
  named ? Expr(:(::), x.args[1], T) : Expr(:(::), T)
end

macro dynamo(ex)
  @capture(shortdef(ex), (name_(args__) = body_) |
                         (name_(args__) where {Ts__} = body_)) ||
    error("@dynamo needs a function definition.")
  Ts = Ts == nothing ? [] : esc.(Ts)
  f, T = isexpr(name, :(::)) ?
    (length(name.args) == 1 ? (esc(gensym()), esc(name.args[1])) : esc.(name.args)) :
    (esc(gensym()), :(Core.Typeof($(esc(name)))))
  gendef = quote
    local cache = Dict()
    @generated ($f::$T)($(esc(:args))...) where $(Ts...) =
      return IRTools.dynamo(cache, $f, args...)
    @generated (f::IRTools.Inner.Lambda{<:Tuple{<:$T,Vararg{Any}}})(args...) where $(Ts...) =
      return IRTools.Inner.dynamo_lambda(cache, f)
  end
  quote
    $(isexpr(name, :(::)) || esc(:(function $name end)))
    function IRTools.transform(::Type{<:$T}, $(esc.(lifttype.(args))...)) where $(Ts...)
      $(esc(body))
    end
    $gendef
    IRTools.refresh(::$T) where $(Ts...) = (Core.eval($__module__, $(QuoteNode(unesc(gendef)))); return)
  end
end

macro code_ir(dy, ex)
  @capture(ex, f_(args__)) || error("@code_dynamo f(x...)")
  :(transform(typeof($(esc(dy))), meta($typesof($(esc(f)), $(esc.(args)...)))))
end

function recurse!(ir, to = self)
  for (x, st) in ir
    isexpr(st.expr, :call) || continue
    if length(st.expr.args) ≥ 2 &&
       st.expr.args[1] == GlobalRef(Core, :_apply_iterate) &&
       st.expr.args[2] == GlobalRef(Base, :iterate)
        funcarg = insert!(ir, x, xcall(:tuple, st.expr.args[3]))
        ir[x] = xcall(Core, :_apply, to, funcarg, st.expr.args[4:end]...)
    elseif st.expr.args[1] == GlobalRef(Core, :_apply)
        funcarg = insert!(ir, x, xcall(:tuple, st.expr.args[2]))
        ir[x] = xcall(Core, :_apply, to, funcarg, st.expr.args[3:end]...)
    else
        ir[x] = Expr(:call, to, st.expr.args...)
    end
  end
  return ir
end

ext: jl


text:
mutable struct Piece{T <: Vector{<:AbstractBlock}} <: AbstractPiece
  owner::Union{AbstractContainer, Nullable{AbstractContainer}}
  blocks::T

  name::Char
  color::AbstractString

  width::Integer
  rotation::Integer

  i::Integer
  j::Integer
end

function Piece(cur_owner::AbstractContainer)
  cur_piece =
    Piece(
      cur_owner,
      Block[],
      'x',
      "grey",
      -1,
      -1,
      -1,
      -1
    )

  for cur_count in 1:4
    push!(
      cur_piece.blocks,
      Block(cur_piece, -1, -1)
    )
  end

  cur_piece
end


text:
### ADAPTIVE SIMPSON RULE FROM GANDER AND GAUTSCHI (2000)

"""
    adaptsim(f,a,b; tol::Real=1e-10, trace::Bool=false)

Numerically integrate `f` over the closed real interval `[a,b]` to within tolerance `tol` using the adaptive Simpson's rule from Gander and Gautschi (2000).

Passing `trace=true` prints out information about where the function is being sampled.

`f` must be defined at `a` and `b`.

```
using QuadGG
adaptsim(sqrt,0,1)
```
"""
function adaptsim(f,a,b; tol::Real=1e-10, trace::Bool=false)
    m = (a+b)/2

    fa = f(a)
    fm = f(m)
    fb = f(b)

    sumyy = sum(f(v) for v in a .+ [0.9501,0.2311,0.6068,0.4860,0.8913].*(b-a))

    _is = (b-a) / 8 * (fa + fm + fb + sumyy)

    if iszero(_is)
        _is = b-a
    end

    _is_new = _is * tol / eps()

    flag = WarnFlag(false)
    Q = adaptsimstp(f,a,b,fa,fm,fb,_is_new,trace,flag)
    return Q
end

function adaptsimstp(f,a,b,fa,fm,fb,_is,trace,flag)
    m = (a+b)/2
    h = (b-a)/4

    fml = f(a+h)
    fmr = f(b-h)

    i1 = h/1.5 * (fa + 4*fm + fb)
    i2 = h/3 * (fa + 4*(fml + fmr) + 2*fm + fb)
    i1 = (16*i2 - i1)/15

    if ≈(_is+i1-i2, _is, atol=1e-16) || m <= a || b <= m|| !isfinite(_is)
        if (m <= a || b <= m) && !flag.nowarn
            @warn "Interval contains no more machine numbers. Required tolerance may not be met."
            flag.nowarn = true
        end
        Q = i1
        trace && @printf "%20.15f    %20.15f    %20.15f\n" a b-a Q
    else
        Q = adaptsimstp(f,a,m,fa,fml,fm,_is,trace,flag) + adaptsimstp(f,m,b,fm,fmr,fb,_is,trace,flag)
    end
    return Q
end


text:
function on_date(obj::RawSphericalHarmonicsProvider, arg0::AbsoluteDate)
    return jcall(obj, "onDate", RawSphericalHarmonicsProvider_RawSphericalHarmonics, (AbsoluteDate,), arg0)
end


text:
using Test

hd = homedir()

if Sys.iswindows()
    Rhome = if haskey(ENV,"R_HOME")
        ENV["R_HOME"]
    else
        using WinReg
        WinReg.querykey(WinReg.HKEY_LOCAL_MACHINE, "Software\\R-Core\\R","InstallPath")
    end
    Rscript = joinpath(Rhome,"bin",Sys.WORD_SIZE==64 ? "x64" : "i386", "Rscript")
else
    Rscript = "Rscript"
end

libpaths = readlines(`$Rscript -e "writeLines(.libPaths())"`)

using RCall
using Missings
using Dates

println(R"sessionInfo()")

println(R"l10n_info()")

# https://github.com/JuliaStats/RCall.jl/issues/68
@test hd == homedir()

# https://github.com/JuliaInterop/RCall.jl/issues/206
@test rcopy(Vector{String}, reval(".libPaths()")) == libpaths

tests = ["basic",
         "convert/base",
         "convert/missing",
         "convert/datetime",
         "convert/dataframe",
         "convert/categorical",
         "convert/formula",
         # "convert/axisarray",
         "macros",
         "namespaces",
         "repl",
         ]

if VERSION < v"1.0"
    insert!(tests, 8, "convert/axisarray")
end

println("Running tests:")

for t in tests
    println(t)
    tfile = string(t, ".jl")
    include(tfile)
end

@test unsafe_load(cglobal((:R_PPStackTop, RCall.libR), Int)) == 0


text:
using BenchmarkTools
#using ViewerGL, LinearAlgebra
#GL = ViewerGL
using LinearAlgebraicRepresentation
Lar = LinearAlgebraicRepresentation
using NearestNeighbors, DataStructures, SparseArrays
using SuiteSparseGraphBLAS, GraphBLASInterface
using SparseMM
using LocalCongruence

LC = LocalCongruence

# Sample 1

GrB_init(GrB_NONBLOCKING)

G = [
	0.5310492999999998 1.0146684 0.3477716 0.8313907882395298 0.6061046999999998 1.0897237999999998 0.42282699999999984 0.9064461979373597 0.5310493 1.0146684000000001 0.6061047 1.0897237772434623 0.3477716 0.8313908 0.422827 0.9064462 0.5310493 0.34777160000000007 0.6061047 0.4228270000000002 1.0146684 0.8313908 1.0897238 0.9064461675456482;
	0.8659989999999999 0.6827212999999999 0.5268921 0.3436144447063971 1.2188832999999994 1.0356056999999999 0.8797763999999998 0.6964987903021808 0.8659989999999999 0.6827213 1.2188833 1.035605657895053 0.5268921 0.3436145 0.8797764000000001 0.6964988 0.8659989999999999 0.5268920999999999 1.2188833 0.8797764 0.6827213 0.3436145 1.0356057 0.6964988122992563;
	0.14191280000000003 0.2169682 0.4947971000000001 0.5698524407571428 0.5200012 0.5950565999999999 0.8728855 0.9479408896095312 0.14191279999999987 0.21696819999999994 0.5200011999999999 0.5950566438156151 0.4947971 0.5698525000000001 0.8728855 0.9479409 0.14191280000000006 0.4947971000000001 0.5200012000000002 0.8728855000000001 0.21696819999999994 0.5698525000000001 0.5950565999999999 0.9479408949632379
];
W = convert(Lar.Points, G')
Delta_0 = SparseArrays.sparse((
	[1, 3, 1, 4, 2, 3, 2, 4, 5, 7, 5, 8, 6, 7, 6, 8, 9, 11, 9, 12, 10, 11, 10, 12, 13, 15, 13, 16, 14, 15, 14, 16, 17, 19, 17, 20, 18, 19, 18, 20, 21, 23, 21, 24, 22, 23, 22, 24],
	[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24],
	Int8[-1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1]
)...);
Delta_1 = SparseArrays.sparse((
	[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6],
	[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
	Int8[1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1]
)...);
T = [Delta_0, Delta_1];

@benchmark LC.chainCongruenceSM(G, T)

#@benchmark chainCongruenceSM(W, T)

@benchmark LC.chainCongruenceAA(W, T)

Delta_0_GB = SparseMM.sm2gbm(Delta_0)
Delta_1_GB = SparseMM.sm2gbm(Delta_1)
T_GB = [Delta_0_GB, Delta_1_GB]

@benchmark LC.chainCongruenceGB(W, T_GB)

# Example 2
G = [0.4851363000000001 0.5099412000000001 0.4604538000000001 0.4852586932051473 0.5099412 0.5347462 0.4852588 0.5100638087892613 0.5347461999999997 0.5595511999999998 0.5100636999999998 0.5348687087555339 0.46045379999999997 0.48525879999999993 0.4357712999999999 0.46057630875553396 0.4852587999999998 0.5100636999999998 0.4605762999999998 0.485381191210697 0.5100636999999999 0.5348686999999999 0.4853812999999999 0.510186289283825 0.43577130000000003 0.46057630000000005 0.41108890000000003 0.4358938892838253 0.46057630000000005 0.48538130000000007 0.43589380000000005 0.4606988195054789 0.48538129999999996 0.5101861999999999 0.46069879999999996 0.4855036999999999 0.7325833 0.7573883 0.7079008 0.732705808755534 0.7573882999999998 0.7821931999999998 0.7327057999999997 0.7575106892500558 0.7821932000000001 0.8069982000000001 0.7575107000000001 0.7823156912444693 0.7079008 0.7327058 0.6832184 0.7080233892838251 0.7327057999999999 0.7575106999999999 0.7080232999999999 0.7328282127105769 0.7575107 0.7823156999999998 0.7328283 0.7576333067948982 0.6832184000000002 0.7080233000000002 0.6585359000000002 0.6833408000000002 0.7080233000000001 0.7328283000000001 0.6833408000000001 0.7081457892500528 0.7328283 0.7576332 0.7081458 0.7329506932051473 0.9800303 1.0048353 0.9553478 0.9801527912444694 1.0048353000000003 1.0296402000000002 0.9801528000000003 1.004957712710577 1.0296402 1.0544452 1.0049578 1.029762806794898 0.9553478000000003 0.9801528000000004 0.9306654000000003 0.9554703980393594 0.9801528 1.0049578 0.9554703 0.9802752892500525 1.0049577999999997 1.0297626999999998 0.9802752999999997 1.0050801932051472 0.9306654 0.9554703 0.9059829 0.9307878019606395 0.9554702999999996 0.9802752999999995 0.9307878999999994 0.9555929175448041 0.9802753000000002 1.0050803000000001 0.9555928000000002 0.9803978000000003 1.2274773000000003 1.2522823000000003 1.2027949000000002 1.2275999067948984 1.2522823 1.2770873 1.2275998 1.2524047892500525 1.2770873 1.3018922 1.2524048 1.2772096932051473 1.2027949 1.2275998 1.1781124 1.2029172932051473 1.2275998000000001 1.2524048000000003 1.2029174000000002 1.227722408789262 1.2524047999999997 1.2772097999999996 1.2277222999999995 1.2525273087555335 1.1781123999999998 1.2029173999999998 1.1534298999999997 1.1782348999999996 1.2029174 1.2277223 1.1782349 1.2030397892500562 1.2277222999999997 1.2525272999999997 1.2030397999999998 1.227844791244469 0.4851363000000001 0.5099412000000001 0.7325833000000002 0.7573882979522348 0.5099411999999999 0.5347462 0.7573883000000001 0.7821931912058342 0.5347461999999998 0.5595511999999999 0.7821932 0.806998201072288 0.46045379999999997 0.4852587999999999 0.7079008 0.7327058010722881 0.4852588000000001 0.5100637 0.7327058000000001 0.7575107097696032 0.5100637000000002 0.5348687000000001 0.7575107000000001 0.7823156989277071 0.43577129999999986 0.4605762999999999 0.6832183999999999 0.7080232999031792 0.4605762999999998 0.48538129999999985 0.7080232999999998 0.7328282902303588 0.4853812999999999 0.5101861999999999 0.7328283 0.7576332010722877 0.4110888999999999 0.4358938 0.6585359 0.6833408000000001 0.4358937999999999 0.4606987999999999 0.6833408 0.7081458086973149 0.4606988000000001 0.48550370000000015 0.7081458000000003 0.7329507990245284 0.7325833000000002 0.7573883000000001 0.9800303000000001 1.0048353010722884 0.7573882999999998 0.7821931999999999 1.0048352999999999 1.0296402097696031 0.7821932000000001 0.8069982 1.0296402 1.054445198927707 0.7079008 0.7327058000000001 0.9553478 0.9801527989277072 0.7327058 0.7575107 0.9801528 1.0049577892548855 0.7575106999999999 0.7823156999999996 1.0049578 1.0297627020477507 0.6832184 0.7080233000000002 0.9306654000000002 0.9554703000000001 0.7080233 0.7328282999999999 0.9554703 0.9802753097696029 0.7328283 0.7576332 0.9802753000000002 1.0050802979522349 0.6585359000000001 0.6833408000000001 0.9059829 0.9307878990245285 0.6833408000000002 0.7081458 0.9307879000000001 0.9555927922781232 0.7081458000000002 0.7329508000000002 0.9555928 0.9803978 0.9800302999999997 1.0048352999999999 1.2274773 1.252282298927707 1.0048353 1.0296402 1.2522822999999996 1.2770872892548857 1.0296401999999998 1.0544451999999997 1.2770872999999998 1.3018922020477506 0.9553478000000001 0.9801528000000002 1.2027949000000002 1.2275998020477508 0.9801527999999998 1.0049577999999997 1.2275997999999997 1.2524048097696028 1.0049578 1.0297626999999998 1.2524048000000003 1.277209797952235 0.9306653999999999 0.9554703000000001 1.1781123999999998 1.2029173990245283 0.9554702999999999 0.9802752999999997 1.2029173999999996 1.227722291205834 0.9802753 1.0050803 1.2277223 1.2525273010722882 0.9059828999999999 0.9307878999999998 1.1534299 1.1782348999999996 0.9307879000000002 0.9555927999999999 1.1782349 1.2030398086973157 0.9555928 0.9803977999999999 1.2030398 1.2278448 0.48513629999999996 0.4604538000000001 0.7325833 0.7079008088474859 0.5099411999999998 0.48525879999999993 0.7573882999999999 0.7327057901770416 0.5347461999999998 0.5100637 0.7821931999999999 0.7575106911524817 0.5595512 0.5348686999999999 0.8069982 0.7823157108081016 0.4604538 0.4357713 0.7079008 0.6832183901673042 0.48525880000000005 0.4605763 0.7327058000000001 0.7080233108081018 0.5100637000000001 0.48538130000000007 0.7575107 0.7328283088474857 0.5348687000000001 0.5101862 0.7823157000000001 0.7576331891918608 0.43577129999999986 0.4110888999999999 0.6832183999999999 0.6585359000048607 0.4605762999999998 0.43589379999999994 0.7080232999999998 0.6833407891918606 0.4853812999999999 0.46069879999999985 0.7328283 0.7081458009803131 0.5101862 0.4855037 0.7576332 0.7329508098229311 0.7325833 0.7079007999999998 0.9800303000000001 0.9553477911524815 0.7573883 0.7327058000000001 1.0048353000000003 0.9801528108081017 0.7821932000000001 0.7575107 1.0296402 1.0049578078623143 0.8069982000000001 0.7823157000000001 1.0544452000000002 1.0297626891918608 0.7079007999999999 0.6832183999999999 0.9553477999999999 0.9306653990196898 0.7327057999999999 0.7080232999999998 0.9801527999999999 0.9554702891918605 0.7575107000000001 0.7328283000000001 1.0049578000000001 0.9802752921376624 0.7823157000000001 0.7576332 1.0297627 1.0050803098229308 0.6832184 0.6585359 0.9306654000000003 0.9059829108081019 0.7080233 0.6833407999999999 0.9554703 0.9307879098229311 0.7328283 0.7081458000000002 0.9802753000000002 0.9555927990196903 0.7576332 0.7329508 1.0050803000000001 0.9803977901770418 0.9800303000000001 0.9553478000000003 1.2274773000000005 1.202794907862315 1.0048353 0.9801527999999999 1.2522822999999998 1.2275997891918604 1.0296401999999998 1.0049577999999997 1.2770872999999998 1.2524047921376624 1.0544452 1.0297627 1.3018922 1.277209809822931 0.9553478 0.9306654000000001 1.2027949 1.1781124019654912 0.9801527999999999 0.9554703 1.2275997999999997 1.2029174098229312 1.0049578 0.9802753 1.2524048000000003 1.2277223088474856 1.0297626999999998 1.0050802999999997 1.2772097999999998 1.2525272901770415 0.9306654 0.9059829000000001 1.1781124 1.1534298891918606 0.9554703000000002 0.9307879000000004 1.2029174 1.178234890177042 0.9802753 0.9555927999999999 1.2277223 1.2030398009803132 1.0050803 0.9803978 1.2525273 1.2278448108081017;
0.9680746999999998 0.9433922 1.2152774 1.190594888290028 0.9433921999999999 0.9187098 1.1905949 1.165912411928616 0.9187097999999998 0.8940273 1.1659124 1.1412299009600377 1.2152773999999995 1.1905948999999998 1.4624799999999996 1.4377975009600377 1.1905948999999998 1.1659123999999996 1.4377974999999996 1.4131150880713321 1.1659123999999998 1.1412299 1.4131150999999997 1.38843260978987 1.4624800000000002 1.4377975000000005 1.7096827 1.6850002097898702 1.4377975000000005 1.4131151000000002 1.6850002000000004 1.6603177021387612 1.4131150999999995 1.3884325999999998 1.6603176999999998 1.6356351999999998 0.9952071000000002 0.9705246000000001 1.2424097000000005 1.217727200960038 0.9705245999999998 0.9458421 1.2177271999999997 1.1930447988212762 0.9458420999999999 0.9211596 1.1930448 1.1683622990399625 1.2424097 1.2177272000000001 1.4896124000000002 1.46492990978987 1.2177271999999997 1.1930447999999998 1.4649298999999998 1.4402473904287851 1.1930448 1.1683623 1.4402474000000003 1.4155649117099405 1.4896124000000002 1.4649299000000005 1.7368150000000007 1.7121325000000003 1.4649298999999998 1.4402473999999998 1.7121324999999994 1.687450098821275 1.4402474000000003 1.4155649000000001 1.6874501000000002 1.662767588290028 1.0223393999999997 0.9976568999999998 1.2695420999999998 1.2448595990399625 0.9976569000000004 0.9729745000000004 1.2448596000000005 1.2201770904287856 0.9729745000000001 0.9482920000000001 1.2201771 1.1954946117099403 1.2695421 1.2448596 1.5167447 1.492062210749909 1.2448596000000003 1.2201771000000001 1.4920622000000003 1.4673797988212758 1.2201771 1.1954946000000002 1.4673798 1.4426972882900277 1.5167447000000003 1.4920622 1.7639474000000002 1.7392648892500637 1.4920621999999997 1.4673797999999998 1.7392648999999998 1.7145824128886509 1.4673798 1.4426973 1.7145824000000003 1.6898998999999997 1.0494717999999998 1.0247893 1.2966744000000001 1.2719919117099405 1.0247893 1.0001067999999997 1.2719919 1.2473094988212754 1.0001068 0.9754243 1.2473095 1.2226269882900276 1.2966744 1.2719919000000002 1.5438771 1.5191945882900277 1.2719919 1.2473095000000003 1.5191946 1.4945121119286158 1.2473094999999998 1.2226269999999997 1.4945120999999997 1.4698296009600378 1.5438771 1.5191945999999998 1.7910796999999998 1.7663972000000001 1.5191945999999998 1.4945120999999997 1.7663971999999997 1.7417147988212762 1.4945121000000001 1.4698296000000002 1.7417148000000002 1.7170322990399627 0.9680747000000001 0.9433922000000001 0.9952071000000001 0.9705246205089642 0.9433921999999998 0.9187097999999998 0.9705245999999997 0.9458421880761753 0.9187098 0.8940273 0.9458421 0.9211595892606733 1.2152773999999997 1.1905948999999998 1.2424096999999998 1.2177271892606731 1.1905949 1.1659124 1.2177272 1.1930447021541872 1.1659123999999996 1.1412298999999995 1.1930447999999996 1.1683623107393253 1.4624800000000002 1.4377975000000003 1.4896124000000002 1.464929900969688 1.4377974999999998 1.4131150999999997 1.4649298999999998 1.4402474978458117 1.4131150999999997 1.3884325999999998 1.4402473999999998 1.4155648892606771 1.7096827 1.6850002 1.736815 1.7121324999999998 1.6850002000000002 1.6603177000000002 1.7121325000000003 1.6874500128935104 1.6603177000000002 1.6356352000000003 1.6874501000000002 1.6627676097696376 0.9952071000000001 0.9705246000000001 1.0223394000000001 0.9976568892606733 0.9705246000000001 0.9458421000000001 0.9976569000000001 0.9729744021541875 0.9458421000000001 0.9211596000000001 0.9729745000000001 0.9482920107393258 1.2424096999999998 1.2177271999999997 1.2695420999999998 1.2448596107393255 1.2177272000000001 1.1930448000000002 1.2448596000000003 1.220177207615455 1.1930448 1.1683623 1.2201771 1.1954945794910787 1.4896123999999995 1.4649298999999996 1.5167446999999996 1.4920621999999997 1.4649299 1.4402474 1.4920622 1.4673797021541881 1.4402473999999998 1.4155648999999997 1.4673797999999998 1.4426973205089635 1.736815 1.7121325 1.7639474 1.7392649097696373 1.7121325000000003 1.6874501000000002 1.7392649000000002 1.7145824773368845 1.6874501000000002 1.6627676000000002 1.7145824000000003 1.6898999000000003 1.0223394 0.9976569 1.0494718 1.024789310739326 0.9976568999999997 0.9729744999999997 1.0247892999999997 1.000106907615454 0.9729744999999999 0.9482919999999999 1.0001067999999997 0.9754242794910788 1.2695421 1.2448596 1.2966744 1.2719918794910787 1.2448595999999998 1.2201770999999997 1.2719918999999997 1.2473094021541877 1.2201771 1.1954946 1.2473095 1.2226270205089642 1.5167446999999998 1.4920621999999997 1.5438770999999998 1.519194609769637 1.4920621999999995 1.4673797999999996 1.5191945999999996 1.4945121880761751 1.4673797999999998 1.4426972999999998 1.4945120999999997 1.469829589260673 1.7639474000000002 1.7392649000000002 1.7910797000000005 1.7663972000000003 1.7392649 1.7145824 1.7663972 1.7417147128935053 1.7145824 1.6898999 1.7417148 1.7170322999999998 0.9680746999999997 1.2152774 0.9952071 1.242409691196175 0.9433921999999998 1.1905948999999998 0.9705245999999998 1.217727209774413 0.9187097999999998 1.1659124 0.9458420999999999 1.1930448088037933 0.8940273000000002 1.1412299 0.9211596 1.1683622892452266 1.2152773999999997 1.4624799999999998 1.2424097 1.4896124097841024 1.1905948999999998 1.4377974999999998 1.2177271999999995 1.4649298892452263 1.1659123999999998 1.4131150999999997 1.1930448 1.4402473911961726 1.1412299 1.3884326000000002 1.1683623000000003 1.4155649107547168 1.4624800000000002 1.7096827 1.4896124000000004 1.7368149999951634 1.4377975 1.6850002 1.4649298999999996 1.7121325107547167 1.4131150999999995 1.6603176999999998 1.4402473999999998 1.6874500990245278 1.3884326000000002 1.6356352000000003 1.4155649 1.6627675902255363 0.9952070999999999 1.2424097 1.0223393999999997 1.2695421088037933 0.9705245999999998 1.2177271999999997 0.9976568999999998 1.2448595892452265 0.9458420999999999 1.1930447999999998 0.9729744999999999 1.220177092176485 0.9211596 1.1683623000000003 0.948292 1.1954946107547169 1.2424096999999998 1.4896124 1.2695421 1.5167447009754724 1.2177271999999997 1.4649298999999998 1.2448596 1.4920622107547166 1.1930448 1.4402474000000003 1.2201771 1.4673798078234879 1.1683623 1.4155649 1.1954946 1.442697290225536 1.4896123999999997 1.736815 1.5167447 1.7639473892452262 1.4649299000000002 1.7121324999999998 1.4920622000000001 1.7392648902255363 1.4402474000000003 1.6874501000000002 1.4673798 1.714582400975472 1.4155649 1.6627676 1.4426973000000003 1.6898999097744127 1.0223394 1.2695421 1.0494718000000003 1.296674392176485 0.9976569000000002 1.2448596000000003 1.0247893 1.2719919107547168 0.9729744999999999 1.2201770999999997 1.0001067999999997 1.247309507823488 0.948292 1.1954946 0.9754242999999999 1.2226269902255362 1.2695421 1.5167447 1.2966744 1.5438770980442142 1.2448596 1.4920622000000001 1.2719919000000002 1.5191945902255362 1.2201771 1.4673798 1.2473095 1.4945120911961751 1.1954946 1.4426973 1.2226269999999997 1.469829609774413 1.5167447000000005 1.7639474000000006 1.5438771000000002 1.7910797107547172 1.4920622000000001 1.7392649000000002 1.5191946 1.7663972097744132 1.4673798000000002 1.7145824000000005 1.4945121000000001 1.741714799024528 1.4426972999999998 1.6898999 1.4698296 1.7170322892452263;
0.9097499999999998 1.1571971 0.9368824 1.1843294095374093 1.1571971 1.4046441 1.1843294000000002 1.4317763902844214 1.4046441 1.6520911 1.4317764 1.6792234992180755 0.9368824000000001 1.1843294 0.9640147000000001 1.2114617992180752 1.1843293999999998 1.4317763999999997 1.2114617999999997 1.4589088097155285 1.4317763999999997 1.6792234999999998 1.4589087999999997 1.706355792026389 0.9640147 1.2114618 0.9911471 1.2385940920263896 1.2114618000000001 1.4589088000000001 1.2385941 1.4860411982580366 1.4589087999999997 1.7063557999999996 1.4860411999999998 1.7334881999999996 0.8876515 1.1350985 0.9147838 1.1622308992180752 1.1350985 1.3825455000000002 1.1622309 1.4096779009600338 1.3825455000000004 1.6299926000000005 1.4096779000000002 1.657124900781924 0.9147838000000001 1.1622308999999997 0.9419162 1.1893631920263896 1.1622309 1.4096779 1.1893632 1.4368102077954668 1.4096779 1.6571248999999997 1.4368102 1.684257290462536 0.9419161999999998 1.1893631999999998 0.9690485999999999 1.2164955999999998 1.1893631999999998 1.4368101999999998 1.2164955999999996 1.463942600960038 1.4368102 1.6842573 1.4639426 1.711389609537409 0.8655529 1.1129999999999998 0.8926852999999999 1.1401323007819242 1.113 1.3604470000000004 1.1401323000000003 1.387579307795467 1.360447 1.6078939999999997 1.3875793 1.635026390462536 0.8926853 1.1401323 0.9198177 1.1672646912444617 1.1401323000000003 1.3875793000000003 1.1672647 1.4147117009600385 1.3875792999999998 1.6350263999999999 1.4147117 1.662158709537409 0.9198177 1.1672646999999998 0.94695 1.1943970087554958 1.1672647 1.4147117000000002 1.194397 1.4418440895024953 1.4147117000000002 1.6621587 1.4418441000000002 1.6892911 0.8434544 1.0909014000000001 0.8705867 1.1180337904625361 1.0909014 1.3383484 1.1180337999999999 1.365480800960038 1.3383484 1.5857955 1.3654807999999998 1.612927809537409 0.8705866999999998 1.1180337999999999 0.8977190999999999 1.145166109537409 1.1180338 1.3654808000000003 1.1451661 1.3926130902844216 1.3654808 1.6129277999999998 1.3926131 1.640060199218075 0.8977191000000001 1.1451661000000002 0.9248515 1.1722985000000001 1.1451661 1.3926131 1.1722984999999997 1.4197455009600337 1.3926131 1.6400602 1.4197455000000003 1.6671925007819244 0.9097499999999998 1.1571971 0.8876514999999999 1.135098502251015 1.1571970999999999 1.4046440999999998 1.1350985 1.382545509667002 1.4046441 1.6520911 1.3825455 1.6299925988212767 0.9368824000000001 1.1843294 0.9147838000000001 1.1622308988212766 1.1843293999999998 1.4317763999999997 1.1622308999999997 1.4096778892606765 1.4317764 1.6792235 1.4096778999999997 1.657124901178723 0.9640147 1.2114618 0.9419162000000001 1.1893632001064307 1.2114617999999997 1.4589087999999997 1.1893631999999998 1.4368102107392913 1.4589088 1.7063557999999999 1.4368101999999998 1.6842572988212776 0.9911471000000001 1.2385941 0.9690486000000001 1.2164956 1.2385940999999998 1.4860411999999998 1.2164956 1.4639425904393994 1.4860412000000003 1.7334882000000003 1.4639426000000004 1.7113896010722924 0.8876515 1.1350985 0.8655528999999997 1.1129999988212766 1.1350984999999998 1.3825455 1.1129999999999998 1.3604469892606765 1.3825455000000004 1.6299926000000005 1.3604470000000002 1.6078940011787235 0.9147838 1.1622308999999997 0.8926852999999999 1.1401323011787232 1.1622309 1.4096779 1.1401323 1.3875793118115767 1.4096778999999997 1.6571248999999995 1.3875792999999998 1.6350263977489887 0.9419162 1.1893632 0.9198177000000001 1.1672647 1.1893632 1.4368102 1.1672647 1.414711689260673 1.4368102 1.6842573 1.4147117 1.6621587022510147 0.9690486 1.2164956 0.9469500000000001 1.1943970010722924 1.2164956 1.4639426 1.194397 1.4418441084882867 1.4639426000000002 1.7113896 1.4418441000000002 1.6892911 0.8655528999999998 1.1129999999999995 0.8434543999999997 1.0909014011787228 1.1129999999999998 1.360447 1.0909013999999997 1.3383484118115767 1.360447 1.6078939999999997 1.3383484 1.5857954977489888 0.8926853 1.1401323 0.8705867 1.118033797748989 1.1401323 1.3875793 1.1180337999999999 1.3654807892606728 1.3875792999999998 1.6350263999999999 1.3654807999999998 1.612927802251015 0.9198177000000001 1.1672647 0.8977191000000001 1.1451661010722924 1.1672646999999998 1.4147116999999998 1.1451660999999997 1.392613109667002 1.4147117 1.6621587 1.3926131 1.6400601988212764 0.94695 1.194397 0.9248514999999998 1.1722985 1.194397 1.4418441 1.1722985 1.4197454904394027 1.4418441000000002 1.6892911 1.4197455000000003 1.6671925 0.9097499999999997 0.9368823999999997 0.8876514999999998 0.9147838882600601 1.1571970999999999 1.1843293999999998 1.1350984999999998 1.1622308020092107 1.4046441 1.4317764 1.3825455 1.4096778117398994 1.6520911 1.6792235 1.6299926 1.6571250078186572 0.9368824 0.9640147 0.9147838 0.9419161019120725 1.1843294 1.2114618 1.1622309 1.1893633078186572 1.4317764 1.4589088 1.4096779 1.4368102882600555 1.6792235 1.7063558 1.6571249 1.6842571921813883 0.9640147 0.9911471 0.9419162 0.9690486000484911 1.2114617999999997 1.2385940999999998 1.1893631999999998 1.2164954921813882 1.4589088 1.4860412 1.4368102 1.4639426097792962 1.7063558000000003 1.7334882000000003 1.6842573000000003 1.7113896979908656 0.8876515 0.9147838 0.8655529 0.8926852117398995 1.1350984999999998 1.1622308999999997 1.1129999999999998 1.140132407818657 1.3825455000000002 1.4096779000000002 1.3604470000000002 1.3875793784322652 1.6299926000000002 1.6571249000000001 1.6078940000000002 1.6350262921813883 0.9147838 0.9419162 0.8926853 0.9198176902206997 1.1622308999999997 1.1893631999999998 1.1401322999999999 1.1672645921813882 1.4096779000000002 1.4368102000000003 1.3875793000000003 1.414711621567728 1.6571248999999995 1.6842572999999996 1.6350263999999997 1.6621587979908652 0.9419162 0.9690486 0.9198177 0.9469501078186573 1.1893632 1.2164956 1.1672647 1.1943970979908654 1.4368102000000003 1.4639426000000002 1.4147117000000002 1.4418440902207037 1.6842573 1.7113896 1.6621587 1.689291002009211 0.8655529000000001 0.8926853000000001 0.8434544000000002 0.870586778432265 1.113 1.1401323 1.0909014 1.1180336921813883 1.3604469999999997 1.3875792999999998 1.3383483999999999 1.3654807215677276 1.607894 1.6350264 1.5857955 1.6129278979908654 0.8926853 0.9198177 0.8705867 0.8977191196071274 1.1401323 1.1672647 1.1180338 1.1451661979908654 1.3875793 1.4147117 1.3654808 1.3926131882600603 1.6350264 1.6621587 1.6129278 1.6400601020092112 0.9198177000000002 0.9469500000000002 0.8977191000000002 0.9248513921813886 1.1672647000000005 1.1943970000000004 1.1451661000000004 1.1722984020092113 1.4147117000000002 1.4418441000000002 1.3926131000000002 1.4197455097792961 1.6621587000000002 1.6892911000000002 1.6400602000000002 1.6671926078186574];

W = convert(Lar.Points, G')

Delta_0 = SparseArrays.sparse(([1, 3, 1, 4, 2, 3, 2, 4, 5, 7, 5, 8, 6, 7, 6, 8, 9, 11, 9, 12, 10, 11, 10, 12, 13, 15, 13, 16, 14, 15, 14, 16, 17, 19, 17, 20, 18, 19, 18, 20, 21, 23, 21, 24, 22, 23, 22, 24, 25, 27, 25, 28, 26, 27, 26, 28, 29, 31, 29, 32, 30, 31, 30, 32, 33, 35, 33, 36, 34, 35, 34, 36, 37, 39, 37, 40, 38, 39, 38, 40, 41, 43, 41, 44, 42, 43, 42, 44, 45, 47, 45, 48, 46, 47, 46, 48, 49, 51, 49, 52, 50, 51, 50, 52, 53, 55, 53, 56, 54, 55, 54, 56, 57, 59, 57, 60, 58, 59, 58, 60, 61, 63, 61, 64, 62, 63, 62, 64, 65, 67, 65, 68, 66, 67, 66, 68, 69, 71, 69, 72, 70, 71, 70, 72, 73, 75, 73, 76, 74, 75, 74, 76, 77, 79, 77, 80, 78, 79, 78, 80, 81, 83, 81, 84, 82, 83, 82, 84, 85, 87, 85, 88, 86, 87, 86, 88, 89, 91, 89, 92, 90, 91, 90, 92, 93, 95, 93, 96, 94, 95, 94, 96, 97, 99, 97, 100, 98, 99, 98, 100, 101, 103, 101, 104, 102, 103, 102, 104, 105, 107, 105, 108, 106, 107, 106, 108, 109, 111, 109, 112, 110, 111, 110, 112, 113, 115, 113, 116, 114, 115, 114, 116, 117, 119, 117, 120, 118, 119, 118, 120, 121, 123, 121, 124, 122, 123, 122, 124, 125, 127, 125, 128, 126, 127, 126, 128, 129, 131, 129, 132, 130, 131, 130, 132, 133, 135, 133, 136, 134, 135, 134, 136, 137, 139, 137, 140, 138, 139, 138, 140, 141, 143, 141, 144, 142, 143, 142, 144, 145, 147, 145, 148, 146, 147, 146, 148, 149, 151, 149, 152, 150, 151, 150, 152, 153, 155, 153, 156, 154, 155, 154, 156, 157, 159, 157, 160, 158, 159, 158, 160, 161, 163, 161, 164, 162, 163, 162, 164, 165, 167, 165, 168, 166, 167, 166, 168, 169, 171, 169, 172, 170, 171, 170, 172, 173, 175, 173, 176, 174, 175, 174, 176, 177, 179, 177, 180, 178, 179, 178, 180, 181, 183, 181, 184, 182, 183, 182, 184, 185, 187, 185, 188, 186, 187, 186, 188, 189, 191, 189, 192, 190, 191, 190, 192, 193, 195, 193, 196, 194, 195, 194, 196, 197, 199, 197, 200, 198, 199, 198, 200, 201, 203, 201, 204, 202, 203, 202, 204, 205, 207, 205, 208, 206, 207, 206, 208, 209, 211, 209, 212, 210, 211, 210, 212, 213, 215, 213, 216, 214, 215, 214, 216, 217, 219, 217, 220, 218, 219, 218, 220, 221, 223, 221, 224, 222, 223, 222, 224, 225, 227, 225, 228, 226, 227, 226, 228, 229, 231, 229, 232, 230, 231, 230, 232, 233, 235, 233, 236, 234, 235, 234, 236, 237, 239, 237, 240, 238, 239, 238, 240, 241, 243, 241, 244, 242, 243, 242, 244, 245, 247, 245, 248, 246, 247, 246, 248, 249, 251, 249, 252, 250, 251, 250, 252, 253, 255, 253, 256, 254, 255, 254, 256, 257, 259, 257, 260, 258, 259, 258, 260, 261, 263, 261, 264, 262, 263, 262, 264, 265, 267, 265, 268, 266, 267, 266, 268, 269, 271, 269, 272, 270, 271, 270, 272, 273, 275, 273, 276, 274, 275, 274, 276, 277, 279, 277, 280, 278, 279, 278, 280, 281, 283, 281, 284, 282, 283, 282, 284, 285, 287, 285, 288, 286, 287, 286, 288, 289, 291, 289, 292, 290, 291, 290, 292, 293, 295, 293, 296, 294, 295, 294, 296, 297, 299, 297, 300, 298, 299, 298, 300, 301, 303, 301, 304, 302, 303, 302, 304, 305, 307, 305, 308, 306, 307, 306, 308, 309, 311, 309, 312, 310, 311, 310, 312, 313, 315, 313, 316, 314, 315, 314, 316, 317, 319, 317, 320, 318, 319, 318, 320, 321, 323, 321, 324, 322, 323, 322, 324, 325, 327, 325, 328, 326, 327, 326, 328, 329, 331, 329, 332, 330, 331, 330, 332, 333, 335, 333, 336, 334, 335, 334, 336, 337, 339, 337, 340, 338, 339, 338, 340, 341, 343, 341, 344, 342, 343, 342, 344, 345, 347, 345, 348, 346, 347, 346, 348, 349, 351, 349, 352, 350, 351, 350, 352, 353, 355, 353, 356, 354, 355, 354, 356, 357, 359, 357, 360, 358, 359, 358, 360, 361, 363, 361, 364, 362, 363, 362, 364, 365, 367, 365, 368, 366, 367, 366, 368, 369, 371, 369, 372, 370, 371, 370, 372, 373, 375, 373, 376, 374, 375, 374, 376, 377, 379, 377, 380, 378, 379, 378, 380, 381, 383, 381, 384, 382, 383, 382, 384, 385, 387, 385, 388, 386, 387, 386, 388, 389, 391, 389, 392, 390, 391, 390, 392, 393, 395, 393, 396, 394, 395, 394, 396, 397, 399, 397, 400, 398, 399, 398, 400, 401, 403, 401, 404, 402, 403, 402, 404, 405, 407, 405, 408, 406, 407, 406, 408, 409, 411, 409, 412, 410, 411, 410, 412, 413, 415, 413, 416, 414, 415, 414, 416, 417, 419, 417, 420, 418, 419, 418, 420, 421, 423, 421, 424, 422, 423, 422, 424, 425, 427, 425, 428, 426, 427, 426, 428, 429, 431, 429, 432, 430, 431, 430, 432], [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, 256, 256, 257, 257, 258, 258, 259, 259, 260, 260, 261, 261, 262, 262, 263, 263, 264, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 270, 270, 271, 271, 272, 272, 273, 273, 274, 274, 275, 275, 276, 276, 277, 277, 278, 278, 279, 279, 280, 280, 281, 281, 282, 282, 283, 283, 284, 284, 285, 285, 286, 286, 287, 287, 288, 288, 289, 289, 290, 290, 291, 291, 292, 292, 293, 293, 294, 294, 295, 295, 296, 296, 297, 297, 298, 298, 299, 299, 300, 300, 301, 301, 302, 302, 303, 303, 304, 304, 305, 305, 306, 306, 307, 307, 308, 308, 309, 309, 310, 310, 311, 311, 312, 312, 313, 313, 314, 314, 315, 315, 316, 316, 317, 317, 318, 318, 319, 319, 320, 320, 321, 321, 322, 322, 323, 323, 324, 324, 325, 325, 326, 326, 327, 327, 328, 328, 329, 329, 330, 330, 331, 331, 332, 332, 333, 333, 334, 334, 335, 335, 336, 336, 337, 337, 338, 338, 339, 339, 340, 340, 341, 341, 342, 342, 343, 343, 344, 344, 345, 345, 346, 346, 347, 347, 348, 348, 349, 349, 350, 350, 351, 351, 352, 352, 353, 353, 354, 354, 355, 355, 356, 356, 357, 357, 358, 358, 359, 359, 360, 360, 361, 361, 362, 362, 363, 363, 364, 364, 365, 365, 366, 366, 367, 367, 368, 368, 369, 369, 370, 370, 371, 371, 372, 372, 373, 373, 374, 374, 375, 375, 376, 376, 377, 377, 378, 378, 379, 379, 380, 380, 381, 381, 382, 382, 383, 383, 384, 384, 385, 385, 386, 386, 387, 387, 388, 388, 389, 389, 390, 390, 391, 391, 392, 392, 393, 393, 394, 394, 395, 395, 396, 396, 397, 397, 398, 398, 399, 399, 400, 400, 401, 401, 402, 402, 403, 403, 404, 404, 405, 405, 406, 406, 407, 407, 408, 408, 409, 409, 410, 410, 411, 411, 412, 412, 413, 413, 414, 414, 415, 415, 416, 416, 417, 417, 418, 418, 419, 419, 420, 420, 421, 421, 422, 422, 423, 423, 424, 424, 425, 425, 426, 426, 427, 427, 428, 428, 429, 429, 430, 430, 431, 431, 432, 432], Int8[-1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1])...);

Delta_1 = SparseArrays.sparse(([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107, 108, 108, 108, 108], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432], Int8[1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1])...);

T = [Delta_0, Delta_1];

@benchmark LC.chainCongruenceSM(G, T)

#@benchmark chainCongruenceSM(W, T)

@benchmark LC.chainCongruenceAA(W, T)

Delta_0_GB = SparseMM.sm2gbm(Delta_0)
Delta_1_GB = SparseMM.sm2gbm(Delta_1)
T_GB = [Delta_0_GB, Delta_1_GB]

@benchmark LC.chainCongruenceGB(W, T_GB)


text:
"""
KernelFunctions. [Github](https://github.com/theogf/KernelFunctions.jl) [Documentation](https://theogf.github.io/KernelFunctions.jl/dev/)
"""
module KernelFunctions

export kernelmatrix, kernelmatrix!, kerneldiagmatrix, kerneldiagmatrix!, kappa
export transform
export params, duplicate, set! # Helpers

export Kernel
export ConstantKernel, WhiteKernel, EyeKernel, ZeroKernel
export SqExponentialKernel, ExponentialKernel, GammaExponentialKernel
export ExponentiatedKernel
export MaternKernel, Matern32Kernel, Matern52Kernel
export LinearKernel, PolynomialKernel
export RationalQuadraticKernel, GammaRationalQuadraticKernel
export KernelSum, KernelProduct
export TransformedKernel, ScaledKernel

export Transform, SelectTransform, ChainTransform, ScaleTransform, LowRankTransform, IdentityTransform, FunctionTransform

export NystromFact, nystrom

using Compat
using Requires
using Distances, LinearAlgebra
using SpecialFunctions: logabsgamma, besselk
using ZygoteRules: @adjoint
using StatsFuns: logtwo
using InteractiveUtils: subtypes
using StatsBase

const defaultobs = 2

"""
Abstract type defining a slice-wise transformation on an input matrix
"""
abstract type Transform end
abstract type Kernel end
abstract type BaseKernel <: Kernel end

include("utils.jl")
include("distances/dotproduct.jl")
include("distances/delta.jl")
include("transform/transform.jl")

for k in ["exponential","matern","polynomial","constant","rationalquad","exponentiated","cosine"]
    include(joinpath("kernels",k*".jl"))
end
include("kernels/transformedkernel.jl")
include("kernels/scaledkernel.jl")
include("matrix/kernelmatrix.jl")
include("kernels/kernelsum.jl")
include("kernels/kernelproduct.jl")
include("approximations/nystrom.jl")
include("generic.jl")

include("zygote_adjoints.jl")

function __init__()
    @require Kronecker="2c470bb0-bcc8-11e8-3dad-c9649493f05e" include("matrix/kernelkroneckermat.jl")
    @require PDMats="90014a1f-27ba-587c-ab20-58faa44d9150" include("matrix/kernelpdmat.jl")
    @require Flux="587475ba-b771-5e3f-ad9e-33799f191a9c" include("trainable.jl")
end

end


text:
@testset "Static graphs" begin
    g = @inferred(CompleteDiGraph(5))
    @test nv(g) == 5 && ne(g) == 20
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = CompleteDiGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteDiGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = CompleteDiGraph(2)
    @test nv(g) == 2 && ne(g) == 2
    g = @inferred CompleteDiGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127 * (127 - 1)
    @test eltype(g) == Int8

    g = @inferred(CompleteGraph(5))
    @test nv(g) == 5 && ne(g) == 10
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = CompleteGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = CompleteGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    g = @inferred CompleteGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127 * (127 - 1) ÷ 2
    @test eltype(g) == Int8

    g = @inferred(CompleteBipartiteGraph(5, 8))
    @test nv(g) == 13 && ne(g) == 40
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = CompleteBipartiteGraph(0,0)
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteBipartiteGraph(5,0)
    @test nv(g) == 5 && ne(g) == 0
    g = CompleteBipartiteGraph(0,5)
    @test nv(g) == 5 && ne(g) == 0
    g = @inferred CompleteBipartiteGraph(Int8(100), Int8(27))
    @test nv(g) == 127 && ne(g) == 100 * 27
    @test eltype(g) == Int8
    g = CompleteBipartiteGraph(Int8(127), Int8(0))
    @test nv(g) == 127 && ne(g) == 0
    g = CompleteBipartiteGraph(Int8(0), Int8(127))
    @test nv(g) == 127 && ne(g) == 0

    function iscompletemultipartite(g, partitions)
      sum(partitions) != nv(g) && return false
      n = nv(g)

      edges = 0
      for p in partitions
        edges += p*(Int(n)-p)
      end
      edges = div(edges, 2)

      edges != ne(g) && return false

      cur = 1
      for p in partitions
        currange = cur:(cur+p-1)
        lowerrange = 1:(cur-1)
        upperrange = (cur+p):n
        for u in currange
          for v in currange # check that no vertices are connected to vertices in the same partition
            has_edge(g, u, v) && return false
          end

          for v in lowerrange # check all lower partition vertices
            !has_edge(g, u, v) && return false
          end

          for v in upperrange # check all higher partition vertices
            !has_edge(g, u, v) && return false
          end
        end
        cur += p
      end
      return true
    end

    g = @inferred(CompleteMultipartiteGraph([5, 8, 3]))
    @test nv(g) == 16 && ne(g) == 79
    @test isvalid_simplegraph(g)
    @test iscompletemultipartite(g, [5, 8, 3])
    # tests for extreme values
    g = CompleteMultipartiteGraph([0, 0, 0])
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteMultipartiteGraph(Int[])
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteMultipartiteGraph([5, 0, 3])
    @test nv(g) == 8 && ne(g) == 15
    @test iscompletemultipartite(g, [5, 0, 3])
    g = CompleteMultipartiteGraph(Int8[100, 25, 2])
    @test nv(g) == 127 && ne(g) == 2750
    @test eltype(g) == Int8
    @test iscompletemultipartite(g, [100, 25, 2])
    g = CompleteMultipartiteGraph([0, 10, 0, 2, 0, 3, 0, 0, 6, 0])
    @test nv(g) == 21 && ne(g) == 146
    @test iscompletemultipartite(g, [0, 10, 0, 2, 0, 3, 0, 0, 6, 0])
    g = CompleteMultipartiteGraph([5, 3, -1])
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteMultipartiteGraph([-5, 0, -11])
    @test nv(g) == 0 && ne(g) == 0
    g = CompleteMultipartiteGraph([5, 3])
    h = CompleteMultipartiteGraph([5, 0, 3])
    j = CompleteMultipartiteGraph([0, 5, 0, 3, 0, 0])
    @test g == h == j
    @test_throws InexactError CompleteMultipartiteGraph(Int8[100, 20, 20])

    function retrievepartitions(n, r)
      partitions = partitions = Vector{Int}(undef, r)
      c = cld(n,r)
      f = fld(n,r)
      for i in 1:(n%r)
        partitions[i] = c
      end
      for i in ((n%r)+1):r
        partitions[i] = f
      end
      return partitions
    end

    g = @inferred(TuranGraph(13, 4))
    @test nv(g) == 13 && ne(g) == 63
    @test isvalid_simplegraph(g)
    @test iscompletemultipartite(g, retrievepartitions(13, 4))
    # testing smaller int types
    g = TuranGraph(Int8(11), Int8(6))
    @test nv(g) == 11 && ne(g) == 50
    @test iscompletemultipartite(g, retrievepartitions(11, 6))
    g = TuranGraph(Int16(35), Int16(17))
    @test nv(g) == 35 && ne(g) == 576
    @test iscompletemultipartite(g, retrievepartitions(35, 17))
    # tests for extreme values
    g = TuranGraph(15,15)
    @test nv(g) == 15 && ne(g) == 105
    @test iscompletemultipartite(g, retrievepartitions(15, 15))
    g = TuranGraph(10, 1)
    @test nv(g) == 10 && ne(g) == 0
    @test iscompletemultipartite(g, retrievepartitions(10, 1))
    @test_throws DomainError TuranGraph(3,0)
    @test_throws DomainError TuranGraph(0,4)
    @test_throws DomainError TuranGraph(3,4)
    @test_throws DomainError TuranGraph(-1,5)
    @test_throws DomainError TuranGraph(3,-6)

    g = @inferred(StarGraph(5))
    @test nv(g) == 5 && ne(g) == 4
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = StarGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = StarGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = StarGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    g = @inferred StarGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127 - 1
    @test eltype(g) == Int8

    g = @inferred(StarDiGraph(5))
    @test nv(g) == 5 && ne(g) == 4
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = StarDiGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = StarDiGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = StarDiGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    @test first(edges(g)) == Edge(1, 2) # edges should point outwards from vertex 1
    g = @inferred StarDiGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127 - 1
    @test eltype(g) == Int8

    g = @inferred(PathDiGraph(5))
    @test nv(g) == 5 && ne(g) == 4
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = PathDiGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = PathDiGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = @inferred PathDiGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 126
    @test eltype(g) == Int8

    g = @inferred(PathGraph(5))
    @test nv(g) == 5 && ne(g) == 4
    @test isvalid_simplegraph(g)
    # tests for extreme values
    g = PathGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = PathGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = @inferred PathGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 126
    @test eltype(g) == Int8

    g = @inferred(CycleDiGraph(5))
    @test nv(g) == 5 && ne(g) == 5
    @test isvalid_simplegraph(g)
     # tests for extreme values
    g = CycleDiGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = CycleDiGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = CycleDiGraph(2)
    @test nv(g) == 2 && ne(g) == 2
    g = @inferred CycleDiGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127
    @test eltype(g) == Int8

    g = @inferred(CycleGraph(5))
    @test nv(g) == 5 && ne(g) == 5
    @test isvalid_simplegraph(g)
     # tests for extreme values
    g = CycleGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = CycleGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = CycleGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    g = @inferred CycleGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 127
    @test eltype(g) == Int8

    g = @inferred(WheelDiGraph(5))
    @test nv(g) == 5 && ne(g) == 8
    @test isvalid_simplegraph(g)
      # tests for extreme values
    g = WheelDiGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = WheelDiGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = WheelDiGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    g = WheelDiGraph(3)
    @test nv(g) == 3 && ne(g) == 4
    g = @inferred WheelDiGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 2 * 126
    @test eltype(g) == Int8

    g = @inferred(WheelGraph(5))
    @test nv(g) == 5 && ne(g) == 8
    @test isvalid_simplegraph(g)
      # tests for extreme values
    g = WheelGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = WheelGraph(1)
    @test nv(g) == 1 && ne(g) == 0
    g = WheelGraph(2)
    @test nv(g) == 2 && ne(g) == 1
    g = WheelGraph(3)
    @test nv(g) == 3 && ne(g) == 3
    g = @inferred WheelGraph(Int8(127))
    @test nv(g) == 127 && ne(g) == 2 * 126
    @test eltype(g) == Int8

    g = @inferred(Grid([3, 3, 4]))
    @test nv(g) == 3 * 3 * 4
    @test ne(g) == 75
    @test Δ(g) == 6
    @test δ(g) == 3
    @test isvalid_simplegraph(g)

    g = @inferred(Grid([3, 3, 4], periodic=true))
    @test nv(g) == 3 * 3 * 4
    @test ne(g) == 108
    @test Δ(g) == 6
    @test δ(g) == 6
    @test isvalid_simplegraph(g)

    g = @inferred(CliqueGraph(3, 5))
    @test nv(g) == 15 && ne(g) == 20
    @test g[1:3] == CompleteGraph(3)
    @test isvalid_simplegraph(g)

    g = @inferred(crosspath(3, BinaryTree(2)))
    # f = Vector{Vector{Int}}[[2 3 4];
    # [1 5];
    # [1 6];
    # [1 5 6 7];
    # [2 4 8];
    # [3 4 9];
    # [4 8 9];
    # [5 7];
    # [6 7]
    # ]
    I = [1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9]
    J = [2, 3, 4, 1, 5, 1, 6, 1, 5, 6, 7, 2, 4, 8, 3, 4, 9, 4, 8, 9, 5, 7, 6, 7]
    V = ones(Int, length(I))
    Adj = sparse(I, J, V)
    @test Adj == sparse(g)
    @test isvalid_simplegraph(g)
    @test_throws DomainError BinaryTree(Int8(8))

    g = @inferred(DoubleBinaryTree(3))
    # [[3, 2, 8]
    # [4, 1, 5]
    # [1, 6, 7]
    # [2]
    # [2]
    # [3]
    # [3]
    # [10, 9, 1]
    # [11, 8, 12]
    # [8, 13, 14]
    # [9]
    # [9]
    # [10]
    # [10]]
    I = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 12, 13, 14]
    J = [3, 2, 8, 4, 1, 5, 1, 6, 7, 2, 2, 3, 3, 10, 9, 1, 11, 8, 12, 8, 13, 14, 9, 9, 10, 10]
    V = ones(Int, length(I))
    Adj = sparse(I, J, V)
    @test Adj == sparse(g)
    @test isvalid_simplegraph(g)

    rg3 = @inferred(RoachGraph(3))
    # [3]
    # [4]
    # [1, 5]
    # [2, 6]
    # [3, 7]
    # [4, 8]
    # [9, 8, 5]
    # [10, 7, 6]
    # [11, 10, 7]
    # [8, 9, 12]
    # [9, 12]
    # [10, 11]
    I = [1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12]
    J = [3, 4, 1, 5, 2, 6, 3, 7, 4, 8, 9, 8, 5, 10, 7, 6, 11, 10, 7, 8, 9, 12, 9, 12, 10, 11]
    V = ones(Int, length(I))
    Adj = sparse(I, J, V)
    @test Adj == sparse(rg3)
    @test isvalid_simplegraph(g)

    function isladdergraph(g)
      n = nv(g)÷2
      !(degree(g, 1) == degree(g, n) == degree(g, n+1) == degree(g, 2*n) == 2) && return false
      !(has_edge(g, 1, n+1) && has_edge(g, n, 2*n)) && return false
      !(has_edge(g, 1, 2) && has_edge(g, n, n-1) && has_edge(g, n+1, n+2) && has_edge(g, 2*n, 2*n-1) ) && return false
      for i in 2:(n-1)
        !(degree(g, i) == 3 && degree(g, n+i) == 3) && return false
        !(has_edge(g, i, i%n +1) && has_edge(g, i, i+n)) && return false
        !(has_edge(g, n+i,n+(i%n +1)) && has_edge(g, n+i, i)) && return false
      end
      return true
    end

    g = @inferred(LadderGraph(5))
    @test nv(g) == 10 && ne(g) == 13
    @test isvalid_simplegraph(g)
    @test isladdergraph(g)
    # tests for extreme values
    g = LadderGraph(0)
    @test nv(g) == 0 && ne(g) == 0
    g = LadderGraph(1)
    @test nv(g) == 2 && ne(g) == 1
    g = @inferred LadderGraph(-1)
    @test nv(g) == 0 && ne(g) == 0
    g = LadderGraph(Int8(63))
    @test nv(g) == 126 && ne(g) == 187
    @test eltype(g) == Int8
    @test isladdergraph(g)
    # tests for errors
    @test_throws InexactError LadderGraph(Int8(64))

    function iscircularladdergraph(g)
      n = nv(g)÷2
      for i in 1:n
        !(degree(g, i) == 3 && degree(g, n+i) == 3) && return false
        !(has_edge(g, i, i%n +1) && has_edge(g, i, i+n)) && return false
        !(has_edge(g, n+i,n+(i%n +1)) && has_edge(g, n+i, i)) && return false
      end
      return true
    end

    g = @inferred(CircularLadderGraph(5))
    @test nv(g) == 10 && ne(g) == 15
    @test isvalid_simplegraph(g)
    @test iscircularladdergraph(g)
    # tests for extreme values
    g = CircularLadderGraph(3)
    @test nv(g) == 6 && ne(g) == 9
    @test iscircularladdergraph(g)
    g = CircularLadderGraph(Int8(63))
    @test nv(g) == 126 && ne(g) == 189
    @test eltype(g) == Int8
    @test iscircularladdergraph(g)
    # tests for errors
    @test_throws InexactError CircularLadderGraph(Int8(64))
    @test_throws DomainError CircularLadderGraph(-1)
    @test_throws DomainError CircularLadderGraph(0)
    @test_throws DomainError CircularLadderGraph(1)
    @test_throws DomainError CircularLadderGraph(2)

    # checking that the nodes are organized correctly
    # see the docstring implementation notes for LollipopGraph
    function isbarbellgraph(g, n1, n2)
      nv(g) != n1+n2 && return false
      ne(g) != n1*(n1-1)÷2+n2*(n2-1)÷2 +1 && return false
      for i in 1:n1
        for j in (i+1):n1
          !has_edge(g, i, j) && return false
        end
      end

      for i in n1 .+ 1:n2
        for j in (i+1):(n1+n2)
          !has_edge(g, i, j) && return false
        end
      end

      !has_edge(g, n1, n1+1) && return false
      return true
    end

    g = @inferred(BarbellGraph(5, 6))
    @test nv(g) == 11 && ne(g) == 26
    @test isvalid_simplegraph(g)
    @test isbarbellgraph(g, 5, 6)
    g = BarbellGraph(Int8(5), Int8(6))
    @test nv(g) == 11 && ne(g) == 26
    @test isvalid_simplegraph(g)
    @test isbarbellgraph(g, 5, 6)
    # extreme values
    g = BarbellGraph(1, 5)
    @test nv(g) == 6 && ne(g) == 11
    @test isbarbellgraph(g, 1, 5)
    g = BarbellGraph(5, 1)
    @test nv(g) == 6 && ne(g) == 11
    @test isbarbellgraph(g, 5, 1)
    g = BarbellGraph(1, 1)
    @test nv(g) == 2 && ne(g) == 1
    @test isbarbellgraph(g, 1, 1)
    @test_throws OverflowError BarbellGraph(Int8(100), Int8(50))
    @test_throws DomainError BarbellGraph(1, 0)
    @test_throws DomainError BarbellGraph(0, 1)
    @test_throws DomainError BarbellGraph(-1, -1)

    # checking that the nodes are organized correctly
    # see the docstring implementation notes for LollipopGraph
    function islollipopgraph(g, n1, n2)
      nv(g) != n1+n2 && return false
      ne(g) != n1*(n1-1)÷2+n2 && return false
      for i in 1:n1
        for j in (i+1):n1
          !has_edge(g, i, j) && return false
        end
      end

      for i in n1 .+ 1:(n2-1)
        !has_edge(g, i, i+1) && return false
      end

      !has_edge(g, n1, n1+1) && return false

      return true
    end

    g = @inferred(LollipopGraph(3, 5))
    @test nv(g) == 8 && ne(g) == 8
    @test isvalid_simplegraph(g)
    @test islollipopgraph(g, 3, 5)
    g = LollipopGraph(Int8(7), Int8(6))
    @test nv(g) == 13 && ne(g) == 27
    @test isvalid_simplegraph(g)
    @test islollipopgraph(g, 7, 6)
    # extreme values
    g = LollipopGraph(1, 3)
    @test nv(g) == 4 && ne(g) == 3
    @test islollipopgraph(g, 1, 3)
    g = LollipopGraph(3, 1)
    @test nv(g) == 4 && ne(g) == 4
    @test islollipopgraph(g, 3, 1)
    g = LollipopGraph(1, 1)
    @test nv(g) == 2 && ne(g) == 1
    @test islollipopgraph(g, 1, 1)
    @test_throws OverflowError LollipopGraph(Int8(100), Int8(50))
    @test_throws DomainError LollipopGraph(1, 0)
    @test_throws DomainError LollipopGraph(0, 1)
    @test_throws DomainError LollipopGraph(-1, -1)
end


text:
empty!(Base.DEPOT_PATH)
push!(Base.DEPOT_PATH, mktempdir(; cleanup = true))

import Pkg
import Logging
import TOML

Pkg.add(; name = "Coverage", uuid = "a2441757-f6aa-5fb2-8edb-039e3f45d037", version = "1")
Pkg.precompile()

import Coverage

function get_external_stdlib_names(stdlib_dir::AbstractString)
    filename_list = filter(x -> isfile(joinpath(stdlib_dir, x)), readdir(stdlib_dir))
    # find all of the files like `Pkg.version`, `Statistics.version`, etc.
    regex_matches_or_nothing = match.(Ref(r"^([\w].*?)\.version$"), filename_list)
    regex_matches = filter(x -> x !== nothing, regex_matches_or_nothing)
    # get the names of the external stdlibs, like `Pkg`, `Statistics`, etc.
    external_stdlib_names = only.(regex_matches)
    unique!(external_stdlib_names)
    sort!(external_stdlib_names)
    @info "# Begin list of external stdlibs"
    for (i, x) in enumerate(external_stdlib_names)
        @info "$(i). $(x)"
    end
    @info "# End list of external stdlibs"
    return external_stdlib_names
end

function get_external_stdlib_prefixes(stdlib_dir::AbstractString)
    external_stdlib_names = get_external_stdlib_names(stdlib_dir)
    prefixes_1 = joinpath.(Ref(stdlib_dir), external_stdlib_names, Ref(""))
    prefixes_2 = joinpath.(Ref(stdlib_dir), string.(external_stdlib_names, Ref("-")))
    prefixes = vcat(prefixes_1, prefixes_2)
    unique!(prefixes)
    sort!(prefixes)
    # example of what `prefixes` might look like:
    # 4-element Vector{String}:
    # "stdlib/Pkg-"
    # "stdlib/Pkg/"
    # "stdlib/Statistics-"
    # "stdlib/Statistics/"
    return prefixes
end

function print_coverage_summary(fc::Coverage.FileCoverage)
    cov_lines, tot_lines = Coverage.get_summary(fc)
    if cov_lines == tot_lines == 0
        cov_pct = 0
    else
        cov_pct = floor(Int, cov_lines/tot_lines * 100)
    end
    pad_1 = 71
    pad_2 = 15
    pad_3 = 15
    col_1 = rpad(fc.filename, pad_1)
    col_2 = rpad(string(cov_pct, " %"), pad_2)
    col_3 = string(
        rpad(string(cov_lines), pad_3),
        string(tot_lines),
    )
    @info "$(col_1) $(col_2) $(col_3)"
    return nothing
end

function print_coverage_summary(
        fcs::Vector{Coverage.FileCoverage}, description::AbstractString,
    )
    cov_lines, tot_lines = Coverage.get_summary(fcs)
    if cov_lines == tot_lines == 0
        cov_pct = 0
    else
        cov_pct = floor(Int, cov_lines/tot_lines * 100)
    end
    @info "$(description): $(cov_pct)% ($(cov_lines)/$(tot_lines))"
    return nothing
end

# `Coverage.process_folder` will have a LOT of `@info` statements that will make the log
# way too long. So before we run `Coverage.process_folder`, we disable logging for `@info`
# statements. After we run `Coverage.process_folder`, we re-enable logging for `@info`
# statements.
Logging.disable_logging(Logging.Info)
const fcs = Coverage.merge_coverage_counts(
    Coverage.process_folder("base"),
    Coverage.process_folder("stdlib"),
);
Logging.disable_logging(Logging.Debug)

# Only include source code files. Exclude test files, benchmarking files, etc.
filter!(fcs) do fc
    occursin(r"^base\/", fc.filename) || occursin("/src/", fc.filename)
end;

# Exclude all external stdlibs (stdlibs that live in external repos).
const external_stdlib_prefixes = get_external_stdlib_prefixes("stdlib")
filter!(fcs) do fc
    all(x -> !startswith(fc.filename, x), external_stdlib_prefixes)
end;

# Exclude all stdlib JLLs (stdlibs of the form `stdlib/*_jll/`).
filter!(fcs) do fc
    !occursin(r"^stdlib\/[A-Za-z0-9]*?_jll\/", fc.filename)
end

sort!(fcs; by = fc -> fc.filename)

print_coverage_summary.(fcs);
print_coverage_summary(fcs, "Total")

# In order to upload to Codecov, you need to have the `CODECOV_TOKEN` environment variable defined.
Coverage.Codecov.submit_local(fcs)

# In order to upload to Coveralls, you need to have the `COVERALLS_TOKEN` environment variable defined.
Coverage.Coveralls.submit_local(fcs)

max_stars_repo_name: Cvikli/julia

max_issues_repo_name: tecosaur/julia

max_forks_repo_name: GregPlowman/julia


text:
using JuMP, Mosek, MosekTools, LinearAlgebra, Suppressor, StatsBase, CSV, DataFrames, Ipopt, Compat
include("convexpenalties.jl")
include("alt_min.jl")

results_template = DataFrame(n=Int[], r=Int[], p=Real[], y=Real[],
    error_NN=Real[], error_GD=Real[], error_FN=Real[], error_BM=Real[], error_AM=Real[], rank_NN=Int[], rank_GD=Int[], rank_FN=Int[], rank_BM=Int[], rank_AM=Int[])

results_basispursuit=similar(results_template, 0)

pRange=collect(0.1:0.1:1.0) # You will also need to look at collect(0.05:0.1:0.95), we only did 1/4 here to avoid running ARGS=1-400 on sbatch which might have upset the cluster admin
pSize=size(pRange, 1)
yRange=collect(0.1:0.1:1.0) # You will also need to look at collect(0.05:0.1:0.95), we only did 1/4 here to avoid running ARGS=1-400 on sbatch which might have upset the cluster admin
ySize=size(yRange, 1)

for ARG in ARGS # Varies between 1 and 100
  n=100

  array_num = parse(Int, ARG)

  y=yRange[(array_num-1)÷ySize+1]
  p=pRange[(array_num-1)%pSize+1]
  r=Int(round(n*(1.0-sqrt(1.0-y*p))))
  if r==0
      r=1
  end
  k=r #assume we picked it via say cross-validation (can only show two dimensions on the plot).
  M_L=randn(n, r)
  M_R=randn(n, r)
  M=M_L*M_R'
  numEntriesSampled=Int(round(p*n^2))
  gamma=500/p #This value needs to be changed to reproduce the plots where gamma is a different value

  coords=[repeat(1:n, inner=size(1:n,1)) repeat(1:n, outer=size(1:n,1))];
  entries=sample(1:n^2, Int(numEntriesSampled), replace=false)

  ############## Nuclear norm  #######################################################
  X_NN=getMatrixNuclearNorm(coords, entries, M, n, numEntriesSampled, true)
  @show err_NN=norm(X_NN-M)/norm(M);
  u,v,w=svd(X_NN);
  @show rnk_NN=sum(v.>1e-2);

  ############## Greedy rounding  #####################################################
  @show k
  X_GD,=getMatrixFrobeniusNorm_greedy(coords, entries, M, n, numEntriesSampled, k, gamma, true)

  u,v,w=svd(X_GD);
  @show rnk_GD=sum(v.>1e-2);
  @show err_GD = norm(X_GD.-M)/norm(M);

  # ############# Frobenius random rounding ##############################################
  X_FN=getMatrixFrobeniusNorm_reg2ndstage(coords, entries, M, n, numEntriesSampled, k, gamma, true)
  u,v,w=svd(X_FN);
  rnk_FN=sum(v.>1e-2);
  err_FN = norm(X_FN.-M)/norm(M);

  # ############ Burer-Monterio ##########################################################
  X_BM=getMatrix_BM(coords, entries, M, n, numEntriesSampled, k, gamma)
  u,v,w=svd(X_BM);
  @show rnk_BM=sum(v.>1e-2);
  @show err_BM =norm(X_BM.-M)/norm(M);
  ########### Alternating Minimization ###########################################################
  X_AM=alternatingminimization_matrixcompletion(coords, entries, M, n, numEntriesSampled, k, gamma, 50, X_GD)
  u,v,=svd(X_AM)
  @show rnk_AM=sum(v.>1e-2);
  @show err_AM = norm(X_AM.-M)/norm(M);

  ########### Push results #############################################################

  push!(results_basispursuit, [n, r, p, y, err_NN, err_GD, err_FN, err_BM, err_AM, rnk_NN, rnk_GD, rnk_FN, rnk_BM, rnk_AM])
  CSV.write("signalrecoveryplot.csv", results_basispursuit, append=true)

end

max_stars_repo_name: ryancorywright/MixedProjectionSoftware

max_issues_repo_name: ryancorywright/MixedProjectionSoftware

max_forks_repo_name: ryancorywright/MixedProjectionSoftware


text:
"""
    FastMove(moveType, stab, power, energy, cooldown)

Struct for holding fast moves that holds all information that determines
mechanics: type, STAB (same type attack bonus), power, energy, and cooldown.
Note that this is agnostic to the identity of the actual move itself.
"""
struct FastMove
    moveType::Int8
    stab::Int8
    power::UInt8
    energy::Int8
    cooldown::Int8
end

"""
    FastMove(gm_move, types)

Generate a fast move from the gamemaster entry of the move, and the types of
the mon using it (to determing STAB, same type attack bonus). This should only
be used internally, as generating the move from the name is a lot cleaner.
"""
function FastMove(gm_move::Dict{String,Any}, types)
    return FastMove(
            typings[gm_move["type"]],
            (typings[gm_move["type"]] in types) ? Int8(12) : Int8(1),
            UInt8(gm_move["power"]),
            Int8(gm_move["energyGain"]),
            Int8(gm_move["cooldown"] ÷ 500)
        )
end

"""
    FastMove(move_name, types)

Generate a fast move from the name of the move, and the types of the mon using
it (to determing STAB, same type attack bonus)
"""
function FastMove(move_name::String, types)
    move_index = findfirst(isequal(move_name), map(x ->
        gamemaster["moves"][x]["moveId"], 1:length(gamemaster["moves"])))
    gm_move = gamemaster["moves"][move_index]
    return FastMove(gm_move, types)
end

"""
    ChargedMove(moveType, stab, power, energy, buffChance, opp_buffs, self_buffs)

Struct for holding charged moves that holds all information that determines
mechanics: type, STAB (same type attack bonus), power, energy, and buff
information (chance, which buffs are applied and to whom). Note that this is
agnostic to the identity of the actual move itself.
"""
struct ChargedMove
    moveType::Int8
    stab::Int8
    power::UInt8
    energy::Int8
    buffChance::Int8
    opp_buffs::StatBuffs
    self_buffs::StatBuffs
end

"""
    ChargedMove(gm_move, types)

Generate a charged move from the gamemaster entry of the move, and the types of
the mon using it (to determing STAB, same type attack bonus). This should only
be used internally, as generating the move from the name is a lot cleaner.
"""
function ChargedMove(gm_move::Dict{String,Any}, types)
    return ChargedMove(
        typings[gm_move["type"]],
        (typings[gm_move["type"]] in types) ? Int8(12) : Int8(10),
        UInt8(gm_move["power"]),
        Int8(gm_move["energy"]),
        haskey(gm_move, "buffs") ? round(Int8, parse(Float64,
            gm_move["buffApplyChance"]) * 100) : Int8(0),
        StatBuffs(haskey(gm_move, "buffs") &&
            gm_move["buffTarget"] == "opponent" ?
                Int8(gm_move["buffs"][1]) : Int8(0), haskey(gm_move, "buffs") &&
            gm_move["buffTarget"] == "opponent" ?
                Int8(gm_move["buffs"][2]) : Int8(0)),
        StatBuffs(haskey(gm_move, "buffs") &&
            gm_move["buffTarget"] == "self" ?
                Int8(gm_move["buffs"][1]) : Int8(0), haskey(gm_move, "buffs") &&
            gm_move["buffTarget"] == "self" ?
                Int8(gm_move["buffs"][2]) : Int8(0))
    )
end

"""
    ChargedMove(move_name, types)

Generate a charged move from the name of the move, and the types of the mon
using it (to determing STAB, same type attack bonus)
"""
function ChargedMove(move_name::String, types)
    if move_name == "NONE"
        return ChargedMove(Int8(0), Int8(0), UInt8(0), Int8(0), Int8(0),
            defaultBuff, defaultBuff)
    end
    move_index = findfirst(isequal(move_name), map(x ->
        gamemaster["moves"][x]["moveId"], 1:length(gamemaster["moves"])))
    gm_move = gamemaster["moves"][move_index]
    return ChargedMove(gm_move, types)
end


text:
# Turing.jl version of model at https://github.com/stan-dev/blob/master/misc/cluster/naive-bayes/naive-bayes.stan
# Reference: http://mlg.eng.cam.ac.uk/teaching/4f13/1617/document%20models.pdf
@model nbmodel(K, V, M, N, z, w, doc, alpha, beta) = begin
  theta ~ Dirichlet(alpha)
  phi = TArray{Any}(K)
  for k = 1:K
    phi[k] ~ Dirichlet(beta)
  end
  #for m = 1:M
  #  z[m] ~ Categorical(theta)
  #end

  log_theta = log.(theta)
  _lp += sum(log_theta[z])

  log_phi = map(x->log.(x), phi)
  _lp += mapreduce(n->log_phi[z[doc[n]]][w[n]], +, 1:N)
  # Turing.acclogp!(vi, lp)

  phi
end


text:
module ByVal

using CUDA, BenchmarkTools, Random

const threads = 256

# simple add matrixes kernel
function kernel_add_mat(n, x1, x2, y)
    i = (blockIdx().x-1) * blockDim().x + threadIdx().x
    if i <= n
        @inbounds y[i] = x1[i] + x2[i]
    end
    return
end

@inline get_inputs3(indx_y, a, b, c)                            = (a, b, c)
@inline get_inputs3(indx_y, a1, a2, b1, b2, c1, c2)             = indx_y == 1 ? (a1, b1, c1) : (a2, b2, c2)
@inline get_inputs3(indx_y, a1, a2, a3, b1, b2, b3, c1, c2, c3) = indx_y == 1 ? (a1, b1, c1) : indx_y == 2 ? (a2, b2, c2) : (a3, b3, c3)

# add arrays of matrixes kernel
function kernel_add_mat_z_slices(n, vararg...)
    x1, x2, y = get_inputs3(blockIdx().y, vararg...)
    i = (blockIdx().x-1) * blockDim().x + threadIdx().x
    if i <= n
        @inbounds y[i] = x1[i] + x2[i]
    end
    return
end

function add_z_slices!(y, x1, x2)
    m1, n1 = size(x1[1]) #get size of first slice
    blocks = (m1 * n1 + threads - 1) ÷ threads
    # get length(x1) more blocks than needed to process 1 slice
    @cuda blocks = blocks, length(x1) threads = threads kernel_add_mat_z_slices(m1 * n1, x1..., x2..., y...)
end

function add!(y, x1, x2)
    m1, n1 = size(x1)
    blocks = (m1 * n1 + threads - 1) ÷ threads
    @cuda blocks = blocks, 1          threads = threads kernel_add_mat(m1 * n1, x1, x2, y)
end

function main()
    results = BenchmarkGroup()

    num_z_slices = 3
    Random.seed!(1)

    #m, n = 7, 5          # tiny to measure overhead
    #m, n = 521, 111
    #m, n = 1521, 1111
    #m, n = 3001, 1511    # prime numbers to test memory access correctness
    m, n = 3072, 1536    # 256 multiplier
    #m, n = 6007, 3001    # prime numbers to test memory access correctness

    x1 = [cu(randn(Float32, (m, n)) .+ Float32(0.5)) for i = 1:num_z_slices]
    x2 = [cu(randn(Float32, (m, n)) .+ Float32(0.5)) for i = 1:num_z_slices]
    y1 = [similar(x1[1]) for i = 1:num_z_slices]

    # reference down to bones add on GPU
    results["reference"] = @benchmark CUDA.@sync add!($y1[1], $x1[1], $x2[1])

    # adding arrays in an array
    for slices = 1:num_z_slices
        results["slices=$slices"] = @benchmark CUDA.@sync add_z_slices!($y1[1:$slices], $x1[1:$slices], $x2[1:$slices])
    end

    # BenchmarkTools captures inputs, JuliaCI/BenchmarkTools.jl#127, so forcibly free them
    CUDA.unsafe_free!.(x1)
    CUDA.unsafe_free!.(x2)
    CUDA.unsafe_free!.(y1)

    return results
end

end

ByVal.main()


text:
importall Bukdu

type TextController <: ApplicationController
end

layout(::Layout, body) = """empty layout"""
index(::TextController) = render(Text)
index_with_layout(::TextController) = render(Text/Layout)

Router() do
    get("/index", TextController, index)
    get("/index_with_layout", TextController, index_with_layout)
end

using Base.Test
conn = (Router)(get, "/index")
@test 200 == conn.status
@test "text/plain" == conn.resp_header["Content-Type"]
@test "" == conn.resp_body

logs = []
before(render, Text) do
    push!(logs, "b")
end
after(render, Text) do
    push!(logs, "a")
end

conn = (Router)(get, "/index")
@test "" == conn.resp_body
@test ["b", "a"] == logs
empty!(logs)

conn = (Router)(get, "/index_with_layout")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "empty layout" == conn.resp_body
@test ["b", "a"] == logs
empty!(logs)

layout(::Layout, body::String) = """layout - $body"""
index1(::TextController) = render(Text, "hello")
index_with_layout1(::TextController) = render(Text/Layout, "hello")

Router() do
    get("/index1", TextController, index1)
    get("/index_with_layout1", TextController, index_with_layout1)
end

conn = (Router)(get, "/index1")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "hello" == conn.resp_body
@test [] == logs

before(render, Text) do body
    push!(logs, "b $body")
end
after(render, Text) do body
    push!(logs, "a $body")
end

conn = (Router)(get, "/index1")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "hello" == conn.resp_body
@test ["b hello", "a hello"] == logs
empty!(logs)

conn = (Router)(get, "/index_with_layout1")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "layout - hello" == conn.resp_body
@test ["b hello", "a hello"] == logs
empty!(logs)

before(render, Text/Layout) do body
    push!(logs, "bl $body")
end
after(render, Text/Layout) do body
    push!(logs, "al $body")
end

conn = (Router)(get, "/index1")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "hello" == conn.resp_body
@test ["b hello", "a hello"] == logs
empty!(logs)

conn = (Router)(get, "/index_with_layout1")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "layout - hello" == conn.resp_body
@test ["bl hello","b hello","a hello","al hello"] == logs
empty!(logs)

layout(::Layout, body::String, c::TextController) = """layout2 - $body, $c"""
index2(c::TextController) = render(Text, "foo", c)
index_with_layout2(c::TextController) = render(Text/Layout, "foo", c)

Router() do
    get("/index2", TextController, index2)
    get("/index_with_layout2", TextController, index_with_layout2)
end

conn = (Router)(get, "/index2")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "foo" == conn.resp_body
@test [] == logs
empty!(logs)

before(render, Text) do body, c
    push!(logs, "b $body, $c")
end

after(render, Text) do body, c
    push!(logs, "a $body, $c")
end

before(render, Text/Layout) do body, c
    push!(logs, "bl")
end

after(render, Text/Layout) do body, c
    push!(logs, "al")
end

conn = (Router)(get, "/index_with_layout2")
@test "text/plain" == conn.resp_header["Content-Type"]
@test "layout2 - foo, TextController()" == conn.resp_body
@test ["bl","b foo, TextController()","a foo, TextController()","al"] == logs
empty!(logs)


text:
@doc """
    floyd_warshall_transitive_closure(g)

Use the [Floyd-Warshall algorithm](http://en.wikipedia.org/wiki/Floyd–Warshall_algorithm)
to compute the transistive closure of a redblackgraph `g`. Return a Matrix{AInteger} that
represents the transitive closure of the redblackgraph adjacency matrix.
"""
function floyd_warshall_transitive_closure(m::Matrix{A}) where A <: AInteger
	return floyd_warshall_transitive_closure!(copy(m))
end

function floyd_warshall_transitive_closure!(m::Matrix{A}) where A <: AInteger
	n = size(m)[1]
	for k in 1:n
		for i in 1:n
			for j in 1:n
				m[i, j] = m[i, j] + m[i, k] * m[k, j]
			end
		end
	end
	return m
end


text:
"""
    LikelihoodRatioTest

Results of MixedModels.likelihoodratiotest

## Fields
* `formulas`: Vector of model formulae
* `models`: NamedTuple of the `dof` and `deviance` of the models
* `tests`: NamedTuple of the sequential `dofdiff`, `deviancediff`, and resulting `pvalues`

## Properties
* `deviance`
* `pvalues`

"""
struct LikelihoodRatioTest
    formulas::AbstractVector{String}
    models::NamedTuple{(:dof,:deviance)}
    tests::NamedTuple{(:dofdiff,:deviancediff,:pvalues)}
end

Base.propertynames(lrt::LikelihoodRatioTest, private::Bool = false) = (
    :deviance,
    :formulas,
    :models,
    :pvalues,
    :tests,
)

function Base.getproperty(lrt::LikelihoodRatioTest, s::Symbol)
    if s == :dof
        lrt.models.dof
    elseif s == :deviance
        lrt.models.deviance
    elseif s == :pvalues
        lrt.tests.pvalues
    elseif s == :formulae
        lrt.formulas
    else
        getfield(lrt, s)
    end
end

# backward syntactic but not type compatibility
Base.getindex(lrt::LikelihoodRatioTest, s::Symbol) = getfield(lrt,s)

"""
    likelihoodratiotest(m::MixedModel...)

Likeihood ratio test applied to a set of nested models.

Note that nesting of the models is not checked.  It is incumbent on the user
to check this. This differs from [`StatsModels.lrtest`](@ref) as nesting in
mixed models, especially in the random effects specification, may be non obvious.

This functionality may be deprecated in the future in favor of [`StatsModels.lrtest`](@ref).
"""
function likelihoodratiotest(m::MixedModel...)
    _iscomparable(m...) || throw(
            ArgumentError("""Models are not comparable: are the objectives, data
                             and, where appropriate, the link and family the same?
            """))

    m = collect(m)   # change the tuple to an array
    dofs = dof.(m)
    formulas = String.(Symbol.(getproperty.(m,:formula)))
    ord = sortperm(dofs)
    dofs = dofs[ord]
    formulas = formulas[ord]
    devs = objective.(m)[ord]
    dofdiffs = diff(dofs)
    devdiffs = .-(diff(devs))
    pvals = map(zip(dofdiffs, devdiffs)) do (dof, dev)
        if dev > 0
            ccdf(Chisq(dof), dev)
        else
            NaN
        end
    end

    LikelihoodRatioTest(
        formulas,
        (dof = dofs, deviance = devs),
        (dofdiff = dofdiffs, deviancediff = devdiffs, pvalues = pvals)
    )
end

function Base.show(io::IO, lrt::LikelihoodRatioTest; digits=2)
    println(io, "Model Formulae")

    for (i, f) in enumerate(lrt.formulas)
        println(io, "$i: $f")
    end

    # the following was adapted from StatsModels#162
    # from nalimilan
    Δdf = lrt.tests.dofdiff
    Δdev = lrt.tests.deviancediff

    nc = 6
    nr = length(lrt.formulas)
    outrows = Matrix{String}(undef, nr+1, nc)

    outrows[1, :] = ["",
                    "model-dof",
                    "deviance",
                    "χ²",
                    "χ²-dof",
                    "P(>χ²)"] # colnms

    outrows[2, :] = ["[1]",
                    string(lrt.dof[1]),
                    Ryu.writefixed(lrt.deviance[1], 4),
                    " "," ", " "]

    for i in 2:nr
        outrows[i+1, :] = ["[$i]",
                           string(lrt.dof[i]),
                           Ryu.writefixed(lrt.deviance[i], 4),
                           Ryu.writefixed(Δdev[i-1], 4),
                           string(Δdf[i-1]),
                           string(StatsBase.PValue(lrt.pvalues[i-1]))]
    end
    colwidths = length.(outrows)
    max_colwidths = [maximum(view(colwidths, :, i)) for i in 1:nc]
    totwidth = sum(max_colwidths) + 2*5

    println(io, '─'^totwidth)

    for r in 1:nr+1
        for c in 1:nc
            cur_cell = outrows[r, c]
            cur_cell_len = length(cur_cell)

            padding = " "^(max_colwidths[c]-cur_cell_len)
            if c > 1
                padding = "  "*padding
            end

            print(io, padding)
            print(io, cur_cell)
        end
        print(io, "\n")
        r == 1 && println(io, '─'^totwidth)
    end
    print(io, '─'^totwidth)

    nothing
end

function _iscomparable(m::LinearMixedModel...)
    allequal(getproperty.(getproperty.(m,:optsum),:REML)) ||
        throw(ArgumentError("Models must all be fit with the same objective (i.e. all ML or all REML)"))

    if any(getproperty.(getproperty.(m,:optsum),:REML))
        allequal(coefnames.(m))  ||
                throw(ArgumentError("Likelihood-ratio tests for REML-fitted models are only valid when the fixed-effects specifications are identical"))
    end

    allequal(nobs.(m)) ||
        throw(ArgumentError("Models must have the same number of observations"))

    true
end

function _iscomparable(m::GeneralizedLinearMixedModel...)
        # TODO: test that all models are fit with same fast/nAGQ option?
        glms = getproperty.(m,:resp);

        allequal(Distribution.(glms)) ||
            throw(ArgumentError("Models must be fit to the same distribution"))

        allequal(string.(Link.(glms))) ||
            throw(ArgumentError("Models must have the same link function"))

        allequal(nobs.(m)) ||
            throw(ArgumentError("Models must have the same number of observations"))

        true
end

"""
    isnested(m1::MixedModel, m2::MixedModel; atol::Real=0.0)
Indicate whether model `m1` is nested in model `m2`, i.e. whether
`m1` can be obtained by constraining some parameters in `m2`.
Both models must have been fitted on the same data. This check
is conservative for `MixedModel`s and may reject nested models with different
parameterizations as being non nested.
"""
function StatsModels.isnested(m1::MixedModel, m2::MixedModel; atol::Real=0.0)
    try
        _iscomparable(m1, m2)
    catch e
        @error e.msg
        false
    end || return false

    # check that the nested fixef are a subset of the outer
    all(in.(coefnames(m1),  Ref(coefnames(m2)))) || return false

    # check that the same grouping vars occur in the outer model
    grpng1 = getproperty.(getproperty.(m1.reterms, :trm), :sym)
    grpng2 = getproperty.(getproperty.(m2.reterms, :trm), :sym)

    all(in.(grpng1, Ref(grpng2))) || return false

    # check that every intercept/slope for a grouping var occurs in the
    # same grouping
    re1 = Dict(re.trm.sym => re.cnames for re in m1.reterms)
    re2 = Dict(re.trm.sym => re.cnames for re in m2.reterms)

    all(all(in.(val, Ref(re2[key]))) for (key, val) in re1) || return false

    true
end