text:
"""
    randomcenters(X, k) -> Vector{Float}

    Return a vector of `k` cluster centers chosen from `X` data matrix.
"""
function randomcenters(X::AbstractMatrix{<:Real}, k::Integer;)
    d, n = size(X)
    i = sample(1:size(X, 2), k)
    return X[:, i]
end

function kmppcenters(
    X::AbstractMatrix{<:Real},
    k::Integer;
    metric::PreMetric = SqEuclidean(),
)
    n = size(X, 2)

    D = eltype(X)
    iseeds = Vector{Int}(undef, k)
    # randomly pick the first center
    p = rand(1:n)
    iseeds[1] = p

    if k > 1
        mincosts = colwise(metric, X, view(X, :, p))
        mincosts[p] = 0

        # pick remaining (with a chance proportional to mincosts)
        tmpcosts = zeros(n)
        for j = 2:k
            p = wsample(1:n, mincosts)
            iseeds[j] = p

            # update mincosts
            c = view(X, :, p)
            colwise!(tmpcosts, metric, X, view(X, :, p))
            updatemin!(mincosts, tmpcosts)
            mincosts[p] = 0
        end
    end

    return X[:, iseeds]
end

"""
    isodata_s(X, k) -> Vector{Float}

    Return a vector of `k` cluster centers calculated from `X` data matrix.
    Starting with one cluster center, this function assigns the data to the clusters,
    then splits the clusters until there are `k` clusters.
"""
function isodata_s(X, k)
    d, n = size(X)
    assignments = Vector{Int}(undef, n)
    centers = randomcenters(X, 1)

    dist = pairwise(Euclidean(), centers, X, dims = 2)
    D = eltype(dist)

    costs = Vector{D}(undef, n)
    counts = Vector{Int}(undef, k)

    while true
        # compute number of clusters
        NROWS = size(centers, 2)

        # assign cluster members
        counts = Vector{Int}(undef, NROWS)
        dist = pairwise(Euclidean(), centers, X, dims = 2)

        update_assignments!(dist, assignments, costs, counts)
        update_centers!(X, assignments, centers, counts)

        # check number of centroids
        if NROWS == k
            return centers
        elseif NROWS > k
            while NROWS > k
                # discard small clusters (fewest assignments), ties broken arbitrarily
                to_delete = findfirst(x -> x ∈ sort(counts)[1:NROWS-k], counts)
                centers = discard([to_delete], centers)
                NROWS = size(centers, 2)

                counts = Vector{Int}(undef, NROWS)
                dist = pairwise(Euclidean(), centers, X, dims = 2)
                update_assignments!(dist, assignments, costs, counts)
                update_centers!(X, assignments, centers, counts)
            end
            return centers
        end

        # split clusters
        sd = Array{D}(undef, d, NROWS)
        update_sd!(X, assignments, centers, counts, sd)

        centers = split!(collect(1:NROWS), centers, sd)
    end

    return centers
end

function updatemin!(r::AbstractArray, x::AbstractArray)
    n = length(r)
    length(x) == n || throw(DimensionMismatch("Inconsistent array lengths."))
    @inbounds for i = 1:n
        xi = x[i]
        if xi < r[i]
            r[i] = xi
        end
    end
    return r
end


text:
export LatticeBond,
       Lattice,
       squareLattice,
       triangularLattice

struct LatticeBond
  s1::Int
  s2::Int
  x1::Float64
  y1::Float64
  x2::Float64
  y2::Float64
  type::String
end

function LatticeBond(s1::Int,s2::Int)
  return LatticeBond(s1,s2,0.0,0.0,0.0,0.0,"")
end

function LatticeBond(s1::Int,s2::Int,
                     x1::Real,y1::Real,
                     x2::Real,y2::Real,
                     bondtype::String="")
  cf(x) = convert(Float64,x)
  return LatticeBond(s1,s2,cf(x1),cf(y1),cf(x2),cf(y2),bondtype)
end

const Lattice = Vector{LatticeBond}

function squareLattice(Nx::Int,
                       Ny::Int;
                       kwargs...)::Lattice
  yperiodic = get(kwargs,:yperiodic,false)
  yperiodic = yperiodic && (Ny > 2)
  N = Nx*Ny
  Nbond = 2N-Ny + (yperiodic ? 0 : -Nx)
  latt = Lattice(undef,Nbond)
  b = 0
  for n=1:N
    x = div(n-1,Ny)+1
    y = mod(n-1,Ny)+1
    if x < Nx
      latt[b+=1] = LatticeBond(n,n+Ny,x,y,x+1,y)
    end
    if Ny > 1
      if y < Ny
        latt[b+=1] = LatticeBond(n,n+1,x,y,x,y+1);
      end
      if yperiodic && y==1
        latt[b+=1] = LatticeBond(n,n+Ny-1,x,y,x,y+Ny)
      end
    end
  end
  return latt
end

function triangularLattice(Nx::Int,
                           Ny::Int;
                           kwargs...)::Lattice
  yperiodic = get(kwargs,:yperiodic,false)
  yperiodic = yperiodic && (Ny > 2)
  N = Nx*Ny
  Nbond = 3N-2Ny + (yperiodic ? 0 : -2Nx+1)
  latt = Lattice(undef,Nbond)
  b = 0
  for n=1:N
    x = div(n-1,Ny)+1
    y = mod(n-1,Ny)+1

    # x-direction bonds
    if x < Nx
      latt[b+=1] = LatticeBond(n,n+Ny)
    end

    # 2d bonds
    if Ny > 1
      # vertical / y-periodic diagonal bond
      if (n+1 <= N) && ((y < Ny) || yperiodic)
        latt[b+=1] = LatticeBond(n,n+1);
      end
      # periodic vertical bond
      if yperiodic && y==1
        latt[b+=1] = LatticeBond(n,n+Ny-1)
      end
      # diagonal bonds
      if x < Nx && y < Ny
        latt[b+=1] = LatticeBond(n,n+Ny+1)
      end
    end
  end
  return latt
end

ext: jl


text:
using DelimitedFiles, ScoreDrivenModels, Statistics

# This is a more advanced example. We want to specify a GARCH model using the GAS framework.
# To that end, we need to overwrite the default link-unlink interface as it would lead to
# a different parametrization.
function ScoreDrivenModels.link!(param_tilde::Matrix{T}, ::Type{Normal}, param::Matrix{T}, t::Int) where T
    param_tilde[t, 1] = link(IdentityLink, param[t, 1])
    param_tilde[t, 2] = link(IdentityLink, param[t, 2])
    return
end
function ScoreDrivenModels.unlink!(param::Matrix{T}, ::Type{Normal}, param_tilde::Matrix{T}, t::Int) where T
    param[t, 1] = unlink(IdentityLink, param_tilde[t, 1])
    param[t, 2] = unlink(IdentityLink, param_tilde[t, 2])
    return
end
function ScoreDrivenModels.jacobian_link!(aux::AuxiliaryLinAlg{T}, ::Type{Normal}, param::Matrix{T}, t::Int) where T
    aux.jac[1] = jacobian_link(IdentityLink, param[t, 1])
    aux.jac[2] = jacobian_link(IdentityLink, param[t, 2])
    return
end

# Load daily German mark/British pound exchange rates data
y = vec(readdlm("../test/data/BG96.csv"))

# Set initial parameters as observed mean and variance of the series
initial_params = [mean(y) var(y)]

# We can set upper and lower bounds for the parameters
ub = [1.0, 1.0, 0.5, 1.0]
lb = [-1.0, 0.0, 0.0, 0.5]

# Specify GAS model: a normal model with time-varying σ and lag 1
gas = Model(1, 1, Normal, 1.0, time_varying_params = [2])

# Set initial point for the optimization
initial_point = [0.0, 0.5, 0.25, 0.75]

# Fit specified model to historical data
f = fit!(
    gas, y;
    initial_params = initial_params,
    opt_method = IPNewton(gas, [initial_point]; ub=ub, lb=lb)
)

# Print estimation statistics
fit_stats(f)


text:
struct Widget
  range::Vector
  index::Int
  label::AbstractString
  type::AbstractString
  datatype::DataType
end

