text:
# © 2016 Massachusetts Institute of Technology.  See LICENSE file for details.
__precompile__(false)
module LLVM

function __init__()
  global const llvmcore = Libdl.dlopen("libLLVMCore.so")
  global const llvmbitwriter = Libdl.dlopen("libLLVMBitWriter.so")

  for i in check_syms
    Libdl.dlsym(eval(i[1]), i[2])
  end
end

lib = :llvmcore
fun_prefix = "LLVM"

for t in [:Context, :MemoryBuffer, :Module, :Type, :Value, :BasicBlock, :Use, :Builder, :Message]
  tt = symbol(t, "Ref")
  @eval immutable $tt ptr::Ptr{Void} end
end

include("fun.jl")

macro aget(getter, lengetter, intype, outtype)
  quote
    @fun $(esc(lengetter))(v::$intype)::Cuint
    @fun $(esc(getter))(v::$intype, a::Vector{$outtype})::Void = (v, a::Ptr{$outtype})
    function $(esc(getter))(v::$intype)
      a = Array($outtype, $lengetter(v))
      $(esc(getter))(v, a)
      return a
    end
  end
end

macro iter(suffix, t1, t2)
  quote
    @fun $(esc(symbol("GetFirst", suffix)))(v::$t2)::$t1
    @fun $(esc(symbol("GetLast", suffix)))(v::$t2)::$t1
    @fun $(esc(symbol("GetNext", suffix)))(v::$t1)::$t1
    @fun $(esc(symbol("GetPrevious", suffix)))(v::$t1)::$t1
  end
end

# Core
#@fun CreateMessage(msg::AbstractString)::MessageRef = (msg::Cstring,)
#@fun DisposeMessage(msg::MessageRef)::Void
#dispose(msg::MessageRef) = DisposeMessage(msg)
#Base.bytestring(msg::MessageRef) = bytestring(reinterpret(Ptr{UInt8}, msg.ptr))
#Base.string(msg::MessageRef) = bytestring(msg)

# Context
@fun ContextCreate()::ContextRef
@fun GetGlobalContext()::ContextRef
@fun ContextDispose(c::ContextRef)::Void
@fun GetMDKindIDInContext(name::AbstractString)::Cuint = (name::Cstring, length(name)::Cuint)
@fun GetMDKindIDInContext(c::ContextRef, name::AbstractString)::Cuint = (c, name::Cstring, length(name)::Cuint)

ContextRef() = ContextCreate()
dispose(c::ContextRef) = ContextDispose(c)

# Memory Buffer
#@fun GetBufferStart(m::MemoryBufferRef)::Ptr{UInt8}
#@fun GetBufferSize(m::MemoryBufferRef)::Csize_t
#@fun DisposeMemoryBuffer(m::MemoryBufferRef)::Void
#dispose(m::MemoryBufferRef) = DisposeMemoryBuffer(m)
#function getbuffer(m::MemoryBufferRef)
#  data = copy(pointer_to_array(GetBufferStart(m), GetBufferSize(m)))
#  DisposeMemoryBuffer(m)
#  return data
#end

# Metadata
@fun MDString(s::AbstractString)::ValueRef = (s::Cstring, length(s)::Cuint)
@fun MDStringInContext(c::ContextRef, s::AbstractString)::ValueRef = (c, s::Cstring, length(s)::Cuint)
@fun MDNode(vals::Vector{ValueRef})::ValueRef = (vals::Ptr{ValueRef}, length(vals)::Cuint)
@fun MDNodeInContext(c::ContextRef, vals::Vector{ValueRef})::ValueRef = (c, vals::Ptr{ValueRef}, length(vals)::Cuint)
@fun GetMDString(v::ValueRef, len::Vector{Cuint})::Cstring = (v, len::Ptr{Cuint})
@aget GetMDNodeOperands GetMDNodeNumOperands ValueRef ValueRef

# Module
@fun ModuleCreateWithName(s::AbstractString)::ModuleRef = (s::Cstring,)
@fun ModuleCreateWithNameInContext(c::ContextRef, s::AbstractString)::ModuleRef = (c, s::Cstring,)
#@fun CloneModule(m::ModuleRef)::ModuleRef
@fun DisposeModule(m::ModuleRef)::Void
@fun AddFunction(mod::ModuleRef, name::AbstractString, llvmtype::TypeRef)::ValueRef = (mod, name::Cstring, llvmtype)
@fun GetNamedFunction(mod::ModuleRef, name::AbstractString)::ValueRef = (mod, name::Cstring)
@iter Function ValueRef ModuleRef
@fun DumpModule(m::ModuleRef)::Void
#@fun PrintModuleToString(m::ModuleRef)::MessageRef

#Base.string(m::ModuleRef) = bytestring(PrintModuleToString(m))

@fun GetDataLayout(m::ModuleRef)::Cstring
@fun SetDataLayout(m::ModuleRef, layout::AbstractString)::Void = (m, layout::Cstring)
@fun GetTarget(m::ModuleRef)::Cstring
@fun SetTarget(m::ModuleRef, triple::AbstractString)::Void = (m, triple::Cstring)

SetDataLayout(m::ModuleRef, layout::AbstractArray) = SetDataLayout(m, join(layout, "-"))

@fun GetNamedMetadataNumOperands(m::ModuleRef, name::AbstractString)::Cuint = (m, name::Cstring)
@fun GetNamedMetadataOperands(m::ModuleRef, name::AbstractString, out::Vector{ValueRef})::Void = (m, name::Cstring, out::Ptr{ValueRef})
@fun AddNamedMetadataOperand(m::ModuleRef, name::AbstractString, val::ValueRef)::Void = (m, name::Cstring, val)

ModuleRef(name::AbstractString) = ModuleCreateWithName(name)
ModuleRef(c::ContextRef, name::AbstractString) = ModuleCreateWithNameInContext(c, name)
#Base.copy(m::ModuleRef) = CloneModule(m)
dispose(m::ModuleRef) = DisposeModule(m)

lib = :llvmbitwriter
#@fun WriteBitcodeToMemoryBuffer(m::ModuleRef)::MemoryBufferRef
@fun WriteBitcodeToFile(m::ModuleRef, path::AbstractString)::MemoryBufferRef = (m, path::Cstring)

lib = :llvmcore
# Type

## Float, Int, and Other types

@fun IntType(width::Integer)::ValueRef = (width::Cuint,)
@fun IntTypeInContext(c::ContextRef, width::Integer)::ValueRef = (c, width::Cuint)
@fun GetIntTypeWidth(t::TypeRef)::Cint

for t in [8,16,32,64] # 128
  @eval @fun $(symbol("Int", t, "Type"))()::TypeRef
  @eval @fun $(symbol("Int", t, "TypeInContext"))(c::ContextRef)::TypeRef

  @eval TypeRef(::Type{$(symbol("Int", t))}) = $(symbol("Int", t, "Type"))()
  @eval Base.convert(::Type{TypeRef}, ::Type{$(symbol("Int", t))}) = $(symbol("Int", t, "Type"))()

  @eval TypeRef(::Type{$(symbol("UInt", t))}) = $(symbol("Int", t, "Type"))()
  @eval Base.convert(::Type{TypeRef}, ::Type{$(symbol("UInt", t))}) = $(symbol("Int", t, "Type"))()
end

for t in [:Int1, :Void, :Label, :X86MMX, :Half, :Float, :Double, :X86FP80, :FP128, :PPCFP128]
  @eval @fun $(symbol(t, "Type"))()::TypeRef
  @eval @fun $(symbol(t, "TypeInContext"))(c::ContextRef)::TypeRef

  if isdefined(Base, t) && isa(eval(t), Type)
    @eval TypeRef(::Type{$t}) = $(symbol(t, "Type"))()
    @eval Base.convert(::Type{TypeRef}, ::Type{$t}) = $(symbol(t, "Type"))()
  end
end

for (t,j) in (:Int1=>:Bool, :Half=>:Float16, :Float=>:Float32, :Double=>:Float64)
  @eval TypeRef(::Type{$j}) = $(symbol(t, "Type"))()
  @eval Base.convert(::Type{TypeRef}, ::Type{$j}) = $(symbol(t, "Type"))()
end

## Function Types
@fun FunctionType(ret::TypeRef, param::Vector{TypeRef}, var::Bool=false)::TypeRef =
  (ret::TypeRef, param::Ptr{TypeRef}, length(param)::Cuint, (var ? 1 : 0)::Cint)

@fun IsFunctionVarArg(f::TypeRef)::Cint
@fun GetReturnType(f::TypeRef)::TypeRef
@aget GetParamTypes CountParamTypes TypeRef TypeRef
@aget GetParams CountParams ValueRef ValueRef
@fun GetParam(fn::ValueRef, i::Integer)::ValueRef = (fn, i::Cuint)
@fun GetParamParent(val::ValueRef)::ValueRef
@iter Param ValueRef ValueRef

## Sequence Types
@fun ArrayType(f::TypeRef, len::Integer)::TypeRef = (f, len::Cuint)
@fun GetElementType(t::TypeRef)::TypeRef
@fun GetArrayLength(f::TypeRef)::Cuint
@fun PointerType(f::TypeRef, space::Integer)::TypeRef = (f::TypeRef, space::Cuint)
@fun GetPointerAddressSpace(f::TypeRef)::Cuint
@fun VectorType(f::TypeRef, len::Integer)::Cuint = (f, len::Cuint)
@fun GetVectorSize(f::TypeRef)::Cuint

