text:
"""
cube!(; args...)

add cubes faces to plot.

a1       :: size of each side

a2       :: position of each side

cxyz     :: cube position center

cmap     :: colormap

topF     :: top side of cube

bottomF  :: bottom side of cube

frontF   :: front side of cube

backF    :: back side of cube

leftF    :: left side of cube

rightF   :: right side of cube

"""
function cube!(ax; a1 = 1, a2 = 1, timeLonLat = (40,50,20), cxyz = (0,0,0),
        cmap = :plasma, transparent = false, limits = limits,
        topF    = randn(timeLonLat[1], timeLonLat[2]),
        bottomF = randn(timeLonLat[1], timeLonLat[2]),
        frontF  = randn(timeLonLat[2], timeLonLat[3]),
        backF   = randn(timeLonLat[2], timeLonLat[3]),
        leftF   = randn(timeLonLat[1], timeLonLat[3]),
        rightF  =  randn(timeLonLat[1], timeLonLat[3])) # highLimit=0, lowLimit=1

    highLimit = maximum(maximum.(x->isnan(x) ? -Inf : x, (topF, bottomF, frontF, backF, leftF, rightF)))
    lowLimit =  minimum(minimum.(x->isnan(x) ?  Inf : x, (topF, bottomF, frontF, backF, leftF, rightF)))

    x = LinRange(-a1, a1, size(topF)[1])
    y = LinRange(-a1, a1, size(topF)[2])
    z = LinRange(-a1, a1, size(leftF)[2])

    bsurf = heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], backF, transformation=(:yz, -a2 + cxyz[1]),
    colormap = cmap, transparency = transparent, limits = limits, colorrange = (lowLimit, highLimit)) # back, limits = FRect((-1,-1,-1), (2,2,2))
    heatmap!(ax, x .+ cxyz[1], z .+ cxyz[3], leftF, transformation=(:xz, -a2 + cxyz[2]),
        colormap = cmap, transparency = transparent, colorrange = (lowLimit, highLimit)) # left
    heatmap!(ax, x .+ cxyz[1], y .+ cxyz[2], bottomF, transformation=(:xy, -a2 + cxyz[3]),
        colormap = cmap, transparency = transparent, colorrange = (lowLimit, highLimit)) # bottom
    heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], frontF, transformation=(:yz,  a2 + cxyz[1]),
        colormap = cmap, transparency = transparent, colorrange = (lowLimit, highLimit)) # front
    heatmap!(ax, x .+ cxyz[1], z .+ cxyz[3], rightF, transformation=(:xz,  a2 + cxyz[2]),
        colormap = cmap, transparency = transparent, colorrange = (lowLimit, highLimit)) # right
    heatmap!(ax, x .+ cxyz[1], y .+ cxyz[2], topF, transformation = (:xy,  a2 + cxyz[3]),
        colormap = cmap, transparency = transparent, colorrange = (lowLimit, highLimit)) # top
    bsurf
end

"""
plotcube(; args...)

a1       ::  size of each side

a2       :: position of each side

cxyz     :: cube position center

cmap     :: colormap

topF     :: top side of cube

bottomF  :: bottom side of cube

frontF   :: front side of cube

backF    :: back side of cube

leftF    :: left side of cube

rightF   :: right side of cube

lonrange :: longitude range for ticks

latrange :: longitude range for ticks

timeStamps :: time ticks to be considered

"""
function plotcube(;a1 = 1, a2 = 1, timeLonLat = (40,50,20), cxyz = (0,0,0),
        cmap = :Spectral_11, transparent = false, limits = Rect(Vec3f0(-1), Vec3f0(2)),
        topF    = randn(timeLonLat[1], timeLonLat[2]),
        bottomF = randn(timeLonLat[1], timeLonLat[2]),
        frontF  = randn(timeLonLat[2], timeLonLat[3]),
        backF   = randn(timeLonLat[2], timeLonLat[3]),
        leftF   = randn(timeLonLat[1], timeLonLat[3]),
        rightF  =  randn(timeLonLat[1], timeLonLat[3]),
        lonrange= (-20,10), latrange = (-25,15),
        timeStamps = ["Jan", "Feb", "Mar", "Apr", "May"], label = "label")

    fig = Figure(resolution = (650, 500))

    ax = LScene(fig, scenekw = (camera = cam3d!, show_axis = true))

    cbox = cube!(ax; a1 = a1, a2 = a2, timeLonLat = timeLonLat, cxyz = cxyz,
        limits = limits, cmap = cmap, transparent = transparent,
        topF = topF, bottomF=bottomF, frontF=frontF, backF =backF,
        leftF= leftF, rightF=rightF )

    cbar  = Colorbar(fig, cbox,  label = label,
        width = 11, height = Relative(2/4), tickalign = 1, ticklabelsize = 12, labelsize = 12,)

    dlon = (lonrange[2] - lonrange[1])
    dlat = (latrange[2] - latrange[1])
    δdlon = round(dlon/4, digits = 2)
    δdlat = round(dlat/4, digits = 2)

    yticks!(ax.scene; ytickrange = -1:0.5:1,
            yticklabels=["$(lonrange[1] + 0.0)", "$(lonrange[1] + δdlon)",
                "$(lonrange[1] + 2*δdlon) ", "$(lonrange[1] + 3*δdlon)", "$(lonrange[2] + 0.0)"])
    zticks!(ax.scene; ztickrange = -1:0.5:1,
            zticklabels=["$(latrange[1] + 0.0)", "$(latrange[1] + δdlat)",
                "$(latrange[1] + 2*δdlat) ", "$(latrange[1] + 3*δdlat)", "$(latrange[2] + 0.0)"])

    xticks!(ax.scene; xtickrange = -1:0.5:1, xticklabels= timeStamps)

    axis = ax.scene[OldAxis]
    axis[:names, :axisnames] = ("time", "lon", "lat")
    axis[:ticks][:textcolor] = :black
    axis[:names][:textcolor] = (:black, :black, :black)
    #limits[] = Rect(Vec3f0(-2,-2,-2), Vec3f0(4.5))
    fig[1, 1] = ax
    fig[1, 2] = cbar
    fig
end

"""
plotSlides(dataSlides, lonrange, latrange; a1 = 1, a2 = 0, cxyz = (0,0,0), cmap = :Spectral_11,
        figsize = (840,800), transparency = true, rmvalue = -9999, iswater = (true, (:dodgerblue, 0.35), -1, 0),
        cbar = false, leg = "legend", inidate = " ", findate = " ")
"""
function plotSlides(dataSlides, lonrange, latrange; a1 = 1, a2 = 0, cxyz = (0,0,0), cmap = :Spectral_11,
        figsize = (840,800), transparency = true, rmvalue = -9999, iswater = (true, (:dodgerblue, 0.35), -1, 0),
        cbar = false, leg = "legend", inidate = " ", findate = " ")
    nxyz = size(dataSlides)
    allSlides = replace(dataSlides, rmvalue => NaN)
    highLimit = maximum(maximum.(x->isnan(x) ? -Inf : x, allSlides))
    lowLimit =  minimum(minimum.(x->isnan(x) ?  Inf : x, allSlides))
    clims = (lowLimit, highLimit)

    y = LinRange(-a1, a1, nxyz[1])
    z = LinRange(-a1, a1, nxyz[2])
    fig = Figure(resolution = figsize)
    #ax = Axis3(fig, aspect = :data, viewmode= viewmode,perspectiveness = 0.5, title = title)
    ax = LScene(fig, scenekw = (camera = cam3d!, show_axis = true))
    scatter!(ax, [Point3f0(0), Point3f0(1)], markersize = 0, limits =  Rect(Vec3f0(-1.1), Vec3f0(2))) # due to ticks issue !
    for (indx,i) in enumerate(LinRange(a1, -a1, nxyz[3]))
        pltobj = heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], allSlides[:,:,indx],
            #limits =  Rect(Vec3f0(-1), Vec3f0(2)), # put them in terms of a1 and  cxyz
            transformation=(:yz, -a2 - i + cxyz[1]), colormap = cmap, transparency = transparency,
            colorrange = clims)
        if iswater[1] == true
            heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], dataSlides[:,:,indx],
                transformation=(:yz, -a2 - i + cxyz[1]), colorrange = (iswater[3],iswater[4]),
                lowclip = iswater[2], highclip = :transparent, transparency = transparency,)
        end
    end
    axis = ax.scene[OldAxis]
    axis[:ticks][:textcolor] = (:transparent, :black, :black)
    axis[:names][:axisnames] = ("", "lon", "lat")
    axis[:names][:rotation] = (qrotation(Vec3(0,0,1), π),
                              qrotation(Vec3(0,0,1), π/2),
                              qrotation(Vec3(0,0,1), -π/2) * qrotation(Vec3(0,1,0), -π/2))
    axis[:names][:align] = ((:center, :right), (:center, :right), (:center, :left))

    dlon = (lonrange[2] - lonrange[1])
    dlat = (latrange[2] - latrange[1])
    δdlon = round(dlon/4, digits = 2)
    δdlat = round(dlat/4, digits = 2)

    yticks!(ax.scene; ytickrange = -1:0.5:1,
        yticklabels=["$(lonrange[1] + 0.0)", "$(lonrange[1] + δdlon)",
            "$(lonrange[1] + 2*δdlon) ", "$(lonrange[1] + 3*δdlon)", "$(lonrange[2] + 0.0)"])
    zticks!(ax.scene; ztickrange = -1:0.5:1,
        zticklabels=["$(latrange[1] + 0.0)", "$(latrange[1] + δdlat)",
            "$(latrange[1] + 2*δdlat) ", "$(latrange[1] + 3*δdlat)", "$(latrange[2] + 0.0)"])

    #ax.limits[] = Rect(Vec3f0(-1), Vec3f0(2))
    text!(inidate, position = Point3f0(-1, -1, 1.2),
    color = :black,
    #rotation = 2π +π/10,
    align = (:center, :center),
    textsize = 20,
    #space = :data
    )
    text!(findate, position = Point3f0(1, -1, 1.2),
    color = :red,
    #rotation = 2π +π/10,
    align = (:center, :center),
    textsize = 20,
    #space = :data
    )

    fig[1,1] = ax
    #fig[0,1] = Label(fig, title, textsize = 20, color = (:black, 0.85))
    if cbar == true
        cbar = Colorbar(fig, limits = clims, nsteps = 100, colormap = cmap,
        label = leg, width = 11, height = Relative(2/4), tickalign = 1)
        fig[1,2] = cbar
    end
    fig
end

