text:
using CUDA.CUSPARSE

using LinearAlgebra
using SparseArrays

@test CUSPARSE.version() isa VersionNumber

m = 25
n = 35
k = 10
blockdim = 5

@testset "array" begin
    x = sprand(m,0.2)
    d_x = CuSparseVector(x)
    @test length(d_x) == m
    @test size(d_x)   == (m, 1)
    @test size(d_x,1) == m
    @test size(d_x,2) == 1
    @test ndims(d_x)  == 1
    CUDA.@allowscalar begin
        @test Array(d_x[:])        == x[:]
        @test d_x[firstindex(d_x)] == x[firstindex(x)]
        @test d_x[div(end, 2)]     == x[div(end, 2)]
        @test d_x[end]             == x[end]
        @test Array(d_x[firstindex(d_x):end]) == x[firstindex(x):end]
    end
    @test_throws BoundsError d_x[firstindex(d_x) - 1]
    @test_throws BoundsError d_x[end + 1]
    @test nnz(d_x)    == nnz(x)
    @test Array(nonzeros(d_x)) == nonzeros(x)
    @test Array(SparseArrays.nonzeroinds(d_x)) == SparseArrays.nonzeroinds(x)
    @test nnz(d_x)    == length(nonzeros(d_x))
    x = sprand(m,n,0.2)
    d_x = CuSparseMatrixCSC(x)
    @test length(d_x) == m*n
    @test size(d_x)   == (m,n)
    @test size(d_x,1) == m
    @test size(d_x,2) == n
    @test size(d_x,3) == 1
    @test ndims(d_x)  == 2
    CUDA.@allowscalar begin
        @test Array(d_x[:])        == x[:]
        @test d_x[firstindex(d_x)] == x[firstindex(x)]
        @test d_x[div(end, 2)]     == x[div(end, 2)]
        @test d_x[end]             == x[end]
        @test d_x[firstindex(d_x), firstindex(d_x)] == x[firstindex(x), firstindex(x)]
        @test d_x[div(end, 2), div(end, 2)]         == x[div(end, 2), div(end, 2)]
        @test d_x[end, end]        == x[end, end]
        @test Array(d_x[firstindex(d_x):end, firstindex(d_x):end]) == x[:, :]
    end
    @test_throws BoundsError d_x[firstindex(d_x) - 1]
    @test_throws BoundsError d_x[end + 1]
    @test_throws BoundsError d_x[firstindex(d_x) - 1, firstindex(d_x) - 1]
    @test_throws BoundsError d_x[end + 1, end + 1]
    @test_throws BoundsError d_x[firstindex(d_x) - 1:end + 1, :]
    @test_throws BoundsError d_x[firstindex(d_x) - 1, :]
    @test_throws BoundsError d_x[end + 1, :]
    @test_throws BoundsError d_x[:, firstindex(d_x) - 1:end + 1]
    @test_throws BoundsError d_x[:, firstindex(d_x) - 1]
    @test_throws BoundsError d_x[:, end + 1]
    @test nnz(d_x)    == nnz(x)
    @test Array(nonzeros(d_x)) == nonzeros(x)
    @test nnz(d_x)    == length(nonzeros(d_x))
    @test !issymmetric(d_x)
    @test !ishermitian(d_x)
    @test_throws ArgumentError size(d_x,0)
    @test_throws ArgumentError CUSPARSE.CuSparseVector(x)
    y = sprand(k,n,0.2)
    d_y = CuSparseMatrixCSC(y)
    @test_throws ArgumentError copyto!(d_y,d_x)
    d_y = CUSPARSE.switch2csr(d_y)
    d_x = CUSPARSE.switch2csr(d_x)
    @test_throws ArgumentError copyto!(d_y,d_x)
    d_y = CUSPARSE.switch2bsr(d_y,convert(Cint,blockdim))
    d_x = CUSPARSE.switch2bsr(d_x,convert(Cint,blockdim))
    @test_throws ArgumentError copyto!(d_y,d_x)
    x = sprand(m,0.2)
    d_x = CuSparseVector(x)
    @test size(d_x, 1) == m
    @test size(d_x, 2) == 1
    @test_throws ArgumentError size(d_x, 0)
    y = sprand(n,0.2)
    d_y = CuSparseVector(y)
    @test_throws ArgumentError copyto!(d_y,d_x)
    x = sprand(m,m,0.2)
    d_x = Symmetric(CuSparseMatrixCSC(x + transpose(x)))
    @test issymmetric(d_x)
    x = sprand(ComplexF64, m, m, 0.2)
    d_x = Hermitian(CuSparseMatrixCSC(x + x'))
    @test ishermitian(d_x)
    x = sprand(m,m,0.2)
    d_x = UpperTriangular(CuSparseMatrixCSC(x))
    @test istriu(d_x)
    @test !istril(d_x)
    d_x = LowerTriangular(CuSparseMatrixCSC(x))
    @test !istriu(d_x)
    @test istril(d_x)
end

@testset "conversion" begin
    @testset for elty in [Float32, Float64, ComplexF32, ComplexF64]
        @testset "make_csc" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSC(x)
            h_x = collect(d_x)
            @test h_x == x
            @test eltype(d_x) == elty
        end

        @testset "make_csr" begin
            x = sprand(elty,m,n, 0.2)
            d_xc = CuSparseMatrixCSC(x)
            d_x  = CuSparseMatrixCSR(x)
            h_x = collect(d_x)
            @test h_x == x
        end

        @testset "convert_r2c" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSR(x)
            d_x = CUSPARSE.switch2csc(d_x)
            h_x = collect(d_x)
            @test h_x.rowval == x.rowval
            @test h_x.nzval ≈ x.nzval
        end

        @testset "convert_r2b" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSR(x)
            d_x = CUSPARSE.switch2bsr(d_x,convert(Cint,blockdim))
            d_x = CUSPARSE.switch2csr(d_x)
            h_x = collect(d_x)
            @test h_x ≈ x
        end

        @testset "convert_c2b" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSC(x)
            d_x = CUSPARSE.switch2bsr(d_x,convert(Cint,blockdim))
            d_x = CUSPARSE.switch2csc(d_x)
            h_x = collect(d_x)
            @test h_x ≈ x
        end

        @testset "convert_d2b" begin
            x = rand(elty,m,n)
            d_x = CuArray(x)
            d_x = CUSPARSE.sparse(d_x,'B')
            d_y = Array(d_x)
            h_x = collect(d_y)
            @test h_x ≈ x
        end

        @testset "convert_c2r" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSC(x)
            d_x = CUSPARSE.switch2csr(d_x)
            h_x = collect(d_x)
            @test h_x.rowval == x.rowval
            @test h_x.nzval ≈ x.nzval
        end

        @testset "convert_r2d" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSR(x)
            d_x = Array(d_x)
            h_x = collect(d_x)
            @test h_x ≈ Array(x)
        end

        @testset "convert_c2d" begin
            x = sprand(elty,m,n, 0.2)
            d_x = CuSparseMatrixCSC(x)
            d_x = Array(d_x)
            h_x = collect(d_x)
            @test h_x ≈ Array(x)
        end

        @testset "convert_d2c" begin
            x = rand(elty,m,n)
            d_x = CuArray(x)
            d_x = CUSPARSE.sparse(d_x,'C')
            h_x = collect(d_x)
            @test h_x ≈ sparse(x)
        end

        @testset "convert_d2r" begin
            x = rand(elty,m,n)
            d_x = CuArray(x)
            d_x = CUSPARSE.sparse(d_x)
            h_x = collect(d_x)
            @test h_x ≈ sparse(x)
        end
    end
end

@testset "bsric02" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        A = rand(elty, m, m)
        A += adjoint(A)
        A += m * Diagonal{elty}(I, m)

        @testset "bsric02!" begin
            d_A = CuSparseMatrixCSR(sparse(tril(A)))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_A = CUSPARSE.ic02!(d_A,'O')
            h_A = collect(CUSPARSE.switch2csr(d_A))
            Ac = sparse(Array(cholesky(Hermitian(A))))
            h_A = transpose(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
            d_A = CuSparseMatrixCSR(sparse(tril(rand(elty,m,n))))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.ic02!(d_A,'O')
        end

        @testset "bsric02" begin
            d_A = CuSparseMatrixCSR(sparse(tril(A)))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_B = CUSPARSE.ic02(d_A,'O')
            h_A = collect(CUSPARSE.switch2csr(d_B))
            Ac = sparse(Array(cholesky(Hermitian(A))))
            h_A = transpose(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
        end
    end
end

@testset "bsrilu02" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        A = rand(elty,m,m)
        A += transpose(A)
        A += m * Diagonal{elty}(I, m)
        @testset "bsrilu02!" begin
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_A = CUSPARSE.ilu02!(d_A,'O')
            h_A = collect(CUSPARSE.switch2csr(d_A))
            Alu = lu(Array(A), Val(false))
            Ac = sparse(Alu.L*Alu.U)
            h_A = adjoint(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
            d_A = CuSparseMatrixCSR(sparse(rand(elty,m,n)))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.ilu02!(d_A,'O')
        end

        @testset "bsrilu02" begin
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_B = CUSPARSE.ilu02(d_A,'O')
            h_A = collect(CUSPARSE.switch2csr(d_B))
            Alu = lu(Array(A),Val(false))
            Ac = sparse(Alu.L*Alu.U)
            h_A = adjoint(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
        end
    end
end

@testset "bsrsm2" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "bsrsm2!" begin
            A = rand(elty,m,m)
            A = triu(A)
            X = rand(elty,m,n)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_X = CUSPARSE.bsrsm2!('N','N',alpha,d_A,d_X,'O')
            h_Y = collect(d_X)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_X = CUDA.rand(elty,n,n)
            @test_throws DimensionMismatch CUSPARSE.bsrsm2!('N','N',alpha,d_A,d_X,'O')
            @test_throws DimensionMismatch CUSPARSE.bsrsm2!('N','T',alpha,d_A,d_X,'O')
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSR(A)
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.bsrsm2!('N','N',alpha,d_A,d_X,'O')
        end

        @testset "bsrsm2" begin
            A = rand(elty,m,m)
            A = triu(A)
            X = rand(elty,m,n)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_Y = CUSPARSE.bsrsm2('N','N',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSR(A)
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.bsrsm2('N','N',alpha,d_A,d_X,'O')
        end
    end
end
@testset "bsrsv2" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "bsrsv2!" begin
            A = rand(elty,m,m)
            A = triu(A)
            X = rand(elty,m)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_X = CUSPARSE.sv2!('N','U',alpha,d_A,d_X,'O')
            h_Y = collect(d_X)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_X = CUDA.rand(elty,n)
            @test_throws DimensionMismatch CUSPARSE.sv2!('N','U',alpha,d_A,d_X,'O')
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSR(A)
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.sv2!('N','U',alpha,d_A,d_X,'O')
        end

        @testset "bsrsv2" begin
            A = rand(elty,m,m)
            A = triu(A)
            Al = tril(A)
            X = rand(elty,m)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            d_Y = CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_Y = UpperTriangular(d_A)\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ A\X
            #=d_Y = UpperTriangular(d_A)'\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ A'\X=#
            d_Y = transpose(UpperTriangular(d_A))\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ transpose(A)\X
            d_Y = LowerTriangular(d_A)\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ Al\X
            #=d_Y = LowerTriangular(d_A)'\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ A'\X=#
            d_Y = transpose(LowerTriangular(d_A))\d_X
            h_Y = collect(d_Y)
            @test h_Y ≈ transpose(Al)\X
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSR(A)
            d_A = CUSPARSE.switch2bsr(d_A, convert(Cint,5))
            @test_throws DimensionMismatch CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
        end
    end
end

@testset "csrsm2" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "csrsm2!" begin
            A = rand(elty,m,m)
            A = triu(A)
            X = rand(elty,m,n)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_X = CUSPARSE.csrsm2!('N','N',alpha,d_A,d_X,'O')
            h_Y = collect(d_X)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_X = CUDA.rand(elty,n,n)
            @test_throws DimensionMismatch CUSPARSE.csrsm2!('N','N',alpha,d_A,d_X,'O')
            @test_throws DimensionMismatch CUSPARSE.csrsm2!('N','T',alpha,d_A,d_X,'O')
            A = sprand(elty,m,n,0.7)
            d_A = CuSparseMatrixCSR(A)
            @test_throws DimensionMismatch CUSPARSE.csrsm2!('N','N',alpha,d_A,d_X,'O')
        end

        @testset "csrsm2" begin
            A = rand(elty,m,m)
            A = triu(A)
            X = rand(elty,m,n)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_Y = CUSPARSE.csrsm2('N','N',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            A = sprand(elty,m,n,0.7)
            d_A = CuSparseMatrixCSR(A)
            @test_throws DimensionMismatch CUSPARSE.csrsm2('N','N',alpha,d_A,d_X,'O')
        end
    end
end
@testset "ilu02" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "csr" begin
            A = rand(elty,m,m)
            A += transpose(A)
            A += m * Diagonal{elty}(I, m)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_B = CUSPARSE.ilu02(d_A,'O')
            h_A = collect(d_B)
            Alu = lu(Array(A),Val(false))
            Ac = sparse(Alu.L*Alu.U)
            h_A = adjoint(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
        end
        @testset "csc" begin
            A = rand(elty,m,m)
            A += transpose(A)
            A += m * Diagonal{elty}(I, m)
            d_A = CuSparseMatrixCSC(sparse(A))
            d_B = CUSPARSE.ilu02(d_A,'O')
            h_A = collect(d_B)
            Alu = lu(Array(A),Val(false))
            Ac = sparse(Alu.L*Alu.U)
            h_A = adjoint(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
        end
    end
end

@testset "ic2" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "csr" begin
            A   = rand(elty, m, m)
            A  += adjoint(A)
            A  += m * Diagonal{elty}(I, m)
            d_A = CuSparseMatrixCSR(sparse(tril(A)))
            d_B = CUSPARSE.ic02(d_A, 'O')
            h_A = collect(d_B)
            Ac  = sparse(Array(cholesky(Hermitian(A))))
            h_A = transpose(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
            A   = rand(elty,m,n)
            d_A = CuSparseMatrixCSR(sparse(tril(A)))
            @test_throws DimensionMismatch CUSPARSE.ic02(d_A, 'O')
        end
        @testset "csc" begin
            A   = rand(elty, m, m)
            A  += adjoint(A)
            A  += m * Diagonal{elty}(I, m)
            d_A = CuSparseMatrixCSC(sparse(tril(A)))
            d_B = CUSPARSE.ic02(d_A, 'O')
            h_A = collect(d_B)
            Ac  = sparse(Array(cholesky(Hermitian(A))))
            h_A = transpose(h_A) * h_A
            @test h_A.rowval ≈ Ac.rowval
            @test reduce(&, isfinite.(h_A.nzval))
            A   = rand(elty,m,n)
            d_A = CuSparseMatrixCSC(sparse(tril(A)))
            @test_throws DimensionMismatch CUSPARSE.ic02(d_A, 'O')
        end
    end
end

@testset "cssv" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "csrsv2" begin
            A = rand(elty,m,m)
            A = triu(A)
            Al = tril(A)
            X = rand(elty,m)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSR(sparse(A))
            d_Y = CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_y = UpperTriangular(d_A)\d_X
            h_y = collect(d_y)
            y = A\X
            @test y ≈ h_y
            d_y = transpose(UpperTriangular(d_A))\d_X
            h_y = collect(d_y)
            y = transpose(A)\X
            @test y ≈ h_y
            #=d_y = UpperTriangular(d_A)'\d_X
            h_y = collect(d_y)
            y = A'\X
            @test y ≈ h_y=#
            d_y = LowerTriangular(d_A)\d_X
            h_y = collect(d_y)
            y = Al\X
            @test y ≈ h_y
            d_y = transpose(LowerTriangular(d_A))\d_X
            h_y = collect(d_y)
            y = transpose(Al)\X
            @test y ≈ h_y
            #=d_y = LowerTriangular(d_A)'\d_X
            h_y = collect(d_y)
            y = A'\X
            @test y ≈ h_y=#
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSR(A)
            @test_throws DimensionMismatch CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
        end

        @testset "cscsv2" begin
            A = rand(elty,m,m)
            A = triu(A)
            Al = tril(A)
            X = rand(elty,m)
            alpha = rand(elty)
            d_X = CuArray(X)
            d_A = CuSparseMatrixCSC(sparse(A))
            d_Y = CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = A\(alpha * X)
            @test Y ≈ h_Y
            d_Y = CUSPARSE.sv2('T','U',alpha,d_A,d_X,'O')
            h_Y = collect(d_Y)
            Y = transpose(A)\(alpha * X)
            @test Y ≈ h_Y
            d_y = UpperTriangular(d_A)\d_X
            h_y = collect(d_y)
            y = A\X
            @test y ≈ h_y
            d_y = transpose(UpperTriangular(d_A))\d_X
            h_y = collect(d_y)
            y = transpose(A)\X
            @test y ≈ h_y
            d_y = LowerTriangular(d_A)\d_X
            h_y = collect(d_y)
            y = Al\X
            @test y ≈ h_y
            d_y = transpose(LowerTriangular(d_A))\d_X
            h_y = collect(d_y)
            y = transpose(Al)\X
            @test y ≈ h_y
            #=d_y = UpperTriangular(d_A)'\d_X
            h_y = collect(d_y)
            y = A'\X
            @test y ≈ h_y=#
            # shouldn't work for now bc sv2 has no way to do conj...
            A = sparse(rand(elty,m,n))
            d_A = CuSparseMatrixCSC(A)
            @test_throws DimensionMismatch CUSPARSE.sv2('N','U',alpha,d_A,d_X,'O')
        end
    end
end

@testset "axpyi" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        @testset "axpyi!" begin
            x = sparsevec(rand(1:m,k), rand(elty,k), m)
            y = rand(elty,m)
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            alpha = rand(elty)
            d_y = CUSPARSE.axpyi!(alpha,d_x,d_y,'O')
            #compare
            h_y = collect(d_y)
            y[x.nzind] += alpha * x.nzval
            @test h_y ≈ y
        end

        @testset "axpyi" begin
            x = sparsevec(rand(1:m,k), rand(elty,k), m)
            y = rand(elty,m)
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            alpha = rand(elty)
            d_z = CUSPARSE.axpyi(alpha,d_x,d_y,'O')
            #compare
            h_z = collect(d_z)
            z = copy(y)
            z[x.nzind] += alpha * x.nzval
            @test h_z ≈ z
            d_z = CUSPARSE.axpyi(d_x,d_y,'O')
            #compare
            h_z = collect(d_z)
            z = copy(y)
            z[x.nzind] += x.nzval
            @test h_z ≈ z
        end
    end
end

@testset "gthr and gthrz" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        x = sparsevec(rand(1:m,k), rand(elty,k), m)
        y = rand(elty,m)
        @testset "gthr!" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            d_y = CUSPARSE.gthr!(d_x,d_y,'O')
            h_x = collect(d_x)
            @test h_x ≈ SparseVector(m,x.nzind,y[x.nzind])
        end

        @testset "gthr" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            d_z = CUSPARSE.gthr(d_x,d_y,'O')
            h_z = collect(d_z)
            @test h_z ≈ SparseVector(m,x.nzind,y[x.nzind])
        end

        @testset "gthrz!" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            d_x,d_y = CUSPARSE.gthrz!(d_x,d_y,'O')
            h_x = collect(d_x)
            h_y = collect(d_y)
            @test h_x ≈ SparseVector(m,x.nzind,y[x.nzind])
            #y[x.nzind] = zero(elty)
            #@test h_y ≈ y
        end

        @testset "gthrz" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            d_z,d_w = CUSPARSE.gthrz(d_x,d_y,'O')
            h_w = collect(d_w)
            h_z = collect(d_z)
            @test h_z ≈ SparseVector(m,x.nzind,y[x.nzind])
            #y[x.nzind] = zero(elty)
            #@test h_w ≈ y
        end
    end
end

@testset "bsrmm2" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        A = sparse(rand(elty,m,k))
        B = rand(elty,k,n)
        C = rand(elty,m,n)
        alpha = rand(elty)
        beta = rand(elty)
        d_B = CuArray(B)
        d_C = CuArray(C)
        d_A = CuSparseMatrixCSR(A)
        d_A = CUSPARSE.switch2bsr(d_A,convert(Cint,blockdim))
        @test_throws DimensionMismatch CUSPARSE.mm2('N','T',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2('T','N',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2('T','T',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2('N','N',alpha,d_A,d_B,beta,d_B,'O')
        d_D = CUSPARSE.mm2('N','N',alpha,d_A,d_B,beta,d_C,'O')
        h_D = collect(d_D)
        D = alpha * A * B + beta * C
        @test D ≈ h_D
        d_D = CUSPARSE.mm2('N','N',d_A,d_B,beta,d_C,'O')
        h_D = collect(d_D)
        D = A * B + beta * C
        @test D ≈ h_D
        d_D = CUSPARSE.mm2('N','N',d_A,d_B,d_C,'O')
        h_D = collect(d_D)
        D = A * B + C
        @test D ≈ h_D
        d_D = CUSPARSE.mm2('N','N',alpha,d_A,d_B,'O')
        h_D = collect(d_D)
        D = alpha * A * B
        @test D ≈ h_D
        d_D = CUSPARSE.mm2('N','N',d_A,d_B,'O')
        h_D = collect(d_D)
        D = A * B
        @test D ≈ h_D
    end
end
@testset "bsrmm2!" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        A = sparse(rand(elty,m,k))
        B = rand(elty,k,n)
        C = rand(elty,m,n)
        alpha = rand(elty)
        beta = rand(elty)
        d_B = CuArray(B)
        d_C = CuArray(C)
        d_A = CuSparseMatrixCSR(A)
        d_A = CUSPARSE.switch2bsr(d_A,convert(Cint,blockdim))
        @test_throws DimensionMismatch CUSPARSE.mm2!('N','T',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2!('T','N',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2!('T','T',alpha,d_A,d_B,beta,d_C,'O')
        @test_throws DimensionMismatch CUSPARSE.mm2!('N','N',alpha,d_A,d_B,beta,d_B,'O')
        CUSPARSE.mm2!('N','N',alpha,d_A,d_B,beta,d_C,'O')
        h_D = collect(d_C)
        D = alpha * A * B + beta * C
        @test D ≈ h_D
        d_C = CuArray(C)
        mul!(d_C, d_A, d_B)
        h_C = collect(d_C)
        D = A * B
        @test D ≈ h_C
    end
end
@testset "mv!" begin
    for elty in [Float32,Float64,ComplexF32,ComplexF64]
        A = sparse(rand(elty,m,m))
        x = rand(elty,m)
        y = rand(elty,m)
        alpha = rand(elty)
        beta = rand(elty)
        A = sparse(rand(elty,m,n))
        x = rand(elty,n)
        y = rand(elty,m)
        alpha = rand(elty)
        beta = rand(elty)
        @testset "mv!" begin
            @testset "bsr" begin
                d_x = CuArray(x)
                d_y = CuArray(y)
                d_A = CuSparseMatrixCSR(A)
                d_A = CUSPARSE.switch2bsr(d_A,convert(Cint,blockdim))
                @test_throws DimensionMismatch CUSPARSE.mv!('T',alpha,d_A,d_x,beta,d_y,'O')
                @test_throws DimensionMismatch CUSPARSE.mv!('N',alpha,d_A,d_y,beta,d_x,'O')
                CUSPARSE.mv!('N',alpha,d_A,d_x,beta,d_y,'O')
                h_z = collect(d_y)
                z = alpha * A * x + beta * y
                @test z ≈ h_z
                mul!(d_y, d_A, d_x)
                h_y = collect(d_y)
                z = A * x
                @test z ≈ h_y
            end
        end
    end
end

@testset "sctr" begin
    @testset for elty in [Float32,Float64,ComplexF32,ComplexF64]
        x = sparsevec(rand(1:m,k), rand(elty,k), m)
        y = zeros(elty,m)
        @testset "sctr!" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            d_y = CUSPARSE.sctr!(d_x,d_y,'O')
            h_y = collect(d_y)
            y[x.nzind]  += x.nzval
            @test h_y ≈ y
        end
        y = zeros(elty,m)

        @testset "sctr" begin
            d_x = CuSparseVector(x)
            d_y = CUSPARSE.sctr(d_x,'O')
            h_y = collect(d_y)
            y = zeros(elty,m)
            y[x.nzind]  += x.nzval
            @test h_y ≈ y
        end
    end
end

@testset "roti" begin
    @testset for elty in [Float32,Float64]
        x = sparsevec(rand(1:m,k), rand(elty,k), m)
        y = rand(elty,m)
        @testset "roti!" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            angle = rand(elty)
            d_x,d_y = CUSPARSE.roti!(d_x,d_y,cos(angle),sin(angle),'O')
            h_x = collect(d_x)
            h_y = collect(d_y)
            z = copy(x)
            w = copy(y)
            y[x.nzind] = cos(angle)*w[z.nzind] - sin(angle)*z.nzval
            @test h_x ≈ SparseVector(m,x.nzind,cos(angle)*z.nzval + sin(angle)*w[z.nzind])
            @test h_y ≈ y
        end

        @testset "roti" begin
            d_x = CuSparseVector(x)
            d_y = CuArray(y)
            angle = rand(elty)
            d_z,d_w = CUSPARSE.roti(d_x,d_y,cos(angle),sin(angle),'O')
            h_w = collect(d_w)
            h_z = collect(d_z)
            z = copy(x)
            w = copy(y)
            w[z.nzind] = cos(angle)*y[x.nzind] - sin(angle)*x.nzval
            @test h_z ≈ SparseVector(m,z.nzind, cos(angle)*x.nzval + sin(angle)*y[x.nzind])
            @test h_w ≈ w
        end
    end
end


text:
# http://adventofcode.com/2016/day/24

# This was an experiment in using Julia, that was scrapped for Python,
# mainly because Julia's graph libraries are awful and immature.

importall LightGraphs

function main()

    point2map = Dict()
    poi2point = Dict()
    point2edge = Dict()

    edges = 0 # edge

    open("sample.txt") do file
        for (x, i) in enumerate(eachline(file))
            for (y, j) in enumerate(i[1:end - 1]) # Cull newlines
                edges += 1
                point2map[(x, y)] = j # Point to map spot
                point2edge[(x, y)] = edges # Point to graph edge

                if isdigit(j)
                    poi2point[j] = (x, y) # Locations of cities
                end
            end
        end
    end

    g = Graph(edges)

    for ((x, y), m) in point2map
        if m != '#' # if this is an empty space

            this_edge = point2edge[(x, y)]

            for p in [(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y)]
                m = get!(point2map, p, nothing)
                if !(m == nothing || m == "#") # and the other is an empty space
                    other_edge = point2edge[p]
                    add_edge!(g, this_edge, other_edge)
                end
            end
        end
    end

    function m2e(m)
        return point2edge[poi2point[m]]
    end

    pois = length(keys(poi2point))
    distances = zeros(pois, pois)

    for start in keys(poi2point)
        for finish in keys(poi2point)
            distance = length(a_star(g, m2e(start), m2e(finish)))
            distances[parse(Int64, start) + 1, parse(Int64, finish) + 1] = distance
            distances[parse(Int64, finish) + 1, parse(Int64, start) + 1] = distance
        end
    end

    h = CompleteGraph(pois)

    print(dijkstra_shortest_paths(h, 1, distances).dists)

    # At this point I gave up. See Day_24.py for an actual completed solution
end

main()

ext: jl


text:
##Interface with JuliaStat's DataFrame
import DataFrames
function Assoc(df::DataFrame)
    #Sorting Columns
    tempcolumn = df.colindex.names
    tempcolumn = [(tempcolumn[i],i)  for i in 1:length(tempcolumn)]
    sort!(tempcolumn)

    column_mapping = [x[2] for x in tempcolumn]
    tempcolumn = [x[1] for x in tempcolumn]

    #There are two scenarios
    # 1. The data frame is column saturated, where the first column isn't row names and the header for the first column is labeled.
    #This is not the standard format csv D4M reads.
    if isempty(searchsorted(tempcolumn,:x))
        column = map(string, tempcolumn)
        row = Array(1:size(df,1))
        mat = Array(df)[:,column_mapping]
    else
    # 2. The data frame isn't column saturated, where the first column is the row names.
    #This is the standard format csv D4M reads.
        xindex = searchsortedfirst(tempcolumn,:x)
        splice!(tempcolumn,xindex)
        splice!(column_mapping,xindex)
        column = map(string, tempcolumn)
        row = Array(df[:x])
        mat = Array(df)[:,column_mapping]
    end

    #Begin mapping value
    r,c,v = findnz(mat)
    val = sort!(unique(v))
    v = map(x -> searchsortedfirst(val,x),v)
    A = sparse(r,c,v)
    row = Array{Union{AbstractString,Number},1}(row)
    column = Array{Union{AbstractString,Number},1}(column)
    val = Array{Union{AbstractString,Number},1}(val)
    return Assoc(row,column,val,A)

end

using DataFrames.DataFrame
function DataFrame(A::Assoc)
    #This requires some pigeon holing which is in part due to how DataFrame resolve column header collisions.
    fullA = full(A)
    df = DataFrame(fullA[2:end,:])

    #name collision pigeon hole
    columnheader = fullA[1,:]'[:]
    if("x" in columnheader)
        index = 1
        while ("x_" * string(index) in columnheader)
            index += 1
        end
        columnheader[findfirst(columnheader,"x")] = "x_"* string(index)
    end

    #update column headers for DataFrame
    columnheader[1] = "x"
    df.colindex.names = map(symbol,columnheader)
    df.colindex.lookup = Dict(zip(df.colindex.names,1:length(df.colindex.names)))
    return df
end


text:
###########################################################
#
#   GenericIncidenceList{V, E, VList, IncList}
#
#   V :         vertex type
#   E :         edge type
#   VList :     the type of vertex list
#   IncList:    the incidence list
#
###########################################################

type GenericIncidenceList{V, E, VList, IncList} <: AbstractGraph{V, E}
    is_directed::Bool
    vertices::VList
    nedges::Int
    inclist::IncList
end

typealias SimpleIncidenceList GenericIncidenceList{Int, IEdge, Range1{Int}, Vector{Vector{IEdge}}}
typealias IncidenceList{V,E} GenericIncidenceList{V, E, Vector{V}, Vector{Vector{E}}}

@graph_implements GenericIncidenceList vertex_list vertex_map edge_map adjacency_list incidence_list

# construction

simple_inclist(nv::Integer; is_directed::Bool=true) =
    SimpleIncidenceList(is_directed, 1:int(nv), 0, multivecs(IEdge, nv))

inclist{V,E}(vs::Vector{V}, ::Type{E}; is_directed::Bool = true) =
    IncidenceList{V,E}(is_directed, vs, 0, multivecs(E, length(vs)))

inclist{V,E}(::Type{V}, ::Type{E}; is_directed::Bool = true) = inclist(V[], E; is_directed=is_directed)
inclist{V}(vs::Vector{V}; is_directed::Bool = true) = inclist(vs, Edge{V}; is_directed=is_directed)
inclist{V}(::Type{V}; is_directed::Bool = true) = inclist(V[], Edge{V}; is_directed=is_directed)

# required interfaces

is_directed(g::GenericIncidenceList) = g.is_directed

num_vertices(g::GenericIncidenceList) = length(g.vertices)
vertices(g::GenericIncidenceList) = g.vertices

num_edges(g::GenericIncidenceList) = g.nedges

vertex_index{V<:ProvidedVertexType}(v::V, g::GenericIncidenceList{V}) = vertex_index(v)
edge_index{V,E}(e::E, g::GenericIncidenceList{V,E}) = edge_index(e)

out_edges{V}(v::V, g::GenericIncidenceList{V}) = g.inclist[vertex_index(v, g)]
out_degree{V}(v::V, g::GenericIncidenceList{V}) = length(out_edges(v, g))
out_neighbors{V}(v::V, g::GenericIncidenceList{V}) = TargetIterator(g, g.inclist[vertex_index(v, g)])

# mutation

function add_vertex!{V,E}(g::GenericIncidenceList{V,E}, v::V)
    push!(g.vertices, v)
    push!(g.inclist, Array(E,0))
    v
end

add_vertex!(g::GenericIncidenceList, x) = add_vertex!(g, make_vertex(g, x))

function add_edge!{V,E}(g::GenericIncidenceList{V,E}, u::V, v::V, e::E)
    # add an edge between (u, v)
    ui::Int = vertex_index(u, g)
    push!(g.inclist[ui], e)
    g.nedges += 1

    if !g.is_directed
        vi::Int = vertex_index(v, g)
        push!(g.inclist[vi], revedge(e))
    end
end

add_edge!{V,E}(g::GenericIncidenceList{V,E}, e::E) = add_edge!(g, source(e, g), target(e, g), e)
add_edge!{V,E}(g::GenericIncidenceList{V, E}, u::V, v::V) = add_edge!(g, u, v, make_edge(g, u, v))


text:
using Statistics

Statistics.varm(A::CuArray{<:Real},m::AbstractArray{<:Real}; dims, corrected::Bool=true) =
    sum((A .- m).^2, dims=dims)/(prod(size(A)[[dims...]])::Int-corrected)

Statistics.stdm(A::CuArray{<:Real},m::AbstractArray{<:Real}, dim::Int; corrected::Bool=true) =
    sqrt.(varm(A,m;dims=dim,corrected=corrected))

Statistics._std(A::CuArray, corrected::Bool, mean, dims) =
    Base.sqrt.(Statistics.var(A; corrected=corrected, mean=mean, dims=dims))

Statistics._std(A::CuArray, corrected::Bool, mean, ::Colon) =
    Base.sqrt.(Statistics.var(A; corrected=corrected, mean=mean, dims=:))

# Revert https://github.com/JuliaLang/Statistics.jl/pull/25
Statistics._mean(A::CuArray, ::Colon)    = sum(A) / length(A)
Statistics._mean(f, A::CuArray, ::Colon) = sum(f, A) / length(A)
Statistics._mean(A::CuArray, dims)    = mean!(Base.reducedim_init(t -> t/2, +, A, dims), A)
Statistics._mean(f, A::CuArray, dims) = sum(f, A, dims=dims) / mapreduce(i -> size(A, i), *, unique(dims); init=1)


text:
"This function may be unsafe: `safe_params` must outlive the `OraCommonCreateParams` generated by this function."
function OraCommonCreateParams(ctx::Context, safe_params::CommonCreateParams)

    function EmptyOraCommonCreateParams(ctx::Context)
        common_create_params_ref = Ref{OraCommonCreateParams}(OraCommonCreateParams(ORA_MODE_CREATE_DEFAULT, C_NULL, C_NULL, C_NULL, 0, C_NULL, 0))
        result = dpiContext_initCommonCreateParams(ctx.handle, common_create_params_ref)
        error_check(ctx, result)
        return common_create_params_ref[]
    end

    result = EmptyOraCommonCreateParams(ctx)

    if safe_params.create_mode != nothing
        result.create_mode = safe_params.create_mode
    end

    result.encoding = pointer(safe_params.encoding)
    result.nencoding = pointer(safe_params.nencoding)

    if safe_params.edition != nothing
        result.edition = pointer(safe_params.edition)
        result.edition_length = sizeof(safe_params.edition)
    end

    if safe_params.driver_name != nothing
        result.driver_name = pointer(safe_params.driver_name)
        result.driver_name_length = sizeof(safe_params.driver_name)
    end

    return result
end

"This function may be unsafe: `safe_params` must outlive the `OraConnCreateParams` generated by this function."
function OraConnCreateParams(ctx::Context, safe_params::ConnCreateParams)

    function EmptyOraConnCreateParams(ctx::Context)
        new_conn_create_params = OraConnCreateParams(ORA_MODE_AUTH_DEFAULT, C_NULL, 0, ORA_PURITY_DEFAULT, C_NULL, 0, C_NULL, 0, 0, C_NULL, C_NULL, C_NULL, 0, 0, C_NULL, 0, 0, C_NULL, 0, C_NULL, 0)
        conn_create_params_ref = Ref{OraConnCreateParams}(new_conn_create_params)
        result = dpiContext_initConnCreateParams(ctx.handle, conn_create_params_ref)
        error_check(ctx, result)
        return conn_create_params_ref[]
    end

    result = EmptyOraConnCreateParams(ctx)

    result.auth_mode = safe_params.auth_mode

    if safe_params.pool != nothing
        result.pool_handle = safe_params.pool.handle
    end

    return result
end

function Connection(ctx::Context, user::String, password::String, connect_string::String, common_params::CommonCreateParams, conn_create_params::ConnCreateParams)
    conn_handle_ref = Ref{Ptr{Cvoid}}()
    ora_common_params = OraCommonCreateParams(ctx, common_params)
    ora_conn_create_params = OraConnCreateParams(ctx, conn_create_params)
    result = dpiConn_create(ctx.handle, user, password, connect_string, Ref(ora_common_params), Ref(ora_conn_create_params), conn_handle_ref)
    error_check(ctx, result)
    return Connection(ctx, conn_handle_ref[], conn_create_params.pool)
end

function Connection(ctx::Context, user::String, password::String, connect_string::String;
        encoding::AbstractString=DEFAULT_CONNECTION_ENCODING,
        nencoding::AbstractString=DEFAULT_CONNECTION_NENCODING,
        create_mode::Union{Nothing, OraCreateMode}=nothing,
        edition::Union{Nothing, String}=nothing,
        driver_name::Union{Nothing, String}=nothing,
        auth_mode::OraAuthMode=ORA_MODE_AUTH_DEFAULT,
        pool::Union{Nothing, Pool}=nothing
    )

    common_params = CommonCreateParams(create_mode, encoding, nencoding, edition, driver_name)
    conn_create_params = ConnCreateParams(auth_mode, pool)

    return Connection(ctx, user, password, connect_string, common_params, conn_create_params)
end

"""
    Connection(user::AbstractString, password::AbstractString, connect_string::AbstractString;
            encoding::AbstractString=DEFAULT_CONNECTION_ENCODING,
            nencoding::AbstractString=DEFAULT_CONNECTION_NENCODING,
            create_mode::Union{Nothing, OraCreateMode}=nothing,
            edition::Union{Nothing, String}=nothing,
            driver_name::Union{Nothing, String}=nothing,
            auth_mode::OraAuthMode=ORA_MODE_AUTH_DEFAULT,
            pool::Union{Nothing, Pool}=nothing
        )

Creates a connection to the Oracle Database.

Connections should always be closed after use
by calling `Oracle.close`.

# Example

```julia
import Oracle

username = "my_username"
password = "my_password"
connect_string = "//IP_ADDRESS/XE" # a valid Oracle connect string

conn = Oracle.Connection(username, password, connect_string)

# connections should always be closed after use.
Oracle.close(conn)
```
"""
function Connection(user::AbstractString, password::AbstractString, connect_string::AbstractString;
        encoding::AbstractString=DEFAULT_CONNECTION_ENCODING,
        nencoding::AbstractString=DEFAULT_CONNECTION_NENCODING,
        create_mode::Union{Nothing, OraCreateMode}=nothing,
        edition::Union{Nothing, String}=nothing,
        driver_name::Union{Nothing, String}=nothing,
        auth_mode::OraAuthMode=ORA_MODE_AUTH_DEFAULT,
        pool::Union{Nothing, Pool}=nothing
    )

    return Connection(Context(), String(user), String(password), String(connect_string),
                encoding=encoding,
                nencoding=nencoding,
                create_mode=create_mode,
                edition=edition,
                driver_name=driver_name,
                auth_mode=auth_mode,
                pool=pool
            )
end

function server_version(conn::Connection)
    release_string_ptr_ref = Ref{Ptr{UInt8}}()
    release_string_length_ref = Ref{UInt32}()
    version_info_ref = Ref{OraVersionInfo}()
    result = dpiConn_getServerVersion(conn.handle, release_string_ptr_ref, release_string_length_ref, version_info_ref)
    error_check(context(conn), result)

    release_string = unsafe_string(release_string_ptr_ref[], release_string_length_ref[])
    return (release_string, version_info_ref[])
end

"""
    ping(conn::Connection)

Pings the database server to check if the connection is still alive.
Throws error if can't ping the server.
"""
function ping(conn::Connection)
    result = dpiConn_ping(conn.handle)
    error_check(context(conn), result)
    nothing
end

function startup_database(conn::Connection, startup_mode::OraStartupMode=ORA_MODE_STARTUP_DEFAULT)
    result = dpiConn_startupDatabase(conn.handle, startup_mode)
    error_check(context(conn), result)
    nothing
end

function shutdown_database(conn::Connection, shutdown_mode::OraShutdownMode=ORA_MODE_SHUTDOWN_DEFAULT)
    result = dpiConn_shutdownDatabase(conn.handle, shutdown_mode)
    error_check(context(conn), result)
    nothing
end

"""
    commit(conn::Connection)

Commits the current active transaction.
"""
function commit(conn::Connection)
    result = dpiConn_commit(conn.handle)
    error_check(context(conn), result)
    nothing
end

"""
    rollback(conn::Connection)

Rolls back the current active transaction.
"""
function rollback(conn::Connection)
    result = dpiConn_rollback(conn.handle)
    error_check(context(conn), result)
    nothing
end

function close(conn::Connection; close_mode::OraConnCloseMode=ORA_MODE_CONN_CLOSE_DEFAULT, tag::String="")
    result = dpiConn_close(conn.handle, close_mode=close_mode, tag=tag)
    error_check(context(conn), result)
    conn.pool = nothing
    nothing
end

function current_schema(conn::Connection) :: Union{Missing, String}
    value_char_array_ref = Ref{Ptr{UInt8}}()
    value_length_ref = Ref{UInt32}()
    result = dpiConn_getCurrentSchema(conn.handle, value_char_array_ref, value_length_ref)
    error_check(context(conn), result)
    if value_char_array_ref[] == C_NULL
        return missing
    else
        return unsafe_string(value_char_array_ref[], value_length_ref[])
    end
end

function stmt_cache_size(conn::Connection) :: UInt32
    cache_size_ref = Ref{UInt32}()
    result = dpiConn_getStmtCacheSize(conn.handle, cache_size_ref)
    error_check(context(conn), result)
    return cache_size_ref[]
end

function stmt_cache_size!(conn::Connection, cache_size::Integer)
    result = dpiConn_setStmtCacheSize(conn.handle, UInt32(cache_size))
    error_check(context(conn), result)
end


text:
"""
	between(obj::AbstractDataFrame, variable::Symbol)

	This function returns the between transformation of the dataframe.
	It uses a variable to perform the transformation. Categorical variables
	that have two values are aggregated by the mean taking the last level
	as `true`. Categorical variables a different number of levels are
	suppressed.
"""
function between(obj::AbstractDataFrame, variable::Symbol)
	obj = dropmissing(obj)
    categorical!(obj)
    obj = obj[union([variable], names(obj))]
    sort!(obj, cols = [variable])
    varlist = names(obj)
    FirstOfEach = collect(values(sort(indexmap(obj[variable]))))
    output = by(obj, variable) do subdf
        DataFrame(colwise(between, subdf[:,2:end]))
    end
    names!(output, varlist)
    incompatible = Vector{Symbol}()
    for name ∈ names(output[:,2:end])
        if typeof(obj[name]) <: AbstractCategoricalVector
            lvls = levels(obj[name])
            if (length(lvls) == 2) & (sort(unique(output[name])) == (0,1))
                output[name] = ifelse.(output[name] .== 0, first(lvls), last(lvls))
            elseif length(lvls) > 2
                if all(output[name] .== true)
                    output[name] = obj[FirstOfEach, name]
                else
                    push!(incompatible, name)
                end
            end
        elseif eltype(obj[name]) <: Dates.TimeType
            if all(output[name] .== true)
                output[name] = obj[FirstOfEach, name]
            else
                push!(incompatible, name)
            end
        end
    end
    output = output[setdiff(names(obj), incompatible)]
    for (name, col) ∈ eachcol(output)
        if typeof(obj[name]) <: AbstractCategoricalVector
            if sort(unique(col)) == [0,1]
                output[name] = obj[FirstOfEach,name]
            end
        end
    end
	return output
end
between(obj::AbstractVector) = mean(obj)
between(obj::AbstractVector{T}) where T <: Dates.TimeType = length(unique(obj)) == 1
function between(obj::AbstractCategoricalVector)
    lvls = levels(obj)
    if length(lvls) == 1
        output = first(lvls)
    elseif length(lvls) == 2
        output = mean(obj .== last(lvls))
    else
        output = length(unique(obj)) == 1
    end
    return output
end


text:
using ApproxFun
using ExponentialFamilies
using StatsPlots
using Test
using Random

taus = range( -4,  6, step=0.2)
twintower_expfamily = ContinuousExponentialFamilyModel(Uniform(-4, 6), collect(taus); df=8, scale=true)
α_example =  [10; 0.0; 6.0; 9.0; -3.0; -2.0; -8.0; -1.0]
cef_example = twintower_expfamily(α_example)

@test isa(cef_example,  ContinuousExponentialFamily{Uniform{T}} where T<:Real)

@test (ContinuousExponentialFamily{Uniform{T}} where T<:Real) <: Sampleable{Univariate}

Zs = rand(cef_example, 50_000)

x_grid = -4:0.01:6
histogram(Zs, nbins=100, normed=true, color=:lightgrey)
plot!(x_grid,  pdf.(cef_example, x_grid), color=:purple,
          linestyle=:dash, linewidth=3)


text:
export constantterm, term, termtype, zeroterm, coefficient, monomial

"""
    term(p::AbstractPolynomialLike)

Converts the polynomial `p` to a term.
When applied on a polynomial, it throws an error if it has more than one term.
When applied to a term, it is the identity and does not copy it.
When applied to a monomial, it create a term of type `AbstractTerm{Int}`.
"""
function term(p::APL{T}) where T
    if nterms(p) == 0
        zeroterm(p)
    elseif nterms(p) > 1
        error("A polynomial is more than one term cannot be converted to a term.")
    else
        leadingterm(p)
    end
end
term(t::AbstractTerm) = t
term(m::AbstractMonomialLike) = 1 * m

"""
    termtype(p::AbstractPolynomialLike)

Returns the type of the terms of `p`.

    termtype(::Type{PT}) where PT<:AbstractPolynomialLike

Returns the type of the terms of a polynomial of type `PT`.

    termtype(p::AbstractPolynomialLike, ::Type{T}) where T

Returns the type of the terms of `p` but with coefficient type `T`.

    termtype(::Type{PT}, ::Type{T}) where {PT<:AbstractPolynomialLike, T}

Returns the type of the terms of a polynomial of type `PT` but with coefficient type `T`.
"""
termtype(::Union{T, Type{T}}) where T <: AbstractTerm = T
termtype(::Union{P, Type{P}}) where P <: APL = Base.promote_op(first ∘ terms, P)
termtype(p::Union{APL, Type{<:APL}}, ::Type{T}) where T = termtype(termtype(p), T)
termtype(m::Union{M, Type{M}}) where M<:AbstractMonomialLike = termtype(m, Int)
termtype(v::Union{AbstractVariable, Type{<:AbstractVariable}}) = termtype(monomialtype(v))
termtype(v::Union{AbstractVariable, Type{<:AbstractVariable}}, ::Type{T}) where T = termtype(monomialtype(v), T)
termtype(::Union{AbstractVector{PT}, Type{<:AbstractVector{PT}}}) where PT <: APL = termtype(PT)
termtype(::Union{AbstractVector{PT}, Type{<:AbstractVector{PT}}}, ::Type{T}) where {PT <: APL, T} = termtype(PT, T)

"""
    coefficient(t::AbstractTermLike)

Returns the coefficient of the term `t`.

    coefficient(p::AbstractPolynomialLike, m::AbstractMonomialLike)

Returns the coefficient of the monomial `m` in `p`.

### Examples

Calling `coefficient` on ``4x^2y`` should return ``4``.
Calling `coefficient(2x + 4y^2 + 3, y^2)` should return ``4``.
Calling `coefficient(2x + 4y^2 + 3, x^2)` should return ``0``.
"""
coefficient(m::AbstractMonomialLike) = 1
function coefficient(p::AbstractPolynomialLike{T}, m::AbstractMonomialLike) where T
    for t in terms(p)
        if monomial(t) == m
            return coefficient(t)
        end
    end
    zero(T)
end

"""
    coefficient(p::AbstractPolynomialLike, m::AbstractMonomialLike, vars)::AbstractPolynomialLike

Returns the coefficient of the monomial `m` of the polynomial `p` considered as a polynomial in variables
`vars`.

### Example
Calling `coefficient((a+b)x^2+2x+y*x^2, x^2, [x,y])` should return `a+b`.
Calling `coefficient((a+b)x^2+2x+y*x^2, x^2, [x])` should return `a+b+y`.
"""
function coefficient(f::APL, m::AbstractMonomialLike, vars)
    coeff = zero(f)
    for t in terms(f)
        match = true
        for v in vars
            if degree(t, v) != degree(m, v)
                match = false
                break
            end
        end
        match || continue

        coeff += coefficient(t) * (_div(monomial(t), m))
    end
    coeff
end

"""
    coefficient(p::AbstractPolynomialLike)

Returns the coefficient type of `p`.

    coefficient(::Type{PT}) where PT

Returns the coefficient type of a polynomial of type `PT`.

### Examples

Calling `coefficienttype` on ``(4//5)x^2y`` should return `Rational{Int}`,
calling `coefficienttype` on ``1.0x^2y + 2.0x`` should return `Float64` and
calling `coefficienttype` on ``xy`` should return `Int`.
"""
coefficienttype(::Union{PT, Type{PT}, AbstractVector{PT}, Type{<:AbstractVector{PT}}}) where {T, PT<:APL{T}} = T
#coefficienttype(::{T, Type{T}}) where {T} = T

"""
    monomial(t::AbstractTermLike)

Returns the monomial of the term `t`.

### Examples

Calling `monomial` on ``4x^2y`` should return ``x^2y``.
"""
function monomial end
monomial(m::AbstractMonomial) = m

"""
    constantterm(α, p::AbstractPolynomialLike)

Creates a constant term with coefficient α and the same variables as p.

    constantterm(α, ::Type{PT} where {PT<:AbstractPolynomialLike}

Creates a constant term of the term type of a polynomial of type `PT`.
"""
constantterm(α, p) = α * constantmonomial(p)

# zero should return a polynomial since it is often used to keep the result of a summation of terms.
# For example, Base.vecdot(x::Vector{<:AbstractTerm}, y:Vector{Int}) starts with `s = zero(dot(first(x), first(y)))` and then adds terms.
# We want `s` to start as a polynomial for this operation to be efficient.
#Base.zero(::Type{TT}) where {T, TT<:AbstractTermLike{T}} = zero(T) * constantmonomial(TT)
#Base.zero(t::AbstractTermLike{T}) where {T} = zero(T) * constantmonomial(t)
"""
    zeroterm(p::AbstractPolynomialLike{T}) where T

Equivalent to `constantterm(zero(T), p)`.

    zeroterm(α, ::Type{PT} where {T, PT<:AbstractPolynomialLike{T}}

Equivalent to `constantterm(zero(T), PT)`.
"""
zeroterm(::Type{PT}) where {T, PT<:APL{T}} = constantterm(zero(T), PT)
zeroterm(p::APL{T}) where {T} = constantterm(zero(T), p)

Base.zero(::Type{TT}) where {T, TT<:AbstractTermLike{T}} = zero(polynomialtype(TT))
Base.zero(t::AbstractTermLike{T}) where {T} = zero(polynomialtype(t))
MA.promote_operation(::typeof(zero), PT::Type{<:AbstractTermLike}) = polynomialtype(PT)
Base.one(::Type{TT}) where {T, TT<:AbstractTermLike{T}} = one(T) * constantmonomial(TT)
Base.one(t::AbstractTermLike{T}) where {T} = one(T) * constantmonomial(t)
MA.promote_operation(::typeof(one), TT::Type{<:AbstractTermLike}) = termtype(TT)
MA.promote_operation(::typeof(one), PT::Type{<:AbstractPolynomialLike}) = polynomialtype(PT)


text:
@testset "default" begin
    p = @inferred boxplot([1, 2, 3, 4, 5])
    test_ref("references/boxplot/default.txt", @show_col(p))
    p = @inferred boxplot("series1", [1, 2, 3, 4, 5])
    test_ref("references/boxplot/default_name.txt", @show_col(p))
    p = @inferred boxplot(
        "series1",
        [1, 2, 3, 4, 5],
        title = "Test",
        xlim = (-1, 8),
        color = :blue,
        width = 50,
        border = :solid,
        xlabel = "foo",
    )
    test_ref("references/boxplot/default_parameters.txt", @show_col(p))
    p = @inferred boxplot(
        "series1",
        [1, 2, 3, 4, 5],
        title = "Test",
        xlim = [-1, 8],
        color = :blue,
        width = 50,
        border = :solid,
        xlabel = "foo",
    )
    test_ref("references/boxplot/default_parameters.txt", @show_col(p))
    test_ref("references/boxplot/default_parameters_nocolor.txt", @show_nocol(p))
end

@testset "scaling" begin
    for (i, max_x) in enumerate([5, 6, 10, 20, 40])
        p = @inferred boxplot([1, 2, 3, 4, 5], xlim = (0, max_x))
        test_ref("references/boxplot/scale$i.txt", @show_col(p))
        p = @inferred boxplot([1, 2, 3, 4, 5], xlim = [0, max_x])
        test_ref("references/boxplot/scale$i.txt", @show_col(p))
    end
end

@testset "multi-series" begin
    p = @inferred boxplot(
        ["one", "two"],
        [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7, 8, 9]],
        title = "Multi-series",
        xlabel = "foo",
        color = :yellow,
    )
    test_ref("references/boxplot/multi1.txt", @show_col(p))
    @test @inferred(boxplot!(p, "one more", [-1, 2, 3, 4, 11])) === p
    test_ref("references/boxplot/multi2.txt", @show_col(p))
    @test @inferred(boxplot!(p, [4, 2, 2.5, 4, 14], name = "last one")) === p
    test_ref("references/boxplot/multi3.txt", @show_col(p))
    p = @inferred boxplot([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7, 8, 9]])
    test_ref("references/boxplot/multi4.txt", @show_col(p))
end

@testset "colors" begin
    p = @inferred boxplot(["one", "two"], [[1, 2, 3], [4, 5, 6]], color = 214)
    test_ref("references/boxplot/col1.txt", @show_col(p))

    p = @inferred boxplot(["one", "two"], [[1, 2, 3], [4, 5, 6]], color = (187, 0, 187))
    test_ref("references/boxplot/col2.txt", @show_col(p))
end


text:
using LazyArrays, ArrayLayouts, LinearAlgebra, FillArrays, StaticArrays, Tracker, Base64, Test
import LazyArrays: BroadcastLayout, arguments, LazyArrayStyle
import Base: broadcasted

@testset "Broadcasting" begin
    @testset "BroadcastArray" begin
        a = randn(6)
        b = BroadcastArray(exp, a)
        @test BroadcastArray(b) == BroadcastVector(b) == b == copyto!(similar(b), b)

        @test b ==  Vector(b) == exp.(a)
        @test b[2:5] isa Vector
        @test b[2:5] == exp.(a[2:5])

        @test exp.(b) isa BroadcastVector
        @test b .+ SVector(1,2,3,4,5,6) isa BroadcastVector
        @test SVector(1,2,3,4,5,6) .+ b isa BroadcastVector

        A = randn(6,6)
        B = BroadcastArray(exp, A)

        @test Matrix(B) == exp.(A)
        @test B[1] == exp(A[1,1])
        @test B[7] == exp(A[1,2])

        C = BroadcastArray(+, A, 2)
        @test C == A .+ 2
        D = BroadcastArray(+, A, C)
        @test D == A + C

        @test sum(B) ≈ sum(exp, A)
        @test sum(C) ≈ sum(A .+ 2)
        @test prod(B) ≈ prod(exp, A)
        @test prod(C) ≈ prod(A .+ 2)

        x = Vcat([3,4], [1,1,1,1,1], 1:3)
        @test x .+ (1:10) isa Vcat
        @test (1:10) .+ x isa Vcat
        @test x + (1:10) isa Vcat
        @test (1:10) + x isa Vcat
        @test x .+ (1:10) == (1:10) .+ x == (1:10) + x == x + (1:10) == Vector(x) + (1:10)

        @test exp.(x) isa Vcat
        @test exp.(x) == exp.(Vector(x))
        @test x .+ 2 isa Vcat
        @test (x .+ 2).args[end] ≡ x.args[end] .+ 2 ≡ 3:5
        @test x .* 2 isa Vcat
        @test 2 .+ x isa Vcat
        @test 2 .* x isa Vcat

        A = Vcat([[1 2; 3 4]], [[4 5; 6 7]])
        @test A .+ Ref(I) == Ref(I) .+ A == Vcat([[2 2; 3 5]], [[5 5; 6 8]])

        @test BroadcastArray(*,1.1,[1 2])[1] == 1.1

        B = BroadcastArray(*, Diagonal(randn(5)), randn(5,5))
        @test B == broadcast(*,B.args...)
        @test colsupport(B,1) == rowsupport(B,1) == 1:1
        @test colsupport(B,3) == rowsupport(B,3) == 3:3
        @test colsupport(B,5) == rowsupport(B,5) == 5:5
        B = BroadcastArray(*, Diagonal(randn(5)), 2)
        @test B == broadcast(*,B.args...)
        @test colsupport(B,1) == rowsupport(B,1) == 1:1
        @test colsupport(B,3) == rowsupport(B,3) == 3:3
        @test colsupport(B,5) == rowsupport(B,5) == 5:5
        B = BroadcastArray(*, Diagonal(randn(5)), randn(5))
        @test B == broadcast(*,B.args...)
        @test colsupport(B,1) == rowsupport(B,1) == 1:1
        @test colsupport(B,3) == rowsupport(B,3) == 3:3
        @test colsupport(B,5) == rowsupport(B,5) == 5:5

        B = BroadcastArray(+, Diagonal(randn(5)), 2)
        @test colsupport(B,1) == rowsupport(B,1) == 1:5
        @test colsupport(B,3) == rowsupport(B,3) == 1:5
        @test colsupport(B,5) == rowsupport(B,5) == 1:5

        @testset "different type" begin
            B = BroadcastArray{Float64}(+, [1,2,3], 2)
            @test eltype(B) == Float64
            @test B[1] ≡ 3.0
        end
    end

    @testset "vector*matrix broadcasting #27" begin
        H = [1., 0.]
        @test applied(*, H, H') .+ 1 == H*H' .+ 1
        B =  randn(2,2)
        @test applied(*, H, H') .+ B == H*H' .+ B
    end

    @testset "BroadcastArray +" begin
        a = BroadcastArray(+, randn(400), randn(400))
        b = similar(a)
        copyto!(b, a)
        @test @allocated(copyto!(b, a)) == 0
        @test b == a
    end

    @testset "Lazy range" begin
        @test broadcasted(LazyArrayStyle{1}(), +, 1:5) ≡ 1:5
        @test broadcasted(LazyArrayStyle{1}(), +, 1, 1:5) ≡ 2:6
        @test broadcasted(LazyArrayStyle{1}(), +, 1:5, 1) ≡ 2:6

        @test broadcasted(LazyArrayStyle{1}(), +, Fill(2,5)) ≡ Fill(2,5)
        @test broadcasted(LazyArrayStyle{1}(), +, 1, Fill(2,5)) ≡ Fill(3,5)
        @test broadcasted(LazyArrayStyle{1}(), +, Fill(2,5), 1) ≡ Fill(3,5)
        @test broadcasted(LazyArrayStyle{1}(), +, Ref(1), Fill(2,5)) ≡ Fill(3,5)
        @test broadcasted(LazyArrayStyle{1}(), +, Fill(2,5), Ref(1)) ≡ Fill(3,5)
        @test broadcasted(LazyArrayStyle{1}(), +, 1, Fill(2,5)) ≡ Fill(3,5)
        @test broadcasted(LazyArrayStyle{1}(), +, Fill(2,5), Fill(3,5)) ≡ Fill(5,5)

        @test broadcasted(LazyArrayStyle{1}(), *, Zeros(5), Zeros(5)) ≡ Zeros(5)
        @test broadcasted(LazyArrayStyle{1}(), *, Fill(2,5), 1:5) ≡ broadcasted(LazyArrayStyle{1}(), *, 1:5, Fill(2,5)) ≡ 2:2:10
        @test broadcasted(LazyArrayStyle{1}(), *, Zeros(5), 1:5) ≡ broadcasted(LazyArrayStyle{1}(), *, 1:5, Zeros(5)) ≡ Zeros(5)
        @test broadcasted(LazyArrayStyle{1}(), *, Ones{Int}(5), 1:5) ≡ broadcasted(LazyArrayStyle{1}(), *, 1:5, Ones{Int}(5)) ≡ 1:5

        b = BroadcastArray(exp, randn(5))
        @test b .* Zeros(5) ≡ Zeros(5)
        @test Zeros(5) .* b ≡ Zeros(5)
    end

    @testset "Sub-broadcast" begin
        A = BroadcastArray(exp,randn(5,5))
        V = view(A, 1:2,2:3)
        @test MemoryLayout(typeof(V)) isa BroadcastLayout{typeof(exp)}
        @test BroadcastArray(V) == A[1:2,2:3] == Array(A)[1:2,2:3]

        B = BroadcastArray(-, randn(5,5), randn(5))
        V = view(B, 1:2,2:3)
        @test MemoryLayout(typeof(V)) isa BroadcastLayout{typeof(-)}
        @test BroadcastArray(V) == B[1:2,2:3] == Array(B)[1:2,2:3]
    end

    @testset "AdjTrans" begin
        A = BroadcastArray(exp,randn(5,5))
        @test MemoryLayout(typeof(transpose(A))) isa BroadcastLayout{typeof(exp)}
        @test MemoryLayout(typeof(A')) isa BroadcastLayout{typeof(exp)}
        @test BroadcastArray(A') == BroadcastArray(transpose(A)) == A' == Array(A)'

        B = BroadcastArray(-, randn(5,5), randn(5))
        @test MemoryLayout(typeof(transpose(B))) isa BroadcastLayout{typeof(-)}
        @test MemoryLayout(typeof(B')) isa BroadcastLayout{typeof(-)}
        @test BroadcastArray(B') == BroadcastArray(transpose(B)) == B' == Array(B)'

        Vc = view(B', 1:2,1:3)
        Vt = view(transpose(B), 1:2,1:3)
        @test MemoryLayout(typeof(Vc)) isa BroadcastLayout{typeof(-)}
        @test MemoryLayout(typeof(Vt)) isa BroadcastLayout{typeof(-)}
        @test arguments(Vc) == (B.args[1][1:3,1:2]', permutedims(B.args[2][1:3]))
        @test arguments(Vt) == (transpose(B.args[1][1:3,1:2]), permutedims(B.args[2][1:3]))
        @test BroadcastArray(Vc) == BroadcastArray(Vt) == Vc == Vt == (Array(B)')[1:2,1:3]

        Vc = view(B,1:3,1:2)'
        Vt = transpose(view(B,1:3,1:2))
        @test MemoryLayout(typeof(Vc)) isa BroadcastLayout{typeof(-)}
        @test MemoryLayout(typeof(Vt)) isa BroadcastLayout{typeof(-)}
        @test arguments(Vc) == (B.args[1][1:3,1:2]', permutedims(B.args[2][1:3]))
        @test arguments(Vt) == (transpose(B.args[1][1:3,1:2]), permutedims(B.args[2][1:3]))
        @test BroadcastArray(Vc) == BroadcastArray(Vt) == Vc == (Array(B)')[1:2,1:3]
    end

    @testset "copy" begin
        a = LazyArray(broadcasted(+, param(rand(3, 3)), 1))
        @test @inferred(copy(a)) isa BroadcastArray{<:Tracker.TrackedReal}

        a = randn(5)
        A = BroadcastArray(*, 2, a)
        @test copy(A) ≡ map(copy,A) ≡ A
        @test copy(A') ≡ A'
    end

    @testset "Number .* A" begin
        a = randn(5)
        A = BroadcastArray(*, 2, a)
        V = view(A,1:3)
        @test arguments(V) == (2,a[1:3])
        @test BroadcastArray(V) == V == 2a[1:3]
    end

    @testset "vec .* A" begin
        A = BroadcastArray(*, 1:3, randn(3,4))
        Ã = BroadcastArray(*, A.args[2],  1:3)
        B = randn(4,2)
        C = BroadcastArray(*, randn(4,2), randn(4,2))
        b = randn(2)
        @test A*B ≈ Matrix(A)*B
        @test Ã*B ≈ Matrix(Ã)*B
        @test A*C ≈ Matrix(A)*Matrix(C)
        @test Ã*C ≈ Matrix(Ã)*Matrix(C)
        @test A[:,2] ≈ Ã[:,2] ≈ Matrix(A)[:,2]
        @test C*b ≈ Matrix(C)*b
    end

    @testset "broadcasted which simplifies" begin
        a = BroadcastVector{Float64}(*, Zeros(10), randn(10))
        @test @inferred(a[1]) == 0.0
        @test @inferred(a[1:5]) ≡ Zeros(5)
        @test @inferred(a[[1,2,4]]) ≡ Zeros(3)
        @test broadcasted(a) ≡ Zeros(10)
        @test_throws TypeError Base.Broadcast.Broadcasted(a)
        @test broadcasted(view(a,1:3)) ≡ Zeros(3)
    end

    @testset "array-valued Broadcast" begin
        a = BroadcastArray(*, 1:3, [[1,2],[3,4],[5,6]])
        @test a == broadcast(*, 1:3, [[1,2],[3,4],[5,6]])
        @test a[2] == [6,8]
        @test a[1:2] == [[1,2], [6,8]]
    end

    @testset "submaterialize" begin
        a = BroadcastArray(/, randn(1000), 2)
        @test a[3:10] ≈ a.args[1][3:10]/2
        @test MemoryLayout(a') isa DualLayout{BroadcastLayout{typeof(/)}}
        @test (a')[:,3:10] isa Adjoint
        @test (a')[:,3:10] ≈ a[3:10]'

        @test BroadcastArray(view(a',1,3:10)) == a[3:10]
    end

    @testset "adjoint broadcast" begin
        a = BroadcastArray(exp, 1:5)
        b = randn(5)
        @test MemoryLayout(a') isa DualLayout{BroadcastLayout{typeof(exp)}}
        @test a'b ≈ Vector(a)'b
        @test BroadcastArray(a')b ≈ [a'b]
    end

    @testset "show" begin
        x = 1:3
        @test stringmime("text/plain", BroadcastArray(factorial, 1:3)) == "factorial.(3-element UnitRange{$Int}):\n 1\n 2\n 6"
        @test stringmime("text/plain", BroadcastArray(^, 1:3, 2)) == "(3-element UnitRange{$Int}) .^ $Int:\n 1\n 4\n 9"
        @test stringmime("text/plain", BroadcastArray(@~ x .^ 2)) == "(3-element UnitRange{$Int}) .^ 2:\n 1\n 4\n 9"
        @test stringmime("text/plain", BroadcastArray(@~ x .^ 2)') == "((3-element UnitRange{$Int}) .^ 2)':\n 1  4  9"
        @test stringmime("text/plain", transpose(BroadcastArray(@~ x .^ 2))) == "transpose((3-element UnitRange{$Int}) .^ 2):\n 1  4  9"

        if VERSION < v"1.6-"
            @test stringmime("text/plain", BroadcastArray(+, [1,2], 2)) == "(2-element Array{$Int,1}) .+ ($Int):\n 3\n 4"
            @test stringmime("text/plain", BroadcastArray(+, [1,2])) == "(+).(2-element Array{$Int,1}):\n 1\n 2"
            @test stringmime("text/plain", BroadcastArray(+, [1,2], 2)) == "(2-element Array{$Int,1}) .+ ($Int):\n 3\n 4"
            @test stringmime("text/plain", BroadcastArray(mod, [1,2], 2)) == "mod.(2-element Array{$Int,1}, $Int):\n 1\n 0"
        else
            @test stringmime("text/plain", BroadcastArray(+, [1,2], 2)) == "(2-element Vector{$Int}) .+ ($Int):\n 3\n 4"
            @test stringmime("text/plain", BroadcastArray(+, [1,2])) == "(+).(2-element Vector{$Int}):\n 1\n 2"
            @test stringmime("text/plain", BroadcastArray(+, [1,2], 2)) == "(2-element Vector{$Int}) .+ ($Int):\n 3\n 4"
            @test stringmime("text/plain", BroadcastArray(mod, [1,2], 2)) == "mod.(2-element Vector{$Int}, $Int):\n 1\n 0"
        end
    end

    @testset "offset indexing" begin
        v = BroadcastArray(+, SubArray(1:3, (Base.IdentityUnitRange(1:3),)), 1)
        @test axes(v) == (Base.IdentityUnitRange(1:3),)
        @test v[1] == 2
        @test stringmime("text/plain", v) == "(3-element view(::UnitRange{$Int}, :) with eltype $Int with indices 1:3) .+ ($Int) with indices 1:3:\n 2\n 3\n 4"
        @test stringmime("text/plain", v') == "((3-element view(::UnitRange{$Int}, :) with eltype $Int with indices 1:3) .+ ($Int) with indices 1:3)' with indices Base.OneTo(1)×1:3:\n 2  3  4"
        @test stringmime("text/plain", transpose(v)) == "transpose((3-element view(::UnitRange{$Int}, :) with eltype $Int with indices 1:3) .+ ($Int) with indices 1:3) with indices Base.OneTo(1)×1:3:\n 2  3  4"
    end

    @testset "Ref" begin
        A = BroadcastArray(norm, Ref([1,2]), [1,2])
        @test A == [norm([1,2],1), norm([1,2],2)]
        Ac = BroadcastArray(A')
        At = BroadcastArray(transpose(A))
        @test Ac == At == [norm([1,2],1) norm([1,2],2)]
    end

    @testset "large args tuple_type_memorylayouts" begin
        a = randn(5)
        @test MemoryLayout(BroadcastArray(+, a)) isa BroadcastLayout{typeof(+)}
        @test MemoryLayout(BroadcastArray(+, a, a)) isa BroadcastLayout{typeof(+)}
        @test MemoryLayout(BroadcastArray(+, a, a, a)) isa BroadcastLayout{typeof(+)}
        @test MemoryLayout(BroadcastArray(+, a, a, a, a)) isa BroadcastLayout{typeof(+)}
        @test MemoryLayout(BroadcastArray(+, a, a, a, a, a)) isa BroadcastLayout{typeof(+)}
        @test MemoryLayout(BroadcastArray(+, a, a, a, a, a, a)) isa BroadcastLayout{typeof(+)}
    end

    @testset "block array axes broadcasting" begin
        # Special cases to support non-allocating block sizes 1:N as in 2D polynomials
        n = BroadcastArray(Fill, Base.OneTo(5), Base.OneTo(5))
        k = BroadcastArray(Base.OneTo,Base.OneTo(5))
        z = BroadcastArray(Zeros, Base.OneTo(5))
        v = BroadcastArray(Vcat, n, k)
        @test map(length, n) ≡ map(length, k) ≡ map(length, z) ≡ Base.OneTo(5)
        @test map(length, v) ≡ 2:2:10
        @test map(length, BroadcastArray(Fill,Base.OneTo(5))) == ones(5)

        @test broadcast(length, n) ≡ broadcast(length, k) ≡ Base.OneTo(5)
    end
end


text:
using DataFrames: DataFrame

struct ROOTDirectory
    name::AbstractString
    header::ROOTDirectoryHeader
    keys::Vector{TKey}
end

struct ROOTFile
    filename::AbstractString
    format_version::Int32
    header::FileHeader
    fobj::IOStream
    tkey::TKey
    streamers::Streamers
    directory::ROOTDirectory
    branch_cache::Dict{String, TBranch}
end

function ROOTFile(filename::AbstractString)
    fobj = Base.open(filename)
    preamble = unpack(fobj, FilePreamble)
    String(preamble.identifier) == "root" || error("Not a ROOT file!")
    format_version = preamble.fVersion

    if format_version < 1000000
        @debug "32bit ROOT file"
        header = unpack(fobj, FileHeader32)
    else
        @debug "64bit ROOT file"
        header = unpack(fobj, FileHeader64)
    end

    # Streamers
    if header.fSeekInfo != 0
        @debug "Reading streamer info."
        seek(fobj, header.fSeekInfo)
        streamers = Streamers(fobj)
    else
        @debug "No streamer info present, skipping."
    end

    seek(fobj, header.fBEGIN)
    tkey = unpack(fobj, TKey)

    # Reading the header key for the top ROOT directory
    seek(fobj, header.fBEGIN + header.fNbytesName)
    dir_header = unpack(fobj, ROOTDirectoryHeader)
    if dir_header.fSeekKeys == 0
        ROOTFile(format_version, header, fobj, tkey, [])
    end

    seek(fobj, dir_header.fSeekKeys)
    header_key = unpack(fobj, TKey)

    n_keys = readtype(fobj, Int32)
    keys = [unpack(fobj, TKey) for _ in 1:n_keys]

    directory = ROOTDirectory(tkey.fName, dir_header, keys)

    ROOTFile(filename, format_version, header, fobj, tkey, streamers, directory, Dict())
end

function Base.show(io::IO, f::ROOTFile)
    n_entries = length(f.directory.keys)
    entries_suffix = n_entries == 1 ? "entry" : "entries"
    n_streamers = length(f.streamers)
    streamers_suffix = n_streamers == 1 ? "streamer" : "streamers"
    print(io, typeof(f))
    print(io, "(\"$(f.filename)\") with $n_entries $entries_suffix ")
    print(io, "and $n_streamers $streamers_suffix.")
end

UUID(f::ROOTFile) = f.header.fUUID

function streamerfor(f::ROOTFile, name::AbstractString)
    for e in f.streamers.elements
        if e.streamer.fName == name
            return e
        end
    end
    error("No streamer found for $name.")
end

function Base.getindex(f::ROOTFile, s::AbstractString)
    if '/' ∈ s
        @debug "Splitting path '$s' and getting items recursively"
        paths = split(s, '/')
        return f[first(paths)][join(paths[2:end], "/")]
    end
    tkey = f.directory.keys[findfirst(isequal(s), keys(f))]
    @debug "Retrieving $s ('$(tkey.fClassName)')"
    streamer = getfield(@__MODULE__, Symbol(tkey.fClassName))
    streamer(f.fobj, tkey, f.streamers.refs)
end

function Base.keys(f::ROOTFile)
    keys(f.directory)
end

function Base.keys(d::ROOTDirectory)
    [key.fName for key in d.keys]
end

function Base.keys(b::TBranchElement)
    [branch.fName for branch in b.fBranches.elements]
end

function Base.get(f::ROOTFile, k::TKey)
end

Base.keys(t::TTree) = [b.fName for b in t.fBranches.elements]

function Base.getindex(t::T, s::AbstractString) where {T<:Union{TTree, TBranchElement}}
    if '/' ∈ s
        @debug "Splitting path '$s' and getting branches recursively"
        paths = split(s, '/')
        return t[first(paths)][join(paths[2:end], "/")]
    end
    @debug "Searching for branch '$s' in $(length(t.fBranches.elements)) branches."
    for branch in t.fBranches.elements
        @debug branch.fName
        if branch.fName == s
            return branch
        end
    end
    missing
end
"""
    function array(f::ROOTFile, path)

Reads an array from a branch. Currently hardcoded to Int32
"""
function array(f::ROOTFile, path; raw=false)
    if path ∈ keys(f.branch_cache)
        branch = f.branch_cache[path]
    else
        branch = f[path]
        if ismissing(branch)
            error("No branch found at $path")
        end
    end

    if raw
        return readbasketsraw(f.fobj, branch)
    end

    if length(branch.fLeaves.elements) > 1
        error("Branches with multiple leaves are not supported yet.")
    end

    leaf = first(branch.fLeaves.elements)

    readbaskets(f.fobj, branch, primitivetype(leaf))
end

"""
    function DataFrame(f::ROOTFile, path)

Reads a tree into a dataframe
"""
function DataFrame(f::ROOTFile, path)
    names = keys(f[path])
    cols = [array(f, path * "/" * n) for n in names]
    for each in cols
        eltype(each) <: Number || error("Jagged array cannot be put into a dataframe")
    end
    DataFrame(cols, names, copycols=false) #avoid double allocation
end

function splitup(data::Vector{UInt8}, offsets, T::Type; skipbytes=0, primitive=false)
    elsize = packedsizeof(T)
    out = sizehint!(Vector{Vector{T}}(), length(offsets))
    lengths = diff(offsets)
    push!(lengths, length(data) - offsets[end] + offsets[1])  # yay ;)
    io = IOBuffer(data)
    for (idx, l) in enumerate(lengths)
        # println("$idx / $(length(lengths))")
        if primitive
            error("primitive interpretation is buggy")
            push!(out, reinterpret(T, data[skipbytes+1:skipbytes+Int32((l - skipbytes))]))
        else
            skip(io, skipbytes)
            n = (l - skipbytes) / elsize
            push!(out, [readtype(io, T) for _ in 1:n])
        end
    end
    out
end

function readbaskets(io, branch, ::Type{T}) where {T}
    seeks = branch.fBasketSeek
    entries = branch.fBasketEntry

    out = sizehint!(Vector{T}(), branch.fEntries)

    for (idx, basket_seek) in enumerate(seeks)
        @debug "Reading basket" idx basket_seek
        if basket_seek == 0
            break
        end
        seek(io, basket_seek)
        basketkey = unpack(io, TBasketKey)
        s = datastream(io, basketkey)

        for _ in entries[idx]:(entries[idx + 1] - 1)
            push!(out, readtype(s, T))
        end
    end
    out
end

function readbasketsraw(io, branch)
    seeks = branch.fBasketSeek
    bytes = branch.fBasketBytes

    total_entries = branch.fEntries
    # Just to check if we have a jagged structure
    # streamer = streamerfor()

    data = sizehint!(Vector{UInt8}(), sum(bytes))
    offsets = sizehint!(Vector{Int32}(), total_entries)
    idx = 1
    for (basket_seek, n_bytes) in zip(seeks, bytes)
        @debug "Reading raw basket data" basket_seek n_bytes
        if basket_seek == 0
            break
        end
        seek(io, basket_seek)
        idx += readbasketbytes!(data, offsets, io, idx)
    end
    data, offsets
end

function readoffsets!(out, s, contentsize, global_offset, local_offset)
    for _ in 1:contentsize
        offset = readtype(s, Int32) + global_offset
        push!(out, offset)
    end
end

function readbasketbytes!(data, offsets, io, idx)
    basketkey = unpack(io, TBasketKey)

    # @show basketkey
    s = datastream(io, basketkey)  # position(s) == 0, but offsets start at -basketkey.fKeylen
    start = position(s)
    # @show start
    contentsize = basketkey.fLast - basketkey.fKeylen
    offsetlength = basketkey.fObjlen - contentsize

    if offsetlength > 0
        @debug "Offset data present" offsetlength
        skip(s, contentsize)
        skip(s, 4)
        readoffsets!(offsets, s, (offsetlength - 8) / 4, length(data), length(data))
        # https://groups.google.com/forum/#!topic/polyglot-root-io/yeC0mAizQcA
        skip(s, 4)  # "Pointer-to/location-of last used byte in basket"
        seek(s, start)
    end

    @debug "Reading $(contentsize) bytes"
    readbytes!(s, data, idx, contentsize)
    # for _ in 1:contentsize
    #     push!(data, readtype(s, UInt8))
    # end
    contentsize
end

"""
    function readbytes!(io, b, offset, nr)

Efficient read of bytes into an existing array at a given offset
"""
function readbytes!(io, b, offset, nr)
    resize!(b, offset + nr - 1)
    nb = UInt(nr)
    GC.@preserve b unsafe_read(io, pointer(b, offset), nr)
end


text:
using Redis
import DataStructures: OrderedSet

if VERSION >= v"0.7"
    using Test
else
    using BaseTestNext
    const Test = BaseTestNext
end

include(joinpath(dirname(@__FILE__),"client_tests.jl"))
include(joinpath(dirname(@__FILE__),"redis_tests.jl"))


text:
using Base.Test
using ThermodynamicsTable
include("maintest.jl")
include("freesteam.jl")


text:
module HonlyHelperGothTattle
using ..Ahorn, Maple

@mapdef Trigger "HonlyHelper/GothTattle" GothTattle(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, GothDialogID::String="GothID", DialogAmount::Integer=1,Loops::Bool=false)

const placements = Ahorn.PlacementDict(
    "Badeline Tattle Zone (HonlyHelper)" => Ahorn.EntityPlacement(
        GothTattle,
        "rectangle",
    ),
)

end

max_stars_repo_name: HollyMagala/HonlyHelper

max_issues_repo_name: HollyMagala/HonlyHelper

max_forks_repo_name: HollyMagala/HonlyHelper


text:
# pi computation for multithreading using Threads macro

using Base.Threads
import Base.Threads.Atomic

function thread_pi(NBIN::Int=100000)::Float64
    step_size = 1.0/NBIN
    pi_sum = Atomic{Float64}(0.0)
    Threads.@threads for i in 1:NBIN
        x = (i+0.5)*step_size
        Threads.atomic_add!(pi_sum, 4.0/(1.0+x*x))
    end
    pi_result = step_size*pi_sum[]
    return pi_result
end

@time @show thread_pi()

max_stars_repo_name: naezzell/accelqat

max_issues_repo_name: naezzell/accelqat

max_forks_repo_name: naezzell/accelqat


text:
module Runtests

# Run all tests with SilentNoPlot (so not plots)

using Modia
using Modia.Test

const  test_title = "Test Modia (version=$(Modia.Version) with SilentNoPlot)"
println("\n... $test_title")

@time @testset verbose=true "$test_title" begin
    usePlotPackage("SilentNoPlot")
    include("include_all.jl")
    usePreviousPlotPackage()
end

end


text:
export marginalrule

@marginalrule NormalMeanPrecision(:out_μ_τ) (m_out::UnivariateNormalDistributionsFamily, m_μ::PointMass, m_τ::PointMass) = begin
    return (out = prod(ProdAnalytical(), NormalMeanPrecision(mean(m_μ), mean(m_τ)), m_out), μ = m_μ, τ = m_τ)
end

@marginalrule NormalMeanPrecision(:out_μ_τ) (m_out::PointMass, m_μ::UnivariateNormalDistributionsFamily, m_τ::PointMass) = begin
    return (out = m_out, μ = prod(ProdAnalytical(), m_μ, NormalMeanPrecision(mean(m_out), mean(m_τ))), τ = m_τ)
end

@marginalrule NormalMeanPrecision(:out_μ) (m_out::UnivariateNormalDistributionsFamily, m_μ::UnivariateNormalDistributionsFamily, q_τ::Gamma) = begin
    W_out  = invcov(m_out)
    W_μ    = invcov(m_μ)
    xi_out = W_out * mean(m_out)
    xi_μ   = W_μ * mean(m_μ)

    W_bar = mean(q_τ)

    W = [ W_out + W_bar -W_bar; -W_bar W_μ + W_bar ]
    m = cholinv(W) * [ xi_out; xi_μ ]

    return MvNormalMeanPrecision(m, W)
end


text:
module HyperParameters

import Base: convert, eltype, promote_type, show, string, ==, *, /, +, -, ^, isless, depwarn

export
    Bound,
        LeftBound,
        RightBound,
        NullBound,

    Interval,
    interval,
    checkbounds,

    HyperParameter,
    getvalue,
    setvalue!,
    checkvalue,
    gettheta,
    settheta!,
    checktheta,
    upperboundtheta,
    lowerboundtheta

#= bound.jl =#
abstract type Bound{T} end

eltype(::Bound{T}) where {T} = T

struct OpenBound{T<:Real} <: Bound{T}
    value::T
    function OpenBound{T}(x::Real) where {T<:Real}
        !(T <: Integer) || error("Bounds must be closed for integers")
        if T <: AbstractFloat
            !isnan(x) || error("Bound value must not be NaN")
            !isinf(x) || error("Bound value must not be Inf/-Inf")
        end
        new{T}(x)
    end
end
OpenBound(x::T) where {T<:Real} = OpenBound{T}(x)

convert(::Type{OpenBound{T}}, b::OpenBound{T}) where {T<:Real} = b
convert(::Type{OpenBound{T}}, b::OpenBound) where {T<:Real} = OpenBound{T}(b.value)
string(b::OpenBound) = string("OpenBound(", b.value, ")")

struct ClosedBound{T<:Real} <: Bound{T}
    value::T
    function ClosedBound{T}(x::Real) where {T<:Real}
        if T <: AbstractFloat
            !isnan(x) || error("Bound value must not be NaN")
            !isinf(x) || error("Bound value must not be Inf/-Inf")
        end
        new{T}(x)
    end
end
ClosedBound(x::T) where {T<:Real} = ClosedBound{T}(x)

convert(::Type{ClosedBound{T}}, b::ClosedBound{T}) where {T<:Real} = b
convert(::Type{ClosedBound{T}}, b::ClosedBound) where {T<:Real} = ClosedBound{T}(b.value)
string(b::ClosedBound) = string("ClosedBound(", b.value, ")")

struct NullBound{T<:Real} <: Bound{T} end
NullBound(::Type{T}) where {T<:Real} = NullBound{T}()

convert(::Type{NullBound{T}}, b::NullBound{T}) where {T<:Real} = b
convert(::Type{NullBound{T}}, b::NullBound) where {T<:Real} = NullBound{T}()
string(b::NullBound{T}) where {T} = string("NullBound(", T, ")")

checkvalue(a::NullBound,   x::Real) = true
checkvalue(a::OpenBound,   x::Real) = a.value <  x
checkvalue(a::ClosedBound, x::Real) = a.value <= x

checkvalue(x::Real, a::NullBound)   = true
checkvalue(x::Real, a::OpenBound)   = x <  a.value
checkvalue(x::Real, a::ClosedBound) = x <= a.value

promote_rule(::Type{Bound{T1}},::Type{Bound{T2}}) where {T1,T2} = Bound{promote_rule(T1,T2)}

function show(io::IO, b::T) where {T<:Bound}
    print(io, string(b))
end

#= interval.jl =#

struct Interval{T<:Real,A<:Bound{T},B<:Bound{T}}
    a::A
    b::B
    function Interval{T}(a::A, b::B) where {T<:Real,A<:Bound{T},B<:Bound{T}}
        if !(A <: NullBound || B <: NullBound)
            va = a.value
            vb = b.value
            if A <: ClosedBound && B <: ClosedBound
                va <= vb || error("Invalid bounds: a=$va must be less than or equal to b=$vb")
            else
                va < vb || error("Invalid bounds: a=$va must be less than b=$vb")
            end
        end
        new{T,A,B}(a,b)
    end
end
Interval(a::Bound{T}, b::Bound{T}) where {T<:Real} = Interval{T}(a,b)

eltype(::Interval{T}) where {T} = T

interval(a::Nothing, b::Nothing) = Interval(NullBound{Float64}(), NullBound{Float64}())
interval(a::Bound{T}, b::Nothing) where {T<:Real} = Interval(a, NullBound{T}())
interval(a::Nothing, b::Bound{T}) where {T<:Real} = Interval(NullBound{T}(), b)
interval(a::Bound{T}, b::Bound{T}) where {T<:Real} = Interval(a,b)
interval(::Type{T}) where {T<:Real} = Interval(NullBound{T}(), NullBound{T}())

checkvalue(I::Interval, x::Real) = checkvalue(I.a, x) && checkvalue(x, I.b)

function theta(I::Interval{T,A,B}, x::T) where {T<:AbstractFloat,A,B}
    depwarn("theta will be removed entirely in a future release", :theta)
    checkvalue(I,x) || throw(DomainError(x, "Not in $I"))
    if A <: OpenBound
        return B <: OpenBound ? log(x-I.a.value) - log(I.b.value-x) : log(x-I.a.value)
    else
        return B <: OpenBound ? log(I.b.value-x) : x
    end
end

function upperboundtheta(I::Interval{T,A,B}) where {T<:AbstractFloat,A,B}
    if B <: ClosedBound
        return A <: OpenBound ? log(I.b.value - I.a.value) : I.b.value
    elseif B <: OpenBound
        return A <: ClosedBound ? log(I.b.value - I.a.value) : convert(T,Inf)
    else
        return convert(T,Inf)
    end
end

function lowerboundtheta(I::Interval{T,A,B}) where {T<:AbstractFloat,A,B}
    A <: ClosedBound && !(B <: OpenBound) ? I.a.value : convert(T,-Inf)
end

function checktheta(I::Interval{T}, x::T) where {T<:AbstractFloat}
    lowerboundtheta(I) <= x <= upperboundtheta(I)
end

function eta(I::Interval{T,A,B}, x::T) where {T<:AbstractFloat,A,B}
    depwarn("eta will be removed entirely in a future release", :eta)
    checktheta(I,x) || throw(DomainError(x, "Not in $I"))
    if A <: OpenBound
        if B <: OpenBound
            return (I.b.value*exp(x) + I.a.value)/(one(T) + exp(x))
        else
            return exp(x) + I.a.value
        end
    else
        return B <: OpenBound ? I.b.value - exp(x) : x
    end
end

function string(I::Interval{T1,T2,T3}) where {T1,T2,T3}
    if T2 <: NullBound
        if T3 <: NullBound
            string("interval(", T1, ")")
        else
            string("interval(nothing,", string(I.b), ")")
        end
    else
        string("interval(", string(I.a), ",", T3 <: NullBound ? "nothing" : string(I.b), ")")
    end
end

function show(io::IO, I::Interval)
    print(io, string(I))
end

#= hyperparameter.jl =#

struct HyperParameter{T<:Real}
    value::Base.RefValue{T}
    interval::Interval{T}
    function HyperParameter{T}(x::T, I::Interval{T}) where {T<:Real}
        checkvalue(I, x) || error("Value $(x) must be in range " * string(I))
        new{T}(Ref(x), I)
    end
end
HyperParameter(x::T, I::Interval{T} = interval(T)) where {T<:Real} = HyperParameter{T}(x, I)

eltype(::HyperParameter{T}) where {T} = T

@inline getvalue(θ::HyperParameter{T}) where {T} = getindex(θ.value)

function setvalue!(θ::HyperParameter{T}, x::T) where {T}
    checkvalue(θ.interval, x) || error("Value $(x) must be in range " * string(θ.interval))
    setindex!(θ.value, x)
    return θ
end

checkvalue(θ::HyperParameter{T}, x::T) where {T} = checkvalue(θ.interval, x)

convert(::Type{HyperParameter{T}}, θ::HyperParameter{T}) where {T<:Real} = θ
function convert(::Type{HyperParameter{T}}, θ::HyperParameter) where {T<:Real}
    HyperParameter{T}(convert(T, getvalue(θ)), convert(Interval{T}, θ.bounds))
end

function show(io::IO, θ::HyperParameter{T}) where {T}
    print(io, string("HyperParameter(", getvalue(θ), ",", string(θ.interval), ")"))
end

function gettheta(θ::HyperParameter)
    depwarn("gettheta will be removed entirely in a future release", :gettheta)
    theta(θ.interval, getvalue(θ))
end

function settheta!(θ::HyperParameter, x::T) where {T}
    depwarn("settheta! will be removed entirely in a future release", :(settheta!))
    setvalue!(θ, eta(θ.interval,x))
end

function checktheta(θ::HyperParameter, x::T) where {T}
    depwarn("checktheta will be removed entirely in a future release", :checktheta)
    checktheta(θ.interval, x)
end

for op in (:isless, :(==), :+, :-, :*, :/)
    @eval begin
        $op(θ1::HyperParameter, θ2::HyperParameter) = $op(getvalue(θ1), getvalue(θ2))
        $op(a::Number, θ::HyperParameter) = $op(a, getvalue(θ))
        $op(θ::HyperParameter, a::Number) = $op(getvalue(θ), a)
    end
end

end # End HyperParameter


text:
# So that this test can be run independently
using Cairo
using Base64

include("shape_functions.jl")

@testset "Test that writing images to a Julia IO object works" begin
    c = CairoRGBSurface(256,256)
    cr = CairoContext(c)
    ddots4(cr,256,246,1.0,3000)
    buf = IOBuffer()
    pipe = Base64EncodePipe(buf)
    write_to_png(c,pipe)
    close(pipe)

    # Catch short writes

    str = String(take!(buf))
    str_data = codeunits(str)

    @test length(str_data) > 200
end

@testset "Test that writing images to a temp file works" begin
    c = CairoRGBSurface(256,256)
    cr = CairoContext(c)
    ddots4(cr,256,246,1.0,3000)
    fn = tempname()*".png"
    @test write_to_png(c,fn) == Cairo.STATUS_SUCCESS
    @test isfile(fn)
    rm(fn)  # clean up
end


text:
using Distributions
using Test
using DataFrames
using CSVFiles
using DataStructures

################################################################################
## SET CONSTANTS
################################################################################
ATOL = 1e-9
ATOL_CI = 1e-2

################################################################################
## JULIA
################################################################################
include("../src/utils.jl")
include("../src/sample_sobol.jl")
include("../src/analyze_sobol.jl")
include("../src/test_functions/ishigami.jl")

# define the (uncertain) parameters of the problem and their distributions
data = SobolData(
    params = OrderedDict(:x1 => Normal(1, 0.2),
        :x2 => Uniform(0.75, 1.25),
        :x3 => LogNormal(0, 0.5)),
    N = 1000
)

N = data.N
D = length(data.params)

# sampling
julia_samples = sample(data) |> DataFrame
julia_ishigami = ishigami(convert(Matrix, julia_samples)) |> DataFrame

# save this DataFrame for Mimi Testing
# names!(julia_saltelli, Symbol.(params.names))
# save("/Users/lisarennels/JuliaProjects/SAJulia/test/data/nonuniform_samples.csv", julia_saltelli)

# analysis
julia_A, julia_B, julia_AB, julia_BA = split_output(convert(Matrix, julia_ishigami), N, D, data.calc_second_order)
julia_results = analyze(data, convert(Matrix, julia_ishigami), num_resamples = 10_000)

################################################################################
## Python
################################################################################

# sampling
py_samples = load("data/py_nonuniform/py_samples.csv", header_exists=false, colnames = ["x1", "x2", "x3"]) |> DataFrame
py_ishigami = load("data/py_nonuniform/py_ishigami.csv", header_exists=false) |> DataFrame

# analysis
py_A = load("data/py_nonuniform/py_A.csv", header_exists=false) |> DataFrame
py_B = load("data/py_nonuniform/py_B.csv", header_exists=false) |> DataFrame
py_AB = load("data/py_nonuniform/py_AB.csv", header_exists=false) |> DataFrame
py_BA = load("data/py_nonuniform/py_BA.csv", header_exists=false) |> DataFrame

py_firstorder = load("data/py_nonuniform/py_firstorder.csv", header_exists=false) |> DataFrame
py_secondorder = load("data/py_nonuniform/py_secondorder.csv", header_exists=false) |> DataFrame
py_totalorder = load("data/py_nonuniform/py_totalorder.csv", header_exists=false) |> DataFrame

py_firstorder_conf = load("data/py_nonuniform/py_firstorder_conf.csv", header_exists=false) |> DataFrame
py_secondorder_conf = load("data/py_nonuniform/py_secondorder_conf.csv", header_exists=false) |> DataFrame
py_totalorder_conf = load("data/py_nonuniform/py_totalorder_conf.csv", header_exists=false) |> DataFrame

################################################################################
## Testing
################################################################################

@testset "Non-Uniform Sampling" begin
    @test convert(Matrix, julia_samples) ≈ convert(Matrix, py_samples) atol = ATOL
end

@testset "Non-Uniform Analysis" begin

    @test convert(Matrix, julia_ishigami) ≈ convert(Matrix, py_ishigami) atol = ATOL
    @test julia_A ≈ convert(Matrix, py_A) atol = ATOL
    @test julia_B ≈ convert(Matrix, py_B) atol = ATOL
    @test julia_AB ≈ convert(Matrix, py_AB) atol = ATOL
    @test julia_BA ≈ convert(Matrix, py_BA) atol = ATOL

    @test julia_results[:firstorder] ≈ convert(Matrix, py_firstorder) atol = ATOL
    @test julia_results[:totalorder]≈ convert(Matrix, py_totalorder) atol = ATOL

    for i = 1:D
        for j = i+1:D
            @test julia_results[:secondorder][i,j] ≈ convert(Matrix, py_secondorder)[i,j] atol = ATOL
        end
    end

    # test confidence intervals (using rtol here, big values throw things off)
    @test julia_results[:firstorder_conf] ≈ convert(Matrix, py_firstorder_conf) atol = ATOL_CI
    @test julia_results[:totalorder_conf] ≈ convert(Matrix, py_totalorder_conf) atol = ATOL_CI

    for i = 1:D
        for j = i+1:D
            @test julia_results[:secondorder_conf][i,j] ≈ convert(Matrix, py_secondorder_conf)[i,j] atol = ATOL_CI
        end
    end

end


text:
using Stride
using Base.Test

download("https://files.rcsb.org/download/1CRN.pdb", "1crn.pdb")

@testset "Secondary Strucure Assignment" begin
    data = stride_run("1crn.pdb")

    @test data.chain[2].name == "THR"
    @test data.chain[1].ss_type == 'C'
    @test data.chain[2].ss_type == 'E'
    @test data.chain[7].ss_type_full == "AlphaHelix"
end

@testset "File handling" begin
    data = stride_run("1crn.pdb", out_path="1crn_result")

    @test isfile("1crn_result")

    if isfile("1crn_result")
        rm("1crn_result")
    end
end

if isfile("1crn.pdb")
    rm("1crn.pdb")
end


text:
is_ch_type(::Val{:SimpleAggregateFunction})  = true
result_type(::Val{:SimpleAggregateFunction},
            aggr_name,
            base_type::TypeAst) = result_type(base_type)

function read_col_data(sock::ClickHouseSock,
                num_rows::VarUInt, ::Val{:SimpleAggregateFunction},
                aggr_name, base_type::TypeAst)

    return read_col_data(sock, num_rows, base_type)
end

function write_col_data(sock::ClickHouseSock,
                data, ::Val{:SimpleAggregateFunction},
                aggr_name, base_type::TypeAst)

    write_col_data(sock, data, base_type)
end


text:
module SyntheticGrids

# This needs to be set before `using PyCall` otherwise the numba library won't see it
# at load time ? :/
ENV["NUMBA_DISABLE_JIT"] = 1

using PyCall
using JSON
using JLD
using CSV
using AutoHashEquals
using Geodesy

const pp = PyNULL()

# https://github.com/JuliaPy/PyCall.jl#using-pycall-from-julia-modules
function __init__()
    copy!(pp, pyimport("pandapower"))
end

export
###### Types ######
Bus,
LoadBus,
GenBus,
Generator,
TransLine,
Substation,
Grid,
###### Main Functions ######
connect!,
cluster!,
create_lines!,
place_loads_from_zips!,
place_gens_from_data!,
add_load!,
add_gen!,
add_substation!,
###### Export Functions ######
to_pandapower,
###### Check Functions ######
total_links,
mean_node_deg,
cluster_coeff,
test_connectivity,
mean_shortest_path,
robustness_line,
robustness_node,
###### Getters ######
distance,
coords,
voltage,
technology,
capacity,
power_factor,
minimum_load,
summer_capacity,
winter_capacity,
status,
generators,
trans_lines,
population,
neighbors,
buses,
substations,
adjacency,
sub_connectivity,
end_points,
impedance

import Base.==
import Base.show
import Base.hash
import Base.mean
import Base.merge!
global const PREC = 1.0e-6 # Precision for random number generation
global const LARGE_GRID_N = 2000 # defines what is considered a large grid
abstract type Bus end

include("transline.jl")
include("generator.jl")
include("bus.jl")
include("distances.jl")
include("substation.jl")
include("grid.jl")
include("clustering.jl")
include("io.jl")
include("misc.jl")

end


text:
"""
    sample mean
"""
function sample_mean(X)
    N = length(X)
    n = length(X[1])
    μ = sum(X) ./ N
    return μ
end

"""
    sample covariance
"""
function sample_covariance(X, β)
    N = length(X)
    μ = sample_mean(X)
    P = sum([(X[i] - μ) * (X[i] - μ)' for i = 1:N]) ./ (2.0 * β^2.0)
    return P
end

"""
    deterministic sampling
"""
function resample(X, β)
    n = length(X[1])
    μ = sample_mean(X)
    P = sample_covariance(X, β)
    cols = sqrt(P)
    Xs = [μ + s * β * cols[:,i] for s in [-1.0, 1.0] for i = 1:n]
    return Xs
end

function resample_vec(X, n, N, β)
    _X = [X[(i - 1) * n .+ (1:n)] for i = 1:N]
    return vcat(resample(_X, β)...)
end

function resample_vec(X, n, N, β, k)
    _X = [X[(i - 1) * n .+ (1:n)] for i = 1:N]
    Xs = resample(_X, β)
    return Xs[k]
end

function resample(μ, P, β::T) where T
    n = length(μ)
    cols = sqrt(P)
    Xs = [μ + s * β * cols[:,i] for s in [-1.0, 1.0] for i = 1:n]
    return Xs
end

max_stars_repo_name: zacmanchester/DirectMotionPlanning

max_issues_repo_name: zacmanchester/DirectMotionPlanning

max_forks_repo_name: zacmanchester/DirectMotionPlanning