text:
using JuliaParser
using FactCheck
using Compat

const Lexer = JuliaParser.Lexer
const TokenStream = JuliaParser.Lexer.TokenStream
const utf8sizeof = Lexer.utf8sizeof

using Lexer: ¬

facts("test skip to end of line") do
    io = IOBuffer("abcd\nabcd\n")
    Lexer.skip_to_eol(io)
    @fact position(io) --> 4
    skip(io, 3)
    @fact position(io) --> 7
    Lexer.skip_to_eol(io)
    @fact position(io) --> 9
    Lexer.readchar(io)
    @fact eof(io) --> true

    context("no line break in buffer") do
        io = IOBuffer("abcde")
        Lexer.skip_to_eol(io)
        @fact position(io) --> 5
        @fact eof(io) --> true
    end

    context("empty buffer") do
        io = IOBuffer()
        Lexer.skip_to_eol(io)
        @fact eof(io) --> true
    end
end

facts("test read operator") do
    for op in Lexer.OPERATORS
        str = "$(string(op))"
        io = TokenStream(str)
        c = Lexer.readchar(io)
        res = Lexer.read_operator(io, c, nothing)
        @fact res --> op
        @fact Lexer.eof(io) --> true
    end
end

facts("test string_to_number") do

    @fact_throws Lexer.string_to_number("",nothing)
    @fact_throws Lexer.string_to_number("1x10",nothing)
    @fact_throws Lexer.string_to_number("x10",nothing)
    @fact_throws Lexer.string_to_number("1.f.10",nothing)
    @fact_throws Lexer.string_to_number("b10",nothing)
    @fact_throws Lexer.string_to_number("0xzz",nothing)
    @fact_throws Lexer.string_to_number("0b22",nothing)

    context("NaN") do
        for s in ("NaN", "+NaN", "-NaN")
            n = Lexer.string_to_number(s,nothing)
            @fact isnan(n) --> true
            @fact isnan(n) --> isnan(eval(parse(s)))
        end
    end

    context("Inf") do
        for s in ("Inf", "+Inf", "-Inf")
            n = Lexer.string_to_number(s,nothing)
            @fact isinf(n) --> true
            @fact isinf(n) --> isinf(eval(parse(s)))
        end
    end

    context("float64") do
        s = "1.0"
        n = Lexer.string_to_number(s,nothing)
        @fact n --> 1.0
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "-1.0"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -1.0
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "1."
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1.0
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "1e10"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1.0e10
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "-1E10"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -1.0e10
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "0x1p0"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1.0
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "0x1.8p3"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 12.0
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        s = "0x0.4p-1"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 0.125
        @fact n --> parse(s)
        @fact typeof(n) --> Float64
        @fact typeof(n) --> typeof(parse(s))

        for _ = 1:10
            tn = rand()
            s  = string(tn)
            n  = Lexer.string_to_number(s, nothing)
            @fact n --> tn
            @fact typeof(n) --> Float64
            @fact n --> parse(s)
            @fact typeof(n) --> typeof(parse(s))
        end
    end

    context("float32") do
        s = "1.0f0"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1.0
        @fact typeof(n) --> Float32
        @fact n --> parse(s)
        @fact typeof(n) --> typeof(parse(s))

        s = "-1.f0"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -1.0
        @fact typeof(n) --> Float32
        @fact n --> parse(s)
        @fact typeof(n) --> typeof(parse(s))

        s = "1f0"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1.0
        @fact typeof(n) --> Float32
        @fact n --> parse(s)
        @fact typeof(n) --> typeof(parse(s))

        s = "1f"
        @fact_throws Lexer.string_to_number(n, nothing)

        for _ = 1:10
            tn = rand(Float32)
            s  = repr(tn)
            n  = Lexer.string_to_number(s, nothing)
            @fact n --> tn
            @fact typeof(n) --> Float32
            @fact n --> parse(s)
            @fact typeof(n) --> typeof(parse(s))
        end
    end

    context("integers") do
        s = "1"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 1
        @fact typeof(n) --> Int64

        s = "-1"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -1
        @fact typeof(n) --> Int64

        s = repr(typemin(Int64))
        n = Lexer.string_to_number(s, nothing)
        @fact n --> typemin(Int64)
        @fact typeof(n) --> Int64

        s = repr(typemax(Int64))
        n = Lexer.string_to_number(s, nothing)
        @fact n --> typemax(Int64)
        @fact typeof(n) --> Int64

        #=
        s = repr(typemax(UInt64))
        n = Lexer.string_to_number(s)
        @fact n --> typemax(UInt64)
        @fact typeof(n) --> UInt64
        =#

        s = "0b010101"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 21
        @fact typeof(n) --> Int64

        s = "-0b010101"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -21
        @fact typeof(n) --> Int64

        s = "0x15"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> 21
        @fact typeof(n) --> Int64

        s = "-0x15"
        n = Lexer.string_to_number(s, nothing)
        @fact n --> -21
        @fact typeof(n) --> Int64
    end
end

facts("test is char hex") do
    for i = 1:9
        @fact Lexer.is_char_hex(first("$i")) --> true
    end
    for c in ['a', 'b', 'c', 'd', 'e', 'f']
        @fact Lexer.is_char_hex(c) --> true
    end
    @fact Lexer.is_char_hex('z') --> false
    for c in ['A', 'B', 'C', 'D', 'E', 'F']
        @fact Lexer.is_char_hex(c) --> true
    end
    @fact Lexer.is_char_hex('Z') --> false
end

facts("test is char oct") do
    for i = 1:9
        if i < 8
            @fact Lexer.is_char_oct(first("$i")) --> true
        else
	        @fact Lexer.is_char_oct(first("$i")) --> false
        end
    end
end

facts("test is char bin") do
    @fact Lexer.is_char_bin('0') --> true
    @fact Lexer.is_char_bin('1') --> true
    @fact Lexer.is_char_bin('2') --> false
end

facts("test uint neg") do
    @fact eval(Lexer.fix_uint_neg(true,  1)) --> -1
    @fact eval(Lexer.fix_uint_neg(false, 1)) --> 1
end

facts("test sized uint literal") do

    context("hexadecimal") do
        s  = "0x0"
        sn = @compat parse(Int,s)
        n  = Lexer.sized_uint_literal(s, 4)
        @fact sn --> n
        @fact typeof(n) --> UInt8

        for ty in (UInt8, UInt16, UInt32, UInt64, UInt128)
            @eval begin
                s = repr(typemax($ty))
                sn = @compat parse(UInt128,s)
                n  = Lexer.sized_uint_literal(s, 4)
                @fact sn --> n
                @fact typeof(n) --> $ty
                # parse / eval output (128 bit integers and BigInts
                # are returned as expressions
                pn = eval(parse(s))
                @fact pn --> n
                @fact typeof(pn) --> $ty
            end
        end

        if VERSION < v"0.4-"
            s  = string(repr(typemax(UInt128)), "f")
            sn = BigInt(s)
            n  = Lexer.sized_uint_literal(s, 4)
            @fact sn == n --> true
            @fact typeof(n) --> BigInt

            pn = eval(parse(s))
            @fact pn == n --> true
            @fact typeof(pn) --> BigInt
        end
    end

    context("octal") do
        s  = "0o0"
        sn = @compat parse(Int,s)
        n  = Lexer.sized_uint_oct_literal(s)
        @fact sn --> n
        @fact typeof(n) --> UInt8

        pn = parse(s)
        @fact pn == n --> true
        @fact typeof(n) --> typeof(pn)

        for ty in (UInt8, UInt16, UInt32, UInt64, UInt128)
            @eval begin
                s = string("0o", oct(typemax($ty)))
                sn = @compat parse(UInt128,s)
                n  = Lexer.sized_uint_oct_literal(s)
                @fact sn --> n
                @fact typeof(n) --> $ty

                pn = eval(parse(s))
                @fact pn --> n
                @fact typeof(pn) --> $ty
            end
        end

        if VERSION < v"0.4-"
            s = "0o" * oct(typemax(UInt128)) * "7"
            sn = BigInt(s)
            n  = Lexer.sized_uint_oct_literal(s)
            @fact sn --> n
            @fact typeof(n) --> BigInt
            pn = eval(parse(s))
            @fact n --> pn
            @fact typeof(n) --> typeof(pn)
        end
    end

    context("binary") do
        s  = "0b0"
        sn = @compat parse(Int,s)
        n  = Lexer.sized_uint_literal(s, 1)
        @fact sn --> n
        @fact typeof(n) --> UInt8

        for ty in (UInt8, UInt16, UInt32, UInt64, UInt128)
            @eval begin
                s = string("0b", bin(typemax($ty)))
                sn = @compat parse(UInt128,s)
                n  = Lexer.sized_uint_literal(s, 1)
                @fact sn --> n
                @fact typeof(n) --> $ty
            end
        end

        s  = string("0b", bin(typemax(UInt128)), "1")
        sn = @compat parse(BigInt,s)
        n  = Lexer.sized_uint_literal(s, 1)
        @fact sn --> n
        @fact typeof(n) --> BigInt
    end
end

facts("test accum_digits") do
    pred = isdigit

    io = TokenStream("1_000_000")
    c = Lexer.readchar(io)
    digits, success = Lexer.accum_digits(io, pred, c, false)
    @fact digits --> [c for c in "1000000"]
    @fact success --> true

    io = TokenStream("01_000_000")
    c = Lexer.peekchar(io)
    digits, success = Lexer.accum_digits(io, pred, c, false)
    @fact digits --> [c for c in "01000000"]
    @fact success --> true

    io = TokenStream("_000_000")
    c = Lexer.peekchar(io)
    _, success = Lexer.accum_digits(io, pred, c, false)
    @fact success --> false

    io = TokenStream("_000_000")
    c = Lexer.peekchar(io)
    _, success = Lexer.accum_digits(io, pred, c, true)
    @fact success --> true
end

facts("test compare num strings") do
    a = "123"
    b = "1453"
    isless = Lexer.compare_num_strings(a, b)
    @fact isless --> true

    a = "123"
    b = "321"
    isless  = Lexer.compare_num_strings(a, b)
    @fact isless --> true
    isless  = Lexer.compare_num_strings(b, a)
    @fact isless --> false
end

facts("test is oct within uint 128") do
    m = typemax(UInt128)
    @fact Lexer.is_oct_within_uint128(string("0o", oct(m))) --> true

    m = typemax(UInt128) - 1
    @fact Lexer.is_oct_within_uint128(string("0o", oct(m))) --> true

    m = BigInt(typemax(UInt128)) + 1
    @fact Lexer.is_oct_within_uint128(string("0o", oct(m))) --> false
end

facts("test is within int128") do
    m = typemax(Int128)
    @fact Lexer.is_within_int128(repr(m)) --> true

    m = BigInt(typemax(Int128)) + 1
    @fact Lexer.is_within_int128(repr(m)) --> false

    m = typemin(Int128)
    @fact Lexer.is_within_int128(repr(m)) --> true

    m = BigInt(typemin(Int128)) - 1
    @fact Lexer.is_within_int128(repr(m)) --> false
end

