text:
using Logging
using JuMP, Gurobi
using DecisionProgramming

const N = 4
const health = [3*k - 2 for k in 1:N]
const test = [3*k - 1 for k in 1:(N-1)]
const treat = [3*k for k in 1:(N-1)]
const cost = [(3*N - 2) + k for k in 1:(N-1)]
const price = [(3*N - 2) + N]
const health_states = ["ill", "healthy"]
const test_states = ["positive", "negative"]
const treat_states = ["treat", "pass"]

@info("Creating the influence diagram.")
S = States([
    (length(health_states), health),
    (length(test_states), test),
    (length(treat_states), treat),
])
C = Vector{ChanceNode}()
D = Vector{DecisionNode}()
V = Vector{ValueNode}()
X = Vector{Probabilities}()
Y = Vector{Consequences}()

for j in health[[1]]
    I_j = Vector{Node}()
    X_j = zeros(S[I_j]..., S[j])
    X_j[1] = 0.1
    X_j[2] = 1.0 - X_j[1]
    push!(C, ChanceNode(j, I_j))
    push!(X, Probabilities(j, X_j))
end

for (i, k, j) in zip(health[1:end-1], treat, health[2:end])
    I_j = [i, k]
    X_j = zeros(S[I_j]..., S[j])
    X_j[2, 2, 1] = 0.2
    X_j[2, 2, 2] = 1.0 - X_j[2, 2, 1]
    X_j[2, 1, 1] = 0.1
    X_j[2, 1, 2] = 1.0 - X_j[2, 1, 1]
    X_j[1, 2, 1] = 0.9
    X_j[1, 2, 2] = 1.0 - X_j[1, 2, 1]
    X_j[1, 1, 1] = 0.5
    X_j[1, 1, 2] = 1.0 - X_j[1, 1, 1]
    push!(C, ChanceNode(j, I_j))
    push!(X, Probabilities(j, X_j))
end

for (i, j) in zip(health, test)
    I_j = [i]
    X_j = zeros(S[I_j]..., S[j])
    X_j[1, 1] = 0.8
    X_j[1, 2] = 1.0 - X_j[1, 1]
    X_j[2, 2] = 0.9
    X_j[2, 1] = 1.0 - X_j[2, 2]
    push!(C, ChanceNode(j, I_j))
    push!(X, Probabilities(j, X_j))
end

for (i, j) in zip(test, treat)
    I_j = [i]
    push!(D, DecisionNode(j, I_j))
end

for (i, j) in zip(treat, cost)
    I_j = [i]
    Y_j = zeros(S[I_j]...)
    Y_j[1] = -100
    Y_j[2] = 0
    push!(V, ValueNode(j, I_j))
    push!(Y, Consequences(j, Y_j))
end

for (i, j) in zip(health[end], price)
    I_j = [i]
    Y_j = zeros(S[I_j]...)
    Y_j[1] = 300
    Y_j[2] = 1000
    push!(V, ValueNode(j, I_j))
    push!(Y, Consequences(j, Y_j))
end

validate_influence_diagram(S, C, D, V)
sort!.((C, D, V, X, Y), by = x -> x.j)

P = DefaultPathProbability(C, X)
U = DefaultPathUtility(V, Y)

@info("Creating the decision model.")
U⁺ = PositivePathUtility(S, U)
model = Model()
z = DecisionVariables(model, S, D)
x_s = PathCompatibilityVariables(model, z, S, P, probability_cut = false)
EV = expected_value(model, x_s, U⁺, P)
@objective(model, Max, EV)

@info("Starting the optimization process.")
optimizer = optimizer_with_attributes(
    () -> Gurobi.Optimizer(Gurobi.Env()),
    "IntFeasTol"      => 1e-9,
)
set_optimizer(model, optimizer)
optimize!(model)

@info("Extracting results.")
Z = DecisionStrategy(z)

@info("Printing decision strategy:")
print_decision_strategy(S, Z)

@info("State probabilities:")
sprobs = StateProbabilities(S, P, Z)
print_state_probabilities(sprobs, health)
print_state_probabilities(sprobs, test)
print_state_probabilities(sprobs, treat)

@info("Conditional state probabilities")
node = 1
for state in 1:2
    sprobs2 = StateProbabilities(S, P, Z, node, state, sprobs)
    print_state_probabilities(sprobs2, health)
    print_state_probabilities(sprobs2, test)
    print_state_probabilities(sprobs2, treat)
end

@info("Computing utility distribution.")
udist = UtilityDistribution(S, P, U, Z)

@info("Printing utility distribution.")
print_utility_distribution(udist)

@info("Printing statistics")
print_statistics(udist)


text:
#= ------------------------------------------------------------------------

    UnitRange{Int64}

------------------------------------------------------------------------ =#

import Base: -, +, contains, ∈
export translate, -, +
export invert, contains, isoverlapping, istouching, isclose

"""
    translate(x::UnitRange{Int64}, y::Integer)

Translate a range. Translation moves a range. A range is translated by adding
an offset to each of its coordinates.

In addition to the translate method, you can also use the + or - operators
to translate a range.

```jldoctest
julia> using Regions

julia> translate(0:10, 5)
5:15

julia> (5:15) + 10
15:25

julia> 10 + (5:15)
15:25

julia> (5:15) - 10
-5:5
```
"""
translate(x::UnitRange{Int64}, y::Integer) = x + y
+(x::UnitRange{Int64}, y::Integer) = x.start + y : x.stop + y
+(x::Integer, y::UnitRange{Int64}) = x + y.start : x + y.stop
-(x::UnitRange{Int64}, y::Integer) = x.start - y : x.stop - y

"""
    invert(x::UnitRange{Int64})

Inverts a range. Inversion mirrors a range at the origin. A range is
inverted by reversing and inverting each of its coordinates.

```jldoctest
julia> using Regions

julia> invert(5:10)
-10:-5

julia> invert(invert(0:100))
0:100
```
"""
invert(x::UnitRange{Int64}) = UnitRange(-x.stop : -x.start)

"""
    contains(x::UnitRange{Int64}, y::Integer)

Test if range x contains value x.

In addition to the contains method, you can also use the ∈ operator.

```jldoctest
julia> using Regions

julia> contains(0:10, 5)
true

julia> contains(0:10, 15)
false

julia> 0 ∈ 0:10
true

julia> 100 ∈ 0:10
false
```
"""
contains(x::UnitRange{Int64}, y::Integer) = y ∈ x

"""
    isoverlapping(x::UnitRange{Int64}, y::UnitRange{Int64})

Test if two ranges overlap.

```jldoctest
julia> using Regions

julia> isoverlapping(0:10, 5:15)
true

julia> isoverlapping(0:10, 20:30)
false
```
"""
isoverlapping(x::UnitRange{Int64}, y::UnitRange{Int64}) = (x < y) ? (x.stop ≥ y.start) : (y.stop ≥ x.start)

"""
    istouching(x::UnitRange{Int64}, y::UnitRange{Int64})

Test if two ranges touch.

```jldoctest
julia> using Regions

julia> istouching(0:10, 11:21)
true

julia> istouching(0:10, 12:22)
false
```
"""
istouching(x::UnitRange{Int64}, y::UnitRange{Int64}) = (x < y) ? (x.stop+1 ≥ y.start) : (y.stop+1 ≥ x.start)

"""
    isclose(::UnitRange{Int64}x, ::UnitRange{Int64}y, distance::Integer)

Test if two ranges are close.

If distance == 0 this is the same as isoverlapping().
If distance == 1 this is the same as istouching().
If distance > 1 this is testing of closeness.

```jldoctest
julia> using Regions

julia> isclose(0:10, 15:25, 5)
true

julia> isclose(0:10, 15:25, 4)
false
```
"""
isclose(x::UnitRange{Int64}, y::UnitRange{Int64}, distance::Integer) = (x < y) ? (x.stop+distance ≥ y.start) : (y.stop+distance ≥ x.start)

ext: jl


text:
using Test

@show Threads.nthreads()
include("test_spectralarray.jl")
include("test_mcm.jl")
include("test_covmat.jl")
include("test_util.jl")
include("test_mcm_planck.jl")

max_stars_repo_name: xzackli/PlanckCov

max_issues_repo_name: xzackli/PlanckCov


text:
module PointMassTest

using Test
using ReactiveMP
using Distributions
using Random
using SpecialFunctions

import ReactiveMP: InfCountingReal, tiny, huge
import ReactiveMP.MacroHelpers: @test_inferred
import ReactiveMP: xtlog, mirrorlog

@testset "PointMass" begin

    rng = MersenneTwister(1234)

    @testset "Real-based PointMass" begin
        for T in (Float16, Float32, Float64, BigFloat)
            scalar = rand(rng, T)
            dist   = PointMass(scalar)

            @test variate_form(dist) === Univariate
            @test_throws BoundsError dist[2]
            @test_throws BoundsError dist[2, 2]

            @test insupport(dist, scalar)
            @test !insupport(dist, scalar + tiny)
            @test !insupport(dist, scalar - tiny)

            @test @test_inferred(T, pdf(dist, scalar))        == one(T)
            @test @test_inferred(T, pdf(dist, scalar + tiny)) == zero(T)
            @test @test_inferred(T, pdf(dist, scalar - tiny)) == zero(T)

            @test @test_inferred(T, logpdf(dist, scalar))        == zero(T)
            @test @test_inferred(T, logpdf(dist, scalar + tiny)) == convert(T, -Inf)
            @test @test_inferred(T, logpdf(dist, scalar - tiny)) == convert(T, -Inf)

            @test_throws MethodError insupport(dist, ones(T, 2))
            @test_throws MethodError insupport(dist, ones(T, 2, 2))
            @test_throws MethodError pdf(dist, ones(T, 2))
            @test_throws MethodError pdf(dist, ones(T, 2, 2))
            @test_throws MethodError logpdf(dist, ones(T, 2))
            @test_throws MethodError logpdf(dist, ones(T, 2, 2))

            @test (@inferred entropy(dist)) == InfCountingReal(eltype(dist), -1)

            @test @test_inferred(T, mean(dist))         == scalar
            @test @test_inferred(T, var(dist))          == zero(T)
            @test @test_inferred(T, std(dist))          == zero(T)
            @test @test_inferred(T, cov(dist))          == zero(T)
            @test @test_inferred(T, precision(dist))    == convert(T, Inf)
            @test @test_inferred(Int, ndims(dist))      == 1
            @test @test_inferred(Type{T}, eltype(dist)) == T

            @test_throws ErrorException probvec(dist)
            @test @test_inferred(T, mean(log, dist))       == log(scalar)
            @test @test_inferred(T, mean(inv, dist))       == inv(scalar)
            @test @test_inferred(T, mean(mirrorlog, dist)) == log(one(scalar) - scalar)
            @test @test_inferred(T, mean(loggamma, dist))  == loggamma(scalar)
        end
    end

    @testset "Vector-based PointMass" begin
        for T in (Float16, Float32, Float64, BigFloat), N in (5, 10)
            vector = rand(rng, T, N)
            dist   = PointMass(vector)

            @test variate_form(dist) === Multivariate
            @test dist[2] === vector[2]
            @test dist[3] === vector[3]
            @test_throws BoundsError dist[N + 1]
            @test_throws BoundsError dist[N - 1, N - 1]

            @test insupport(dist, vector)
            @test !insupport(dist, vector .+ tiny)
            @test !insupport(dist, vector .- tiny)

            @test @test_inferred(T, pdf(dist, vector))         == one(T)
            @test @test_inferred(T, pdf(dist, vector .+ tiny)) == zero(T)
            @test @test_inferred(T, pdf(dist, vector .- tiny)) == zero(T)

            @test @test_inferred(T, logpdf(dist, vector))         == zero(T)
            @test @test_inferred(T, logpdf(dist, vector .+ tiny)) == convert(T, -Inf)
            @test @test_inferred(T, logpdf(dist, vector .- tiny)) == convert(T, -Inf)

            @test_throws MethodError insupport(dist, one(T))
            @test_throws MethodError insupport(dist, ones(T, 2, 2))
            @test_throws MethodError pdf(dist, one(T))
            @test_throws MethodError pdf(dist, ones(T, 2, 2))
            @test_throws MethodError logpdf(dist, one(T))
            @test_throws MethodError logpdf(dist, ones(T, 2, 2))

            @test (@inferred entropy(dist)) == InfCountingReal(eltype(dist), -1)

            @test @test_inferred(AbstractVector{T}, mean(dist))         == vector
            @test @test_inferred(AbstractVector{T}, var(dist))          == zeros(T, N)
            @test @test_inferred(AbstractVector{T}, std(dist))          == zeros(T, N)
            @test @test_inferred(AbstractMatrix{T}, cov(dist))          == zeros(T, N, N)
            @test @test_inferred(AbstractMatrix{T}, precision(dist))    == fill(convert(T, Inf), (N, N))
            @test @test_inferred(Int, ndims(dist))      == N
            @test @test_inferred(Type{T}, eltype(dist)) == T

            @test @test_inferred(AbstractVector{T}, probvec(dist))      == vector
            @test @test_inferred(AbstractVector{T}, mean(log, dist))    == log.(vector)
            @test_throws ErrorException mean(inv, dist)
            @test_throws ErrorException mean(mirrorlog, dist)
            @test @test_inferred(AbstractVector{T}, mean(loggamma, dist)) == loggamma.(vector)
        end
    end

    @testset "Matrix-based PointMass" begin
        for T in (Float16, Float32, Float64, BigFloat), N in (5, 10)
            matrix = rand(rng, T, N, N)
            dist   = PointMass(matrix)

            @test variate_form(dist) === Matrixvariate
            @test dist[2]    === matrix[2]
            @test dist[3]    === matrix[3]
            @test dist[3, 3] === matrix[3, 3]
            @test_throws BoundsError dist[N ^ 3]
            @test_throws BoundsError dist[N + 1, N + 1]

            @test insupport(dist, matrix)
            @test !insupport(dist, matrix .+ tiny)
            @test !insupport(dist, matrix .- tiny)

            @test @test_inferred(T, pdf(dist, matrix))         == one(T)
            @test @test_inferred(T, pdf(dist, matrix .+ tiny)) == zero(T)
            @test @test_inferred(T, pdf(dist, matrix .- tiny)) == zero(T)

            @test @test_inferred(T, logpdf(dist, matrix))         == zero(T)
            @test @test_inferred(T, logpdf(dist, matrix .+ tiny)) == convert(T, -Inf)
            @test @test_inferred(T, logpdf(dist, matrix .- tiny)) == convert(T, -Inf)

            @test_throws MethodError insupport(dist, one(T))
            @test_throws MethodError insupport(dist, ones(T, 2))
            @test_throws MethodError pdf(dist, one(T))
            @test_throws MethodError pdf(dist, ones(T, 2))
            @test_throws MethodError logpdf(dist, one(T))
            @test_throws MethodError logpdf(dist, ones(T, 2))

            @test (@inferred entropy(dist)) == InfCountingReal(eltype(dist), -1)

            @test @test_inferred(AbstractMatrix{T}, mean(dist))       == matrix
            @test @test_inferred(AbstractMatrix{T}, var(dist))        == zeros(N, N)
            @test @test_inferred(AbstractMatrix{T}, std(dist))        == zeros(N, N)
            @test @test_inferred(Tuple{Int, Int}, ndims(dist)) == (N, N)
            @test @test_inferred(Type{T}, eltype(dist))        == T

            @test_throws ErrorException cov(dist)
            @test_throws ErrorException precision(dist)

            @test_throws ErrorException probvec(dist)
            @test @test_inferred(AbstractMatrix{T}, mean(log, dist))  == log.(matrix)
            @test @test_inferred(AbstractMatrix{T}, mean(inv, dist))  ≈ cholinv(matrix)
            @test_throws ErrorException mean(mirrorlog, dist)
            @test @test_inferred(AbstractMatrix{T}, mean(loggamma, dist)) == loggamma.(matrix)
        end
    end