## Structure Types
@fun StructType(eltypes::Vector{TypeRef}, packed::Bool)::TypeRef = (eltypes::Ptr{TypeRef}, length(eltypes)::Cuint, (packed?1:0)::Cuint)
@fun StructTypeInContext(c::ContextRef, eltypes::Vector{TypeRef}, packed::Bool)::TypeRef = (c, eltypes::Ptr{TypeRef}, length(eltypes)::Cuint, (packed?1:0)::Cuint)
@fun StructCreateNamed(c::ContextRef, name::AbstractString)::TypeRef = (c, name::Cstring)
@fun GetStructName(t::TypeRef)::Cstring
@fun StructSetBody(t::TypeRef, eltypes::Vector{TypeRef}, packed::Bool)::Void = (t, eltypes::Ptr{TypeRef}, length(eltypes)::Cuint, (packed?1:0)::Cuint)
#@fun StructGetTypeAtIndex(t::TypeRef, i::Cuint)::TypeRef
@fun IsPackedStruct(t::TypeRef)::Cuint
@fun IsOpaqueStruct(t::TypeRef)::Cuint

@aget GetStructElementTypes CountStructElementTypes TypeRef TypeRef

# Value
@fun TypeOf(val::ValueRef)::TypeRef
@fun GetValueName(val::ValueRef)::Cstring
@fun SetValueName(val::ValueRef, name::AbstractString)::Void = (val, name::Cstring)
@fun DumpValue(val::ValueRef)::Void
#@fun PrintValueToString(val::ValueRef)::MessageRef
@fun ReplaceAllUsesWith(old::ValueRef, new::ValueRef)::Void
@fun IsConstant(v::ValueRef)::Cuint
@fun IsUndef(v::ValueRef)::Cuint
@fun IsAMDNode(v::ValueRef)::ValueRef
@fun IsAMDString(v::ValueRef)::ValueRef

@fun GetFirstUse(val::ValueRef)::UseRef
@fun GetNextUse(val::UseRef)::UseRef
@fun GetUser(u::UseRef)::ValueRef
@fun GetUsedValue(u::UseRef)::ValueRef

@fun GetOperand(val::ValueRef, index::Integer)::ValueRef = (val, index::Cuint)
#@fun GetOperandUse(val::ValueRef, index::Integer)::UseRef = (val, index::Cuint)
@fun SetOperand(user::ValueRef, index::Integer, val::ValueRef)::Void = (user, index::Cuint, val)
@fun GetNumOperands(val::ValueRef)::Cint

@fun ConstNull(ty::TypeRef)::ValueRef
@fun ConstAllOnes(ty::TypeRef)::ValueRef
@fun GetUndef(ty::TypeRef)::ValueRef
@fun IsNull(val::ValueRef)::Cuint
@fun ConstPointerNull(ty::TypeRef)::ValueRef

@fun ConstInt(t::TypeRef, n::Integer, sext::Bool)::ValueRef =
  (t, (typeof(n) <: Signed ? reinterpret(Culonglong, Clonglong(n)) : Culonglong(n))::Culonglong, sext::Cuint)
@fun ConstReal(t::TypeRef, n::Real)::ValueRef = (t, n::Cdouble)
@fun ConstIntGetZExtValue(v::ValueRef)::Culonglong
@fun ConstIntGetSExtValue(v::ValueRef)::Clonglong
#@fun ConstRealGetDouble(v::ValueRef, losesInfo::Vector{Cuint})::Cdouble = (v,losesInfo::Ptr{Cuint})

@fun AddFunctionAttr(fn::ValueRef, a::Integer)::Void = (fn, a::Cuint)
@fun GetFunctionAttr(fn::ValueRef)::Cuint
@fun RemoveFunctionAttr(fn::ValueRef, a::Integer)::Void = (fn, a::Cuint)

const ZExtAttribute       = 1<<0
const SExtAttribute       = 1<<1
const NoReturnAttribute   = 1<<2
const InRegAttribute      = 1<<3
const StructRetAttribute  = 1<<4
const NoUnwindAttribute   = 1<<5
const NoAliasAttribute    = 1<<6
const ByValAttribute      = 1<<7
const NestAttribute       = 1<<8
const ReadNoneAttribute   = 1<<9
const ReadOnlyAttribute   = 1<<10
const NoInlineAttribute   = 1<<11
const AlwaysInlineAttribute    = 1<<12
const OptimizeForSizeAttribute = 1<<13
const StackProtectAttribute    = 1<<14
const StackProtectReqAttribute = 1<<15
const Alignment = 31<<16
const NoCaptureAttribute  = 1<<21
const NoRedZoneAttribute  = 1<<22
const NoImplicitFloatAttribute = 1<<23
const NakedAttribute      = 1<<24
const InlineHintAttribute = 1<<25
const StackAlignment = 7<<26
const ReturnsTwice = 1 << 29
const UWTable = 1 << 30
const NonLazyBind = 1 << 31

# Basic Block
@fun BasicBlockAsValue(bb::BasicBlockRef)::ValueRef
@fun ValueIsBasicBlock(v::ValueRef)::Cuint
@fun ValueAsBasicBlock(v::ValueRef)::BasicBlockRef
@fun GetBasicBlockParent(bb::BasicBlockRef)::ValueRef
@fun GetBasicBlockTerminator(bb::BasicBlockRef)::ValueRef
@aget GetBasicBlocks CountBasicBlocks ValueRef BasicBlockRef
@iter BasicBlock BasicBlockRef ValueRef
@fun GetEntryBasicBlock(fn::ValueRef)::BasicBlockRef
@fun AppendBasicBlock(fn::ValueRef, name::AbstractString)::BasicBlockRef = (fn, name::Cstring)
@fun AppendBasicBlockInContext(c::ContextRef, fn::ValueRef, name::AbstractString)::BasicBlockRef = (c, fn, name::Cstring)
@fun InsertBasicBlock(bb::BasicBlockRef, name::AbstractString)::BasicBlockRef = (bb, name::Cstring)
@fun InsertBasicBlockInContext(c::ContextRef, bb::BasicBlockRef, name::AbstractString)::BasicBlockRef = (c, bb, name::Cstring)
@fun DeleteBasicBlock(bb::BasicBlockRef)::Void
@fun RemoveBasicBlockFromParent(bb::BasicBlockRef)::Void
@fun MoveBasicBlockBefore(bb::BasicBlockRef, pos::BasicBlockRef)::Void
@fun MoveBasicBlockAfter(bb::BasicBlockRef, pos::BasicBlockRef)::Void
@iter Instruction ValueRef BasicBlockRef

# InstructionBuilder
@fun CreateBuilder()::BuilderRef
@fun CreateBuilderInContext(c::ContextRef)::BuilderRef
@fun PositionBuilder(b::BuilderRef, bb::BasicBlockRef, val::ValueRef)::Void
@fun PositionBuilderBefore(b::BuilderRef, val::ValueRef)::Void
@fun PositionBuilderAtEnd(b::BuilderRef, val::BasicBlockRef)::Void
@fun GetInsertBlock(b::BuilderRef)::BasicBlockRef
@fun ClearInsertionPosition(b::BuilderRef)::Void
@fun InsertIntoBuilder(b::BuilderRef, instr::ValueRef)::Void
@fun InsertIntoBuilderWithName(b::BuilderRef, instr::ValueRef, name::AbstractString)::Void = (b, instr, name::Cstring)
@fun DisposeBuilder(b::BuilderRef)::Void
dispose(b::BuilderRef) = DisposeBuilder(b)

for i in ["RetVoid", "Unreachable"]
  @eval @fun $(symbol("Build", i))(b::BuilderRef)::ValueRef
end

for i in ["Ret", "Resume", "Free"]
  @eval @fun $(symbol("Build", i))(b::BuilderRef, v::ValueRef)::ValueRef
end

for i in ["Add", "NSWAdd", "NUWAdd", "FAdd",
          "Sub", "NSWSub", "NUWSub", "FSub",
          "Mul", "NSWMul", "NUWMul", "FMul",
          "UDiv", "SDiv", "ExactSDiv", "FDiv",
          "URem", "SRem", "FRem",
          "Shl", "LShr", "AShr",
          "And", "Or", "Xor",
          "Store", "PtrDiff"]
  @eval @fun $(symbol("Build", i))(b::BuilderRef, lhs::ValueRef, rhs::ValueRef, name::AbstractString)::ValueRef = (b, lhs, rhs, name::Cstring)
end

for i in ["Neg", "NSWNeg", "NUWNeg", "FNeg", "Not", "Load", "IsNull", "IsNotNull", "Load"]
  @eval @fun $(symbol("Build", i))(b::BuilderRef, val::ValueRef, name::AbstractString)::ValueRef = (b, val, name::Cstring)
end

for i in ["ICmp", "FCmp"]
  @eval @fun $(symbol("Build", i))(b::BuilderRef, pred::Integer, lhs::ValueRef, rhs::ValueRef, name::AbstractString)::ValueRef = (b, pred::Cint, lhs, rhs, name::Cstring)
end

const IntEQ = 32      # equal
const IntNE = 33      # not equal
const IntUGT = 34     # unsigned greater than
const IntUGE = 35     # unsigned greater or equal
const IntULT = 36     # unsigned less than
const IntULE = 37     # unsigned less or equal
const IntSGT = 38     # signed greater than
const IntSGE = 39     # signed greater or equal
const IntSLT = 40     # signed less than
const IntSLE = 41      # signed less or equal