"""
recordSlides(dataSlides, tstamps, lonrange, latrange; filename = "temp.mp4", framerate = 24,
        a1 = 1, a2 = 0, cxyz = (0,0,0), cmap = :Spectral_11, figsize = (900,900), transparency = true,
        iswater = (true, (:dodgerblue, 0.35), -1, 0), cbar = false, leg = "legend")
"""
function recordSlides(dataSlides, tstamps, lonrange, latrange; filename = "temp.mp4", framerate = 24,
        a1 = 1, a2 = 0, cxyz = (0,0,0), cmap = :Spectral_11, figsize = (900,900), transparency = true,
        iswater = (true, (:dodgerblue, 0.35), -1, 0), cbar = false, leg = "legend")
    inidate = "$(Date(tstamps[1]))"
    #findate = Node(" ")
    nxyz = size(dataSlides)
    allSlides = replace(dataSlides, -9999 => NaN)
    highLimit = maximum(maximum.(x->isnan(x) ? -Inf : x, allSlides))
    lowLimit =  minimum(minimum.(x->isnan(x) ?  Inf : x, allSlides))
    clims = (lowLimit, highLimit)

    y = LinRange(-a1, a1, nxyz[1])
    z = LinRange(-a1, a1, nxyz[2])
    fig = Figure(resolution = figsize)
    #ax = Axis3(fig, aspect = :data, title = "hola")
    ax = LScene(fig, scenekw = (camera = cam3d!, show_axis = true))
    scatter!(ax, [Point3f0(0), Point3f0(1)], markersize = 0, limits =  Rect(Vec3f0(-1.1), Vec3f0(2))) # due to ticks issue !
    axis = ax.scene[OldAxis]
    axis[:ticks][:textcolor] = (:transparent, :black, :black)
    axis[:names][:axisnames] = ("", "lon", "lat")
    axis[:names][:rotation] = (qrotation(Vec3(0,0,1), π),
                              qrotation(Vec3(0,0,1), π/2),
                              qrotation(Vec3(0,0,1), -π/2) * qrotation(Vec3(0,1,0), -π/2))
    axis[:names][:align] = ((:center, :right), (:center, :right), (:center, :left))

    dlon = (lonrange[2] - lonrange[1])
    dlat = (latrange[2] - latrange[1])
    δdlon = round(dlon/4, digits = 2)
    δdlat = round(dlat/4, digits = 2)

    yticks!(ax.scene; ytickrange = -1:0.5:1,
        yticklabels=["$(lonrange[1] + 0.0)", "$(lonrange[1] + δdlon)",
            "$(lonrange[1] + 2*δdlon) ", "$(lonrange[1] + 3*δdlon)", "$(lonrange[2] + 0.0)"])
    zticks!(ax.scene; ztickrange = -1:0.5:1,
        zticklabels=["$(latrange[1] + 0.0)", "$(latrange[1] + δdlat)",
            "$(latrange[1] + 2*δdlat) ", "$(latrange[1] + 3*δdlat)", "$(latrange[2] + 0.0)"])

    if cbar == true
        cbar = Colorbar(fig, limits = clims, nsteps = 100, colormap = cmap,
        label = leg, width = 11, height = Relative(2/4), tickalign = 1)
        fig[1,2] = cbar
    end
    text!(inidate, position = Point3f0(-1, -1, 1.2),
    color = :black,
    #rotation = 2π +π/10,
    align = (:center, :center),
    textsize = 20,
    #space = :data
    )
    #Label(fig[1, 1, Bottom()], findate, color = :red, padding = (5, 0, 0, 0))
    #Label(fig[1, 1, Right()], inidate, rotation = pi/2, padding = (0, 0, 0, 0))
    record(fig, filename, framerate=framerate) do io
        for (indx,i) in enumerate(LinRange(a1, -a1, nxyz[3]))
            heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], allSlides[:,:,indx],
                #limits =  Rect(Vec3f0(-1), Vec3f0(2)), # put them in terms of a1 and  cxyz
                transformation=(:yz, -a2 - i + cxyz[1]), colormap = cmap, transparency = transparency,
                colorrange = clims)
            if iswater[1] == true
                heatmap!(ax, y .+ cxyz[2], z .+ cxyz[3], dataSlides[:,:,indx],
                    transformation=(:yz, -a2 - i + cxyz[1]), colorrange = (iswater[3],iswater[4]),
                    lowclip = iswater[2], highclip = :transparent, transparency = transparency,)
            end

            txtobj = text!("$(Date(tstamps[indx]))", position = Point3f0(1, -1, 1.2), # Point3f0(-a2 - i, -1, 1.2),
                color = :red,
                #rotation = 2π +π/10,
                align = (:center, :center),
                textsize = 20,
                #space = :data
                )
            fig[1,1] = ax
            #findate[] = "$(Date(tstamps[indx]))"
            #fig[0,1] = Label(fig, "$(Date(tstamps[indx]))", textsize = 20, color = (:white, 0.85))
            recordframe!(io)
            if indx < nxyz[3]
                delete!(ax, txtobj) # horrible hack !
            end
        end
        #ax.limits[] = Rect(Vec3f0(-1), Vec3f0(2))
    end
end


text:
include("wikipedia_corpus.jl")
include("kmeans.jl")
using Kmeans
using PyPlot

# For k = 2
centroids, labels, j_hist = Kmeans.kmeans(article_histograms, 2)
plot(j_hist)
centroids, labels, j_hist_2 = Kmeans.kmeans(article_histograms, 2)
plot(j_hist_2)
println(article_titles[labels .== 1])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[1],rev=true)][1:3]
println(top_3)
println("===========================")
println(article_titles[labels .== 2])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[2],rev=true)][1:3]
println(top_3)

# For k = 5
centroids, labels, j_hist = Kmeans.kmeans(article_histograms, 5)
centroids, labels, j_hist_2 = Kmeans.kmeans(article_histograms, 5)
plot(j_hist)
plot(j_hist_2)
println(article_titles[labels .== 1])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[1],rev=true)][1:3]
println(top_3)
println("===========================")
println(article_titles[labels .== 2])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[2],rev=true)][1:3]
println(top_3)
println("===========================")
println(article_titles[labels .== 3])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[3],rev=true)][1:3]
println(top_3)
println("===========================")
println(article_titles[labels .== 4])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[4],rev=true)][1:3]
println(top_3)
println("===========================")
println(article_titles[labels .== 5])
println("===========================")
println("Top 3 words")
top_3 = dictionary[sortperm(centroids[5],rev=true)][1:3]
println(top_3)

# For k = 10
centroids, labels, j_hist = Kmeans.kmeans(article_histograms, 10)
centroids, labels, j_hist_2 = Kmeans.kmeans(article_histograms, 10)
println(article_titles[labels .== 1])
println("===========================")
println(article_titles[labels .== 2])
println("===========================")
println(article_titles[labels .== 3])
println("===========================")
println(article_titles[labels .== 4])
println("===========================")
println(article_titles[labels .== 5])
println("===========================")
println(article_titles[labels .== 6])
println("===========================")
println(article_titles[labels .== 7])
println("===========================")
println(article_titles[labels .== 8])
println("===========================")
println(article_titles[labels .== 9])
println("===========================")
println(article_titles[labels .== 10])
plot(j_hist)
plot(j_hist_2)

#=
4.2 a)
 In each iteration (X-Axis), the value of j(Y-Axis) keep decreasing, it each iteration it keeps getting better
unless the difference between each iteration does not change. The fact that j keeps decreasing denotes that
KMeans is converging in a finite number of steps.

Based on different number of runs, the graph can vary as the initial centroid is chosen randomly and might
take different number for convergence
=#

#=
4.2 b)
For k=2, the grouping is under clustered, as one may find articles from multiple topic under one cluter.
For example:
In above run for k = 2, `World Trade Organization`, `Digital signal` and `Monsoon are classified under one
single category which could be further classified to achieve a much granular cluster.

k=5 is perfectly clustered, upon inspection it is clear that article are classified into following categories
i) Organistaion and Unions
ii) Arts and Painting
iii) Weather and tools related to weather
iv) Signals
v) Pokemon

Therefore, k = 5 is the perfect for clustering the given set of articles. It can be also verified that corpus
was picked from set of 5 articles hence clustering into group of 5 is perfect.

k=10 is the case of over clustering/categorization, topics such as Pokemon (in k = 5) is further broken down
into multiple groups. This is not the most optimal solution.

Based on the observation of above data, it is clear that k = 5.
=#

ext: jl


text:
#=
GradientDescent.jl

    Provides gradient descent methods, such as Newton and quasi-Newton methods,
    for differentiable objective functions.

@author: Quint Wiersma <q.wiersma@vu.nl>

@date: 2022/01/24
=#

module GradientDescent

using LinearAlgebra, LineSearch

export
    # Structs
    BFGSState,
    LBFGS, LBFGSState,
    # BFGS
    bfgs!,
    lbfgs!

# Include programs
include("bfgs.jl")
include("lbfgs.jl")

end


text:
#=== Cube ===#

struct Cube{P} <: AbstractCell
    origin::AbstractVector{P}
    extent::AbstractVector{P}
    function Cube(o::AbstractVector{P}, x::AbstractVector{P}) where{P}
        @assert length(x) <= length(o) "Too many extent elements"
        new{P}(o, x)
    end
end
Cube(x::AbstractVector{P}) where {P} = Cube(zeros(P, length(x)), x)
Cube(::Type{P}) where {P} = Cube(P[], P[])
show(io::IO, c::Cube) = show(io, "Cube[$(c.origin) + $(c.extent)]")

# Public methods

dim(c::Cube) = length(findall(!iszero, c.origin - c.extent))

==(a::Cube, b::Cube) = hash(a) == hash(b)

hash(c::Cube) = hash(vcat(c.origin, c.extent))

function faces(c::Cube{P}, ε=zero(P)) where {P}
    d = dim(c)
    d == 0 && return Cube[]
    kₙ = findall(!iszero, c.origin - c.extent) # on-degenerate intervals
    (Cube(copy(c.origin), [i == j ? ε : c.extent[j] for j in 1:length(c.origin)]) for i in kₙ)
end

function boundary(::Type{R}, c::Cube) where {R}
    d = dim(c)
    ch = Chain(d-1, R)
    d == 0 && return ch
    o = one(R)
    for (i,(λ⁰, λ¹)) in enumerate(zip(faces(c,zero(R)), faces(c, one(R))))
        # println("λ⁰:", λ⁰," λ¹:", λ¹)
        push!(ch, hash(λ⁰)=>( isodd(i) ? -o : o))
        push!(ch, hash(λ¹)=>( isodd(i) ? o : -o))
    end
    return simplify(ch)
end

# Misc. methods

function volume(c::Cube)
    sizes = similar(c.origin,0)
    for (i,ex) in enumerate(c.extent)
        if ex != 0.
            expoint = copy(c.origin)
            expoint[i] += ex
            l = norm(expoint - c.origin)
            push!(sizes, l)
        end
    end
    return prod(sizes)
end


text:
"""
some utilities for managing memory
"""
module MemoryUtils
using ..CUDAGpuUtils, CUDA
export clearSharedMemWarpLong
"""
In case we have 32 length shared memory we can clear it using given warps
o x dim is assumed to be from 1 to 32 and ydim is supplied
"""
function clearSharedMemWarpLong(shmem, ydim::UInt8 )
@unroll for i::UInt8 in UInt8(1):UInt8(ydim)
    @ifY i shmem[threadIdxX(),i]=UInt32(0)
end#for
sync_threads()
end#clearSharedMemWarpLong

function clearSharedMemWarpLong(shmem, ydim::UInt8 , value)
    @unroll for i::UInt8 in UInt8(1):UInt8(ydim)
        @ifY i shmem[threadIdxX(),i]=value
    end#for
    sync_threads()
    end#clearSharedMemWarpLong

end#MemoryUtils


text:
module CUDA

using ..CuArrays

CuArrays.libcudnn != nothing && include("cudnn.jl")

end


text:
"""
    marchonintime(W0,Z,B,I)

Solve by marching-on-in-time the causal convolution problem defined by `(W0,Z,B)`
up to timestep `I`. Here, `Z` is an array of order 3 that contains a discretisation
of a time translation invariant retarded potential operator. `W0` is the inverse of
the slice `Z[:,:,1]`.
"""
function marchonintime(W0,Z,B,I)
    T = eltype(W0)
    M,N = size(Z)
    @assert M == size(B,1)
    x = zeros(T,N,I)
    for i in 1:I
        b = B[:,i] - convolve(Z,x,i,2)
        x[:,i] += W0 * b
        (i % 10 == 0) && print(i, "[", I, "] - ")
    end
    return x
end

using BlockArrays

function convolve(Z::BlockArray, x, i, j_start)
    cs = BlockArrays.cumulsizes(Z)
    bs = [blocksize(Z, (i,1))[1] for i in 1:nblocks(Z,1)]
    # @show bs
    T = eltype(eltype(Z))
    y = PseudoBlockVector{T}(undef,bs)
    fill!(y,0)
    for I in 1:nblocks(Z,1)
        # xI = view(x, cs[1][I] : cs[1][I+1]-1, :)
        for J in 1:nblocks(Z,2)
            xJ = view(x, cs[2][J] : cs[2][J+1]-1, :)
            isassigned(Z.blocks, I, J) || continue
            ZIJ = Z[Block(I,J)].banded
            # @show size(xJ) size(ZIJ)
            # @show size(y[Block(I)])
            y[Block(I)] .+= convolve(ZIJ, xJ, i, j_start)
        end
    end
    return y
end

function marchonintime(W0,Z::BlockArray,B,I)
    T = eltype(W0)
    M,N = size(W0)
    @assert M == size(B,1)
    x = zeros(T,N,I)
    for i in 1:I
        R = [ B[j][i] for j in 1:N ]
        S = convolve(Z,x,i,2)
        # @show size(R)
        # @show size(S)
        # b = R - convolve(Z,x,i,2)
        b = R - S
        x[:,i] += W0 * b
        (i % 10 == 0) && print(i, "[", I, "] - ")
    end
    return x
end


text:
## DEMONSTRATION OF BASIC USAGE

# Load the basic Koala toolset:
using Koala

# Load a built-in supervised learning data set:
X, y = load_ames();

# Note that `X`, which stores the input patterns, is a `DataFrame`
# object; the high-level Koala interface expects all inputs to be
# `DataFrame` objects. Columns of element type `T <: AbstractFloat`
# are treated as numerical features; all others are treated as
# categorical.

# Not in particular that a missing-type column - i.e., a column `col`
# of element type `Union{T, Missings.Missing}` - will be treated as
# categorical. In that case replace any missing values in `col` and
# substitue `purify(col)` for `col` to get the type you probably
# wanted. We can check for missing-type columns as follows:
[ismissingtype(eltype(X[j])) for j in 1:size(X, 2)]

# Or get a summary of eltype information:
showcols(X)

# In Koala, normal practice is to store training and test data in a
# single `DataFrame`, `X`, padding unknown instances of the target
# `y`, and to construct integer vectors pointing to the rows of the
# training, validation and test parts of the data:
train, valid, test = split(eachindex(y), 0.7, 0.1); # that's 70%, 10%, 20%.

# Choose a model for learning:
using KoalaTrees
tree = TreeRegressor()

# Here `tree` is just a `mutable struct` storing the parameters
# specifying how we should train a single tree regressor:
showall(tree)

# Construct a "machine" from the model, which wraps the model in
# transformed versions of the data:
treeM = Machine(tree, X, y, train)
treeM.Xt[1:6,:]
treeM.yt[1:6]

# Note that `Xt` and `yt represents *all* the transformed data. The
# `train` argument of `Machine` merely specifies which part of the
# data should be used to calibrate the transformations which, to
# safeguard against data leakage, should not include validation or
# test data. If we want to change the way we would like data to be
# transformed, then we must build a new machine:
ty = treeM.transformer_y
showall(ty)
ty.standardize = true
treeM = Machine(tree, X, y, train, transformer_y=ty, verbosity=2)
treeM.yt[1:6,:]

