text:
@generated function saturated_add(x::I, y::I) where {I <: IntegerTypesHW}
    typ = "i$(8sizeof(I))"
    s = I <: Signed ? 's' : 'u'
    f = "@llvm.$(s)add.sat.$typ"
    decl = "declare $typ $f($typ, $typ)"
    instrs = """
        %res = call $typ $f($typ %0, $typ %1)
        ret $typ %res
    """
    llvmcall_expr(decl, instrs, JULIA_TYPES[I], :(Tuple{$I,$I}), typ, [typ,typ], [:x,:y])
end
@generated function saturated_add(x::Vec{W,I}, y::Vec{W,I}) where {W,I}
    typ = "i$(8sizeof(I))"
    vtyp = "<$W x $(typ)>"
    s = I <: Signed ? 's' : 'u'
    f = "@llvm.$(s)add.sat.$(suffix(W,typ))"
    decl = "declare $vtyp $f($vtyp, $vtyp)"
    instrs = """
        %res = call $vtyp $f($vtyp %0, $vtyp %1)
        ret $vtyp %res
    """
    llvmcall_expr(decl, instrs, :(_Vec{$W,$I}), :(Tuple{_Vec{$W,$I},_Vec{$W,$I}}), vtyp, [vtyp,vtyp], [:(data(x)),:(data(y))])
end

@eval @inline function assume(b::Bool)
    $(llvmcall_expr("declare void @llvm.assume(i1)", "%b = trunc i8 %0 to i1\ncall void @llvm.assume(i1 %b)\nret void", :Cvoid, :(Tuple{Bool}), "void", ["i8"], [:b]))
end

@generated function bitreverse(i::I) where {I<:Base.BitInteger}
    typ = string('i', 8sizeof(I))
    f = "$typ @llvm.bitreverse.$(typ)"
    decl = "declare $f($typ)"
    instr = "%res = call $f($(typ) %0)\nret $(typ) %res"
    llvmcall_expr(decl, instr, JULIA_TYPES[I], :(Tuple{$I}), typ, [typ], [:i])
end

# Doesn't work, presumably because the `noalias` doesn't propagate outside the function boundary.
# @generated function noalias!(ptr::Ptr{T}) where {T <: NativeTypes}
#     Base.libllvm_version ≥ v"11" || return :ptr
#     typ = LLVM_TYPES[T]
#     # if Base.libllvm_version < v"10"
#     #     funcname = "noalias" * typ
#     #     decls = "define noalias $typ* @$(funcname)($typ *%a) willreturn noinline { ret $typ* %a }"
#     #     instrs = """
#     #         %ptr = inttoptr $ptyp %0 to $typ*
#     #         %naptr = call $typ* @$(funcname)($typ* %ptr)
#     #         %jptr = ptrtoint $typ* %naptr to $ptyp
#     #         ret $ptyp %jptr
#     #     """
#     # else
#     decls = "declare void @llvm.assume(i1)"
#     instrs = """
#                 %ptr = inttoptr $(JULIAPOINTERTYPE) %0 to $typ*
#                 call void @llvm.assume(i1 true) ["noalias"($typ* %ptr)]
#                 %int = ptrtoint $typ* %ptr to $(JULIAPOINTERTYPE)
#                 ret $(JULIAPOINTERTYPE) %int
#             """
#     llvmcall_expr(decls, instrs, :(Ptr{$T}), :(Tuple{Ptr{$T}}), JULIAPOINTERTYPE, [JULIAPOINTERTYPE], [:ptr])
# end
# @inline noalias!(x) = x

# @eval @inline function expect(b::Bool)
#     $(llvmcall_expr("declare i1 @llvm.expect.i1(i1, i1)", """
#     %b = trunc i8 %0 to i1
#     %actual = call i1 @llvm.expect.i1(i1 %b, i1 true)
#     %byte = zext i1 %actual to i8
#     ret i8 %byte""", :Bool, :(Tuple{Bool}), "i8", ["i8"], [:b]))
# end
# @generated function expect(i::I, ::Val{N}) where {I <: Integer, N}
#     ityp = 'i' * string(8sizeof(I))
#     llvmcall_expr("declare i1 @llvm.expect.$ityp($ityp, i1)", """
#     %actual = call $ityp @llvm.expect.$ityp($ityp %0, $ityp $N)
#     ret $ityp %actual""", I, :(Tuple{$I}), ityp, [ityp], [:i])
# end

# for (op,f) ∈ [("abs",:abs)]
# end
if Base.libllvm_version ≥ v"12"
  for (op,f,S) ∈ [("smax",:max,:Signed),("smin",:min,:Signed),("umax",:max,:Unsigned),("umin",:min,:Unsigned)]
    vf = Symbol(:v,f)
    @eval @generated $vf(v1::Vec{W,T}, v2::Vec{W,T}) where {W, T <: $S} = (TS = JULIA_TYPES[T]; build_llvmcall_expr($op, W, TS, [W, W], [TS, TS]))
    @eval @inline $vf(v1::Vec{W,<:$S}, v2::Vec{W,<:$S}) where {W} = ((v3,v4) = promote(v1,v2); $vf(v3,v4))
  end
  # TODO: clean this up.
  @inline vmax(v1::Vec{W,<:Signed}, v2::Vec{W,<:Unsigned}) where {W} = vifelse(v1 > v2, v1, v2)
  @inline vmin(v1::Vec{W,<:Signed}, v2::Vec{W,<:Unsigned}) where {W} = vifelse(v1 < v2, v1, v2)
  @inline vmax(v1::Vec{W,<:Unsigned}, v2::Vec{W,<:Signed}) where {W} = vifelse(v1 > v2, v1, v2)
  @inline vmin(v1::Vec{W,<:Unsigned}, v2::Vec{W,<:Signed}) where {W} = vifelse(v1 < v2, v1, v2)
else
    @inline vmax(v1::Vec{W,<:Integer}, v2::Vec{W,<:Integer}) where {W} = vifelse(v1 > v2, v1, v2)
    @inline vmin(v1::Vec{W,<:Integer}, v2::Vec{W,<:Integer}) where {W} = vifelse(v1 < v2, v1, v2)
end
@inline vmax_fast(v1::Vec{W,<:Integer}, v2::Vec{W,<:Integer}) where {W} = vmax(v1, v2)
@inline vmin_fast(v1::Vec{W,<:Integer}, v2::Vec{W,<:Integer}) where {W} = vmin(v1, v2)

# floating point
for (op,f) ∈ [("sqrt",:vsqrt),("fabs",:vabs),("floor",:vfloor),("ceil",:vceil),("trunc",:vtrunc),("nearbyint",:vround)#,("roundeven",:roundeven)
              ]
    # @eval @generated Base.$f(v1::Vec{W,T}) where {W, T <: Union{Float32,Float64}} = llvmcall_expr($op, W, T, (W,), (T,), "nsz arcp contract afn reassoc")
    @eval @generated $f(v1::Vec{W,T}) where {W, T <: Union{Float32,Float64}} = (TS = T === Float32 ? :Float32 : :Float64; build_llvmcall_expr($op, W, TS, [W], [TS], "fast"))
end
@inline vsqrt(v::AbstractSIMD{W,T}) where {W,T<:IntegerTypes} = vsqrt(float(v))
@inline vsqrt(v::FloatingTypes) = Base.sqrt_llvm_fast(v)
@inline vsqrt(v::Integer) = Base.sqrt_llvm_fast(float(v))
# @inline roundeven(v::VecUnroll) = VecUnroll(fmap(roundeven, getfield(v,:data)))
# @generated function Base.round(::Type{Int64}, v1::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
#     llvmcall_expr("lrint", W, Int64, (W,), (T,), "")
# end
# @generated function Base.round(::Type{Int32}, v1::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
#     llvmcall_expr("lrint", W, Int32, (W,), (T,), "")
# end
@inline vtrunc(::Type{I}, v::VecUnroll{N,1,T,T}) where {N, I<:IntegerTypesHW, T <: NativeTypes} = VecUnroll(fmap(Base.unsafe_trunc, I, data(v)))
@inline vtrunc(::Type{I}, v::AbstractSIMD{W,T}) where {W, I<:IntegerTypesHW, T <: NativeTypes} = vconvert(I, v)
for f ∈ [:vround, :vfloor, :vceil]
    @eval @inline $f(::Type{I}, v::AbstractSIMD{W,T}) where {W,I<:IntegerTypesHW,T <: NativeTypes} = vconvert(I, $f(v))
end
for f ∈ [:vtrunc, :vround, :vfloor, :vceil]
    @eval @inline $f(v::AbstractSIMD{W,I}) where {W,I<:IntegerTypesHW} = v
end

# """
#    setbits(x::Unsigned, y::Unsigned, mask::Unsigned)

# If you have AVX512, setbits of vector-arguments will select bits according to mask `m`, selecting from `y` if 0 and from `x` if `1`.
# For scalar arguments, or vector arguments without AVX512, `setbits` requires the additional restrictions on `y` that all bits for
# which `m` is 1, `y` must be 0.
# That is for scalar arguments or vector arguments without AVX512, it requires the restriction that
# ((y ⊻ m) & m) == m
# """
# @inline setbits(x, y, m) = (x & m) | y

"""
   bitselect(m::Unsigned, x::Unsigned, y::Unsigned)

If you have AVX512, setbits of vector-arguments will select bits according to mask `m`, selecting from `x` if 0 and from `y` if `1`.
For scalar arguments, or vector arguments without AVX512, `setbits` requires the additional restrictions on `y` that all bits for
which `m` is 1, `y` must be 0.
That is for scalar arguments or vector arguments without AVX512, it requires the restriction that
((y ⊻ m) & m) == m
"""
@inline bitselect(m, x, y) = ((~m) & x) | (m & y)

# AVX512 lets us use 1 instruction instead of 2 dependent instructions to set bits
@generated function vpternlog(m::Vec{W,UInt64}, x::Vec{W,UInt64}, y::Vec{W,UInt64}, ::Val{L}) where {W, L}
    @assert W ∈ (2,4,8)
    bits = 64W
    decl64 = "declare <$W x i64> @llvm.x86.avx512.mask.pternlog.q.$(bits)(<$W x i64>, <$W x i64>, <$W x i64>, i32, i8)"
    instr64 = """
                %res = call <$W x i64> @llvm.x86.avx512.mask.pternlog.q.$(bits)(<$W x i64> %0, <$W x i64> %1, <$W x i64> %2, i32 $L, i8 -1)
                ret <$W x i64> %res
            """
    arg_syms = [:(data(m)), :(data(x)), :(data(y))]
    llvmcall_expr(decl64, instr64, :(_Vec{$W,UInt64}), :(Tuple{_Vec{$W,UInt64},_Vec{$W,UInt64},_Vec{$W,UInt64}}), "<$W x i64>", ["<$W x i64>", "<$W x i64>", "<$W x i64>"], arg_syms)
end
@generated function vpternlog(m::Vec{W,UInt32}, x::Vec{W,UInt32}, y::Vec{W,UInt32}, ::Val{L}) where {W, L}
    @assert W ∈ (4,8,16)
    bits = 32W
    decl32 = "declare <$W x i32> @llvm.x86.avx512.mask.pternlog.d.$(bits)(<$W x i32>, <$W x i32>, <$W x i32>, i32, i16)"
    instr32 = """
                %res = call <$W x i32> @llvm.x86.avx512.mask.pternlog.d.$(bits)(<$W x i32> %0, <$W x i32> %1, <$W x i32> %2, i32 $L, i16 -1)
                ret <$W x i32> %res
            """
    arg_syms = [:(data(m)), :(data(x)), :(data(y))]
    llvmcall_expr(decl32, instr32, :(_Vec{$W,UInt32}), :(Tuple{_Vec{$W,UInt32},_Vec{$W,UInt32},_Vec{$W,UInt32}}), "<$W x i32>", ["<$W x i32>", "<$W x i32>", "<$W x i32>"], arg_syms)
end
    # @eval @generated function setbits(x::Vec{W,T}, y::Vec{W,T}, m::Vec{W,T}) where {W,T <: Union{UInt32,UInt64}}
    #     ex = if W*sizeof(T) ∈ (16,32,64)
    #         :(vpternlog(x, y, m, Val{216}()))
    #     else
    #         :((x & m) | y)
    #     end
    #     Expr(:block, Expr(:meta, :inline), ex)
# end

@inline _bitselect(m::Vec{W,T}, x::Vec{W,T}, y::Vec{W,T}, ::False) where {W,T<:Union{UInt32,UInt64}} = ((~m) & x) | (m & y)
@inline _bitselect(m::Vec{W,T}, x::Vec{W,T}, y::Vec{W,T}, ::True) where {W,T<:Union{UInt32,UInt64}} = vpternlog(m, x, y, Val{172}())

@inline function bitselect(m::Vec{W,T}, x::Vec{W,T}, y::Vec{W,T}) where {W,T <: Union{UInt32,UInt64}}
    bytes = StaticInt{W}() * static_sizeof(T)
    use_ternary_logic = has_feature(Val(:x86_64_avx512f)) & ((eq(bytes, StaticInt{16}()) | eq(bytes, StaticInt{32}())) | eq(bytes, StaticInt{64}()))
    _bitselect(m, x, y, use_ternary_logic)
end

@inline function _vcopysign(v1::Vec{W,Float64}, v2::Vec{W,Float64}, ::True) where {W}
    reinterpret(Float64, bitselect(Vec{W,UInt64}(0x8000000000000000), reinterpret(UInt64, v1), reinterpret(UInt64, v2)))
end
@inline function _vcopysign(v1::Vec{W,Float32}, v2::Vec{W,Float32}, ::True) where {W}
    reinterpret(Float32, bitselect(Vec{W,UInt32}(0x80000000), reinterpret(UInt32, v1), reinterpret(UInt32, v2)))
end
@inline function _vcopysign(v1::Vec{W,Float64}, v2::Vec{W,Float64}, ::False) where {W}
    llvm_copysign(v1, v2)
end
@inline function _vcopysign(v1::Vec{W,Float32}, v2::Vec{W,Float32}, ::False) where {W}
    llvm_copysign(v1, v2)
end