const RealPredicateFalse = 0   # Always false (always folded)
const RealOEQ = 1              # True if ordered and equal
const RealOGT = 2              # True if ordered and greater than
const RealOGE = 3              # True if ordered and greater than or equal
const RealOLT = 4              # True if ordered and less than
const RealOLE = 5              # True if ordered and less than or equal
const RealONE = 6              # True if ordered and operands are unequal
const RealORD = 7              # True if ordered (no nans)
const RealUNO = 8              # True if unordered: isnan(X) | isnan(Y)
const RealUEQ = 9              # True if unordered or equal
const RealUGT = 10             # True if unordered or greater than
const RealUGE = 11             # True if unordered, greater than, or equal
const RealULT = 12             # True if unordered or less than
const RealULE = 13             # True if unordered, less than, or equal
const RealUNE = 14             # True if unordered or not equal
const RealPredicateTrue = 15   # Always true (always folded)

@fun BuildStore(b::BuilderRef, val::ValueRef, ptr::ValueRef)::ValueRef
@fun BuildCall(b::BuilderRef, fn::ValueRef, args::Vector{ValueRef}, name::AbstractString)::ValueRef = (b, fn, args::Ptr{ValueRef}, length(args)::Cuint, name::Cstring)
@fun BuildGEP(b::BuilderRef, p::ValueRef, inds::Vector{ValueRef}, name::AbstractString)::ValueRef = (b, p, inds::Ptr{ValueRef}, length(inds)::Cuint, name::Cstring)
@fun BuildInBoundsGEP(b::BuilderRef, p::ValueRef, inds::Vector{ValueRef}, name::AbstractString)::ValueRef = (b, p, inds::Ptr{ValueRef}, length(inds)::Cuint, name::Cstring)

@fun BuildBr(b::BuilderRef, dest::BasicBlockRef)::ValueRef
@fun BuildCondBr(b::BuilderRef, cond::ValueRef, then::BasicBlockRef, otherwise::BasicBlockRef)::ValueRef

@fun BuildPhi(b::BuilderRef, ty::TypeRef, name::AbstractString)::ValueRef = (b, ty, name::Cstring)
@fun AddIncoming(phi::ValueRef, vals::Vector{ValueRef}, blocks::Vector{BasicBlockRef})::Void = (phi, vals::Ptr{ValueRef}, blocks::Ptr{BasicBlockRef}, (@assert length(vals) == length(blocks); length(vals))::Cuint)
@fun CountIncoming(phi::ValueRef)::Cuint
@fun GetIncomingValue(phi::ValueRef, index::Integer)::ValueRef = (phi, index::Cuint)
@fun GetIncomingBlock(phi::ValueRef, index::Integer)::BasicBlockRef = (phi, index::Cuint)

end


text:
#=
    significand_bits
    Returns the number of bits needed to represent
    the absolute value of the significand of an
    ArbFloat{P} value, directly or as an ArbReal{P} midpoint.
    This is the minimum precision in bits that
    allows an exact representation of that value.
    Returns 0 if x is a special value.
=#

function significand_bits(x::ArbFloat{P}) where {P}
    # returns the number of bits needed to represent the absolute value of the significand of x,
    # i.e. the minimum precision sufficient to represent x exactly. Returns 0 if x is a special value.
    nbits = ccall(@libarb(arf_bits), Clong, (Ref{ArbFloat},), x)
    return nbits%Int
end

function significand_bits(x::ArbReal{P}) where {P}
    # returns the number of bits needed to represent the absolute value of the significand of midpoint(x),
    # i.e. the minimum precision sufficient to represent x exactly. Returns 0 if x is a special value.
    nbits = ccall(@libarb(arb_bits), Clong, (Ref{ArbReal},), x)
    return nbits%Int
end

function significand_bits(x::ArbComplex{P}) where {P}
    # returns the number of bits needed to represent the maximum of bits(real(x)), bits(imag(x)).
    nbits = ccall(@libarb(acb_bits), Clong, (Ref{ArbComplex},), x)
    return nbits%Int
end

#=
    arb_rel_error_bits
    Returns the effective relative error of x measured in bits,
    defined as the difference between
    the position of the top bit in the radius
    and the top bit in the midpoint, plus one.
    The result is clamped between plus/minus ARF_PREC_EXACT
    (ARF_PREC_EXACT == ±(2^{63}-1) inclusive on a 64-bit machine).
    acb_rel_error_bits
    Returns the effective relative error of x measured in bits.
    This is computed as if calling arb_rel_error_bits() on the real ball
    whose midpoint is the larger out of the real and imaginary midpoints of x,
    and whose radius is the larger out of the real and imaginary radiuses of x.
=#

relerror_bits(x::ArbFloat{P}) where {P} = 0

function relerror_bits(x::ArbReal{P}) where {P}
    nbits = ccall(@libarb(arb_rel_error_bits), Clong, (Ref{ArbReal},), x)
    return nbits%Int
end

function relerror_bits(x::ArbComplex{P}) where {P}
    nbits = ccall(@libarb(crb_rel_error_bits), Clong, (Ref{ArbComplex},), x)
    return nbits%Int
end

#=
    rel_accuracy_bits
    Returns the effective relative accuracy intrinsic to a ball, measured in bits.
    This is equal to -relerror_bits.
=#

relaccuracy_bits(x::ArbFloat{P}) where {P} = 0

function relaccuracy_bits(x::ArbReal{P}) where {P}
    nbits = ccall(@libarb(arb_rel_accuracy_bits), Clong, (Ref{ArbReal},), x)
    return nbits%Int
end

function relaccuracy_bits(x::ArbComplex{P}) where {P}
    nbits = ccall(@libarb(acb_rel_accuracy_bits), Clong, (Ref{ArbComplex},), x)
    return nbits%Int
end

#=
    Rounds the significand of a value to the number of bits
    equal to the accuracy of x (as indicated by its radius),
    plus a few guard bits so enclosure is maintained.
=#

trim_bits(x::Mag) = x

function trim_bits(x::ArbFloat{P}, roundingmode::RoundingMode=RoundFromZero) where {P}
    nbits = significand_bits(x)
    nbits == P && return x
    rounding = match_rounding_mode(roundingmode)
    z = ArbFloat{nbits}
    res = ccall(@libarb(arf_set_round), Cint, (Ref{ArbFloat}, Ref{ArbFloat}, Clong, Cint), z, x, nbits, rounding)
    return res
end
function trim_bits(x::ArbReal{P}) where {P}
    z = ArbReal{P}()
    ccall(@libarb(arb_trim), Cvoid, (Ref{ArbReal}, Ref{ArbReal}), z, x)
    return z
end
function trim_bits(x::ArbComplex{P}) where {P}
    z = ArbComplex{P}()
    ccall(@libarb(acb_trim), Cvoid, (Ref{ArbComplex}, Ref{ArbComplex}), z, x)
    return z
end

#=
void arf_mag_set_ulp(mag_t res, const arf_t x, slong prec)
    Sets res to the magnitude of the unit in the last place (ulp) of x at precision prec.
=#

function ulp(x::ArbFloat{P}) where {P}
    if isnan(x) || isinf(x)
        return ArbFloat{P}(NaN)
    end
    if !iszero(x)
        w = Mag()
        #   Sets z to the magnitude of the unit in the last place (ulp) of x at precision P.
        ccall(@libarb(arf_mag_set_ulp), Cvoid, (Ref{Mag}, Ref{ArbFloat}, Clong), w, x, P)
        z = ArbFloat{P}(w)
    else
        z = ArbFloat{P}(2.0)^(-workingprecision(x))
    end
    return z
end

function eps(x::ArbFloat{P}) where {P}
    if isnan(x) || isinf(x)
        return ArbFloat{P}(NaN)
    end
    if !iszero(x)
        w = Mag()
        #   Sets z to the magnitude of the unit in the last place (ulp) of x at precision P.
        ccall(@libarb(arf_mag_set_ulp), Cvoid, (Ref{Mag}, Ref{ArbFloat}, Clong), w, x, P)
        z = ArbFloat{P}(w)
        z += z
    else
        z = ArbFloat{P}(2.0)^(-workingprecision(x))
    end
    return z
end

function ulp(x::ArbFloat{P}, prec::Int) where {P}
    prec < MINIMUM_PRECISION && throw(DomainError("bit precision ($prec) is too low"))
    y = ArbFloat(x, prec)
    z = ulp(y)
    return z
end

function eps(x::ArbFloat{P}, prec::Int) where {P}
    prec < MINIMUM_PRECISION && throw(DomainError("bit precision ($prec) is too low"))
    y = ArbFloat(x, prec)
    z = eps(y)
    return z
end

ulp(x::ArbReal{P}) where {P} = ulp(midpoint_byref(x))
eps(x::ArbReal{P}) where {P} = eps(midpoint_byref(x))

ulp(x::ArbComplex{P}) where {P} = ulp(midpoint_byref(real(x)))
eps(x::ArbComplex{P}) where {P} = eps(midpoint_byref(real(x)))

ulps(x::ArbComplex{P}) where {P} = ulp(midpoint_byref(real(x))), ulp(midpoint_byref(imag(x)))
epss(x::ArbComplex{P}) where {P} = eps(midpoint_byref(real(x))), eps(midpoint_byref(imag(x)))

ulp(::Type{ArbFloat{P}}) where {P} = ulp(one(ArbFloat{P}))
eps(::Type{ArbFloat{P}}) where {P} = eps(one(ArbFloat{P}))

ulp(::Type{ArbReal{P}}) where {P} = ulp(one(ArbReal{P}))
eps(::Type{ArbReal{P}}) where {P} = eps(one(ArbReal{P}))

ulp(::Type{ArbComplex{P}}) where {P} = ulp(one(ArbComplex{P}))
eps(::Type{ArbComplex{P}}) where {P} = eps(one(ArbComplex{P}))