facts("test readnumber") do

    context("signed integer") do
        io = TokenStream("100")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 100
        @fact typeof(n) --> Int64

        io = TokenStream("100_000_000")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 100_000_000
        @fact typeof(n) --> Int64

        io = TokenStream("-100")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, false, true)
        @fact n --> -100
        @fact typeof(n) --> Int64

        io = TokenStream("00100")
        n = ¬Lexer.read_number(io, false,  false)
        @fact n --> 100
        @fact typeof(n) --> Int64
    end

    context("decimal") do
        io = TokenStream("100.0")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 100.0
        @fact typeof(n) --> Float64

        io = TokenStream("100.0f0")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 100.0
        @fact typeof(n) --> Float32

        io = TokenStream("10.0.0")
        @fact_throws Lexer.read_number(io, false, false)
    end

    context("floating point exponent") do
        io = TokenStream("1e10")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 1e10
        @fact typeof(n) --> Float64

        io = TokenStream("-10E10")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, false, true)
        @fact n --> -10e10
        @fact typeof(n) --> Float64

        io = TokenStream("1e-1")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 1e-1
        @fact typeof(n) --> Float64
    end

    context("leading dot") do
        io = TokenStream(".01")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, true, false)
        @fact n --> 0.01
        @fact typeof(n) --> Float64

        io = TokenStream(".000_1")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, true, false)
        @fact n --> 0.0001
        @fact typeof(n) --> Float64

        io = TokenStream("-.01")
        Lexer.skip(io, 2)
        n = ¬Lexer.read_number(io, true, true)
        @fact n --> -0.01
        @fact typeof(n) --> Float64

        io = TokenStream("-.000_1")
        Lexer.skip(io, 2)
        n = ¬Lexer.read_number(io, true, true)
        @fact n --> -0.0001
        @fact typeof(n) --> Float64

        io = TokenStream(".01f0")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, true, false)
        @fact n --> 0.01f0
        @fact typeof(n) --> Float32

        io = TokenStream(".000_1f0")
        Lexer.skip(io, 1)
        n = ¬Lexer.read_number(io, true, false)
        @fact n --> 0.0001f0
        @fact typeof(n) --> Float32

        io = TokenStream("-.01f0")
        Lexer.skip(io, 2)
        n = ¬Lexer.read_number(io, true, true)
        @fact n --> -0.01f0
        @fact typeof(n) --> Float32

        io = TokenStream("-.000_1f0")
        Lexer.skip(io, 2)
        n = ¬Lexer.read_number(io, true, true)
        @fact n --> -0.0001f0
        @fact typeof(n) --> Float32
    end

    context("floating point hex") do
        io = TokenStream("0x1.8p3")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 12.0
        @fact typeof(n) --> Float64

        io = TokenStream("0x0.4p-1")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 0.125
        @fact typeof(n) --> Float64
    end

    context("binary") do
        io = TokenStream(string("0b", bin(10)))
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 10
    end

    context("hex") do
        io = TokenStream(string("0x", hex(10), " "))
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 10

        io = TokenStream("0xffff7f000001")
        n = ¬Lexer.read_number(io, false, false)
        @fact n --> 0xffff7f000001
    end

    context("bigint") do
        io = TokenStream("15732444386908125794514089057706229429197107928209")
        n  = ¬Lexer.read_number(io, false, false)
        @fact n --> @compat parse(BigInt, "15732444386908125794514089057706229429197107928209")
        @fact typeof(n) --> BigInt
    end
end

facts("test skipwhitespace") do
    io = TokenStream("   abc")
    Lexer.skipws(io)
    @fact Lexer.position(io) --> 3

    io = TokenStream("abc")
    Lexer.skipws(io)
    @fact Lexer.position(io) --> 0

    io = TokenStream("  \n abc")
    Lexer.skipws(io)
    @fact Lexer.position(io) --> 2
    @fact Lexer.readchar(io) --> '\n'

    io = TokenStream("")
    Lexer.skipws(io)
    @fact Lexer.position(io) --> 0
end

facts("test skip comment") do
    io = TokenStream("#test\n")
    Lexer.skipcomment(io)
    @fact Lexer.position(io) --> 5

    io = TokenStream("# \ntest")
    Lexer.skipcomment(io)
    @fact Lexer.position(io) --> 2

    io = TokenStream("#")
    Lexer.skipcomment(io)
    @fact Lexer.position(io) --> 1

    io = TokenStream("# ")
    Lexer.skipcomment(io)
    @fact Lexer.position(io) --> 2

    context("must start with a comment symbol") do
        io = TokenStream("test")
        @fact_throws Lexer.skipcomment(io)
    end
end

facts("test skip multiline comment") do
    io = TokenStream("#=test=#a")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 8

    io = TokenStream("#======#a")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 8

    io = TokenStream("#==#a")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 4

    io = TokenStream("#=test\ntest\n=#a")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 14

    io = TokenStream("#= # =#")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 7

    io = TokenStream("#=\n#= =# =#")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 11

    io = TokenStream("#=#==#=#")
    Lexer.skip_multiline_comment(io, 0)
    @fact Lexer.position(io) --> 8

    io = TokenStream("#=#=#")
    @fact_throws Lexer.skip_multiline_comment(io, 0)

    io = TokenStream("#= test")
    @fact_throws Lexer.skip_multiline_comment(io, 0)

    io = TokenStream("#=#")
    @fact_throws Lexer.skip_multiline_comment(io, 0)
end