@inline function vcopysign(v1::Vec{W,T}, v2::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
    _vcopysign(v1, v2, has_feature(Val(:x86_64_avx512f)))
end

for (op,f,fast) ∈ [
    ("minnum",:vmin,false),("minnum",:vmin_fast,true),
    ("maxnum",:vmax,false),("maxnum",:vmax_fast,true),
    ("copysign",:llvm_copysign,true)
]
    ff = fast_flags(fast)
    fast && (ff *= " nnan")
    @eval @generated function $f(v1::Vec{W,T}, v2::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
        TS = T === Float32 ? :Float32 : :Float64
        build_llvmcall_expr($op, W, TS, [W, W], [TS, TS], $ff)
    end
end
@inline _signbit(v::Vec{W, I}) where {W, I<:Signed} = v & Vec{W,I}(typemin(I))
@inline vcopysign(v1::Vec{W,I}, v2::Vec{W,I}) where {W, I <: Signed} = vifelse(_signbit(v1) == _signbit(v2), v1, -v1)

@inline vcopysign(x::Float32, v::Vec{W}) where {W} = vcopysign(vbroadcast(Val{W}(), x), v)
@inline vcopysign(x::Float64, v::Vec{W}) where {W} = vcopysign(vbroadcast(Val{W}(), x), v)
@inline vcopysign(x::Float32, v::VecUnroll{N,W,T,V}) where {N,W,T,V} = vcopysign(vbroadcast(Val{W}(), x), v)
@inline vcopysign(x::Float64, v::VecUnroll{N,W,T,V}) where {N,W,T,V} = vcopysign(vbroadcast(Val{W}(), x), v)
@inline vcopysign(v::Vec, u::VecUnroll) = VecUnroll(fmap(vcopysign, v, getfield(u, :data)))
@inline vcopysign(v::Vec{W,T}, x::NativeTypes) where {W,T} = vcopysign(v, Vec{W,T}(x))
@inline vcopysign(v1::Vec{W,T}, v2::Vec{W}) where {W,T} = vcopysign(v1, convert(Vec{W,T}, v2))
@inline vcopysign(v1::Vec{W,T}, ::Vec{W,<:Unsigned}) where {W,T} = vabs(v1)
@inline vcopysign(s::IntegerTypesHW, v::Vec{W}) where {W} = vcopysign(vbroadcast(Val{W}(), s), v)
@inline vcopysign(v::Vec, s::UnsignedHW) = vabs(v)
@inline vcopysign(v::VecUnroll, s::UnsignedHW) = vabs(v)
@inline vcopysign(v::VecUnroll{N,W,T}, s::NativeTypes) where {N,W,T} = VecUnroll(fmap(vcopysign, getfield(v, :data), vbroadcast(Val{W}(), s)))

for (f, fl) ∈ [(:vmax, :max), (:vmax_fast, :max_fast), (:vmin, :min), (:vmin_fast, :min_fast)]
    @eval begin
        @inline function $f(a::Union{FloatingTypes,Vec{<:Any,<:FloatingTypes}}, b::Union{FloatingTypes,Vec{<:Any,<:FloatingTypes}})
            c, d = promote(a, b)
            $f(c, d)
        end
        @inline function $f(a::Union{FloatingTypes,Vec{<:Any,<:FloatingTypes}}, b::Union{NativeTypes,Vec{<:Any,<:NativeTypes}})
            c, d = promote(a, b)
            $f(c, d)
        end
        @inline function $f(a::Union{NativeTypes,Vec{<:Any,<:NativeTypes}}, b::Union{FloatingTypes,Vec{<:Any,<:FloatingTypes}})
            c, d = promote(a, b)
            $f(c, d)
        end
        @inline $f(v::Vec{W,<:IntegerTypesHW}, s::IntegerTypesHW) where {W} = $f(v, vbroadcast(Val{W}(), s))
        @inline $f(s::IntegerTypesHW, v::Vec{W,<:IntegerTypesHW}) where {W} = $f(vbroadcast(Val{W}(), s), v)
        @inline $f(a::FloatingTypes, b::FloatingTypes) = Base.FastMath.$fl(a, b)
        @inline $f(a::Integer, b::Integer) = Base.FastMath.$fl(a, b)
    end
end

# ternary
for (op,f,fast) ∈ [
    ("fma",:vfma,false),("fma",:vfma_fast,true),
    ("fmuladd",:vmuladd,false),("fmuladd",:vmuladd_fast,true)
]
  @eval @generated function $f(v1::Vec{W,T}, v2::Vec{W,T}, v3::Vec{W,T}) where {W, T <: FloatingTypes}
    TS = JULIA_TYPES[T]
    build_llvmcall_expr($op, W, TS, [W, W, W], [TS, TS, TS], $(fast_flags(fast)))
  end
end
# @inline Base.fma(a::Vec, b::Vec, c::Vec) = vfma(a,b,c)
# @inline Base.muladd(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W,T<:FloatingTypes} = vmuladd(a,b,c)
# Generic fallbacks
@inline vfma(a::NativeTypes, b::NativeTypes, c::NativeTypes) = fma(a,b,c)
@inline vmuladd(a::NativeTypes, b::NativeTypes, c::NativeTypes) = muladd(a,b,c)
@inline vfma_fast(a::NativeTypes, b::NativeTypes, c::NativeTypes) = fma(a,b,c)
@inline vmuladd_fast(a::Float32, b::Float32, c::Float32) =  Base.FastMath.add_float_fast(Base.FastMath.mul_float_fast(a,b),c)
@inline vmuladd_fast(a::Float64, b::Float64, c::Float64) =  Base.FastMath.add_float_fast(Base.FastMath.mul_float_fast(a,b),c)
@inline vmuladd_fast(a::NativeTypes, b::NativeTypes, c::NativeTypes) = Base.FastMath.add_fast(Base.FastMath.mul_fast(a,b),c)
@inline vfma(a, b, c) = fma(a,b,c)
@inline vmuladd(a, b, c) = muladd(a,b,c)
@inline vfma_fast(a, b, c) = fma(a,b,c)
@inline vmuladd_fast(a, b, c) = Base.FastMath.add_fast(Base.FastMath.mul_fast(a,b),c)
for f ∈ [:vfma, :vmuladd, :vfma_fast, :vmuladd_fast]
    @eval @inline function $f(v1::AbstractSIMD{W,T}, v2::AbstractSIMD{W,T}, v3::AbstractSIMD{W,T}) where {W,T <: IntegerTypesHW}
        vadd(vmul(v1, v2), v3)
    end
end

# vfmadd -> muladd -> promotes arguments to hit definitions from VectorizationBase
# const vfmadd = FMA_FAST ? vfma : vmuladd
@inline _vfmadd(a, b, c, ::True) = vfma(a, b, c)
@inline _vfmadd(a, b, c, ::False) = vmuladd(a, b, c)
@inline vfmadd(a, b, c) = _vfmadd(a, b, c, fma_fast())
@inline vfnmadd(a, b, c) = vfmadd(-a, b, c)
@inline vfmsub(a, b, c) = vfmadd(a, b, -c)
@inline vfnmsub(a, b, c) = -vfmadd(a, b, c)
# const vfmadd_fast = FMA_FAST ? vfma_fast : vmuladd_fast
@inline _vfmadd_fast(a, b, c, ::True) = vfma_fast(a, b, c)
@inline _vfmadd_fast(a, b, c, ::False) = vmuladd_fast(a, b, c)
@inline vfmadd_fast(a, b, c) = _vfmadd_fast(a, b, c, fma_fast())
# @inline vfnmadd_fast(a, b, c) = @fastmath c - a * b
@inline vfnmadd_fast(a, b, c) = vfmadd_fast(Base.FastMath.sub_fast(a), b, c)
@inline vfmsub_fast(a, b, c) = vfmadd_fast(a, b, Base.FastMath.sub_fast(c))
@inline vfnmsub_fast(a, b, c) = Base.FastMath.sub_fast(vfmadd_fast(a, b, c))
@inline vfnmadd_fast(a::Union{Unsigned,AbstractSIMD{<:Any,<:Union{Unsigned,Bit,Bool}}}, b, c) = Base.FastMath.sub_fast(c, Base.FastMath.mul_fast(a,b))
@inline vfmsub_fast(a, b, c::Union{Unsigned,AbstractSIMD{<:Any,<:Union{Unsigned,Bit,Bool}}}) = Base.FastMath.sub_fast(Base.FastMath.mul_fast(a, b), c)
# floating vector, integer scalar
# @generated function Base.:(^)(v1::Vec{W,T}, v2::Int32) where {W, T <: Union{Float32,Float64}}
#     llvmcall_expr("powi", W, T, (W, 1), (T, Int32), "nsz arcp contract afn reassoc")
# end
# @inline ifelse_reduce_step(f::F, a::Number, b::Number) where {F} = ifelse(f(a,b), a, b)
@inline firstelement(x::AbstractSIMDVector) = extractelement(x,0)
@inline secondelement(x::AbstractSIMDVector) = extractelement(x,1)
@inline firstelement(x::VecUnroll) = VecUnroll(fmap(extractelement, data(x), 0))
@inline secondelement(x::VecUnroll) = VecUnroll(fmap(extractelement, data(x), 1))

@inline ifelse_reduce(f::F, x::Number) where {F} = x
@inline function ifelse_reduce(f::F, x::AbstractSIMD{2,T}) where {F,T}
  a = firstelement(x)
  b = secondelement(x)
  ifelse(f(a,b), a, b)::T
end
@inline function ifelse_reduce(f::F, x::AbstractSIMD{W,T}) where {F,W,T}
  a = uppervector(x)
  b = lowervector(x)
  ifelse_reduce(f, ifelse(f(a,b), a, b))::T
end
@inline ifelse_reduce(f::F, x::MM) where {F} = ifelse_reduce(f, Vec(x))

# @inline ifelse_reduce(f::F, x::VecUnroll) where {F} = ifelse_reduce(f, ifelse_collapse(f, x))

@inline ifelse_collapse(f::F, a, x::Tuple{}) where {F} = a
@inline function ifelse_collapse(f::F, a, x::Tuple{T}) where {F,T}
  b = first(x)
  ifelse(f(a,b), a, b)::typeof(a)
end
@inline function ifelse_collapse(f::F, a, x::Tuple) where {F}
  b = first(x)
  ifelse_collapse(f, ifelse(f(a,b), a, b), Base.tail(x))::typeof(a)
end
@inline function ifelse_collapse(f::F, x::VecUnroll{N,W,T,V}) where {F,N,W,T,V}
  d = data(x)
  ifelse_collapse(f, first(d), Base.tail(d))::V
end
# @inline function ifelse_collapse(f::F, x::VecUnroll) where {F}
#   d = data(x)
#   ifelse_collapse(f, first(d), Base.tail(d))
# end

@inline ifelse_reduce_mirror(f::F, x::Number, y::Number) where {F} = x, y
@inline function ifelse_reduce_mirror(f::F, x::AbstractSIMD{2}, y::AbstractSIMD{2}) where {F}
  a = firstelement(x); b = secondelement(x)
  m = firstelement(y); n = secondelement(y)
  fmn = f(m,n)
  ifelse(fmn, a, b), ifelse(fmn, m, n)
end
@inline function ifelse_reduce_mirror(f::F, x::AbstractSIMD, y::AbstractSIMD) where {F}
  a = uppervector(x); b = lowervector(x)
  m = uppervector(y); n = lowervector(y)
  fmn = f(m,n)
  ifelse_reduce_mirror(f, ifelse(fmn, a, b), ifelse(fmn, m, n))
end
@inline ifelse_reduce_mirror(f::F, x::MM, y::MM) where {F} = ifelse_reduce_mirror(f, Vec(x), Vec(y))

function collapse_mirror_expr(N, op, final)
  N += 1
  t = Expr(:tuple); m = Expr(:tuple);
  s = Vector{Symbol}(undef, N);
  r = Vector{Symbol}(undef, N);
  cmp = Vector{Symbol}(undef, N>>>1);
  for n ∈ 1:N
    s_n = s[n] = Symbol(:v_, n)
    push!(t.args, s_n)
    r_n = r[n] = Symbol(:r_, n)
    push!(m.args, r_n)
    n ≤ length(cmp) && (cmp[n] = Symbol(:cmp_, n))
  end
  q = quote
    $(Expr(:meta,:inline))
    $m = data(a)
    $t = data(x)
  end
  _final = if final == 1
    1
  else
    2final
  end
  while N > _final
    for n ∈ 1:N >>> 1
      push!(q.args, Expr(:(=), cmp[n], Expr(:call, op, s[n], s[n + (N >>> 1)])))
      push!(q.args, Expr(:(=), s[n], Expr(:call, ifelse, cmp[n], s[n], s[n + (N >>> 1)])))
      push!(q.args, Expr(:(=), r[n], Expr(:call, ifelse, cmp[n], r[n], r[n + (N >>> 1)])))
    end
    if isodd(N)
      push!(q.args, Expr(:(=), cmp[1], Expr(:call, op, s[1], s[N])))
      push!(q.args, Expr(:(=), s[1], Expr(:call, ifelse, cmp[1], s[1], s[N])))
      push!(q.args, Expr(:(=), r[1], Expr(:call, ifelse, cmp[1], r[1], r[N])))
    end
    N >>>= 1
  end
  if final ≠ 1
    for n ∈ final+1:N
      push!(q.args, Expr(:(=), cmp[n-final], Expr(:call, op, s[n-final], s[n])))
      push!(q.args, Expr(:(=), s[n-final], Expr(:call, ifelse, cmp[n-final], s[n-final], s[n])))
      push!(q.args, Expr(:(=), r[n-final], Expr(:call, ifelse, cmp[n-final], r[n-final], r[n])))
    end
    # t = Expr(:tuple)
    m = Expr(:tuple)
    for n ∈ 1:final
      # push!(t.args, s[n])
      push!(m.args, r[n])
    end
    push!(q.args, :(VecUnroll($m)))
    # push!(q.args, :((VecUnroll($t),VecUnroll($m))))
    # push!(q.args, :(@show(VecUnroll($t),VecUnroll($m))))
  end
  q
end
@generated ifelse_collapse_mirror(f::F, a::VecUnroll{N}, x::VecUnroll{N}) where {F,N} = collapse_mirror_expr(N, :f, 1)
# @generated ifelse_collapse_mirror(f::F, a::VecUnroll{N}, x::VecUnroll{N}, ::StaticInt{C}) where {F,N,C} = collapse_mirror_expr(N, :f, C)
@generated ifelse_collapse_mirror(f::F, a::VecUnroll{N}, x::VecUnroll{N}, ::StaticInt{C}) where {C,N,F} = collapse_mirror_expr(N, :f, C)

# @inline ifelse_collapse_mirror(f::F, a, ::Tuple{}, x, ::Tuple{}) where {F} = a, x
# @inline function ifelse_collapse_mirror(f::F, a, c::Tuple{T}, x, z::Tuple{T}) where {F,T}
#   b = first(c); y = first(z)
#   fxy = f(x,y)
#   ifelse(fxy, a, b), ifelse(fxy, x, y)
# end
# @inline function ifelse_collapse_mirror(f::F, a, c::Tuple, x, z::Tuple) where {F}
#   b = first(c); y = first(z)
#   fxy = f(x,y)
#   ifelse_collapse_mirror(f, ifelse(fxy, a, b), Base.tail(c), ifelse(fxy, x, y), Base.tail(z))
# end
# @inline function ifelse_collapse_mirror(f::F, x::VecUnroll, y::VecUnroll) where {F}
#   dx = data(x); dy = data(y)
#   ifelse_collapse_mirror(f, first(dx), Base.tail(dx), first(dy), Base.tail(dy))
# end

for (opname,f) ∈ [
  ("fadd",:vsum),
  ("fmul",:vprod)
]
  if Base.libllvm_version < v"12"
    op = "experimental.vector.reduce.v2." * opname
  else
    op = "vector.reduce." * opname
  end
  @eval @generated function $f(v1::T, v2::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
    TS = JULIA_TYPES[T]
    build_llvmcall_expr($op, -1, TS, [1, W], [TS, TS], "nsz arcp contract afn reassoc")
  end
end
@inline vsum(s::S, v::Vec{W,T}) where {W,T,S} = Base.FastMath.add_fast(s, vsum(v))
@inline vprod(s::S, v::Vec{W,T}) where {W,T,S} = Base.FastMath.mul_fast(s, vprod(v))
# for (op,f) ∈ [
#   ("vector.reduce.fmax",:vmaximum),
#   ("vector.reduce.fmin",:vminimum)
# ]
#   Base.libllvm_version < v"12" && (op = "experimental." * op)
#   @eval @generated function $f(v1::Vec{W,T}) where {W, T <: Union{Float32,Float64}}
#     TS = JULIA_TYPES[T]
#     build_llvmcall_expr($op, -1, TS, [W], [TS], "nsz arcp contract afn reassoc")
#   end
# end
@inline vminimum(x) =  ifelse_reduce(<, x)
@inline vmaximum(x) =  ifelse_reduce(>, x)
# @inline vminimum(x, y) =  ifelse_reduce(<, x)
# @inline vmaximum(x, y) =  ifelse_reduce(>, (ifelse_reduce(>, x), y))
for (op,f,S) ∈ [
  ("vector.reduce.add",:vsum,:Integer),
  ("vector.reduce.mul",:vprod,:Integer),
  ("vector.reduce.and",:vall,:Integer),
  ("vector.reduce.or",:vany,:Integer),
  ("vector.reduce.xor",:vxorreduce,:Integer),
  ("vector.reduce.smax",:vmaximum,:Signed),
  ("vector.reduce.smin",:vminimum,:Signed),
  ("vector.reduce.umax",:vmaximum,:Unsigned),
  ("vector.reduce.umin",:vminimum,:Unsigned)
]
  Base.libllvm_version < v"12" && (op = "experimental." * op)
  @eval @generated function $f(v1::Vec{W,T}) where {W, T <: $S}
    TS = JULIA_TYPES[T]
    build_llvmcall_expr($op, -1, TS, [W], [TS])
  end
end
if Sys.ARCH == :aarch64 # TODO: maybe the default definition will stop segfaulting some day?
  for I ∈ (:Int64, :UInt64), (f,op) ∈ ((:vmaximum,:max),(:vminimum,:min))
    @eval @inline $f(v::Vec{W,$I}) where {W} = ArrayInterface.reduce_tup($op, Tuple(v))
  end
end

#         W += W
#     end
# end
@inline vsum(v::Vec{W,T}) where {W,T<:Union{Float32,Float64}} = vsum(-zero(T), v)
@inline vprod(v::Vec{W,T}) where {W,T<:Union{Float32,Float64}} = vprod(one(T), v)
@inline vsum(x, v::Vec{W,T}) where {W,T<:Union{Float32,Float64}} = vsum(convert(T, x), v)
@inline vprod(x, v::Vec{W,T}) where {W,T<:Union{Float32,Float64}} = vprod(convert(T, x), v)

for (f,f_to,op,reduce,twoarg) ∈ [
  (:reduced_add,:reduce_to_add,:+,:vsum,true),(:reduced_prod,:reduce_to_prod,:*,:vprod,true),
  (:reduced_max,:reduce_to_max,:max,:vmaximum,false),(:reduced_min,:reduce_to_min,:min,:vminimum,false),
  (:reduced_all,:reduce_to_all,:(&),:vall,false),(:reduced_any,:reduce_to_any,:(|),:vany,false)
]
  @eval begin
    @inline $f_to(x::NativeTypes, y::NativeTypes) = x
    @inline $f_to(x::AbstractSIMD{W}, y::AbstractSIMD{W}) where {W} = x
    @generated function $f_to(x0::AbstractSIMD{W1}, y::AbstractSIMD{W2}) where {W1,W2}
      @assert W1 ≥ W2
      i = 0
      q = Expr(:block, Expr(:meta,:inline))
      xtp = :x0
      while (W1 >>> i) ≠ W2
        i += 1
        xt = Symbol(:x,i)
        xt0 = Symbol(xt,:_0); xt1 = Symbol(xt,:_1)
        push!(q.args, Expr(:(=), Expr(:tuple,xt0,xt1), Expr(:call,:splitvector,xtp)), Expr(:(=), xt, Expr(:call, $op, xt0, xt1)))
        xtp = xt
      end
      push!(q.args, Symbol(:x,i))
      q
    end
    @inline $f_to(x::AbstractSIMD, y::NativeTypes) = $reduce(x)
    @inline $f(x::NativeTypes, y::NativeTypes) = $op(x,y)
    @inline $f(x::AbstractSIMD{W}, y::AbstractSIMD{W}) where {W} = $op(x,y)
    @inline $f(x::AbstractSIMD, y::AbstractSIMD) = $op($f_to(x,y),y)
    @inline $f_to(x::VecUnroll, y::VecUnroll) = VecUnroll(fmap($f_to, getfield(x, :data), getfield(y, :data)))
    @inline $f(x::VecUnroll, y::VecUnroll) = VecUnroll(fmap($f, getfield(x, :data), getfield(y, :data)))
  end
  if twoarg
    # @eval @inline $f(y::T, x::AbstractSIMD{W,T}) where {W,T} = $reduce(y, x)
    @eval @inline $f(x::AbstractSIMD, y::NativeTypes) = $reduce(y, x)
    # @eval @inline $f(x::AbstractSIMD, y::NativeTypes) = ((y2,x2,r) = @show (y, x, $reduce(y, x)); r)
  else
    # @eval @inline $f(y::T, x::AbstractSIMD{W,T}) where {W,T} = $op(y, $reduce(x))
    @eval @inline $f(x::AbstractSIMD, y::NativeTypes) = $op(y, $reduce(x))
  end
end

@inline roundint(x::Float32) = round(Int32, x)
@inline _roundint(x, ::True) = round(Int, x)
@inline _roundint(x, ::False) = round(Int32, x)

@inline roundint(x::Float64) = _roundint(x, has_feature(Val(:x86_64_avx512dq)))
if Sys.WORD_SIZE ≥ 64
    @inline roundint(v::Vec{W,Float64}) where {W} = _roundint(v, has_feature(Val(:x86_64_avx512dq)))
    @inline roundint(v::Vec{W,Float32}) where {W} = round(Int32, v)
else
    @inline roundint(v::Vec{W,T}) where {W,T<:Union{Float32,Float64}} = round(Int32, v)
end

# binary

function count_zeros_func(W, I, op, tf = 1)
    typ = "i$(8sizeof(I))"
    vtyp = "<$W x $typ>"
    instr = "@llvm.$op.v$(W)$(typ)"
    decl = "declare $vtyp $instr($vtyp, i1)"
    instrs = "%res = call $vtyp $instr($vtyp %0, i1 $tf)\nret $vtyp %res"
    rettypexpr = :(_Vec{$W,$I})
    llvmcall_expr(decl, instrs, rettypexpr, :(Tuple{$rettypexpr}), vtyp, [vtyp], [:(data(v))])
end
# @generated Base.abs(v::Vec{W,I}) where {W, I <: Integer} = count_zeros_func(W, I, "abs", 0)
@generated vleading_zeros(v::Vec{W,I}) where {W, I <: Integer} = count_zeros_func(W, I, "ctlz")
@generated vtrailing_zeros(v::Vec{W,I}) where {W, I <: Integer} = count_zeros_func(W, I, "cttz")

for (op,f) ∈ [("ctpop", :vcount_ones)]
    @eval @generated $f(v1::Vec{W,T}) where {W,T} = (TS = JULIA_TYPES[T]; build_llvmcall_expr($op, W, TS, [W], [TS]))
end

for (op,f) ∈ [("fshl",:funnel_shift_left),("fshr",:funnel_shift_right)
              ]
    @eval @generated function $f(v1::Vec{W,T}, v2::Vec{W,T}, v3::Vec{W,T}) where {W,T}
        TS = JULIA_TYPES[T]
        build_llvmcall_expr($op, W, TS, [W,W,W], [TS,TS,TS])
    end
end
@inline function funnel_shift_left(a::T, b::T, c::T) where {T}
    _T = eltype(a)
    S = 8sizeof(_T) % _T
    (a << c) | (b >>> (S - c))
end
@inline function funnel_shift_right(a::T, b::T, c::T) where {T}
    _T = eltype(a)
    S = 8sizeof(_T) % _T
    (a >>> c) | (b << (S - c))
end
@inline function funnel_shift_left(_a, _b, _c)
    a, b, c = promote(_a, _b, _c)
    funnel_shift_left(a, b, c)
end
@inline function funnel_shift_right(_a, _b, _c)
    a, b, c = promote(_a, _b, _c)
    funnel_shift_right(a, b, c)
end
@inline funnel_shift_left(a::MM, b::MM, c::MM) = funnel_shift_left(Vec(a), Vec(b), Vec(c))
@inline funnel_shift_right(a::MM, b::MM, c::MM) = funnel_shift_right(Vec(a), Vec(b), Vec(c))
@inline rotate_left(a::T, b::T) where {T} = funnel_shift_left(a, a, b)
@inline rotate_right(a::T, b::T) where {T} = funnel_shift_right(a, a, b)
@inline function rotate_left(_a, _b)
    a, b = promote_div(_a, _b)
    funnel_shift_left(a, a, b)
end
@inline function rotate_right(_a, _b)
    a, b = promote_div(_a, _b)
    funnel_shift_right(a, a, b)
end

@inline vfmadd231(a, b, c) = vfmadd(a, b, c)
@inline vfnmadd231(a, b, c) = vfnmadd(a, b, c)
@inline vfmsub231(a, b, c) = vfmsub(a, b, c)
@inline vfnmsub231(a, b, c) = vfnmsub(a, b, c)
@inline vfmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::False) where {W, T <: Union{Float32,Float64}} = vfmadd(a, b, c)
@inline vfnmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::False) where {W, T <: Union{Float32,Float64}} = vfnmadd(a, b, c)
@inline vfmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::False) where {W, T <: Union{Float32,Float64}} = vfmsub(a, b, c)
@inline vfnmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::False) where {W, T <: Union{Float32,Float64}} = vfnmsub(a, b, c)
@generated function vfmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::True) where {W, T <: Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfmadd_str = """%res = call <$W x $(typ)> asm "vfmadd231$(suffix) \$3, \$2, \$1", "=v,0,v,v"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0)
                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta, :inline))
        Vec($LLVMCALL($vfmadd_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T}}, data(a), data(b), data(c)))
    end
end
@generated function vfnmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::True) where {W, T <: Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfnmadd_str = """%res = call <$W x $(typ)> asm "vfnmadd231$(suffix) \$3, \$2, \$1", "=v,0,v,v"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0)
                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta, :inline))
        Vec($LLVMCALL($vfnmadd_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T}}, data(a), data(b), data(c)))
    end