nextfloat(::Type{ArbFloat{P}}) where {P} = one(ArbFloat{P}) + ulp(one(ArbFloat{P}))
nextfloat(::Type{ArbReal{P}}) where {P} = ArbReal{P}(nextfloat(ArbFloat{P}))
prevfloat(::Type{ArbFloat{P}}) where {P} = one(ArbFloat{P}) - ulp(one(ArbFloat{P}))
prevfloat(::Type{ArbReal{P}}) where {P} = ArbReal{P}(prevfloat(ArbFloat{P}))

nextfloat(x::ArbFloat{P}) where {P} = x + ulp(x)
nextfloat(x::ArbReal{P}) where {P} = x + ulp(x)
prevfloat(x::ArbFloat{P}) where {P} = x - ulp(x)
prevfloat(x::ArbReal{P}) where {P} = x - ulp(x)

nextfloat(::Type{ArbFloat{P}}, n::Int) where {P} = one(ArbFloat{P}) + n*ulp(one(ArbFloat{P}))
nextfloat(::Type{ArbReal{P}}, n::Int) where {P} = ArbReal{P}(nextfloat(ArbFloat{P}, n))
prevfloat(::Type{ArbFloat{P}}, n::Int) where {P} = one(ArbFloat{P}) - n*ulp(one(ArbFloat{P}))
prevfloat(::Type{ArbReal{P}}, n::Int) where {P} = ArbReal{P}(prevfloat(ArbFloat{P}, n))

nextfloat(x::ArbFloat{P}, n::Int) where {P} = x + n*ulp(x)
nextfloat(x::ArbReal{P}, n::Int) where {P} = x + n*ulp(x)
prevfloat(x::ArbFloat{P}, n::Int) where {P} = x - n*ulp(x)
prevfloat(x::ArbReal{P}, n::Int) where {P} = x - n*ulp(x)

ext: jl


text:
module Checksum

function main()
    count2 = 0
    count3 = 0
    open("../input/input.txt") do file
        for line in eachline(file)
            counts = zeros(256)
            for char in line
                counts[Int(char)] += 1
            end
            count2 += any(counts .== 2)
            count3 += any(counts .== 3)
        end
    end
    println(count2 * count3)
end

main()

end

max_stars_repo_name: tjpalmer/advent

max_issues_repo_name: tjpalmer/advent

max_forks_repo_name: tjpalmer/advent


text:
using Test
using SafeTestsets

@safetestset "Geometry" begin include("Geometry/runtests.jl") end

@safetestset "Interpolation" begin include("Interpolation/runtests.jl") end

@safetestset "Integration" begin include("Integration/runtests.jl") end

@safetestset "Mesh" begin include("Mesh/runtests.jl") end

@safetestset "Trees" begin include("Trees/runtests.jl") end

# @safetestset "IO" begin include("IO/runtests.jl") end

max_stars_repo_name: WaveProp/WavePropBase

max_issues_repo_name: WaveProp/WavePropBase

max_forks_repo_name: WaveProp/WavePropBase


text:
using Judycon, Documenter

makedocs(modules=[Judycon],
         format = Documenter.HTML(),
         checkdocs = :all,
         sitename = "Judycon.jl",
         pages = ["index.md"])


text:
testnx(g, nx) = isapprox(g.nx, nx)
testny(g, ny) = isapprox(g.ny, ny)
testnz(g, nz) = isapprox(g.nz, nz)

# Physical grid tests
function testdx(dev, g::Union{OneDGrid{T}, TwoDGrid{T}, ThreeDGrid{T}}) where T
  dxgrid = @. g.x[2:end] - g.x[1:end-1]
  dxones = ArrayType(dev)(g.dx*ones(T, size(dxgrid)))
  isapprox(dxgrid, dxones)
end

function testdy(dev, g::Union{TwoDGrid{T}, ThreeDGrid{T}}) where T
  dygrid = @. g.y[2:end] - g.y[1:end-1]
  dyones = ArrayType(dev)(g.dy*ones(T, size(dygrid)))
  isapprox(dygrid, dyones)
end

function testdz(dev, g::ThreeDGrid{T}) where T
  dzgrid = @. g.z[2:end] - g.z[1:end-1]
  dzones = ArrayType(dev)(g.dz*ones(T, size(dzgrid)))
  isapprox(dzgrid, dzones)
end

testx(g) = isapprox(g.x[end]-g.x[1], g.Lx-g.dx)
testy(g) = isapprox(g.y[end]-g.y[1], g.Ly-g.dy)
testz(g) = isapprox(g.z[end]-g.z[1], g.Lz-g.dz)

testdk(g::Union{OneDGrid, TwoDGrid, ThreeDGrid}) = CUDA.@allowscalar isapprox(g.k[2], 2π/g.Lx)
testdl(g::Union{TwoDGrid, ThreeDGrid}) = CUDA.@allowscalar isapprox(g.l[2], 2π/g.Ly)
testdm(g::ThreeDGrid) = CUDA.@allowscalar isapprox(g.m[2], 2π/g.Lz)

# Test proper arrangement of fft wavenumbers. k = [0:nx/2, -nx/2+1:-1].
flippednegatives(k, mid) = -reverse(k[mid+2:end])
function testwavenumberalignment(k, nx)
  mid = Int(nx/2)
  positives = k[2:mid]
  negatives = flippednegatives(k, mid)
  isapprox(reshape(positives, mid-1), reshape(negatives, mid-1))
end

testk(g) = testwavenumberalignment(g.k, g.nx)
testl(g::Union{TwoDGrid, ThreeDGrid}) = testwavenumberalignment(g.l, g.ny)
testm(g::ThreeDGrid) = testwavenumberalignment(g.m, g.nz)
testkr(g) = CUDA.@allowscalar isapprox(cat(g.k[1:g.nkr-1], abs(g.k[g.nkr]), dims=1), g.kr)

function testgridpoints(dev::Device, g::TwoDGrid{T}) where T
  X, Y = gridpoints(g)
  dXgrid = @. X[2:end, :] - X[1:end-1, :]
  dYgrid = @. Y[:, 2:end] - Y[:, 1:end-1]
  dXones = ArrayType(dev)(g.dx*ones(T, size(dXgrid)))
  dYones = ArrayType(dev)(g.dy*ones(T, size(dYgrid)))
  isapprox(dXgrid, dXones) && isapprox(dYgrid, dYones)
end

function testgridpoints(dev::Device, g::ThreeDGrid{T}) where T
  X, Y, Z = gridpoints(g)
  dXgrid = @. X[2:end, :, :] - X[1:end-1, :, :]
  dYgrid = @. Y[:, 2:end, :] - Y[:, 1:end-1, :]
  dZgrid = @. Z[:, :, 2:end] - Z[:, :, 1:end-1]
  dXones = ArrayType(dev)(g.dx*ones(T, size(dXgrid)))
  dYones = ArrayType(dev)(g.dy*ones(T, size(dYgrid)))
  dZones = ArrayType(dev)(g.dz*ones(T, size(dZgrid)))
  isapprox(dXgrid, dXones) && isapprox(dYgrid, dYones) && isapprox(dZgrid, dZones)
end

function testdealias(g::OneDGrid)
  T = typeof(g.Lx)
  fh = ones(Complex{T}, size(g.kr))
  dealias!(fh, g)
  kmax = round(maximum(g.kr)*2/3)
  CUDA.@allowscalar isapprox(sum(abs.(fh[g.kr .>= kmax])), 0)
end

function testdealias(g::TwoDGrid)
  T = typeof(g.Lx)
  fh = ones(Complex{T}, size(g.Krsq))
  dealias!(fh, g)
  kmax = round(maximum(g.kr)*2/3)
  lmax = floor(maximum(g.l)*2/3)

  temp = 0.0
  for j = 1:g.nl, i = 1:g.nkr
    if (CUDA.@allowscalar g.kr[i] >= kmax) & (CUDA.@allowscalar g.l[j] >= lmax || CUDA.@allowscalar g.l[j] < -lmax)
      temp += abs.(fh[i, j]) #temp = sum of |fh| for aliased wavenumbers
    end
  end
  isapprox(temp, 0)
end

function testdealias(g::ThreeDGrid)
  T = typeof(g.Lx)
  fh = ones(Complex{T}, size(g.Krsq))
  dealias!(fh, g)
  kmax = round(maximum(g.kr)*2/3)
  lmax = floor(maximum(g.l)*2/3)
  mmax = floor(maximum(g.m)*2/3)

  temp = 0.0
  for k = 1:g.nm, j = 1:g.nl, i = 1:g.nkr
    if (CUDA.@allowscalar g.kr[i] >= kmax ) & (CUDA.@allowscalar g.l[j] >= lmax || CUDA.@allowscalar g.l[j] < -lmax) & (CUDA.@allowscalar g.m[k] >= mmax || CUDA.@allowscalar g.m[k] < -mmax)
      temp += abs.(fh[i, j, k]) #temp = sum of |fh| for aliased wavenumbers
    end
  end
  isapprox(temp, 0)
end

function testtypedonedgrid(dev::Device, nx, Lx; T=Float64)
  gr = OneDGrid(nx, Lx, T=T)
  typeof(gr.dx)==T && typeof(gr.x[1])==T && typeof(gr.Lx)==T && eltype(gr) == T
end

function testtypedtwodgrid(dev::Device, nx, Lx, ny=Lx, Ly=Lx; T=Float64)
  gr = TwoDGrid(nx, Lx, ny, Ly, T=T)
  typeof(gr.dx)==T && typeof(gr.dy)==T && typeof(gr.x[1])==T && typeof(gr.y[1])==T && typeof(gr.Lx)==T && typeof(gr.Ly)==T && eltype(gr) == T
end

function testtypedthreedgrid(dev::Device, nx, Lx, ny=nx, Ly=Lx, nz=nx, Lz=Lx; T=Float64)
  gr = ThreeDGrid(nx, Lx, ny, Ly, nz, Lz, T=T)
  typeof(gr.dx)==T && typeof(gr.dy)==T && typeof(gr.dz)==T && typeof(gr.x[1])==T && typeof(gr.y[1])==T && typeof(gr.z[1])==T && typeof(gr.Lx)==T && typeof(gr.Ly)==T && typeof(gr.Lz)==T && eltype(gr) == T
end

function testmakefilter(dev::Device, g::AbstractGrid)
  T = eltype(g)
  filter = FourierFlows.makefilter(g)
  G = typeof(g)
  nofilter = G<:OneDGrid ? filter[@. g.kr*g.dx/π < 0.65] : ( G<:TwoDGrid ? filter[@. sqrt((g.kr*g.dx/π)^2 + (g.l*g.dy/π)^2) < 0.65] : filter[@. sqrt((g.kr*g.dx/π)^2 + (g.l*g.dy/π)^2 + (g.m*g.dz/π)^2) < 0.65] )
  fullfilter = G<:OneDGrid ? filter[@. g.kr*g.dx/π > 0.999] : ( G<:TwoDGrid ? filter[@. sqrt((g.kr*g.dx/π)^2 + (g.l*g.dy/π)^2) > 0.999] : filter[@. sqrt((g.kr*g.dx/π)^2 + (g.l*g.dy/π)^2 + (g.m*g.dz/π)^2) > 0.999] )
  nofilter== zeros(dev, T, size(nofilter)) .+ 1 && isapprox(fullfilter, zeros(dev, T, size(fullfilter)), atol=1e-12)
end

function test_plan_flows_fftrfft(::CPU; T=Float64)
  A = ArrayType(CPU())
  return (typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4,))))) <: FFTW.cFFTWPlan{Complex{T},-1,false,1} &&
  typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6))))) <: FFTW.cFFTWPlan{Complex{T},-1,false,2} &&
  typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6, 8))))) <: FFTW.cFFTWPlan{Complex{T},-1,false,3} &&
  FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6, 8))), [1, 2]).region == [1, 2] &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4,))))) <: FFTW.rFFTWPlan{T,-1,false,1} &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4, 6))))) <: FFTW.rFFTWPlan{T,-1,false,2} &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4, 6, 8))))) <: FFTW.rFFTWPlan{T,-1,false,3} &&
  FourierFlows.plan_flows_rfft(A(rand(T, (4, 6, 8))), [1, 2]).region == [1, 2])
end

function test_plan_flows_fftrfft(::GPU; T=Float64)
  A = ArrayType(GPU())
  return (typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4,))))) == CUDA.CUFFT.cCuFFTPlan{Complex{T},-1,false,1} &&
  typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6))))) == CUDA.CUFFT.cCuFFTPlan{Complex{T},-1,false,2} &&
  typeof(FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6, 8))))) == CUDA.CUFFT.cCuFFTPlan{Complex{T},-1,false,3} &&
  FourierFlows.plan_flows_fft(A(rand(Complex{T}, (4, 6, 8))), [1, 2]).region == [1, 2] &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4,))))) == CUDA.CUFFT.rCuFFTPlan{T,-1,false,1} &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4, 6))))) == CUDA.CUFFT.rCuFFTPlan{T,-1,false,2} &&
  typeof(FourierFlows.plan_flows_rfft(A(rand(T, (4, 6, 8))))) == CUDA.CUFFT.rCuFFTPlan{T,-1,false,3} &&
  FourierFlows.plan_flows_rfft(A(rand(T, (4, 6, 8))), [1, 2]).region == [1, 2])
end


text:
@testset "runtestFibonacci" begin
    println("Testing runtestFibonacci")
    include("../src/bfgaFibonacci.jl")
    using .bfgaFibonacci

    include("../src/Bf.jl")
    using .BfInterpreter

    @time model = test_serial()
    prems = model.refSet[length(model.refSet)]
    println("Generation : $(model.params.currentGeneration)")
    println("& fitness : $(fitness(prems, model.instructionsSet))")
    #bfcode :: Array{Float64,1}  = prems.dna
    println("code : $(prems.program) " )# $(join(genesToBfInstructions(bfcode), "") ) ")

    #_trainingExamples = [ "00" , "01" , "10" , "11" ]
    #_trainingResults = [ '1', '0', '0', '1' ]

    #bft = bfType(bfcode)
    for num in 1:4
        input = _trainingExamples[num]
        goal =  sum(input)
        last_value = input[2]
        output, _ = execute(prems.program, input, model.instructionsSet)
        n= length(output)
        @show output[1:nb_predictions]
        @test length(output) >= nb_predictions
        for i in 1:n
            if i> nb_predictions
                break
            end
            @test goal == Int(output[i])
            goal, last_value = last_value + goal, goal
        end
    end

    # do the test_parallel after ...
    #test_parallel()
end


text:
### A Pluto.jl notebook ###
# v0.12.15

using Markdown
using InteractiveUtils

# ╔═╡ 0d72abba-33cc-11eb-17d9-dd6b7b0e20ea
import CSV

# ╔═╡ 2afa63bc-33cc-11eb-17ee-775f761bafd1
import DataFrames

# ╔═╡ b8ea3d76-33f6-11eb-035a-e75f6aa022eb
demographic = CSV.read("/Users/rene/Data/UNIQA/DemographicData/raster250-hole-austria-with-generalized-latlaon.csv")

# ╔═╡ 56cdd0c8-33f7-11eb-148d-6b58e4ee88dc
demographic.LAT

# ╔═╡ fe64378c-33f6-11eb-2b46-877c21a7e605
DataFrames.describe(demographic)

# ╔═╡ 34151992-33cc-11eb-1194-fbb0c1dcbb9f
function mergecrspcompkernel(;crsp=error("crsp is required"), comp=error("comp is required"))
  ###Merge one permno at a time, linking each crsp row to a compid (comp row)
  scrsps = groupby(crsp, :permno)
  scomps = groupby(comp, :permno)
  comp.compid = 1:size(comp,1) |> collect
  crsp.compid = Vector{Union{Int, Missing}}(undef, size(crsp,1))

  #faster to work within the rows for a particular permno
  Threads.@threads for permno ∈ keys(scomps)
    scomp = scomps[permno]
    crsppermnokey = permno |> Tuple
    (!haskey(scrsps,crsppermnokey)) && continue
    #because the key originates from comp, cant use it directly on crsp- instead need its value
    scrsp = scrsps[crsppermnokey]

    #the idea here is to select all of the crsp rows between the effective date
    #and the end date of the comp row
    for r ∈ eachrow(scomp)
      targetrows = view(scrsp, (r.effdate .≤ scrsp.date) .& (scrsp.date .≤ r.enddate), :compid)
      if length(targetrows) > 0
        #under no circumstances should this be assigned, since date and permno should be unique
        (targetrows .=== missing) |> all || error(
          "multiple crsp rows found for a particular compid!!")
        targetrows .= r.compid
      end
    end
  end

  crsp = crsp[crsp.compid .!== missing, :]

  #now merge the linked rows
  rename!(comp, :permno=>:lpermno)
  panel = innerjoin(crsp, comp, on=:compid)

  #sanity checks
  @assert size(panel,1) == size(crsp,1)
  @assert (crsp.permno .== panel.permno) |> all
  @assert (crsp.date .== panel.date) |> all

  return panel
end

# ╔═╡ Cell order:
# ╠═0d72abba-33cc-11eb-17d9-dd6b7b0e20ea
# ╠═2afa63bc-33cc-11eb-17ee-775f761bafd1
# ╠═b8ea3d76-33f6-11eb-035a-e75f6aa022eb
# ╠═56cdd0c8-33f7-11eb-148d-6b58e4ee88dc
# ╠═fe64378c-33f6-11eb-2b46-877c21a7e605
# ╠═34151992-33cc-11eb-1194-fbb0c1dcbb9f

max_stars_repo_name: OpenDGPS/SimulAT

max_issues_repo_name: OpenDGPS/SimulAT

max_forks_repo_name: OpenDGPS/SimulAT


text:
module LyapunovExponentsTests

print_with_color(:blue, let
    message = " Warnings below (if any) are fine. "
    margin = (displaysize(STDOUT)[2] - length(message)) ÷ 2
    ("=" ^ margin) * message * ("=" ^ margin)
end)
println()
flush(STDOUT)
import Plots
import ForwardDiff
import DifferentialEquations
import OnlineStats
flush(STDOUT)
flush(STDERR)
print_with_color(:blue, "=" ^ displaysize(STDOUT)[2])
println()

using LyapunovExponents
using Base.Test

tic()
include("test_testtools.jl")
include("test_utils.jl")
include("test_online_stats.jl")
include("test_smoke.jl")
include("test_ui.jl")
include("test_examples.jl")
include("test_integrators.jl")
include("test_terminators.jl")
include("test_clv.jl")
include("test_null_clv.jl")
toc()

end


text:
synth_imgs = [
    "Float64_0" => rand(127, 257),
    "Float64_1" => rand(127, 257, 1),
    "Float64_2" => rand(127, 257, 2),
    "Float64_3" => rand(127, 257, 3),
    "Float64_4" => rand(127, 257, 4),
    "Bool_0" => rand(Bool, 127, 257),
    "Bool_1" => rand(Bool, 127, 257, 1),
    "Bool_2" => rand(Bool, 127, 257, 2),
    "Bool_3" => rand(Bool, 127, 257, 3),
    "Bool_4" => rand(Bool, 127, 257, 4),
    "UInt8_0" => rand(UInt8, 127, 257),
    "UInt8_1" => rand(UInt8, 127, 257, 1),
    "UInt8_2" => rand(UInt8, 127, 257, 2),
    "UInt8_3" => rand(UInt8, 127, 257, 3),
    "UInt8_4" => rand(UInt8, 127, 257, 4),
    "UInt16_0" => rand(UInt16, 127, 257),
    "UInt16_1" => rand(UInt16, 127, 257, 1),
    "UInt16_2" => rand(UInt16, 127, 257, 2),
    "UInt16_3" => rand(UInt16, 127, 257, 3),
    "UInt16_4" => rand(UInt16, 127, 257, 4),
    "N0f8_0" => rand(N0f8, 127, 257),
    "N0f8_1" => rand(N0f8, 127, 257, 1),
    "N0f8_2" => rand(N0f8, 127, 257, 2),
    "N0f8_3" => rand(N0f8, 127, 257, 3),
    "N0f8_4" => rand(N0f8, 127, 257, 4),
    "N0f16_0" => rand(N0f16, 127, 257),
    "N0f16_1" => rand(N0f16, 127, 257, 1),
    "N0f16_2" => rand(N0f16, 127, 257, 2),
    "N0f16_3" => rand(N0f16, 127, 257, 3),
    "N0f16_4" => rand(N0f16, 127, 257, 4),
    "Gray" => rand(Gray, 127, 257),
    "GrayA" => rand(GrayA, 127, 257),
    "RGB" => rand(RGB, 127, 257),
    "RGBA" => rand(RGBA, 127, 257),
    "Gray-N0f8" => rand(Gray{N0f8}, 127, 257),
    "GrayA-N0f8" => rand(GrayA{N0f8}, 127, 257),
    "RGB-N0f8" => rand(RGB{N0f8}, 127, 257),
    "RGBA-N0f8" => rand(RGBA{N0f8}, 127, 257),
    "Gray-N0f16" => rand(Gray{N0f16}, 127, 257),
    "GrayA-N0f16" => rand(GrayA{N0f16}, 127, 257),
    "RGB-N0f16" => rand(RGB{N0f16}, 127, 257),
    "RGBA-N0f16" => rand(RGBA{N0f16}, 127, 257),
    "Gray-N0f8" => rand(Gray{N0f8}, 127, 257),
    "GrayA-N0f8" => rand(GrayA{N0f8}, 127, 257),
    "Gray-Float64" => rand(Gray{Float64}, 127, 257),
    "GrayA-Float64" => rand(GrayA{Float64}, 127, 257),
    "RGB-Float64" => rand(RGB{Float64}, 127, 257),
    "RGBA-Float64" => rand(RGBA{Float64}, 127, 257),
]

edge_case_imgs = [
    ("BitArray_0", x -> _convert(Gray, N7f1, x), randn(127, 257) .> 0),
    ("BitArray_1", x -> _convert(Gray, N7f1, x), randn(127, 257, 1) .> 0),
    ("BitArray_2", x -> _convert(GrayA, N7f1, x), randn(127, 257, 2) .> 0),
    ("BitArray_3", x -> _convert(RGB, N7f1, x), randn(127, 257, 3) .> 0),
    ("BitArray_4", x -> _convert(RGBA, N7f1, x), randn(127, 257, 4) .> 0),
    ("N4f12_0", x -> _convert(Gray, N0f16, x), rand(N4f12, 127, 257)),
    ("N4f12_1", x -> _convert(Gray, N0f16, x), rand(N4f12, 127, 257, 1)),
    ("N4f12_2", x -> _convert(GrayA, N0f16, x), rand(N4f12, 127, 257, 2)),
    ("N4f12_3", x -> _convert(RGB, N0f16, x), rand(N4f12, 127, 257, 3)),
    ("N4f12_4", x -> _convert(RGBA, N0f16, x), rand(N4f12, 127, 257, 4)),
    ("BGR-N0f8", identity, rand(BGR{N0f8}, 127, 257)),
    ("BGR-N01f16", identity, rand(BGR{N0f16}, 127, 257)),
    ("BGR-Float64", identity, BGR{Float64}.(rand(BGR{N0f8}, 127, 257))),
    ("BGRA-N0f8", identity, rand(BGRA{N0f8}, 127, 257)),
    ("BGRA-N0f16", identity, rand(BGRA{N0f16}, 127, 257)),
    ("BGRA-Float64", identity, BGRA{Float64}.(rand(BGRA{N0f8}, 127, 257))),
    ("ABGR-N0f8", identity, rand(ABGR{N0f8}, 127, 257)),
    ("ABGR-N0f16", identity, rand(ABGR{N0f16}, 127, 257)),
    ("ABGR-Float64", identity, ABGR{Float64}.(rand(ABGR{N0f8}, 127, 257))),
    ("ARGB-N0f8", identity, rand(ARGB{N0f8}, 127, 257)),
    ("ARGB-N0f16", identity, rand(ARGB{N0f16}, 127, 257)),
    ("ARGB-Float64", identity, ARGB{Float64}.(rand(ARGB{N0f8}, 127, 257))),
]

@testset "synthetic images" begin
    for (case, image) in synth_imgs
        @testset "$(case)" begin
            expected = collect(PNGFiles._prepare_buffer(image))
            fpath = joinpath(PNG_TEST_PATH, "test_img_$(case).png")
            @testset "write" begin
                open(io->PNGFiles.save(io, image), fpath, "w") #test IO method
                @test PNGFiles.save(fpath, image) == 0
            end
            @testset "read" begin
                global read_in_pngf = PNGFiles.load(fpath)
                @test typeof(read_in_pngf) <: AbstractMatrix
            end
            @testset "compare" begin
                @test all(expected .≈ read_in_pngf)
            end
            global read_in_immag = _standardize_grayness(ImageMagick.load(fpath))
            @testset "$(case): ImageMagick read type equality" begin
                # The lena image is Grayscale saved as RGB...
                @test eltype(_standardize_grayness(read_in_pngf)) == eltype(read_in_immag)
            end
            @testset "$(case): ImageMagick read values equality" begin
                imdiff_val = imdiff(read_in_pngf, read_in_immag)
                onfail(@test imdiff_val < 0.01) do
                    PNGFiles._inspect_png_read(fpath)
                    _add_debugging_entry(fpath, case, imdiff_val)
                end
            end
            path, ext = splitext(fpath)
            newpath = path * "_new" * ext
            PNGFiles.save(newpath, read_in_pngf)
            @testset "$(case): Fpath save IO is idempotent" begin
                @test all(read_in_pngf .≈ PNGFiles.load(newpath))
                @test all(read_in_pngf .≈ open(io->PNGFiles.load(io), newpath))
            end
            open(io->PNGFiles.save(io, read_in_pngf), newpath, "w") #test IO method
            @testset "$(case): Stream save IO is idempotent" begin
                @test all(read_in_pngf .≈ PNGFiles.load(newpath))
                @test all(read_in_pngf .≈ open(io->PNGFiles.load(io), newpath))
            end
        end
    end

    for (case, func_in, image) in edge_case_imgs
        @testset "$(case)" begin
            fpath = joinpath(PNG_TEST_PATH, "test_img_$(case).png")
            @testset "write" begin
                @test PNGFiles.save(fpath, image) == 0
            end
            @testset "read" begin
                global read_in_pngf = PNGFiles.load(fpath)
                @test read_in_pngf isa Matrix
            end
            @testset "compare" begin
                @test all(read_in_pngf .== func_in(image))
            end
            global read_in_immag = _standardize_grayness(ImageMagick.load(fpath))
            @testset "$(case): ImageMagick read type equality" begin
                @test eltype(read_in_pngf) == eltype(read_in_immag)
            end
            @testset "$(case): ImageMagick read values equality" begin
                imdiff_val = imdiff(read_in_pngf, read_in_immag)
                onfail(@test imdiff_val < 0.01) do
                    PNGFiles._inspect_png_read(fpath)
                    _add_debugging_entry(fpath, case, imdiff_val)
                end
            end
            path, ext = splitext(fpath)
            newpath = path * "_new" * ext
            PNGFiles.save(newpath, read_in_pngf)
            @testset "$(case): IO is idempotent" begin
                @test imdiff(read_in_pngf, PNGFiles.load(newpath)) < 0.01
                @test imdiff(read_in_pngf, open(io->PNGFiles.load(io), newpath)) < 0.01
            end
        end
    end
end


text:
# *****************************************************************************
# Written by Ritchie Lee, ritchie.lee@sv.cmu.edu
# *****************************************************************************
# Copyright ã 2015, United States Government, as represented by the
# Administrator of the National Aeronautics and Space Administration. All
# rights reserved.  The Reinforcement Learning Encounter Simulator (RLES)
# platform is licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You
# may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable
# law or agreed to in writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
# _____________________________________________________________________________
# Reinforcement Learning Encounter Simulator (RLES) includes the following
# third party software. The SISLES.jl package is licensed under the MIT Expat
# License: Copyright (c) 2014: Youngjun Kim.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
# "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# *****************************************************************************

using Iterators
using RLESUtils, RunUtils, IFTTTUtils

const RANGE = 3:5
const COMP = gethostname()
const DATA = "nvn_libcas098smallfilt_10K"
const CONFIG = "normal"

template_ce_tree(seed) =
"""
using GrammarExpts, ACASX_CE_Tree
config = configure(ACASX_CE_Tree, "$DATA", "$CONFIG")
acasx_ce_tree(; seed=$seed, outdir=joinpath(ACASX_CE_Tree.RESULTDIR, "ACASX_CE_Tree_$(DATA)_seed$seed"), config...)
"""

notifydone() = sendifttt(;value1="$COMP done")

A = JuliaSource[]
for i in RANGE
    push!(A, JuliaSource(template_ce_tree(i)))
end

#include("run_ce_procs.jl")
#fs=julia_process(A, np); notifydone()


text:
promptname(level, name) = "$level|$name > "
function RunDebugger(stack, repl = Base.active_repl, terminal = Base.active_repl.t)

    state = DebuggerState(stack, repl, terminal)

    # Setup debug panel
    panel = LineEdit.Prompt(promptname(state.level, "debug");
        prompt_prefix="\e[38;5;166m",
        prompt_suffix=Base.text_colors[:white],
        on_enter = s->true)

    panel.hist = REPL.REPLHistoryProvider(Dict{Symbol,Any}(:debug => panel))
    REPL.history_reset_state(panel.hist)

    search_prompt, skeymap = LineEdit.setup_search_keymap(panel.hist)
    search_prompt.complete = REPL.LatexCompletions()

    state.main_mode = panel

    panel.on_done = (s,buf,ok)->begin
        line = String(take!(buf))
        old_level = state.level
        if !ok || strip(line) == "q"
            LineEdit.transition(s, :abort)
            LineEdit.reset_state(s)
            return false
        end
        if isempty(strip(line)) && length(panel.hist.history) > 0
            command = panel.hist.history[end]
        else
            command = strip(line)
        end
        do_print_status = true
        cmd1 = split(command,' ')[1]
        do_print_status = try
            execute_command(state, state.stack[state.level], Val{Symbol(cmd1)}(), command)
        catch err
            rethrow(err)
        end
        if old_level != state.level
            panel.prompt = promptname(state.level,"debug")
        end
        LineEdit.reset_state(s)
        if isempty(state.stack)
            LineEdit.transition(s, :abort)
            LineEdit.reset_state(s)
            return false
        end
        if do_print_status
            print_status(Base.pipe_writer(terminal), state)
        end
        return true
    end

    key = '`'
    repl_switch = Dict{Any,Any}(
        key => function (s,args...)
            if isempty(s) || position(LineEdit.buffer(s)) == 0
                prompt = julia_prompt(state, state.stack[1])
                buf = copy(LineEdit.buffer(s))
                LineEdit.transition(s, prompt) do
                    LineEdit.state(s, prompt).input_buffer = buf
                end
            else
                LineEdit.edit_insert(s,key)
            end
        end
    )

    state.standard_keymap = Dict{Any,Any}[skeymap, LineEdit.history_keymap, LineEdit.default_keymap, LineEdit.escape_defaults]
    panel.keymap_dict = LineEdit.keymap([repl_switch;state.standard_keymap])

    print_status(Base.pipe_writer(terminal), state)
    REPL.run_interface(terminal, LineEdit.ModalInterface([panel,search_prompt]))

    return state.overall_result
end

function julia_prompt(state::DebuggerState, frame::JuliaStackFrame)
    # Return early if this has already been called on the state
    isassigned(state.julia_prompt) && return state.julia_prompt[]

    julia_prompt = LineEdit.Prompt(promptname(state.level, "julia");
        # Copy colors from the prompt object
        prompt_prefix = state.repl.prompt_color,
        prompt_suffix = (state.repl.envcolors ? Base.input_color : state.repl.input_color),
        complete = DebugCompletionProvider(state),
        on_enter = REPL.return_callback)
    julia_prompt.hist = state.main_mode.hist
    julia_prompt.hist.mode_mapping[:julia] = julia_prompt

    julia_prompt.on_done = (s,buf,ok)->begin
        if !ok
            LineEdit.transition(s, :abort)
            return false
        end
        xbuf = copy(buf)
        command = String(take!(buf))
        @static if VERSION >= v"1.2.0-DEV.253"
            response = eval_code(state, command)
            REPL.print_response(state.repl, response, true, true)
        else
            ok, result = eval_code(state, command)
            REPL.print_response(state.repl, ok ? result : result[1], ok ? nothing : result[2], true, true)
        end
        println(state.terminal)
        LineEdit.reset_state(s)
    end
    julia_prompt.keymap_dict = LineEdit.keymap([REPL.mode_keymap(state.main_mode); state.standard_keymap])
    state.julia_prompt[] = julia_prompt
    return julia_prompt
end

# Completions

mutable struct DebugCompletionProvider <: REPL.CompletionProvider
    state::DebuggerState
end

function LineEdit.complete_line(c::DebugCompletionProvider, s)
    partial = REPL.beforecursor(s.input_buffer)
    full = LineEdit.input_string(s)
    ret, range, should_complete = completions(c, full, partial)
    return unique!(map(REPLCompletions.completion_text, ret)), partial[range], should_complete
end

function completions(c::DebugCompletionProvider, full, partial)
    mod = moduleof(first(c.state.stack))
    ret, range, should_complete = REPLCompletions.completions(full, partial, mod)

    # TODO Add local variable completions
    return ret, range, should_complete
end


text:
module Forms

using Genie, Stipple, StippleUI, StippleUI.API
import Genie.Renderer.Html: HTMLString, normal_element

export form

function __init__()
  Genie.Renderer.Html.register_normal_element("q__form", context = Genie.Renderer.Html)
end

function form(args...;
              wrap::Function = StippleUI.DEFAULT_WRAPPER,
              noresetfocus::Bool = false,
              kwargs...)
  wrap() do
    Genie.Renderer.Html.q__form(args...; attributes([kwargs...], StippleUI.API.ATTRIBUTES_MAPPINGS)...)
  end
end

end


text:
struct LayerMixture{T<:Real, I<:Integer}
    μ::Vector{T}
    σ::Vector{T}
    N::Vector{T}
    k::I
end

function getpeaks(ping::Ping; thresh=0, order=1, dz=1.0)
    n = length(ping)
    D2 = DerivativeOperator{Float64}(2, order, dz, n, :Dirichlet0, :Dirichlet0)
    ii = [ci.I[1] for ci in findlocalmaxima(ping) if ping[ci] > thresh]
    curvature = D2 * ping
    jj = findall(x -> x < 0, curvature)
    ii = intersect(ii, jj)
    return depths(ping)[ii], ping[ii], curvature[ii]
end

function guesslayers(ping::Ping; thresh=0, order=1, dz=1.0)
    μ, p, c = getpeaks(ping, thresh=thresh, order=order, dz=dz)
    σ = sqrt.(-p ./ c)
    N = p .* sqrt.(2pi * σ.^2)
    k = length(μ)
    return LayerMixture(μ, σ, N, k)
end

function mixpdf(μ, σ, N, z)
    res = zeros(length(z))
    k = length(μ)
    for i in 1:k
        res .+= N[i] * pdf.(Normal(μ[i], σ[i]), z)
    end
    return res
end

mixpdf(mix::LayerMixture, z) = mixpdf(mix.μ, mix.σ, mix.N, z)

function getbasis!(basis, mix, z)
    for i in 1:mix.k
        basis[:, i] = pdf.(Normal(mix.μ[i], mix.σ[i]), z)
    end
end

function getbasis(mix::LayerMixture, z::AbstractVector)
    res = zeros(length(z), mix.k)
    getbasis!(res, mix, z)
    return res
end

function refine_heights!(mix::LayerMixture, basis, ping)
    masked = copy(basis)
    for i in 1:mix.k
        imask = findall(z -> abs(z - mix.μ[i]) > mix.σ[i], depths(ping))
        masked[imask, i] .= 0
    end
    N1 = nnls(basis, ping.data)
    mix.N .= N1
end

function cost(μ, σ, N, ping)
    model = mixpdf(μ, σ, N, depths(ping))
    # return sum((ping.-model).^2 .* ping)
    return sum(abs2, ping - model)
    # return sum(log.(ping) .* (log.(model) .- log.(ping)))
end

function refine_σ!(mix::LayerMixture, ping)
    μ, σ, N, k  = mix.μ, mix.σ, mix.N, mix.k
    fit1 = optimize(θ -> cost(mix.μ, exp.(θ), N, ping), log.(σ))
    mix.σ[:] .= exp.(fit1.minimizer)
    return fit1
end

function refine_μσ!(mix::LayerMixture, ping)
    μ, σ, N, k  = mix.μ, mix.σ, mix.N, mix.k
    lx = [fill(minimum(mix.μ), mix.k); fill(-Inf, mix.k)]
    ux = [fill(maximum(mix.μ), mix.k); fill(log(25), mix.k)]
    θ = [mix.μ; log.(mix.σ)]
    fit1 = optimize(θ -> cost(θ[1:k], exp.(θ[k+1:end]), N, ping), θ)
    μ1 = fit1.minimizer[1:k]
    σ1 = exp.(fit1.minimizer[k+1:end])
    mix.μ[:] .= μ1
    mix.σ[:] .= σ1
    return fit1
end

const refine_funcs = Dict(:σ => refine_σ!, :μσ => refine_μσ!,
    :widths => refine_σ!, :widths_locs => refine_μσ!)

function fit!(mix, ping; tol=eps(), trace=false, refine=:σ)
    basis = getbasis(mix, depths(ping))
    if refine != :none
        refiner! = refine_funcs[refine]
        ss = Inf
        while true
            refine_heights!(mix, basis, ping)
            opt = refine_σ!(mix, ping)
            if trace
                println(opt.minimum)
            end
            if ss - opt.minimum < tol
                return opt
            end
            ss = opt.minimum
        end
    end
end

function fit(mix, ping; tol=eps(), trace=false, refine=:σ)
    mix1 = deepcopy(mix)
    fit!(mix1, ping; tol=eps(), trace=false)
    return mix1
end

function fitlayers(echo::Echogram; thresh=0, tol=eps(), refine=:σ)
    layers = []
    n = size(echo, 2)
    z = echo.z
    printstyled("Detecting layers...\n", color=:green)
    @showprogress for i in 1:n
        mix = guesslayers(getping(echo, i), thresh=thresh)
        fit!(mix, getping(echo, i), tol=tol, refine=refine)
        push!(layers, mix)
    end
    return layers