end

end


text:
# automatically generated by the FlatBuffers compiler, do not modify

UnionVector.eval(quote

FlatBuffers.@UNION(Character, (
    Nothing,
    Attacker,
    Rapunzel,
    BookReader,
    BookReader,
    String,
    String,
))

end)

max_stars_repo_name: rjkat/flatbuffers-julia

max_issues_repo_name: rjkat/flatbuffers-julia

max_forks_repo_name: rjkat/flatbuffers-julia


text:
using BinaryBuilder

name = "SCS_MKL"
version = v"3.2.1"

# Collection of sources required to build SCSBuilder
sources = [
    GitSource("https://github.com/cvxgrp/scs.git", "c785d2fad46a30f1d43764d682509d0b56e5c64f")
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/scs*
scsflags="DLONG=1 USE_OPENMP=0 BLAS32=1 NOBLASSUFFIX=1"
mklflags="-L${prefix}/lib -Wl,--no-as-needed -lmkl_rt -lmkl_core -lpthread -lm -ldl"

make ${scsflags} MKLFLAGS="${mklflags}" out/libscsmkl.${dlext}

mkdir -p ${libdir}
cp out/libscs*.${dlext} ${libdir}
"""

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

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

# Dependencies that must be installed before this package can be built
dependencies = [
    Dependency("MKL_jll"; compat="2022.0.0"),
]

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

max_stars_repo_name: MichelJuillard/Yggdrasil

max_issues_repo_name: MichelJuillard/Yggdrasil

max_forks_repo_name: MichelJuillard/Yggdrasil


text:
export matmul, matmulTT, matmulNT, matmulTN

immutable LinAlg <: AFImpl
    matmul::Ptr{Void}

    function LinAlg(ptr)
        new(
            Libdl.dlsym(ptr, :af_matmul)
        )
    end
end

function matmul{B}(
    lhs::AFArray{B},
    rhs::AFArray{B},
    optLhs = AF_MAT_NONE,
    optRhs = AF_MAT_NONE)
    verifyAccess(lhs)
    verifyAccess(rhs)
    af = lhs.af
    result = af.results.ptr
    err = ccall(af.linAlg.matmul,
        Cint, (Ptr{Ptr{Void}}, Ptr{Void}, Ptr{Void}, Int32, Int32),
        result, lhs.ptr, rhs.ptr, optLhs, optRhs)
    assertErr(err)
    array(af, result[])
end

matmulTT(lhs, rhs) = matmul(lhs, rhs, AF_MAT_TRANS, AF_MAT_TRANS)

matmulTN(lhs, rhs) = matmul(lhs, rhs, AF_MAT_TRANS, AF_MAT_NONE)

matmulNT(lhs, rhs) = matmul(lhs, rhs, AF_MAT_NONE, AF_MAT_TRANS)

max_stars_repo_name: unbornchikken/julia-ml-proto

max_issues_repo_name: unbornchikken/julia-ml-proto

max_forks_repo_name: unbornchikken/julia-ml-proto


text:
using CANalyze.Decode
using CANalyze.Frames
using CANalyze.Signals

frame = Frames.CANFrame(20, [1, 2, 0xFD, 4, 5, 6, 7, 8])

sig1 = Signals.Unsigned{Float32}(0, 1)
sig2 = Signals.Unsigned{Float64}(start=0, length=8, factor=2, offset=20)
sig3 = Signals.Unsigned(0, 8, 1, 0, :little_endian)
sig4 = Signals.Unsigned(start=0, length=8, factor=1.0, offset=-1337f0, byte_order=:little_endian)

sig5 = Signals.Signed{Float32}(0, 1)
sig6 = Signals.Signed{Float64}(start=3, length=16, factor=2, offset=20, byte_order=:big_endian)
sig7 = Signals.Signed(0, 8, 1, 0, :little_endian)
sig8 = Signals.Signed(start=0, length=8, factor=1.0, offset=-1337f0, byte_order=:little_endian)

sig9    = Signals.Raw(0, 8, :big_endian)
sig10   = Signals.Raw(start=21, length=7, byte_order=:little_endian)

println(sig1)
println(sig2)
println(sig3)
println(sig4)

println(sig5)
println(sig6)
println(sig7)
println(sig8)

println(sig9)
println(sig10)

# signal = Signals.Float32Signal(start=7, factor=1.0f0, offset=0.0f0, byte_order=:big_endian)
bits = Signals.Bits(sig6)
println(bits)
# value  = Decode.decode(signal,frame)
# hex = reinterpret(UInt8, [value])
# println(value)
# println(hex)
#
# signal = Signals.Float32Signal(start=0, byte_order=:little_endian)
# value  = Decode.decode(signal,frame)
# hex = reinterpret(UInt8, [value])
# println(value)
# println(hex)
# println(Signals.overlap(sig1,sig5))

s = Signals.Float32Signal(start=0, byte_order=:little_endian)
signal = Signals.NamedSignal("ABC", nothing, nothing, s)

# println(signal)
# value  = Decode.decode(signal,frame)
# hex = reinterpret(UInt8, [value])
# println(value)
# println(hex)


text:
module StrictPositive

import PublicAPI
PublicAPI.@strict using PublicAPI: Internal

end


text:
using BinaryProvider

const verbose = "--verbose" in ARGS
const prefix = Prefix(get(filter(!isequal("--verbose"), ARGS), 1, joinpath(@__DIR__, "usr")))
products = [LibraryProduct(prefix, ["libzstd"], :libzstd)]

bin_prefix = "https://github.com/JuliaPackaging/Yggdrasil/releases/download/Zstd-v1.4.2+0"

download_info = Dict(
    Linux(:aarch64, libc=:glibc) =>
        ("$bin_prefix/Zstd.v1.4.2.aarch64-linux-gnu.tar.gz",
         "fa5b1a0bbaf0d0c9b68b74f985609c16212288ad1822834a8bc973dc28de7b3b"),
    Linux(:aarch64, libc=:musl) =>
        ("$bin_prefix/Zstd.v1.4.2.aarch64-linux-musl.tar.gz",
         "913f994d6c6005d2b574a1f7b00cef59fc0ad99ac1b6df91ac16ea0b7fee7f99"),
    Linux(:armv7l, libc=:glibc, call_abi=:eabihf) =>
        ("$bin_prefix/Zstd.v1.4.2.arm-linux-gnueabihf.tar.gz",
         "bf474a692e013b0c6e74b9a738e04c6aa12b0c0f54269a6d94eed45eec05aabb"),
    Linux(:armv7l, libc=:musl, call_abi=:eabihf) =>
        ("$bin_prefix/Zstd.v1.4.2.arm-linux-musleabihf.tar.gz",
         "489e8706c27b6277b3cd604f9bfc88c8f81d2ae9b76d34062f099fe31c024e5d"),
    Linux(:i686, libc=:glibc) =>
        ("$bin_prefix/Zstd.v1.4.2.i686-linux-gnu.tar.gz",
         "ed8652f9509fd6cb6cd3cca9023326b698d1437f6d22026c7763a32658a8fca5"),
    Linux(:i686, libc=:musl) =>
        ("$bin_prefix/Zstd.v1.4.2.i686-linux-musl.tar.gz",
         "b0de4b032efa9a0108c32a00e27367352e36304f3f62c3cfbe9cdae5ff48fa2f"),
    Windows(:i686) =>
        ("$bin_prefix/Zstd.v1.4.2.i686-w64-mingw32.tar.gz",
         "785a2a97ba59fbe2529b4ded1e380d1385351b805f9d0b91df64802db36648d5"),
    Linux(:powerpc64le, libc=:glibc) =>
        ("$bin_prefix/Zstd.v1.4.2.powerpc64le-linux-gnu.tar.gz",
         "8dbc6e14931d70f5b112f9f00534c80d2b5cde18dbb74ebae31b6ff97f7863dd"),
    MacOS(:x86_64) =>
        ("$bin_prefix/Zstd.v1.4.2.x86_64-apple-darwin14.tar.gz",
         "5ff8c2b4719fd1b605413388608007e5bdeb92caa60619c32f1809dc6907fcfc"),
    Linux(:x86_64, libc=:glibc) =>
        ("$bin_prefix/Zstd.v1.4.2.x86_64-linux-gnu.tar.gz",
         "a6806ca68680bf813ff326f65f4a478574a2a4e27b8ad72c8e9a8f180a89b816"),
    Linux(:x86_64, libc=:musl) =>
        ("$bin_prefix/Zstd.v1.4.2.x86_64-linux-musl.tar.gz",
         "b00c751cfb61d160415c427a795fdc3521735c37c3c32164b8218f210e8a3d51"),
    FreeBSD(:x86_64) =>
        ("$bin_prefix/Zstd.v1.4.2.x86_64-unknown-freebsd11.1.tar.gz",
         "d38e10e988a4b7229906c1f52f1b1a12589063d1d6ad90315fbc72532650f468"),
    Windows(:x86_64) =>
        ("$bin_prefix/Zstd.v1.4.2.x86_64-w64-mingw32.tar.gz",
         "ab42350bf99389cd9118e1d10a310d6a572afcfe521e70abd42f7bfa340666bd"),
)

unsatisfied = any(p->!satisfied(p, verbose=verbose), products)
dl_info = choose_download(download_info, platform_key_abi())
if dl_info === nothing && unsatisfied
    error("Your platform (\"$(Sys.MACHINE)\", parsed as ",
          "\"$(triplet(platform_key_abi()))\") is not supported by this package!")
end

if unsatisfied || !isinstalled(dl_info..., prefix=prefix)
    install(dl_info..., prefix=prefix, force=true, verbose=verbose)
end

write_deps_file(joinpath(@__DIR__, "deps.jl"), products, verbose=verbose)


text:
include("godunov_3.jl")
using .Godunov
using Plots
fig = Plots.plot()

# Physical parameters:
α = 1.0
ν = 1.0
s = 0.01

# Other params:
Nc = 40 # no of cells
tmax = 1.0e1 # max time
dt = 1.0e0 # how often to plot
tp = 0.0e0#5000 # when to start plotting

r=Godunov.ring(Nc, (α,ν,s), xfr=3.0)
Godunov.step!(r)

xh = r.Ls["Lcrit"]
xv = r.Ls["Lvisc"]
x_ = (r.X●[1:end-1]+r.X●[2:end])/2.0
x2_ = 2*r.X●[end].-reverse(x_)
xx_ = cat(x_,x2_,dims=1)
Godunov.step!(r)
#for i in 1:10
for tt in 0.0:dt:tmax
    tx = r.t; Σ_ = r.Σ_; Φ_ = r.Φ_
    if tx ≥ tp
        ΣΣ_ = cat(Σ_[2:end-1], reverse(Σ_[2:end-1]),dims=1)
        ΦΦ_ = cat(Φ_[2:end-1],-reverse(Φ_[2:end-1]),dims=1)
        Plots.plot!(xx_./xv,ΣΣ_,label="t: $tx",legend=false,xlim=(0,2*r.X●[end]/xv),ylim=(0,1.2*maximum(ΣΣ_)))#:bottomright)#,title="Σ")#;legend=false)
        display(fig)
        print("time: $tx\n")
#        Plots.plot!(xx_,ΦΦ_,label=false,linestyle=:dash)#,label="t: $t",legend=:topleft)#,title="J")#;legend=false)
#        display(fig)
    end
#    for j in 1:800
#        Godunov.step!(r)#,dt)
#    end
    Godunov.tstep!(r,dt)
end

tf=r.t
print("Done at t= $tf\n")

max_stars_repo_name: diakosmos/razor

max_issues_repo_name: diakosmos/razor

max_forks_repo_name: diakosmos/razor


text:
using JuMP
using CPLEX
include("parser.jl")

function PL_heuristic(cout_ouverture, Fct_commod, func_cost, func_capacity, nb_nodes, nb_arcs, nb_commodities, latency, node_capacity, commodity, nb_func, exclusion, remaining_capacity_fi)
  # version modifiee du PL normal
  # remaining_capacity_fi DONE

  m = Model(CPLEX.Optimizer)

	# Var
	@variable(m, x_i[1:nb_nodes], Bin) # activation d'une fonction au sommet i
	@variable(m, x_fi[1:nb_func,1:nb_nodes], Int) # activation(s) de la fonction f au sommet i
	@variable(m, x_ikf[1:nb_nodes,1:nb_commodities,1:nb_func], Bin) # activation de la fonction f au sommet i pour le traitement de la commodite k
	@variable(m, e[1:nb_nodes,1:nb_nodes,1:nb_commodities,1:nb_func+1], Bin) # passage par l'arc (i,j) par la commodite k lpour traitement par la fonction f, ou en direction du puit si on considère e[i,j,k,end]

	#Constraint on states
	for i in 1:nb_nodes
		@constraint(m,[f in 1:nb_func], x_fi[f,i]*func_capacity[f] + remaining_capacity_fi[f,i] >= sum(x_ikf[i,k,f]*commodity[k,3] for k in 1:nb_commodities), base_name = "n_"*string(f)*"_"*string(i)) # Nombre de fonctions f a placer en i
		@constraint(m,sum(x_fi[f,i] for f in 1:nb_func) <= node_capacity[i], base_name = "cap_"*string(i) ) #capacite de noeud
    for k in 1:nb_commodities
			@constraint(m,[f in 1:nb_func],x_i[i] >= x_ikf[i,k,f], base_name = "ouverture_"*string(i)*"_"*string(f)) #ouverture du noeud en i
			#@constraint(m,[f in 1:nb_func],x_ikf[i,k,f] <= length( findall( y -> y == f, Fct_commod[k] ))) #fixer a 0 x_ikf si fonction f n'est pas a appliquer a commodite k (donc pas sur le noeud i en particulier)
			if size(exclusion[k,:])[1]>0
				@constraint(m,sum(x_ikf[i,k,w] for w in exclusion[k,:] if w!=0) <= 1, base_name = "exclusion_"*string(k)*"_"*string(i)) # exclusion
			end
			for j in 1:nb_nodes
				if latency[i,j] == 0
					@constraint(m,[f in 1:nb_func],e[i,j,k,f]==0, base_name = "no_arc_"*string(i)*"_"*string(j)*"_"*string(f)) #absence d'arcs
				end
			end
		end
	end

	#Contrainte de flots successifs pour chaque commodite
	for k in 1:nb_commodities
		size_fk=length( findall( y -> y > 0, Fct_commod[k,:]))

		tab_fk=sortperm( Fct_commod[k,:])[1:size_fk]
		@constraint(m,sum(e[commodity[k,1],j,k,tab_fk[1]] - e[j,commodity[k,1],k,tab_fk[1]] for j in 1:nb_nodes)-x_ikf[commodity[k,1],k,tab_fk[1]]==1, base_name = "init_flot_"*string(k)) #initialisation du flot a la source
		@constraint(m,[i in 1:nb_nodes ; i!=commodity[k,1]],sum(e[i,j,k,tab_fk[1]] - e[j,i,k,tab_fk[1]]  for j in 1:nb_nodes)+x_ikf[i,k,tab_fk[1]]==0, base_name = "1er_flot_"*string(k)*"_"*string(i)) #flot pour traiter la première fonction de puis la source
		for t in 2:size_fk
			@constraint(m,[i in 1:nb_nodes],sum(e[i,j,k,tab_fk[t]] - e[j,i,k,tab_fk[t]] for j in 1:nb_nodes)-x_ikf[i,k,tab_fk[t-1]]+x_ikf[i,k,tab_fk[t]]==0, base_name = "mid_flow_"*string(t)*"_"*string(k)*"_"*string(i)) #flot d'un traitement au suivant
		end
		@constraint(m,[i in 1:nb_nodes ; i!=commodity[k,2]],sum(e[i,j,k,nb_func+1] - e[j,i,k,nb_func+1] for j in 1:nb_nodes)-x_ikf[i,k,tab_fk[end]]==0, base_name = "last_flow_"*string(k)*"_"*string(i)) #flot du dernier traitement vers le puit
		@constraint(m,sum(e[j,commodity[k,2],k,end] for j in 1:nb_nodes)+x_ikf[commodity[k,2],k,tab_fk[end]]==1, base_name = "end_flow_"*string(k)) #fin de flot sur le puit
	end

	for k in 1:nb_commodities
		for f in 1:nb_func
			@constraint(m,sum(x_ikf[i,k,f] for i in 1:nb_nodes)<=1, base_name = "concatenation_"*string(k)*"_"*string(f)) #concatenation des problemes de flot
		end
	end

	#Contraintes de latence
	@constraint(m, [k in 1:nb_commodities], sum( sum( sum(e[i,j,k,f]*latency[i,j] for f in 1:nb_func+1) for j in 1:nb_nodes) for i in 1:nb_nodes) <= commodity[k,4])

	#Objective
	@objective(m, Min, sum(x_i[i]*cout_ouverture[i] + sum(x_fi[f,i]*func_cost[f,i] for f in 1:nb_func) for i in 1:nb_nodes) )

	optimize!(m)
  for i in 1:nb_nodes
    for f in 1:nb_func
      # ATTENTION, JuMP.value.() renvoie un Float64 qui peut etre inexact (2.999999999595) ce qui fait planter le PLNE
      # remaining_capacity_fi[f,i] = Int(trunc(JuMP.value.(x_fi)[f,i]))*func_capacity[f] + remaining_capacity_fi[f,i] - Int(trunc(JuMP.value.(x_ikf)[i,1,f]))*commodity[1,3] # mise a jour de la capacite restante sur les noeuds
    end
  end
  status = termination_status(m)
  isOptimal = status == MOI.OPTIMAL
  if isOptimal == true
    return JuMP.value.(x_i), JuMP.objective_value.(m),  JuMP.value.(x_fi), remaining_capacity_fi, JuMP.value.(x_ikf), JuMP.value.(e), isOptimal
  end
  return Array{Int64,1}(zeros(nb_nodes)), 0, Array{Int64,2}(zeros(nb_func,nb_nodes)), remaining_capacity_fi, Array{Int64,3}(zeros(nb_nodes,nb_commodities,nb_func)), Array{Int64,4}(zeros(nb_nodes,nb_nodes,nb_commodities, nb_func+1)), isOptimal
end

function heuristic(MyFileName::String)
  cout_ouverture, Fct_commod, func_cost, func_capacity, nb_nodes, nb_arcs, nb_commodities, latency, node_capacity, commodity, nb_func, exclusion = read_instance(MyFileName)

  c = cout_ouverture
  cout_ouverture = Array{Int64,1}(zeros(nb_nodes))
  for i in 1:nb_nodes
    cout_ouverture[i] = c
  end
  sum_objectives = 0
  Fct_commodity = Array{Int64,2}(zeros(1,nb_func))
  Fct_commodity[1,:] = Fct_commod[1,:] # create an array with one element, it's simpler
  exclusion_new = Array{Int64,2}(zeros(1,2))
  exclusion_new[1,:] = exclusion[1,:]
  commodity_new = Array{Any,2}(zeros(1,4))
  commodity_new[1,:] = commodity[1,:]
  remaining_capacity_fi = Array{Int64,2}(zeros(nb_func,nb_nodes))

  x_i_sum = Array{Int64,1}(zeros(nb_nodes))
  x_fi_sum =  Array{Int64,2}(zeros(nb_func,nb_nodes))
  x_ikf_sum = Array{Int64,3}(zeros(nb_nodes,nb_commodities,nb_func))
  e_sum = Array{Int64,4}(zeros(nb_nodes,nb_nodes,nb_commodities, nb_func+1))

  x_i, current_objective, x_fi, remaining_capacity_fi, x_ikf, e, isOptimal = PL_heuristic(cout_ouverture, Fct_commodity, func_cost, func_capacity, nb_nodes, nb_arcs, 1, latency, node_capacity, commodity_new, nb_func, exclusion_new, remaining_capacity_fi)
  if isOptimal == false
    println("non soluble par cette methode")
    return false
  end
  for j in 1:nb_nodes
    x_i_sum[j] = x_i_sum[j] + Int(trunc(x_i[j]))
  end
  for k in 1:nb_nodes
    for j in 1:nb_func
      x_fi_sum[j,k] = x_fi_sum[j,k] + Int(trunc(x_fi[j,k]))
    end
  end
  for j in 1:nb_nodes
    x_ikf_sum[j,1,:] = x_ikf[j,1,:]
  end
  for j in 1:nb_nodes
    for l in 1:nb_nodes
      for zz in 1:nb_func+1
        e_sum[j,l,1,zz] = Int(trunc(e[j,l,1,zz]))
      end
    end
  end

  for i in 2:nb_commodities
    # update node_capacity
    for k in 1:nb_nodes
      for j in 1:nb_func
        node_capacity[k] = max(0, node_capacity[k] - Int(trunc(x_fi[j,k])))
      end
    end

    # update cout_ouverture
    for k in 1:nb_nodes
      cout_ouverture[k] = max(0, cout_ouverture[k] - c * Int(trunc(x_i[k])))
    end

    # update sum_objectives
    sum_objectives = sum_objectives + current_objective
    Fct_commodity = Array{Int64,2}(zeros(1,nb_func))
    Fct_commodity[1,:] = Fct_commod[i,:]
    exclusion_new = Array{Int64,2}(zeros(1,2))
    exclusion_new[1,:] = exclusion[i,:]
    commodity_new = Array{Any,2}(zeros(1,4))
    commodity_new[1,:] = commodity[i,:]
    x_i, current_objective, x_fi, remaining_capacity_fi, x_ikf, e, isOptimal = PL_heuristic(cout_ouverture, Fct_commodity, func_cost, func_capacity, nb_nodes, nb_arcs, 1, latency, node_capacity, commodity_new, nb_func, exclusion_new, remaining_capacity_fi)
    if isOptimal == false
      println("non soluble par cette methode")
      return false
    end
    for j in 1:nb_nodes
      x_i_sum[j] = x_i_sum[j] + Int(trunc(x_i[j]))
      if x_i_sum[j] > 1
        x_i_sum[j] = 1
      end
    end
    for k in 1:nb_nodes
      for j in 1:nb_func
        x_fi_sum[j,k] = x_fi_sum[j,k] + Int(trunc(x_fi[j,k]))
      end
    end
    for j in 1:nb_nodes
      for zz in 1:nb_func
        x_ikf_sum[j,i,zz] = Int(trunc(x_ikf[j,1,zz]))
      end
    end
    for j in 1:nb_nodes
      for l in 1:nb_nodes
        for zz in 1:nb_func+1
          e_sum[j,l,i,zz] = Int(trunc(e[j,l,1,zz]))
        end
      end
    end
  end
  return Int(trunc(sum_objectives)), x_i_sum, x_fi_sum, x_ikf_sum, e_sum
end

# heuristic("test_")
heuristic("di-yuan/di-yuan_1/")

max_stars_repo_name: boumpteryx/RORT

max_issues_repo_name: boumpteryx/RORT

max_forks_repo_name: boumpteryx/RORT


text:
module FaceLabelingsTests

using Test
using Gridap.Helpers
using Gridap.Arrays
using Gridap.ReferenceFEs
using Gridap.Geometry
using Gridap.Geometry: GridTopologyMock
using Gridap.Io

model = GridTopologyMock()

d_to_num_dfaces = [num_vertices(model), num_edges(model), num_cells(model)]

labels = FaceLabeling(d_to_num_dfaces)

@test num_tags(labels) == 0
@test num_entities(labels) == 0
@test num_faces(labels,0) == num_faces(model,0)
@test num_faces(labels,1) == num_faces(model,1)
@test num_faces(labels,2) == num_faces(model,2)
@test num_vertices(labels) == num_vertices(model)
@test num_edges(labels) == num_edges(model)
@test num_facets(labels) == num_facets(model)
@test num_faces(labels) == num_faces(model)
@test num_dims(labels) == num_dims(model)
@test num_cell_dims(labels) == num_cell_dims(model)
@test get_face_entity(labels,0) === labels.d_to_dface_to_entity[0+1]
@test get_face_entity(labels,1) === labels.d_to_dface_to_entity[1+1]
@test get_face_entity(labels,2) === labels.d_to_dface_to_entity[2+1]
@test get_face_entity(labels) == vcat(labels.d_to_dface_to_entity...)

get_face_entity(labels,0) .= get_isboundary_face(model,0) .+ 1
get_face_entity(labels,1) .= get_isboundary_face(model,1) .+ 1
get_face_entity(labels,2) .= get_isboundary_face(model,2) .+ 1

add_tag!(labels,"interior",[1,])
add_tag!(labels,"boundary",[2,])
add_tag_from_tags!(labels,"all",["interior","boundary"])
@test num_entities(labels) == 2
@test num_tags(labels) == 3
@test get_tag_name(labels,1) == "interior"
@test get_tag_name(labels,3) == "all"
@test get_tag_from_name(labels,"interior") == 1
@test get_tag_from_name(labels,"all") == 3

dict = to_dict(labels)
labels2 = from_dict(FaceLabeling,dict)
@test labels2.d_to_dface_to_entity == labels.d_to_dface_to_entity
@test labels2.tag_to_entities == labels.tag_to_entities
@test labels2.tag_to_name == labels.tag_to_name

labels2 = from_json(FaceLabeling,to_json(labels))
@test labels2.d_to_dface_to_entity == labels.d_to_dface_to_entity
@test labels2.tag_to_entities == labels.tag_to_entities
@test labels2.tag_to_name == labels.tag_to_name

d = mktempdir()
f = joinpath(d,"labels.jld2")

to_jld2_file(labels,f)
labels2 = from_jld2_file(typeof(labels),f)
@test labels2.d_to_dface_to_entity == labels.d_to_dface_to_entity
@test labels2.tag_to_entities == labels.tag_to_entities
@test labels2.tag_to_name == labels.tag_to_name

rm(d,recursive=true)

@test get_tags_from_names(labels,["interior","all"]) == [1,3]

face_to_mask = get_face_mask(labels,"interior",1)
@test face_to_mask == Bool[0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0]

face_to_tag = get_face_tag(labels,["boundary","interior"],1)
@test face_to_tag == [2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2]

face_to_tag = get_face_tag_index(labels,["boundary","interior"],1)
@test face_to_tag == Int8[1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1]

labels = FaceLabeling(model)
@test num_entities(labels) == 2
@test num_tags(labels) == 2

end # module


text:
swapa(a, i, j) = begin a[i], a[j] = a[j], a[i] end

function pd!(a, first, last)
    while (c = 2 * first - 1) < last
        if c < last && a[c] < a[c + 1]
            c += 1
        end
        if a[first] < a[c]
            swapa(a, c, first)
            first = c
        else
            break
        end
    end
end

hfy!(a, n) = (f = div(n, 2); while f >= 1 pd!(a, f, n); f -= 1 end)

heapsort!(a) = (n = length(a); hfy!(a, n); l = n; while l > 1 swapa(a, 1, l); l -= 1; pd!(a, 1, l) end; a)

a = shuffle(collect(1:12))
println("Unsorted: $a")
println("Heap sorted: ", heapsort!(a))

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
m=rand(2:10)
n=rand(1:10)
Z = Frobenius(m, randn(n)) #size m+n

#Special properties
@test Matrix(inv(Z)) ≈ inv(Matrix(Z))

#Matvec product
b = randn(m+n)
@test Z*b ≈ Matrix(Z)*b

#Matmul product
Y1 = Frobenius(m, randn(n)) #Another one of the same column
@test Matrix(Y1*Z) ≈ Matrix(Y1)*Matrix(Z)

n2=rand(1:(m+n-1))
Y2 = Frobenius(m+n-n2, randn(n2)) #Probably not the same column
@test Matrix(Y2*Z) ≈ Matrix(Y2)*Matrix(Z)


text:
@testset "Interval" begin
    test_values = [
        (-10, 1000, 1),
        (0.0, 1, 0.01),  # Use different types to test promotion
        ('a', 'z', 1),
        (Date(2013, 2, 13), Date(2013, 3, 13), Day(1)),
        (DateTime(2016, 8, 11, 0, 30), DateTime(2016, 8, 11, 1), Millisecond(1)),

        # Infinite endpoints
        (-Inf, 10, 1),
        (10, Inf, 1),
        (-Inf, Inf, 1),
        (-Inf, 1.0, 0.01),
        (0.0, Inf, 0.01),

        # Using Infinity.jl
        (-∞, 10, 1),
        (10, ∞, 1),
        (-∞, ∞, 1),
        (-∞, 1.0, 0.01),
        (-∞, Date(2013, 3, 13), Day(1)),
        (Date(2013, 2, 13), ∞, Day(1)),
        (-∞, DateTime(2016, 8, 11, 1), Millisecond(1)),
        (DateTime(2016, 8, 11, 0, 30), ∞, Millisecond(1)),
        (-∞, Time(1), Millisecond(1)),
        (Time(1), ∞, Millisecond(1)),
    ]

    @testset "constructor" begin
        for T in [Int32, Int64, Float64]
            @test Interval{T}() == Interval{T, Open, Open}(zero(T), zero(T))
        end

        @test Interval{Date}() == Interval{Date, Open, Open}(Date(0), Date(0))
        @test Interval{DateTime}() == Interval{DateTime, Open, Open}(
            DateTime(0), DateTime(0)
        )
        @test Interval{ZonedDateTime}() == Interval{ZonedDateTime, Open, Open}(
            ZonedDateTime(0, tz"UTC"), ZonedDateTime(0, tz"UTC")
        )

        @test Interval(nothing, nothing) == Interval{Nothing, Unbounded, Unbounded}(nothing, nothing)
        @test_throws MethodError Interval{Nothing, Open, Unbounded}(nothing, nothing)
        @test_throws MethodError Interval{Nothing, Unbounded, Closed}(nothing, nothing)

        for (a, b, _) in test_values
            T = promote_type(typeof(a), typeof(b))

            @test a..b == Interval(a, b)
            @test Interval(a, b) == Interval{T, Closed, Closed}(a, b)
            @test Interval{T}(a, b) == Interval{T, Closed, Closed}(a, b)
            @test Interval{Open, Closed}(a, b) == Interval{T, Open, Closed}(a, b)
            @test Interval(LeftEndpoint{Closed}(a), RightEndpoint{Closed}(b)) ==
                Interval{T, Closed, Closed}(a, b)

            @test Interval(a, nothing) == Interval{T, Closed, Unbounded}(a, nothing)
            @test Interval(nothing, b) == Interval{T, Unbounded, Closed}(nothing, b)
            @test Interval{T}(a, nothing) == Interval{T, Closed, Unbounded}(a, nothing)
            @test Interval{T}(nothing, b) == Interval{T, Unbounded, Closed}(nothing, b)
            @test Interval{T}(nothing, nothing) == Interval{T, Unbounded, Unbounded}(nothing, nothing)
            @test Interval{Open, Unbounded}(a, nothing) == Interval{T, Open, Unbounded}(a, nothing)
            @test Interval{Unbounded, Open}(nothing, b) == Interval{T, Unbounded, Open}(nothing, b)
        end

        # If we aren't careful in how we define our Interval constructors we could end up
        # causing a StackOverflow
        @test_throws MethodError Interval{Int, Unbounded, Closed}(1, 2)
        @test_throws MethodError Interval{Int, Closed, Unbounded}(1, 2)
        @test_throws MethodError Interval{Int, Unbounded, Unbounded}(1, 2)

        # Deprecated
        @test_deprecated Interval{DateTime,Open,Closed}(DateTime(0), DateTime(0), Inclusivity(false, true))
        @test_throws ArgumentError Interval{DateTime,Open,Closed}(DateTime(0), DateTime(0), Inclusivity(true, true))

        @test_deprecated Interval{Float64,Open,Closed}(0, 0, Inclusivity(false, true))
        @test_throws ArgumentError Interval{Float64,Open,Closed}(0, 0, Inclusivity(true, true))
        @test_throws MethodError Interval{Float64,Unbounded,Closed}(nothing, 0, Inclusivity(true, true))
        @test_throws MethodError Interval{Float64,Open,Unbounded}(0, nothing, Inclusivity(false, true))
        @test_throws ArgumentError Interval{Nothing,Unbounded,Unbounded}(nothing, nothing, Inclusivity(false, false))
    end

    @testset "non-ordered" begin
        @test_throws ArgumentError Interval(NaN, NaN)
        @test_throws ArgumentError Interval(NaN, Inf)
        @test_throws ArgumentError Interval(-Inf, NaN)
        # @test_throws ArgumentError Interval(Inf, -Inf)  # Would result in a NaN span

        @test_throws ArgumentError Interval{Float64, Open, Unbounded}(NaN, nothing)
        @test_throws ArgumentError Interval{Float64, Unbounded, Closed}(nothing, NaN)
    end

    @testset "hash" begin
        # Need a complicated enough element type for this test to ever fail
        zdt = now(tz"Europe/London")
        a = Interval(zdt, zdt)
        b = deepcopy(a)
        @test hash(a) == hash(b)
    end

    @testset "conversion" begin
        @test_throws DomainError convert(Int, Interval{Open, Open}(10, 10))
        @test_throws DomainError convert(Int, Interval{Open, Closed}(10, 10))
        @test_throws DomainError convert(Int, Interval{Closed, Open}(10, 10))
        @test convert(Int, Interval{Closed, Closed}(10, 10)) == 10
        @test_throws DomainError convert(Int, Interval{Closed, Closed}(10, 11))

        for T in (Date, DateTime)
            dt = T(2013, 2, 13)
            @test_throws DomainError convert(T, Interval{Open, Open}(dt, dt))
            @test_throws DomainError convert(T, Interval{Open, Closed}(dt, dt))
            @test_throws DomainError convert(T, Interval{Closed, Open}(dt, dt))
            @test convert(T, Interval{Closed, Closed}(dt, dt)) == dt
            @test_throws DomainError convert(T, Interval{Closed, Closed}(dt, dt + Day(1)))
        end
    end

    @testset "eltype" begin
        @test eltype(Interval(1,2)) == Int
        @test eltype(Interval{Float64}(1,2)) == Float64
    end

    @testset "accessors" begin
        for (a, b, _) in test_values
            for (L, R) in BOUND_PERMUTATIONS
                interval = Interval{L, R}(a, b)

                @test first(interval) == a
                @test last(interval) == b
                @test span(interval) == b - a
                @test isclosed(interval) == (L === Closed && R === Closed)
                @test isopen(interval) == (L === Open && R === Open)
            end
        end

        # DST transition
        firstpoint = ZonedDateTime(2018, 3, 11, 1, tz"America/Winnipeg")
        endpoint = ZonedDateTime(2018, 3, 11, 3, tz"America/Winnipeg")
        interval = Interval(firstpoint, endpoint)
        @test span(interval) == Hour(1)

        firstpoint = ZonedDateTime(2018, 11, 4, 0, tz"America/Winnipeg")
        endpoint = ZonedDateTime(2018, 11, 4, 2, tz"America/Winnipeg")
        interval = Interval(firstpoint, endpoint)
        @test span(interval) == Hour(3)
    end

    @testset "display" begin
        interval = Interval{Open, Open}(1, 2)
        @test string(interval) == "(1 .. 2)"
        @test sprint(show, interval, context=:compact=>true) == string(interval)
        @test sprint(show, interval) == "Interval{$Int,Open,Open}(1, 2)"

        interval = Interval{Open, Closed}('a', 'b')
        @test string(interval) == "(a .. b]"
        @test sprint(show, interval, context=:compact=>true) == string(interval)
        @test sprint(show, interval) == "Interval{Char,Open,Closed}('a', 'b')"

        interval = Interval{Closed, Open}(Date(2012), Date(2013))
        shown = string(
            "Interval{Date,Closed,Open}(",
            sprint(show, Date(2012, 1, 1)),
            ", ",
            sprint(show, Date(2013, 1, 1)),
            ")",
        )

        @test string(interval) == "[2012-01-01 .. 2013-01-01)"
        @test sprint(show, interval, context=:compact=>true) == string(interval)
        @test sprint(show, interval) == shown

        interval = Interval{Closed, Closed}("a", "b")
        @test string(interval) == "[a .. b]"
        @test sprint(show, interval, context=:compact=>true) == string(interval)
        @test sprint(show, interval) ==
            "Interval{String,Closed,Closed}(\"a\", \"b\")"
    end

    @testset "equality" begin
        for (a, b, unit) in test_values
            for (L, R) in BOUND_PERMUTATIONS
                interval = Interval{L, R}(a, b)
                cp = copy(interval)
                lesser_val = Interval{L, R}(a - unit, b - unit)
                greater_val = Interval{L, R}(a + unit, b + unit)

                L′ = L === Closed ? Open : Closed
                R′ = R === Closed ? Open : Closed
                diff_inc = Interval{L′, R′}(a, b)

                @test interval == cp
                @test isequal(interval, cp)
                @test hash(interval) == hash(cp)

                @test interval != diff_inc
                @test !isequal(interval, diff_inc)
                @test hash(interval) != hash(diff_inc)

                if !isinf(a) || !isinf(b)
                    @test interval != lesser_val
                    @test !isequal(interval, lesser_val)
                    @test hash(interval) != hash(lesser_val)
                else
                    @test interval == lesser_val
                    @test isequal(interval, lesser_val)
                    @test hash(interval) == hash(lesser_val)
                end

                @test !isless(interval, cp)
                @test !(interval < cp)
                @test !(interval ≪ cp)
                @test !(interval > cp)
                @test !(interval ≫ cp)

                @test isless(interval, greater_val) || isinf(a)
                @test interval < greater_val || isinf(a)
                @test !(interval ≪ greater_val)     # Still overlap, so not disjoint
                @test !(interval > greater_val)
                @test !(interval ≫ greater_val)

                @test !isless(greater_val, interval)
                @test !(greater_val < interval)
                @test !(greater_val ≪ interval)     # Still overlap, so not disjoint
                @test greater_val > interval || isinf(a)
                @test !(greater_val ≫ interval)     # Still overlap, so not disjoint

                @test isless(lesser_val, interval) || isinf(a)
                @test lesser_val < interval || isinf(a)
                @test !(lesser_val ≪ interval)
                @test !(lesser_val > interval)
                @test !(lesser_val ≫ interval)

                @test !isless(interval, lesser_val)
                @test !(interval < lesser_val)
                @test !(interval ≪ lesser_val)
                @test interval > lesser_val || isinf(a)
                @test !(interval ≫ lesser_val)      # Still overlap, so not disjoint
            end
        end

        @test Interval(2010, 2011) ≪ Interval(2012, 2013)
        @test !(Interval(2012, 2013) ≪ Interval(2010, 2011))

        @test Interval(Date(2010), Date(2011)) ≪ Interval(Date(2012), Date(2013))
        @test !(Interval(Date(2012), Date(2013)) ≪ Interval(Date(2010), Date(2011)))

        @test !(Interval(0, 10) ≪ Interval(10, 20))
        @test !(Interval(10, 20) ≪ Interval(0, 10))

        @test Interval{Closed, Open}(0, 10) ≪
            Interval{Open, Closed}(10, 20)
        @test !(
            Interval{Closed, Open}(10, 20) ≪
            Interval{Open, Closed}(0, 10)
        )

        # Comparisons between Interval{T} and T
        @test isless(5, Interval(10, 20))
        @test 5 < Interval(10, 20)
        @test 5 ≪ Interval(10, 20)
        @test !(5 > Interval(10, 20))
        @test !(5 ≫ Interval(10, 20))

        @test isless(10, Interval{Open, Open}(10, 20))
        @test 10 < Interval{Open, Open}(10, 20)
        @test 10 ≪ Interval{Open, Open}(10, 20)
        @test !(10 > Interval{Open, Open}(10, 20))
        @test !(10 ≫ Interval{Open, Open}(10, 20))

        @test !isless(10, Interval(10, 20))
        @test !(10 < Interval(10, 20))
        @test !(10 ≪ Interval(10, 20))
        @test !(10 > Interval(10, 20))
        @test !(10 ≫ Interval(10, 20))

        @test !isless(15, Interval(10, 20))
        @test !(15 < Interval(10, 20))
        @test !(15 ≪ Interval(10, 20))
        @test 15 > Interval(10, 20)
        @test !(15 ≫ Interval(10, 20))

        @test !isless(20, Interval(10, 20))
        @test !(20 < Interval(10, 20))
        @test !(20 ≪ Interval(10, 20))
        @test 20 > Interval(10, 20)
        @test !(20 ≫ Interval(10, 20))

        @test !isless(20, Interval{Open, Open}(10, 20))
        @test !(20 < Interval{Open, Open}(10, 20))
        @test !(20 ≪ Interval{Open, Open}(10, 20))
        @test 20 > Interval{Open, Open}(10, 20)
        @test 20 ≫ Interval{Open, Open}(10, 20)

        @test !isless(25, Interval(10, 20))
        @test !(25 < Interval(10, 20))
        @test !(25 ≪ Interval(10, 20))
        @test 25 > Interval(10, 20)
        @test 25 ≫ Interval(10, 20)

        @test !isless(Interval(10, 20), 5)
        @test !(Interval(10, 20) < 5)
        @test !isless(Interval{Open, Open}(10, 20), 10)
        @test !(Interval{Open, Open}(10, 20) < 10)
        @test !isless(Interval(10, 20), 10)
        @test !(Interval(10, 20) < 10)
        @test !(Interval(10, 20) ≪ 10)
        @test isless(Interval(10, 20), 15)
        @test Interval(10, 20) < 15
        @test !(Interval(10, 20) ≪ 15)
        @test isless(Interval(10, 20), 20)
        @test Interval(10, 20) < 20
        @test !(Interval(10, 20) ≪ 20)
        @test isless(Interval{Open, Open}(10, 20), 20)
        @test Interval{Open, Open}(10, 20) < 20
        @test isless(Interval(10, 20), 25)
        @test Interval(10, 20) < 25

        for lt in (isless, <)
            @test lt(Date(2013), Interval(Date(2014), Date(2016)))
            @test lt(Date(2014), Interval{Open, Open}(Date(2014), Date(2016)))
            @test !lt(Date(2014), Interval(Date(2014), Date(2016)))
            @test !lt(Date(2014), Interval(Date(2014), Date(2016)))
            @test !lt(Date(2015), Interval(Date(2014), Date(2016)))
            @test !lt(Date(2016), Interval(Date(2014), Date(2016)))
            @test !lt(Date(2016), Interval{Open, Open}(Date(2014), Date(2016)))
            @test !lt(Date(2017), Interval(Date(2014), Date(2016)))
        end

        @test !isless(Interval(Date(2014), Date(2016)), Date(2013))
        @test !(Interval(Date(2014), Date(2016)) < Date(2013))
        @test !isless(Interval{Open, Open}(Date(2014), Date(2016)), Date(2014))
        @test !(Interval{Open, Open}(Date(2014), Date(2016)) < Date(2014))
        @test !isless(Interval(Date(2014), Date(2016)), Date(2014))
        @test !(Interval(Date(2014), Date(2016)) < Date(2014))
        @test !(Interval(Date(2014), Date(2016)) ≪ Date(2014))
        @test isless(Interval(Date(2014), Date(2016)), Date(2015))
        @test Interval(Date(2014), Date(2016)) < Date(2015)
        @test !(Interval(Date(2014), Date(2016)) ≪ Date(2015))
        @test isless(Interval(Date(2014), Date(2016)), Date(2016))
        @test Interval(Date(2014), Date(2016)) < Date(2016)
        @test !(Interval(Date(2014), Date(2016)) ≪ Date(2016))
        @test isless(Interval{Open, Open}(Date(2014), Date(2016)), Date(2016))
        @test Interval{Open, Open}(Date(2014), Date(2016)) < Date(2016)
        @test Interval{Open, Open}(Date(2014), Date(2016)) ≪ Date(2016)
        @test isless(Interval(Date(2014), Date(2016)), Date(2017))
        @test Interval(Date(2014), Date(2016)) < Date(2017)
    end

    @testset "broadcasting" begin
        # Validate that an Interval is treated as a scalar during broadcasting
        interval = Interval(DateTime(2016, 8, 11, 17), DateTime(2016, 8, 11, 18))
        @test size(interval .== interval) == ()
    end

    @testset "sort" begin
        i1 = 1 .. 10
        i2 = Interval{Open, Open}(1, 10)
        i3 = 2 .. 11
        i4 = -Inf .. Inf

        @test sort([i1, i2, i3, i4]) == [i4, i1, i2, i3]
        @test sort([i1, i2, i3, i4]; rev=true) == [i3, i2, i1, i4]
    end

    @testset "arithmetic" begin
        for (a, b, unit) in test_values
            for (L, R) in BOUND_PERMUTATIONS
                interval = Interval{L, R}(a, b)
                @test interval + unit == Interval{L, R}(a + unit, b + unit)
                @test unit + interval == Interval{L, R}(a + unit, b + unit)
                @test interval - unit == Interval{L, R}(a - unit, b - unit)

                if a isa Number && b isa Number
                    @test -interval == Interval{R, L}(-b, -a)
                    @test unit - interval == Interval{R, L}(unit - b, unit - a)
                else
                    @test_throws MethodError -interval
                    @test_throws MethodError unit - interval
                end
            end

            @test_throws MethodError Interval(a, b) + Interval(a, b)
            @test_throws MethodError Interval(a, b) - Interval(a, b)
        end

        # DST transition
        firstpoint = ZonedDateTime(2018, 3, 11, 1, tz"America/Winnipeg")
        endpoint = ZonedDateTime(2018, 3, 11, 3, tz"America/Winnipeg")
        interval = Interval(firstpoint, endpoint) + Hour(1)
        @test first(interval) == ZonedDateTime(2018, 3, 11, 3, tz"America/Winnipeg")
        @test last(interval) == ZonedDateTime(2018, 3, 11, 4, tz"America/Winnipeg")

        firstpoint = ZonedDateTime(2018, 11, 4, 0, tz"America/Winnipeg")
        endpoint = ZonedDateTime(2018, 11, 4, 2, tz"America/Winnipeg")
        interval = Interval(firstpoint, endpoint) + Hour(1)
        @test first(interval) == ZonedDateTime(2018, 11, 4, 1, tz"America/Winnipeg", 1)
        @test last(interval) == ZonedDateTime(2018, 11, 4, 3, tz"America/Winnipeg")
    end

    @testset "isempty" begin
        for T in [Int32, Int64, Float64, Date, DateTime, ZonedDateTime]
            @test isempty(Interval{T}())
        end

        @test !isempty(Interval{Open, Open}(0, 1))
        @test !isempty(Interval{Open, Closed}(0, 1))
        @test !isempty(Interval{Closed, Open}(0, 1))
        @test !isempty(Interval{Closed, Closed}(0, 1))

        @test isempty(Interval{Open, Open}(0, 0))
        @test isempty(Interval{Open, Closed}(0, 0))
        @test isempty(Interval{Closed, Open}(0, 0))
        @test !isempty(Interval{Closed, Closed}(0, 0))

        # DST transition
        @test !isempty(
            Interval{Open,Open}(
                ZonedDateTime(2018, 11, 4, 1, tz"America/Winnipeg", 1),
                ZonedDateTime(2018, 11, 4, 1, tz"America/Winnipeg", 2),
            )
        )
    end

    @testset "in" begin
        for (a, b, unit) in test_values
            interval = Interval(a, b)
            @test  in(a, interval)
            @test  in(a + unit, interval)
            @test !in(a - unit, interval) || isinf(a)
            @test  in(b, interval)
            @test  in(b - unit, interval)
            @test !in(b + unit, interval) || isinf(b)

            interval = Interval{Closed, Open}(a, b)
            @test  in(a, interval)
            @test  in(a + unit, interval)
            @test !in(a - unit, interval) || isinf(a)
            @test !in(b, interval)
            @test  in(b - unit, interval) || isinf(b)
            @test !in(b + unit, interval)

            interval = Interval{Open, Closed}(a, b)
            @test !in(a, interval)
            @test  in(a + unit, interval) || isinf(a)
            @test !in(a - unit, interval)
            @test  in(b, interval)
            @test  in(b - unit, interval)
            @test !in(b + unit, interval) || isinf(b)

            interval = Interval{Open, Open}(a, b)
            @test !in(a, interval)
            @test  in(a + unit, interval) || isinf(a)
            @test !in(a - unit, interval) || isinf(a)
            @test !in(b, interval)
            @test  in(b - unit, interval) || isinf(b)
            @test !in(b + unit, interval) || isinf(b)

            @test_throws ArgumentError (in(Interval(a, b), Interval(a, b)))
        end
    end

    @testset "issubset" begin
        @test 0..10 ⊆ 0..10
        @test 0..10 ⊇ 0..10
        @test Interval{Open, Open}(0, 10) ⊆ 0..10
        @test Interval{Open, Open}(0, 10) ⊉ 0..10
        @test 0..10 ⊈ Interval{Open, Open}(0, 10)
        @test 0..10 ⊇ Interval{Open, Open}(0, 10)
        @test 1..9 ⊆ 0..10
        @test 1..9 ⊉ 0..10
        @test 0..10 ⊈ 1..9
        @test 0..10 ⊇ 1..9
        @test 1..11 ⊈ 0..10
        @test 1..11 ⊉ 0..10
        @test -1..9 ⊈ 0..10
        @test -1..9 ⊉ 0..10
        @test 20..30 ⊈ 0..10
        @test 20..30 ⊉ 0..10
    end

    @testset "intersect" begin
        @testset "overlapping" begin
            a = Interval{Closed, Closed}(-10, 5)
            b = Interval{Closed, Closed}(-2, 10)
            @test intersect(a, b) == Interval{Closed, Closed}(-2, 5)
            @test intersect(b, a) == intersect(a, b)

            a = Interval{Closed, Open}(-10, 5)
            b = Interval{Closed, Closed}(-2, 10)
            @test intersect(a, b) == Interval{Closed, Open}(-2, 5)
            @test intersect(b, a) == intersect(a, b)

            a = Interval{Closed, Closed}(-10, 5)
            b = Interval{Open, Closed}(-2, 10)
            @test intersect(a, b) == Interval{Open, Closed}(-2, 5)
            @test intersect(b, a) == intersect(a, b)

            a = Interval{Closed, Open}(-10, 5)
            b = Interval{Open, Closed}(-2, 10)
            @test intersect(a, b) == Interval{Open, Open}(-2, 5)
            @test intersect(b, a) == intersect(a, b)
        end

        @testset "adjacent" begin
            a = Interval{Closed, Closed}(-10, 0)
            b = Interval{Closed, Closed}(0, 10)
            @test intersect(a, b) == Interval{Closed, Closed}(0, 0)
            @test intersect(b, a) == intersect(a, b)

            a = Interval{Closed, Open}(-10, 0)
            b = Interval{Closed, Closed}(0, 10)
            @test isempty(intersect(a, b))
            @test isempty(intersect(b, a))

            a = Interval{Closed, Closed}(-10, 0)
            b = Interval{Open, Closed}(0, 10)
            @test isempty(intersect(a, b))
            @test isempty(intersect(b, a))

            a = Interval{Closed, Open}(-10, 0)
            b = Interval{Open, Closed}(0, 10)
            @test isempty(intersect(a, b))
            @test isempty(intersect(b, a))
        end

        @testset "identical" begin
            for (L, R) in BOUND_PERMUTATIONS
                x = Interval{L, R}(1, 10)
                @test intersect(x, x) == x
            end

            x = Interval{Open, Open}(0, 0)
            @test intersect(x, x) == x
            @test isempty(intersect(x, x))

            # But what if their inclusivities are different?
            expected = Interval{Open, Open}(1, 10)
            @test intersect(
                Interval{Closed, Closed}(1, 10),
                Interval{Open, Open}(1, 10),
            ) == expected
            @test intersect(
                Interval{Closed, Open}(1, 10),
                Interval{Open, Closed}(1, 10),
            ) == expected
        end

        @testset "disjoint" begin
            for (L, R) in BOUND_PERMUTATIONS
                a = Interval{L, R}(-100, -1)
                b = Interval{L, R}(1, 100)
                @test isempty(intersect(a, b))
                @test isempty(intersect(b, a))
            end
        end
    end

    @testset "astimezone" begin
        zdt1 = ZonedDateTime(2013, 2, 13, 0, 30, tz"America/Winnipeg")
        zdt2 = ZonedDateTime(2016, 8, 11, 21, tz"America/Winnipeg")

        for (L, R) in BOUND_PERMUTATIONS
            for tz in (tz"America/Winnipeg", tz"America/Regina", tz"UTC")
                @test isequal(
                    astimezone(Interval{L, R}(zdt1, zdt2), tz),
                    Interval{L, R}(astimezone(zdt1, tz), astimezone(zdt2, tz)),
                )
            end
        end
    end

    @testset "timezone" begin
        @testset "basic" begin
            zdt1 = ZonedDateTime(2013, 2, 13, 0, 30, tz"America/Winnipeg")
            zdt2 = ZonedDateTime(2016, 8, 11, 21, tz"America/Winnipeg")
            @test timezone(Interval(zdt1, zdt2)) == tz"America/Winnipeg"
        end

        @testset "multiple timezones" begin
            zdt1 = ZonedDateTime(2013, 2, 13, 0, 30, tz"America/Winnipeg")
            zdt2 = ZonedDateTime(2016, 8, 11, 21, tz"Europe/London")
            @test_throws ArgumentError timezone(Interval(zdt1, zdt2))
        end
    end

    @testset "merge" begin
        a = Interval(-100, -1)
        b = Interval(-3, 10)

        @test merge(a, b) == Interval(-100, 10)
        @test merge(b, a) == Interval(-100, 10)

        b = Interval(1, 10)
        @test_throws ArgumentError merge(a, b)

        a = Interval{Open, Open}(-100, -1)
        b = Interval{Closed, Closed}(-2, 10)
        @test merge(a, b) == Interval{Open, Closed}(-100, 10)

        a = Interval{Closed, Open}(-100, -1)
        b = Interval{Open, Open}(-2, 10)
        @test merge(a, b) == Interval{Closed, Open}(-100, 10)
    end

    @testset "union" begin
        intervals = [
            Interval{Open, Open}(-100, -1),
            Interval{Open, Open}(-10, -1),
            Interval{Open, Open}(10, 15),
            Interval{Open, Open}(13, 20),
        ]
        expected = [
            Interval{Open, Open}(-100, -1),
            Interval{Open, Open}(10, 20),
        ]
        @test union(intervals) == expected

        # Ordering
        intervals = [
            Interval{Open, Open}(-100, -1),
            Interval{Open, Open}(10, 15),
            Interval{Open, Open}(-10, -1),
            Interval{Open, Open}(13, 20),
        ]
        @test union(intervals) == expected
        @test intervals == [
            Interval{Open, Open}(-100, -1),
            Interval{Open, Open}(10, 15),
            Interval{Open, Open}(-10, -1),
            Interval{Open, Open}(13, 20),
        ]
        @test union!(intervals) == expected
        @test intervals == expected

        # Mixing bounds
        intervals = [
            Interval{Open, Open}(-100, -1),
            Interval{Closed, Closed}(-10, -1)
        ]
        @test union(intervals) == [Interval{Open, Closed}(-100, -1)]
    end

    @testset "legacy deserialization" begin
        # Serialized string generated on Intervals@1.2 with:
        # `julia --project -E 'using Serialization, Intervals; sprint(serialize, Interval(1, 2, true, false))'`.
        buffer = IOBuffer(
            SERIALIZED_HEADER *
            "\x004\x10\x01\bInterval\x1f\v՞\x84\xec\xf7-`\x87\xbbS\xe1Á\x88A\xd8\x01\t" *
            "IntervalsD\x01\0\0\0\0\b\xe0\xe14\x10\x01\vInclusivity\x1f\v՞\x84\xec\xf7" *
            "-`\x87\xbbS\xe1Á\x88A\xd8,\x02\0DML"
        )

        interval = deserialize(buffer)
        @test interval isa Interval
        @test interval == Interval{Closed,Open}(1, 2)
    end

    @testset "parse" begin
        @testset "double-dot" begin
            @test parse(Interval{Int}, "[1..2]") == Interval{Closed,Closed}(1, 2)
            @test parse(Interval{Int}, "(1..2]") == Interval{Open,Closed}(1, 2)
            @test parse(Interval{Int}, "[1..2)") == Interval{Closed,Open}(1, 2)
            @test parse(Interval{Int}, "(1..2)") == Interval{Open,Open}(1, 2)
        end

        @testset "comma" begin
            @test parse(Interval{Int}, "[1,2]") == Interval{Closed,Closed}(1, 2)
            @test parse(Interval{Int}, "(1,2]") == Interval{Open,Closed}(1, 2)
            @test parse(Interval{Int}, "[1,2)") == Interval{Closed,Open}(1, 2)
            @test parse(Interval{Int}, "(1,2)") == Interval{Open,Open}(1, 2)
        end

        @testset "entire string" begin
            @test_throws ArgumentError parse(Interval{Int}, "a[1,2]")
            @test_throws ArgumentError parse(Interval{Int}, "[1,2]b")
        end

        @testset "unbounded" begin
            @test parse(Interval{Nothing}, "[,]") == Interval{Unbounded,Unbounded}(nothing, nothing)
            @test parse(Interval{Nothing}, "(,]") == Interval{Unbounded,Unbounded}(nothing, nothing)
            @test parse(Interval{Nothing}, "[,)") == Interval{Unbounded,Unbounded}(nothing, nothing)
            @test parse(Interval{Nothing}, "(,)") == Interval{Unbounded,Unbounded}(nothing, nothing)
        end

        @testset "space" begin
            @test parse(Interval{Int}, "[1 .. 2)") == Interval{Closed,Open}(1, 2)
            @test parse(Interval{Int}, "(1 .. )") == Interval{Open,Unbounded}(1, nothing)
            @test parse(Interval{Int}, "( .. 2)") == Interval{Unbounded,Open}(nothing, 2)
            @test parse(Interval{Int}, "( .. )") == Interval{Unbounded,Unbounded}(nothing, nothing)

            # TODO: Should probably not be allowed
            @test parse(Interval{Int}, "[ 1..2]") == 1 .. 2
            @test parse(Interval{Int}, "[1..2 ]") == 1 .. 2
            @test parse(Interval{Int}, "[1  ..2]") == 1 .. 2
            @test parse(Interval{Int}, "[1..  2]") == 1 .. 2

            @test parse(Interval{Int}, "[1, 2)") == Interval{Closed,Open}(1, 2)
            @test parse(Interval{Int}, "(1, )") == Interval{Open,Unbounded}(1, nothing)
            @test parse(Interval{Int}, "(, 2)") == Interval{Unbounded,Open}(nothing, 2)
            @test parse(Interval{Int}, "(, )") == Interval{Unbounded,Unbounded}(nothing, nothing)

            # TODO: Should probably not be allowed
            @test parse(Interval{Int}, "[ 1,2]") == 1 .. 2
            @test parse(Interval{Int}, "[1,2 ]") == 1 .. 2
            @test parse(Interval{Int}, "[1  ,2]") == 1 .. 2
            @test parse(Interval{Int}, "[1,  2]") == 1 .. 2
            @test parse(Interval{Int}, "[1 ,2]") == 1 .. 2
            @test parse(Interval{Int}, "[1 , 2]") == 1 .. 2
        end

        @testset "custom parser" begin
            parser = (T, str) -> parse(T, str, dateformat"yyyy/mm/dd")
            @test_throws ArgumentError parse(Interval{Date}, "[2000/1/2,2001/2/3]")
            @test parse(Interval{Date}, "[2000/1/2,2001/2/3]", element_parser=parser) ==
                Date(2000, 1, 2) .. Date(2001, 2, 3)
        end

        @testset "quoting" begin
            parser = (T, str) -> str
            @test_throws ArgumentError parse(Interval{String}, "[a,b,c,d]", element_parser=parser)
            @test parse(Interval{String}, "[\"a,b\",\"c,d\"]", element_parser=parser) ==
                Interval("a,b", "c,d")

            @test_throws ArgumentError parse(Interval{String}, "[a..b..c..d]", element_parser=parser)
            @test parse(Interval{String}, "[\"a..b\"..\"c..d\"]", element_parser=parser) ==
                Interval("a..b", "c..d")

            @test_throws ArgumentError parse(Interval{Interval{Int}}, "[[1..2]..[3..4]]")
            @test parse(Interval{Interval{Int}}, "[\"[1..2]\"..\"[3..4]\"]") ==
                (1 .. 2) .. (3 .. 4)
        end

        # Ensure format used by LibPQ can be successfully parsed
        @testset "libpq" begin
            parse(Interval{Int}, "[\"1\",\"\")") == Interval(1, nothing)
        end

        @testset "test values" begin
            function parser(::Type{Char}, str)
                @assert length(str) == 1
                return first(str)
            end
            parser(::Type{T}, str) where T = parse(T, str)

            for (left, right, _) in test_values, (lb, rb) in product(('[', '('), (']', ')'))
                T = promote_type(typeof(left), typeof(right))

                str = "$lb$left .. $right$rb"
                L = lb == '[' ? Closed : Open
                R = rb == ']' ? Closed : Open

                result = parse(Interval{T}, str, element_parser=parser)
                @test result == Interval{T,L,R}(left, right)
            end
        end
    end
end


text:
#load pendulum and controllers
using HeavyChain
include("feedforward.jl")
include("feedback2.jl")

#define parameters
enable_anim = false
enable_sim = true
chain = create_chain()
dt = 1/1000
all_t = collect(0:dt:15)
(F_ff, xL_target, x0_target, v0_target, phi0_target, phi0_dot_target) = chain_feedforward(all_t)

#plot signals
using Plots
pyplot()
fig = plot(layout = (3, 1))
plot!(fig[1], all_t, xL_target, lab = "xL")
plot!(fig[1], all_t, x0_target, l = :dot, lab = "x0")
plot!(fig[2], all_t, phi0_target, lab = "phi")
plot!(fig[2], all_t, phi0_dot_target, l = :dot, lab = "dphidt")
plot!(fig[3], all_t, F_ff, lab = "F")
gui()

#simulate
u_in = 0.0
if enable_sim
  println("Starting simulation")
  chain = create_chain()
  all_xL = Array{Float64}(length(xL_target))
  all_x0 = Array{Float64}(length(x0_target))
  @time for i = 1:length(all_t)
    if mod(i, 5)==1
      target = vcat(x0_target[i], v0_target[i], phi0_target[i], phi0_dot_target[i])
      u_in = chain_feedback(chain, target) #+F_ff[i]
    end
    all_x0[i] = chain.q[1]
    all_xL[i] = getendpoint(chain)
    simulate!(chain, u_in, dt)
  end
  fig = plot(layout = (2, 1))
  plot!(fig[1], all_t, x0_target, l=:dot, lab = "x0_target")
  plot!(fig[1], all_t, all_x0, lab = "x0", c=:black)

  plot!(fig[2], all_t, xL_target, l=:dot, lab = "xL_target")
  plot!(fig[2], all_t, all_xL, lab = "xL", c=:black)
  savefig("plot.pdf")
end

#animate
if enable_anim
  println("Starting animation")
  xmin = -0.2
  xmax = 0.7
  chain = create_chain()
  anim = Animation()
  all_u = [NaN for i = 1:length(all_t)]
  iter=1
  u_in = 0.0
  for t = all_t
    #take frame
    if mod(t, 0.04)<dt*0.5 || mod(t, 0.04)>(0.04-dt*0.5)
      println("Frame at t = $(t)")
      l = Plots.@layout [a{0.7h}; b]
      fig = plot(layout = l, size = (1280, 720))
      heavychain_plot!(fig[1], chain, xmin, xmax, t)
      plot!(fig[2], all_t, all_u, lab = "u")
      frame(anim)
    end

    #simulate one step
    if mod(iter, 5)==1
      target = vcat(x0_target[iter], v0_target[iter], phi0_target[iter], phi0_dot_target[iter])
      u_in = F_ff[iter]#+chain_feedback(chain, target)
    end
    simulate!(chain, u_in, dt, massmat, fvec)
    all_u[iter] = u_in
    iter+=1
  end
  gif(anim, "animation.mp4", fps = round(Int, 1/0.04))
end

max_stars_repo_name: NikonPic/REINFORCEMENT-JULIA

max_issues_repo_name: NikonPic/REINFORCEMENT-JULIA

max_forks_repo_name: NikonPic/REINFORCEMENT-JULIA


text:
@userplot DirectivityMap

@recipe function f(h::DirectivityMap)
    if length(h.args) != 1 || !(typeof(h.args[1]) <: AngularMeasurements)
        error("Directivity Map should be given single vector. Got: $(typeof(h.args))")
    end
    ds = h.args[1]

    size --> (1000, 500)
    xlims --> (20, 20000)
    ylims --> (-180,180)

    xscale --> :log10
    xticks --> audiofreqlogticks()
    xformatter --> audiofreqlogtickformatter
    yticks --> [-180, -135, -90, -45, 0, 45, 90, 135, 180]

    x = domain(ds)
    y = copy(ds.angles)
    Z = amp2db.(abs.(parent(ds))).data

    @series begin
        seriestype := :contour
        fill := true
        x, y, Z'
    end

    @series begin
        seriestype := :hline
        seriescolor := :black
        seriesalpha := 0.3
        label := ""
        [-90, 0, 90]
    end
end

@userplot DirectivityPlot

@recipe function f(h::DirectivityPlot; db=true, minclip=0)
    if length(h.args) != 2 || !(typeof(h.args[1]) <: AngularMeasurements) || !(typeof(h.args[2]) <: AbstractVector)
        error("Directivity Plot should be given two vectors. Got: $(typeof(h.args))")
    end
    ds, freqs = h.args

    if :ylims ∈ keys(plotattributes)
        ylims := plotattributes[:ylims] .- minclip
    end

    yformatter := y -> begin
        yt = y + minclip
        yt == round(yt) ? round(Int64, yt) : yt
    end

    amplitudes = abs.(parent(ds))
    anglesrad = deg2rad.(angles(ds))
    for f in freqs
        freqamps = reshape(slice(amplitudes, f), :)
        if db
            freqamps = amp2db.(freqamps)
        end
        freqamps = max.(freqamps, minclip)
        freqamps .-= minclip
        @assert all(freqamps .>= 0)
        push!(anglesrad, anglesrad[1])
        push!(freqamps, freqamps[1])
        @series begin
            projection := :polar
            label := "$f"
            anglesrad, freqamps
        end
    end
end

@userplot MeanDirectivityPlot

@recipe function f(h::MeanDirectivityPlot; db=true, minclip=0)
    if length(h.args) != 2 || !(typeof(h.args[1]) <: AngularMeasurements) || !(typeof(h.args[2]) <: AbstractVector)
        error("Directivity Plot should be given two vectors. Got: $(typeof(h.args))")
    end
    ds, angles = h.args

    # mean non-weighted over all angles, and various front angle ranges
    @series begin
        label :="all"
        mean(ds)
    end
    for α in Float64.(angles)
        @series begin
            label :="≤ $(α)"
            mean(ds[-α, α])
        end
    end
end


text:
export supported_platforms, expand_gcc_versions
using BinaryProvider: compiler_abi

## The build environment is broken up into multiple parts:
#
#  * RootFS - Host-only tools such as `bash`, `make`, `cmake`, etc....
#  * BaseCompilerShard - Target-specific binutils, libc, etc....
#  * GCC - Target-and-ABI-specific GCC compilers
#  * LLVM - Target-nonspecific clang compilers
#
# Given a `Platform`, we determine the set of shards to mount in to the
# sandbox for that `Platform`.  If there are multiple possible options,
# (e.g. the Platform sets no ABI requirement) the oldest compiler possible
# is used by default, for libstdc++ compatibility reasons.  (Even though we
# ship a very recent version of libstdc++ with Julia, we need to ensure that
# our binaries are as compatible as possible for custom builds)
#
# Each chunk of the build environment (referred to as a `shard`) is served
# as either a `.tar.gz` file or a `.squashfs` file.  While `.squashfs` files
# are desirable for multiple reasons (smaller download size, no need to unpack
# on the host filesystem taking up disk space) they currently require `sudo`
# privileges to mount on Linux machines, and as such cannot be used in the
# unprivileged user namespace setting, which is what we most often use.
# We therefore support downloading `.squashfs` files when a privileged
# usernamespace or qemu runnre is being used.
#
# Shards are downloaded to `<storage_dir>/downloads`, unpacked (in the case
# of `.tar.gz` files) to `<storage_dir>/mounts` or mounted to
# `<storage_dir>/mounts`.  We must take a little care when dealing with this
# mixture of unpacked and mounted shards (especially when switching Runner
# backends, as they will often cause the shard storage type to change!) but
# it's still desirable as it cuts down on the complexity of needing to change
# which paths are being mounted based on the archive type of the shard, etc...

# This is a type that encompasses a shard; it makes it easy to pass it around,
# get its download url, extraction url, mounting url, etc...
struct CompilerShard
    # Something like "RootFS", or "GCC"
    name::String

    # Something like v"7.1.0"
    version::VersionNumber

    # Things like Windows(:x86_64; gcc_version=:gcc7)
    target::Union{Nothing,Platform}

    # Right now, always `Linux(:x86_64)`
    host::Platform

    # :squashfs or :targz.  Possibly more in the future.
    archive_type::Symbol

    function CompilerShard(name, version, host, archive_type; target = nothing)
        # Ensure we have the right archive type
        if !(archive_type in (:squashfs, :targz))
            error("Invalid archive type '$(archive_type)'")
        end

        # Ensure the platforms have no ABI portion (that is only used
        # by higher-level things to choose e.g. which version of GCC
        # to use, but once we're at this level we only care about the
        # larger-scale things, not the ABI).
        host = abi_agnostic(host)
        if target != nothing
            target = abi_agnostic(target)
        end

        # Construct our shiny new CompilerShard object
        return new(name, version, target, host, archive_type)
    end
end

"""
    abi_agnostic(p::Platform)

Strip out the CompilerABI portion of a Platform, making it "ABI agnostic".
"""
function abi_agnostic(p::P) where {P <: Platform}
    return P(arch(p), libc(p), call_abi(p))
end

"""
    filename(cs::CompilerShard)

Return the filename of this shard.  Used by e.g. `url()` or `download_path()`.
"""
function filename(cs::CompilerShard)
    ext = Dict(:squashfs => "squashfs", :targz => "tar.gz")[cs.archive_type]
    return string(dir_name(cs), ".", ext)
end

"""
    url(cs::CompilerShard)

Return the URL from which this shard can be downloaded.
"""
function url(cs::CompilerShard)
    urlroot = "https://julialangmirror.s3.amazonaws.com/binarybuilder"
    return joinpath(urlroot, filename(cs))
end

"""
    hash(cs::CompilerShard)

Return the integrity hash for this compiler shard, for ensuring it has been
downloaded properly/has not been tampered with.
"""
function hash(cs::CompilerShard)
    global shard_hash_table
    try
        return shard_hash_table[cs]
    catch
        throw(ArgumentError("Compiler shard $(cs) is not found in our hash table!"))
    end
end

"""
    dir_name(cs::CompilerShard)

Return a "directory name" for a compiler shard; used by e.g. `extraction_path()`
or `mount_path()`, to create names like "Rootfs.v2018.08.27-x86_64-linux-gnu".
"""
function dir_name(cs::CompilerShard)
    target = ""
    if cs.target != nothing
        target = "-$(triplet(cs.target))"
    end
    return "$(cs.name)$(target).v$(cs.version).$(triplet(cs.host))"
end

"""
    map_target(cs::CompilerShard)

Return the location this compiler shard should be mounted at.  We basically
analyze the name and platform of this shard and return a path based on that.
"""
function map_target(cs::CompilerShard)
    if lowercase(cs.name) == "rootfs"
        return "/"
    elseif lowercase(cs.name) in ("gcc", "basecompilershard")
        return joinpath("/opt", triplet(cs.target), "$(cs.name)-$(cs.version)")
    elseif lowercase(cs.name) == "llvm"
        return joinpath("/opt", triplet(cs.host), "$(cs.name)-$(cs.version)")
    else
        error("Unknown mapping for shard named $(cs.name)")
    end
end

"""
    download_path(cs::CompilerShard)

Return the location this shard will be downloaded to.
"""
download_path(cs::CompilerShard) = storage_dir("downloads", filename(cs))
"""
    mount_path(cs::CompilerShard)

Return the location this shard will be mounted to.  For `.tar.gz` shards,
this is also the location it will be extracted to.
"""
mount_path(cs::CompilerShard) = storage_dir("mounts", dir_name(cs))

"""
    mount(cs::CompilerShard)

Mount a compiler shard, if possible.  Uses `run()` so will error out if
something goes awry.  Note that this function only does something when
using a `.squashfs` shard, with a UserNS or Docker runner, on Linux.
All other combinations of shard archive type, runner and platform result
in a no-op from this function.
"""
function mount(cs::CompilerShard; verbose::Bool = false)
    # Skip out if we're not Linux with a UserNSRunner trying to use a .squashfs
    if !Sys.islinux() || (preferred_runner() != UserNSRunner &&
                          preferred_runner() != DockerRunner) ||
                         cs.archive_type != :squashfs ||
                         is_mounted(cs)
        return
    end

    # Signal to the user what's going on, since this probably requires sudo.
    if verbose
        @info("Mounting $(download_path(cs)) to $(mount_path(cs))")
    end

    # If the destination directory does not already exist, create it
    mkpath(mount_path(cs))

    # Run the mountaining
    run(`$(sudo_cmd()) mount $(download_path(cs)) $(mount_path(cs)) -o ro,loop`)
end

"""
    is_mounted(cs::CompilerShard)

Return true if the given shard is mounted.  Uses `run()` so will error out if
something goes awry.  Note that if you ask if a `.tar.gz` shard is mounted,
this method will return true if the `.squashfs` version is mounted.  This is
actually desirable, as we use this to see if we should unmount the `.squashfs`
version before unpacking the `.tar.gz` version into the same place.
"""
function is_mounted(cs::CompilerShard)
    # Note that unlike `mount()`, we don't care about the current runner,
    # because it is possible that we're checking if something is mounted
    # after switching runners.
    if !Sys.islinux()
        return false
    end

    return success(`mountpoint $(mount_path(cs))`)
end

"""
    unmount(cs::CompilerShard)

Unmount a compiler shard, if possible.  Uses `run()` so will error out if
something goes awry.  Note that this function only does something when using a
`.squashfs` shard, on Linux.  All other combinations of shard archive type
and platform result in a no-op from this function.
"""
function unmount(cs::CompilerShard; verbose::Bool = false, fail_on_error::Bool = false)
    # Only try to unmount if it's mounted
    if is_mounted(cs)
        if verbose
            @info("Unmounting $(mount_path(cs))`")
        end
        try
            cmd = `$(sudo_cmd()) umount $(mount_path(cs))`
            run(pipeline(cmd, stdin=devnull, stdout=devnull, stderr=devnull))

            # Remove mountpoint directory
            rm(mount_path(cs); force=true, recursive=false)
        catch e
            # By default we don't error out if this unmounting fails
            if fail_on_error
                rethrow(e)
            end
        end
    end
end

function macos_sdk_already_installed()
    # We just check to see if there are any BaseCompilerShard downloads for
    # macOS in our downloads directory.  If so, say we have already installed it.
    files = filter(x -> occursin("BaseCompilerShard", x) || occursin("GCC", x), readdir(storage_dir("downloads")))
    return !isempty(filter(x -> occursin("-darwin", x), files))
end

"""
    prepare_shard(cs::CompilerShard; mount_squashfs = true, verbose = false)

Download and mount the given compiler shard.  If it is a `.tar.gz` shard, it
will be unpacked into the directory given by `mount_path(cs)`.  If it is a
`.squashfs` shard, it will be mounted into the directory given by
`mount_path(cs)` (unless `mount_squashfs` is set to `false`.  This is done by
the QEMU runner, for instance, as it prefers to read the `.squashfs` files
directly, so no need to try mounting things).

If it is a macOS shard, you must have accepted the Xcode license before it will
be downloaded or mounted.
"""
function prepare_shard(cs::CompilerShard; mount_squashfs::Bool = true, verbose::Bool = false)
    # Before doing anything with a MacOS shard, make sure the user knows that
    # they must accept the Xcode EULA.  This will be skipped if either the
    # environment variable BINARYBUILDER_AUTOMATIC_APPLE has been set to `true`
    # or if the SDK has been downloaded in the past.
    global automatic_apple
    if typeof(cs.target) <: MacOS && !automatic_apple && !macos_sdk_already_installed()
        if !isinteractive()
            msg = strip("""
            This is not an interactive Julia session, so we will not prompt you
            to download and install the macOS SDK.  Because you have not agreed
            to the Xcode license terms, we will not be able to build for MacOS.
            """)
            @warn(msg)
            error("macOS SDK not installable")
        else
            msg = strip("""
            Apple restricts distribution and usage of the macOS SDK, a necessary
            component to build software for macOS targets.  Please read the Apple
            and Xcode SDK agreement for more information on the restrictions and
            legal terms you agree to when using the SDK to build software for Apple
            operating systems: https://images.apple.com/legal/sla/docs/xcode.pdf.
            """)
            printstyled(msg, bold=true)
            println()
            while true
                print("Would you like to download and use the macOS SDK? [y/N]: ")
                answer = lowercase(strip(readline(stdin)))
                if answer == "y" || answer == "yes"
                    break
                elseif answer == "n" || answer == "no"
                    error("macOS SDK not installable")
                else
                    println("Unrecognized answer. Answer `y` or `n`.")
                end
            end
        end
    end

    # Unmount previously mounted `.squashfs` version of this file if it existed.
    # If we're switching to a `.tar.gz` this is desirable because we want to
    # unpack into that direcftory.  If we're updating a `.squashfs` file, this
    # is also desirable as we're about to
    unmount(cs; verbose=verbose)

    # For .tar.gz shards, we unpack as well
    if cs.archive_type == :targz
        # verify/redownload/reunpack the tarball, if necessary
        download_verify_unpack(
            url(cs),
            hash(cs),
            mount_path(cs);
            tarball_path = download_path(cs),
            verbose = verbose,
            force = true,
        )

        # Finally, mount this shard (if we need to)
        mount(cs; verbose=verbose)
    elseif cs.archive_type == :squashfs
        download_verify(
            url(cs),
            hash(cs),
            download_path(cs);
            verbose = verbose,
            force = true
        )

        rewrite_squashfs_uids(download_path(cs), getuid(); verbose=verbose)
        touch(string(download_path(cs), ".sha256"))

        # Finally, mount this shard (if we need to)
        if mount_squashfs
            mount(cs; verbose=verbose)
        end
    end
end

"""
    choose_shards(p::Platform; rootfs_build, bcs_build, GCC_builds,
                               LLVM_builds, archive_type)

This method chooses, given a `Platform`, which shards to download, extract and
mount, returning a list of `CompilerShard` objects.  At the moment, this always
consists of four shards, but that may not always be the case.
"""
function choose_shards(p::Platform;
            rootfs_build::VersionNumber=v"2018.11.11",
            bcs_build::VersionNumber=v"2018.11.11",
            GCC_builds::Vector{VersionNumber}=[v"8.1.0"],
            LLVM_build::VersionNumber=v"6.0.1-0",
            archive_type::Symbol = (use_squashfs ? :squashfs : :targz),
        )

    # If GCC version is not specificed by `p`, choose earliest possible.
    if compiler_abi(p).gcc_version == :gcc_any
        GCC_build = GCC_builds[1]
    else
        # Otherwise, match major versions with a delightfully convoluted line:
        GCC_build = GCC_builds[Dict(
            :gcc4 => 1,
            :gcc6 => 2,
            :gcc7 => 3,
            :gcc8 => 4)[compiler_abi(p).gcc_version]]
    end

    host_platform = Linux(:x86_64)
    shards = [
        # We always need our Rootfs for Linux(:x86_64)
        CompilerShard("Rootfs", rootfs_build, host_platform, archive_type),
        # BCS contains our binutils, libc, etc...
        CompilerShard("BaseCompilerShard", bcs_build, host_platform, archive_type; target=p),
        # GCC gets a particular version that was chosen above
        CompilerShard("GCC", GCC_build, host_platform, archive_type; target=p),
        # God bless LLVM; a single binary that targets all platforms!
        CompilerShard("LLVM", LLVM_build, host_platform, archive_type),
    ]

    # If we're not building for the host platform, then add host shard for things
    # like HOSTCC, HOSTCXX, etc...
    if !(typeof(p) <: typeof(host_platform)) || (arch(p) != arch(host_platform) || libc(p) != libc(host_platform))
        push!(shards, CompilerShard("BaseCompilerShard", bcs_build, host_platform, archive_type; target=host_platform))
        push!(shards, CompilerShard("GCC", GCC_build, host_platform, archive_type; target=host_platform))
    end
    return shards
end

"""
    supported_platforms(;exclude::Union{Vector{<:Platform},Function}=x->false)

Return the list of supported platforms as an array of `Platform`s.  These are the platforms we
officially support building for, if you see a mapping in `get_shard_hash()` that isn't
represented here, it's probably because that platform is still considered "in beta".

Platforms can be excluded from the list by specifying an array of platforms to `exclude` i.e.
`supported_platforms(exclude=[Windows(:i686),Windows(:x86_64)])`
or a function that returns true for exclusions i.e.
```
islin(x) = typeof(x) == Linux
supported_platforms(exclude=islin)
```
"""
function supported_platforms(;exclude::Union{Vector{<:Platform},Function}=x->false)
    exclude_platforms!(platforms, exclude::Function) = filter(!exclude, platforms)
    exclude_platforms!(platforms, exclude::Vector{<:Platform}) = filter!(!in(exclude), platforms)
    standard_platforms = [
        # glibc Linuces
        Linux(:i686),
        Linux(:x86_64),
        Linux(:aarch64),
        Linux(:armv7l),
        Linux(:powerpc64le),

        # musl Linuces
        Linux(:i686, :musl),
        Linux(:x86_64, :musl),
        Linux(:aarch64, :musl),
        Linux(:armv7l, :musl),

        # BSDs
        MacOS(:x86_64),
        FreeBSD(:x86_64),

        # Windows
        Windows(:i686),
        Windows(:x86_64),
    ]
    return exclude_platforms!(standard_platforms,exclude)
end

function replace_gcc_version(p::Platform, gcc_version::Symbol)
    new_cabi = CompilerABI(gcc_version, compiler_abi(p).cxx_abi)
    return typeof(p)(arch(p); libc=libc(p), call_abi=call_abi(p), compiler_abi=new_cabi)
end

"""
    expand_gcc_versions(p::Platform)

Given a `Platform`, returns an array of `Platforms` with a spread of identical
entries with the exception of the `gcc_version` member of the `CompilerABI`
struct within the `Platform`.  This is used to take, for example, a list of
supported platforms and expand them to include multiple GCC versions for
the purposes of ABI matching.  If the given `Platform` already specifies a
GCC version (as opposed to `:gcc_any`) only that `Platform` is returned.
"""
function expand_gcc_versions(p::Platform)
    # If this platform cannot be expanded, then exit out fast here.
    if compiler_abi(p).gcc_version != :gcc_any
        return [p]
    end

    # Otherwise, generate new versions!
    gcc_versions = [:gcc4, :gcc7, :gcc8]
    return replace_gcc_version.(Ref(p), gcc_versions)
end

function expand_gcc_versions(ps::Vector{P}) where {P <: Platform}
    expanded_ps = Platform[]
    for p in ps
        append!(expanded_ps, expand_gcc_versions(p))
    end
    return expanded_ps
end

"""
    download_all_shards(; verbose::Bool=false)

Helper function to download all (.tar.gz AND .squashfs) shards, so that no
matter what happens, you don't need an internet connection to build your
precious, precious binaries.
"""
function download_all_shards(; verbose::Bool = false)
    prepare_shard.(keys(shard_hash_table); mount_squashfs=false, verbose=verbose)
end

"""
    getuid()

Wrapper around libc's `getuid()` function
"""
function getuid()
    return ccall(:getuid, Cint, ())
end
"""
    getgid()

Wrapper around libc's `getgid()` function
"""
function getgid()
    return ccall(:getgid, Cint, ())
end

# Note: produce these values by #including squashfs_fs.h from linux in Cxx.jl
# and running the indicated command
const offsetof_id_table_start = 0x30    # offsetof(struct suqashfs_super_block, id_table_start)
const offsetof_no_ids = 0x1a            # offsetof(struct suqashfs_super_block, no_ids)

# From squashfs_fs.h
const SQUASHFS_COMPRESSED_BIT = UInt16(1) << 15
const SQUASHFS_MAGIC = 0x73717368

"""
    rewrite_squashfs_uids(path, new_uid)

In order for the sandbox to work well, we need to have the uids of the squashfs
images match the uid of the current unpriviledged user. Unfortunately there is
no mount-time option to do this for us. However, fortunately, squashfs is simple
enough that if the id table is uncompressed, we can just manually patch the uids
to be what we need. This functions performs this operation, by rewriting all
uids/gids to new_uid.
"""
function rewrite_squashfs_uids(path, new_uid; verbose::Bool = false)
    open(path, "r+") do file
       # Check magic
       if read(file, UInt32) != SQUASHFS_MAGIC
           error("`$path` is not a squashfs file")
       end
       # Check that the image contains only one id (which we will rewrite)
       seek(file, offsetof_no_ids)
       if read(file, UInt16) != 1
           error("`$path` uses more than one uid/gid")
       end
       # Find the index table
       seek(file, offsetof_id_table_start)
       offset = read(file, UInt64)
       seek(file, offset)
       # Find the correct metdata block
       index = read(file, UInt64)
       seek(file, index)
       # Read the metadata block
       size = read(file, UInt16)
       # Make sure it's uncompressed (yes, I know that flag is terribly
       # named - it indicates that the data is uncompressed)
       if ((size & SQUASHFS_COMPRESSED_BIT) == 0)
           error("Metadata block is compressed")
       end
       p = position(file)
       uid = read(file, UInt32)
       if uid == new_uid
           return
       end
       if verbose
           @info("Rewriting $(basename(path)) from UID $(uid) -> $(new_uid)")
       end
       seek(file, p)
       write(file, UInt32(new_uid))
    end
    return nothing
end

_sudo_cmd = nothing
function sudo_cmd()
    global _sudo_cmd

    # Use cached value if we've already run this
    if _sudo_cmd != nothing
        return _sudo_cmd
    end

    if getuid() == 0
        # If we're already root, don't use any kind of sudo program
        _sudo_cmd = ``
    elseif success(`sudo -V`)
        # If `sudo` is available, use that
        _sudo_cmd = `sudo`
    else
        # Fall back to `su` if all else fails
        _sudo_cmd = `su root -c`
    end
    return _sudo_cmd
end

"""
    shard_mappings(shards::Vector{CompilerShard})

Return the default mappings for a set of compiler shards
"""
function shard_mappings(shards::Vector{CompilerShard})
    mappings = Pair{String,String}[]
    for shard in shards
        # No mapping for the main rootfs shard
        if lowercase(shard.name) == "rootfs"
            continue
        end

        # For everything else, map it into its proper place
        push!(mappings, mount_path(shard) => map_target(shard))
    end

    # Reverse mapping order, because `sandbox` reads them backwards
    reverse!(mappings)
    return mappings
end


text:
using InformationInequalities
using Documenter
using Plots

DocMeta.setdocmeta!(InformationInequalities, :DocTestSetup, :(using InformationInequalities); recursive=true)

makedocs(;
    modules=[InformationInequalities],
    authors="Nivedita Rethnakar et al.",
    repo="https://github.com/nivupai/InformationInequalities.jl/blob/{commit}{path}#{line}",
    sitename="InformationInequalities.jl",
    format=Documenter.HTML(;
        prettyurls=get(ENV, "CI", "false") == "true",
        canonical="https://nivupai.github.io/InformationInequalities.jl",
        assets=String[],
        collapselevel=1,
    ),
    pages=[
        "Home" => "index.md",
        "Tutorials" => [
            "Canonical Decompositions" => "tutorials/canonical.md",
            "Entropic Space" => "tutorials/entropic2d.md"
        ],
        "Explanations" => [
            "Canonical Decomposition" => "explanations/decomposition.md",
            "oXitip: Machine Proof Checker" => "explanations/oxitip.md"
        ],
        "References" => "references.md",
        "Contributing" => "CONTRIBUTING.md"
    ],
)

deploydocs(;
    repo="github.com/nivupai/InformationInequalities.jl",
    devbranch="main",
    push_preview=true
)


text:
__precompile__()

module PkgName

export hessenberg, eigen
include("hessenberg.jl")
include("eigenval.jl")

end


text:
isna(x, nastrings) = x == "" || x in nastrings

const common_date_formats = Any[
    dateformat"yyyy-mm-dd", dateformat"yyyy/mm/dd",
    dateformat"mm-dd-yyyy", dateformat"mm/dd/yyyy",
    dateformat"dd-mm-yyyy", dateformat"dd/mm/yyyy",
    dateformat"dd u yyyy",  dateformat"e, dd u yyyy"
]

const common_datetime_formats = Any[
    dateformat"yyyy-mm-ddTHH:MM:SS",
    dateformat"yyyy-mm-dd HH:MM:SS",
    ISODateTimeFormat,
    dateformat"yyyy-mm-dd HH:MM:SS.s",
    RFC1123Format,
    dateformat"yyyy/mm/dd HH:MM:SS.s",
    dateformat"yyyymmdd HH:MM:SS.s"
]

const DEFAULT_QUOTES = ('"', ''')

function guessdateformat(str)

    dts = Any[Date => d for d in common_date_formats]
    dts = vcat(dts, Any[DateTime => d for d in common_datetime_formats])

    for (typ, df) in dts
        x, len = try
            tryparsenext_internal(typ, str, 1, lastindex(str), df)
        catch err
            continue
        end
        if !isnull(x)
            try
                typ(get(x)...)
                if len > lastindex(str)
                    return DateTimeToken(typ, df)
                end
            catch err; end
        end
    end
    return nothing
end

# force precompilation
guessdateformat("xyz")

function getquotechar(x)
    if (length(x) > 0 && x[1] in DEFAULT_QUOTES) && last(x) == x[1]
        return x[1]
    end
    return '\0'
end

function guesstoken(x, @nospecialize(prev_guess)=Unknown(), nastrings=NA_STRINGS)
    q = getquotechar(x)

    if isa(prev_guess, StringToken)
        # there is nothing wider than a string
        return prev_guess
    elseif q !== '\0'
        # remove quotes and detect inner token
        if isa(prev_guess, Quoted)
            prev_inner = prev_guess.inner
        else
            prev_inner = prev_guess
        end
        inner_token = guesstoken(strip(strip(x, q)), prev_inner, nastrings)
        return Quoted(inner_token)
    elseif isa(prev_guess, Quoted)
        # but this token is not quoted
        return Quoted(guesstoken(x, prev_guess.inner, nastrings))
    elseif isa(prev_guess, NAToken)
        # This column is nullable
        if isna(x, nastrings)
            # x is null too, return previous guess
            return prev_guess
        else
            tok = guesstoken(x, prev_guess.inner, nastrings)
            if isa(tok, StringToken)
                return tok # never wrap a string in NAToken
            elseif isa(tok, Quoted)
                # Always put the quoted wrapper on top
                return Quoted(NAToken(tok.inner))
            else
                return NAToken(tok, nastrings=nastrings)
            end
        end
    elseif isna(x, nastrings)
        return NAToken(prev_guess, nastrings=nastrings)
    else
        # x is neither quoted, nor null,
        # prev_guess is not a NAToken or a StringToken
        ispercent = strip(x)[end] == '%'
        if ispercent
            x = x[1:end-1]
        end
        if tryparse(Int, x) !== nothing || tryparse(Float64, x) !== nothing
            T = tryparse(Int, x) === nothing ? Float64 : Int

            if ispercent
                return Percentage()
            end

            if prev_guess == Unknown()
                return Numeric(T)
            elseif isa(prev_guess, Numeric)
                return Numeric(promote_type(T, fieldtype(prev_guess)))
            else
                # something like a date turned into a single number?
                return StringToken(StrRange)
            end
        else
            # fast-path
            if length(filter(isnumeric, x)) < 4
                return StringToken(StrRange)
            end

            maybedate = guessdateformat(x)
            if maybedate === nothing
                return StringToken(StrRange)
            else
                return maybedate
            end
        end
    end
end


text:
export add_harmonic!, add_Hopf!
import Symbolics.get_variables

"""
$(TYPEDSIGNATURES)
Add the harmonic `ω` to the harmonic ansatz used to expand the variable `var` in `diff_eom`.

## Example

# define the simple harmonic oscillator and specify that x(t) oscillates with frequency ω
```julia-repl
julia> @variables t, x(t), y(t), ω0, ω, F, k;
julia> diff_eq = DifferentialEquation(d(x,t,2) + ω0^2 * x ~ F * cos(ω*t), x);
julia> add_harmonic!(diff_eq, x, ω) # expand x using ω

System of 1 differential equations
Variables:       x(t)
Harmonic ansatz: x(t) => ω;

(ω0^2)*x(t) + Differential(t)(Differential(t)(x(t))) ~ F*cos(t*ω)
```
"""
function add_harmonic!(diff_eom::DifferentialEquation, var::Num, ω)
    diff_eom.harmonics[var] = unique(cat(diff_eom.harmonics[var], ω, dims=1))
    diff_eom
end

"""
$(TYPEDSIGNATURES)
Return the dependent variables of `diff_eom`.
"""
get_variables(diff_eom::DifferentialEquation) = collect(keys(diff_eom.equations))

is_harmonic(diff_eom::DifferentialEquation, t::Num) = all([is_harmonic(eq, t) for eq in values(diff_eom.equations)])

"Pretty printing of the newly defined types"
function show_fields(object)
    for field in fieldnames(typeof(object)) # display every field
        display(string(field)); display(getfield(object, field))
    end
end

"""
$(TYPEDSIGNATURES)
Return the independent dependent variables of `diff_eom`.
"""
function get_independent_variables(diff_eom::DifferentialEquation)
    Num.(flatten(unique([x.val.arguments for x in keys(diff_eom.equations)])))
end

show(eom::DifferentialEquation) = show_fields(eom)