function widget(input_range; value=nothing, label::AbstractString="", type::AbstractString="")
  isa(input_range, Widget) && return input_range
  @assert label != ""

  cur_range = collect(input_range)

  if type == ""
    if all(isa.(cur_range, Number)) && !all(isa.(cur_range, Bool))
      type = "slider"
    else
      if length(cur_range) <= 5
        type = "toggle"
      else
        type = "dropdown"
      end
    end
  end

  @assert isa(cur_range, Array)
  datatype = eltype(cur_range)

  if isnothing(value)
    if all(isa.(cur_range, Number))
      cur_index = Int(ceil( length(cur_range) // 2 ))
    else
      cur_index = 1
    end
  else
    all_indices = findall(cur_value -> cur_value == value, cur_range)

    @assert length(all_indices) == 1
    cur_index = all_indices[1]
  end

  cur_widget = Widget(cur_range, cur_index, label, type, datatype)
  observe!(cur_widget)

  cur_widget
end

get_value(cur_widget::Widget) = cur_widget.range[cur_widget.index]

slider = widget
dropdown = widget

export slider, dropdown


text:
export RedisList

struct RedisList{T} <: AbstractRedisCollection
    conn::AbstractRedisConnection
    key::String

    RedisList{T}(conn, key) where T = if serializeable(T)
        new(conn, key)
    else
        throw(ArgumentError("RedisList currently does not support arbitrary element type"))
    end

    RedisList{T}(key) where T = RedisList{T}(default_connection, key)
end

function getindex(rv::RedisList{T}, index::Int64) where T
    res = exec(rv.conn, "lindex", rv.key, zero_index(index))
    deserialize(T, @some(res))
end

function getindex(rv::RedisList{T}, ::Colon) where T
    res = exec(rv.conn, "lrange", rv.key, 0, -1)
    map(deserialize(T), res)
end

function getindex(rv::RedisList{T}, x::Integer, y::Integer) where T
    res = exec(rv.conn, "lrange", rv.key, zero_index(x), zero_index(y))
    map(deserialize(T), res)
end

function getindex(rv::RedisList, x::UnitRange{<:Integer})
    rv[Int(x.start), Int(x.stop)]
end

function setindex!(rv::RedisList{T}, value, index::Int64) where T
    exec(rv.conn, "lset", rv.key, zero_index(index), serialize(T, value))
end

function collect(rv::RedisList)
    rv[:]
end

function unshift!(rv::RedisList{T}, value) where T
    exec(rv.conn, "lpush", rv.key, serialize(T, value))
    rv
end

"pushfirst!([],1,2,3) will get [1,2,3], which like julia's pushfirst! but contrary to Redis's lpush"
function pushfirst!(rv::RedisList{T}, values...) where T
    values = map(serialize∘T, values) |> reverse
    exec(rv.conn, "lpush", rv.key, values...)
    rv
end

function popfirst!(rv::RedisList{T}) where T
    res = exec(rv.conn, "lpop", rv.key)
    deserialize(T, @some(res))
end

function push!(rv::RedisList{T}, value) where T
    exec(rv.conn, "rpush", rv.key, serialize(T, value))
    rv
end

function push!(rv::RedisList{T}, values...) where T
    values = map(serialize∘T, values)
    exec(rv.conn, "rpush", rv.key, values...)
    rv
end

function pop!(rv::RedisList{T}) where T
    res = exec(rv.conn, "rpop", rv.key)
    deserialize(T, @some(res))
end

function length(rv::RedisList)
    exec(rv.conn, "llen", rv.key)::Int64
end

function lastindex(rv::RedisList)
    length(rv)
end

function size(rv::RedisList)
    (length(rv),)
end

function isempty(rv::RedisList)
    length(rv) == 0
end

function sort(rv::RedisList{T}; rev::Bool=false) where T <: Number
    order = rev ? "desc" : "asc"
    res = exec(rv.conn, "sort", rv.key, order)
    T[deserialize(T, i) for i in res]
end

function sort(rv::RedisList{T}; rev::Bool=false) where T <: AbstractString
    order = rev ? "desc" : "asc"
    res = exec(rv.conn, "sort", rv.key, "alpha", order)
    T[deserialize(T, i) for i in res]
end

function sort!(rv::RedisList{<:Number}; rev::Bool=false)
    order = rev ? "desc" : "asc"
    exec(rv.conn, "sort", rv.key, order, "store", rv.key)::Int64 # returns the length
end

function sort!(rv::RedisList{<:AbstractString}; rev::Bool=false)
    order = rev ? "desc" : "asc"
    exec(rv.conn, "sort", rv.key, "alpha", order, "store", rv.key)::Int64
end

"keep only the first `n` elements of `rv`"
function resize!(rv::RedisList, n::Integer)
    n <= 1 && throw(ArgumentError("n must > 1"))
    exec(rv.conn, "ltrim", rv.key, 0, n-1)
end

"""
iterator batch 12 elements a round.
"""
const BATCHSIZE = 12

function fetch_batch(rv::RedisList, index)
    rv[index:index+BATCHSIZE-1]
end

function iterate(rv::RedisList)
    cache = fetch_batch(rv, 1)
    iterate(rv, (cache, 1, 1+BATCHSIZE))
end

function iterate(rv::RedisList, (cache, ci, index))
    ci > length(cache) && return nothing

    cache[ci], if ci+1 > length(cache)
        cache = fetch_batch(rv, index)
        cache, 1, index + BATCHSIZE
    else
        cache, ci+1, index
    end
end

function eltype(::Type{RedisList{T}}) where T
    T
end


text:
"""
`KernelProduct(kernels::Array{Kernel})`
Create a multiplication of kernels.
One can also use the operator `*`
```
k1 = SqExponentialKernel()
k2 = LinearKernel()
k = KernelProduct([k1,k2])
kernelmatrix(k,X) == kernelmatrix(k1,X).*kernelmatrix(k2,X)
kernelmatrix(k,X) == kernelmatrix(k1*k2,X)
```
"""
struct KernelProduct <: Kernel
    kernels::Vector{Kernel}
end

Base.:*(k1::Kernel,k2::Kernel) = KernelProduct([k1,k2])
Base.:*(k1::KernelProduct,k2::KernelProduct) = KernelProduct(vcat(k1.kernels,k2.kernels)) #TODO Add test
Base.:*(k::Kernel,kp::KernelProduct) = KernelProduct(vcat(k,kp.kernels))
Base.:*(kp::KernelProduct,k::Kernel) = KernelProduct(vcat(kp.kernels,k))

Base.length(k::KernelProduct) = length(k.kernels)

kappa(κ::KernelProduct, x ,y) = prod(kappa(k, x, y) for k in κ.kernels)

hadamard(x,y) = x.*y

function kernelmatrix(
    κ::KernelProduct,
    X::AbstractMatrix;
    obsdim::Int=defaultobs)
    reduce(hadamard,kernelmatrix(κ.kernels[i],X,obsdim=obsdim) for i in 1:length(κ))
end

function kernelmatrix(
    κ::KernelProduct,
    X::AbstractMatrix,
    Y::AbstractMatrix;
    obsdim::Int=defaultobs)
    reduce(hadamard,_kernelmatrix(κ.kernels[i],X,Y,obsdim) for i in 1:length(κ))
end

function kerneldiagmatrix(
    κ::KernelProduct,
    X::AbstractMatrix;
    obsdim::Int=defaultobs) #TODO Add test
    reduce(hadamard,kerneldiagmatrix(κ.kernels[i],X,obsdim=obsdim) for i in 1:length(κ))
end

function Base.show(io::IO,κ::KernelProduct)
    printshifted(io,κ,0)
end

function printshifted(io::IO,κ::KernelProduct, shift::Int)
    print(io,"Product of $(length(κ)) kernels:")
    for i in 1:length(κ)
        print(io,"\n"*("\t"^(shift+1))*"- ")
        printshifted(io,κ.kernels[i],shift+2)
    end
end


text:
# test for unifybase.jl
using Test
#include("utils.jl") # for isinvar()
#include("unifybase.jl")

#unifybase.jl has common functions for naive and dvc

@testset "loop check" begin
 @test loopcheck(:x,:(g(y)))==false
## not happen case: @test loopcheck(:x,:x)==false
 @test_throws Loop loopcheck(:x,:(g(x)))
 @test_throws Loop loopcheck(:x,:(f(a,g(x))))
 @test loopcheck(:x,:(f(g(y),g(h(y)))))==false
 @test_throws Loop loopcheck(:x,:(f(g(a),g(x))))
 @test_throws Loop loopcheck(:x,:(f(g(x),g(x))))
end

@testset "vindex" begin
 @test 0 == vindex([], :a)
 @test 0 == vindex([:x,:y], :a)
 @test 1 == vindex([:x,:y], :x)
 @test 2 == vindex([:x,:y], :y)
end

max_stars_repo_name: sazare/cheapViews

max_issues_repo_name: sazare/cheapViews

max_forks_repo_name: sazare/cheapViews


text:
# RichReportingTestSet extends ReportingTestSet with providing richer
# test output for XUnit
mutable struct RichReportingTestSet <: Test.AbstractTestSet
    reporting_test_set::Ref{Option{ReportingTestSet}}
    flattened_reporting_test_set::Ref{Option{ReportingTestSet}}
    description::AbstractString
    xml_output::String
    html_output::String
    out_buff::IOBuffer
    err_buff::IOBuffer
end

# constructor takes a description string and options keyword arguments
function RichReportingTestSet(
    desc;
    xml_output::String="test-results.xml",
    other_args...
)
    html_output = "$xml_output.html"
    RichReportingTestSet(
        ReportingTestSet(desc),
        nothing,
        desc,
        xml_output,
        html_output,
        IOBuffer(),
        IOBuffer(),
    )
end

function Test.record(rich_ts::RichReportingTestSet, child::AbstractTestSet)
    return Test.record(rich_ts.reporting_test_set[], child)
end
function Test.record(rich_ts::RichReportingTestSet, res::Result)
    return Test.record(rich_ts.reporting_test_set[], res)
end
function Test.finish(rich_ts::RichReportingTestSet)
    # If we are a nested test set, do not print a full summary
    # now - let the parent test set do the printing
    if Test.get_testset_depth() != 0
        # Attach this test set to the parent test set
        parent_ts = get_testset()
        record(parent_ts, rich_ts)
    end

    return rich_ts
end

function TestReports.add_to_ts_default!(
    ts_default::Test.DefaultTestSet, rich_ts::RichReportingTestSet
)
    ts = rich_ts.reporting_test_set[]
    sub_ts = Test.DefaultTestSet(get_description(rich_ts))
    TestReports.add_to_ts_default!.(Ref(sub_ts), ts.results)
    push!(ts_default.results, sub_ts)
end

function TestReports.display_reporting_testset(
    ts::AbstractTestSet;
    throw_on_error::Bool = true,
)
    # show(ts)
    return nothing
end

function TestReports.display_reporting_testset(
    rich_ts::RichReportingTestSet;
    throw_on_error::Bool = true,
)
    ts_default = convert_to_default_testset(rich_ts)
    try
        # Finish the top level testset, to mimick the output from Pkg.test()
        finish(ts_default)
    catch err
        (throw_on_error || has_wrapped_exception(err, InterruptException)) && rethrow()
        # Otherwise, don't want to error here if a test fails or errors, as we just want to
        # display the result and don't care about alerting the caller program about the
        # test failures. This way, we can make sure that printing the test results always
        # happens completely, regardless of the tests having and error/failure or not.
    end
    return nothing
end

function Test.get_test_counts(ts::Union{RichReportingTestSet, AsyncTestSuiteOrTestCase})
    return Test.get_test_counts(convert_to_default_testset(ts))
end

function convert_to_default_testset(ts::AsyncTestSuiteOrTestCase)
    return convert_to_default_testset(ts.testset_report)
end
function convert_to_default_testset(rich_ts::RichReportingTestSet)::DefaultTestSet
    ts = rich_ts.reporting_test_set[]
    return _convert_to_default_testset(get_description(rich_ts), ts.results)
end

function _convert_to_default_testset(description, results)::DefaultTestSet
    # Create top level default testset to hold all results
    ts_default = DefaultTestSet(description)
    Test.push_testset(ts_default)
    TestReports.add_to_ts_default!.(Ref(ts_default), results)
    Test.pop_testset()
    return ts_default
end

function XUnit.convert_to_default_testset(ts::AbstractTestSet)
    return _convert_to_default_testset(get_description(ts), ts.results)
end

function test_out_io()
    ts = get_testset()
    @assert ts isa RichReportingTestSet
    ts.out_buff
end

function test_err_io()
    ts = get_testset()
    @assert ts isa RichReportingTestSet
    ts.err_buff
end

# Gathers per-test output. Should be used instead of `println` if you want to gather any
# output without worrying about multi-threaded execution of tests.
function test_print(input...)
    print(test_out_io(), input...)
end

# Gathers per-test output. Should be used instead of `print` if you want to gather any
# output without worrying about multi-threaded execution of tests.
function test_println(input...)
    println(test_out_io(), input...)
end

include("to-xml.jl")

"""
    html_report(rich_ts::RichReportingTestSet)

Generates an HTML file output for the given testset.

If `show_stdout` is `true`, then it also prints the test output in the standard output.
"""
function html_report(rich_ts::RichReportingTestSet)
    try
        xml_report(rich_ts)

        run(`junit2html $(rich_ts.xml_output)`)

        println("Test results in HTML format: $(rich_ts.html_output)")
    catch e
        @error "Error while producing the HTML report" exception=e
    end

    return rich_ts
end

"""
    function xml_report(rich_ts::RichReportingTestSet)

Generates an xUnit/JUnit-style XML file output for the given testset.
"""
function xml_report(rich_ts::RichReportingTestSet)
    # We are the top level, lets do this
    flatten_results!(rich_ts)

    open(rich_ts.xml_output, "w") do fh
        print(fh, report(rich_ts))
    end
    return rich_ts
end

create_deep_copy(x::Test.Broken) = x
create_deep_copy(x::Test.Pass) = x
create_deep_copy(x::Test.Fail) = x
create_deep_copy(x::Test.Error) = x
create_deep_copy(x::Nothing) = x

function create_deep_copy(ts::RichReportingTestSet)::RichReportingTestSet
    RichReportingTestSet(
        create_deep_copy(ts.reporting_test_set[]),
        create_deep_copy(ts.flattened_reporting_test_set[]),
        get_description(ts),
        ts.xml_output,
        ts.html_output,
        copy(ts.out_buff),
        copy(ts.out_buff),
    )
end

function create_deep_copy(ts::ReportingTestSet)::ReportingTestSet
    return ReportingTestSet(
        get_description(ts),
        map(create_deep_copy, ts.results),
        copy(ts.properties)
    )
end

function flatten_results!(rich_ts::RichReportingTestSet)
    if rich_ts.flattened_reporting_test_set[] === nothing
        rich_ts.flattened_reporting_test_set[] = create_deep_copy(rich_ts.reporting_test_set[])
        ts = rich_ts.flattened_reporting_test_set[]
        # Add any top level Results to their own TestSet
        TestReports.handle_top_level_results!(ts)

        # Flatten all results of top level testset, which should all be testsets now
        rich_ts.flattened_reporting_test_set[].results = vcat(_flatten_results!.(ts.results)...)
    end
    return rich_ts
end

"""
    _flatten_results!(ts::AbstractTestSet)::Vector{<:AbstractTestSet}

Recursively flatten `ts` to a vector of `TestSet`s.
"""
function _flatten_results!(rich_ts::RichReportingTestSet)::Vector{<:AbstractTestSet}
    rich_ts.flattened_reporting_test_set[] = create_deep_copy(rich_ts.reporting_test_set[])
    ts = rich_ts.flattened_reporting_test_set[]
    original_results = ts.results
    flattened_results = AbstractTestSet[]
    # Track results that are a Result so that if there are any, they can be added
    # in their own testset to flattened_results
    results = Result[]

    # Define nested functions
    function inner!(rs::Result)
        # Add to results vector
        push!(results, rs)
    end
    function inner!(childts::AbstractTestSet)
        # Make it a sibling
        TestReports.update_testset_properties!(childts, ts)
        childts.description = get_description(rich_ts) * "/" * get_description(childts)
        push!(flattened_results, childts)
    end

    # Iterate through original_results
    for res in original_results
        children = _flatten_results!(res)
        for child in children
            inner!(child)
        end
    end

    # results will be empty if ts.results only contains testsets
    if !isempty(results)
        # Use same ts to preserve description
        ts.results = results
        push!(flattened_results, rich_ts)
    end
    return flattened_results
end

function _flatten_results!(ts::ReportingTestSet)::Vector{<:AbstractTestSet}
    return TestReports._flatten_results!(ts)
end

"""
    _flatten_results!(rs::Result)

Return vector containing `rs` so that when iterated through,
`rs` is added to the results vector.
"""
_flatten_results!(rs::Result) = [rs]

html_output(rich_ts::RichReportingTestSet) = rich_ts.html_output
xml_output(rich_ts::RichReportingTestSet) = rich_ts.xml_output


text:
module SpinnakerGUI

Base.@kwdef mutable struct sessionStatus
    recording::Bool = false
    bufferedframes::Int64 = 0
    savedframes::Int64 = 0
    terminate::Bool = false
    droppedframes::Int64 = 0
    resolutionupdate::Bool = true
end

include("utils.jl")

# camera settings
include("camera-settings.jl")
cam = nothing
sessionStat = sessionStatus()
camSettings = settings()
camSettingsLimits = settingsLimits()
camGPIO = GPIO()
camGPIOLimits = GPIOLimits()

# Load camera framework
ENV["USE_DUMMYCAM"] = 0
@static if ENV["USE_DUMMYCAM"]=="1"
    include("camera-dummy.jl")
else
    include("camera-spinnaker.jl")
end

# global image buffers
camImage = nothing
camImageFrameBuffer = Vector{Array{UInt8}}(undef,0)

# GUI settings
gui_open = nothing
control_open = true

# performance reporting
perfGrabFramerate = 0.0

include("gui.jl")
include("recording.jl")

function start(;camid::Int64=0,recordthreads=0,reccompression=0)
    global cam, gui_open
    global sessionStat
    global camImageFrameBuffer
    sessionStat.terminate = false
    sessionStat.recording = false
    sessionStat.savedframes = 0
    sessionStat.bufferedframes = 0
    sessionStat.droppedframes = 0
    camImageFrameBuffer = Vector{Array{UInt8}}(undef,0)

    cam = cam_init(camid=camid)

    gui_open = true # Async means you have to assume it's open - could be improved
    # Start gui (operates asynchronously at at ~60 FPS)
    @info "Starting GUI (async)"
    t_gui = @async_errhandle gui(timerInterval=1/60)

    # Start settings updater (operates asynchronously at at ~10 FPS)
    @info "Starting Camera Settings Updater (async)"
    t_settings = @async_errhandle camSettingsUpdater(timerInterval=1/10)

    # Start recording listener
    @info "Starting recording listener (async)"
    t_recorder = @async_errhandle videowritelistener(threads=recordthreads,compression=reccompression)

    # Run camera control with priority
    @info "Starting Camera Acquisition (async)"
    t_capture = @async_errhandle runCamera()

    governorTimer = Timer(0.0, interval = 1)
    while !istaskdone(t_gui) && !istaskdone(t_settings) && !istaskdone(t_recorder) && !istaskdone(t_capture)
        wait(governorTimer)
    end

    if !gui_open && istaskdone(t_gui) && !istaskdone(t_settings) && !istaskdone(t_recorder) && !istaskdone(t_capture)
        # if the gui finished, and nothing else finished
        sessionStat.terminate = true #send terminate bool to async functions

        while !istaskdone(t_gui) || !istaskdone(t_settings) || !istaskdone(t_recorder) || !istaskdone(t_capture)
            wait(Timer(0.1))
        end
        @info "SpinnakerGUI: Successful exit"
    else
        println("") #Async errors cause a lack of new line
        @info "SpinnakerGUI: Something went wrong:"

        istaskdone(t_gui) && @info "GUI crashed"
        istaskdone(t_settings) && @info "Camera settings updater crashed"
        istaskdone(t_recorder) && @info "Record listener crashed"
        istaskdone(t_capture) && @info "Camera acquisition crashed"

        sessionStat.terminate = true
    end
    Spinnaker._release!(cam)
    return nothing
end

export start

end


text:
using BenchmarkTools, CLHMM, MS_HMMBase, Distributions
using StatsFuns: logsumexp
include("mouchet_fns.jl")
import HMMBase:HMM

no_samples=100
nevals=2000
obsl=1000

obs = zeros(Int64, obsl+1,1)
obs[1:obsl] = rand(1:4,obsl)
obs_lengths=[obsl]

π = [.5 .5
.5 .5]
D = [Categorical(ones(4)/4), Categorical([.7,.1,.1,.1])]
m_hmm = HMMBase.HMM(π, D)
ms_hmm = MS_HMMBase.HMM(π,D)

@info "Judging CLHMM.linear_step vs HMMBase.mle_step"
old_step = median(@benchmark (mouchet_mle_step($m_hmm, $obs[1:obsl])))
lin_step = median(@benchmark (linear_step($m_hmm, $obs, $obs_lengths)))
display(judge(old_step,lin_step))

@info "Judging linear_step vs MS"
new_step = median(@benchmark (MS_HMMBase.mle_step($ms_hmm, $obs, $obs_lengths)))
display(judge(new_step,lin_step))

@info "Judging linear_step vs threaded_linear_step"
threaded_step = median(@benchmark (CLHMM.threaded_linear_step($m_hmm, $obs, $obs_lengths)))
display(judge(threaded_step,lin_step))


text:
module ExampleHelpers

using Graphs, Logging, Markdown, Reexport, MetaGraphs, LinearAlgebra
using Bio3DView: viewfile
@reexport using Xtals

include("moiety.jl")

function __init__()
    # list of required files for examples
    required_files = Dict(
        :crystals => ["IRMOF-1.cif", "SIFSIX-2-Cu-i.cif", "IRMOF-1_noH.cif", "UiO-66.cif", "NiPyC_fragment_trouble.cif"],

        :moieties => [
            "2-!-p-phenylene.xyz", "2-acetylamido-p-phenylene.xyz", "1,4-C-phenylene_noH.xyz", "1,4-C-phenylene.xyz", "4-pyridyl.xyz",
            "acetylene.xyz", "BDC.xyz", "disordered_ligand!.xyz", "formate_caps.xyz", "SBU.xyz"
        ]
    )
    rc[:r_tag] = '!'
    rc[:paths][:moieties] = joinpath(rc[:paths][:data], "moieties")
    # make sure directories are present and the right files for the examples
    for file_type in [:moieties, :crystals]
        # make sure directories exist
        if ! isdir(rc[:paths][file_type])
            @warn "$(rc[:paths][file_type]) directory not present; creating it."
            mkpath(rc[:paths][file_type])
        end
        for required_file in required_files[file_type]
            where_it_shld_be = joinpath(rc[:paths][file_type], required_file)
            if ! isfile(where_it_shld_be)
                @warn "$where_it_shld_be not present; copying it from src."
                where_it_is = normpath(joinpath(@__DIR__, "..", "examples", "data", String(file_type), required_file))
                cp(where_it_is, where_it_shld_be)
            end
        end
    end
end

function input_file_message()
    return md"""
!!! note \"input files for the example Pluto notebooks\"
    if the input files required for the example Pluto notebooks are not present in the correct folders, `ExampleHelpers` automatically copies the required input files from the `examples/data` directory of the `PoreMatMod.jl` source code to the folders `rc[:paths][:crystals]` and `rc[:paths][:moieties]`. all input files for the examples are also on Github [here](https://github.com/SimonEnsemble/PoreMatMod.jl/tree/master/examples/data).

    n.b. you may change the folders from which `PoreMatMod.jl` reads input files by setting `rc[:paths][:crystals]` and `rc[:paths][:moieties]` as the desired path. for example, if you desire to store your crystal structures in a folder `~/my_xtals/` (a folder in your home directory), set:
    ```julia
    rc[:paths][:crystals] = joinpath(homedir(), \"my_xtals\").
    ```
"""
end

function xtal_folder_message()
    return md"""
📕 folder from which `PoreMatMod.jl` reads `.cif` files that represent crystal structures:
"""
end

function moiety_folder_message()
    return md"""
📕 folder from which `PoreMatMod.jl` reads `.xyz` files that represent fragments/moities:
"""
end

function fragment_construction_note()
    return md"""
!!! note \"how can we construct the query/replacement fragments?\"
    two options we use: (1) use Avogadro as a molecule builder/editor and export it as `.xyz` or (2) cut the appropriate fragment out of the MOF crystal structure in the `.cif` file using e.g. iRASPA.
"""
end

function write_cif_message()
    return md"""
write the child crystal structure to file for downstream molecular simulations
"""
end

# function to visualize a crystal in the notebook
function view_structure(xtal::Crystal; drop_cross_pb=true)
    # write the box mesh
    write_vtk(xtal.box, "temp_unit_cell.vtk")
    # drop symmetry info and charges
    x = deepcopy(Crystal(xtal.name, xtal.box, xtal.atoms, Charges{Frac}(0), xtal.bonds, Xtals.SymmetryInfo()))
    # drop cross-boundary bonds (they don't render correctly)
    if drop_cross_pb
        # drop the cross-boundary bonds
        drop_cross_pb_bonds!(x)
    end
    write_mol2(x, filename="temp_view.mol2")
    output = nothing
    try
        output = viewfile("temp_view.mol2", "mol2", vtkcell="temp_unit_cell.vtk")
    catch
        output = viewfile("temp_view.mol2", "mol2", vtkcell="temp_unit_cell.vtk", html=true)
    finally
        rm("temp_unit_cell.vtk")
        rm("temp_view.mol2")
    end
    return output
end

# function to visualize a moiety in the notebook
function view_query_or_replacement(filename::String)
    moty = moiety(filename) # load the moiety
    for i in 1:moty.atoms.n # fix H! atom bonding bug (tagged atom covalent radius too large in JMol)
        if moty.atoms.species[i] == :H!
            moty.atoms.species[i] = :He
        end
        if moty.atoms.species[i] == :C!
            moty.atoms.species[i] = :Ne
        end
    end
    # write temporary modified file, view it, and delete it
    filename = joinpath(rc[:paths][:moieties], "temp_" * filename)
    write_xyz(moty, filename)
    output = nothing
    try
        output = viewfile(filename, "xyz")
    catch
        output = viewfile(filename, "xyz", html=true)
    finally
        rm(filename)
    end
    return output
end

# function to print the contents of a moiety file
function display_query_or_replacement_file(filename::String)
    filename = joinpath(rc[:paths][:moieties],
                        filename)

    println("contents of: ", filename, "\n")
    open(filename, "r") do io
        print(read(io, String))
    end
end

export  display_query_or_replacement_file, view_query_or_replacement, view_structure, write_cif_message,
        xtal_folder_message, moiety_folder_message, fragment_construction_note, input_file_message

end


text:
module Copulas
    import Base
    import Random
    import SpecialFunctions
    import GSL
    import Roots
    using Distributions
    using StatsBase
    using TaylorSeries
    import ForwardDiff

    # Standard copulas and stuff.
    include("utils.jl")
    include("Copula.jl")
    include("EmpiricalCopula.jl")
    include("SklarDist.jl")
    export pseudos,
           EmpiricalCopula,
           SklarDist

    # These three distributions might be merged in Distrbutions.jl one day.
    include("univariate_distributions/Sibuya.jl")
    include("univariate_distributions/Logarithmic.jl")
    include("univariate_distributions/AlphaStable.jl")

    # Elliptical copulas
    include("EllipticalCopula.jl")
    include("EllipticalCopulas/GaussianCopula.jl")
    include("EllipticalCopulas/TCopula.jl")
    export GaussianCopula,
           TCopula

    # Archimedean copulas
    include("ArchimedeanCopula.jl")
    include("ArchimedeanCopulas/IndependentCopula.jl")
    include("ArchimedeanCopulas/ClaytonCopula.jl")
    include("ArchimedeanCopulas/JoeCopula.jl")
    include("ArchimedeanCopulas/GumbelCopula.jl")
    include("ArchimedeanCopulas/FrankCopula.jl")
    include("ArchimedeanCopulas/AMHCopula.jl")
    export IndependentCopula,
           ClaytonCopula,
           JoeCopula,
           GumbelCopula,
           FrankCopula,
           AMHCopula

    # Others.
    include("MiscellaneousCopulas/MCopula.jl")
    include("MiscellaneousCopulas/WCopula.jl")
    include("MiscellaneousCopulas/SurvivalCopula.jl")
    export MCopula,
        Wcopula,
        SurvivalCopula

end


text:
module PatentsLens

using Dates
using JSON3
using StructTypes
using Patents

include("lens.jl")

function Patents.ApplicationID(a::LensApplication)
    ApplicationID(
        "lens",
        lensid(a),
        jurisdiction(a),
        docnr(a),
        kind(a),
        date(a)
    )
end

function Patents.ApplicationID(m::Member)
    ApplicationID(
        "lens",
        m.lens_id,
        m.document_id.jurisdiction,
        m.document_id.doc_number,
        m.document_id.kind,
        m.document_id.date
    )
end

function Patents.ApplicationID(p::PatentCitation)
    ApplicationID(
        "lens",
        p.lens_id,
        p.document_id.jurisdiction,
        p.document_id.doc_number,
        p.document_id.kind,
        p.document_id.date
    )
end

function Patents.ApplicationID(p::CitingDoc)
    ApplicationID(
        "lens",
        p.lens_id,
        p.document_id.jurisdiction,
        p.document_id.doc_number,
        p.document_id.kind,
        p.document_id.date
    )
end

function Base.convert(::Type{Application}, a::LensApplication)
    Application(
        ApplicationID(a),
        status(a).patent_status,
        type(a),
        inventors(a),
        applicants(a),
        title(a),
        abstract(a),
        [Claims([first(x.claim_text) for x in c.claims], c.lang) for c in a.claims],
        classification(a),
        [ApplicationID(s) for s in siblings(a)],
        [ApplicationID(c) for c in cites(a)],
        cites_npl(a),
        [ApplicationID(c) for c in citedby(a)],
        family_size_simple(a),
        cites_count(a),
        cites_count_npl(a),
        citedby_count(a)
    )
end

function read(file)
    map(eachline(file)) do l
        lens = JSON3.read(l, LensApplication)
        convert(Application, lens)
    end
end

end


text:
int_rules_5_1_4 = @theory begin

    #= ::Subsection::Closed:: =#
    #= 5.1.4*(f*x)^m*(d+e*x^2)^p*(a+b*arcsin(c*x))^n =#
    @apply_utils Antiderivative((~x * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n')) / (~d + ~(e') * (~x) ^ 2), ~x) => (-1 / ~e) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n * tan(~x), ~x), ~x, asin(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~n, 0))
    @apply_utils Antiderivative((~x * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n')) / (~d + ~(e') * (~x) ^ 2), ~x) => (1 / ~e) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n * cot(~x), ~x), ~x, acos(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~n, 0))
    @apply_utils Antiderivative(~x * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => ((~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (2 * ~e * (~p + 1)) + ((~b * ~n) / (2 * ~c * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && NeQ(~p, -1)))
    @apply_utils Antiderivative(~x * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (2 * ~e * (~p + 1)) - ((~b * ~n) / (2 * ~c * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && NeQ(~p, -1)))
    @apply_utils Antiderivative((~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n') / (~x * (~d + ~(e') * (~x) ^ 2)), ~x) => (1 / ~d) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n / (cos(~x) * sin(~x)), ~x), ~x, asin(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~n, 0))
    @apply_utils Antiderivative((~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n') / (~x * (~d + ~(e') * (~x) ^ 2)), ~x) => (-1 / ~d) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n / (cos(~x) * sin(~x)), ~x), ~x, acos(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~n, 0))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~d * ~f * (~m + 1)) - ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (EqQ(~m + 2 * ~p + 3, 0) && NeQ(~m, -1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~d * ~f * (~m + 1)) + ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (EqQ(~m + 2 * ~p + 3, 0) && NeQ(~m, -1))))
    @apply_utils Antiderivative(((~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x))) / ~x, ~x) => (((~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x))) / (2 * ~p) - ((~b * ~c * (~d) ^ ~p) / (2 * ~p)) * Antiderivative((1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2), ~x)) + ~d * Antiderivative(((~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * asin(~c * ~x))) / ~x, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~p, 0))
    @apply_utils Antiderivative(((~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x))) / ~x, ~x) => ((~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x))) / (2 * ~p) + ((~b * ~c * (~d) ^ ~p) / (2 * ~p)) * Antiderivative((1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2), ~x) + ~d * Antiderivative(((~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * acos(~c * ~x))) / ~x, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~p, 0))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x))) / (~f * (~m + 1)) - ((~b * ~c * (~d) ^ ~p) / (~f * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2), ~x)) - ((2 * ~e * ~p) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * asin(~c * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~p, 0) && ILtQ((~m + 1) / 2, 0)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x))) / (~f * (~m + 1)) + ((~b * ~c * (~d) ^ ~p) / (~f * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2), ~x)) - ((2 * ~e * ~p) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * acos(~c * ~x)), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~p, 0) && ILtQ((~m + 1) / 2, 0)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)), ~x) => With([u = IntHide((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * asin(~c * ~x), u, ~x) - ~b * ~c * Antiderivative(SimplifyIntegrand(u / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~p, 0))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)), ~x) => With([u = IntHide((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * acos(~c * ~x), u, ~x) + ~b * ~c * Antiderivative(SimplifyIntegrand(u / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && IGtQ(~p, 0))
    @apply_utils Antiderivative((~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)), ~x) => With([u = IntHide((~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * asin(~c * ~x), u, ~x) - ~b * ~c * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(SimplifyIntegrand(u / sqrt(~d + ~e * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IntegerQ(~p - 1 / 2) && (NeQ(~p, -1 / 2) && (IGtQ((~m + 1) / 2, 0) || ILtQ((~m + 2 * ~p + 3) / 2, 0)))))
    @apply_utils Antiderivative((~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)), ~x) => With([u = IntHide((~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * acos(~c * ~x), u, ~x) + ~b * ~c * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(SimplifyIntegrand(u / sqrt(~d + ~e * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IntegerQ(~p - 1 / 2) && (NeQ(~p, -1 / 2) && (IGtQ((~m + 1) / 2, 0) || ILtQ((~m + 2 * ~p + 3) / 2, 0)))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * sqrt(~d + ~(e') * (~x) ^ 2) * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~f * (~m + 1)) - ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m + 1) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x)) + ((~c) ^ 2 / ((~f) ^ 2 * (~m + 1))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(((~f * ~x) ^ (~m + 2) * (~a + ~b * asin(~c * ~x)) ^ ~n) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && LtQ(~m, -1)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * sqrt(~d + ~(e') * (~x) ^ 2) * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~f * (~m + 1)) + ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m + 1) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) + ((~c) ^ 2 / ((~f) ^ 2 * (~m + 1))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(((~f * ~x) ^ (~m + 2) * (~a + ~b * acos(~c * ~x)) ^ ~n) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && LtQ(~m, -1)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * sqrt(~d + ~(e') * (~x) ^ 2) * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~f * (~m + 2)) - ((~b * ~c * ~n) / (~f * (~m + 2))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m + 1) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x)) + (1 / (~m + 2)) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(((~f * ~x) ^ ~m * (~a + ~b * asin(~c * ~x)) ^ ~n) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (IGtQ(~m, -2) || EqQ(~n, 1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * sqrt(~d + ~(e') * (~x) ^ 2) * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~f * (~m + 2)) + ((~b * ~c * ~n) / (~f * (~m + 2))) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m + 1) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) + (1 / (~m + 2)) * Simp(sqrt(~d + ~e * (~x) ^ 2) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2)) * Antiderivative(((~f * ~x) ^ ~m * (~a + ~b * acos(~c * ~x)) ^ ~n) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (IGtQ(~m, -2) || EqQ(~n, 1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~f * (~m + 1)) - ((2 * ~e * ~p) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x)) - ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (GtQ(~p, 0) && LtQ(~m, -1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~f * (~m + 1)) - ((2 * ~e * ~p) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x)) + ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (GtQ(~p, 0) && LtQ(~m, -1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~f * (~m + 2 * ~p + 1)) + ((2 * ~d * ~p) / (~m + 2 * ~p + 1)) * Antiderivative((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x)) - ((~b * ~c * ~n) / (~f * (~m + 2 * ~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (GtQ(~p, 0) && Not(LtQ(~m, -1)))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~f * (~m + 2 * ~p + 1)) + ((2 * ~d * ~p) / (~m + 2 * ~p + 1)) * Antiderivative((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p - 1) * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x) + ((~b * ~c * ~n) / (~f * (~m + 2 * ~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (GtQ(~p, 0) && Not(LtQ(~m, -1)))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~d * ~f * (~m + 1)) + (((~c) ^ 2 * (~m + 2 * ~p + 3)) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x)) - ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && ILtQ(~m, -1)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * ~x) ^ (~m + 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~d * ~f * (~m + 1)) + (((~c) ^ 2 * (~m + 2 * ~p + 3)) / ((~f) ^ 2 * (~m + 1))) * Antiderivative((~f * ~x) ^ (~m + 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x) + ((~b * ~c * ~n) / (~f * (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && ILtQ(~m, -1)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * (~f * ~x) ^ (~m - 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (2 * ~e * (~p + 1)) - (((~f) ^ 2 * (~m - 1)) / (2 * ~e * (~p + 1))) * Antiderivative((~f * ~x) ^ (~m - 2) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x)) + ((~b * ~f * ~n) / (2 * ~c * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (LtQ(~p, -1) && IGtQ(~m, 1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * (~f * ~x) ^ (~m - 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (2 * ~e * (~p + 1)) - (((~f) ^ 2 * (~m - 1)) / (2 * ~e * (~p + 1))) * Antiderivative((~f * ~x) ^ (~m - 2) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x)) - ((~b * ~f * ~n) / (2 * ~c * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (LtQ(~p, -1) && IGtQ(~m, 1))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (-((~f * ~x) ^ (~m + 1)) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (2 * ~d * ~f * (~p + 1)) + ((~m + 2 * ~p + 3) / (2 * ~d * (~p + 1))) * Antiderivative((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x) + ((~b * ~c * ~n) / (2 * ~f * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (LtQ(~p, -1) && (Not(GtQ(~m, 1)) && (IntegerQ(~m) || (IntegerQ(~p) || EqQ(~n, 1)))))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((-((~f * ~x) ^ (~m + 1)) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (2 * ~d * ~f * (~p + 1)) + ((~m + 2 * ~p + 3) / (2 * ~d * (~p + 1))) * Antiderivative((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x)) - ((~b * ~c * ~n) / (2 * ~f * (~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (LtQ(~p, -1) && (Not(GtQ(~m, 1)) && (IntegerQ(~m) || (IntegerQ(~p) || EqQ(~n, 1)))))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (~f * (~f * ~x) ^ (~m - 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~e * (~m + 2 * ~p + 1)) + (((~f) ^ 2 * (~m - 1)) / ((~c) ^ 2 * (~m + 2 * ~p + 1))) * Antiderivative((~f * ~x) ^ (~m - 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x) + ((~b * ~f * ~n) / (~c * (~m + 2 * ~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (IGtQ(~m, 1) && NeQ(~m + 2 * ~p + 1, 0))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((~f * (~f * ~x) ^ (~m - 1) * (~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~e * (~m + 2 * ~p + 1)) + (((~f) ^ 2 * (~m - 1)) / ((~c) ^ 2 * (~m + 2 * ~p + 1))) * Antiderivative((~f * ~x) ^ (~m - 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x)) - ((~b * ~f * ~n) / (~c * (~m + 2 * ~p + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p + 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && (IGtQ(~m, 1) && NeQ(~m + 2 * ~p + 1, 0))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~n, ~x) => ((~f * ~x) ^ ~m * sqrt(1 - (~c) ^ 2 * (~x) ^ 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ (~n + 1)) / (~b * ~c * (~n + 1)) - ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (LtQ(~n, -1) && EqQ(~m + 2 * ~p + 1, 0)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~n, ~x) => (-((~f * ~x) ^ ~m) * sqrt(1 - (~c) ^ 2 * (~x) ^ 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ (~n + 1)) / (~b * ~c * (~n + 1)) + ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~p], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (LtQ(~n, -1) && EqQ(~m + 2 * ~p + 1, 0)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~n, ~x) => (((~f * ~x) ^ ~m * sqrt(1 - (~c) ^ 2 * (~x) ^ 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ (~n + 1)) / (~b * ~c * (~n + 1)) - ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n + 1), ~x)) + ((~c * (~m + 2 * ~p + 1)) / (~b * ~f * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * asin(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (LtQ(~n, -1) && (IGtQ(2 * ~p, 0) && (NeQ(~m + 2 * ~p + 1, 0) && IGtQ(~m, -3)))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~n, ~x) => ((-((~f * ~x) ^ ~m) * sqrt(1 - (~c) ^ 2 * (~x) ^ 2) * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ (~n + 1)) / (~b * ~c * (~n + 1)) + ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m - 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n + 1), ~x)) - ((~c * (~m + 2 * ~p + 1)) / (~b * ~f * (~n + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Antiderivative((~f * ~x) ^ (~m + 1) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ (~p - 1 / 2) * (~a + ~b * acos(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (LtQ(~n, -1) && (IGtQ(2 * ~p, 0) && (NeQ(~m + 2 * ~p + 1, 0) && IGtQ(~m, -3)))))
    #= Antiderivative(((~f')*(~x))^(~m')*((~d)+(~e')*(~x)^2)^(~p')*((~a')+(~b')*asin((~c')*(~x)))^(~n),(~x)*Symbol) :=  (f*x)^m*sqrt(1-c^2*x^2)*(d+e*x^2)^p*(a+b*asin(c*x))^(n+1)/(b*c*(n+1) ) - f*m/(b*c*(n+1))*Simp((d+e*x^2)^p/(1-c^2*x^2)^p)*Antiderivative((f*x)^(m-1)*(1- c^2*x^2)^(p+1/2)*(a+b*asin(c*x))^(n+1),x) + c*(2*p+1)/(b*f*(n+1))*Simp((d+e*x^2)^p/(1-c^2*x^2)^p)*Antiderivative((f*x)^(m+ 1)*(1-c^2*x^2)^(p-1/2)*(a+b*asin(c*x))^(n+1),x) <--  FreeQ([a,b,c,d,e,f],x) && EqQ(c^2*d+e,0) && LtQ(n,-1) &&  IntegerQ(2*p) && NeQ(p,-1/2) && IGtQ(m,-3) =#
    #= Antiderivative(((~f')*(~x))^(~m')*((~d)+(~e')*(~x)^2)^(~p')*((~a')+(~b')*acos((~c')*(~x)))^(~n),(~x)*Symbol) :=  -(f*x)^m*sqrt(1-c^2*x^2)*(d+e*x^2)^p*(a+b*acos(c*x))^(n+1)/(b*c*(n+ 1)) + f*m/(b*c*(n+1))*Simp((d+e*x^2)^p/(1-c^2*x^2)^p)*Antiderivative((f*x)^(m-1)*(1- c^2*x^2)^(p+1/2)*(a+b*acos(c*x))^(n+1),x) - c*(2*p+1)/(b*f*(n+1))*Simp((d+e*x^2)^p/(1-c^2*x^2)^p)*Antiderivative((f*x)^(m+ 1)*(1-c^2*x^2)^(p-1/2)*(a+b*acos(c*x))^(n+1),x) <--  FreeQ([a,b,c,d,e,f],x) && EqQ(c^2*d+e,0) && LtQ(n,-1) &&  IntegerQ(2*p) && NeQ(p,-1/2) && IGtQ(m,-3) =#
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~m * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n')) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => (~f * (~f * ~x) ^ (~m - 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * asin(~c * ~x)) ^ ~n) / (~e * ~m) + ((~b * ~f * ~n) / (~c * ~m)) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m - 1) * (~a + ~b * asin(~c * ~x)) ^ (~n - 1), ~x) + (((~f) ^ 2 * (~m - 1)) / ((~c) ^ 2 * ~m)) * Antiderivative(((~f * ~x) ^ (~m - 2) * (~a + ~b * asin(~c * ~x)) ^ ~n) / sqrt(~d + ~e * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && IGtQ(~m, 1)))
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~m * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n')) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => ((~f * (~f * ~x) ^ (~m - 1) * sqrt(~d + ~e * (~x) ^ 2) * (~a + ~b * acos(~c * ~x)) ^ ~n) / (~e * ~m) - ((~b * ~f * ~n) / (~c * ~m)) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m - 1) * (~a + ~b * acos(~c * ~x)) ^ (~n - 1), ~x)) + (((~f) ^ 2 * (~m - 1)) / ((~c) ^ 2 * ~m)) * Antiderivative(((~f * ~x) ^ (~m - 2) * (~a + ~b * acos(~c * ~x)) ^ ~n) / sqrt(~d + ~e * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (GtQ(~n, 0) && IGtQ(~m, 1)))
    @apply_utils Antiderivative(((~x) ^ ~m * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n')) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => (1 / (~c) ^ (~m + 1)) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n * sin(~x) ^ ~m, ~x), ~x, asin(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~n, 0) && IntegerQ(~m)))
    @apply_utils Antiderivative(((~x) ^ ~m * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n')) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => (-1 / (~c) ^ (~m + 1)) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Subst(Antiderivative((~a + ~b * ~x) ^ ~n * cos(~x) ^ ~m, ~x), ~x, acos(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~n, 0) && IntegerQ(~m)))
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~m * (~(a') + ~(b') * asin(~(c') * ~x))) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => ((~f * ~x) ^ (~m + 1) / (~f * (~m + 1))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * (~a + ~b * asin(~c * ~x)) * HypergeometricFunctions._₂F₁(1 / 2, (1 + ~m) / 2, (3 + ~m) / 2, (~c) ^ 2 * (~x) ^ 2) - ((~b * ~c * (~f * ~x) ^ (~m + 2)) / ((~f) ^ 2 * (~m + 1) * (~m + 2))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * HypergeometricPFQ([1, 1 + ~m / 2, 1 + ~m / 2], [3 / 2 + ~m / 2, 2 + ~m / 2], (~c) ^ 2 * (~x) ^ 2) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && Not(IntegerQ(~m)))
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~m * (~(a') + ~(b') * acos(~(c') * ~x))) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => ((~f * ~x) ^ (~m + 1) / (~f * (~m + 1))) * (~a + ~b * acos(~c * ~x)) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * HypergeometricFunctions._₂F₁(1 / 2, (1 + ~m) / 2, (3 + ~m) / 2, (~c) ^ 2 * (~x) ^ 2) + ((~b * ~c * (~f * ~x) ^ (~m + 2)) / ((~f) ^ 2 * (~m + 1) * (~m + 2))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * HypergeometricPFQ([1, 1 + ~m / 2, 1 + ~m / 2], [3 / 2 + ~m / 2, 2 + ~m / 2], (~c) ^ 2 * (~x) ^ 2) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && Not(IntegerQ(~m)))
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~(m') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~n) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => ((~f * ~x) ^ ~m / (~b * ~c * (~n + 1))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * (~a + ~b * asin(~c * ~x)) ^ (~n + 1) - ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m - 1) * (~a + ~b * asin(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && LtQ(~n, -1))
    @apply_utils Antiderivative(((~(f') * ~x) ^ ~(m') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~n) / sqrt(~d + ~(e') * (~x) ^ 2), ~x) => (-((~f * ~x) ^ ~m) / (~b * ~c * (~n + 1))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * (~a + ~b * acos(~c * ~x)) ^ (~n + 1) + ((~f * ~m) / (~b * ~c * (~n + 1))) * Simp(sqrt(1 - (~c) ^ 2 * (~x) ^ 2) / sqrt(~d + ~e * (~x) ^ 2)) * Antiderivative((~f * ~x) ^ (~m - 1) * (~a + ~b * acos(~c * ~x)) ^ (~n + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && LtQ(~n, -1))
    @apply_utils Antiderivative((~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => (1 / (~b * (~c) ^ (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Subst(Antiderivative((~x) ^ ~n * sin(-(~a) / ~b + ~x / ~b) ^ ~m * cos(-(~a) / ~b + ~x / ~b) ^ (2 * ~p + 1), ~x), ~x, ~a + ~b * asin(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~n], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(2 * ~p + 2, 0) && IGtQ(~m, 0)))
    @apply_utils Antiderivative((~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => (-1 / (~b * (~c) ^ (~m + 1))) * Simp((~d + ~e * (~x) ^ 2) ^ ~p / (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~p) * Subst(Antiderivative((~x) ^ ~n * cos(-(~a) / ~b + ~x / ~b) ^ ~m * sin(-(~a) / ~b + ~x / ~b) ^ (2 * ~p + 1), ~x), ~x, ~a + ~b * acos(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~n], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(2 * ~p + 2, 0) && IGtQ(~m, 0)))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => Antiderivative(ExpandIntegrand((~a + ~b * asin(~c * ~x)) ^ ~n / sqrt(~d + ~e * (~x) ^ 2), (~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p + 1 / 2), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~p + 1 / 2, 0) && (Not(IGtQ((~m + 1) / 2, 0)) && (EqQ(~m, -1) || EqQ(~m, -2)))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~m * (~d + ~(e') * (~x) ^ 2) ^ ~p * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => Antiderivative(ExpandIntegrand((~a + ~b * acos(~c * ~x)) ^ ~n / sqrt(~d + ~e * (~x) ^ 2), (~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ (~p + 1 / 2), ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n], ~x) && (EqQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~p + 1 / 2, 0) && (Not(IGtQ((~m + 1) / 2, 0)) && (EqQ(~m, -1) || EqQ(~m, -2)))))
    @apply_utils Antiderivative(~x * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)), ~x) => ((~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * asin(~c * ~x))) / (2 * ~e * (~p + 1)) - ((~b * ~c) / (2 * ~e * (~p + 1))) * Antiderivative((~d + ~e * (~x) ^ 2) ^ (~p + 1) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~p], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && NeQ(~p, -1))
    @apply_utils Antiderivative(~x * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)), ~x) => ((~d + ~e * (~x) ^ 2) ^ (~p + 1) * (~a + ~b * acos(~c * ~x))) / (2 * ~e * (~p + 1)) + ((~b * ~c) / (2 * ~e * (~p + 1))) * Antiderivative((~d + ~e * (~x) ^ 2) ^ (~p + 1) / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~p], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && NeQ(~p, -1))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)), ~x) => With([u = IntHide((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * asin(~c * ~x), u, ~x) - ~b * ~c * Antiderivative(SimplifyIntegrand(u / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && (IntegerQ(~p) && (GtQ(~p, 0) || IGtQ((~m - 1) / 2, 0) && LeQ(~m + ~p, 0))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)), ~x) => With([u = IntHide((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x)], Dist(~a + ~b * acos(~c * ~x), u, ~x) + ~b * ~c * Antiderivative(SimplifyIntegrand(u / sqrt(1 - (~c) ^ 2 * (~x) ^ 2), ~x), ~x)) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && (IntegerQ(~p) && (GtQ(~p, 0) || IGtQ((~m - 1) / 2, 0) && LeQ(~m + ~p, 0))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => Antiderivative(ExpandIntegrand((~a + ~b * asin(~c * ~x)) ^ ~n, (~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~n, 0) && (IntegerQ(~p) && IntegerQ(~m))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => Antiderivative(ExpandIntegrand((~a + ~b * acos(~c * ~x)) ^ ~n, (~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f], ~x) && (NeQ((~c) ^ 2 * ~d + ~e, 0) && (IGtQ(~n, 0) && (IntegerQ(~p) && IntegerQ(~m))))
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => Unintegrable((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n, ~p], ~x)
    @apply_utils Antiderivative((~(f') * ~x) ^ ~(m') * (~d + ~(e') * (~x) ^ 2) ^ ~(p') * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => Unintegrable((~f * ~x) ^ ~m * (~d + ~e * (~x) ^ 2) ^ ~p * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~m, ~n, ~p], ~x)
    @apply_utils Antiderivative((~(h') * ~x) ^ ~(m') * (~d + ~(e') * ~x) ^ ~p * (~f + ~(g') * ~x) ^ ~q * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => ((-((~d) ^ 2) * ~g) / ~e) ^ ~q * Antiderivative((~h * ~x) ^ ~m * (~d + ~e * ~x) ^ (~p - ~q) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~q * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n], ~x) && (EqQ(~e * ~f + ~d * ~g, 0) && (EqQ((~c) ^ 2 * (~d) ^ 2 - (~e) ^ 2, 0) && (HalfIntegerQ(~p, ~q) && (GeQ(~p - ~q, 0) && (GtQ(~d, 0) && LtQ(~g / ~e, 0))))))
    @apply_utils Antiderivative((~(h') * ~x) ^ ~(m') * (~d + ~(e') * ~x) ^ ~p * (~f + ~(g') * ~x) ^ ~q * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((-((~d) ^ 2) * ~g) / ~e) ^ ~q * Antiderivative((~h * ~x) ^ ~m * (~d + ~e * ~x) ^ (~p - ~q) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~q * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n], ~x) && (EqQ(~e * ~f + ~d * ~g, 0) && (EqQ((~c) ^ 2 * (~d) ^ 2 - (~e) ^ 2, 0) && (HalfIntegerQ(~p, ~q) && (GeQ(~p - ~q, 0) && (GtQ(~d, 0) && LtQ(~g / ~e, 0))))))
    @apply_utils Antiderivative((~(h') * ~x) ^ ~(m') * (~d + ~(e') * ~x) ^ ~p * (~f + ~(g') * ~x) ^ ~q * (~(a') + ~(b') * asin(~(c') * ~x)) ^ ~(n'), ~x) => ((((-((~d) ^ 2) * ~g) / ~e) ^ IntPart(~q) * (~d + ~e * ~x) ^ FracPart(~q) * (~f + ~g * ~x) ^ FracPart(~q)) / (1 - (~c) ^ 2 * (~x) ^ 2) ^ FracPart(~q)) * Antiderivative((~h * ~x) ^ ~m * (~d + ~e * ~x) ^ (~p - ~q) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~q * (~a + ~b * asin(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n], ~x) && (EqQ(~e * ~f + ~d * ~g, 0) && (EqQ((~c) ^ 2 * (~d) ^ 2 - (~e) ^ 2, 0) && (HalfIntegerQ(~p, ~q) && GeQ(~p - ~q, 0))))
    @apply_utils Antiderivative((~(h') * ~x) ^ ~(m') * (~d + ~(e') * ~x) ^ ~p * (~f + ~(g') * ~x) ^ ~q * (~(a') + ~(b') * acos(~(c') * ~x)) ^ ~(n'), ~x) => ((((-((~d) ^ 2) * ~g) / ~e) ^ IntPart(~q) * (~d + ~e * ~x) ^ FracPart(~q) * (~f + ~g * ~x) ^ FracPart(~q)) / (1 - (~c) ^ 2 * (~x) ^ 2) ^ FracPart(~q)) * Antiderivative((~h * ~x) ^ ~m * (~d + ~e * ~x) ^ (~p - ~q) * (1 - (~c) ^ 2 * (~x) ^ 2) ^ ~q * (~a + ~b * acos(~c * ~x)) ^ ~n, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n], ~x) && (EqQ(~e * ~f + ~d * ~g, 0) && (EqQ((~c) ^ 2 * (~d) ^ 2 - (~e) ^ 2, 0) && (HalfIntegerQ(~p, ~q) && GeQ(~p - ~q, 0))))
end

max_stars_repo_path: src/rules/5 Inverse trig functions/5.1 Inverse sine/5.1.4 (f x)^m (d+e x^2)^p (a+b arcsin(c x))^n.jl


text:
using SymbolicUtils
using Logging

export integrate

"""
    TowerOfDifferentialFields(Hs) -> K, gs, D

Construct tower of differential fields.

Given `Hs = [H₁,...,Hₙ]` with `Hᵢ` in `C(x,t₁,...,tₙ)` (i.e., they are fractions
of multivariate polynomials in variables `x, t₁,...,tₙ` over a field `C`)
such that `Hᵢ` can be represented as a polynomial in `tᵢ` with coefficients  in `C(x, t₁,...,tᵢ₋₁)` (in particular, `Hᵢ` does not depend on `tᵢ₊₁,...,tₙ`),
return a field `K = C(x)(t₁)...(tₙ)` isomorphic to `C(x, t₁,...,tₙ)` and a derivation `D` on `K` such that
`K` is constructed by iteratively adjoining the indeterminates `x`, `t₁`,...,`tₙ`, `C` is the constant field
of `D`, `D` is `d/dx` on `C(x)`, and `D` is iteratively extended from `C(x)(t₁)...(tᵢ₋₁)` to `C(x)(t₁)...(tᵢ)`
such that `tᵢ` is monomial over `C(x)(t₁)...(tᵢ₋₁)` with `D(tᵢ)=Hᵢ=Hᵢ(x, t₁,....,tᵢ)`.
The generators `x` of C(x) over C and `tᵢ` of `C(x)(t₁)...(tᵢ)` over `C(x)(t₁)...(tᵢ₋₁)` are returned
as `gs=[x, t₁,...,tₙ]`. (Note that these generators, although here denoted by the same symbols for simplicity, are isomorphic but not identical to
the generators `x, t₁,...,tₙ` of `C(x,t₁,...,tₙ)` given implicitely as the variables of the rational functions `Hᵢ`.)

# Example
```julia
R, (x, t1, t2) = PolynomialRing(QQ, [:x, :t1, :t2])
Z = zero(R)//1 # zero element of the fraction field of R
K, gs, D = TowerOfDifferentialFields([t1//x, (t2^2+1)*x*t1 + Z])
```
(Note: by adding `Z` to a polynomial we explicitely transform it to an element of the fraction field.)
"""
function TowerOfDifferentialFields(Hs::Vector{F})  where
    {T<:FieldElement, P<:MPolyElem{T}, F<:FracElem{P}}
    n = length(Hs)
    n>0 || error("height extension tower must be >= 1")
    MF = parent(Hs[1])
    MR = base_ring(MF)
    nvars(MR) == n + 1 || error("number of monmials must be number of variables - 1")
    syms = symbols(MR)
    K = base_ring(MR)
    gs = Any[zero(K) for i=1:n+1]
    Kt, gs[1] = PolynomialRing(K, syms[1])
    D = BasicDerivation(Kt)
    K = FractionField(Kt)
    for i=1:n
        Kt, gs[i+1] = PolynomialRing(K, syms[i+1])
        p = numerator(Hs[i])
        q = denominator(Hs[i])
        maximum(vcat(0, var_index.(vars(p)), var_index.(vars(q)))) <=i+1 ||
            error("Hs[$(i)] may only depend on $(gens(MR)[1:i+1]))")
        H = p(gs...)//q(gs...)
        isone(denominator(H)) ||
            error("Hs[$(i)] must be a polynomial in $(gens(MR[i+1]))")
        H = numerator(H)
        D = ExtensionDerivation(Kt, D, H)
        K = FractionField(Kt)
    end
    K, gs, D
end

"""
    transform_mpoly_to_tower(f, gs) -> f1

Transform elements of `C(x,t₁,...,tₙ)` to elements of `C(x)(t₁)...(tₙ)`.

Given `f` in `C(x,t₁,...,tₙ)` and the generators `gs=[x, t₁,...,tₙ]` as returned by
`TowerOfDifferentialFields`, return the corresponding element `f1` in `C(x)(t₁)...(tₙ)`,

# Example
```
R, (x, t1, t2) = PolynomialRing(QQ, [:x, :t1, :t2])
Z = zero(R)//1 # zero element of the fraction field of R
K, gs, D = TowerOfDifferentialFields([t1//x, (t2^2+1)*x*t1 + Z])
f = (x+t1)//(x+t2)     # element of FractionField(R)
f1 = transform_mpoly_to_tower(f, gs)  # element of K
```
"""
function transform_mpoly_to_tower(f::F, gs::Vector) where
    {T<:FieldElement, P<:MPolyElem{T}, F<:FracElem{P}}
    numerator(f)(gs...)//denominator(f)(gs...)
end

@syms Root(x::qqbar)

to_symb(t::Number) = t

function to_symb(t::Rational)
    if isone(denominator(t))
        return numerator(t)
    else
        return t
    end
end

to_symb(t::fmpq) = to_symb(Rational(t))

function to_symb(t::qqbar)
    if degree(t)==1
        return to_symb(fmpq(t))
    end
    kx, _ = PolynomialRing(Nemo.QQ, :x)
    f = minpoly(kx, t)
    if degree(f)==2 && iszero(coeff(f,1))
        y = to_symb(-coeff(f,0)//coeff(f, 2))
        if y>=0
            if t==maximum(conjugates(t))
                return SymbolicUtils.Term(sqrt,y)
            else
                return -SymbolicUtils.Term(sqrt,y)
            end
        else
            if imag(t)==maximum(imag.(conjugates(t)))
                return SymbolicUtils.Term(sqrt,-y)*1im
            else
                return -SymbolicUtils.Term(sqrt,-y)*1im
            end
        end
    elseif degree(f)==2 # coeff(f,1)!=0
        s = coeff(f, 1)//(2*coeff(f,2))
        return to_symb(t + s) - to_symb(s)
    else
        return Root(t)
    end
end

function height(K::F) where F<:AbstractAlgebra.Field
    0
end

function height(K::F) where
    {T<:FieldElement, P<:PolyElem{T}, F<:FracField{P}}
    height(base_ring(base_ring(K)))+1
end

function height(R::P) where
    {T<:FieldElement, P<:PolyRing{T}}
    height(base_ring(R))+1
end

subst_tower(t::Number, subs::Vector, h::Int=0) = to_symb(t)

subst_tower(t::fmpq, subs::Vector, h::Int=0) = to_symb(t)

subst_tower(t::qqbar, subs::Vector, h::Int=0) = to_symb(t)

function convolution(a::Vector{T}, b::Vector{T}, s::Int; output_size::Int=0) where T<:RingElement
    @assert s==1 || s==-1
    m = length(a)
    n = length(b)
    if m==0 && n==0
        return T[]
    end
    R = m!=0 ? parent(a[1]) : parent(b[1])
    c = zeros(R, output_size<=0 ? max(m, n) : output_size)
    for t = (s==+1 ? 0 : 1):(m-1)
        for k=1:min(m-t, n)
            c[t+1] += a[k+t]*b[k]
        end
    end
    for t=1:n-1
        for k=1:min(m, n-t)
            c[t+1] += s*a[k]*b[k+t]
        end
    end
    c
end

function tan2sincos(f::K, arg::SymbolicUtils.Symbolic, vars::Vector, h::Int=0) where
    {T<:FieldElement, P<:PolyElem{T}, K<:FracElem{P}}
    # This function transforms a Nemo/AbstractAlgebra rational funktion with
    # varibale t representing tan(arg) to a SymbolicUtils expression which is
    # a quotient in which both numerator and denominator are linear combinations
    # of expressions of the form cos(2*j*arg) or sin(2*j*arg) where j is an integer >=0.
    k = base_ring(base_ring(parent(f)))
    kz, I = PolynomialRing(k, :I)
    kI = ResidueField(kz, I^2+1)
    kIE, E = PolynomialRing(kI, :E)
    # I represents sqrt(-1), E represents exp(2*I*arg), so that t = I*(1-E)//(1+E) represents tan(arg)
    t = I*(1 - E)//(1 + E)
    F = numerator(f)(t)//denominator(f)(t)  # F is f as expression in I and E

    # Compute as = [a_1, a_2,...] and bs, cs, ds similarly, such that
    #      ∑_j a_j*E^j + I*∑_j b_j*E^j
    # F = -----------------------------
    #      ∑_j c_j*E^j + I*∑_j d_j*E^j
    as = [coeff(data(c), 0) for c in coefficients(numerator(F))] # = real(numerator(F))
    bs = [coeff(data(c), 1) for c in coefficients(numerator(F))] # = imag(numerator(F))
    cs = [coeff(data(c), 0) for c in coefficients(denominator(F))] # = real(denominator(F))
    ds = [coeff(data(c), 1) for c in coefficients(denominator(F))] # = real(denominator(F))

    # In the above representation of F we multiply both numerator and denominator with
    # the complex conjugate of the denominator ∑_j c_j*E^(-j) - I*∑_j d_j*E^(-j)
    # and take the real part. We obtain a representation of F of the form
    #             ∑_j p_j*cos(2*j*arg) + ∑_j q_j*sin(2*j*arg)
    # real(F) = ----------------------------------------------
    #             ∑_j r_j*cos(2*j*arg) + ∑_j s_j*sin(2*j*arg)
    N = maximum([length(as), length(bs), length(cs), length(ds)])
    ps = convolution(as, cs, +1, output_size=N) + convolution(bs, ds, +1, output_size=N)
    qs = -convolution(bs, cs, -1, output_size=N) + convolution(as, ds, -1, output_size=N)
    rs = convolution(cs, cs, +1, output_size=N) + convolution(ds, ds, +1, output_size=N)
    ss = 2*convolution(cs, ds, -1)

    arg2 = 2*arg
    num = subst_tower(ps[1], vars, h - 1)
    for j=2:length(ps)
        num += subst_tower(ps[j], vars, h - 1)*cos((j - 1)*arg2)
    end
    for j=2:length(qs)
        num += subst_tower(qs[j], vars, h - 1)*sin((j - 1)*arg2)
    end
    den = subst_tower(rs[1], vars, h - 1)
    for j=2:length(rs)
        den += subst_tower(rs[j], vars, h - 1)*cos((j - 1)*arg2)
    end
    for j=2:length(ss)
        den += subst_tower(ss[j], vars, h - 1)*sin((j - 1)*arg2)
    end
    num//den
end

function subst_tower(f::F, vars::Vector, h::Int) where
    {T<:FieldElement, P<:PolyElem{T}, F<:FracElem{P}}
    if isa(vars[h], SymbolicUtils.Term) && operation(vars[h])==tan && !isone(denominator(f))
        return tan2sincos(f, arguments(vars[h])[1], vars, h)
    end
    if isone(denominator(f))
        return subst_tower(numerator(f), vars, h)
    else
        return subst_tower(numerator(f), vars, h)//subst_tower(denominator(f), vars, h)
    end
end

function subst_tower(p::P, vars::Vector, h::Int) where
    {T<:FieldElement, P<:PolyElem{T}}
    if iszero(p)
        return zero(vars[h])
    end
    cs = [subst_tower(c, vars, h - 1) for c in coefficients(p)]
    if isa(vars[h], SymbolicUtils.Term) && operation(vars[h])==exp
        # Write polynomial in exp(a) as sum_i c_i*exp(i*a) instead sum_i c_i*exp(a)^i
        a = arguments(vars[h])[1]
        return sum([cs[i]*(i==1 ? 1 : exp((i - 1)*a)) for i=1:length(cs)])
    else
        return sum([cs[i]*vars[h]^(i - 1) for i=1:length(cs)])
    end
end

function subst_tower(f::F, vars::Vector) where
    {T<:FieldElement, P<:PolyElem{T}, F<:FracElem{P}}
    h = height(parent(f))
    subst_tower(f, vars, h)
end

function subst_tower(p::P, vars::Vector) where
    {T<:FieldElement, P<:PolyElem{T}}
    h = height(parent(p))
    subst_tower(p, vars, h)
end

function subst_tower(t::IdTerm, subs::Vector)
    subst_tower(t.arg, subs)
end

function subst_tower(t::FunctionTerm, subs::Vector)
    subst_tower(t.coeff, subs)*t.op(subst_tower(t.arg, subs))
end

function subst_tower(ts::Vector{Term}, subs::Vector)
    if isempty(ts)
        return 0
    end
    sum([subst_tower(t, subs) for t in ts])
end

struct UpdatedArgList <: Exception end

function analyze_expr(f, x::SymbolicUtils.Sym)
    tanArgs = []
    expArgs = []
    restart = true
    while restart
        funs = Any[x]
        vars = SymbolicUtils.Sym[x]
        args = Any[x]
        try
            p = analyze_expr(f, funs, vars, args, tanArgs, expArgs)
            return p, funs, vars, args
        catch e
            if e isa UpdatedArgList
                restart = true
            else
                rethrow(e)
            end
        end
    end
end

function analyze_expr(f::SymbolicUtils.Sym , funs::Vector, vars::Vector{SymbolicUtils.Sym},
                      args::Vector, tanArgs::Vector, expArgs::Vector)
    if hash(f) != hash(funs[1])
        throw(NotImplementedError("integrand contains unsupported symbol $f different from the integration variable $(funs[1])"))
    end
    return f
end

function analyze_expr(f::Number , funs::Vector, vars::Vector{SymbolicUtils.Sym}, args::Vector, tanArgs::Vector, expArgs::Vector)
    # TODO distinguish types of number (rational, real,  complex, etc. )
    return f
end

function analyze_expr(f::Union{SymbolicUtils.Add, SymbolicUtils.Mul, SymbolicUtils.Div}, funs::Vector,
                      vars::Vector{SymbolicUtils.Sym}, args::Vector, tanArgs::Vector, expArgs::Vector)
    as = arguments(f)
    ps = [analyze_expr(a, funs, vars, args, tanArgs, expArgs) for a in as]
    operation(f)(ps...) # apply f
end

function analyze_expr(f::SymbolicUtils.Pow, funs::Vector, vars::Vector{SymbolicUtils.Sym}, args::Vector, tanArgs::Vector, expArgs::Vector)
    as = arguments(f)
    p1 = analyze_expr(as[1], funs, vars, args, tanArgs, expArgs)
    p2 = analyze_expr(as[2], funs, vars, args, tanArgs, expArgs)
    if isa(p2, Integer)
        return p1^p2
    elseif isa(p2, Number)
        throw(NotImplementedError("integrand contains power with unsupported exponent $p2"))
    end
    exp(p2*log(p1))
end

is_rational_multiple(a, b) = false

is_rational_multiple(a::SymbolicUtils.Mul, b::SymbolicUtils.Mul) =
    a.dict == b.dict && (isa(a.coeff, Integer) || isa(a.coeff, Rational)) &&
                        (isa(b.coeff, Integer) || isa(b.coeff, Rational))

is_rational_multiple(a::SymbolicUtils.Mul, b::SymbolicUtils.Symbolic) =
    (isa(a.coeff, Integer) || isa(a.coeff, Rational)) && (b in keys(a.dict)) && isone(a.dict[b])

is_rational_multiple(a::SymbolicUtils.Symbolic, b::SymbolicUtils.Mul) =
    (isa(b.coeff, Integer) || isa(b.coeff, Rational)) && (a in keys(b.dict)) && isone(b.dict[a])

rational_multiple(a, b) = error("not a rational multiple")

function rational_multiple(a::SymbolicUtils.Mul, b::SymbolicUtils.Mul)
    if !is_rational_multiple(a, b)
        error("not a rational multiple")
    end
    a.coeff//b.coeff
end

function rational_multiple(a::SymbolicUtils.Mul, b::SymbolicUtils.Symbolic)
    if !is_rational_multiple(a, b)
        error("not a rational multiple")
    end
    return a.coeff//1
end

function rational_multiple(a::SymbolicUtils.Symbolic, b::SymbolicUtils.Mul)
    if !is_rational_multiple(a, b)
        error("not a rational multiple")
    end
    return 1//b.coeff
end

function tan_nx(n::Int, x)
    sign_n = sign(n)
    n = abs(n)
    a = zero(x)
    s = +1
    for k=1:2:n
        a += s*binomial(n, k)*tan(x)^k
        s = -s
    end
    b = zero(x)
    s = +1
    for k=0:2:n
        b += s*binomial(n, k)*tan(x)^k
        s = -s
    end
    sign_n*a/b
end

function analyze_expr(f::SymbolicUtils.Term , funs::Vector, vars::Vector{SymbolicUtils.Sym}, args::Vector, tanArgs::Vector, expArgs::Vector)
    op = operation(f)
    a = arguments(f)[1]
    if op == exp
        i = findfirst(x -> is_rational_multiple(a, x), expArgs)
        n = 1
        if i === nothing
            push!(expArgs, a)
        else
            n = rational_multiple(a, expArgs[i])
            if !isone(denominator(n)) # n not an integer
                expArgs[i] = 1//denominator(n)*expArgs[i]
                throw(UpdatedArgList())
            end
            n = numerator(n)
        end
        if n != 1
            f = exp(expArgs[i])^n
            return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
        end
    elseif op==tan
        i = findfirst(x -> is_rational_multiple(a, x), tanArgs)
        n = 1
        if i === nothing
            push!(tanArgs, a)
        else
            n = rational_multiple(a, tanArgs[i])
            if !isone(denominator(n)) # n not an integer
                tanArgs[i] = 1//denominator(n)*tanArgs[i]
                throw(UpdatedArgList())
            end
            n = numerator(n)
        end
        if n != 1
            f = tan_nx(n, tanArgs[i])
            return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
        end
    elseif op == sinh
        f = 1//2*(exp(a) - 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == cosh
        f = 1//2*(exp(a) + 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == csch # 1/sinh
        f = 2/(exp(a) - 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == sech
        f = 2/(exp(a) + 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == tanh
        f = (exp(a) - 1/exp(a))/(exp(a) + 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == coth
        f = (exp(a) + 1/exp(a))/(exp(a) - 1/exp(a))
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == sin # transform to half angle format
        f = 2*tan(1//2*a)/(1 + tan(1//2*a)^2)
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == cos
        f = (1 - tan(1//2*a)^2)/(1 + tan(1//2*a)^2)
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == csc # 1/sin
        f = 1//2*(1 + tan(1//2*a)^2)/tan(1//2*a)
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == sec # 1/cos
        f = (1 + tan(1//2*a)^2)/(1 - tan(1//2*a)^2)
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    elseif op == cot
        f = 1/tan(a)
        return analyze_expr(f, funs, vars, args, tanArgs, expArgs)
    end
    i = findfirst(x -> hash(x)==hash(f), funs)
    if i !== nothing
        return vars[i]
    end
    op in [exp, log, atan, tan] ||
        throw(NotImplementedError("integrand contains unsupported function $op"))
    p = analyze_expr(a, funs, vars, args, tanArgs, expArgs)
    tname = Symbol(:t, length(vars))
    t = SymbolicUtils.Sym{Number, Nothing}(tname, nothing)
    push!(funs, f)
    push!(vars, t)
    push!(args, p)
    t
end

function transform_symtree_to_mpoly(f::SymbolicUtils.Sym, vars::Vector, vars_mpoly::Vector)
    i = findfirst(x -> hash(x)==hash(f), vars)
    @assert i!== nothing
    vars_mpoly[i]
end

transform_symtree_to_mpoly(f::Number, vars::Vector, vars_mpoly::Vector) = f

(F::CalciumQQBarField)(x::Rational) = F(fmpq(x))
Base.promote(x::fmpq, y::MPolyElem{Nemo.qqbar}) = promote(qqbar(x), y)
Base.promote(x::MPolyElem{Nemo.qqbar}, y::fmpq) = promote(x, qqbar(y))

transform_symtree_to_mpoly(f::SymbolicUtils.Add, vars::Vector, vars_mpoly::Vector) =
    sum([transform_symtree_to_mpoly(a, vars, vars_mpoly) for a in arguments(f)])

transform_symtree_to_mpoly(f::SymbolicUtils.Mul, vars::Vector, vars_mpoly::Vector) =
    prod([transform_symtree_to_mpoly(a, vars, vars_mpoly) for a in arguments(f)])

function transform_symtree_to_mpoly(f::SymbolicUtils.Div, vars::Vector, vars_mpoly::Vector)
    as = arguments(f)
    transform_symtree_to_mpoly(as[1], vars, vars_mpoly)//transform_symtree_to_mpoly(as[2], vars, vars_mpoly)
end

function transform_symtree_to_mpoly(f::SymbolicUtils.Pow, vars::Vector, vars_mpoly::Vector)
    as = arguments(f)
    @assert isa(as[2], Integer)
    if as[2]>=0
        return transform_symtree_to_mpoly(as[1], vars, vars_mpoly)^as[2]
    else
        return 1//transform_symtree_to_mpoly(as[1], vars, vars_mpoly)^(-as[2])
    end
end

function TowerOfDifferentialFields(terms::Vector{Term})  where
    {T<:FieldElement, P<:MPolyElem{T}, F<:FracElem{P}}
    n = length(terms)
    MF = parent(terms[1].arg)
    MR = base_ring(MF)
    nvars(MR) == n || error("number of args must be number of variables")
    syms = symbols(MR)
    K = base_ring(MR)
    gs = Any[zero(K) for i=1:n]
    Kt, gs[1] = PolynomialRing(K, syms[1])
    D = BasicDerivation(Kt)
    K = FractionField(Kt)
    for i=2:n
        f = transform_mpoly_to_tower(terms[i].arg, gs) # needs old gs
        Kt, gs[i] = PolynomialRing(K, syms[i])
        t = gs[i]

        op = terms[i].op
        if op == exp
            H = t*D(f)
        elseif op == log
            H = D(f)//f + 0*t
        elseif op == tan
            H = (t^2+1)*D(f)
        elseif op == atan
            H = D(f)//(f^2+1) + 0*t
        else
            @assert false # never reach this point
        end

        if op==log || op==atan
            # Check condition of Theorem 5.1.1
            u, ρ = InFieldDerivative(constant_coefficient(H), D)
            if ρ>0
                #TODO: For this case there is always a remedy
                throw(NotImplementedError("integrand seems to contain logarithms with hidden algebraic dependency"))
            end
        elseif op == exp
            # Check condition of Theorem 5.1.2
            m, u, ρ = InFieldLogarithmicDerivativeOfRadical(coeff(H, 1), D)
            if ρ>0
                #TODO: For this case there is a remedy if m=1 or m=-1
                throw(NotImplementedError("integrand seems to contain exponentials with hidden algebraic dependency"))
            end
        elseif op == tan
            # Check condition of Theorem 5.10.1
            _, I, DI = Complexify(K, D)
            η = I*constant_coefficient(divexact(H, t^2 + 1))
            m, u, ρ = InFieldLogarithmicDerivativeOfRadical(η, DI)
            if ρ>0
                #TODO: For this case there is a remedy if m=1 or m=-1
                throw(NotImplementedError("integrand seems to contain trigonometric functions with hidden algebraic dependency"))
            end
        else
            @assert false # never reach this point
        end

        D = ExtensionDerivation(Kt, D, H)
        K = FractionField(Kt)
    end
    K, gs, D
end

@syms ∫(f, x)

struct AlgebraicNumbersInvolved <: Exception end

function integrate(f::SymbolicUtils.Add, x::SymbolicUtils.Sym; useQQBar::Bool=false,
    catchNotImplementedError::Bool=true, catchAlgorithmFailedError::Bool=true)
    # For efficiency compute integral of sum as sum of integrals
    g = f.coeff*x
    for (h, c) in f.dict
        g += c*integrate(h, x, useQQBar=useQQBar, catchNotImplementedError=catchNotImplementedError,
                         catchAlgorithmFailedError=catchAlgorithmFailedError)
    end
    g
end

function integrate(f::SymbolicUtils.Symbolic, x::SymbolicUtils.Sym; useQQBar::Bool=false,
    catchNotImplementedError::Bool=true, catchAlgorithmFailedError::Bool=true)
    try
        p, funs, vars, args = analyze_expr(f, x)
        if useQQBar
            F = Nemo.QQBar
        else
            F = Nemo.QQ
        end
        R, vars_mpoly = PolynomialRing(F, Symbol.(vars))
        Z = zero(R)//one(R)
        args_mpoly = typeof(Z)[transform_symtree_to_mpoly(a, vars, vars_mpoly) + Z for a in args]
        terms = vcat(IdTerm(args_mpoly[1]), Term[FunctionTerm(operation(funs[i]), 1, args_mpoly[i]) for i=2:length(funs)])
        p_mpoly = transform_symtree_to_mpoly(p, vars, vars_mpoly)
        _, gs, D = TowerOfDifferentialFields(terms)
        p = transform_mpoly_to_tower(p_mpoly + Z, gs)
        try
            g, r, ρ = Integrate(p, D)
            g = subst_tower(g, funs)
            if isa(g, SymbolicUtils.Add)
                g -= g.coeff # remove constant term
            end
            if ρ<=0
                return g + ∫(subst_tower(r, funs), x)
            else
                return g
            end
        catch e
            if e isa AlgebraicNumbersInvolved
                # try again now with algebraic numbers enabled
                return integrate(f, x, useQQBar=true,
                    catchNotImplementedError=catchNotImplementedError,
                    catchAlgorithmFailedError=catchAlgorithmFailedError)
            end
            rethrow(e)
        end
    catch e
        if e isa NotImplementedError
            if catchNotImplementedError
                @warn "NotImplementedError: $(e.msg)"
                return ∫(f, x)
            end
        elseif e isa AlgorithmFailedError
            if catchAlgorithmFailedError
                @warn "AlgorithmFailedError: $(e.msg)"
                return ∫(f, x)
            end
        end
        rethrow(e)
    end
end


text:
using Test
using LinearAlgebra
using Random

using RigidBodyDynamics
using RigidBodyDynamics.Graphs
using RigidBodyDynamics.Contact
using RigidBodyDynamics.PDControl
using Rotations
using StaticArrays

import Base.Iterators: filter
import ForwardDiff
import LightXML

include("test_exports.jl")
include("test_graph.jl")
include("test_custom_collections.jl")
include("test_frames.jl")
include("test_spatial.jl")
include("test_contact.jl")
include("test_urdf.jl")
include("test_double_pendulum.jl")
include("test_caches.jl")
include("test_mechanism_algorithms.jl")
include("test_simulate.jl")
include("test_mechanism_modification.jl")
include("test_pd_control.jl")
include("test_notebooks.jl")

@testset "benchmarks" begin
    @test begin include("../perf/runbenchmarks.jl"); true end
end


text:
# Functional roles

A = [
     false true false false false false;
     false false false true false false;
     false true false false false false;
     false false false false true false;
     false false false false false true;
     false false false false false false
    ]
U = UnipartiteNetwork(A)
L = [1,1,1,2,2,2]
P = Partition(U, L)
n = networkroles(P)

# Values of z
@test n[1,1] ≈ -0.57 atol = 0.02
@test n[2,1] ≈  1.15 atol = 0.02
@test n[3,1] ≈ -0.57 atol = 0.02
@test n[4,1] ≈ -0.57 atol = 0.02
@test n[5,1] ≈  1.15 atol = 0.02
@test n[6,1] ≈ -0.57 atol = 0.02

# Values of c
@test n[1,2] ≈ 0.00 atol = 0.02
@test n[2,2] ≈ 0.45 atol = 0.02
@test n[3,2] ≈ 0.00 atol = 0.02
@test n[4,2] ≈ 0.50 atol = 0.02
@test n[5,2] ≈ 0.00 atol = 0.02
@test n[6,2] ≈ 0.00 atol = 0.02


text:
using BenchmarkTools
using Printf
using Transducers

values = readlines("src/advent/day1/input.txt") |> Map(v -> parse(Int64, v)) |> collect

#########################################

function part1a(v)
    n = length(v)
    for i = 1:n-1, j=i+1:n
        v[i] + v[j] == 2020 && return (v[i] * v[j], v[i], v[j])
    end
    return Tuple{Int64}()
end

function part1b(v)
    n = length(v)
    Iterators.product(v[1:n-1], v[2:n]) |> Filter(x -> sum(x) == 2020) |> Take(1) |> Map(x -> reduce(*, x)) |> only
end

function part1c(v)
    n = length(v)
    Iterators.product(v[1:n-1], v[2:n]) |> Filter(x -> sum(x) == 2020) |> Map(x -> reduce(*, x)) |> first
end

@printf("part1a(values)=%s\n", part1a(values))
@printf("part1b(values)=%s\n", part1b(values))
@printf("part1c(values)=%s\n", part1c(values))

@assert part1a(values)[1] == 913824
@assert part1b(values) == 913824
@assert part1c(values) == 913824

#########################################

function part2a(v)
    n = length(v)
    for i = 1:n-2
        v[i] > 2020 && continue
        for j = i+1:n-1
            v[i] + v[j] > 2020 && continue
            for k = j+1:n
                v[i] + v[j] + v[k] == 2020 && return (v[i] * v[j] * v[k], v[i], v[j], v[k])
            end
        end
    end
    return Tuple{Int64}()
end

function part2b(v)
    n = length(v)
    Iterators.product(v[1:n-2], v[2:n-1], v[3:n]) |> Filter(x -> sum(x) == 2020) |> Take(1) |> Map(x -> reduce(*, x)) |> only
end

function part2c(v)
    n = length(v)
    Iterators.product(v[1:n-2], v[2:n-1], v[3:n]) |> Filter(x -> sum(x) == 2020) |> Map(x -> reduce(*, x)) |> first
end

@printf("part2a(values)=%s\n", part2a(values))
@printf("part2b(values)=%s\n", part2b(values))
@printf("part2c(values)=%s\n", part2c(values))

@assert part2a(values)[1] == 240889536
@assert part2b(values) == 240889536
@assert part2c(values) == 240889536

#########################################

@btime part1a(values);
@btime part1b(values);
@btime part1c(values);
@btime part2a(values);
@btime part2b(values);
@btime part2c(values);