end
@generated function vfmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::True) where {W, T <: Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfmsub_str = """%res = call <$W x $(typ)> asm "vfmsub231$(suffix) \$3, \$2, \$1", "=v,0,v,v"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0)
                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta, :inline))
        Vec($LLVMCALL($vfmsub_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T}}, data(a), data(b), data(c)))
    end
end
@generated function vfnmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}, ::True) where {W, T <: Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfnmsub_str = """%res = call <$W x $(typ)> asm "vfnmsub231$(suffix) \$3, \$2, \$1", "=v,0,v,v"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0)
                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta, :inline))
        Vec($LLVMCALL($vfnmsub_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T}}, data(a), data(b), data(c)))
    end
end

@inline vifelse(::typeof(vfmadd231), m, a, b, c, ::False) = vifelse(vfmadd, m, a, b, c)
@inline vifelse(::typeof(vfnmadd231), m, a, b, c, ::False)  = vifelse(vfnmadd, m, a, b, c)
@inline vifelse(::typeof(vfmsub231), m, a, b, c, ::False)  = vifelse(vfmsub, m, a, b, c)
@inline vifelse(::typeof(vfnmsub231), m, a, b, c, ::False)  = vifelse(vfnmsub, m, a, b, c)

@generated function vifelse(::typeof(vfmadd231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T},::True) where {W,U<:Unsigned,T<:Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfmaddmask_str = """%res = call <$W x $(typ)> asm "vfmadd231$(suffix) \$3, \$2, \$1 {\$4}", "=v,0,v,v,^Yk"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0, i$W %3)
                                            ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta,:inline))
        Vec($LLVMCALL($vfmaddmask_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T},$U}, data(a), data(b), data(c), data(m)))
    end
end
@generated function vifelse(::typeof(vfnmadd231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T},::True) where {W,U<:Unsigned,T<:Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfnmaddmask_str = """%res = call <$W x $(typ)> asm "vfnmadd231$(suffix) \$3, \$2, \$1 {\$4}", "=v,0,v,v,^Yk"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0, i$W %3)
                                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta,:inline))
        Vec($LLVMCALL($vfnmaddmask_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T},$U}, data(a), data(b), data(c), data(m)))
    end
end
@generated function vifelse(::typeof(vfmsub231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T},::True) where {W,U<:Unsigned,T<:Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfmsubmask_str = """%res = call <$W x $(typ)> asm "vfmsub231$(suffix) \$3, \$2, \$1 {\$4}", "=v,0,v,v,^Yk"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0, i$W %3)
                                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta,:inline))
        Vec($LLVMCALL($vfmsubmask_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T},$U}, data(a), data(b), data(c), data(m)))
    end
end
@generated function vifelse(::typeof(vfnmsub231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T},::True) where {W,U<:Unsigned,T<:Union{Float32,Float64}}
    typ = LLVM_TYPES[T]
    suffix = T == Float32 ? "ps" : "pd"
    vfnmsubmask_str = """%res = call <$W x $(typ)> asm "vfnmsub231$(suffix) \$3, \$2, \$1 {\$4}", "=v,0,v,v,^Yk"(<$W x $(typ)> %2, <$W x $(typ)> %1, <$W x $(typ)> %0, i$W %3)
                                        ret <$W x $(typ)> %res"""
    quote
        $(Expr(:meta,:inline))
        Vec($LLVMCALL($vfnmsubmask_str, _Vec{$W,$T}, Tuple{_Vec{$W,$T},_Vec{$W,$T},_Vec{$W,$T},$U}, data(a), data(b), data(c), data(m)))
    end
end

@inline function use_asm_fma(::StaticInt{W}, ::Type{T}) where {W,T}
    WT = StaticInt{W}() * static_sizeof(T)
    (has_feature(Val(:x86_64_fma)) & _ispow2(StaticInt{W}())) & (le(WT, register_size()) & ge(WT, StaticInt{16}()))
end

@inline function vfmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}}
    vfmadd231(a, b, c, use_asm_fma(StaticInt{W}(), T))
end
@inline function vfnmadd231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}}
    vfnmadd231(a, b, c, use_asm_fma(StaticInt{W}(), T))
end
@inline function vfmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}}
    vfmsub231(a, b, c, use_asm_fma(StaticInt{W}(), T))
end
@inline function vfnmsub231(a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}}
    vfnmsub231(a, b, c, use_asm_fma(StaticInt{W}(), T))
end

@inline function vifelse(::typeof(vfmadd231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}, U}
    vifelse(vfmadd231, m, a, b, c, use_asm_fma(StaticInt{W}(), T) & has_feature(Val(:x86_64_avx512bw)))
end
@inline function vifelse(::typeof(vfnmadd231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}, U}
    vifelse(vfnmadd231, m, a, b, c, use_asm_fma(StaticInt{W}(), T) & has_feature(Val(:x86_64_avx512bw)))
end
@inline function vifelse(::typeof(vfmsub231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}, U}
    vifelse(vfmsub231, m, a, b, c, use_asm_fma(StaticInt{W}(), T) & has_feature(Val(:x86_64_avx512bw)))
end
@inline function vifelse(::typeof(vfnmsub231), m::AbstractMask{W,U}, a::Vec{W,T}, b::Vec{W,T}, c::Vec{W,T}) where {W, T<:Union{Float32, Float64}, U}
    vifelse(vfnmsub231, m, a, b, c, use_asm_fma(StaticInt{W}(), T) & has_feature(Val(:x86_64_avx512bw)))
end

"""
    Fast approximate reciprocal.

    Guaranteed accurate to at least 2^-14 ≈ 6.103515625e-5.

    Useful for special funcion implementations.
    """
@inline inv_approx(x) = inv(x)
@inline inv_approx(v::VecUnroll) = VecUnroll(fmap(inv_approx, getfield(v, :data)))

@inline vinv_fast(v) = vinv(v)
@inline vinv_fast(v::AbstractSIMD{<:Any,<:Integer}) = vinv_fast(float(v))

@static if (Sys.ARCH === :x86_64) || (Sys.ARCH === :i686)

    function inv_approx_expr(W, @nospecialize(T), hasavx512f, hasavx512vl, hasavx, vector::Bool=true)
        bits = 8sizeof(T) * W
        pors = (vector | hasavx512f) ? 'p' : 's'
        if (hasavx512f && (bits === 512)) || (hasavx512vl && (bits ∈ (128, 256)))
            typ = T === Float64 ? "double" : "float"
            vtyp = "<$W x $(typ)>"
            dors = T === Float64 ? "d" : "s"
            f = "@llvm.x86.avx512.rcp14.$(pors)$(dors).$(bits)"
            decl = "declare $(vtyp) $f($(vtyp), $(vtyp), i$(max(8,W))) nounwind readnone"
            instrs = "%res = call $(vtyp) $f($vtyp %0, $vtyp zeroinitializer, i$(max(8,W)) -1)\nret $(vtyp) %res"
            return llvmcall_expr(decl, instrs, :(_Vec{$W,$T}), :(Tuple{_Vec{$W,$T}}), vtyp, [vtyp], [:(data(v))], true)
        elseif (hasavx && (W == 8)) && (T === Float32)
            decl = "declare <8 x float> @llvm.x86.avx.rcp.$(pors)s.256(<8 x float>) nounwind readnone"
            instrs = "%res = call <8 x float> @llvm.x86.avx.rcp.$(pors)s.256(<8 x float> %0)\nret <8 x float> %res"
            return llvmcall_expr(decl, instrs, :(_Vec{8,Float32}), :(Tuple{_Vec{8,Float32}}), "<8 x float>", ["<8 x float>"], [:(data(v))], true)
        elseif W == 4
            decl = "declare <4 x float> @llvm.x86.sse.rcp.$(pors)s(<4 x float>) nounwind readnone"
            instrs = "%res = call <4 x float> @llvm.x86.sse.rcp.$(pors)s(<4 x float> %0)\nret <4 x float> %res"
            if T === Float32
                return llvmcall_expr(decl, instrs, :(_Vec{4,Float32}), :(Tuple{_Vec{4,Float32}}), "<4 x float>", ["<4 x float>"], [:(data(v))])
            else#if T === Float64
                argexpr = [:(data(convert(Float32, v)))]
                call = llvmcall_expr(decl, instrs, :(_Vec{4,Float32}), :(Tuple{_Vec{4,Float32}}), "<4 x float>", ["<4 x float>"], argexpr, true)
                return :(convert(Float64, $call))
            end
        elseif (hasavx512f || (T === Float32)) && bits < 128
            L = 16 ÷ sizeof(T)
            inv_expr = inv_approx_expr(L, T, hasavx512f, hasavx512vl, hasavx, W > 1)
            resize_expr = W < 1 ? :(extractelement(v⁻¹, 0)) : :(vresize(Val{$W}(), v⁻¹))
            return quote
                v⁻¹ = let v = vresize(Val{$L}(), v)
                    $inv_expr
                end
                $resize_expr
            end
        else
            return :(inv(v))
        end
    end

    @generated function _inv_approx(v::Vec{W,T}, ::AVX512F, ::AVX512VL, ::AVX) where {W,T<:Union{Float32,Float64},AVX512F,AVX512VL,AVX}
        inv_approx_expr(W, T, AVX512F === True, AVX512VL === True, AVX === True, true)
    end
    @generated function _inv_approx(v::T, ::AVX512F, ::AVX512VL, ::AVX) where {T<:Union{Float32,Float64},AVX512F,AVX512VL,AVX}
        inv_approx_expr(0, T, AVX512F === True, AVX512VL === True, AVX === True, false)
    end
    @inline function inv_approx(v::Vec{W,T}) where {W,T<:Union{Float32,Float64}}
        _inv_approx(v, has_feature(Val(:x86_64_avx512f)), has_feature(Val(:x86_64_avx512vl)), has_feature(Val(:x86_64_avx)))
    end
    @inline function inv_approx(v::T) where {T<:Union{Float32,Float64}}
        _inv_approx(v, has_feature(Val(:x86_64_avx512f)), has_feature(Val(:x86_64_avx512vl)), has_feature(Val(:x86_64_avx)))
    end

    """
    vinv_fast(x)

    More accurate version of inv_approx, using 1 (`Float32`) or 2 (`Float64`) Newton iterations to achieve reasonable accuracy.
    Requires x86 CPUs for `Float32` support, and `AVX512F` for `Float64`. Otherwise, it falls back on `vinv(x)`.

    y = 1 / x
    Use a Newton iteration:
    yₙ₊₁ = yₙ - f(yₙ)/f′(yₙ)
    f(yₙ) = 1/yₙ - x
    f′(yₙ) = -1/yₙ²
    yₙ₊₁ = yₙ + (1/yₙ - x) * yₙ² = yₙ + yₙ - x * yₙ² = 2yₙ - x * yₙ² = yₙ * ( 2 - x * yₙ )
    yₙ₊₁ = yₙ * ( 2 - x * yₙ )
    """
    @inline function vinv_fast(v::AbstractSIMD{W,Float32}) where {W}
        v⁻¹ = inv_approx(v)
        vmul_fast(v⁻¹, vfnmadd_fast(v, v⁻¹, 2f0))
    end

    @inline function _vinv_fast(v, ::True)
        v⁻¹₁ = inv_approx(v)
        v⁻¹₂ = vmul_fast(v⁻¹₁, vfnmadd_fast(v, v⁻¹₁, 2.0))
        v⁻¹₃ = vmul_fast(v⁻¹₂, vfnmadd_fast(v, v⁻¹₂, 2.0))
    end
  @inline _vinv_fast(v, ::False) = vinv(v)
  @inline vinv_fast(v::AbstractSIMD{W,Float64}) where {W} = _vinv_fast(v, has_feature(Val(:x86_64_avx512vl)))
  @inline vfdiv_afast(a::VecUnroll{N}, b::VecUnroll{N}, ::False) where {N} = VecUnroll(fmap(vfdiv_fast, getfield(a,:data), getfield(b,:data)))
  @inline vfdiv_afast(a::VecUnroll{N}, b::VecUnroll{N}, ::True) where {N} = VecUnroll(fmap(vfdiv_fast, getfield(a,:data), getfield(b,:data)))
  @inline function vfdiv_afast(a::VecUnroll{N,W,T,Vec{W,T}}, b::VecUnroll{N,W,T,Vec{W,T}}, ::True) where {N,W,T<:FloatingTypes}
    VecUnroll(_vfdiv_afast(getfield(a,:data),getfield(b,:data)))
  end
  # @inline function _vfdiv_afast(a::Tuple{Vec{W,T},Vec{W,T},Vec{W,T},Vec{W,T},Vararg{Vec{W,T},K}}, b::Tuple{Vec{W,T},Vec{W,T},Vec{W,T},Vec{W,T},Vararg{Vec{W,T},K}}) where {W,K,T<:FloatingTypes}
  #   # c1 = vfdiv_fast(a[1], b[1])
  #   binv1 = _vinv_fast(b[1], True())
  #   c2 = vfdiv_fast(a[2], b[2])
  #   c3 = vfdiv_fast(a[3], b[3])
  #   c4 = vfdiv_fast(a[4], b[4])
  #   c1 = vmul_fast(a[1], binv1)
  #   (c1, c2, c3, c4, _vfdiv_afast(Base.tail(Base.tail(Base.tail(Base.tail(a)))), Base.tail(Base.tail(Base.tail(Base.tail(b)))))...)
  # end
  @inline function _vfdiv_afast(a::Tuple{Vec{W,T},Vec{W,T},Vararg{Vec{W,T},K}}, b::Tuple{Vec{W,T},Vec{W,T},Vararg{Vec{W,T},K}}) where {W,K,T<:FloatingTypes}
    c1 = vmul_fast(a[1], _vinv_fast(b[1], True()))
    c2 = vfdiv_fast(a[2], b[2])
    (c1, c2, _vfdiv_afast(Base.tail(Base.tail(a)), Base.tail(Base.tail(b)))...)
  end
  @inline function _vfdiv_afast(a::Tuple{Vec{W,T},Vec{W,T}}, b::Tuple{Vec{W,T},Vec{W,T}}) where {W,T<:FloatingTypes}
    c1 = vmul_fast(a[1], _vinv_fast(b[1], True()))
    # c1 = vfdiv_fast(a[1], b[1])
    c2 = vfdiv_fast(a[2], b[2])
    (c1, c2)
  end
  ge_one_fma(::Val{:tigerlake}) = False()
  ge_one_fma(::Val{:icelake}) = False()
  ge_one_fma(::Val) = True()
  @inline _vfdiv_afast(a::Tuple{Vec{W,T}}, b::Tuple{Vec{W,T}}) where {W,T<:FloatingTypes} = (vfdiv_fast(getfield(a,1,false),getfield(b,1,false)),)
  @inline _vfdiv_afast(a::Tuple{}, b::Tuple{}) = ()
  @inline function vfdiv_fast(a::VecUnroll{N,W,Float64,Vec{W,Float64}},b::VecUnroll{N,W,Float64,Vec{W,Float64}}) where {N,W}
    vfdiv_afast(a, b, has_feature(Val(:x86_64_avx512f)) & ge_one_fma(cpu_name()))
  end
  # @inline vfdiv_fast(a::VecUnroll{N,W,Float32,Vec{W,Float32}},b::VecUnroll{N,W,Float32,Vec{W,Float32}}) where {N,W} = vfdiv_afast(a, b, True())
else
  ge_one_fma(::Val) = True()
end


text:
# Note there is some type piracy going on here. This is not for general use.
# Also, modifying display might be preferable to print.
import HttpServer.Client
import HttpServer.HttpHandler
import HttpServer.Response
import HttpServer.Request
import HttpServer.Server
import HttpCommon.Cookie
import HttpCommon.Request
import HttpCommon.Response
import HttpCommon.STATUS_CODES
import URIParser.URI
import WebSockets.WebSocketHandler
import WebSockets.WebSocket
import Base.print
"Date time group string"
dtg() = Dates.format(now(), "HH:MM:SS")
"""
Console log with a heading, buffer and no mixing with output from other tasks.
We may, of course, be interrupting other tasks like stacktrace output.
"""
function clog(args...)
    buf = startbuf()
    pwc(buf, dtg(), " ", args...)
    lock(STDERR)
    print(STDERR, String(take!(buf)))
    unlock(STDERR)
    nothing
end
"Print with 'color' arguments Base.text_colors placed anywhere. Color_normal is set after the call is finished. "
function pwc(io::IO, args...)
    for arg in args
        if isa(arg,Symbol)
            print_color(io, arg)
        else
            print(io,arg)
        end
    end
    print(io, Base.color_normal)
    nothing
end
"Type piracy on dictionaries, not nice normally"
function print(io::IO, headers::Dict{AbstractString, AbstractString})
    for pa in headers
        print(io, pa)
    end
    print(io, "\n")
    nothing
end
function print(io::IO, headers::Dict{String, Function})
    for pa in headers
        print(io, pa)
    end
    print(io, "\n")
    nothing
end

"Add color code"
print_color(io::IO, color::Symbol) = print(io, get(Base.text_colors, color, Base.color_normal))
 "Return an IO stream with colored heading and tabs"
function startbuf(prefix = "INFO:")
            buf = IOBuffer()
            pwc(buf, Base.info_color(),  :bold , prefix )
            length(prefix) > 0 && prefix[end]!= "\t" &&  print(buf, "\t")
            buf
end

"Pair print on a line with tab indent"
function print(io::IO, p::Pair)
    print(io, "\t")
    isa(p.first,Pair) && print(io, "(")
    print(io, p.first)
    isa(p.first,Pair) && print(io, ")")
    print(io, "\t=> ")
    isa(p.second,Pair) && print(io, "(")
    print(io, p.second)
    isa(p.second,Pair) && print(io, ")")
    print(io,"\n")
    nothing
end
"Print function name with reference, not nice type piracy.."
function print(io::IO, f::Function)
    show(io, f)
    print(io, "\t")
     mt = typeof(f).name.mt
     print(io, mt.defs.func.file)
     print(io, ":")
     print(io, mt.defs.func.line)
     nothing
end
"Print client"
function print(io::IO, client::Client{TCPSocket})
    pwc(io, typeof(client), " ", :bold, client.id,"\n")
    pwc(io, :cyan, "\tsock ", :bold, client.sock, "\n")
    pwc(io, :cyan, "\tparser ", :bold, client.parser.parser)
    nothing
end
"Print response"
function print(io::IO, response:: Response)
    pwc(io, :green, "\tResponse status: ", :bold, response.status," ")
    pwc(io, :green, get(STATUS_CODES, response.status, "--"), " ")
    pwc(io, :green, " Finished: ", :bold, response.finished)
    if !isempty(response.headers)
        pwc(io, :green, " Headers: ", :bold, response.headers.count)
        pwc(io, :green, " Age: ", :bold, Int(response.headers.age))
        pwc(io, :green, "\n", response.headers)
    end
    if !isempty(response.cookies)
        pwc(io, " Cookies: ", :bold, length(response.cookies))
        pwc(io, " Age: ", :bold, Int(response.headers.age))
        pwc("\n", response.cookies)
    end
    if !isempty(response.data)
        printdata(io, response.data, get(response.headers, "Content-Type","image/jpeg"))
    end
    nothing
end
"Print request"
function print(io::IO, request::Request)
    pwc(io, :cyan, :bold, "\tRequest: ", request.method, :normal, " resource ", :bold, request.resource)
    pwc(io, :cyan, "\tUri:", :bold, sprint(print, request.uri), "\n")
    if !isempty(request.headers)
        pwc(io, :cyan, "\tHeaders: ", :bold, request.headers.count, " Age: ", :bold, Int(request.headers.age))
        pwc(io, :cyan, "\n", request.headers)
    end
    if !isempty(request.data)
        printdata(io, request.data, get(request.headers, "Content-type","text/html; charset=utf-8"))
    end
    nothing
end

"Prints data, limited length"
function limlen(data)
    le= length(data)
    if le <  100
        return  String(data)
    else
        # Not sure if this is a safe way to split some types, but String should throw an error.
        return "Truncated:\n$(String(data)[1:65]).....$(String(data)[le-29:end])"
    end
end

"Indents and cleans up for printing"
function compact_format(s::String)
                    replace(s, "\r\n", "\n") |>
                    s-> replace(s, "\n\n", "\n") |>
                    s -> replace(s, "\t\t", "\t") |>
                    s -> replace(s, "\n\t", "\n") |>
                    s -> replace(s, "\n", "\n\t") |>
                    s->    startswith(s,"\t") ? s  : "\t"*s |>
                    s->    endswith(s,"\n") ? s  : s*"\n"
end
"Text data as a (truncated) repl-friendly string ."
function printdata{T<:Array{UInt8,1}}(io::IO, data::T, contenttype::String)
    le = length(data)
    pwc(io, :green, "\tData length: ",  le,"\n")
    if ismatch(r"^text", contenttype)
        pwc(io, :blue, data|> prettystring)
    end
end
"Text data as a (truncated) repl-friendly string ."
function prettystring(s::String)
        s|> limlen |> compact_format
end
prettystring(u::Array{UInt8,1}) = prettystring(String(u))
"Print server"
function print(io::IO, server::Server)
    pwc(io, :bold , Base.info_color(),  "Server\n")
    server.http != nothing  && print(io, server.http)
    server.websock != nothing  &&    print(io, server.websock)
end
"Print httphandler"
function print(io::IO, httphandler::HttpHandler)
    pwc(io,   :bold , Base.info_color(), "\tHttpHandler\n")
    pwc(io, :blue, :bold, "\t", :normal, "Called on opening (websocket, response):\n")
    pwc(io,  :green, "\t", httphandler.handle, "\n")
    pwc(io, "      \t", "Functions called on events:\n")
    pwc(io,  :green, httphandler.events)
    pwc(io,  "      \t", "Socket:\t", :green, httphandler.sock,"\n")
    nothing
end
"""
Print websockethandler
"""
function print(io::IO, wsh::WebSocketHandler)
    try
        pwc(io,   :bold , Base.info_color(), "\tWebSocketHandler")
        pwc(io, :blue, :bold, "\t", :normal, "Function called with (request, client):\n")
        pwc(io,  :green, "\t", wsh.handle, "\n")
    end
    nothing
end

"""
Print websocket
"""
function print(io::IO, ws::WebSocket)
    try
        pwc(io, :green, "\t", :normal, "Websocket id: ", :bold, ws.id)
        pwc(io, :green, :bold, "\t", ws.state )
        pwc(io,  "\n")
    end
    nothing
end
nothing

ext: jl


text:
# ------------------------------------------------------------------------------
# Plotting functions for geometric objects
# -------------------------------------------------------------------------------

"Submodule containing functions for plotting geometric objects"
module GeoPlots
export
    plot, plot!, shape

using PlaneGeometry
using Plots

import Plots: plot, plot!

"""
    shape(ptlist::Vector{Point})

Create a `Plots.Shape` object for a polygon with vertices `ptlist`.
"""
function shape(ptlist::Vector{PlaneGeometry.Point})
    xlist = [pt.x for pt in ptlist]
    ylist = [pt.y for pt in ptlist]
    shape = Shape(xlist, ylist)
end;

"""
    shape(ptlist::Vector{Point})

Create a `Plots.Shape` object for a polygon with vertices `ptlist`.
"""
shape(tri::Triangle) = shape(vertices(tri));

"""
    shape(c::Circle)

Create a `Plots.Shape` object for a circle `c`.
"""
function shape(c::Circle)
    θ = LinRange(0, 2*π, 300)
    c.center.x .+ c.radius*sin.(θ), c.center.y .+ c.radius*cos.(θ)
end;

"""
    shape(e::Edge)

Create a `Plots.Shape` object for an edge `e`.
"""
function shape(e::Edge)
    shape([e.src, e.dst])
end;

"""
    plot(obj::GeoObject, args...; kwargs...)

Plot `obj` on current plot.
"""
plot(obj::GeoObject, args...; kwargs...) = plot(shape(obj), args...; kwargs...)

"""
    plot!(obj::GeoObject, args...; kwargs...)

Plot `obj` on current plot.
"""
plot!(obj::GeoObject, args...; kwargs...) = plot!(shape(obj), args...; kwargs...)

"""
    plot!(edge::Edge, args...; kwargs...)

Plot `edge` on current plot.
"""
function plot!(edge::Edge, args...; kwargs...)
    eshape = shape(edge)
    plot!(eshape.x, eshape.y, args...; kwargs...)
end

"""
    plot(edge::Edge, args...; kwargs...)

Plot `edge` on current plot.
"""
function plot(edge::Edge, args...; kwargs...)
    eshape = shape(edge)
    plot(eshape.x, eshape.y, args...; kwargs...)
end
end


text:
"""
function make_dir(path::String)

Check if the following directory exist or not.

# Argument
- path: Full directory path.
"""

function makedir(path::String)
    if !isdir(path)
        mkdir(path)
    end
end

"""
function setup_flow(p::Dict)

Set up the initial project flow. Execution of the function will
create datalake, insights, vizfiles and datafiles directories
in to given project roots.

# Argument
- p: A dictionary auto read by the profiler.
"""
function set_workflow(p::Dict)
    root = p["project_root"]
    projects = p["projects_dir"]
    data = p["data_dir"]
    insights = p["insights_dir"]
    try
        makedir(joinpath(root, projects))
        makedir(joinpath(root, data))
        makedir(joinpath(root, insights))
        return
    catch ex
        throw(ex)
    end
end


text:
# ---
# title: 1074. Number of Submatrices That Sum to Target
# id: problem1074
# author: Indigo
# date: 2021-05-29
# difficulty: Hard
# categories: Array, Dynamic Programming, Sliding Window
# link: <https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/description/>
# hidden: true
# ---
#
# Given a `matrix` and a `target`, return the number of non-empty submatrices
# that sum to target.
#
# A submatrix `x1, y1, x2, y2` is the set of all cells `matrix[x][y]` with `x1
# <= x <= x2` and `y1 <= y <= y2`.
#
# Two submatrices `(x1, y1, x2, y2)` and `(x1', y1', x2', y2')` are different if
# they have some coordinate that is different: for example, if `x1 != x1'`.
#
#
#
# **Example 1:**
#
# ![](https://assets.leetcode.com/uploads/2020/09/02/mate1.jpg)
#
#
#
#     Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
#     Output: 4
#     Explanation: The four 1x1 submatrices that only contain 0.
#
#
# **Example 2:**
#
#
#
#     Input: matrix = [[1,-1],[-1,1]], target = 0
#     Output: 5
#     Explanation: The two 1x2 submatrices, plus the two 2x1 submatrices, plus the 2x2 submatrix.
#
#
# **Example 3:**
#
#
#
#     Input: matrix = [[904]], target = 0
#     Output: 0
#
#
#
#
# **Constraints:**
#
#   * `1 <= matrix.length <= 100`
#   * `1 <= matrix[0].length <= 100`
#   * `-1000 <= matrix[i] <= 1000`
#   * `-10^8 <= target <= 10^8`
#
#
## @lc code=start
using LeetCode

function num_submatrix_sum_target(matrix::AbstractMatrix{Int}, target::Int)
    m, n = size(matrix)
    m > n && return num_submatrix_sum_target(matrix', target)
    pref_sum = OffsetArray(fill(0, m + 1, n + 1), -1, -1)

    for i in 1:m, j in 1:n
        pref_sum[i, j] = pref_sum[i - 1, j] + pref_sum[i, j - 1] + matrix[i, j] - pref_sum[i - 1, j - 1]
    end
    res = 0
    for tp in 1:m, bot in tp:m
        sum_cnt = Dict{Int, Int}()
        for r in 1:n
            rows_sum = pref_sum[bot, r] - pref_sum[tp - 1, r]
            rows_sum == target && (res += 1)
            res += get(sum_cnt, rows_sum - target, 0)
            sum_cnt[rows_sum] = get(sum_cnt, rows_sum, 0) + 1
        end
    end
    return res
end
## @lc code=end


text:
"""
    StaticFloat64{N}

A statically sized `Float64`.
Use `StaticInt(N)` instead of `Val(N)` when you want it to behave like a number.
"""
struct StaticFloat64{N} <: AbstractFloat
    StaticFloat64{N}() where {N} = new{N::Float64}()
    StaticFloat64(x::Float64) = new{x}()
    StaticFloat64(x::Int) = new{Base.sitofp(Float64, x)::Float64}()
end

(::Type{T})(x::Integer) where {T<:StaticFloat64} = StaticFloat64(x)
(::Type{T})(x::AbstractFloat) where {T<:StaticFloat64} = StaticFloat64(x)
@generated function Base.AbstractFloat(::StaticInt{N}) where {N}
    Expr(:call, Expr(:curly, :StaticFloat64, Float64(N)))
end
StaticFloat64(x::StaticInt{N}) where {N} = float(x)

const FloatOne = StaticFloat64{one(Float64)}
const FloatZero = StaticFloat64{zero(Float64)}

Base.show(io::IO, ::StaticFloat64{N}) where {N} = print(io, "static($N)")

Base.convert(::Type{T}, ::StaticFloat64{N}) where {N,T<:AbstractFloat} = T(N)
Base.promote_rule(::Type{StaticFloat64{N}}, ::Type{T}) where {N,T} = promote_type(T, Float64)
Base.promote_rule(::Type{StaticFloat64{N}}, ::Type{Float64}) where {N} = Float64
Base.promote_rule(::Type{StaticFloat64{N}}, ::Type{Float32}) where {N} = Float32
Base.promote_rule(::Type{StaticFloat64{N}}, ::Type{Float16}) where {N} = Float16

@static if VERSION == v"1.2"
    Base.promote_rule(::Type{StaticFloat64{N}}, ::Type{Any}) where {N} = Any
end

Base.eltype(::Type{T}) where {T<:StaticFloat64} = Float64
Base.iszero(::FloatZero) = true
Base.iszero(::StaticFloat64) = false
Base.isone(::FloatOne) = true
Base.isone(::StaticFloat64) = false
Base.zero(::Type{T}) where {T<:StaticFloat64} = FloatZero()
Base.one(::Type{T}) where {T<:StaticFloat64} = FloatOne()

Base.@pure function fsub(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X,Y}
    return StaticFloat64{Base.sub_float(X, Y)::Float64}()
end

Base.@pure function fadd(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X,Y}
    return StaticFloat64{Base.add_float(X, Y)::Float64}()
end

Base.@pure function fdiv(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X,Y}
    return StaticFloat64{Base.div_float(X, Y)::Float64}()
end

Base.@pure function fmul(::StaticFloat64{X}, ::StaticFloat64{Y}) where {X,Y}
    return StaticFloat64{Base.mul_float(X, Y)::Float64}()
end

Base.:+(x::StaticFloat64{X}, y::StaticFloat64{Y}) where {X,Y} = fadd(x, y)
Base.:+(x::StaticFloat64{X}, y::StaticInt{Y}) where {X,Y} = +(x, float(y))
Base.:+(x::StaticInt{X}, y::StaticFloat64{Y}) where {X,Y} = +(float(x), y)
Base.:+(x::FloatZero, ::FloatZero) = x
Base.:+(x::StaticFloat64{X}, ::FloatZero) where {X} = x
Base.:+(::FloatZero, y::StaticFloat64{Y}) where {Y} = y
Base.:+(x::StaticFloat64{X}, ::Zero) where {X} = x
Base.:+(::Zero, y::StaticFloat64{Y}) where {Y} = y

Base.:-(::StaticFloat64{X}) where {X} = StaticFloat64{-X}()
Base.:-(x::StaticFloat64{X}, y::StaticFloat64{Y}) where {X,Y} = fsub(x, y)
Base.:-(x::StaticFloat64{X}, y::StaticInt{Y}) where {X,Y} = -(x, float(y))
Base.:-(x::StaticInt{X}, y::StaticFloat64{Y}) where {X,Y} = -(float(x), y)
Base.:-(x::FloatZero, ::FloatZero) = x
Base.:-(x::StaticFloat64{X}, ::FloatZero) where {X} = x
Base.:-(x::StaticFloat64{X}, ::Zero) where {X} = x
Base.:-(::FloatZero, y::StaticFloat64{Y}) where {Y} = -y
Base.:-(::Zero, y::StaticFloat64{Y}) where {Y} = -y

Base.:*(x::StaticFloat64{X}, y::StaticFloat64{Y}) where {X,Y} = fmul(x, y)
Base.:*(x::StaticFloat64{X}, y::StaticInt{Y}) where {X,Y} = *(x, float(y))
Base.:*(::StaticFloat64{X}, ::Zero) where {X} = FloatZero()
Base.:*(::Zero, ::StaticFloat64{Y}, ) where {Y} = FloatZero()
Base.:*(x::StaticFloat64{X}, ::One) where {X} = x
Base.:*(x::StaticInt{X}, y::StaticFloat64{Y}) where {X,Y} = *(float(x), y)
Base.:*(::One, y::StaticFloat64{Y}) where {Y} = y
Base.:*(x::FloatZero, ::FloatZero) = x
Base.:*(::StaticFloat64{X}, y::FloatZero) where {X} = y
Base.:*(x::FloatZero, ::StaticFloat64{Y}) where {Y} = x
Base.:*(x::FloatZero, ::FloatOne) = x
Base.:*(x::FloatOne, ::FloatOne) = x
Base.:*(x::StaticFloat64{X}, ::FloatOne) where {X} = x
Base.:*(::FloatOne, y::StaticFloat64{Y}) where {Y} = y
Base.:*(::FloatOne, y::FloatZero) = y

Base.:/(x::StaticFloat64{X}, y::StaticFloat64{Y}) where {X,Y} = fdiv(x, y)
Base.:/(x::StaticFloat64{X}, y::StaticInt{Y}) where {X,Y} = /(x, float(y))
Base.:/(x::StaticInt{X}, y::StaticFloat64{Y}) where {X,Y} = /(float(x), y)

@generated Base.sqrt(::StaticInt{M}) where {M} = Expr(:call, Expr(:curly, :StaticFloat64, sqrt(M)))
@generated Base.sqrt(::StaticFloat64{M}) where {M} = Expr(:call, Expr(:curly, :StaticFloat64, sqrt(M)))

@generated Base.round(::StaticFloat64{M}) where {M} = Expr(:call, Expr(:curly, :StaticFloat64, round(M)))
@generated roundtostaticint(::StaticFloat64{M}) where {M} = Expr(:call, Expr(:curly, :StaticInt, round(Int, M)))
roundtostaticint(x::AbstractFloat) = round(Int, x)
@generated floortostaticint(::StaticFloat64{M}) where {M} = Expr(:call, Expr(:curly, :StaticInt, floor(Int, M)))
floortostaticint(x::AbstractFloat) = Base.fptosi(Int, x)

Base.:(^)(::StaticFloat64{x}, y::Float64) where {x} = exp2(log2(x) * y)

Base.inv(x::StaticFloat64{N}) where {N} = fdiv(one(x), x)


text:
module Ex5_14
using FaultDetectionTools
using DescriptorSystems
using LinearAlgebra
using Polynomials
using Test

# Example 5.14 - Solution of an H∞ AMMP
println("Example 5.14")

s = rtf('s'); # define the Laplace variable s
Gf = 1/(s+1);        # enter $G_f(s)$
Gw = 1/(s+2);        # enter $G_w(s)$
mu = 0; mf = 1; mw = 1; p = 1; # set dimensions

# build the synthesis model with additive faults
sysf = fdimodset(dss([Gf Gw]), f = 1:mf, n = mf .+ (1:mw));

# define Mr(s) = 1/(s+3)
Mr = FDFilterIF(dss(1/(s+3)),0,0,mf)

Q, R, info = ammsyn(sysf, Mr; atol = 1.e-7, reltol = 1.e-5, sdeg = -1, normalize = "gain");

println("Q = $(zpk(dss2rm(Q.sys)[1,1]))")

# check suboptimal solution
Ge = [sysf.sys[:,[sysf.faults;sysf.noise]]; zeros(mu,mf+mw)]; Me = [info.M*Mr.sys zeros(mf,mw)];
@test iszero(R.sys-Q.sys*Ge, atol = 1.e-7) &&
      fdimmperf(R,info.M*Mr) ≈ info.gammasub && glinfnorm(Me-Q.sys*Ge)[1] ≈ info.gammasub

println("gamma_opt0 = $(info.gammaopt0)")  # optimal performance for the initial problem
println("gamma_opt  = $(info.gammaopt)")   # optimal performance
println("gamma_sub  = $(info.gammasub)")   # suboptimal performance

end # module

max_stars_repo_name: andreasvarga/FaultDetectionTools

max_issues_repo_name: andreasvarga/FaultDetectionTools

max_forks_repo_name: andreasvarga/FaultDetectionTools


text:
using MyExample

# load a fully observed dataset
data =  "Data/0.15_(15, 15, 15)_(1, 1, 1)_data.txt"
Y = SparseTensor(data)

Y
density(Y)
full(Y)
tensor(Y)
eachindex(Y)

### sparsetensor <: AbstractArray, also multiplying with MPS works, but slower
@time Mps(randn(15,15), randn(15,15), randn(15,15))*Y
Y2 = tensor(Y)
@time Mps(randn(15,15), randn(15,15), randn(15,15))*Y2

# removing some elements form Y
Y2 = SparseTensor(Y, eachindex(Y)[1:1000])
density(Y2)
full(Y2)
tensor(Y, "zeros")

max_stars_repo_name: padwulf/MyExample

max_issues_repo_name: padwulf/MyExample

max_forks_repo_name: padwulf/MyExample


text:
using MPCCModelManager, Test, UnPack

# @test Int64 <: Integer
# @test Float64 <: AbstractFloat

model_cfg = mpccmodel_load_defn_from_file("dev1");

@unpack n, q, l, me, mi, r, s = model_cfg.dimspec

x = [ 1.0, 2, 3, 4 ]
pr0 = [ -0.5, 1.0 ]
ps0 = [ 1 ]

#--------------------------------------------------------------------------------
# Check mutating functions match standard return values
#--------------------------------------------------------------------------------

# f
res_f = model_cfg.fns.f(x, pr0, ps0)
res_f_mut = similar(res_f) * 0.0
res_f_mut *= 0.0
model_cfg.fns.f!(res_f_mut, x, pr0, ps0)
@test res_f ≈ res_f_mut

# ce
res_ce = model_cfg.fns.ce(x, pr0, ps0)
res_ce_mut = similar(res_ce) * 0.0
res_ce_mut *= 0.0
model_cfg.fns.ce!(res_ce_mut, x, pr0, ps0)
@test res_ce ≈ res_ce_mut

# ci
res_ci = model_cfg.fns.ci(x, pr0, ps0)
res_ci_mut = similar(res_ci) * 0.0
res_ci_mut *= 0.0
model_cfg.fns.ci!(res_ci_mut, x, pr0, ps0)
@test res_ci ≈ res_ci_mut

# F
res_F = model_cfg.fns.F(x, pr0, ps0)
res_F_mut = similar(res_F) * 0.0
model_cfg.fns.F!(res_F_mut, x, pr0, ps0)
@test res_F ≈ res_F_mut

# ce indexed
for lp_ce=1:me
    res_ce_i = model_cfg.fns.ce_i[lp_ce](x, pr0, ps0)
    res_ce_i_mut = similar(res_ce_i) * 0.0
    model_cfg.fns.ce_i![lp_ce](res_ce_i_mut, x, pr0, ps0)
    @test res_ce_i ≈ res_ce_i_mut
end

# ci indexed
for lp_ci=1:mi
    res_ci_i = model_cfg.fns.ci_i[lp_ci](x, pr0, ps0)
    res_ci_i_mut = similar(res_ci_i) * 0.0
    model_cfg.fns.ci_i![lp_ci](res_ci_i_mut, x, pr0, ps0)
    @test res_ci_i ≈ res_ci_i_mut
end

# F indexed
for lp_l=1:l
    for lp_q=1:q
        res_F_i = model_cfg.fns.F_i[lp_l, lp_q](x, pr0, ps0)
        res_F_i_mut = similar(res_F_i) * 0.0
        model_cfg.fns.F_i![lp_l, lp_q](res_F_i_mut, x, pr0, ps0)
        @test res_F_i ≈ res_F_i_mut
    end
end


text:
"""
    getTable(params::Dict,tablename::String;tableOptional::Bool=false)

Returns the table named `tablename` from the contents of a TOML file, which was
previously parsed into the dictionary `params`. If `tableOptional` is `true`
the output will be either a dictionary with the contents of the table or
`missing`. If `tableOptional` is true the function will throw an error instead
of returning missing.
"""
function getTable(params::Dict,tablename::String;tableOptional::Bool=false)
    for part in split(tablename,".")
        params = get(params,part,missing)
        ismissing(params) & !tableOptional && throw(MissingException("Non-optional table [$(tablename)] missing in configuration file."))
    end
    return params
end

"""
    getValue(params::Dict,tablename::String,key::Sring;valueOptional::Bool=false)

Returns a the value specified by a `key` from the table named `tablename` from
the contents of a TOML file, which was previously parsed into the dictionary
`params`. If `valueOptional` is `true` the output will be either the value or
`missing`. If `valueOptional` is true the function will throw an error instead
of returning missing.
"""
function getValue(params::Dict,tablename::String,key::String;valueOptional::Bool=false)
    params = getTable(params,tablename,tableOptional=valueOptional)
    if ismissing(params)
	    return missing
    else
	    value = get(params,key,missing)
        ismissing(value) & !valueOptional && throw(MissingException("key $(key) expected in table [$(tablename)] but missing."))
	    return value
    end
end

"""
    getType(params::Dict,tablename::String)

Tries to parse the key "type" from the table named `tablename` from the
contents of a TOML file, which was previously parsed into the dictionary
`params` into an actual julia type. Returns missing if it fails to do so, e.g.
if the key is missing in the TOML file.
"""
getType(params::Dict,tablename::String) = eval(Symbol(getValue(params,tablename,"type",valueOptional=true)))

"""
    initialize(T::Type,params::Dict,floatType::Type)

Tries to initialize the type `T` from the contents of a TOML file, which was
previously parsed into the dictionary `params`. To this end all values obtained
from the TOML are converted to the type `floatType` or arrays thereof. So `T`
needs to have a suitable constructor.
"""
function initialize(T::Type,tablename::String,params::Dict,floatType::Type)
    fieldNamesT = map(string,fieldnames(T))
    values = map(key->getValue(params,tablename,key),fieldNamesT)
    fieldValues = []
    for (i,value) in enumerate(values)
        TField = fieldtype(T,i)
        if TField <: Integer && isprimitivetype(TField)
            push!(fieldValues,TField(value))
        elseif typeof(value) <: Real
            push!(fieldValues,floatType(value))
        elseif typeof(value) <: Array{T} where {T<:Array}
            push!(fieldValues,floatType.(hcat(value...)))
        elseif typeof(value) <: Array{T} where {T<:Real}
            push!(fieldValues,floatType.(value))
        elseif typeof(value) <: Dict{String,Any}
            if length(keys(value))==1
                typeName = collect(keys(value))[1]
                type = eval(Symbol(typeName))
                push!(fieldValues,initialize(type,typeName,value,floatType))
            else
                throw(ErrorException("Recursive initialization failed. Dictionariy $value expected to have a single key only."))
            end
        else
            throw(ErrorException("I do not know how to handle value $value when trying to initialize type $T from table $tablename"))
        end
    end
    return T(fieldValues...)
end

"""
    getTableName(T::Type)

Outputs the tablename which is expected to hold the data to `initialize` the
type `T` from the contents of a TOML file.
"""
function getTableName(T::Type)
    out = String[]
    while T != Any
        typeString = string(T)
        m = match(r"^(?:\w*\.)*(\w+)", typeString)
	    pushfirst!(out,m.captures[1])
        T = supertype(T)
    end
    return join(out,".")
end


text:
_ordered(a, b) = a ≤ b ? (a, b) : (b, a)
function _get_most_informative(d_edges, tagged_edges)
    s = 0
    si = 1
    for (i, edges) in enumerate(d_edges)
        t = sum([1 for e ∈ edges if e ∉ tagged_edges])
        if t > s
            s = t
            si = i
        end
    end
    si
end

"""
Selection with Informativeness Algorithm.

`haplotypes` is a nxm matrix (or n-element list of m-element array)
where the j-th element of the i-th row indicates the allele type of the j-th SNP
in the i-th haplotype.

Assuming that all the SNPs are biallelic, it does not matter whether 0's indicate MAF.

Note that currently this function implements a naive greedy algorithm,
which is expected to be time consuming.

`ξ` is the informativeness threshold.

Return:

`tagSNPs`: an array of SNP indices that has at least `ξ` informativeness.
"""
function informative_select(
    haplotypes::Matrix{Bool};
    MAF_threshold = 0.1,
    ξ = 0.8
)
    @assert ξ ≤ 1

    fs, haplotypes = prepare_select(haplotypes)
    n, m = size(haplotypes)
    snp_indices = (1:m)[fs .< (1 - MAF_threshold)]
    m2 = length(snp_indices)

    total = Set{Tuple{Int, Int}}()
    d_edges = Set{Tuple{Int, Int}}[]
    for index in snp_indices
        vs = haplotypes[:, index]
        v0s = (1:n)[vs .≡ false]
        v1s = (1:n)[vs .≡ true]
        edges = Set{Tuple{Int, Int}}()
        for i in v0s
            for j in v1s
                push!(edges, _ordered(i, j))
            end
        end
        push!(d_edges, edges)
        union!(total, edges)
    end
    len_d_edges = length.(d_edges)

    first = argmax(len_d_edges)

    tags = [snp_indices[first]]
    tagged_edges = d_edges[first]
    deleteat!(snp_indices, first)
    deleteat!(d_edges, first)

    target = ceil(Int, ξ * length(total))
    while length(tagged_edges) < target && length(tags) < m2
        si = _get_most_informative(d_edges, tagged_edges)
        union!(tagged_edges, d_edges[si])
        push!(tags, snp_indices[si])
        deleteat!(snp_indices, si)
        deleteat!(d_edges, si)
    end
    tags
end

informative_select(
    haplotypes::AbstractVector;
    kwargs...
) = informative_select(make_binary(haplotypes); kwargs...)


text:
# Sketch algorithms
#
# Danny Perry (dperry@cs.utah.edu)
# Oct 2014
#

module Sketch

export
	# Frequent Directions
	FD,
	# Column Sampling
	LinearTimeSVD, LeverageLinearTimeSVD,
	# CUR
	LinearTimeCUR, LeverageCUR,
	# Sparsification
	RandomSparsify, RandomRoundSparsify

# Frequent Directions
include("FD.jl")

# Column sampling
include("ColumnSampling.jl")

# CUR
include("CUR.jl")

# Sparsify
include("Sparsification.jl")

end # module


text:
abstract type AbstractDynamicChunker{F} end

struct DynamicBottleneckChunker{F} <: AbstractDynamicChunker{F}
    f::F
end

@inline _dynamic_chunker_combine(::DynamicBottleneckChunker) = max

struct DynamicTotalChunker{F} <: AbstractDynamicChunker{F}
    f::F
end

@inline _dynamic_chunker_combine(::DynamicTotalChunker) = +

function pack_stripe(A::SparseMatrixCSC{Tv, Ti}, method::DynamicTotalChunker, args...; kwargs...) where {Tv, Ti}
    #Reference Implementation
    return pack_stripe(A, DynamicTotalChunker(ConstrainedCost(method.f, FeasibleCost(), Feasible())), args...; kwargs...)
end

function pack_stripe(A::SparseMatrixCSC{Tv, Ti}, method::DynamicTotalChunker{<:ConstrainedCost}, args...; kwargs...) where {Tv, Ti}
    #Reference Implementation
    @inbounds begin
        # matrix notation...
        # i = 1:m rows, j = 1:n columns
        m, n = size(A)

        f = oracle_stripe(StepHint(), method.f.f, A, args...; kwargs...)
        w = oracle_stripe(StepHint(), method.f.w, A, args...; kwargs...)
        w_max = method.f.w_max

        cst = Vector{cost_type(f)}(undef, n + 1)
        cst[1] = zero(cost_type(f))
        spl = Vector{Int}(undef, n + 1)
        j₀ = 1
        for j′ = 2:n + 1
            while w(j₀, j′) > w_max
                j₀ += 1
            end
            @assert j₀ < j′ #TODO infeasibility

            best_c = cst[j₀] + f(j₀, j′)
            best_j = j₀
            for j = j₀ + 1 : j′ - 1
                c = cst[j] + Step(f)(Next(j), Same(j′))
                if c < best_c
                    best_c = c
                    best_j = j
                end
            end
            cst[j′] = best_c
            spl[j′] = best_j
        end

        return unravel_chunks!(spl, n)
    end
end

function unravel_chunks!(spl, n)
    begin
        K = 0
        j′ = n + 1
        while j′ != 1
            j = spl[j′]
            spl[end - K] = j′
            K += 1
            j′ = j
        end
        spl[1] = 1
        for k = 1:K
            spl[k + 1] = spl[end - K + k]
        end
        resize!(spl, K + 1)
        return SplitPartition(K, spl)
    end
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 44194c10-3d62-11eb-2089-2b2813796028
using STMOZOO.LocalSearch

# ╔═╡ 9db0d300-3d63-11eb-31bb-b3a8acc6a1c9
md"""

# Solving a Sudoku using Local Search

Sudoku is a world wide popular Japanese puzzle. Although very challenging, Sudoku rules are quite simple: placing digits between 1-9 on a 9×9 grid such that
each digit appears once in each row, column and each 3x3 sub-grid.

Local search methods, opposed to brute force algorithm, move from state to state in the space of states by applying local changes, trying to get closer to the solution for each time.

A naive local search algorithm starts from a complete random assignment, then attempts to find a better state by making an incremental change until it finds the solution or gets stuck in a local minimum.

#### Get a Sudoku puzzle
"""

# ╔═╡ 9ca452c4-5105-11eb-15b4-7b0e6caa8a7d
# Would it better to put just one example to help to follow up?

# ╔═╡ dec03be0-3d6a-11eb-003a-197ac59933dc
md"""
The puzzle is presented so that in the beginning there are
some static numbers, givens, in the grid that are given in
advance and cannot be changed or moved. The number of
givens does not determine the difficulty of the puzzle. In the matrix, the zeros represent missing values.
"""

# ╔═╡ dd7c43d0-3d62-11eb-2f9c-69eb6819d094
sudoku_1

# ╔═╡ 479a4660-3d6b-11eb-2453-399baa5b059f
sudoku_2

# ╔═╡ 58841be0-3d6b-11eb-3e22-b5465d1cf3a3
md"""
#### Get an initial state

Randomly assign numbers from 1 to 9 to each missing value

"""

# ╔═╡ f2e96870-3d6b-11eb-1dee-61f5f48f8ba4
sudoku_full1 = fill_in(sudoku_1)

# ╔═╡ 088135a0-3d6c-11eb-03a1-d5b500d99e92
sudoku_full2 = fill_in(sudoku_2)

# ╔═╡ 45f09890-3d6c-11eb-2653-b17cf5ebd7fd
md"""
#### Finding a better state

Randomly change the number of a particular position, then evaluate if the new state is better than the previous. To make the evaluation a fitness/cost function must be defined. Here the cost function shows how many times a number in the evaluated position is present in the same row, column or subgrid.

Lets evaluate the cost of the **position [1,1]** in **Sudoku_full1.**
"""

# ╔═╡ 652f7270-3d6d-11eb-034f-4b9a8852189e
#shows the number of repetitions of number in position [1,1]
cc1 = check_value(sudoku_full1, 1, 1)

# ╔═╡ 8523fd2e-3d6d-11eb-30f2-cd1240c6f3d6
md"""
Now we can assign a different number, for example "5", to that position and evaluate if the cost increase or decrease
"""

# ╔═╡ 4efa8570-3d6e-11eb-1b08-6b78d70cfaac
cc2 = check_value(sudoku_full1, 1, 1, 5)

# ╔═╡ ab19f9e0-3dea-11eb-1bd1-1d1417688288
cc2 < cc1

# ╔═╡ 5f31fae0-3d6e-11eb-05bc-87215c66feb0
md"""
The total cost of the sudoku will be the sum of the costs of all positions
"""

# ╔═╡ d5f59dc0-3d6f-11eb-3c25-713923efc3ad
sudoku_cost(sudoku_full1)

# ╔═╡ 4597cd5e-3d70-11eb-275a-bfe09278d486
md"""
#### Solving a Sudoku

We can repeat multiple times the previous process using the function `sudoku_greedydesc`, which randomly assigns new numbers per position in the grid. it will only move to a new state if its cost isnt higher than the previous.
"""

# ╔═╡ 0f8aacb0-3d70-11eb-0be0-af7c2b65dc1b
solution1, cost1 = sudoku_greedydesc(sudoku_full1, sudoku_1, 1000)

# ╔═╡ e6888ebe-3d71-11eb-1774-89ccc2f2a893
md"""
After 1000 random replacements, the obtained solution has a **total cost of $cost1.**
Therefore, it is not the true solution or global minimun.

Since the `fill_in` function fills each row with numbers from 1 to 9 without repetitions, a sligthly different approach we can use is not to change numbers randomly but to swap numbers only within rows.

We can swap two random positions using `fliprow` function.
"""

# ╔═╡ 07e5b4c0-3d73-11eb-0e06-d7907a930654
sudoku_flip1, pos1, pos2 = fliprow(sudoku_full1, sudoku_1)

# ╔═╡ 17aa4b10-3dea-11eb-10c8-e98295270098
md"""
Now, we can check the cost of the new state and evaluate if it is better/worse than the previous.
"""

# ╔═╡ 4ad903f0-3dea-11eb-188b-cfd082eb0727
sudoku_cost(sudoku_flip1) <= sudoku_cost(sudoku_full1)

# ╔═╡ 77b58ea0-3d74-11eb-057f-11a15bcab5b3
md"""
Similarly to what we did with `sudoku_greedydesc` function, we can repeat this process many times while evaluating the cost of the new state after the swap. It will only move to a new state if its cost isnt higher than the previous. This can be done with the function `makefliprow`
"""

# ╔═╡ 4c189700-3d75-11eb-06e2-878687d8edba
solution2 = makefliprow(sudoku_full1, sudoku_1, 1000)

# ╔═╡ 77ce2a40-3d75-11eb-3808-3df0aefaa6be
cost2 = sudoku_cost(solution2)

# ╔═╡ 89f9ce90-3d75-11eb-0e85-49bbafb27035
md"""
Again, since the **cost is $cost2**, the obtained state is not the global minimum.

The problem with these approaches is that they are strongly affected by the initial state, therefore, is necessary to restart or iteratively change the initial state to avoid getting stuck in a local minimum.

We can use the swapping approach. Start with a random assigment, then make swaps to reduce the cost of the solution, if the cost is not zero, start from another random assigment.
"""

# ╔═╡ 5c5fa760-3d76-11eb-074d-b57c5caed0ba
begin
	solution3 =[]
	min_cost = Inf
	j = 0
	for i in 1:100
		global j, min_cost, solution3
		j += 1 #to count iterations
		start = fill_in(sudoku_1) #restart in a different state
		sol = makefliprow(start, sudoku_1, 1000) #make 1000 swaps
		cost = sudoku_cost(sol) #get the cost of the obtained solution
		if cost == 0 #if it is zero then it is the final solution
			solution3 = sol
			break
		end
		if cost < min_cost #keep track of the solution with the minimum cost
			min_cost = cost
			solution3 = sol
		end
	end
end

# ╔═╡ 0ed0cac0-3ded-11eb-2542-4f3c14ebbbe2
solution3

# ╔═╡ 3bf138a0-3ded-11eb-09b6-bba39aa01e3b
sudoku_cost(solution3)

# ╔═╡ 72a372f0-3ded-11eb-3dcf-4b342b390890
md"""
By restarting the intial state, the algorithm was able to find the true solution with **cost $(sudoku_cost(solution3))** in **$j iterations**.

Now, we can try to solve `sudoku_2`
"""

# ╔═╡ df1ceb52-3ded-11eb-3223-f1a0ae406d4c
begin
	solution4 =[]
	min_cost2 = Inf
	k = 0
	for i in 1:100
		global k, min_cost2, solution4
		k += 1 #to count iterations
		start = fill_in(sudoku_2) #restart in a different state
		sol = makefliprow(start, sudoku_2, 1000) #make 1000 swaps
		cost = sudoku_cost(sol) #get the cost of the obtained solution
		if cost == 0 #if it is zero then it is the final solution
			solution4 = sol
			break
		end
		if cost < min_cost2 #keep track of the solution with the minimun cost
			min_cost2 = cost
			solution4 = sol
		end
	end
end

# ╔═╡ 37e557e0-3dee-11eb-2f5f-03a88ced69c3
solution4

# ╔═╡ 3e56d182-3dee-11eb-07a9-d7baa09ebc45
sudoku_cost(solution4)

# ╔═╡ 506e5190-3dee-11eb-184e-4d36e8eb1c51
md"""
The true solution with **cost $(sudoku_cost(solution4))** was found in **$k iterations.**
"""

# ╔═╡ 61de9850-3df2-11eb-1452-c79af84acab7
md"""
Now, lets use `sudoku_greedydesc` to find the true solution. As mentioned before, this function randomly replaces numbers in the matrix that decrease the cost of the solution.
"""

# ╔═╡ a932ed90-3dee-11eb-3c98-71279cf5e3bb
begin
	solution5 =[]
	min_cost3 = Inf
	m = 0
	for i in 1:100
		global m, min_cost3, solution5
		m += 1 #to count iterations
		start = fill_in(sudoku_1) #restart in a different state
		sol, cost = sudoku_greedydesc(start, sudoku_1, 10000) #make 1000 swaps
		if cost == 0 #if it is zero then it is the final solution
			solution5 = sol
			break
		end
		if cost < min_cost3 #keep track of the solution with the minimun cost
			min_cost3 = cost
			solution5 = sol
		end
	end
end

# ╔═╡ 5c5853f0-3df0-11eb-1a78-274cceaf7711
solution5

# ╔═╡ 633fe7f0-3df0-11eb-3f20-1d38fa05b17c
sudoku_cost(solution5)

# ╔═╡ 1fe59f80-3dfb-11eb-08f2-b1e4a62e679f
md"""
This approach is far less effecient than the previous. It will need at least 10000 iterations to find the correct solution
"""

# ╔═╡ Cell order:
# ╠═44194c10-3d62-11eb-2089-2b2813796028
# ╟─9db0d300-3d63-11eb-31bb-b3a8acc6a1c9
# ╠═9ca452c4-5105-11eb-15b4-7b0e6caa8a7d
# ╟─dec03be0-3d6a-11eb-003a-197ac59933dc
# ╠═dd7c43d0-3d62-11eb-2f9c-69eb6819d094
# ╠═479a4660-3d6b-11eb-2453-399baa5b059f
# ╟─58841be0-3d6b-11eb-3e22-b5465d1cf3a3
# ╠═f2e96870-3d6b-11eb-1dee-61f5f48f8ba4
# ╠═088135a0-3d6c-11eb-03a1-d5b500d99e92
# ╟─45f09890-3d6c-11eb-2653-b17cf5ebd7fd
# ╠═652f7270-3d6d-11eb-034f-4b9a8852189e
# ╟─8523fd2e-3d6d-11eb-30f2-cd1240c6f3d6
# ╠═4efa8570-3d6e-11eb-1b08-6b78d70cfaac
# ╠═ab19f9e0-3dea-11eb-1bd1-1d1417688288
# ╟─5f31fae0-3d6e-11eb-05bc-87215c66feb0
# ╠═d5f59dc0-3d6f-11eb-3c25-713923efc3ad
# ╟─4597cd5e-3d70-11eb-275a-bfe09278d486
# ╠═0f8aacb0-3d70-11eb-0be0-af7c2b65dc1b
# ╟─e6888ebe-3d71-11eb-1774-89ccc2f2a893
# ╠═07e5b4c0-3d73-11eb-0e06-d7907a930654
# ╟─17aa4b10-3dea-11eb-10c8-e98295270098
# ╠═4ad903f0-3dea-11eb-188b-cfd082eb0727
# ╟─77b58ea0-3d74-11eb-057f-11a15bcab5b3
# ╠═4c189700-3d75-11eb-06e2-878687d8edba
# ╠═77ce2a40-3d75-11eb-3808-3df0aefaa6be
# ╟─89f9ce90-3d75-11eb-0e85-49bbafb27035
# ╠═5c5fa760-3d76-11eb-074d-b57c5caed0ba
# ╠═0ed0cac0-3ded-11eb-2542-4f3c14ebbbe2
# ╠═3bf138a0-3ded-11eb-09b6-bba39aa01e3b
# ╟─72a372f0-3ded-11eb-3dcf-4b342b390890
# ╠═df1ceb52-3ded-11eb-3223-f1a0ae406d4c
# ╠═37e557e0-3dee-11eb-2f5f-03a88ced69c3
# ╠═3e56d182-3dee-11eb-07a9-d7baa09ebc45
# ╟─506e5190-3dee-11eb-184e-4d36e8eb1c51
# ╟─61de9850-3df2-11eb-1452-c79af84acab7
# ╟─a932ed90-3dee-11eb-3c98-71279cf5e3bb
# ╠═5c5853f0-3df0-11eb-1a78-274cceaf7711
# ╠═633fe7f0-3df0-11eb-3f20-1d38fa05b17c
# ╟─1fe59f80-3dfb-11eb-08f2-b1e4a62e679f


text:
file_name = [
    "stack",
    "queue",
    "deque",
    "circular_queue",
    "sparse_array",
    "linked_list",
    "binary_tree",
    "union_find",
    "heap",
    "min_max_heap",
    "priority_queue",
    "graph",
]

for f in file_name
    teststr = "# Test '$(f)' #"
    len = length(teststr)
    teststr = "\n$("#"^len)\n$(teststr)\n$("#"^len)\n"
    println()
    @info teststr

    include("$f.jl")
end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct VirtualNetworkTapPropertiesFormat <: SwaggerModel
    networkInterfaceTapConfigurations::Any # spec type: Union{ Nothing, Vector{NetworkInterfaceTapConfiguration} } # spec name: networkInterfaceTapConfigurations
    resourceGuid::Any # spec type: Union{ Nothing, String } # spec name: resourceGuid
    provisioningState::Any # spec type: Union{ Nothing, ProvisioningState } # spec name: provisioningState
    destinationNetworkInterfaceIPConfiguration::Any # spec type: Union{ Nothing, NetworkInterfaceIPConfiguration } # spec name: destinationNetworkInterfaceIPConfiguration
    destinationLoadBalancerFrontEndIPConfiguration::Any # spec type: Union{ Nothing, FrontendIPConfiguration2 } # spec name: destinationLoadBalancerFrontEndIPConfiguration
    destinationPort::Any # spec type: Union{ Nothing, Int32 } # spec name: destinationPort

    function VirtualNetworkTapPropertiesFormat(;networkInterfaceTapConfigurations=nothing, resourceGuid=nothing, provisioningState=nothing, destinationNetworkInterfaceIPConfiguration=nothing, destinationLoadBalancerFrontEndIPConfiguration=nothing, destinationPort=nothing)
        o = new()
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("networkInterfaceTapConfigurations"), networkInterfaceTapConfigurations)
        setfield!(o, Symbol("networkInterfaceTapConfigurations"), networkInterfaceTapConfigurations)
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("resourceGuid"), resourceGuid)
        setfield!(o, Symbol("resourceGuid"), resourceGuid)
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("provisioningState"), provisioningState)
        setfield!(o, Symbol("provisioningState"), provisioningState)
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("destinationNetworkInterfaceIPConfiguration"), destinationNetworkInterfaceIPConfiguration)
        setfield!(o, Symbol("destinationNetworkInterfaceIPConfiguration"), destinationNetworkInterfaceIPConfiguration)
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("destinationLoadBalancerFrontEndIPConfiguration"), destinationLoadBalancerFrontEndIPConfiguration)
        setfield!(o, Symbol("destinationLoadBalancerFrontEndIPConfiguration"), destinationLoadBalancerFrontEndIPConfiguration)
        validate_property(VirtualNetworkTapPropertiesFormat, Symbol("destinationPort"), destinationPort)
        setfield!(o, Symbol("destinationPort"), destinationPort)
        o
    end
end # type VirtualNetworkTapPropertiesFormat

const _property_map_VirtualNetworkTapPropertiesFormat = Dict{Symbol,Symbol}(Symbol("networkInterfaceTapConfigurations")=>Symbol("networkInterfaceTapConfigurations"), Symbol("resourceGuid")=>Symbol("resourceGuid"), Symbol("provisioningState")=>Symbol("provisioningState"), Symbol("destinationNetworkInterfaceIPConfiguration")=>Symbol("destinationNetworkInterfaceIPConfiguration"), Symbol("destinationLoadBalancerFrontEndIPConfiguration")=>Symbol("destinationLoadBalancerFrontEndIPConfiguration"), Symbol("destinationPort")=>Symbol("destinationPort"))
const _property_types_VirtualNetworkTapPropertiesFormat = Dict{Symbol,String}(Symbol("networkInterfaceTapConfigurations")=>"Vector{NetworkInterfaceTapConfiguration}", Symbol("resourceGuid")=>"String", Symbol("provisioningState")=>"ProvisioningState", Symbol("destinationNetworkInterfaceIPConfiguration")=>"NetworkInterfaceIPConfiguration", Symbol("destinationLoadBalancerFrontEndIPConfiguration")=>"FrontendIPConfiguration2", Symbol("destinationPort")=>"Int32")
Base.propertynames(::Type{ VirtualNetworkTapPropertiesFormat }) = collect(keys(_property_map_VirtualNetworkTapPropertiesFormat))
Swagger.property_type(::Type{ VirtualNetworkTapPropertiesFormat }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_VirtualNetworkTapPropertiesFormat[name]))}
Swagger.field_name(::Type{ VirtualNetworkTapPropertiesFormat }, property_name::Symbol) =  _property_map_VirtualNetworkTapPropertiesFormat[property_name]

function check_required(o::VirtualNetworkTapPropertiesFormat)
    true
end

function validate_property(::Type{ VirtualNetworkTapPropertiesFormat }, name::Symbol, val)
end


text:
import HTTP
import Gumbo
import Cascadia

#=
Download the BAL datasets from https://grail.cs.washington.edu/projects/bal/.
Unzip all of the files.
=#

function scrape_downloads_for_category(category)
    downloads = String[]

    url = "https://grail.cs.washington.edu/projects/bal/$category.html"
    response = HTTP.get(url)

    html = Gumbo.parsehtml(String(response.body))
    links = Cascadia.eachmatch(
        Cascadia.Selector("a"),
        html.root
    )
    for link in links
        href = Gumbo.getattr(link, "href")

        # exclude the "return to index" link
        if occursin(category, href)
            push!(downloads, href)
        end
    end
    return downloads
end

function download_bal_problem(web_link, category)

    short_name = basename(web_link)

    if startswith(web_link, "http")
        long_name = web_link
    else
        long_name = "https://grail.cs.washington.edu/projects/bal/$web_link"
    end

    local_name = joinpath(joinpath(dataset_dir, category), short_name)
    local_unzipped_name = replace(local_name, ".txt.bz2" => ".txt")

    if !isfile(local_unzipped_name)

        if !isfile(local_name)
            println("Downloading ", category, "/", short_name)
            download(long_name, local_name)
        end

        println("Decompressing ", category, "/", short_name)
        run(`bzip2 -d $local_name`)
    end
end

function main()
    # put the BAL files here
    dataset_dir = normpath(joinpath(@__DIR__, "..", "dataset", "bal"))
    println("Downloading BAL dataset to ", dataset_dir)

    # make sure the dataset directory exists
    mkpath(dataset_dir)

    bal_categories = [
        "ladybug",
        "trafalgar",
        "dubrovnik",
        "venice",
        "final"
    ]
    for category in bal_categories

        category_dir = joinpath(dataset_dir, category)
        if !isdir(category_dir)
            mkdir(category_dir)
        end

        web_links = scrape_downloads_for_category(category)
        for link in web_links
            download_bal_problem(link, category)
        end
    end
end

max_stars_repo_name: wilsonkl/sfmflex-release

max_issues_repo_name: wilsonkl/sfmflex-release

max_forks_repo_name: wilsonkl/sfmflex-release


text:
#-------------------------------------------------------------------
#* EMSO Model Library (EML) Copyright (C) 2004 - 2007 ALSOC.
#*
#* This LIBRARY is free software; you can distribute it and/or modify
#* it under the therms of the ALSOC FREE LICENSE as available at
#* http://www.enq.ufrgs.br/alsoc.
#*
#* EMSO Copyright (C) 2004 - 2007 ALSOC, original code
#* from http://www.rps.eng.br Copyright (C) 2002-2004.
#* All rights reserved.
#*
#* EMSO is distributed under the therms of the ALSOC LICENSE as
#* available at http://www.enq.ufrgs.br/alsoc.
#*-----------------------------------------------------------------------
#* Author: Tiago Os򱨯rio
#* $Id$
#*---------------------------------------------------------------------
type Multiply
	Multiply()=begin
		new(
			control_signal(Dict{Symbol,Any}(
				:Brief=>"input signal 1",
				:PosX=>0,
				:PosY=>0.75
			)),
			control_signal(Dict{Symbol,Any}(
				:Brief=>"input signal 2",
				:PosX=>0,
				:PosY=>0.25
			)),
			control_signal(Dict{Symbol,Any}(
				:Brief=>"output signal",
				:PosX=>1,
				:PosY=>0.5
			)),
			[
				:(output=input1*input2),
			],
			[
				"Calculate output",
			],
			[:input1,:input2,:output,]
		)
	end
	input1::control_signal
	input2::control_signal
	output::control_signal
	equations::Array{Expr,1}
	equationNames::Array{String,1}
	variables::Array{Symbol,1}
	attributes::Dict{Symbol,Any}
end
export Multiply
function setEquationFlow(in::Multiply)
	addEquation(1)
end
function atributes(in::Multiply,_::Dict{Symbol,Any})
	fields::Dict{Symbol,Any}=Dict{Symbol,Any}()
	fields[:Pallete]=false
	fields[:Icon]="icon/Multiply"
	fields[:Brief]="Model Multiply."
	fields[:Info]="== Inputs ==
* Two input signals.

== Outputs ==
* One output signal.
"
	drive!(fields,_)
	return fields
end
Multiply(_::Dict{Symbol,Any})=begin
	newModel=Multiply()
	newModel.attributes=atributes(newModel,_)
	newModel
end


text:
# type aliases
typealias EuropeanOption Option{EuropeanExercise}
typealias AmericanOption Option{AmericanExercise}
typealias BermudanOption Option{BermudanExercise}

type OptionResults # Greeks
  delta::Float64
  gamma::Float64
  theta::Float64
  vega::Float64
  rho::Float64
  dividendRho::Float64
  deltaForward::Float64
  elasticity::Float64
  thetaPerDay::Float64
  strikeSensitivity::Float64
  itmCashProbability::Float64
  value::Float64
end

OptionResults() = OptionResults(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

type VanillaOptionArgs{P <: StrikedTypePayoff, E <: Exercise}
  payoff::P
  exercise::E
end

function reset!(res::OptionResults)
  res.delta = 0.0
  res.gamma = 0.0
  res.theta = 0.0
  res.vega = 0.0
  res.rho = 0.0
  res.dividendRho = 0.0
  res.deltaForward = 0.0
  res.elasticity = 0.0
  res.thetaPerDay = 0.0
  res.strikeSensitivity = 0.0
  res.itmCashProbability = 0.0
  res.value = 0.0

  return res
end

type VanillaOption{S <: StrikedTypePayoff, E <: Exercise, P <: PricingEngine} <: OneAssetOption{E}
  lazyMixin::LazyMixin
  payoff::S
  exercise::E
  pricingEngine::P
  results::OptionResults
end

VanillaOption{S <: StrikedTypePayoff, E <: Exercise, P <: PricingEngine}(payoff::S, exercise::E, pe::P) =
              VanillaOption{S, E, P}(LazyMixin(), payoff, exercise, pe, OptionResults())

get_pricing_engine_type{S, E, P}(::VanillaOption{S, E, P}) = P

function clone{P <: PricingEngine}(opt::VanillaOption, pe::P = opt.pricingEngine)
  lazyMixin, res = pe == opt.pricingEngine ? (opt.lazyMixin, opt.results) : (LazyMixin(), OptionResults())

  return VanillaOption{typeof(opt.payoff), typeof(opt.exercise), P}(lazyMixin, opt.payoff, opt.exercise, pe, res)
end


text:
function SubLine(arg0::Hyperplane, arg1::Region)
    return SubLine((Hyperplane, Region), arg0, arg1)
end

function SubLine(arg0::Segment)
    return SubLine((Segment,), arg0)
end

function SubLine(arg0::Vector2D, arg1::Vector2D, arg2::jdouble)
    return SubLine((Vector2D, Vector2D, jdouble), arg0, arg1, arg2)
end

function apply_transform(obj::AbstractSubHyperplane, arg0::Transform)
    return jcall(obj, "applyTransform", AbstractSubHyperplane, (Transform,), arg0)
end

function copy_self(obj::AbstractSubHyperplane)
    return jcall(obj, "copySelf", AbstractSubHyperplane, ())
end

function get_hyperplane(obj::AbstractSubHyperplane)
    return jcall(obj, "getHyperplane", Hyperplane, ())
end

function get_remaining_region(obj::AbstractSubHyperplane)
    return jcall(obj, "getRemainingRegion", Region, ())
end

function get_segments(obj::SubLine)
    return jcall(obj, "getSegments", List, ())
end

function get_size(obj::AbstractSubHyperplane)
    return jcall(obj, "getSize", jdouble, ())
end

function intersection(obj::SubLine, arg0::SubLine, arg1::jboolean)
    return jcall(obj, "intersection", Vector2D, (SubLine, jboolean), arg0, arg1)
end

function is_empty(obj::AbstractSubHyperplane)
    return jcall(obj, "isEmpty", jboolean, ())
end

function reunite(obj::AbstractSubHyperplane, arg0::SubHyperplane)
    return jcall(obj, "reunite", AbstractSubHyperplane, (SubHyperplane,), arg0)
end

function split(obj::SubLine, arg0::Hyperplane)
    return jcall(obj, "split", SubHyperplane_SplitSubHyperplane, (Hyperplane,), arg0)
end


text:
#=
只测试了不等式的特例的6元形式，选取了4096个样本
=#

function test(LHS::Function,RHS::Function)
    c=zero(Float64)
    for a1 in 1:4
        for a2 in 1:4
            for a3 in 1:4
                for a4 in 1:4
                    for a5 in 1:4
                        for a6 in 1:4
                            c+=LHS(a1,a2,a3,a4,a5,a6)/RHS(a1,a2,a3,a4,a5,a6)
                        end
                    end
                end
            end
        end
    end
    return 1/(c/4096-1)
end

代数平均(a,b,c,d,e,f)=(a+b+c+d+e+f)/6.0
几何平均(a,b,c,d,e,f)=(a*b*c*d*e*f)^(1.0/6)
平方平均(a,b,c,d,e,f)=sqrt((a*a+b*b+c*c+d*d+e*e+f*f)/6.0)
调和平均(a,b,c,d,e,f)=6/(1.0/a+1.0/b+1.0/c+1.0/d+1.0/e+1.0/f)
顺序和(a,b,c,d,e,f)=a*a+b*b+c*c+d*d+e*e+f*f
乱序和(a,b,c,d,e,f)=a*b+b*d+c*a+d*f+e*c+f*e
function 逆序和(a,b,c,d,e,f)
    x=sort([a,b,c,d,e,f])
    return (x[1]*x[6]+x[2]*x[5]+x[3]*x[4])*2.0
end
柯西L(a,b,c,d,e,f)=(a^3+b^3+c^3+d^3+e^3+f^3)*(a+b+c+d+e+f)
柯西R(a,b,c,d,e,f)=(a*a+b*b+c*c+d*d+e*e+f*f)^2
广义伯努利L(a,b,c,d,e,f)=(1+a)*(1+b)*(1+c)*(1+d)*(1+e)*(1+f)
广义伯努利R(a,b,c,d,e,f)=(1+a+b+c+d+e+f)*1.0

cd(@__DIR__)
io=open("strength.dict","w")
println(io,"代数-几何 ",test(代数平均,几何平均))
println(io,"平方-代数 ",test(平方平均,代数平均))
println(io,"几何-调和 ",test(几何平均,调和平均))
println(io,"顺序-乱序 ",test(顺序和,乱序和))
println(io,"乱序-逆序 ",test(乱序和,逆序和))
println(io,"柯西 ",test(柯西L,柯西R))
println(io,"广义伯努利 ",test(广义伯努利L,广义伯努利R))
close(io)

max_stars_repo_name: Rratic/notes

max_issues_repo_name: Rratic/notes

max_forks_repo_name: Rratic/notes


text:
function detrend_ts(arr)
    """
    This function removes time trend from a time series (array)
    """
    x = collect(0:1/12:1/12*(length(arr)-1))
    x = convert(Array{Float64,1},x)
    y = Array{Union{Float64, Missing}}(arr)
    data = DataFrame(X=x, Y=y)
    ols = lm(@formula(Y ~ X), data)
    f(x) = coef(ols)[1] + coef(ols)[2]*x
    return (arr - f.(x))
end


text:
using JLD

currentDir = dirname(@__FILE__)
@show currentDir
@show findlast("/",currentDir)[1]
@show dirname(@__FILE__)
setDir = string(currentDir[1:findlast("/",currentDir)[1]],"preBuild/")

function loadFermionicCr(i::Int, N::Int, Np::Int)

	cr = load(string(string(setDir,"Creation/Fermionic/"),"cr_",string(i),"_N",string(N),"_Np",string(Np),".jld"))
	cr = cr["creation"]

	return cr
end

function saveFermionicCr(cr::AbstractArray{<:Number,2},i::Int, N::Int, Np::Int)
	save(string(string(setDir,"Creation/Fermionic/"),"cr_",string(i),"_N",string(N),"_Np",string(Np),".jld"),"creation",cr)
end

#=
function loadFermionicFT()
end

function saveFermionicFT()
end
=#

max_stars_repo_name: Gawatz/exactQmodule

max_issues_repo_name: Gawatz/exactQmodule

max_forks_repo_name: Gawatz/exactQmodule


text:
@testset "to_vec" begin
    @testset "Composite{Tuple}" begin
        @testset "basic" begin
            x_tup = (1.0, 2.0, 3.0)
            x_comp = Composite{typeof(x_tup)}(x_tup...)

            x_vec, from_vec = ChainRulesTestUtils.to_vec(x_comp)
            @test x_vec == collect(x_tup)
            x_regen = from_vec(x_vec)

            @test x_comp == x_regen
        end

        @testset "nested" begin
            x_inner = (2, 3)
            x_outer = (1, x_inner)
            x_comp = Composite{typeof(x_outer)}(1, Composite{typeof(x_inner)}(2, 3))

            x_vec, from_vec = ChainRulesTestUtils.to_vec(x_comp)
            x_regen = from_vec(x_vec)

            @test x_comp == x_regen
        end
    end
end