end

max_stars_repo_name: ElOceanografo/ScatteringLayers

max_issues_repo_name: ElOceanografo/ScatteringLayers

max_forks_repo_name: ElOceanografo/ScatteringLayers


text:
# Testing modulation filterbank response
using Compat.DelimitedFiles
x = [1, zeros(9999)...]
mf = compute_modulation_cfs(4,128,8)
mfb = modulation_filterbank(mf, 16000, 2)
y = filt(mfb, x)

mf_matlab = readdlm(open(joinpath(dirname(@__FILE__), "data", "modfilters_freqs.csv")), ',')
y_matlab = readdlm(open(joinpath(dirname(@__FILE__), "data", "modfilters_response.csv")), ',')

@test y ≈ y_matlab'
@test mf ≈ mf_matlab


text:
module Handlers
    export test_handler

    function test_handler(Adapter, channel, message)
        print("Тестовый обработчик")
    end
end


text:
fname = :ARCqKOp
c = Combi(hessian_operator,PDataK,solve_modelKARC,preprocessKARC,decreaseKARC,TparamsKARC())
include("Template.jl")


text:
# Autogenerated wrapper script for ThriftJuliaCompiler_jll for aarch64-linux-musl
export thrift

JLLWrappers.@generate_wrapper_header("ThriftJuliaCompiler")
JLLWrappers.@declare_executable_product(thrift)
function __init__()
    JLLWrappers.@generate_init_header()
    JLLWrappers.@init_executable_product(
        thrift,
        "bin/thrift",
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
# Misc. Tests
using Schrodinger
using Compat, Compat.Test, Compat.LinearAlgebra, Compat.SparseArrays
include("reffuns.jl")
println("Testing Misc. Functions...")

@testset "Misc. Tests" begin

@testset "Partial Trace" begin
cases = [
    (rand(4,4), (2,), (2,2)),
    (rand(6,6), (1,), (2,3)),
    (rand(24,24), (1,3), (2,4,3)),
    (rand(36,36), (1,), (2,9,2)),
    (rand(48,48), (1,2), (3,4,2,2)),
    (rand(50,50), (2,), (5,5,2)),
    (rand(ComplexF64,72,72), (1,2,4), (3,4,2,3)),]

for (A, out, sysdims) in cases
    @test ptrace(A,out,sysdims)[1] ≈ ptrace_ref(A,out,sysdims)[1]
    #a = median(@benchmark(ptrace($A,$out,$sysdims)))
    #b = median(@benchmark(ptrace_ref($A,$out,$sysdims)))
    #println("ptrace speedup: $(ratio(a,b))")
end
end

end


text:
#
# This is a port (with some simplifications) of Google OR-tools Sudoku (SAT) solver
# https://github.com/google/or-tools/blob/stable/examples/python/sudoku_sat.py
#
# Compared to sudoku_or_tools.jl, here we use the newer SAT solver which has a
# little different API from the older CP solver pywrapcp.
#
# For debugging: Most of the methods are available via Julia's help
# (which is really neat). E.g.
#
# help?> model.AddAllDifferent
# """
# Adds AllDifferent(variables).
#
# This constraint forces all variables to have different values.
#
# Args:
#   variables: a list of integer variables.
#
# Returns:
#   An instance of the `Constraint` class.
# """
#

# A run:
#=
julia> @time solve_sudoku(initial_grid)

status:OPTIMAL
[8, 6, 1, 4, 5, 9, 7, 2, 3]
[4, 5, 2, 3, 1, 7, 6, 9, 8]
[7, 9, 3, 6, 8, 2, 5, 1, 4]
[2, 1, 6, 8, 3, 5, 4, 7, 9]
[9, 8, 4, 2, 7, 6, 1, 3, 5]
[3, 7, 5, 1, 9, 4, 8, 6, 2]
[5, 4, 7, 9, 2, 1, 3, 8, 6]
[1, 3, 9, 5, 6, 8, 2, 4, 7]
[6, 2, 8, 7, 4, 3, 9, 5, 1]

Resonse stats:
CpSolverResponse:
status: OPTIMAL
objective: 0
best_bound: 0
booleans: 0
conflicts: 0
branches: 0
propagations: 0
integer_propagations: 0
restarts: 0
lp_iterations: 0
walltime: 0.00166678
usertime: 0.00166675
deterministic_time: 0
primal_integral: 0

  0.012847 seconds (3.79 k allocations: 149.188 KiB)
=#

#
using PyCall

# Resize matrix to "normal" form
function resize_matrix(grid)
    rows = size(grid)
    transpose(reduce(hcat,grid)) # Suggestion by @Mason Protter @ Zulip
end

# Be sure that ortools are installed correctly
cp = pyimport("ortools.sat.python.cp_model")

"Solves the sudoku problem with the CP-SAT solver."
function solve_sudoku(initial_grid)

    # Create the model.
    model = cp.CpModel()

    cell_size = 3
    line_size = cell_size^2
    line = 1:line_size
    cell = 1:cell_size

    grid = [model.NewIntVar(1, line_size, "grid[$i,$j]") for i in line, j in line]

    # AllDifferent on rows.
    for i in line
        model.AddAllDifferent([grid[i, j] for j in line])
    end

    # AllDifferent on columns.
    for j in line
        model.AddAllDifferent([grid[i, j] for i in line])
    end

    # AllDifferent on cells.
    for i in cell, j in cell
        model.AddAllDifferent(
                        vec([grid[(i-1) * cell_size + di, (j-1) * cell_size + dj] for di in cell, dj in cell] )
                    )
    end

    # Initial values.
    for i in line, j in line
        if initial_grid[i,j] > 0
            model.Add(grid[i, j] == initial_grid[i,j])
        end
    end

    # Solve and print out the solution.
    solver = cp.CpSolver()
    status = solver.Solve(model)
    println("status:", solver.StatusName())
    if status == cp.OPTIMAL
        for i in line
            println([solver.Value(grid[i, j]) for j in line])
        end
    end
    println()
    println("Resonse stats:\n", solver.ResponseStats())

    # Return the model and solver since it's instructive to see what they contain...
    return model,solver

end

initial_grid = resize_matrix([[0, 6, 0, 0, 5, 0, 0, 2, 0],
                              [0, 0, 0, 3, 0, 0, 0, 9, 0],
                              [7, 0, 0, 6, 0, 0, 0, 1, 0],
                              [0, 0, 6, 0, 3, 0, 4, 0, 0],
                              [0, 0, 4, 0, 7, 0, 1, 0, 0],
                              [0, 0, 5, 0, 9, 0, 8, 0, 0],
                              [0, 4, 0, 0, 0, 1, 0, 0, 6],
                              [0, 3, 0, 0, 0, 8, 0, 0, 0],
                              [0, 2, 0, 0, 4, 0, 0, 5, 0]])

@time model,solver = solve_sudoku(initial_grid)

max_stars_repo_name: tias/hakank

max_issues_repo_name: tias/hakank

max_forks_repo_name: tias/hakank


text:
function part1()
	lines = readlines("inputD9.txt")
	depths = [[parse(Int, i) for i in line] for line in lines]
	lowvals = Int[]

	for (i, line) in enumerate(depths)
		for (j, val) in enumerate(line)
			matches = true
			if i - 1 >= 1
				if depths[i-1][j] <= val
					matches = false
				end
			end
			if i + 1 <= length(depths)
				if depths[i+1][j] <= val
					matches = false
				end
			end
			if j - 1 >= 1
				if depths[i][j-1] <= val
					matches = false
				end
			end
			if j + 1 <= length(line)
				if depths[i][j+1] <= val
					matches = false
				end
			end

			if matches
				push!(lowvals, val)
			end
		end
	end

	return sum(lowvals .+ 1)
end

function part2()
	lines = readlines("inputD9.txt")
	depths = [[parse(Int, i) for i in line] for line in lines]
	Coordtype = NTuple{2, Int}
	lowvals = Coordtype[]

	for (i, line) in enumerate(depths)
		for (j, val) in enumerate(line)
			matches = true
			if i - 1 >= 1
				if depths[i-1][j] <= val
					matches = false
				end
			end
			if i + 1 <= length(depths)
				if depths[i+1][j] <= val
					matches = false
				end
			end
			if j - 1 >= 1
				if depths[i][j-1] <= val
					matches = false
				end
			end
			if j + 1 <= length(line)
				if depths[i][j+1] <= val
					matches = false
				end
			end

			if matches
				push!(lowvals, (i, j))
			end
		end
	end

	basins :: Vector{Vector{Coordtype}} = []
	for start in lowvals
		basin = Coordtype[start]
		checked = Coordtype[]
		while any((!(b in checked)) for b in basin)
			x, y = first(b for b in basin if !(b in checked))
			valatcoord = depths[x][y]
			if valatcoord < 8
				if x - 1 >= 1
					if depths[x-1][y] != 9
						push!(basin, (x-1, y))
					end
				end
				if x + 1 <= length(depths)
					if depths[x+1][y] != 9
						push!(basin, (x+1, y))
					end
				end
				if y - 1 >= 1
					if depths[x][y-1] != 9
						push!(basin, (x, y-1))
					end
				end
				if y + 1 <= length(depths[x])
					if depths[x][y+1] != 9
						push!(basin, (x, y+1))
					end
				end
			end

			push!(checked, (x, y))
		end

		basin = collect(Set(basin))
		push!(basins, basin)
	end
	return prod(reverse(sort(length.(basins)))[1:3])
end

println(part1())
println(part2())