# Now yt[train] will have zero mean and unit variance, but notice
# that the full `yt` vector has slightly different statistics:
mean(treeM.yt), std(treeM.yt)

# Now we train the machine, specifying the training rows:
fit!(treeM, train)

# And report the error on the validation rows:
err(treeM, valid)

# Note that target predictions are automatically *inverse transformed*
# and compared with the untransformed validation data to report the
# error we actually want.

# If we call `showall` on our machine, we see a summary of its
# internals and also a ranking of feature importance, according to the
# training we just performed.
showall(treeM)

# If we want to retrain on the *same* data, with a modified model
# parameter, then their is no need to respecify the rows:
tree.regularization = 0.5
fit!(treeM)
err(treeM, valid)

# To retrain using *different* data:
fit!(treeM, vcat(train, valid))
err(treeM, test)

# Let's tune the regularization parameter. We will use Koala's
# `@curve` macro:
r_vals, errs = @curve r linspace(0,0.99,101) begin
    tree.regularization = r
    fit!(treeM, train)
    err(treeM, valid)
end;

# Here `linspace(0,0.99,101)` specifies the range of values for the
# variable `r`. Plotting the results:
using UnicodePlots
lineplot(r_vals, errs)

# The optimal regularization is given by
r = r_vals[indmin(errs)]

# Here's how to obtain cross-validation errors (parallelized by default):
fulltrain = vcat(train, valid);
cv(treeM, fulltrain)

# If computation is slow, it occassionally help to report errors for
# the *transformed* target instead:
cv(treeM, fulltrain, raw=true, n_folds=6)

# We'll now fine-tune using cross-validation:
r_vals, errs = @curve r linspace(0.8,0.99,51) begin
    tree.regularization = r
    mean(cv(treeM, fulltrain, verbosity=0))
end;

# And report final estimate for the error:
tree.regularization = r_vals[indmin(errs)]
errs = cv(treeM, fulltrain, n_folds=12)
println("95% confidence interval for error = ", mean(errs), " ± ", 2*std(errs))

# And the test error is:
err(treeM, test)

## ENSEMBLE MODELS

# Build an ensemble of `RegressorTree` models, :
using KoalaEnsembles
forest = EnsembleRegressor(atom=tree)
showall(forest)

# If we tweak `tree` parameters, these are reflected in the forest:
tree.regularization = 0
tree.max_features = 4
showall(forest.atom)

# Let's wrap the model in appropriately transformed data:
forestM = Machine(forest, X, y, train)

# A model with `n` as a parameter indicates it is iterative in some
# sense. Here `forest.n` is the number of models in the
# ensemble. Koala's built in function `learning_curve` can be used to
# determine the size of `n`.
n_vals, errs = learning_curve(forestM, train, valid, 20:10:400)
lineplot(n_vals, errs)

# So the following is reasonable:
forest.n = 250

# Commonly in ensemble methods, predictions are the means of the
# predictions of each regressor in the ensemble. Here predictions are
# *weighted* sums and the weights are optimized to minimize the RMS
# training error. Since this sometimes leads to "under-regularized"
# models the training error is further penalized with a term measuring
# the deviation of the weights from uniformity. Set the parameter
# `forest.weight_regularization=1` (the default and maximum permitted
# value) and weights are completely uniform. Set
# `forest.weight_regularization=0` and the training error penalty is
# dropped altogether.

fit!(forestM, train)
forestM.report[:normalized_weights] |> showall

# To refit the weights with a new regularization penalty, but without
# changing the ensemble itself, use ``fit_weights``:

forest.weight_regularization = 0.5
fit_weights!(forestM)
forestM.report[:normalized_weights] |> showall

# Tuning the parameter `forest.weight_regularization` may be done
# with the help of the `weight_regularization_curve` function:

reg_vals, errs = weight_regularization_curve(forestM, test; range = linspace(0,1,51));
lineplot(reg_vals, errs)

# In this case maximum regulariation is indicated:
reg_vals[indmin(errs)]


text:
# represents transfers from a stop

struct Transfer
    target_stop::Int64
    distance_meters::Float64
end


text:
# -*- coding: utf-8 -*-
# # Typegraphs: teaching the compiler to reason about models
#
# In this notebook, we will be going through a tutorial on how to use the `typegraph` functionality to extract the relationships between types and functions within programs.

using SemanticModels
using SemanticModels.Parsers
using SemanticModels.ModelTools
import SemanticModels.ModelTools: CallArg, RetArg, Edge, Edges, @typegraph, typegraph

# After loading `@typegraph` in to our workspace, we simply begin the extraction by calling the macro immediately followed by an `Expr` which will return an edge list which is easily passed through to `MetaGraphs.jl` to visualize the transformations that are taking place throughout the code.
#
# *_To learn more about `Expr` & metaprogramming, we recommend looking at the offcial [Julia docs](@https://docs.julialang.org/en/v1.0/manual/metaprogramming/) on the topic._

# +
using SemanticModels.Parsers
import Base: ==

shorttype(T::Type) = T.name.name
# -

# Below we are using our `parsefile` function to take scripts and wrap them around in `module` headings that way they can be consumed by our other API's. We then pass off our `Expr`s to our `typegraph` function which collects all the type information we would like extracted from the code.
#
# You can see the code that is being loaded here at [agentbased2.jl](github.com/jpfairbanks/SemanticModels.jl/blob/master/examples/agentbased2.jl)

expr = parsefile("agentbased2.jl")
expr2 = ModelTools.typegraph(expr.args[end])
expr3 = :(module Foo
    using SemanticModels.ModelTools
    import SemanticModels.ModelTools: CallArg, RetArg
    $(expr2.args...) end);

# In the above example, we have a simple agent based simulation where we defined new stucts to collect the singltonian type information for our simulation. To reduce the nosie from collecting the iterations throughout the runtime of our model we need to collect the unique calls through our our example which contain the relevant information.

# +
Mod = eval(expr3)
Mod.main(10)
edgelist_symbol = Mod.edgelist

E = unique((f.func, f.args, f.ret) for f in Edges(edgelist_symbol))
E = unique(("\"$(f.func)\"", tuple(shorttype.(f.args)...), shorttype.(f.ret)) for f in Edges(edgelist_symbol))
@show E
# -

# We are going to repeat the process again for another similar script to see if we are able to detect the differences between the two programs.
#
# You can see the code that is being loaded here at [agenttypes.jl](github.com/jpfairbanks/SemanticModels.jl/blob/master/examples/agenttypes.jl)

expr = parsefile("agenttypes.jl")
expr2 = ModelTools.typegraph(expr.args[end].args[end].args[end])
expr3 = :(module ModTyped
    using SemanticModels.ModelTools
    import SemanticModels.ModelTools: CallArg, RetArg
    $(expr2.args...) end);

# +
Mod = eval(expr3)
Mod.main(10)
edgelist_typed = Mod.edgelist

E_typed = unique(("\"$(f.func)\"", tuple(shorttype.(f.args)...), shorttype.(f.ret)) for f in Edges(edgelist_typed))
# -

println("=============\nSymbols Graph\n============")
for e in E
    println(join(e, ", "))
end
println("\n=============\nTypes Graph\n============")
for e in E_typed
    println(join(e, ", "))
end

# ## Visualizing the edges
#
# Now that we have extracted the relevant type information, we want to visualize these transformations in a knowledge graph.