facts("test skip ws and comment") do
    io = TokenStream("")
    Lexer.skipws_and_comments(io)
    @fact Lexer.eof(io) --> true

    io = TokenStream(" \n")
    Lexer.skipws_and_comments(io)
    @fact Lexer.eof(io) --> true

    io = TokenStream("  # test comment\n")
    Lexer.skipws_and_comments(io)
    @fact Lexer.eof(io) --> true

    io = TokenStream("    #= test comment \n
                  another comment =#a")
    Lexer.skipws_and_comments(io)
    @fact Lexer.readchar(io) --> 'a'

    io = TokenStream(" # a comment\ntest")
    Lexer.skipws_and_comments(io)
    @fact Lexer.readchar(io) --> 't'
end

tokens(ts::TokenStream) = begin
    toks = Any[]
    while !eof(ts.io)
        push!(toks, Lexer.next_token(ts))
    end
    return toks
end
tokens(str::AbstractString) = tokens(TokenStream(str))
raw_tokens(s) = map(¬,tokens(s))

facts("test TokenStream constructor") do
    io = TokenStream("testfunc(i) = i * i")
    try
        ts = TokenStream(io)
        @fact true --> true
    catch
        @fact false --> false
    end
end

facts("test set_token! / last_token") do
    code = "1 + 1"

    tks = tokens(code)
    @fact map(¬,tks) --> Any[1, :+, 1]

    ts = TokenStream(code)
    @fact ¬Lexer.last_token(ts) --> nothing

    Lexer.set_token!(ts, tks[1])
    @fact Lexer.last_token(ts) --> tks[1]

    Lexer.set_token!(ts, tks[2])
    @fact Lexer.last_token(ts) --> tks[2]
end

facts("test put_back!") do
    code = "1 + 1"
    tks  = tokens(code)
    ts   = TokenStream(code)
    Lexer.put_back!(ts, tks[1])
    @fact ts.putback --> tks[1]
    @fact_throws ts.put_back(tks[2])
end

facts("test peek_token") do
    code = "1 + 1"
    tks  = tokens(code)
    ts   = TokenStream(code)
    @fact Lexer.peek_token(ts) --> tks[1]
    Lexer.put_back!(ts, Lexer.Token(:test))
    @fact ¬Lexer.peek_token(ts) --> :test
    @fact_throws Lexer.put_back!(ts, Lexer.Token(:test2))
    Lexer.set_token!(ts, Lexer.Token(:test2))
    @fact ¬Lexer.peek_token(ts) --> :test
end

# you must peek before you can take
facts("test take_token") do
    code = "1 + 1"
    ts   = TokenStream(code)
    @fact Lexer.take_token(ts) --> nothing
    for t in tokens(code)
        tk = Lexer.peek_token(ts)
        @fact tk --> t
        Lexer.take_token(ts)
    end
end

facts("test require_token") do
    code = "1 +\n1"
    ts   = TokenStream(code)
    for t in (1, :+, 1)
        tk = Lexer.require_token(ts)
        @fact ¬tk --> t
        Lexer.take_token(ts)
    end
end

facts("test next_token") do
    # throw EOF error
    ts  = Lexer.TokenStream("")
    @fact Lexer.next_token(ts) --> Lexer.eof_token(Lexer.Token)

    ts  = Lexer.TokenStream("\n")
    tok = Lexer.next_token(ts)
    @fact ¬tok --> '\n'

    toks = raw_tokens("true false")
    @fact toks --> Any[true, false]

    toks = raw_tokens("(test,)")
    @fact toks --> Any['(', :test, ',', ')']

    toks = raw_tokens("[10.0,2.0]")
    @fact toks --> Any['[', 10.0, ',', 2.0, ']']

    toks = raw_tokens("#test\n{10,};")
    @fact toks --> Any['\n', '{', 10, ',', '}', ';']

    toks = raw_tokens("#=test1\ntest2\n=#@test\n")
    @fact toks --> Any['@', :test, '\n']

    toks = raw_tokens("1<=2")
    @fact toks --> Any[1, :(<=), 2]

    toks = raw_tokens("1.0 .+ 2")
    @fact toks --> Any[1.0, :(.+), 2]

    toks = raw_tokens("abc .+ .1")
    @fact toks --> Any[:abc, :(.+), 0.1]

    toks = raw_tokens("`ls`")
    @fact toks --> Any['`', :ls, '`']

    toks = raw_tokens("@testmacro")
    @fact toks --> Any['@', :testmacro]

    toks = raw_tokens("x::Int32 + 1")
    @fact toks --> Any[:x, :(::), :Int32, :(+), 1]

    toks = raw_tokens("func(2) |> send!")
    @fact toks --> Any[:func, '(', 2, ')', :(|>), :(send!)]

    sym_end = Symbol("end")

    toks = raw_tokens("type Test{T<:Int32}\n\ta::T\n\tb::T\nend")
    @fact toks --> Any[:type, :Test, '{',  :T, :(<:), :Int32, '}', '\n',
                   :a, :(::), :T, '\n',
                   :b, :(::), :T, '\n',
                   sym_end]

    toks = raw_tokens("function(x::Int)\n\treturn x^2\nend")
    @fact toks --> Any[:function, '(', :x, :(::), :Int, ')', '\n',
                   :return , :x, :(^), 2, '\n',
                   sym_end]

    toks = raw_tokens("+(x::Bool, y::Bool) = int(x) + int(y)")
    @fact toks --> Any[:+, '(', :x, :(::), :Bool, ',', :y, :(::), :Bool, ')',
                   :(=), :int, '(', :x, ')', :+, :int, '(', :y, ')']
end

facts("test utf8sizeof") do
    @fact utf8sizeof('a') --> 1
    @fact utf8sizeof('\uff') --> 2
    @fact utf8sizeof('\uffff') --> 3
    @fact utf8sizeof('\U1f596') --> 4
    @fact utf8sizeof(@compat Char(0x110000)) --> 3
end

facts("test windows style newline") do
    toks = raw_tokens("1+#= =#\t\r\n2")
    @fact toks --> Any[1, :+, '\n', 2]
end


text:
using BenchmarkTools
using SymSpellChecker
using SymSpellChecker: VerbosityALL, VerbosityTOP, VerbosityCLOSEST
using Statistics
using CSV
using DataFrames

ASSETS_PATH = joinpath(@__DIR__, "..", "..", "assets")
function load_noisy()
    map(readlines(joinpath(ASSETS_PATH, "noisy_query_en_1000.txt"))) do x
        String(split(x)[1])
    end
end

dicts = [
    joinpath(ASSETS_PATH, "frequency_dictionary_en_30_000.txt"),
    joinpath(ASSETS_PATH, "frequency_dictionary_en_82_765.txt"),
    joinpath(ASSETS_PATH, "frequency_dictionary_en_500_000.txt"),
]

dict_names = ["30k", "82k", "500k"]

query1k = load_noisy()

function mix(d, data, verbosity)
    sum(length(lookup(d, word, verbosity = verbosity)) for word in data)
end

df = DataFrame(max_edit = Int[], prefix_length = Int[], dict_name = String[], verbosity = String[], type = String[],
    res = Int[], min_val = Float64[], med_val = Float64[], avg_val = Float64[])

for max_edit in 1:3
    for prefix_length in 5:7
        for (dict_path, dict_name) in zip(dicts, dict_names)
            d = SymSpell(dict_path, max_dictionary_edit_distance = max_edit, prefix_length = prefix_length)
            for verbosity in [VerbosityTOP, VerbosityCLOSEST, VerbosityALL]
                verb_name = verbosity == VerbosityTOP ? "top" : verbosity == VerbosityCLOSEST ? "closest" : "all"
                b = @benchmark lookup($d, $"different", verbosity = $verbosity)
                println("max_edit: $max_edit\tprefix_length: $prefix_length\tdict: $dict_name\tverbosity: $verbosity\ttype: exact\tmin: $(minimum(b.times/1000_000))\tmed: $(median(b.times/1000_000))\tavg: $(mean(b.times/1000_000))")
                res = length(lookup(d, "different", verbosity = verbosity))

                push!(df, (max_edit, prefix_length, dict_name, verb_name, "exact", res,
                    minimum(b.times/1000_000), median(b.times/1000_000), mean(b.times/1000_000)))

                b = @benchmark lookup($d, $"hockie", verbosity = $verbosity)
                println("max_edit: $max_edit\tprefix_length: $prefix_length\tdict: $dict_name\tverbosity: $verbosity\ttype: non-exact\tmin: $(minimum(b.times/1000_000))\tmed: $(median(b.times/1000_000))\tavg: $(mean(b.times/1000_000))")
                res = length(lookup(d, "hockie", verbosity = verbosity))

                push!(df, (max_edit, prefix_length, dict_name, verb_name, "non-exact", res,
                    minimum(b.times/1000_000), median(b.times/1000_000), mean(b.times/1000_000)))

                b = @benchmark mix($d, $query1k, $verbosity)
                println("max_edit: $max_edit\tprefix_length: $prefix_length\tdict: $dict_name\tverbosity: $verbosity\ttype: mix\tmin: $(minimum(b.times/1000_000_000))\tmed: $(median(b.times/1000_000_000))\tavg: $(mean(b.times/1000_000_000))")
                res = mix(d, query1k, verbosity)

                push!(df, (max_edit, prefix_length, dict_name, verb_name, "mix", res,
                    minimum(b.times/1000_000_000), median(b.times/1000_000_000), mean(b.times/1000_000_000)))
            end
        end
    end
end

CSV.write(joinpath(@__DIR__, "bench.csv"), df)

ext: jl


text:
id(x::T) where T>:Any = x

id(x::T) where T>:Int = -x

println(id(5))
println(id(3.14))

max_stars_repo_name: prl-julia/julia-sub

max_issues_repo_name: prl-julia/julia-sub

max_forks_repo_name: prl-julia/julia-sub


text:
using LinearAlgebra
using StatsFuns
using Distributions

function getKalman(A::Array{Float64,2}, C::Array{Float64,2}, totalI::Int, initVar::Array{Float64,2})
    if size(initVar,1)!=size(initVar,2)
        initVar = diagm(initVar)
    end
    Vars = Array{Array{Float64,2}, 1}(undef, totalI)
    Ks = Array{Array{Float64,2}, 1}(undef, totalI)
    Vars[1] = initVar
    #Get filter
    for i = 2:totalI
        Ks[i] = (A*Vars[i-1]*A'*C')/(C*A*Vars[i-1]*A'*C' .+ C*initVar*C')
        Vars[i] = (I - Ks[i]*C)*A*Vars[i-1]*A'
    end
    return Ks, Vars
end

struct KalmanModel{A2<:Array{Float64,2}, F<:Float64, I<:Int64, A1<:Array{Float64,1}, AA<:Array{Array{Float64,2},1}, FN<:Function}
    A::A2
    C::A2
    muPrior::A1
    initVar::A2
    a::F
    totalI::I
    Ks::AA
    Vars::AA
    getMusLL::FN
end

function runSim(Zs::Array{Array{Float64,1},1}, Ys::Array{Array{Float64,1},1}, KM::KalmanModel)
    LLike = (Mu::Array{Float64,1}, Cov::Array{Float64,2}, Y::Array{Float64,1})->log(((2*pi)^(-length(KM.muPrior)/2))*(det(Cov)^(-1/2))*exp(-((Y-Mu)'*inv(Cov)*(Y-Mu))/2))
    Mus = Array{Float64,2}(undef, length(Zs[1])+1, KM.totalI)
    Mus[:,1] = vcat(KM.muPrior, 0)
    for i = 2:KM.totalI
        sum!(Mus[1:end-1,i], KM.A*Mus[1:end-1,i-1] + KM.Ks[i]*(Ys[i] - KM.C*KM.A*Mus[1:end-1,i-1]))
        Mus[end,i] = LLike(KM.C*Mus[1:end-1,i], KM.C*KM.Vars[i]*KM.C', Ys[i])
    end
    Mus[1:end-1,:] -= hcat(Zs...)
    Mus[1:end-1,:] = Mus[1:end-1,:].^2
    accumulate!(logaddexp, Mus[end,:], Mus[end,:])
    return Mus
end
#
# @generated function runSim(Mus::Array{Float64,2}, totalI::Int, A::Array{Float64,2}, C::Array{Float64,2},
#                 Ks::Array{Array{Float64,2},1}, Vars::Array{Array{Float64,2},1}, LLike::Function,
#                 Zs::Array{Array{Float64,1},1}, Ys::Array{Array{Float64,1},1})
#     for i = 2:totalI
#         sum!(Mus[1:end-1,i], A*Mus[1:end-1,i-1] + Ks[i]*(Ys[i] - C*A*Mus[1:end-1,i-1]))
#         # Mus[end,i] = LLikeSum(Mus[end,i-1], C*Mus[1:end-1,i], C*Vars[i]*C', Ys[i])
#         Mus[end,i] = LLike(C*Mus[1:end-1,i], C*Vars[i]*C', Ys[i])
#     end
#     # accumulate!(logaddexp, Mus[end,:], LLike.([Mus[1:end-1,i] for i in 1:size(Mus,2)], Vars, Ys))
#     Mus[1:end-1,:] -= hcat(Zs...)
#     Mus[1:end-1,:] = Mus[1:end-1,:].^2
#     accumulate!(logaddexp, Mus[end,:], Mus[end,:])
#     # cumsum!(Mus[end,:], Mus[end,:])
#     return Mus
# end
#
# function getRunSim(A, C, muPrior, initVar, a, totalI, Ks, Vars)
#     Mus = Array{Float64,2}(undef, length(muPrior)+1, totalI)
#     Mus[:,1] = vcat(muPrior, 0)
#     nCon = ((2*pi)^(-length(muPrior)/2))
#     # LLikeSum = (last, Mu, Cov, Y)->logaddexp(last, log(nCon*(det(Cov)^(-1/2))*exp(-((Y-Mu)'*inv(Cov)*(Y-Mu))/2)))
#     LLike = (Mu::Array{Float64,1}, Cov::Array{Float64,2}, Y::Array{Float64,1})->log(nCon*(det(Cov)^(-1/2))*exp(-((Y-Mu)'*inv(Cov)*(Y-Mu))/2))
#
#     # LLike = (Mu::Array{Float64,1}, Cov::Array{Float64,2}, Y::Array{Float64,1})->log(nCon*(det(C*Cov*C')^(-1/2))*exp(-((Y-C*Mu)'*inv(C*Cov*C')*(Y-C*Mu))/2))
#
#     return (Zs::Array{Array{Float64,1},1}, Ys::Array{Array{Float64,1},1}) -> :(runSim($Mus, $totalI, $A, $C, $Ks, $Vars, $LLike, Zs, Ys))
# end
#
# function runSim(muPrior::Array{Float64,1}, totalI::Int, A::Array{Float64,2}, C::Array{Float64,2},
#                 Ks::Array{Array{Float64,2},1}, Vars::Array{Array{Float64,2},1},
#                 Zs::Array{Array{Float64,1},1}, Ys::Array{Array{Float64,1},1})
#     Mus = Array{Float64,2}(undef, length(muPrior)+1, totalI)
#     Mus[:,1] = vcat(muPrior, 0)
#     nCon = ((2*pi)^(-length(muPrior)/2))
#     # LLikeSum = (last, Mu, Cov, Y)->logaddexp(last, log(nCon*(det(Cov)^(-1/2))*exp(-((Y-Mu)'*inv(Cov)*(Y-Mu))/2)))
#     LLike = (Mu::Array{Float64,1}, Cov::Array{Float64,2}, Y::Array{Float64,1})->log(nCon*(det(Cov)^(-1/2))*exp(-((Y-Mu)'*inv(Cov)*(Y-Mu))/2))
#
#     # LLike = (Mu::Array{Float64,1}, Cov::Array{Float64,2}, Y::Array{Float64,1})->log(nCon*(det(C*Cov*C')^(-1/2))*exp(-((Y-C*Mu)'*inv(C*Cov*C')*(Y-C*Mu))/2))
#
#     for i = 2:totalI
#         sum!(Mus[1:end-1,i], A*Mus[1:end-1,i-1] + Ks[i]*(Ys[i] - C*A*Mus[1:end-1,i-1]))
#         # Mus[end,i] = LLikeSum(Mus[end,i-1], C*Mus[1:end-1,i], C*Vars[i]*C', Ys[i])
#         Mus[end,i] = LLike(C*Mus[1:end-1,i], C*Vars[i]*C', Ys[i])
#     end
#     # accumulate!(logaddexp, Mus[end,:], LLike.([Mus[1:end-1,i] for i in 1:size(Mus,2)], Vars, Ys))
#     Mus[1:end-1,:] -= hcat(Zs...)
#     Mus[1:end-1,:] = Mus[1:end-1,:].^2
#     accumulate!(logaddexp, Mus[end,:], Mus[end,:])
#     # cumsum!(Mus[end,:], Mus[end,:])
#     return Mus
# end

KalmanModel(A::Array{Float64,2}, C::Array{Float64,2}, muPrior::Array{Float64,1}, initVar::Array{Float64,1}, a::Float64, totalI::Int) =
    KalmanModel(A, C, muPrior, diagm(initVar), a, totalI, getKalman(A, C, totalI, diagm(initVar))...)
KalmanModel(A::Array{Float64,2}, C::Array{Float64,2}, muPrior::Array{Float64,1}, initVar::Array{Float64,2}, a::Float64, totalI::Int, Ks::Array{Array{Float64,2},1}, Vars::Array{Array{Float64,2},1}) =
    KalmanModel(A, C, muPrior, initVar, a, totalI, Ks, Vars,
        (Zs::Array{Array{Float64,1},1}, Ys::Array{Array{Float64,1},1})->runSim(muPrior, totalI, A, C, Ks, Vars, Zs, Ys))

max_stars_repo_name: rhoadesScholar/Drugowitsch-Rotation

max_issues_repo_name: rhoadesScholar/Drugowitsch-Rotation

max_forks_repo_name: rhoadesScholar/Drugowitsch-Rotation


text:
# # Ocean convection example
#
# In this example, two-dimensional convection into a stratified fluid
# mixes a phytoplankton-like tracer. This example demonstrates how
#
#   * to set boundary conditions;
#   * to defined and insert a user-defined forcing function into a simulation.
#   * to use the `TimeStepWizard` to manage and adapt the simulation time-step.
#
# To begin, we load Oceananigans, a plotting package, and a few miscellaneous useful packages.

using Oceananigans, Plots, Random, Printf

# ## Parameters
#
# We choose a modest two-dimensional resolution of 128² in a 64² m² domain ,
# implying a resolution of 0.5 m. Our fluid is initially stratified with
# a squared buoyancy frequency
#
# $ N² = 10⁻⁵ \rm{s⁻²} $
#
# and a surface buoyancy flux
#
# $ Q_b = 10⁻⁸ \rm{m³ s⁻²} $
#
# Because we use the physics-based convection whereby buoyancy flux by a
# positive vertical velocity implies positive flux, a positive buoyancy flux
# at the top of the domain carries buoyancy out of the fluid and causes convection.
# Finally, we end the simulation after 1 day.

Nz = 128
Lz = 64.0
N² = 1e-5
Qb = 1e-8
end_time = day / 2
nothing # hide

# ## Creating boundary conditions
#
# Create boundary conditions. Note that temperature is buoyancy in our problem.
#

buoyancy_bcs = HorizontallyPeriodicBCs(   top = BoundaryCondition(Flux, Qb),
                                       bottom = BoundaryCondition(Gradient, N²))
nothing # hide

# ## Define a forcing function
#
# Our forcing function roughly corresponds to the growth of phytoplankton in light
# (with a penetration depth of 16 meters here), and death due to natural mortality
# at a rate of 1 phytoplankton unit per second.

growth_and_decay = SimpleForcing((x, y, z, t) -> exp(z/16))

## Instantiate the model
model = Model(
                   grid = RegularCartesianGrid(size = (Nz, 1, Nz), length = (Lz, Lz, Lz)),
                closure = ConstantIsotropicDiffusivity(ν=1e-4, κ=1e-4),
               coriolis = FPlane(f=1e-4),
                tracers = (:b, :plankton),
               buoyancy = BuoyancyTracer(),
                forcing = ModelForcing(plankton=growth_and_decay),
    boundary_conditions = BoundaryConditions(b=buoyancy_bcs)
)
nothing # hide

## Set initial condition. Initial velocity and salinity fluctuations needed for AMD.
Ξ(z) = randn() * z / Lz * (1 + z / Lz) # noise
b₀(x, y, z) = N² * z + N² * Lz * 1e-6 * Ξ(z)
set!(model, b=b₀)

## A wizard for managing the simulation time-step.
wizard = TimeStepWizard(cfl=0.1, Δt=1.0, max_change=1.1, max_Δt=90.0)
nothing # hide

# Run the model:

anim = @animate for i = 1:100
    update_Δt!(wizard, model)
    walltime = @elapsed time_step!(model, 100, wizard.Δt)

    ## Print a progress message
    @printf("progress: %.1f %%, i: %04d, t: %s, Δt: %s, wall time: %s\n",
            model.clock.time / end_time * 100, model.clock.iteration,
            prettytime(model.clock.time), prettytime(wizard.Δt), prettytime(walltime))

    ## Coordinate arrays for plotting
    xC, zF, zC = model.grid.zC, model.grid.zF[1:Nz], model.grid.zC

    ## Fields to plot (converted to 2D arrays).
    w = Array(interior(model.velocities.w))[:, 1, :]
    p = Array(interior(model.tracers.plankton))[:, 1, :]

    ## Plot the fields.
    w_plot = heatmap(xC, zF, w', xlabel="x (m)", ylabel="z (m)", color=:balance, clims=(-1e-2, 1e-2))
    p_plot = heatmap(xC, zC, p', xlabel="x (m)", ylabel="z (m)", color=:matter) #, legend=false)

    ## Arrange the plots side-by-side.
    plot(w_plot, p_plot, layout=(1, 2), size=(1000, 400),
         title=["vertical velocity (m/s)" "Plankton concentration"])
end

mp4(anim, "ocean_convection_with_plankton.mp4", fps = 15) # hide


text:
"""
    sort!(df::AbstractDataFrame, cols;
          alg::Union{Algorithm, Nothing}=nothing, lt=isless, by=identity,
          rev::Bool=false, order::Ordering=Forward)

Sort data frame `df` by column(s) `cols`.

`cols` can be any column selector ($COLUMNINDEX_STR; $MULTICOLUMNINDEX_STR).

If `alg` is `nothing` (the default), the most appropriate algorithm is
chosen automatically among `TimSort`, `MergeSort` and `RadixSort` depending
on the type of the sorting columns and on the number of rows in `df`.
If `rev` is `true`, reverse sorting is performed. To enable reverse sorting
only for some columns, pass `order(c, rev=true)` in `cols`, with `c` the
corresponding column index (see example below).
See other methods for a description of other keyword arguments.

# Examples
```jldoctest
julia> df = DataFrame(x = [3, 1, 2, 1], y = ["b", "c", "a", "b"])
4×2 DataFrame
 Row │ x      y
     │ Int64  String
─────┼───────────────
   1 │     3  b
   2 │     1  c
   3 │     2  a
   4 │     1  b

julia> sort!(df, :x)
4×2 DataFrame
 Row │ x      y
     │ Int64  String
─────┼───────────────
   1 │     1  c
   2 │     1  b
   3 │     2  a
   4 │     3  b

julia> sort!(df, [:x, :y])
4×2 DataFrame
 Row │ x      y
     │ Int64  String
─────┼───────────────
   1 │     1  b
   2 │     1  c
   3 │     2  a
   4 │     3  b

julia> sort!(df, [:x, :y], rev=true)
4×2 DataFrame
 Row │ x      y
     │ Int64  String
─────┼───────────────
   1 │     3  b
   2 │     2  a
   3 │     1  c
   4 │     1  b

julia> sort!(df, [:x, order(:y, rev=true)])
4×2 DataFrame
 Row │ x      y
     │ Int64  String
─────┼───────────────
   1 │     1  c
   2 │     1  b
   3 │     2  a
   4 │     3  b
```
"""
function Base.sort!(df::DataFrame, cols=[]; alg=nothing,
                    lt=isless, by=identity, rev=false, order=Forward)
    if !(isa(by, Function) || eltype(by) <: Function)
        msg = "'by' must be a Function or a vector of Functions. " *
              "Perhaps you wanted 'cols'."
        throw(ArgumentError(msg))
    end
    # exclude AbstractVector as in that case cols can contain order(...) clauses
    if cols isa MultiColumnIndex && !(cols isa AbstractVector)
        cols = index(df)[cols]
    end
    ord = ordering(df, cols, lt, by, rev, order)
    _alg = Sort.defalg(df, ord; alg=alg, cols=cols)
    return sort!(df, _alg, ord)
end

function Base.sort!(df::DataFrame, a::Base.Sort.Algorithm, o::Base.Sort.Ordering)
    p = _sortperm(df, a, o)
    pp = similar(p)
    c = _columns(df)

    for (i, col) in enumerate(c)
        # Check if this column has been sorted already
        if any(j -> c[j]===col, 1:i-1)
            continue
        end

        copyto!(pp, p)
        Base.permute!!(col, pp)
    end
    return df
end


text:
using VT100
using Base.Test
using Compat

failed_tests = 0
for test in [
    "basic/hello", "basic/hello-nocr", "basic/long",
    "basic/color", "basic/boserase"
]
    em = ScreenEmulator(80,24)
    basepath = joinpath(dirname(@__FILE__),test)
    if isfile(string(basepath,".raw.in"))
        open(f->(parseall!(em,f)),string(basepath,".raw.in"))
    else
        @assert isfile(string(basepath,".in"))
        open(f->(parseall!(em,IOBuffer(unescape_string(readstring(f))))),
            string(basepath,".in"))
    end
    output = open(read,string(basepath,".out"))
    buf = IOBuffer()
    VT100.dump(buf,DevNull,em)
    outbuf = takebuf_array(buf)
    if outbuf != output
        print_with_color(:red, "Failed test $test\n")
        failed_tests += 1
        println(output)
        println(outbuf)
        println(Compat.UTF8String(output))
        println(Compat.UTF8String(outbuf))
    end
end
exit(failed_tests)


text:
module IO

using ..Utils
using ..Logical

export

# CircuitParser
load_logical_circuit,
load_smooth_logical_circuit,
load_struct_smooth_logical_circuit,
load_psdd_logical_circuit,
load_lc_logical_circuit,
parse_lc_file,
parse_psdd_file,

# CircuitLineCompiler
# CircuitLineTypes
# can be kept internal

# CircuitSaver
save_as_dot, is_true_node, save_circuit,
# get_node2id,get_vtree2id,vtree_node, decompile, make_element, save_lines, save_psdd_comment_line, save_sdd_comment_line,
# save_line, to_string

# VtreeParser / Saver
parse_vtree_file, compile_vtree_format_lines, load_vtree, save,

# Loaders
mnist, sampled_mnist, twenty_datasets, twenty_dataset_names, dataset,
zoo_vtree_file, zoo_vtree, zoo_psdd, zoo_lc, zoo_clt,
zoo_cnf_file, zoo_cnf, zoo_dnf_file, zoo_dnf,
zoo_lc_file, zoo_psdd_file, zoo_clt_file, zoo_sdd_file

include("VtreeLineCompiler.jl")
include("VtreeParser.jl")
include("VtreeSaver.jl")

include("CircuitLineTypes.jl")
include("CircuitLineCompiler.jl")
include("CircuitParser.jl")

include("CircuitSaver.jl")

include("Loaders.jl")

end


text:
using CUDA.NVML

macro maybe_unsupported(ex)
    quote
        try
            $(esc(ex))
        catch err
            (isa(err, NVMLError) && err.code == NVML.ERROR_NOT_SUPPORTED) || rethrow()
        end
    end
end

@testset "system" begin
    @test NVML.version() isa VersionNumber
    @test NVML.driver_version() isa VersionNumber
    @test NVML.cuda_driver_version() == CUDA.version()
end

@testset "devices" begin
    dev = NVML.Device(0)
    @test dev == first(NVML.devices())

    cuda_dev = CuDevice(0)
    nvml_dev = NVML.Device(uuid(cuda_dev))

    @test NVML.uuid(nvml_dev) == uuid(cuda_dev)
    NVML.brand(nvml_dev)
    @test NVML.name(nvml_dev) == name(cuda_dev)
    @maybe_unsupported NVML.serial(nvml_dev)

    @maybe_unsupported NVML.power_usage(nvml_dev)
    @maybe_unsupported NVML.energy_consumption(nvml_dev)

    NVML.memory_info(nvml_dev)

    @maybe_unsupported NVML.utilization_rates(nvml_dev)

    NVML.compute_mode(nvml_dev)
    @test NVML.compute_capability(nvml_dev) == capability(cuda_dev)
    context()
    # FIXME: https://github.com/NVIDIA/gpu-monitoring-tools/issues/63
    #@test getpid() in keys(NVML.compute_processes(dev))
    NVML.compute_processes(dev)
end


text:
using GeometryTypes, ColorTypes
using GeometryTypes, Reactive, GLAbstraction, ModernGL
import Quaternions
using FileIO
using GLVisualize, GLWindow, ModernGL

w, r = glscreen();

area_msg, area3d = x_partition(w.area, 30.0);
screen3D         = Screen(w, area=area3d);
screenMSG        = Screen(w, area=area_msg);

cs = cubecamera(screen3D);

using Benchmarks
function GLVisualize.visualize(b::Benchmarks.Results, i::Float32)
    t = b.samples.elapsed_times
    m = maximum(t)
    l = length(t)
    ps = Point3f0[Point3f0(i/l,1f0-(x/m), 0f0) for (i,x) in enumerate(t)]
    visualize(ps, color=RGBA(0.84f0, 0.851f0, 1f0, 1f0), scale=Vec3f0(0.006), model=translationmatrix(Vec3f0(0,0,i)), primitive=GLNormalMesh(Sphere{Float32}(Point3f0(0), 1f0)))
end
glClearColor(1,1,1,1)

view(visualize(@benchmark(sin(1.9)), 1f0), screen3D);

cos_01{T}(i::T) = (cos(i)+T(1)) / T(2)
sin_01{T}(i::T) = (sin(i)+T(1)) / T(2)

glClearColor(1,1,1,1)

cap(a, lower=0f0, upper=1f0) = min(max(a, lower), upper)

@enum State Waiting WellDone Failed

color_periodic(k::Float32, i::Float32, j::Float32) = RGBA{U8}(
    cos_01((i/2f0-sin(k)))*sin_01((j/2f0+cos(k))) * abs(sin(k)),
    cos_01(j/2f0)*sin_01(i/2f0) * abs(cos(k)),
    0.01f0,
    cap((cos_01((i/2f0-sin(k)))*sin_01((j/2f0+cos(k))) * abs(sin(k))) +
    (cos_01(j/2f0)*sin_01(i/2f0) * abs(cos(k))))
)

function color_update(done0, k::Float32, done::State)
    done0, image = done0
    if done == Waiting
        return false, RGBA{U8}[color_periodic(k, i, j) for i=0f0:0.1f0:30f0, j=0f0:0.1f0:1f0]
    else
        if done0
            return true, image
        else
            done1 = (isapprox(k, 1f0*pi) && done == WellDone) || (isapprox(k, 0.5f0*pi) && done == Failed)#green
            if done == Failed
                return done1, RGBA{U8}[RGBA{U8}(abs(sin(k)), abs(cos(k)), 0.01f0, abs(sin(k))) for i=0f0:0.1f0:30f0, j=0f0:0.1f0:1f0]
            else
                return done1, RGBA{U8}[RGBA{U8}(abs(sin(k)), abs(cos(k)), 0.01f0, abs(cos(k))) for i=0f0:0.1f0:30f0, j=0f0:0.1f0:1f0]
            end
        end
    end
end

function status_animation(state::Signal{State})
    v0 = RGBA{U8}[color_periodic(0f0, 0f0, 0f0) for i=0f0:0.1f0:30f0, j=0f0:0.1f0:1f0]
    status_img      = foldl(color_update, (false, v0), bounce(0f0:0.01f0*pi:2f0*pi), state)
    animation_done  = lift(first, status_img)
    return dropwhen(animation_done, v0, lift(last, status_img))
end

macro myspawn(expr, f)
    ff = esc(f)
    quote
    ref = @spawn $(esc(expr))
    @async while true
        if isready(ref)
            $ff(fetch(ref))
            break
        else
            yield()
            sleep(0.001)
        end
    end
    end
end

function visualize_bench(name, s)
    state1  = Input(Waiting)
    ref = @spawn sleep(s)
    @async while true
        if isready(ref)
            push!(state1, rand(Bool) ? WellDone : Failed)
            break
        else
            yield()
            sleep(0.001)
        end
    end
    robj1   = visualize(status_animation(state1))
    robj2   = visualize(name)
    [robj1, robj2]
end

a = [
    visualize(visualize_bench("random access", 2)),
    visualize(visualize_bench("linear index", 25)),
    visualize(visualize_bench("öppöpöpö", 15)),
    visualize(visualize_bench("lol index", 7)),
    visualize(visualize_bench("trolol index", 20))
]

c = visualize(a, gap=5f0)

view(c, screenMSG)

r()

#=
function GLVisualize.visualize(b::Benchmarks.Results, i::Float32)
    t = b.samples.elapsed_times
    m = maximum(t)
    l = length(t)
    ps = Point3f0[Point3f0(i/l,1f0-(x/m), 0f0) for (i,x) in enumerate(t)]
    visualize(ps, color=RGBA(0.84f0, 0.851f0, 1f0, 1f0), scale=Vec3f0(0.006), model=translationmatrix(Vec3f0(0,0,i)), primitive=GLNormalMesh(Sphere{Float32}(Point3f0(0), 1f0)))
end

view(visualize(@benchmark(sin(1.9)), 1f0), screen3D);
benches = Benchmarks.Results[(a = rand(n); inds=rand(1:n, 100); @benchmark(test_bench(a, inds))) for n=100:100:10^6]
=#


text:
immutable Categorical <: DiscreteUnivariateDistribution
    K::Int
    prob::Vector{Float64}

    Categorical(p::Vector{Float64}, ::NoArgCheck) = new(length(p), p)

    function Categorical(p::Vector{Float64})
        isprobvec(p) || error("p is not a valid probability vector.")
        new(length(p), p)
    end

    Categorical(k::Int) = new(k, fill(1.0/k, k))
end

ncategories(d::Categorical) = d.K
probs(d::Categorical) = d.prob
probs(d::Categorical, rgn::UnitRange) = d.prob[rgn]

### handling support

function insupport(d::Categorical, x::Real)
    isinteger(x) && one(x) <= x <= d.K && d.prob[x] != 0.0
end

isupperbounded(::Union(Categorical, Type{Categorical})) = true
islowerbounded(::Union(Categorical, Type{Categorical})) = true
isbounded(::Union(Categorical, Type{Categorical})) = true

minimum(::Union(Categorical, Type{Categorical})) = 1
maximum(d::Categorical) = d.K
support(d::Categorical) = 1:d.K

# evaluation

function cdf(d::Categorical, x::Real)
    x < one(x) && return 0.0
    d.K <= x && return 1.0
    p = d.prob[1]
    for i in 2:ifloor(x)
        p += d.prob[i]
    end
    p
end

pdf(d::Categorical, x::Real) = isinteger(x) && 1 <= x <= d.K ? d.prob[x] : 0.0

logpdf(d::Categorical, x::Real) = isinteger(x) && 1 <= x <= d.K ? log(d.prob[x]) : -Inf

function quantile(d::Categorical, p::Real)
    0. <= p <= 1. || throw(DomainError())
    k = d.K
    pv = d.prob
    i = 1
    v = pv[1]
    while v < p && i < k
        i += 1
        @inbounds v += pv[i]
    end
    i
end

# properties

function categorical_mean(p::AbstractArray{Float64})
    k = length(p)
    s = 0.
    for i = 1 : k
        @inbounds s += p[i] * i
    end
    s
end

mean(d::Categorical) = categorical_mean(d.prob)

function median(d::Categorical)
    k = d.K
    p = d.prob
    cp = 0.
    i = 0
    while cp < 0.5 && i <= k
        i += 1
        @inbounds cp += p[i]
    end
    i
end

function var(d::Categorical)
    k = d.K
    p = d.prob
    m = categorical_mean(p)
    s = 0.0
    for i = 1 : k
        @inbounds s += abs2(i - m) * p[i]
    end
    s
end

function skewness(d::Categorical)
    k = d.K
    p = d.prob
    m = categorical_mean(p)
    s = 0.0
    for i = 1 : k
        @inbounds s += (i - m)^3 * p[i]
    end
    v = var(d)
    s / (v * sqrt(v))
end

function kurtosis(d::Categorical)
    k = d.K
    p = d.prob
    m = categorical_mean(p)
    s = 0.0
    for i = 1 : k
        @inbounds s += (i - m)^4 * p[i]
    end
    s / abs2(var(d)) - 3.0
end

entropy(d::Categorical) = entropy(d.prob)

function mgf(d::Categorical, t::Real)
    k = d.K
    p = d.prob
    s = 0.0
    for i = 1 : k
        @inbounds s += p[i] * exp(t)
    end
    s
end

function cf(d::Categorical, t::Real)
    k = d.K
    p = d.prob
    s = 0.0 + 0.0im
    for i = 1 : k
        @inbounds s += p[i] * exp(im * t)
    end
    s
end

mode(d::Categorical) = indmax(d.prob)

function modes(d::Categorical)
    K = d.K
    p = d.prob
    maxp = maximum(p)
    r = Array(Int, 0)
    for k = 1:K
        @inbounds if p[k] == maxp
            push!(r, k)
        end
    end
    r
end

# sampling

sampler(d::Categorical) = AliasTable(d.prob)

### sufficient statistics

immutable CategoricalStats <: SufficientStats
    h::Vector{Float64}
end

function add_categorical_counts!{T<:Integer}(h::Vector{Float64}, x::AbstractArray{T})
    for i = 1 : length(x)
        @inbounds xi = x[i]
        h[xi] += 1.   # cannot use @inbounds, as no guarantee that x[i] is in bound
    end
    h
end

function add_categorical_counts!{T<:Integer}(h::Vector{Float64}, x::AbstractArray{T}, w::AbstractArray{Float64})
    n = length(x)
    if n != length(w)
        throw(ArgumentError("Inconsistent array lengths."))
    end
    for i = 1 : n
        @inbounds xi = x[i]
        @inbounds wi = w[i]
        h[xi] += wi   # cannot use @inbounds, as no guarantee that x[i] is in bound
    end
    h
end

function suffstats{T<:Integer}(::Type{Categorical}, k::Int, x::AbstractArray{T})
    CategoricalStats(add_categorical_counts!(zeros(k), x))
end

function suffstats{T<:Integer}(::Type{Categorical}, k::Int, x::AbstractArray{T}, w::AbstractArray{Float64})
    CategoricalStats(add_categorical_counts!(zeros(k), x, w))
end

suffstats{T<:Integer}(::Type{Categorical}, data::(Int, Array{T})) = suffstats(Categorical, data...)
suffstats{T<:Integer}(::Type{Categorical}, data::(Int, Array{T}), w::Array{Float64}) = suffstats(Categorical, data..., w)

### Model fitting

function fit_mle(::Type{Categorical}, ss::CategoricalStats)
    Categorical(pnormalize!(ss.h))
end

function fit_mle{T<:Integer}(::Type{Categorical}, k::Integer, x::Array{T})
    Categorical(pnormalize!(add_categorical_counts!(zeros(k), x)), NoArgCheck())
end

function fit_mle{T<:Integer}(::Type{Categorical}, k::Integer, x::Array{T}, w::Array{Float64})
    Categorical(pnormalize!(add_categorical_counts!(zeros(k), x, w)), NoArgCheck())
end

fit_mle{T<:Integer}(::Type{Categorical}, data::(Int, Array{T})) = fit_mle(Categorical, data...)
fit_mle{T<:Integer}(::Type{Categorical}, data::(Int, Array{T}), w::Array{Float64}) = fit_mle(Categorical, data..., w)

fit_mle{T<:Integer}(::Type{Categorical}, x::Array{T}) = fit_mle(Categorical, maximum(x), x)
fit_mle{T<:Integer}(::Type{Categorical}, x::Array{T}, w::Array{Float64}) = fit_mle(Categorical, maximum(x), x, w)


text:
# Cannot use the static library cp.lib: very hard to build the corresponding
# dynamic library.
# Cannot use CxxWrap, because it is highly tied to MinGW... and CPLEX CPO is
# compiled with Visual C++.
# Use JavaCall, even though it has some problems with JULIA_COPY_STACKS, @async,
# and other parts of the program using it (the classpath must be set before
# initialising JavaCall).

const depsfile = joinpath(dirname(@__FILE__), "deps.jl")
if isfile(depsfile)
    rm(depsfile)
end

function write_depsfile(path)
    open(depsfile, "w") do f
        println(f, "const libcplexcpojava = \"$(escape_string(path))\"")
        return
    end
    return
end

function get_jar_file()
    # List of supported versions. The latest version must be last.
    cpxvers = ["129", "1290", "1210", "12100", "201", "2010", "20100"]

    # Iterate through a series of places where CPLEX could be found:
    # - either in the path (directly the callable library or the CPLEX executable)
    cplex_path = try
        @static if Sys.isapple() || Sys.isunix()
            dirname(strip(read(`which cpoptimizer`, String)))
        elseif Sys.iswindows()
            dirname(strip(read(`where cpoptimizer`, String)))
        else
            nothing
        end
    catch
        nothing
    end

    if cplex_path !== nothing
        lib_path = abspath(cplex_path * "../../lib/ILOG.CP.jar")
        if isfile(lib_path)
            return lib_path
        end
    end

    # - or from an environment variable.
    base_env = "CPLEX_STUDIO_DIR"
    for env in [base_env, [base_env * v for v in reverse(cpxvers)]...]
        if !haskey(ENV, env)
            continue
        end

        lib_path = abspath(ENV[env] * "/cpoptimizer/lib/ILOG.CP.jar")
        if isfile(lib_path)
            return lib_path
        end
    end

    # Nothing could be found.
    return error(
        "Unable to locate CPLEX installation. Note this must be downloaded " *
        "separately. See the CPLEXCP.jl README for further instructions.",
    )
end

function try_local_installation()
    location = get_jar_file()
    write_depsfile(location)
    @info("Using CPLEX found in location `$(location)`")
end

if get(ENV, "JULIA_REGISTRYCI_AUTOMERGE", "") == "true"
    # We need to be able to install and load this package without error for
    # Julia's registry AutoMerge to work. Just write a fake path.
    write_depsfile("nothing")
else
    try_local_installation()
end


text:
using GpABC, Test
import GpABC.scaled_squared_distance, GpABC.scaled_squared_distance_grad

@testset "Scaled Squared Distance Tests" begin

    D2 = [
        1.67814152778737 1.20785927753982 0.624461685654236 1.46408315059547 8.48310688500901 1.45871370121154 6.42543323212624;
        1.14246534460365 1.85035457131647 1.19053740612926 0.611497365423743 6.99118646721199 2.43597535692027 5.07544002153986;
        7.23733046161335 3.16542101637104 2.72647762438244 8.92586928526950 17.1642767758545 1.17728913861911 14.7362524561371;
        19.0995257794008 4.56588070446465 5.99211031953106 11.1739924041597 34.8720573587766 15.7837441497418 30.3384444420246;
        0.466988806886986 3.56126964624601 2.47101254290117 2.18123029882355 4.99339934819349 1.06659412805776 3.56150053043329
    ]
    x1 = [
        0.459530675532078 0.485182659460782;
        0.332063667630806 0.464957557369470;
        0.994061870963342 0.541666708673195;
        0.197865280880530 0.792372670393611;
        0.521775759068213 0.407471305414788
    ]
    x2 = [
        0.370230106343622 0.358754987995492;
        0.457397317261154 0.595083240231072;
        0.476711208222765 0.564018563630068;
        0.0852766000131502 0.459998930552974;
        0.243816421015103 0.202025803831418;
        0.822588000829605 0.447684994641545;
        0.236529943177723 0.241704940442790
    ]
    log_theta = [-log(10)/2, -log(100)/2]
    @test D2 ≈ scaled_squared_distance(log_theta, x1, x2)
    D2D = [
        0 0.203383856493429 3.17628077043479 10.1212580692727 0.642649959010387;
        0.203383856493429 0 4.97084560152883 10.9001576937249 0.690373692755269;
        3.17628077043479 4.97084560152883 0 12.6246380248108 4.03138234045883;
        10.1212580692727 10.9001576937249 12.6246380248108 0 15.8640860550538;
        0.642649959010387 0.690373692755269 4.03138234045883 15.8640860550539 0
    ]
    @test D2D ≈ scaled_squared_distance(log_theta, x1, x1)

    x1 = [
        0.289686565422307	0.400690696388805;
        0.762105052714285	0.408534206640224;
        0.699620968987989	0.234411002245923;
        0.529625781127078	0.745714747228527;
        0.420503402790289	0.227756669850907;
    ]
    x2 = [
        0.906350184188387	0.112500416632975;
        0.0275456542277456	0.794502350406024;
        0.959810605719597	0.201003274042627;
        0.536850329272845	0.262026834423666;
        0.843484088705612	0.885006158559120;
        0.437078875227402	0.298506903135454;
        0.984655946951665	0.00552099757153587;
    ]
    log_theta = log.([2, 3])

    R57 = [
        0.791406184803418	0.290820793849798	0.273243301209641	0.976630407840307	0.919637321922759	0.373113582084474	0.167134671084180;
        0.163747991045820	0.825082233559844	0.400163430441247	0.227264572040767	0.344469555814038	0.919974093753832	0.0324169118108307;
        0.112485507089871	0.157099440301349	0.546775426038902	0.635662289166666	0.499824566533707	0.00459372066175273	0.831036804630904;
        0.543917659457735	0.370293144774760	0.654585435825673	0.576094024151607	0.551489732019366	0.206663162078086	0.235575431601878;
        0.624102506145883	0.516884229386637	0.617419922080552	0.412263916066039	0.887926049478318	0.387765046389664	0.316278932763393;
    ]
    R55 = [
        0.700022954354073	0.281477719210776	0.145081796750930	0.243184048330031	0.327940463706823;
        0.285793828911052	0.796026775518445	0.389757992881238	0.194300282837032	0.695373520578897;
        0.336882508051061	0.822016138500542	0.662586354959098	0.604853641989107	0.142760369527508;
        0.984312814187404	0.625239778601211	0.0888677975576687	0.775160910922643	0.373530648822678;
        0.345468047701506	0.404958950544223	0.601073551737272	0.129429876864622	0.929614762742824;
    ]

    @test scaled_squared_distance([0.0], ones(5,3), ones(7, 3)) == zeros(5, 7)
    @test scaled_squared_distance(zeros(4), ones(5,4), ones(7, 4) * 0.5) == ones(5, 7)

    @test [-1.36366400189887, -0.500622886827688] ≈ scaled_squared_distance_grad(log_theta, x1, x2, R57)
    @test [-0.275598889477765, -0.147072058193387] ≈ scaled_squared_distance_grad(log_theta, x1, x1, R55)

end


text:
#####
##### Hyperparameters
#####
Network = ResNet

netparams = ResNetHP(
  num_filters=256,
  num_blocks=25,
  conv_kernel_size=(3, 3),
  num_policy_head_filters=128,
  num_value_head_filters=128,
  batch_norm_momentum=0.1)

self_play = SelfPlayParams(
  num_games=1000,
  reset_mcts_every=1,
  mcts=MctsParams(
    use_gpu=true,
    num_workers=32,
    num_iters_per_turn=1000,
    cpuct=4.0,
    prior_temperature=0.7,
    temperature=PLSchedule([0, 24], [1.0, 0.5]),
    dirichlet_noise_ϵ=0.25,
    dirichlet_noise_α=1.25))

arena = ArenaParams(
  num_games=2,
  reset_mcts_every=1,
  flip_probability=0.1,
  update_threshold=0.5,
  play_swiss_style=true,
  mcts=MctsParams(
    self_play.mcts,
    temperature=ConstSchedule(0.2),
    dirichlet_noise_ϵ=0.05))

learning = LearningParams(
  use_gpu=true,
  use_position_averaging=true,
  samples_weighing_policy=LOG_WEIGHT,
  batch_size=128,
  loss_computation_batch_size=256,
  optimiser=CyclicNesterov(
    lr_base=0.0075,
    lr_high=0.05,
    lr_low=0.0025,
    momentum_high=0.95,
    momentum_low=0.8),
  l2_regularization=1e-5,
  nonvalidity_penalty=1.,
  min_checkpoints_per_epoch=1,
  max_batches_per_checkpoint=25000,
  num_checkpoints=1)

params = Params(
  arena=arena,
  self_play=self_play,
  learning=learning,
  num_iters=100,
  ternary_rewards=false,
  use_symmetries=true,
  memory_analysis=MemAnalysisParams(
    num_game_stages=4),
  mem_buffer_size=PLSchedule(
  [      5,        57],
  [208_000, 1_560_000]))

#####
##### Benchmarks
#####

# mcts_baseline =
#   Benchmark.MctsRollouts(
#     MctsParams(
#       arena.mcts,
#       num_iters_per_turn=1000,
#       num_workers=1,
#       cpuct=1.))

# minmax_baseline = Benchmark.MinMaxTS(depth=5, amplify_rewards=true, τ=0.2)

solver_baseline = Benchmark.Solver(ϵ=0)

players = [
  Benchmark.Full(arena.mcts),
  Benchmark.NetworkOnly(τ=0.25, use_gpu=true)]

baselines = [
  solver_baseline,
  solver_baseline]

make_duel(player, baseline) =
  Benchmark.Duel(
    player,
    baseline,
    num_games=150,
    flip_probability=0.1,
    color_policy=ALTERNATE_COLORS,
    play_swiss_style=true)

benchmark = [make_duel(p, b) for (p, b) in zip(players, baselines)]

max_stars_repo_name: btheodorou/Bridge-NN-Research

max_issues_repo_name: btheodorou/Bridge-NN-Research

max_forks_repo_name: btheodorou/Bridge-NN-Research


text:
import RandomNumbers: AbstractRNG
export ScramblingRngAdapter, OriginalScramblingRng
abstract type ScramblingRng end

#An adapter to use a standard 64-bit or 32-bit integer RNG for scrambling
mutable struct ScramblingRngAdapter{T} <: ScramblingRng
    rng::AbstractRNG{T} #may be Chacha, Philox or Blabla. Not suited for MT/Well as individual bits distribution not as good
    counter::UInt8
    x::T
    ScramblingRngAdapter(rng::AbstractRNG{T}) where {T} = new{T}(rng, UInt8(64), zero(T))
end

@inline function unirand(s::ScramblingRngAdapter{UInt64})
    if s.counter >= 64
        s.x = rand(s.rng, UInt64)
        s.counter = 0
    end
    b = (s.x >> s.counter) & one(UInt64)
    s.counter += 1
    return b
end

@inline function unirand(s::ScramblingRngAdapter{UInt32})
    if s.counter >= 32
        s.x = rand(s.rng, UInt32)
        s.counter = 0
    end
    b = (s.x >> s.counter) & one(UInt32)
    s.counter += 1
    return b
end

mutable struct OriginalScramblingRng <: ScramblingRng
    seedi::Int32
    seedj::Int32
    seedcarry::Float64
    seedseeds::Vector{Float64}
end

function OriginalScramblingRng()
    seedi = 24
    seedj = 10
    seedcarry = 0
    seedseeds = [
        0.8804418,
        0.2694365,
        0.0367681,
        0.4068699,
        0.4554052,
        0.2880635,
        0.1463408,
        0.2390333,
        0.6407298,
        0.1755283,
        0.713294,
        0.4913043,
        0.2979918,
        0.1396858,
        0.3589528,
        0.5254809,
        0.9857749,
        0.4612127,
        0.2196441,
        0.7848351,
        0.40961,
        0.9807353,
        0.2689915,
        0.5140357,
    ]
    rng = OriginalScramblingRng(seedi, seedj, seedcarry, seedseeds)
    resetSeed(rng)
end

function seed(s::OriginalScramblingRng, seeds::Vector{Float64})
    s.seedi = 24
    s.seedj = 10
    s.seedcarry = 0
    s.seedseeds .= seeds
    s
end

function resetSeed(rng::OriginalScramblingRng)
    seeds = [
        0.8804418,
        0.2694365,
        0.0367681,
        0.4068699,
        0.4554052,
        0.2880635,
        0.1463408,
        0.2390333,
        0.6407298,
        0.1755283,
        0.713294,
        0.4913043,
        0.2979918,
        0.1396858,
        0.3589528,
        0.5254809,
        0.9857749,
        0.4612127,
        0.2196441,
        0.7848351,
        0.40961,
        0.9807353,
        0.2689915,
        0.5140357,
    ]
    seed(rng, seeds)
end

@inline unirand(s::OriginalScramblingRng) = trunc(UInt32, rand(s) * 1000.0) % 2

@inline function rand(s::OriginalScramblingRng)
    retVal = s.seedseeds[s.seedi] - s.seedseeds[s.seedj] - s.seedcarry
    if retVal < 0
        retVal += 1
        s.seedcarry = 5.9604644775390625e-8 #1/2^24
    else
        s.seedcarry = 0
    end
    s.seedseeds[s.seedi] = retVal
    s.seedi = 24 - (25 - s.seedi) % 24
    s.seedj = 24 - (25 - s.seedj) % 24
    return retVal
end


text:
using Test
using LinearAlgebra
using Random
using Winston
include("lowerbounds.jl")

function check_square(m, msg)
	n = size(m, 1)
	if n != size(m, 2)
		error(msg)
	end
	return n
end

function legal_circuit(circuit)
	n = length(circuit) - 1
	return circuit[1] == circuit[end] && sort(circuit[1:(end-1)]) == 1:n
end

function testpathvalidity(path, iscycle)
	if iscycle
		@test path[1] == path[end]
	end
	n = iscycle ? length(path) - 1 : length(path)
	@test sort(unique(path)) == collect(1:n)
end

function pathcost(distmat::Matrix{T},path::AbstractArray{S},
				  manWeight, goodWeight, capacities,
                  lb::Int = 1, ub::Int = length(path)) where {T<:Real, S<:Integer}
				  # distmat: the distance matrix generated by  generate_planar_distmat() in runtests.jl
				  # path: the order of visiting
	cost = zero(T)
	curWeight = manWeight + goodWeight
	for i in lb:(ub - 1)
		curWeight = (curWeight - capacities[i] >= manWeight) ? curWeight - capacities[i] : manWeight
		@inbounds cost += distmat[path[i], path[i+1]] * curWeight
		# @inbounds elinimates the bound checking to improve performance
	end
	return cost
end

function pathcost_rev(distmat::Matrix{T}, path::AbstractArray{S},
					  manWeight, goodWeight, capacities,
                      revLow::Int, revHigh::Int) where {T<:Real, S<:Integer}
	cost = zero(T)
	curWeight = manWeight + goodWeight
	reverse!(path, revLow, revHigh)
	# println(path)
	for i in 1:(length(path) - 1)
		curWeight = (curWeight - capacities[i] >= manWeight) ? curWeight - capacities[i] : manWeight
		@inbounds cost += distmat[path[i], path[i+1]] * curWeight
	end
	return cost
end

function simulated_annealing(distmat::Matrix{T} where {T<:Real},
							 capacities::Array{T} where {T<:Real},
							 manWeight, goodWeight;
                             steps = 50*length(distmat),
							 num_starts = 1,
							 init_temp = exp(8), final_temp = exp(-6.5),
							 init_path::Union{Vector{Int}, Nothing} = nothing)

	# check inputs
	n = check_square(distmat, "Must pass a square distance matrix to simulated_annealing.")

	# cooling rate: we multiply by a constant mult each step
	cool_rate = (final_temp / init_temp)^(1 / (steps - 1))

	# do SA with a single starting path
	function sahelper!(path)
		temp = init_temp / cool_rate # divide by cool_rate so when we first multiply we get init_temp
		n = size(distmat, 1)
		cost_cur = pathcost(distmat, path, manWeight, goodWeight, capacities)  # current state's energy

		for i in 1:steps
			temp *= cool_rate

			# take a step
			# keep first and last cities fixed
			first, last = rand(2:n), rand(2:n)
			if first > last
				first, last = last, first # to be swapped
			end
			cost_other = pathcost_rev(distmat, path, manWeight, goodWeight, capacities, first, last)  # neighbour state's energy
			@fastmath accept = cost_other < cost_cur ? true : rand() < exp((cost_cur - cost_other) / temp)
			# should we accept?
			if accept
				reverse!(path, first, last)
				cost_cur = cost_other
			end
		end

		return path, cost_cur
	end

	# unpack the initial path
	if init_path == nothing
		randstart = true
		path = randpath(n)
	else
		if !legal_circuit(init_path)
			error("The init_path passed to simulated_annealing must be a legal circuit.")
		end
		randstart = false
		path = init_path
	end
	cost = pathcost(distmat, path, manWeight, goodWeight, capacities) # The emergy of currrent state

	for _ in 1:num_starts
		path_this_start = randstart ? randpath(n) : deepcopy(init_path) # generate new
		otherpath, othercost = sahelper!(path_this_start)
		if othercost < cost
			cost = othercost
			path = otherpath
		end
	end

	return path, cost
end

function randpath(n)
	path = 1:n |> collect |> shuffle
	push!(path, path[1]) # loop
	return path
end

function generate_planar_distmat(n)
	pts = rand(2, n)
	dm = [norm(pts[:,i] - pts[:,j]) for i in 1:n, j in 1:n]
	return dm, pts
end

function generate_city_capacity(n , weight_of_good)
	base = weight_of_good / n
	city_capacities = [0 for i in 1:n]
	for i = 1:n
		city_capacities[i] = rand(floor(Int, base*0.6):floor(Int, base*1.4))
	end
	return city_capacities
end

function test_simulated_annealing()
	n = 3
	manWeight = 100
	goodWeight = manWeight*3
	dm, pts = generate_planar_distmat(n)
	pts = transpose(pts)

	dm = ones(3, 3)

	println("The pts are: ")
	println(pts)
	println("The distance matrix is: ")
	println(dm)

	capacities = [100 300 300]#generate_city_capacity(n, goodWeight)
	# single start
	path, cost = simulated_annealing(dm, capacities , manWeight, goodWeight)
	println("The solution path is: ", path)
	println("The cost is: ", cost)
	@test cost > 0
	testpathvalidity(path, true) # closed path
	# multi-start
	n = 8
	dm, pts = generate_planar_distmat(n)
	capacities = generate_city_capacity(n, goodWeight)
	path, cost = simulated_annealing(dm, capacities ,  manWeight, goodWeight, num_starts = 3)
	@test cost > 0
	testpathvalidity(path, true) # also closed
	# given init path
	init_path = collect(1:8)
	push!(init_path, 1)
	reverse!(init_path, 2, 6)
	path, cost = simulated_annealing(dm, capacities,  manWeight, goodWeight, init_path = init_path)
	@test cost > lowerbound(dm)
	testpathvalidity(path, true) # still closed
end

test_simulated_annealing()


text:
using SymSemiseparableMatrices
using LinearAlgebra
import SymSemiseparableMatrices: spline_kernel_matrix, spline_kernel

U, V = spline_kernel(Vector(0.1:0.01:1), 2); # Creating Input Generators resulting in a PSD K
K = SymSemiseparable(U,V); # Generator symmetric semiseparable matrix
x = ones(K.n); # Test vector

K*x

K'*x

K*(K\x)

L = SymSemiseparableChol(K); # Creating Cholesky factorization
L*x
L'*x

L\x
L'\x

Kdiag = DiaSymSemiseparable(U,V,rand(size(U,1)))


text:
module TuringModels

using Reexport

@reexport using Turing
@reexport using CSV, DataFrames, Distributions
@reexport using MCMCChains, StatsFuns

end # module


text:
using Metis, CSparse, Compat
using Base.Test

include("testmat.jl")

function specialize(A::SparseMatrixCSC)
    issymmetric(A) && return Symmetric(triu!(A),:U)
    ishermitian(A) && return Hermitian(triu!(A),:U)
    istril(A) && return LowerTriangular(A)
    istriu(A) && return UpperTriangular(A)
    A
end

cd("Matrix") do
    global mats = [specialize(testmat(nm)) for nm in readdir()]
end

@test size(mats[1]) == (219,85)

@test size(mats[2]) == (48,48)
const o48 = ones(48)
@test_approx_eq mats[2]*(mats[2]\o48) o48
@test_approx_eq Ac_mul_B(mats[2],Ac_ldiv_B(mats[2],o48)) o48

const bc01t = mats[2]'
@test istriu(bc01t)
@test isa(bc01t,UpperTriangular)
@test size(bc01t) == (48,48)
@test_approx_eq bc01t*(bc01t\o48) o48
@test_approx_eq Ac_mul_B(bc01t,Ac_ldiv_B(bc01t,o48)) o48

@test size(mats[3]) == (4884,4884)
const o4884 = ones(4884)
@test_approx_eq mats[3]*(mats[3]\o4884) o4884
@test_approx_eq Ac_mul_B(mats[3],Ac_ldiv_B(mats[3],o4884)) o4884

const bc16t = mats[3]'
@test istriu(bc16t)
@test isa(bc16t,UpperTriangular)
@test size(bc16t) == (4884,4884)
@test_approx_eq bc16t*(bc16t\o4884) o4884
@test_approx_eq Ac_mul_B(bc16t,Ac_ldiv_B(bc16t,o4884)) o4884

const sc1 = Symmetric(triu(mats[2].data'mats[2].data),:U)
const perm1,iperm1 = nodeND(sc1)
const tr1 = etree(sc1)
const sc2 = symperm(sc1,iperm1)
const tr2,postperm = etree(sc2,true)
const sc3 = symperm(sc2,invperm(postperm))
const tr3 = etree(sc3)
@show(tr1)
@show(tr2)
@show(tr3)

# elimination tree
## upper triangle of the pattern test matrix from Figure 4.2 of
## "Direct Methods for Sparse Linear Systems" by Tim Davis, SIAM, 2006
rowval = Int32[1,2,2,3,4,5,1,4,6,1,7,2,5,8,6,9,3,4,6,8,10,3,5,7,8,10,11]
colval = Int32[1,2,3,3,4,5,6,6,6,7,7,8,8,8,9,9,10,10,10,10,10,11,11,11,11,11,11]
A = sparse(rowval, colval, ones(length(rowval)))
p = etree(A)
P,post = etree(A, true)
@test P == p
@test P == Int32[6,3,8,6,8,7,9,10,10,11,0]
@test post == Int32[2,3,5,8,1,4,6,7,9,10,11]
@test isperm(post)

# csc_permute
A = sprand(10,10,0.2)
p = randperm(10)
q = randperm(10)
@test CSparse.csc_permute(A, invperm(p), q) == full(A)[p, q]

# symperm
srand(1234321)
A = triu(sprand(10,10,0.2))       # symperm operates on upper triangle
perm = [10,6,1,9,5,3,7,8,4,2]
@test symperm(A,perm).colptr == [1,1,2,4,5,5,6,8,8,9,10]


text:
function fresh_data()
    t1 = scatter(;y=[1, 2, 3])
    t2 = scatter(;y=[10, 20, 30])
    t3 = scatter(;y=[100, 200, 300])
    l = Layout(;title="Foo")
    p = Plot([copy(t1), copy(t2), copy(t3)], copy(l))
    t1, t2, t3, l, p
end

@testset "Test api methods on Plot" begin

    @testset "test helpers" begin
        @test PlotlyBase._prep_restyle_vec_setindex([1, 2], 2) == [1, 2]
        @test PlotlyBase._prep_restyle_vec_setindex([1, 2], 3) == [1, 2, 1]
        @test PlotlyBase._prep_restyle_vec_setindex([1, 2], 4) == [1, 2, 1, 2]

        @test PlotlyBase._prep_restyle_vec_setindex((1, [42, 4]), 2) == Any[1, [42, 4]]
        @test PlotlyBase._prep_restyle_vec_setindex((1, [42, 4]), 3) == Any[1, [42, 4], 1]
        @test PlotlyBase._prep_restyle_vec_setindex((1, [42, 4]), 4) == Any[1, [42, 4], 1, [42, 4]]
    end

    @testset "test _update_fields" begin
        t1, t2, t3, l, p = fresh_data()
        # test dict version
        o = copy(t1)
        PlotlyBase._update_fields(o, 1, Dict{Symbol,Any}(:foo=>"Bar"))
        @test o["foo"] == "Bar"
        # kwarg version
        PlotlyBase._update_fields(o, 1; foo="Foo")
        @test o["foo"] == "Foo"

        # dict + kwarg version. Make sure dict gets through w/out replacing _
        PlotlyBase._update_fields(o, 1, Dict{Symbol,Any}(:fuzzy_wuzzy=>"Bear");
                                fuzzy_wuzzy="?")
        @test o.fields[:fuzzy_wuzzy] == "Bear"
        @test isa(o.fields[:fuzzy], Dict)
        @test o["fuzzy.wuzzy"] == "?"
    end

    @testset "test relayout!" begin
        t1, t2, t3, l, p = fresh_data()
        # test on plot object
        relayout!(p, Dict{Symbol,Any}(:title=>"Fuzzy"); xaxis_title="wuzzy")
        @test p.layout["title"] == "Fuzzy"
        @test p.layout["xaxis.title"] == "wuzzy"

        # test on layout object
        relayout!(l, Dict{Symbol,Any}(:title=>"Fuzzy"); xaxis_title="wuzzy")
        @test l["title"] == "Fuzzy"
        @test l["xaxis.title"] == "wuzzy"
    end

    @testset "test restyle!" begin
        t1, t2, t3, l, p = fresh_data()
        # test on trace object
        restyle!(t1, 1, Dict{Symbol,Any}(:opacity=>0.4); marker_color="red")
        @test t1["opacity"] == 0.4
        @test t1["marker.color"] == "red"

        # test for single trace in plot
        restyle!(p, 2, Dict{Symbol,Any}(:opacity=>0.4); marker_color="red")
        @test p.data[2]["opacity"] == 0.4
        @test p.data[2]["marker.color"] == "red"

        # test for multiple trace in plot
        restyle!(p, [1, 3], Dict{Symbol,Any}(:opacity=>0.9); marker_color="blue")
        @test p.data[1]["opacity"] == 0.9
        @test p.data[1]["marker.color"] == "blue"
        @test p.data[3]["opacity"] == 0.9
        @test p.data[3]["marker.color"] == "blue"

        # test for all traces in plot
        restyle!(p, 1:3, Dict{Symbol,Any}(:opacity=>0.42); marker_color="white")
        for i in 1:3
            @test p.data[i]["opacity"] == 0.42
            @test p.data[i]["marker.color"] == "white"
        end

        @testset "test restyle with vector attributes applied to all traces" begin
            # test that short arrays repeat
            restyle!(p, marker_color=["red", "green"])
            @test p.data[1]["marker.color"] == "red"
            @test p.data[2]["marker.color"] == "green"
            @test p.data[3]["marker.color"] == "red"

            # test that array of arrays is repeated and applied everywhere
            restyle!(p, marker_color=(["red", "green"],))
            @test p.data[1]["marker.color"] == ["red", "green"]
            @test p.data[2]["marker.color"] == ["red", "green"]
            @test p.data[3]["marker.color"] == ["red", "green"]

            # test that array of arrays is repeated and applied everywhere
            restyle!(p, marker_color=(["red", "green"], "blue"))
            @test p.data[1]["marker.color"] == ["red", "green"]
            @test p.data[2]["marker.color"] == "blue"
            @test p.data[3]["marker.color"] == ["red", "green"]
        end

        @testset "test restyle with vector attributes applied to vector of traces" begin
            # test that short arrays repeat
            restyle!(p, 1:3, marker_color=["red", "green"])
            @test p.data[1]["marker.color"] == "red"
            @test p.data[2]["marker.color"] == "green"
            @test p.data[3]["marker.color"] == "red"

            # test that array of arrays is repeated and applied everywhere
            restyle!(p, 1:3, marker_color=(["red", "green"],))
            @test p.data[1]["marker.color"] == ["red", "green"]
            @test p.data[2]["marker.color"] == ["red", "green"]
            @test p.data[3]["marker.color"] == ["red", "green"]

            # test that array of arrays is repeated and applied everywhere
            restyle!(p, 1:3, marker_color=(["red", "green"], "blue"))
            @test p.data[1]["marker.color"] == ["red", "green"]
            @test p.data[2]["marker.color"] == "blue"
            @test p.data[3]["marker.color"] == ["red", "green"]
        end

        @testset "test restyle with vector attributes applied to trace object" begin
            restyle!(t1, 1, x=[1, 2, 3])
            @test t1["x"] == 1

            restyle!(t1, 1, x=([1, 2, 3],))
            @test t1["x"] == [1, 2, 3]
        end

        @testset "test restyle with vector attributes applied to single trace " begin
            restyle!(p, 2, x=[1, 2, 3])
            @test p.data[2]["x"] == 1

            restyle!(p, 2, x=([1, 2, 3],))
            @test p.data[2]["x"] == [1, 2, 3]
        end
    end

    @testset "test addtraces!" begin
        t1, t2, t3, l, p = fresh_data()
        p2 = Plot()

        # test add one trace to end
        addtraces!(p2, t1)
        @test length(p2.data) == 1
        @test p2.data[1] == t1

        # test add two traces to end
        addtraces!(p2, t2, t3)
        @test length(p2.data) == 3
        @test p2.data[2] == t2
        @test p2.data[3] == t3

        # test add one trace middle
        t4 = scatter()
        addtraces!(p2, 2, t4)
        @test length(p2.data) == 4
        @test p2.data[1] == t1
        @test p2.data[2] == t4
        @test p2.data[3] == t2
        @test p2.data[4] == t3

        # test add multiple trace middle
        t5 = scatter()
        t6 = scatter()
        addtraces!(p2, 2, t5, t6)
        @test length(p2.data) == 6
        @test p2.data[1] == t1
        @test p2.data[2] == t5
        @test p2.data[3] == t6
        @test p2.data[4] == t4
        @test p2.data[5] == t2
        @test p2.data[6] == t3
    end

    @testset "test deletetraces!" begin
        t1, t2, t3, l, p = fresh_data()

        # test delete one trace
        deletetraces!(p, 2)
        @test length(p.data) == 2
        @test p.data[1]["y"] == t1["y"]
        @test p.data[2]["y"] == t3["y"]

        # test delete multiple traces
        deletetraces!(p, 1, 2)
        @test length(p.data) == 0
    end

    @testset "test movetraces!" begin
        t1, t2, t3, l, p = fresh_data()

        # test move one trace to end
        movetraces!(p, 2)  # now 1 3 2
        @test p.data[1]["y"] == t1["y"]
        @test p.data[2]["y"] == t3["y"]
        @test p.data[3]["y"] == t2["y"]

        # test move two traces to end
        movetraces!(p, 1, 2) # now 2 1 3
        @test p.data[1]["y"] == t2["y"]
        @test p.data[2]["y"] == t1["y"]
        @test p.data[3]["y"] == t3["y"]

        # test move from/to
        movetraces!(p, [1, 3], [2, 1])  # 213 -> 123 -> 312
        @test p.data[1]["y"] == t3["y"]
        @test p.data[2]["y"] == t1["y"]
        @test p.data[3]["y"] == t2["y"]
    end
end