using MetaGraphs;
using LightGraphs;
# patch for https://github.com/JuliaGraphs/MetaGraphs.jl/pull/71/files
function escapehtml(i::AbstractString)
    # Refer to http://stackoverflow.com/a/7382028/3822752 for spec. links
    replace=Main.replace
    o = replace(i, "&" =>"&")
    o = replace(o, "\""=>""")
    o = replace(o, "'" =>"'")
    o = replace(o, "<" =>"<")
    o = replace(o, ">" =>">")
    return o
end

# +
function buildgraph(E)
    g = MetaDiGraph();
    set_indexing_prop!(g,:label);

    for e in E
        try
            g[e[2],:label]
        catch
            add_vertex!(g,:label,e[2]) # add ags
        end

        try
            g[e[3],:label]
        catch
            add_vertex!(g,:label,e[3]) # add rets
        end

        try
            add_edge!(g,g[e[2],:label],g[e[3],:label],:label,e[1])#escapehtml(string(e[1]))) # add func edges
        catch
            nothing
        end
    end
    return g
end

function projectors(g, key=:label)
    newedges = []
for v in vertices(g)
    args = g.vprops[v][key]
    if isa(args, Tuple)
        for (i, a) in enumerate(args)
            push!(newedges, ("π$i", a, args))
        end
    end
    end
        return newedges
end

function add_projectors!(g, key=:label)
    πs = projectors(g)
    for e in πs
        add_edge!(g,g[e[2],:label],g[e[3],:label],:label,e[1])
    end
    return g, πs
end
# -

function draw(g, filename)
    savegraph(filename, g, DOTFormat())
    try
        run(`dot -Tsvg -O $filename`)
    catch ex
        @warn "Problem running dot" error=ex
        try
            run(`dot --version`)
        catch
            @warn "Dot is not installed"
        end
    end
    display("image/svg+xml", read("$filename.svg", String))
end

g = buildgraph(E)
add_projectors!(g)

h = deepcopy(g)
g = buildgraph(E_typed)
g, πs = add_projectors!(g);
g

using Colors
cm = Colors.colormap("RdBu", 2nv(h))
color(v) = "#$(hex(cm[v + floor(Int, nv(h)/2)]))"

# We will draw the graph of types in initial model that uses symbols to represent the agent states. Remember that Symbol is type that represents "things that are like variable names" and in this case we are using the Symbol type to represent the agent states of :Susceptible, :Infected, and :Recovered.
#
# In this drawing each vertex has its own color. These colors will be used again when drawing the next graph.

for v in vertices(h)
    h.vprops[v][:color] = color(v)
    h.vprops[v][:style] = "filled"
end
draw(h, "exampletypegraph.dot")

# We then onstruct the typegraph for the program 2, which uses singleton types to represent the state of the agents. One of the central tennants of this project is that the more information you inject into the julia type system, the more the compiler can help you. Here we will see that they type system knows about the structure of the agents behavior now that the we have encoded their states as types.

# now we draw the new, bigger type graph with the same color scheme as before. We define a graph homomorphism $\phi$ that maps every type to one of the vertices of the original graph show above. This homomorphism from $\phi: G \mapsto H$ shows how the semantics of the first program is embedded in the semantics of the second program.

# +
ϕ(t) = begin
    d=Dict{Symbol,Symbol}(:Susceptible=>:Symbol,
        :Infected=>:Symbol,
        :Recovered=>:Symbol,
    )
    val = get(d, t, t)
    return val
end

for v in vertices(g)
    vname = ϕ.(g[v,:label])
    try
        vh = h[vname, :label]
        g.vprops[v][:fillcolor]=color(vh)
        g.vprops[v][:style]="filled"
    catch ex
        @warn ex
    end
end

# -

draw(g, "typegraphmorphism.dot")

# Note that the type Symbol does not appear in the second program at all, but instead the types Susceptible, Infected, and Recovered play the role of the Symbol vertex in this new graph. The graph is bigger and harder to visualize, but it contains the same structure. You can chack that for every edge in the $g$ there is an edge in $h$ that has the same color vertices as endpoints.
#
# In this new model the structure of the agents states is readily apparant in the type system.

tedges = filter((p) -> p[2][:label]=="\"transition\"", g.eprops)
tv = src.(keys(tedges)) ∪ dst.(keys(tedges))
DFA = g[tv]
draw(DFA, "type_DFA.dot")

# By contracting the edges labeled $\pi_3$ you identify a minor of
# the typegraph isomorphic to the discrete finite automata or
# finite state machine representation of the agents in our agent based simulation.
#
#
# Since the typegraph contains this information, we can say that the julia compiler "understands"
# a semantic feature of the model. We can introduce compile time logic based on these properties of
# the model. ANy changes to the underlying code that changed the state space of the agents, or the
# possible transitions they undergo would affect the type graph of the model.
#
# For the model version that used :Symbols, or categorical states, the julia type system is blissfully
# ignorant of the relationships between the states. However once we introduce types to the model, the
# compiler is able to represent the structure of the model. Any changes to the model will either preserve
# or disrupt this type graph and we will be able to identify and quantify that change to the structure of the model.
#
# This example is an instance of a large phenomenon that we hope to advance in modeling.
# Programs that implement models can get more out of the compiler if they add more information.
# In this case we declared the states of our agents as types and the compiler was able to infer
# the state transition graph from the our code.

# ## Conclusions
#
# We can see from the examples presented here that similar models produce similar type graphs. In this case we have two programs that impement the same model and have homomorphic type graphs. This homomorphism is natural in the sense that every vertex that appears in both graphs satisfies $\phi(v) = v$. Adding information to the type system in the julia program allows the type graph of the model to understand more of the program semantics. This powerful insight can teach the machines to reason about the behaviour of computational models.


text:
int_rules_4_3_2_1 = @theory begin

    #= ::Subsection::Closed:: =#
    #= 4.3.2.1*(a+b*tan)^m*(c+d*tan)^n =#
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~(m') * (~c + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~(n'), ~x) => (~a) ^ ~m * (~c) ^ ~m * Antiderivative(sec(~e + ~f * ~x) ^ (2 * ~m) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - ~m), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (EqQ(~b * ~c + ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (IntegerQ(~m) && Not(IGtQ(~n, 0) && (LtQ(~m, 0) || GtQ(~m, ~n))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~c + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~a * ~c) / ~f) * Subst(Antiderivative((~a + ~b * ~x) ^ (~m - 1) * (~c + ~d * ~x) ^ (~n - 1), ~x), ~x, tan(~e + ~f * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (EqQ(~b * ~c + ~a * ~d, 0) && EqQ((~a) ^ 2 + (~b) ^ 2, 0))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) * (~c + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (~a * ~c - ~b * ~d) * ~x + (~b * ~d * tan(~e + ~f * ~x)) / ~f <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && EqQ(~b * ~c + ~a * ~d, 0))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (~a * ~c - ~b * ~d) * ~x + (~b * ~d * tan(~e + ~f * ~x)) / ~f + (~b * ~c + ~a * ~d) * Antiderivative(tan(~e + ~f * ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && NeQ(~b * ~c + ~a * ~d, 0))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (-((~b * ~c - ~a * ~d)) * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m) / (2 * ~a * ~f * ~m) + ((~b * ~c + ~a * ~d) / (2 * ~a * ~b)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && LtQ(~m, 0)))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (~d * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m) / (~f * ~m) + ((~b * ~c + ~a * ~d) / ~b) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && Not(LtQ(~m, 0))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (~d * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m) / (~f * ~m) + Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 1) * Simp((~a * ~c - ~b * ~d) + (~b * ~c + ~a * ~d) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && GtQ(~m, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((~b * ~c - ~a * ~d) * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1)) / (~f * (~m + 1) * ((~a) ^ 2 + (~b) ^ 2)) + (1 / ((~a) ^ 2 + (~b) ^ 2)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * Simp((~a * ~c + ~b * ~d) - (~b * ~c - ~a * ~d) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && LtQ(~m, -1)))
    @apply_utils Antiderivative((~c + ~(d') * tan(~(e') + ~(f') * ~x)) / (~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => (~c / (~b * ~f)) * log(RemoveContent(~a * cos(~e + ~f * ~x) + ~b * sin(~e + ~f * ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && EqQ(~a * ~c + ~b * ~d, 0)))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) / (~(a') + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => ((~a * ~c + ~b * ~d) * ~x) / ((~a) ^ 2 + (~b) ^ 2) + ((~b * ~c - ~a * ~d) / ((~a) ^ 2 + (~b) ^ 2)) * Antiderivative((~b - ~a * tan(~e + ~f * ~x)) / (~a + ~b * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ(~a * ~c + ~b * ~d, 0)))
    @apply_utils Antiderivative((~c + ~(d') * tan(~(e') + ~(f') * ~x)) / sqrt(~(b') * tan(~(e') + ~(f') * ~x)), ~x) => ((-2 * (~d) ^ 2) / ~f) * Subst(Antiderivative(1 / (2 * ~c * ~d + ~b * (~x) ^ 2), ~x), ~x, (~c - ~d * tan(~e + ~f * ~x)) / sqrt(~b * tan(~e + ~f * ~x))) <-- FreeQ([~b, ~c, ~d, ~e, ~f], ~x) && EqQ((~c) ^ 2 - (~d) ^ 2, 0)
    #= Antiderivative(((~c)+(~d')*tan((~e')+(~f')*(~x)))/sqrt((~b')*tan((~e')+(~f')*(~x))),~x) :=   (c+d)/2*Antiderivative((1+tan(e+f*x))/sqrt(b*tan(e+f*x)),x) + (c-d)/2*Antiderivative((1-tan(e+f*x))/sqrt(b*tan(e+f*x)),x) <--  FreeQ([b,c,d,e,f],x) && NeQ(c^2+d^2,0) && NeQ(c^2-d^2,0) =#
    @apply_utils Antiderivative((~c + ~(d') * tan(~(e') + ~(f') * ~x)) / sqrt(~(b') * tan(~(e') + ~(f') * ~x)), ~x) => ((2 * (~c) ^ 2) / ~f) * Subst(Antiderivative(1 / (~b * ~c - ~d * (~x) ^ 2), ~x), ~x, sqrt(~b * tan(~e + ~f * ~x))) <-- FreeQ([~b, ~c, ~d, ~e, ~f], ~x) && EqQ((~c) ^ 2 + (~d) ^ 2, 0)
    #= Antiderivative(((~c)+(~d')*tan((~e')+(~f')*(~x)))/sqrt((~b')*tan((~e')+(~f')*(~x))),~x) :=   (c+im*d)/2*Antiderivative((1-im*tan(e+f*x))/sqrt(b*tan(e+f*x)),x) +  (c-im*d)/2*Antiderivative((1+im*tan(e+f*x))/sqrt(b*tan(e+f*x)),x) <--  FreeQ([b,c,d,e,f],x) && NeQ(c^2-d^2,0) && NeQ(c^2+d^2,0) =#
    @apply_utils Antiderivative((~c + ~(d') * tan(~(e') + ~(f') * ~x)) / sqrt(~(b') * tan(~(e') + ~(f') * ~x)), ~x) => (2 / ~f) * Subst(Antiderivative((~b * ~c + ~d * (~x) ^ 2) / ((~b) ^ 2 + (~x) ^ 4), ~x), ~x, sqrt(~b * tan(~e + ~f * ~x))) <-- FreeQ([~b, ~c, ~d, ~e, ~f], ~x) && (NeQ((~c) ^ 2 - (~d) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) / sqrt(~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => ((-2 * (~d) ^ 2) / ~f) * Subst(Antiderivative(1 / ((2 * ~b * ~c * ~d - 4 * ~a * (~d) ^ 2) + (~x) ^ 2), ~x), ~x, ((~b * ~c - 2 * ~a * ~d) - ~b * ~d * tan(~e + ~f * ~x)) / sqrt(~a + ~b * tan(~e + ~f * ~x))) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && EqQ(2 * ~a * ~c * ~d - ~b * ((~c) ^ 2 - (~d) ^ 2), 0))))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) / sqrt(~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => With([q = Rt((~a) ^ 2 + (~b) ^ 2, 2)], (1 / (2q)) * Antiderivative((~a * ~c + ~b * ~d + ~c * q + ((~b * ~c - ~a * ~d) + ~d * q) * tan(~e + ~f * ~x)) / sqrt(~a + ~b * tan(~e + ~f * ~x)), ~x) - (1 / (2q)) * Antiderivative((((~a * ~c + ~b * ~d) - ~c * q) + ((~b * ~c - ~a * ~d) - ~d * q) * tan(~e + ~f * ~x)) / sqrt(~a + ~b * tan(~e + ~f * ~x)), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (NeQ(2 * ~a * ~c * ~d - ~b * ((~c) ^ 2 - (~d) ^ 2), 0) && (PerfectSquareQ((~a) ^ 2 + (~b) ^ 2) || RationalQ(~a, ~b, ~c, ~d))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~c + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((~c * ~d) / ~f) * Subst(Antiderivative((~a + (~b / ~d) * ~x) ^ ~m / ((~d) ^ 2 + ~c * ~x), ~x), ~x, ~d * tan(~e + ~f * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && EqQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~c + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ~c * Antiderivative((~b * tan(~e + ~f * ~x)) ^ ~m, ~x) + (~d / ~b) * Antiderivative((~b * tan(~e + ~f * ~x)) ^ (~m + 1), ~x) <-- FreeQ([~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && Not(IntegerQ(2 * ~m)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((~c + im * ~d) / 2) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (1 - im * tan(~e + ~f * ~x)), ~x) + ((~c - im * ~d) / 2) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (1 + im * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && Not(IntegerQ(~m)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ 2, ~x) => (-(~b) * (~a * ~c + ~b * ~d) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m) / (2 * (~a) ^ 3 * ~f * ~m) + (1 / (2 * (~a) ^ 2)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * Simp(((~a * (~c) ^ 2 - 2 * ~b * ~c * ~d) + ~a * (~d) ^ 2) - 2 * ~b * (~d) ^ 2 * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (LeQ(~m, -1) && EqQ((~a) ^ 2 + (~b) ^ 2, 0)))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ 2 / (~(a') + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => (~d * (2 * ~b * ~c - ~a * ~d) * ~x) / (~b) ^ 2 + ((~d) ^ 2 / ~b) * Antiderivative(tan(~e + ~f * ~x), ~x) + ((~b * ~c - ~a * ~d) ^ 2 / (~b) ^ 2) * Antiderivative(1 / (~a + ~b * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && NeQ((~a) ^ 2 + (~b) ^ 2, 0))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ 2, ~x) => ((~b * ~c - ~a * ~d) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1)) / (~b * ~f * (~m + 1) * ((~a) ^ 2 + (~b) ^ 2)) + (1 / ((~a) ^ 2 + (~b) ^ 2)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * Simp(((~a * (~c) ^ 2 + 2 * ~b * ~c * ~d) - ~a * (~d) ^ 2) - ((~b * (~c) ^ 2 - 2 * ~a * ~c * ~d) - ~b * (~d) ^ 2) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (LtQ(~m, -1) && NeQ((~a) ^ 2 + (~b) ^ 2, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ 2, ~x) => ((~d) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1)) / (~b * ~f * (~m + 1)) + Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * Simp(((~c) ^ 2 - (~d) ^ 2) + 2 * ~c * ~d * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (Not(LeQ(~m, -1)) && Not(EqQ(~m, 2) && EqQ(~a, 0))))
    @apply_utils Antiderivative(sqrt(~a + ~(b') * tan(~(e') + ~(f') * ~x)) / sqrt(~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((-2 * ~a * ~b) / ~f) * Subst(Antiderivative(1 / ((~a * ~c - ~b * ~d) - 2 * (~a) ^ 2 * (~x) ^ 2), ~x), ~x, sqrt(~c + ~d * tan(~e + ~f * ~x)) / sqrt(~a + ~b * tan(~e + ~f * ~x))) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~a * ~b * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~f * (~m - 1) * (~a * ~c - ~b * ~d)) + ((2 * (~a) ^ 2) / (~a * ~c - ~b * ~d)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (EqQ(~m + ~n, 0) && GtQ(~m, 1 / 2)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~a * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n) / (2 * ~b * ~f * ~m) - ((~a * ~c - ~b * ~d) / (2 * (~b) ^ 2)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (EqQ(~m + ~n, 0) && LeQ(~m, -1 / 2)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~a * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (2 * ~f * ~m * (~b * ~c - ~a * ~d)) + (1 / (2 * ~a)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (EqQ(~m + ~n + 1, 0) && LtQ(~m, -1)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (-(~d) * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~f * ~m * ((~c) ^ 2 + (~d) ^ 2)) + (~a / (~a * ~c - ~b * ~d)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (EqQ(~m + ~n + 1, 0) && Not(LtQ(~m, -1))))))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n / (~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => (-((~a * ~c + ~b * ~d)) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n) / (2 * (~b * ~c - ~a * ~d) * ~f * (~a + ~b * tan(~e + ~f * ~x))) + (1 / (2 * ~a * (~b * ~c - ~a * ~d))) * Antiderivative((~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1) * Simp((~a * ~c * ~d * (~n - 1) + ~b * (~c) ^ 2 + ~b * (~d) ^ 2 * ~n) - ~d * (~b * ~c - ~a * ~d) * (~n - 1) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && LtQ(0, ~n, 1))))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n / (~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => ((~b * ~c - ~a * ~d) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1)) / (2 * ~a * ~f * (~a + ~b * tan(~e + ~f * ~x))) + (1 / (2 * (~a) ^ 2)) * Antiderivative((~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 2) * Simp(((~a * (~c) ^ 2 + ~a * (~d) ^ 2 * (~n - 1)) - ~b * ~c * ~d * ~n) - ~d * (~a * ~c * (~n - 2) + ~b * ~d * ~n) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && GtQ(~n, 1))))
    @apply_utils Antiderivative(1 / ((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x))), ~x) => (~b / (~b * ~c - ~a * ~d)) * Antiderivative(1 / (~a + ~b * tan(~e + ~f * ~x)), ~x) - (~d / (~b * ~c - ~a * ~d)) * Antiderivative(1 / (~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n / (~a + ~(b') * tan(~(e') + ~(f') * ~x)), ~x) => (-(~a) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (2 * ~f * (~b * ~c - ~a * ~d) * (~a + ~b * tan(~e + ~f * ~x))) + (1 / (2 * ~a * (~b * ~c - ~a * ~d))) * Antiderivative((~c + ~d * tan(~e + ~f * ~x)) ^ ~n * Simp((~b * ~c + ~a * ~d * (~n - 1)) - ~b * ~d * ~n * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && Not(GtQ(~n, 0)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (-((~a) ^ 2) * (~b * ~c - ~a * ~d) * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~d * ~f * (~b * ~c + ~a * ~d) * (~n + 1)) + (~a / (~d * (~b * ~c + ~a * ~d) * (~n + 1))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1) * Simp(~b * (~b * ~c * (~m - 2) - ~a * ~d * ((~m - 2 * ~n) - 4)) + ((~a * ~b * ~c * (~m - 2) + (~b) ^ 2 * ~d * (~n + 1)) - (~a) ^ 2 * ~d * ((~m + ~n) - 1)) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (GtQ(~m, 1) && (LtQ(~n, -1) && (IntegerQ(~m) || IntegersQ(2 * ~m, 2 * ~n)))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ (3 / 2) / (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((2 * (~a) ^ 2) / (~a * ~c - ~b * ~d)) * Antiderivative(sqrt(~a + ~b * tan(~e + ~f * ~x)), ~x) - ((2 * ~b * ~c * ~d + ~a * ((~c) ^ 2 - (~d) ^ 2)) / (~a * ((~c) ^ 2 + (~d) ^ 2))) * Antiderivative(((~a - ~b * tan(~e + ~f * ~x)) * sqrt(~a + ~b * tan(~e + ~f * ~x))) / (~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ (3 / 2) / sqrt(~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => 2 * ~a * Antiderivative(sqrt(~a + ~b * tan(~e + ~f * ~x)) / sqrt(~c + ~d * tan(~e + ~f * ~x)), ~x) + (~b / ~a) * Antiderivative(((~b + ~a * tan(~e + ~f * ~x)) * sqrt(~a + ~b * tan(~e + ~f * ~x))) / sqrt(~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~b) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~d * ~f * ((~m + ~n) - 1)) + (~a / (~d * ((~m + ~n) - 1))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n * Simp(~b * ~c * (~m - 2) + ~a * ~d * (~m + 2 * ~n) + (~a * ~c * (~m - 2) + ~b * ~d * ((3 * ~m + 2 * ~n) - 4)) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (IntegerQ(2 * ~m) && (GtQ(~m, 1) && (NeQ((~m + ~n) - 1, 0) && (IntegerQ(~m) || IntegersQ(2 * ~m, 2 * ~n))))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * sqrt(~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (-(~b) * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * sqrt(~c + ~d * tan(~e + ~f * ~x))) / (2 * ~a * ~f * ~m) + (1 / (4 * (~a) ^ 2 * ~m)) * Antiderivative(((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * Simp(2 * ~a * ~c * ~m + ~b * ~d + ~a * ~d * (2 * ~m + 1) * tan(~e + ~f * ~x), ~x)) / sqrt(~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~m, 0) && IntegersQ(2 * ~m)))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (-((~b * ~c - ~a * ~d)) * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1)) / (2 * ~a * ~f * ~m) + (1 / (2 * (~a) ^ 2 * ~m)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 2) * Simp((~c * (~a * ~c * ~m + ~b * ~d * (~n - 1)) - ~d * (~b * ~c * ~m + ~a * ~d * (~n - 1))) - ~d * (~b * ~d * ((~m - ~n) + 1) - ~a * ~c * ((~m + ~n) - 1)) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~m, 0) && (GtQ(~n, 1) && (IntegerQ(~m) || IntegersQ(2 * ~m, 2 * ~n)))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~a * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (2 * ~f * ~m * (~b * ~c - ~a * ~d)) + (1 / (2 * ~a * ~m * (~b * ~c - ~a * ~d))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n * Simp((~b * ~c * ~m - ~a * ~d * (2 * ~m + ~n + 1)) + ~b * ~d * (~m + ~n + 1) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~m, 0) && (IntegerQ(~m) || IntegersQ(2 * ~m, 2 * ~n))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~d * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1)) / (~f * ((~m + ~n) - 1)) - (1 / (~a * ((~m + ~n) - 1))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 2) * Simp((~d * (~b * ~c * ~m + ~a * ~d * (-1 + ~n)) - ~a * (~c) ^ 2 * ((~m + ~n) - 1)) + ~d * (~b * ~d * ~m - ~a * ~c * ((~m + 2 * ~n) - 2)) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (GtQ(~n, 1) && (NeQ((~m + ~n) - 1, 0) && (IntegerQ(~n) || IntegersQ(2 * ~m, 2 * ~n)))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~d * (~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~f * (~n + 1) * ((~c) ^ 2 + (~d) ^ 2)) - (1 / (~a * ((~c) ^ 2 + (~d) ^ 2) * (~n + 1))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1) * Simp((~b * ~d * ~m - ~a * ~c * (~n + 1)) + ~a * ~d * (~m + ~n + 1) * tan(~e + ~f * ~x), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~n, -1) && (IntegerQ(~n) || IntegersQ(2 * ~m, 2 * ~n))))))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m / (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (~a / (~a * ~c - ~b * ~d)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m, ~x) - (~d / (~a * ~c - ~b * ~d)) * Antiderivative(((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~b + ~a * tan(~e + ~f * ~x))) / (~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative(sqrt(~a + ~(b') * tan(~(e') + ~(f') * ~x)) * sqrt(~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => ((~a * ~c - ~b * ~d) / ~a) * Antiderivative(sqrt(~a + ~b * tan(~e + ~f * ~x)) / sqrt(~c + ~d * tan(~e + ~f * ~x)), ~x) + (~d / ~a) * Antiderivative((sqrt(~a + ~b * tan(~e + ~f * ~x)) * (~b + ~a * tan(~e + ~f * ~x))) / sqrt(~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~a + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~a * ~b) / ~f) * Subst(Antiderivative(((~a + ~x) ^ (~m - 1) * (~c + (~d / ~b) * ~x) ^ ~n) / ((~b) ^ 2 + ~a * ~x), ~x), ~x, ~b * tan(~e + ~f * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (EqQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~b * ~c - ~a * ~d) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~d * ~f * (~n + 1) * ((~c) ^ 2 + (~d) ^ 2)) - (1 / (~d * (~n + 1) * ((~c) ^ 2 + (~d) ^ 2))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 3) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1) * Simp((((~a) ^ 2 * ~d * (~b * ~d * (~m - 2) - ~a * ~c * (~n + 1)) + ~b * (~b * ~c - 2 * ~a * ~d) * (~b * ~c * (~m - 2) + ~a * ~d * (~n + 1))) - ~d * (~n + 1) * (((3 * (~a) ^ 2 * ~b * ~c - (~b) ^ 3 * ~c) - (~a) ^ 3 * ~d) + 3 * ~a * (~b) ^ 2 * ~d) * tan(~e + ~f * ~x)) - ~b * (~a * ~d * (2 * ~b * ~c - ~a * ~d) * ((~m + ~n) - 1) - (~b) ^ 2 * ((~c) ^ 2 * (~m - 2) - (~d) ^ 2 * (~n + 1))) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (GtQ(~m, 2) && (LtQ(~n, -1) && IntegerQ(2 * ~m))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~b) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~d * ~f * ((~m + ~n) - 1)) + (1 / (~d * ((~m + ~n) - 1))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 3) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n * Simp((((~a) ^ 3 * ~d * ((~m + ~n) - 1) - (~b) ^ 2 * (~b * ~c * (~m - 2) + ~a * ~d * (1 + ~n))) + ~b * ~d * ((~m + ~n) - 1) * (3 * (~a) ^ 2 - (~b) ^ 2) * tan(~e + ~f * ~x)) - (~b) ^ 2 * (~b * ~c * (~m - 2) - ~a * ~d * ((3 * ~m + 2 * ~n) - 4)) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (IntegerQ(2 * ~m) && (GtQ(~m, 2) && ((GeQ(~n, -1) || IntegerQ(~m)) && Not(IGtQ(~n, 2) && (Not(IntegerQ(~m)) || EqQ(~c, 0) && NeQ(~a, 0)))))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~b * ~c - ~a * ~d) * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1)) / (~f * (~m + 1) * ((~a) ^ 2 + (~b) ^ 2)) + (1 / ((~m + 1) * ((~a) ^ 2 + (~b) ^ 2))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 2) * Simp(((~a * (~c) ^ 2 * (~m + 1) + ~a * (~d) ^ 2 * (~n - 1) + ~b * ~c * ~d * ((~m - ~n) + 2)) - ((~b * (~c) ^ 2 - 2 * ~a * ~c * ~d) - ~b * (~d) ^ 2) * (~m + 1) * tan(~e + ~f * ~x)) - ~d * (~b * ~c - ~a * ~d) * (~m + ~n) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~m, -1) && (LtQ(1, ~n, 2) && IntegerQ(2 * ~m))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~b * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n) / (~f * (~m + 1) * ((~a) ^ 2 + (~b) ^ 2)) + (1 / ((~m + 1) * ((~a) ^ 2 + (~b) ^ 2))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1) * Simp(((~a * ~c * (~m + 1) - ~b * ~d * ~n) - (~b * ~c - ~a * ~d) * (~m + 1) * tan(~e + ~f * ~x)) - ~b * ~d * (~m + ~n + 1) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (LtQ(~m, -1) && (GtQ(~n, 0) && IntegerQ(2 * ~m))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => ((~b) ^ 2 * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n + 1)) / (~f * (~m + 1) * ((~a) ^ 2 + (~b) ^ 2) * (~b * ~c - ~a * ~d)) + (1 / ((~m + 1) * ((~a) ^ 2 + (~b) ^ 2) * (~b * ~c - ~a * ~d))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m + 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n * Simp(((~a * (~b * ~c - ~a * ~d) * (~m + 1) - (~b) ^ 2 * ~d * (~m + ~n + 2)) - ~b * (~b * ~c - ~a * ~d) * (~m + 1) * tan(~e + ~f * ~x)) - (~b) ^ 2 * ~d * (~m + ~n + 2) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (IntegerQ(2 * ~m) && (LtQ(~m, -1) && ((LtQ(~n, 0) || IntegerQ(~m)) && Not(ILtQ(~n, -1) && (Not(IntegerQ(~m)) || EqQ(~c, 0) && NeQ(~a, 0)))))))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~b * (~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 1) * (~c + ~d * tan(~e + ~f * ~x)) ^ ~n) / (~f * ((~m + ~n) - 1)) + (1 / ((~m + ~n) - 1)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ (~m - 2) * (~c + ~d * tan(~e + ~f * ~x)) ^ (~n - 1) * Simp(((~a) ^ 2 * ~c * ((~m + ~n) - 1) - ~b * (~b * ~c * (~m - 1) + ~a * ~d * ~n)) + ((2 * ~a * ~b * ~c + (~a) ^ 2 * ~d) - (~b) ^ 2 * ~d) * ((~m + ~n) - 1) * tan(~e + ~f * ~x) + ~b * (~b * ~c * ~n + ~a * ~d * ((2 * ~m + ~n) - 2)) * tan(~e + ~f * ~x) ^ 2, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && (GtQ(~m, 1) && (GtQ(~n, 0) && IntegerQ(2 * ~n))))))
    @apply_utils Antiderivative(1 / ((~a + ~(b') * tan(~(e') + ~(f') * ~x)) * (~(c') + ~(d') * tan(~(e') + ~(f') * ~x))), ~x) => (((~a * ~c - ~b * ~d) * ~x) / (((~a) ^ 2 + (~b) ^ 2) * ((~c) ^ 2 + (~d) ^ 2)) + ((~b) ^ 2 / ((~b * ~c - ~a * ~d) * ((~a) ^ 2 + (~b) ^ 2))) * Antiderivative((~b - ~a * tan(~e + ~f * ~x)) / (~a + ~b * tan(~e + ~f * ~x)), ~x)) - ((~d) ^ 2 / ((~b * ~c - ~a * ~d) * ((~c) ^ 2 + (~d) ^ 2))) * Antiderivative((~d - ~c * tan(~e + ~f * ~x)) / (~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative(sqrt(~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) / (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (1 / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative(Simp(~a * ~c + ~b * ~d + (~b * ~c - ~a * ~d) * tan(~e + ~f * ~x), ~x) / sqrt(~a + ~b * tan(~e + ~f * ~x)), ~x) - ((~d * (~b * ~c - ~a * ~d)) / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative((1 + tan(~e + ~f * ~x) ^ 2) / (sqrt(~a + ~b * tan(~e + ~f * ~x)) * (~c + ~d * tan(~e + ~f * ~x))), ~x) <-- FreeQ([~a, ~b, ~c, ~d], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ (3 / 2) / (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (1 / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative(Simp(((~a) ^ 2 * ~c - (~b) ^ 2 * ~c) + 2 * ~a * ~b * ~d + ((2 * ~a * ~b * ~c - (~a) ^ 2 * ~d) + (~b) ^ 2 * ~d) * tan(~e + ~f * ~x), ~x) / sqrt(~a + ~b * tan(~e + ~f * ~x)), ~x) + ((~b * ~c - ~a * ~d) ^ 2 / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative((1 + tan(~e + ~f * ~x) ^ 2) / (sqrt(~a + ~b * tan(~e + ~f * ~x)) * (~c + ~d * tan(~e + ~f * ~x))), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m / (~(c') + ~(d') * tan(~(e') + ~(f') * ~x)), ~x) => (1 / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~c - ~d * tan(~e + ~f * ~x)), ~x) + ((~d) ^ 2 / ((~c) ^ 2 + (~d) ^ 2)) * Antiderivative(((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (1 + tan(~e + ~f * ~x) ^ 2)) / (~c + ~d * tan(~e + ~f * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && (NeQ((~c) ^ 2 + (~d) ^ 2, 0) && Not(IntegerQ(~m)))))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~m * (~c + ~(d') * tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => With([ff = FreeFactors(tan(~e + ~f * ~x), ~x)], (ff / ~f) * Subst(Antiderivative(((~a + ~b * ff * ~x) ^ ~m * (~c + ~d * ff * ~x) ^ ~n) / (1 + ff ^ 2 * (~x) ^ 2), ~x), ~x, tan(~e + ~f * ~x) / ff)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (NeQ(~b * ~c - ~a * ~d, 0) && (NeQ((~a) ^ 2 + (~b) ^ 2, 0) && NeQ((~c) ^ 2 + (~d) ^ 2, 0)))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~(m') * (~(d') / tan(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~d) ^ ~m * Antiderivative((~b + ~a * cot(~e + ~f * ~x)) ^ ~m * (~d * cot(~e + ~f * ~x)) ^ (~n - ~m), ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~f, ~n], ~x) && (Not(IntegerQ(~n)) && IntegerQ(~m))
    @apply_utils Antiderivative((~(a') + ~(b') * cot(~(e') + ~(f') * ~x)) ^ ~(m') * (~(d') / cot(~(e') + ~(f') * ~x)) ^ ~n, ~x) => (~d) ^ ~m * Antiderivative((~b + ~a * tan(~e + ~f * ~x)) ^ ~m * (~d * tan(~e + ~f * ~x)) ^ (~n - ~m), ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~f, ~n], ~x) && (Not(IntegerQ(~n)) && IntegerQ(~m))
    @apply_utils Antiderivative((~(a') + ~(b') * tan(~(e') + ~(f') * ~x)) ^ ~(m') * (~(c') * (~(d') * tan(~(e') + ~(f') * ~x)) ^ ~p) ^ ~n, ~x) => (((~c) ^ IntPart(~n) * (~c * (~d * tan(~e + ~f * ~x)) ^ ~p) ^ FracPart(~n)) / (~d * tan(~e + ~f * ~x)) ^ (~p * FracPart(~n))) * Antiderivative((~a + ~b * tan(~e + ~f * ~x)) ^ ~m * (~d * tan(~e + ~f * ~x)) ^ (~n * ~p), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n, ~p], ~x) && (Not(IntegerQ(~n)) && Not(IntegerQ(~m)))
    @apply_utils Antiderivative((~(a') + ~(b') * cot(~(e') + ~(f') * ~x)) ^ ~(m') * (~(c') * (~(d') * cot(~(e') + ~(f') * ~x)) ^ ~p) ^ ~n, ~x) => (((~c) ^ IntPart(~n) * (~c * (~d * cot(~e + ~f * ~x)) ^ ~p) ^ FracPart(~n)) / (~d * cot(~e + ~f * ~x)) ^ (~p * FracPart(~n))) * Antiderivative((~a + ~b * cot(~e + ~f * ~x)) ^ ~m * (~d * cot(~e + ~f * ~x)) ^ (~n * ~p), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n, ~p], ~x) && (Not(IntegerQ(~n)) && Not(IntegerQ(~m)))
end

max_stars_repo_path: src/rules/4 Trig functions/4.3 Tangent/4.3.2.1 (a+b tan)^m (c+d tan)^n.jl


text:
using Test

include("./decisiontree.jl")
include("./graph.jl")
include("./heapqueue.jl")
include("./searching.jl")
include("./sorting.jl")
include("./unionfind.jl")

max_stars_repo_name: Jetafull/AlgorithmsInJulia

max_issues_repo_name: Jetafull/algorithms-in-julia

max_forks_repo_name: Jetafull/algorithms-in-julia


text:
function safeRound(num)
  if VERSION < v"0.4-"
    iround(num)
  else
    round(Integer, num)
  end
end

function safeFloor(num)
  if VERSION < v"0.4-"
    ifloor(num)
  else
    floor(Integer, num)
  end
end

macro _not_implemented()
  quote
    throw(ArgumentError("Not implemented for the given type"))
  end
end


text:
function _empty_plot()
    backend = Plots.backend()
    return _empty_plot(backend)
end

function _make_ylabel(
    base_power::Float64;
    variable::String = "Generation",
    time::String = "",
)
    if isapprox(base_power, 1.0)
        ylabel = "$variable (MW$time)"
    elseif isapprox(base_power, 1000.0)
        ylabel = "$variable (GW$time)"
    else
        ylabel = "$variable (MW$time x$base_power)"
    end
    return ylabel
end

function get_default_seriescolor()
    backend = Plots.backend()
    return get_default_seriescolor(backend)
end

function get_default_seriescolor(backend)
    return GR_DEFAULT
end

function get_default_seriescolor(backend::Plots.PlotlyJSBackend)
    return PLOTLY_DEFAULT
end
################################### DEMAND #################################

"""
    plot_demand(results)
    plot_demand(system)

This function makes a plot of the demand in the system.

# Arguments

- `res::Union{Results, Vector{IS.Results}}`: results to be plotted

# Example

```julia
res = PSI.solve_op_problem!(OpProblem)
plot = plot_demand(res)
```

# Accepted Key Words

- `linestyle::Symbol = :dash` : set line style
- `title::String`: Set a title for the plots
- `horizon::Int64`: To plot a shorter window of time than the full results
- `initial_time::DateTime`: To start the plot at a different time other than the results initial time
- `aggregate::String = "System", "PowerLoad", or "Bus"`: aggregate the demand other than by generator
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""

function plot_demand(result::Union{IS.Results, PSY.System}; kwargs...)
    return plot_demand!(_empty_plot(), result; kwargs...)
end

"""
    plot_demand!(plot, results)
    plot_demand!(plot, system)

This function makes a plot of the demand in the system.

# Arguments

- `plot` : existing plot handle
- `result::Union{IS.Results, PSY.System}` : simulation results or PowerSystems.System

# Accepted Key Words

- `linestyle::Symbol = :dash` : set line style
- `title::String`: Set a title for the plots
- `horizon::Int64`: To plot a shorter window of time than the full results
- `initial_time::DateTime`: To start the plot at a different time other than the results initial time
- `aggregate::String = "System", "PowerLoad", or "Bus"`: aggregate the demand other than by generator
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_demand!(p, result::Union{IS.Results, PSY.System}; kwargs...)
    backend = Plots.backend()
    set_display = get(kwargs, :set_display, true)
    save_fig = get(kwargs, :save, nothing)
    bar = get(kwargs, :bar, false)
    linestyle = get(kwargs, :linestyle, :solid)

    title = get(kwargs, :title, "Demand")
    y_label = get(kwargs, :y_label, bar ? "MWh" : "MW")

    load = get_load_data(result; kwargs...)
    load_agg = combine_categories(load.data)

    if isnothing(load_agg)
        Throw(error("No load data found"))
    end

    p = plot_dataframe!(
        p,
        load_agg,
        load.time;
        seriescolor = get(kwargs, :seriescolor, get_default_seriescolor()),
        linestyle = Symbol(linestyle),
        line_dash = string(linestyle),
        linewidth = get(kwargs, :linewidth, 1),
        y_label = y_label,
        set_display = false,
        title = title,
        kwargs...,
    )

    if set_display
        if backend == Plots.PlotlyJSBackend()
            display(Plots.PlotlyJS.plot(p))
        else
            display(p)
        end
    end
    if !isnothing(save_fig)
        title = replace(title, " " => "_")
        save_plot(p, joinpath(save_fig, "$(title).png"), backend; kwargs...)
    end
    return p
end

################################# Plotting a Single DataFrame ##########################

"""
    plot_dataframe(df)
    plot_dataframe(df, time_range)

Plots data from DataFrame where each row represents a time period and each column represents a trace

# Arguments

- `df::DataFrames.DataFrame`: DataFrame where each row represents a time period and each column represents a trace.
If only the dataframe is provided, it must have a column of `DateTime` values.
- `time_range:::Union{DataFrames.DataFrame, Array, StepRange}`: The time periods of the data

# Example

```julia
var_name = :P__ThermalStandard
df = PSI.read_variables_with_keys(results, names = [var_name])[var_name]
time_range = PSI.get_realized_timestamps(results)
plot = plot_dataframe(df, time_range)
```

# Accepted Key Words
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""

function plot_dataframe(df::DataFrames.DataFrame; kwargs...)
    return plot_dataframe!(_empty_plot(), no_datetime(df), df.DateTime; kwargs...)
end
function plot_dataframe(
    df::DataFrames.DataFrame,
    time_range::Union{DataFrames.DataFrame, Array, StepRange};
    kwargs...,
)
    return plot_dataframe!(_empty_plot(), df, time_range; kwargs...)
end

"""
    plot_dataframe!(plot, df)
    plot_dataframe!(plot, df, time_range)

Plots data from DataFrame where each row represents a time period and each column represents a trace

# Arguments

- `plot`: existing plot handle
- `df::DataFrames.DataFrame`: DataFrame where each row represents a time period and each column represents a trace.
If only the dataframe is provided, it must have a column of `DateTime` values.
- `time_range:::Union{DataFrames.DataFrame, Array, StepRange}`: The time periods of the data

# Accepted Key Words
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""

function plot_dataframe!(p, df::DataFrames.DataFrame; kwargs...)
    return plot_dataframe!(p, no_datetime(df), df.DateTime; kwargs...)
end

function plot_dataframe!(
    p,
    variable::DataFrames.DataFrame,
    time_range::Union{DataFrames.DataFrame, Array, StepRange};
    kwargs...,
)
    time_range =
        typeof(time_range) == DataFrames.DataFrame ? time_range[:, 1] : collect(time_range)
    backend = Plots.backend()
    p = _dataframe_plots_internal(p, variable, time_range, backend; kwargs...)
    return p
end

################################# Plotting PGData ##########################

"""
    plot_pgdata(pgdata)

This function makes a plot of a PGdata object

# Arguments

- `pgdata::PGData`: The dataframe to be plotted

# Accepted Key Words
- `combine_categories::Bool = false` : plot category values or each value in a category
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_pgdata(pgdata::PGData; kwargs...)
    return plot_pgdata!(_empty_plot(), pgdata; kwargs...)
end

"""
    plot_pgdata!(plot, pgdata)

This function makes a plot of a PGdata object

# Arguments

- `plot` : existing plot handle (optional)
- `pgdata::PGData`: The dataframe to be plotted

# Accepted Key Words
- `combine_categories::Bool = false` : plot category values or each value in a category
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_pgdata!(p, pgdata::PGData; kwargs...)
    backend = Plots.backend()
    title = get(kwargs, :title, "")
    set_display = get(kwargs, :set_display, true)
    save_fig = get(kwargs, :save, nothing)

    if get(kwargs, :combine_categories, true)
        aggregate = get(kwargs, :aggregate, nothing)
        names = get(kwargs, :names, nothing)
        data = combine_categories(pgdata.data; names = names, aggregate = aggregate)
    else
        data = pgdata.data
    end
    kwargs =
        Dict{Symbol, Any}((k, v) for (k, v) in kwargs if k ∉ [:title, :save, :set_display])

    p = plot_dataframe!(p, data, pgdata.time; set_display = false, kwargs...)

    if set_display
        if backend == Plots.PlotlyJSBackend()
            display(Plots.PlotlyJS.plot(p))
        else
            display(p)
        end
    end
    if !isnothing(save_fig)
        title = replace(title, " " => "_")
        format = get(kwargs, :format, "png")
        save_plot(p, joinpath(save_fig, "$title.$format"), backend; kwargs...)
    end
    return p
end

"""
    plot_results(results)

This function makes a plot of a results dictionary object

# Arguments

- `results::Dict{String, DataFrame`: The results to be plotted

# Accepted Key Words
- `combine_categories::Bool = false` : plot category values or each value in a category
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_results(results::Dict{String, DataFrames.DataFrame}; kwargs...)
    return plot_pgdata!(_empty_plot(), PGData(results); kwargs...)
end

"""
    plot_results!(plot, results)

This function makes a plot of a results dictionary

# Arguments

- `plot` : existing plot handle (optional)
- `results::Dict{String, DataFrame}`: The results to be plotted

# Accepted Key Words
- `combine_categories::Bool = false` : plot category values or each value in a category
- `curtailment::Bool`: plot the curtailment with the variable
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_results!(p, results::Dict{String, DataFrames.DataFrame}; kwargs...)
    return plot_pgdata!(p, PGData(results); kwargs...)
    return p
end

################################# Plotting Fuel Plot of Results ##########################
"""
    plot_fuel(results)

This function makes a stack plot of the results by fuel type
and assigns each fuel type a specific color.

# Arguments

- `res::PSI.Results` : results to be plotted

# Example

```julia
res = solve_op_problem!(OpProblem)
plot = plot_fuel(res)
```

# Accepted Key Words
- `generator_mapping_file` = "file_path" : file path to yaml definig generator category by fuel and primemover
- `variables::Union{Nothing, Vector{Symbol}}` = nothing : specific variables to plot
- `slacks::Bool = true` : display slack variables
- `load::Bool = true` : display load line
- `curtailment::Bool = true`: To plot the curtailment in the stack plot
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""

function plot_fuel(result::IS.Results; kwargs...)
    return plot_fuel!(_empty_plot(), result; kwargs...)
end

"""
    plot_fuel!(plot, results)

This function makes a stack plot of the results by fuel type
and assigns each fuel type a specific color.

# Arguments

- `plot` : existing plot handle (optional)
- `res::PSI.Results` : results to be plotted

# Accepted Key Words
- `generator_mapping_file` = "file_path" : file path to yaml definig generator category by fuel and primemover
- `variables::Union{Nothing, Vector{Symbol}}` = nothing : specific variables to plot
- `slacks::Bool = true` : display slack variables
- `load::Bool = true` : display load line
- `curtailment::Bool = true`: To plot the curtailment in the stack plot
- `set_display::Bool = true`: set to false to prevent the plots from displaying
- `save::String = "file_path"`: set a file path to save the plots
- `format::String = "png"`: set a different format for saving a PlotlyJS plot
- `seriescolor::Array`: Set different colors for the plots
- `title::String = "Title"`: Set a title for the plots
- `stack::Bool = true`: stack plot traces
- `bar::Bool` : create bar plot
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
"""
function plot_fuel!(p, result::IS.Results; kwargs...)
    backend = Plots.backend()
    set_display = get(kwargs, :set_display, true)
    save_fig = get(kwargs, :save, nothing)
    curtailment = get(kwargs, :curtailment, true)
    slacks = get(kwargs, :slacks, true)
    load = get(kwargs, :load, true)
    title = get(kwargs, :title, "Fuel")
    stack = get(kwargs, :stack, true)
    bar = get(kwargs, :bar, false)
    kwargs =
        Dict{Symbol, Any}((k, v) for (k, v) in kwargs if k ∉ [:title, :save, :set_display])

    # Generation stack
    gen = get_generation_data(result; kwargs...)
    sys = PSI.get_system(result)
    if sys === nothing
        Throw(error("No System data present: please run `set_system!(results, sys)`"))
    end
    cat = make_fuel_dictionary(sys; kwargs...)
    fuel = categorize_data(gen.data, cat; curtailment = curtailment, slacks = slacks)

    # passing names here enforces order
    # TODO: enable custom sort with kwarg
    fuel_agg = combine_categories(fuel; names = intersect(CATEGORY_DEFAULT, keys(fuel)))
    y_label = get(kwargs, :y_label, bar ? "MWh" : "MW")

    seriescolor = get(kwargs, :seriescolor, match_fuel_colors(fuel_agg, backend))
    p = plot_dataframe!(
        p,
        fuel_agg,
        gen.time;
        stack = stack,
        seriescolor = seriescolor,
        y_label = y_label,
        title = title,
        set_display = false,
        kwargs...,
    )

    kwargs = Dict{Symbol, Any}((k, v) for (k, v) in kwargs if k ∉ [:nofill, :seriescolor])
    kwargs[:linestyle] = get(kwargs, :linestyle, :dash)
    kwargs[:linewidth] = get(kwargs, :linewidth, 3)

    if load
        # load line
        p = plot_demand!(
            p,
            result;
            nofill = true,
            title = title,
            y_label = y_label,
            set_display = false,
            stack = stack,
            seriescolor = ["black"],
            kwargs...,
        )
    end

    # service stack
    # TODO: how to display this?

    if set_display
        if backend == Plots.PlotlyJSBackend()
            display(Plots.PlotlyJS.plot(p))
        else
            display(p)
        end
    end
    if !isnothing(save_fig)
        title = replace(title, " " => "_")
        format = get(kwargs, :format, "png")
        save_plot(p, joinpath(save_fig, "$title.$format"), backend; kwargs...)
    end
    return p
end

"""
    save_plot(plot, filename)

Saves plot to specified filename

# Arguments

- `plot`: plot object
- `filename::String` : save to filename

# Example

```julia
res = solve_op_problem!(OpProblem)
plot = plot_fuel(res)
save_plot(plot, "my_plot.png")
```

# Accepted Key Words (currently only implemented for PlotlyJS backend)
- `width::Union{Nothing,Int}=nothing`
- `height::Union{Nothing,Int}=nothing`
- `scale::Union{Nothing,Real}=nothing`
"""
function save_plot(plot, filename::String; kwargs...) # this needs to be typed but Plots.PlotlyJS.Plot doesn't exist until PlotlyJS is loaded
    backend = Plots.backend()
    return save_plot(plot, filename, backend; kwargs...)
end

max_stars_repo_name: NREL-SIIP/InfrastructureSystemsPlots

max_issues_repo_name: NREL-SIIP/InfrastructureSystemsPlots

max_forks_repo_name: NREL-SIIP/InfrastructureSystemsPlots


text:
using MultiIndices
using Base.Test

@testset "abstract" begin
    n = 1000
    𝕽¹ = Cartesian(n)

    𝕽̃¹ = 𝕽¹ ⊕ 𝕽¹ ⊕ 𝕽¹
    @test dims(𝕽̃¹) == dims(𝕽¹) == 1
    @test order(𝕽̃¹) == order(𝕽¹) == (1,)
    @test size(𝕽̃¹) == 3size(𝕽¹)[1] == 3n

    @test 𝕽̃¹[1] == 𝕽¹
    @test 𝕽̃¹[1,2] == 2
    # @test 𝕽̃¹[2,1] == 1 + n

    𝕽² = 𝕽¹ ⊗ 𝕽¹
    𝕽³a = 𝕽² ⊗ 𝕽¹
    𝕽³b = 𝕽¹ ⊗ 𝕽²

    @test dims(𝕽¹) == 1
    @test order(𝕽¹) == (1,)

    @test dims(𝕽²) == 2
    @test order(𝕽²) == (1,2)
    @test size(𝕽²) == (n, n)

    @test order(𝕽¹,𝕽¹) == (1,2)
    @test order(𝕽²,𝕽²) == (1,2,3,4)

    @test dims(𝕽³a) == dims(𝕽³b) == 3
    @test order(𝕽³a) == order(𝕽³b) == (1, 2, 3)
    @test size(𝕽³a) == size(𝕽³b) == (n, n, n)

    # # Actually, we would like this to be true, as well, since the
    # # constituent spaces are the same
    # @test 𝕽³a == 𝕽³b

    @test 𝕽²[2,1] == 2
    @test 𝕽²[1,2] == 1+n

    @test 𝕽³a[2,1,1] == 2
    @test 𝕽³a[1,2,1] == 1 + n
    @test 𝕽³a[1,1,2] == 1 + n^2
end

@testset "cartesian" begin
    𝖃𝖄 = CartesianXY(100,500)
    @test 𝖃𝖄[2,1] == 2
    @test 𝖃𝖄[1,2] == 101
    @test dims(𝖃𝖄) == 2
    @test order(𝖃𝖄) == (1,2)
    @test size(𝖃𝖄) == (100, 500)

    𝖄𝖃 = CartesianYX(100,500)
    @test 𝖄𝖃[2,1] == 501
    @test 𝖄𝖃[1,2] == 2
    @test dims(𝖄𝖃) == 2
    @test order(𝖄𝖃) == (2,1)
    @test size(𝖄𝖃) == (100, 500)
end

@testset "polar" begin
    𝔓 = Polar{(1,2)}(100,10)
    @test dims(𝔓) == 2
    @test order(𝔓) == (1,2)
    @test size(𝔓) == (100,10)
    @test 𝔓[2,1] == 2
    @test 𝔓[1,2] == 101
end

@testset "spin" begin
    𝔖 = Spin{5//2}()
    @test dims(𝔖) == 1
    @test order(𝔖) == (1,)
    @test size(𝔖) == (6,)
    @test 𝔖[4] == 4
end


text:
using Test

using Distributions: Gamma, mean, params
using DataStructures: Queue, enqueue!, dequeue!
using SpecialFunctions: gamma, digamma

include("../edges/edge_gamma.jl")
include("../nodes/node_gamma.jl")

@testset "constructor" begin

    shape = 1.0
    rate = 1.0
    nodes = Dict{String, Symbol}()
    id = "x"

    x = EdgeGamma(shape, rate, nodes, id)

    @test isa(x.params, Dict{String, Float64})
    @test x.params["shape"] == shape
    @test x.params["rate"] == rate
    @test x.id == id

    # TODO test invalid inputs
end

@testset "update" begin

    shape = 1.0
    rate = 1.0
    nodes = Dict{String, Symbol}()
    id = "x"

    message_left = Gamma(0.5, 2.0)
    message_right = Gamma(1.0, 1.0)

    x = EdgeGamma(shape, rate, nodes, id)
    update(x, message_left, message_right)

    @test x.params["shape"] == 0.5
    @test x.params["rate"] == 3.0

    new_shape, new_rate = params(message(x))
    @test new_shape == 0.5
    @test new_rate == 3.0

    # TODO test invalid inputs
end

@testset "queue_message" begin

    f = NodeGamma(:x, 0.1, 2.0, "f")
    g = NodeGamma(:x, 0.5, 3.0, "g")

    shape = 1.5
    rate = 2.0
    nodes = Dict{String, Symbol}("left" => :f, "right" => :g)
    id = "x"

    message_left = message(f)
    message_right = message(g)

    x = EdgeGamma(shape, rate, nodes, id)
    update(x, message_left, message_right)
    act(x, message(x), 10.0)

    @test dequeue!(f.incoming_messages) == (message(x), 10.0, "outcome")
    @test dequeue!(g.incoming_messages) == (message(x), 10.0, "outcome")

    # TODO test invalid inputs
end

max_stars_repo_name: wmkouw/schedulefreeMP

max_issues_repo_name: wmkouw/schedulefreeMP

max_forks_repo_name: wmkouw/schedulefreeMP


text:
function bin_dist(n, k, p, q)
    return binomial(n, k) * p^k * q^(n-k)
end

function f(n, k, p, q)
    mass = 0
    for i = 0:k
        mass += bin_dist(n, i, p, q)
    end
    return mass
end

function g(n, k, p, q)
    mass = 0
    for i = k:n
        mass += bin_dist(n, i, p, q)
    end
    return mass
end

str = readline()
strvec = split(str, ' ')
intvec = map(x -> parse(Int64, x), strvec)
a = intvec[1]
n = intvec[2]

p = a / 100
q = 1 - p

println(round(f(n, 2, p, q), 3))
println(round(g(n, 2, p, q), 3))

max_stars_repo_path: Tutorials/10 Days of Statistics/Day 4/binomial_distribution2.jl

max_stars_repo_name: xuedong/hacker-rank

max_issues_repo_name: xuedong/hacker-rank

max_forks_repo_name: xuedong/hacker-rank


text:
"""
    SimpleIndex
"""
struct SimpleIndex{name,V,Vs<:AbstractUnitRange{V}} <: AbstractIndex{name,V,V,Vs,Vs}
    _kv::Vs
end

SimpleIndex(vs) = SimpleIndex{nothing}(vs)
SimpleIndex{name}(vs) where {name} = SimpleIndex{name,eltype(vs),typeof(vs)}(vs)

###
### Interface
###

Base.values(si::SimpleIndex) = getfield(si, :_kv)

Base.keys(si::SimpleIndex) = getfield(si, :_kv)

###
### pop
###
Base.pop!(si::SimpleIndex) = pop!(values(si))
function StaticRanges.pop(si::SimpleIndex)
    can_set_last(a) || error("Cannot change size of index of type $(typeof(a)).")
    return SimpleIndex{dimnames(si)}(pop(values(si)))
end

Base.popfirst!(si::SimpleIndex) = popfirst!(values(si))
function StaticRanges.popfirst(si::SimpleIndex)
    can_set_first(a) || error("Cannot change size of index of type $(typeof(a)).")
    return SimpleIndex{dimnames(si)}(popfirst(values(si)))
end

###
### Traits
###

StaticRanges.is_dynamic(::Type{T}) where {T<:SimpleIndex} = is_dynamic(keys_type(T))

StaticRanges.is_fixed(::Type{T}) where {T<:SimpleIndex} = is_fixed(keys_type(T))

StaticRanges.is_static(::Type{T}) where {T<:SimpleIndex} = is_static(keys_type(T))

StaticRanges.can_set_first(::Type{T}) where {T<:SimpleIndex} = can_set_first(keys_type(T))

StaticRanges.can_set_last(::Type{T}) where {T<:SimpleIndex} =  can_set_last(keys_type(T))

StaticRanges.can_set_length(::Type{T}) where {T<:SimpleIndex} = can_set_length(keys_type(T))

function StaticRanges.set_length!(a::SimpleIndex, len::Int)
    can_set_length(a) || error("Cannot use set_length! for instances of typeof $(typeof(x)).")
    set_length!(keys(a), len)
    return a
end

index_by(a::SimpleIndex{name,K}, i::K) where {name,K<:Integer} = ByValue
index_by(a::SimpleIndex{name,K}, i::AbstractVector{K}) where {name,K<:Integer} = ByValue
index_by(a::SimpleIndex{name,K}, i::I) where {name,K,I<:Integer} = ByValue
index_by(a::SimpleIndex{name,K}, i::AbstractVector{I}) where {name,K,I<:Integer} = ByValue

###
### show
###
function Base.show(io::IO, si::SimpleIndex)
    if isnothing(dimnames(si))
        print(io, "SimpleIndex($(keys(si)))")
    else
        print(io, "SimpleIndex{$(dimnames(si))}($(keys(si)))")
    end
end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

                     @variable(m, -1 <= x[i=1:4] <= 1)

                     @variable(m, -1.3634297333714107 <= q <= -0.20981772159177886)

                     add_NL_constraint(m, :(softplus(-0.25086622252953283 + -0.4158912166699471*softplus(0.18862560740304835 + -0.15744636994779526*softplus(0.5575683410422836 + 0.3104874388021095*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.12330243724213741*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))) + 0.6894873557418655*softplus(0.5818927234969289 + 0.4060546195732435*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.22410021012329473*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4])))) + 0.15556574286983027*softplus(-0.6464546506721769 + -0.3052437329487665*softplus(0.5575683410422836 + 0.3104874388021095*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.12330243724213741*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))) + 0.4287563119683666*softplus(0.5818927234969289 + 0.4060546195732435*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.22410021012329473*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))))) + softplus(-0.9805026843034819 + -0.19393497198753096*softplus(0.18862560740304835 + -0.15744636994779526*softplus(0.5575683410422836 + 0.3104874388021095*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.12330243724213741*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))) + 0.6894873557418655*softplus(0.5818927234969289 + 0.4060546195732435*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.22410021012329473*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4])))) + -0.01642706539433636*softplus(-0.6464546506721769 + -0.3052437329487665*softplus(0.5575683410422836 + 0.3104874388021095*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.12330243724213741*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))) + 0.4287563119683666*softplus(0.5818927234969289 + 0.4060546195732435*softplus(0.8764207742833086 + -0.10444718155116828*$(x[1]) + 0.8852151451027264*$(x[2]) + -0.8060184127084176*$(x[3]) + -0.617200197422199*$(x[4])) + 0.22410021012329473*softplus(0.934307327106453 + 0.477402449923221*$(x[1]) + -0.9131747528764835*$(x[2]) + 0.07837215353953164*$(x[3]) + 0.2564992344946111*$(x[4]))))) - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions