text:
#################################################################
# This file implements a .pomdpx file generator using the
# POMDPs.jl interface.
#################################################################

abstract type AbstractPOMDPXFile end

mutable struct POMDPXFile <: AbstractPOMDPXFile
    file_name::AbstractString
    description::AbstractString

    state_name::AbstractString
    action_name::AbstractString
    reward_name::AbstractString
    obs_name::AbstractString

    initial_belief::Vector{Float64}

    #initial_belief::Vector{Float64} # belief over partially observed vars

    function POMDPXFile(file_name::AbstractString; description::AbstractString="",
                    initial_belief::Vector{Float64}=Float64[])

        if isempty(description)
            description = "This is a pomdpx file for a partially observable MDP"
        end

        self = new()
        self.file_name = file_name
        self.description = description

        self.state_name = "state"
        self.action_name = "action"
        self.reward_name = "reward"
        self.obs_name = "observation"

        self.initial_belief = initial_belief

        return self
    end

end

function Base.write(pomdp::POMDP, pomdpx::AbstractPOMDPXFile)
    file_name = pomdpx.file_name
    description = pomdpx.description
    discount_factor = discount(pomdp)

    # Open file to write to
    out_file = open("$file_name", "w")

    # Header stuff for xml
    write(out_file, "<?xml version='1.0' encoding='ISO-8859-1'?>\n\n\n")
    write(out_file, "<pomdpx version='0.1' id='test' ")
    write(out_file, "xmlns:='http://www.w3.org/2001/XMLSchema-instance' ")
    write(out_file, "xsi:noNamespaceSchemaLocation='pomdpx.xsd'>\n\n\n")

    ############################################################################
    # DESCRIPTION
    ############################################################################
    write(out_file, "\t<Description> $(description)</Description>\n\n\n")

    ############################################################################
    # DISCOUNT
    ############################################################################
    write(out_file, "\t<Discount>$(discount_factor)</Discount>\n\n\n")

    ############################################################################
    # VARIABLES
    ############################################################################
    write(out_file, "\t<Variable>\n")
    # State Variables
    str = state_xml(pomdp, pomdpx)
    write(out_file, str)
    # Action Variables
    str = action_xml(pomdp, pomdpx)
    write(out_file, str)
    # Observation Variables
    str = obs_var_xml(pomdp, pomdpx)
    write(out_file, str)
    # Reward Variable
    str = reward_var_xml(pomdp, pomdpx)
    write(out_file, str)
    write(out_file, "\t</Variable>\n\n\n")

    ############################################################################
    # INITIAL STATE BELIEF
    ############################################################################
    belief_xml(pomdp, pomdpx, out_file)

    ############################################################################
    # STATE TRANSITION FUNCTION
    ############################################################################
    trans_xml(pomdp, pomdpx, out_file)

    ############################################################################
    # OBS FUNCTION
    ############################################################################
    obs_xml(pomdp, pomdpx, out_file)

    ############################################################################
    # REWARD FUNCTION
    ############################################################################
    reward_xml(pomdp, pomdpx, out_file)

    # CLOSE POMDPX TAG AND FILE
    write(out_file, "</pomdpx>")
    close(out_file)
end

############################################################################
# function: state_xml
# input: pomdp model, pomdpx type
# output: string in xml format the defines the state varaibles
############################################################################
function state_xml(pomdp::POMDP, pomdpx::POMDPXFile)
    # defines state vars for a POMDP
    n_s = length(states(pomdp))
    sname = pomdpx.state_name
    str = "\t\t<StateVar vnamePrev=\"$(sname)0\" vnameCurr=\"$(sname)1\" fullyObs=\"false\">\n"
    str = "$(str)\t\t\t<NumValues>$(n_s)</NumValues>\n"
    str = "$(str)\t\t</StateVar>\n\n"
    return str
end
############################################################################

############################################################################
# function: obs_var_xml
# input: pomdp model, pomdpx type
# output: string in xml format the defines the observation varaibles
############################################################################
function obs_var_xml(pomdp::POMDP, pomdpx::AbstractPOMDPXFile)
    # defines observation vars for POMDP and MOMDP
    n_o = length(observations(pomdp))
    oname = pomdpx.obs_name
    str = "\t\t<ObsVar vname=\"$(oname)\">\n"
    str = "$(str)\t\t\t<NumValues>$(n_o)</NumValues>\n"
    str = "$(str)\t\t</ObsVar>\n\n"
    return str
end
############################################################################

############################################################################
# function: action_xml
# input: pomdp model, pomdpx type
# output: string in xml format the defines the action varaibles
############################################################################
function action_xml(pomdp::POMDP, pomdpx::AbstractPOMDPXFile)
    # defines action vars for MDP, POMDP and MOMDP
    n_a = length(actions(pomdp))
    aname = pomdpx.action_name
    str = "\t\t<ActionVar vname=\"$(aname)\">\n"
    str = "$(str)\t\t\t<NumValues>$(n_a)</NumValues>\n"
    str = "$(str)\t\t</ActionVar>\n\n"
    return str
end
############################################################################

############################################################################
# function: reward_var_xml
# input: pomdp model, pomdpx type
# output: string in xml format the defines the reward varaible
############################################################################
function reward_var_xml(pomdp::POMDP, pomdpx::AbstractPOMDPXFile)
    # defines reward var for MDP, POMDP and MOMDP
    rname = pomdpx.reward_name
    str = "\t\t<RewardVar vname=\"$(rname)\"/>\n\n"
    return str
end
############################################################################

############################################################################
# function: belief_xml
# input: pomdp model, pomdpx type, output file
# output: None, writes the initial belief to the output file
############################################################################
function belief_xml(pomdp::POMDP, pomdpx::POMDPXFile, out_file::IOStream)
    belief = pomdpx.initial_belief
    var = pomdpx.state_name
    write(out_file, "\t<InitialStateBelief>\n")
    str = "\t\t<CondProb>\n"
    str = "$(str)\t\t\t<Var>$(var)0</Var>\n"
    str = "$(str)\t\t\t<Parent>null</Parent>\n"
    str = "$(str)\t\t\t<Parameter type = \"TBL\">\n"

    d = initialstate(pomdp)
    for (i, s) in enumerate(ordered_states(pomdp))
        p = pdf(d, s)
        str = "$(str)\t\t\t\t<Entry>\n"
        str = "$(str)\t\t\t\t\t<Instance>s$(i-1)</Instance>\n"
        str = "$(str)\t\t\t\t\t<ProbTable>$(p)</ProbTable>\n"
        str = "$(str)\t\t\t\t</Entry>\n"
    end
    str = "$(str)\t\t\t</Parameter>\n"
    str = "$(str)\t\t</CondProb>\n"
    write(out_file, str)
    write(out_file, "\t</InitialStateBelief>\n\n\n")
end
############################################################################

############################################################################
# function: trans_xml
# input: pomdp model, pomdpx type, output file
# output: None, writes the transition probability table to the output file
############################################################################
function trans_xml(pomdp::POMDP, pomdpx::POMDPXFile, out_file::IOStream)
    pomdp_states = ordered_states(pomdp)
    pomdp_pstates = ordered_states(pomdp)
    acts = ordered_actions(pomdp)

    aname = pomdpx.action_name
    var = pomdpx.state_name

    write(out_file, "\t<StateTransitionFunction>\n")
    str = "\t\t<CondProb>\n"
    str = "$(str)\t\t\t<Var>$(var)1</Var>\n"
    str = "$(str)\t\t\t<Parent>$(aname) $(var)0</Parent>\n"
    str = "$(str)\t\t\t<Parameter>\n"
    write(out_file, str)
    for (i, s) in enumerate(pomdp_states)
        if isterminal(pomdp, s) # if terminal, just remain in the same state
            str = "\t\t\t\t<Entry>\n"
            str = "$(str)\t\t\t\t\t<Instance>* s$(i-1) s$(i-1)</Instance>\n"
            str = "$(str)\t\t\t\t\t<ProbTable>1.0</ProbTable>\n"
            str = "$(str)\t\t\t\t</Entry>\n"
            write(out_file, str)
        else
            for (ai, a) in enumerate(acts)
                d = transition(pomdp, s, a)
                for (j, sp) in enumerate(pomdp_pstates)
                    p = pdf(d, sp)
                    if p > 0.0
                        str = "\t\t\t\t<Entry>\n"
                        str = "$(str)\t\t\t\t\t<Instance>a$(ai-1) s$(i-1) s$(j-1)</Instance>\n"
                        str = "$(str)\t\t\t\t\t<ProbTable>$(p)</ProbTable>\n"
                        str = "$(str)\t\t\t\t</Entry>\n"
                        write(out_file, str)
                    end
                end
            end
        end
    end
    str = "\t\t\t</Parameter>\n"
    str = "$(str)\t\t</CondProb>\n"
    write(out_file, str)
    write(out_file, "\t</StateTransitionFunction>\n\n\n")
    return nothing
end
############################################################################

############################################################################
# function: obs_xml
# input: pomdp model, pomdpx type, output file
# output: None, writes the observation probability table to the output file
############################################################################
function obs_xml(pomdp::POMDP, pomdpx::POMDPXFile, out_file::IOStream)
    pomdp_states = ordered_states(pomdp)
    acts = ordered_actions(pomdp)
    obs = ordered_observations(pomdp)

    aname = pomdpx.action_name
    oname = pomdpx.obs_name
    var = pomdpx.state_name

    write(out_file, "\t<ObsFunction>\n")
    str = "\t\t<CondProb>\n"
    str = "$(str)\t\t\t<Var>$(oname)</Var>\n"
    str = "$(str)\t\t\t<Parent>$(aname) $(var)1</Parent>\n"
    str = "$(str)\t\t\t<Parameter>\n"
    write(out_file, str)

    try observation(pomdp, first(acts), first(pomdp_states))
    catch ex
        if ex isa MethodError
            @warn("""POMDPXFiles only supports observation distributions conditioned on a and sp.

                  Check that there is an `observation(::M, ::A, ::S)` method available (or an (::A, ::S) method of the observation function for a QuickPOMDP).

                  This warning is designed to give a helpful hint to fix errors, but may not always be relevant.
                  """, M=typeof(pomdp), S=typeof(first(pomdp_states)), A=typeof(first(acts)))
        end
        rethrow(ex)
    end

    for (i, s) in enumerate(pomdp_states)
        for (ai, a) in enumerate(acts)
            d = observation(pomdp, a, s)
            for (oi, o) in enumerate(obs)
                p = pdf(d, o)
                if p > 0.0
                    str = "\t\t\t\t<Entry>\n"
                    str = "$(str)\t\t\t\t\t<Instance>a$(ai-1) s$(i-1) o$(oi-1)</Instance>\n"
                    str = "$(str)\t\t\t\t\t<ProbTable>$(p)</ProbTable>\n"
                    str = "$(str)\t\t\t\t</Entry>\n"
                    write(out_file, str)
                end
            end
        end
    end
    write(out_file, "\t\t\t</Parameter>\n")
    write(out_file, "\t\t</CondProb>\n")
    write(out_file, "\t</ObsFunction>\n")
end
############################################################################

############################################################################
# function: reward_xml
# input: pomdp model, pomdpx type, output file
# output: None, writes the reward function to the output file
############################################################################
function reward_xml(pomdp::POMDP, pomdpx::POMDPXFile, out_file::IOStream)
    pomdp_states = ordered_states(pomdp)
    acts = ordered_actions(pomdp)
    rew = StateActionReward(pomdp)

    aname = pomdpx.action_name
    var = pomdpx.state_name
    rname = pomdpx.reward_name

    write(out_file, "\t<RewardFunction>\n")
    str = "\t\t<Func>\n"
    str = "$(str)\t\t\t<Var>$(rname)</Var>\n"
    str = "$(str)\t\t\t<Parent>$(aname) $(var)0</Parent>\n"
    str = "$(str)\t\t\t<Parameter>\n"
    write(out_file, str)

    for (i, s) in enumerate(pomdp_states)
        if !isterminal(pomdp, s)
            for (ai, a) in enumerate(acts)
                r = rew(s, a)
                str = "\t\t\t\t<Entry>\n"
                str = "$(str)\t\t\t\t\t<Instance>a$(ai-1) s$(i-1)</Instance>\n"
                str = "$(str)\t\t\t\t\t<ValueTable>$(r)</ValueTable>\n"
                str = "$(str)\t\t\t\t</Entry>\n"
                write(out_file, str)
            end
        end
    end

    write(out_file, "\t\t\t</Parameter>\n\t\t</Func>\n")
    write(out_file, "\t</RewardFunction>\n\n")
end
############################################################################


text:
using Distributions;
using NLsolve;
using ForwardDiff;

include(joinpath(@__DIR__, "dipole_response.jl"));

ϕ_dist = Uniform(0.0, 2*π);

# the way that the energy functions are organized is a mess; I'm sorry
# also... not sorry
abstract type Energy end

mutable struct EAPChain
  b::Float64;
  E0::Float64;
  μ::DipoleResponse;
  UFunction::Energy;
  kT::Float64;
  Fz::Float64;
  Fx::Float64;
  ϕs::FdVector;
  cϕs::FdVector;
  sϕs::FdVector;
  n̂s::FdMatrix;
  μs::FdMatrix;
  us::FdVector;
  xs::FdMatrix;
  r::FdVector;
  U::Float64;
end

@inline n(chain::EAPChain) = length(chain.ϕs);

@inline n̂(cϕ, sϕ) = [cϕ; sϕ];

@inline n̂j(chain::EAPChain, idx::Int) = n̂(chain.cϕs[idx], chain.sϕs[idx]);

function update_xs!(chain::EAPChain, idx::Int)
  @warn "This implementation of update_xs! is generally slower than the vectorized implementation";
  if idx == 1
    @inbounds chain.xs[:, idx] = chain.b / 2 * n̂j(chain, idx);
    idx += 1;
  end
  for i=idx:n(chain)
    @inbounds chain.xs[:, i] = (chain.xs[:, i-1] +
                                chain.b / 2 * (n̂j(chain, i) + n̂j(chain, i-1)));
  end
end

@inline function update_xs!(chain::EAPChain)
  chain.xs[:, :] = chain.b*(cumsum(chain.n̂s, dims=2) - 0.5*chain.n̂s);
end

#=
function update_xs!(chain::EAPChain)
  @show chain.n̂s
  @show cumsum(chain.n̂s, dims=2);
  @show (cumsum(chain.n̂s, dims=2) - 0.5*chain.n̂s);
  idx = rand(1:n(chain));
  @assert(dot(chain.n̂s[:, idx], chain.n̂s[:, idx]) ≈ 1.0);
  chain.xs[:, :] = chain.b*(cumsum(chain.n̂s, dims=2) - 0.5*chain.n̂s);
end
=#

@inline u(E0::Real, μ::FdVector) = -1/2*E0*μ[1];

function EAPChain(pargs::Dict)
  ϕs = rand(ϕ_dist, pargs["num-monomers"]);

  dr = if pargs["chain-type"] == "dielectric"
    DielectricResponse(pargs["K1"], pargs["K2"]);
  elseif pargs["chain-type"] == "polar"
    PolarResponse(pargs["mu"] * [1.0 0.0; 0.0 1.0]);
  else
    error("chain-type is not understood.");
  end

  ret =  EAPChain(
                  pargs["mlen"],
                  pargs["E0"],
                  dr,
                  if pargs["energy-type"] == "noninteracting"
                    NonInteractingEnergy();
                  elseif pargs["energy-type"] == "interacting"
                    InteractingEnergy();
                  elseif pargs["energy-type"] == "Ising"
                    IsingEnergy();
                  else
                    error("energy-type is not understood.");
                  end,
                  pargs["kT"],
                  pargs["Fz"],
                  pargs["Fx"],
                  ϕs,
                  map(cos, ϕs),
                  map(sin, ϕs),
                  zeros(2, pargs["num-monomers"]),
                  zeros(2, pargs["num-monomers"]),
                  zeros(pargs["num-monomers"]),
                  zeros(2, pargs["num-monomers"]),
                  zeros(2),
                  0.0
                 );
  ret.n̂s[:, :] = hcat(map(j -> n̂j(ret, j), 1:n(ret))...);
  @simd for i=1:n(ret)
    @inbounds ret.μs[:, i] = dr(ret.E0, ret.cϕs[i], ret.sϕs[i]);
  end
  ret.us[:] = map(i -> u(ret.E0, view(ret.μs, :, i)), 1:n(ret));
  update_xs!(ret);
  ret.r[:] = end_to_end(ret);
  ret.U = U(ret);
  return ret;
end

function EAPChain(chain::EAPChain)
  return EAPChain(
                  chain.b,
                  chain.E0,
                  chain.μ,
                  chain.UFunction,
                  chain.kT,
                  chain.Fz,
                  chain.Fx,
                  chain.ϕs[:],
                  chain.cϕs[:],
                  chain.sϕs[:],
                  chain.n̂s[:, :],
                  chain.μs[:, :],
                  chain.us[:],
                  chain.xs[:, :],
                  chain.r[:],
                  chain.U
                 );
end

# TODO: consider rewriting this to make better use of past calculations
# this is probably by far the slowest calculation *shrug emoji*
function U_interaction(chain::EAPChain)
  U = 0.0;
  @inbounds for i=1:n(chain)
    @simd for j=i+1:n(chain) # once debugged, use inbounds
      r = chain.xs[:, i] - chain.xs[:, j];
      r2 = dot(r, r);
      rmag = sqrt(r2);
      r̂ = r / rmag;
      r3 = r2*rmag;
      μi = view(chain.μs, :, i);
      μj = view(chain.μs, :, j);
      U += (dot(μi, μj) - 3*dot(μi, r̂)*dot(μj, r̂)) / (4*π*r3);
    end
  end
  return U;
end

# TODO: consider rewriting this to make better use of past calculations
# this is probably by far the slowest calculation *shrug emoji*
function U_Ising(chain::EAPChain)
  U = 0.0;
  @inbounds for i=1:n(chain)-1
    r = chain.xs[:, i] - chain.xs[:, i+1];
    r2 = dot(r, r);
    rmag = sqrt(r2);
    r̂ = r / rmag;
    r3 = r2*rmag;
    μi = view(chain.μs, :, i);
    μj = view(chain.μs, :, i+1);
    U += (dot(μi, μj) - 3*dot(μi, r̂)*dot(μj, r̂)) / (4*π*r3);
  end
  return U;
end

function move!(chain::EAPChain, idx::Int, dϕ::Real)
  @inbounds begin
    chain.ϕs[idx] += dϕ;
    chain.cϕs[idx] = cos(chain.ϕs[idx]);
    chain.sϕs[idx] = sin(chain.ϕs[idx]);

    # the order of these updates is important
    chain.n̂s[:, idx] = n̂j(chain, idx);
    chain.μs[:, idx] = chain.μ(chain.E0, chain.cϕs[idx], chain.sϕs[idx]);
    chain.us[idx] = u(chain.E0, view(chain.μs, :, idx));
    update_xs!(chain);
    chain.r[:] = end_to_end(chain);
    chain.U = U(chain);
  end
  return true;
end

function flip_n!(chain::EAPChain, idx::Int)
  move!(chain, idx, π)
end

pflip_linear(ip::Real) = (1 + ip) / 2;

function cluster_flip!(chain::EAPChain, idx::Int;
                       pflip::Function = pflip_linear,
                       ϵflip::Real = 1.0,
                       ηerr::Real = 1e-10
                      )

  # grow the cluster to the right
  upper_p = NaN;
  upper_idx = idx;
  while true
    if upper_idx >= n(chain)
      upper_p = 0.0;
      break;
    end
    upper_p = pflip_linear(dot(n̂j(chain, upper_idx), n̂j(chain, upper_idx+1)));
    if rand() <= upper_p
      upper_idx += 1
    else
      break;
    end
  end
  @assert(!isnan(upper_p) && upper_idx <= n(chain));

  # grow the cluster to the left
  lower_p = NaN;
  lower_idx = idx;
  while true
    if lower_idx <= 1
      lower_p = 0.0;
      break;
    end
    lower_p = pflip_linear(dot(n̂j(chain, lower_idx), n̂j(chain, lower_idx-1)));
    if rand() <= lower_p
      lower_idx -= 1
    else
      break;
    end
  end
  @assert(!isnan(lower_p) && lower_idx >= 1);

  if rand() <= ϵflip
    prev_n̂s = copy(chain.n̂s[:, lower_idx:upper_idx]);
    for i in lower_idx:upper_idx
      flip_n!(chain, i);
    end

    if norm(prev_n̂s + chain.n̂s[:, lower_idx:upper_idx], Inf) > ηerr
      println("prev");
      display(prev_n̂s)
      println();
      println("curr");
      display(chain.n̂s[:, lower_idx:upper_idx])
      println();
      @show(norm(prev_n̂s + chain.n̂s[:, lower_idx:upper_idx], Inf))
    end
    @assert(norm(prev_n̂s + chain.n̂s[:, lower_idx:upper_idx], Inf) < ηerr);

    new_upper_p = if upper_idx < n(chain)
      pflip_linear(dot(n̂j(chain, upper_idx), n̂j(chain, upper_idx+1)));
    else
      0
    end
    new_lower_p = if lower_idx > 1
      pflip_linear(dot(n̂j(chain, lower_idx), n̂j(chain, lower_idx-1)));
    else
      0
    end
    return (
             ((1 - new_upper_p)*(1 - new_lower_p)) /
             ((1 - upper_p)*(1 - lower_p))
            );
  else
    return 1.0;
  end

end

@inline end_to_end(chain::EAPChain) = @inbounds (chain.xs[:, end] +
                                                 chain.b/2.0*n̂j(chain, n(chain)));

@inline chain_μ(chain::EAPChain) = reshape(sum(chain.μs, dims=2), 2);

include(joinpath(@__DIR__, "energy.jl"));
@inline U(chain::EAPChain) = chain.UFunction(chain); # forward energy call to chain

ext: jl

max_stars_repo_name: grasingerm/polymer-stats

max_issues_repo_name: grasingerm/polymer-stats

max_forks_repo_name: grasingerm/polymer-stats


text:
approximate(state,toapprox,alg::Union{Dmrg,Dmrg2},envs...) = approximate!(copy(state),toapprox,alg,envs...)

function approximate!(init::Union{MPSComoving,FiniteMPS},sq,alg,envs=environments(init,sq))
    tor =  approximate!(init,[sq],alg,[envs]);
    return (tor[1],tor[2][1],tor[3])
end

function approximate!(init::Union{MPSComoving,FiniteMPS},squash::Vector,alg::Dmrg2,envs=[environments(init,sq) for sq in squash])

    tol=alg.tol;maxiter=alg.maxiter
    iter = 0; delta = 2*tol

    while iter < maxiter && delta > tol
        delta = 0.0

        (init,envs) = alg.finalize(iter,init,squash,envs)::Tuple{typeof(init),typeof(envs)};

        for pos=[1:(length(init)-1);length(init)-2:-1:1]
            ac2 = init.AC[pos]*_transpose_tail(init.AR[pos+1]);

            nac2 = sum(map(zip(squash,envs)) do (sq,pr)
                ac2_proj(pos,init,pr)
            end)

            (al,c,ar) = tsvd(nac2,trunc=alg.trscheme)

            delta = max(delta,norm(al*c*ar-ac2)/norm(ac2));

            init.AC[pos] = (al,complex(c))
            init.AC[pos+1] = (complex(c),_transpose_front(ar));
        end

        alg.verbose && @info "2site dmrg iter $(iter) error $(delta)"

        #finalize
        iter += 1
    end

    delta > tol && @warn "2site dmrg failed to converge $(delta)>$(tol)"
    return init,envs,delta
end

function approximate!(init::Union{MPSComoving,FiniteMPS}, squash::Vector,alg::Dmrg,envs = [environments(init,sq) for sq in squash])

    tol=alg.tol;maxiter=alg.maxiter
    iter = 0; delta = 2*tol

    while iter < maxiter && delta > tol
        delta=0.0

        #finalize
        (init,envs) = alg.finalize(iter,init,squash,envs)::Tuple{typeof(init),typeof(envs)};

        for pos = [1:(length(init)-1);length(init):-1:2]
            newac = sum(map(zip(squash,envs)) do (sq,pr)
                ac_proj(pos,init,pr)
            end)

            delta = max(delta,norm(newac-init.AC[pos])/norm(newac))

            init.AC[pos] = newac
        end

        alg.verbose && @info "dmrg iter $(iter) error $(delta)"

        iter += 1
    end

    delta > tol && @warn "dmrg failed to converge $(delta)>$(tol)"
    return init,envs,delta
end


text:
using Experiment
using Test

@testset "Experiment.jl" begin
    ## 测试读取数据是否出错
    M = MicrophoneParameter("线路输入 (LIS_MIIS_8X8_192K)", 44100, 30, 4);
    hardware = M(:MATLAB);
    data = getdata(hardware, ishilbert = true);

    ## 测试过备原子基生成, 全部ok，但是二维会有181*181个基
    ##窄带情况都无法满足，宽带情况更加无法时间要求
    l1 = linear1(0.17, 4);
    l2 = linear2(0.17, 0.1, 4, 4);
    C = circle(4, 0.17);

    Al1 = A_matrix((0.0, 90.0), [0.17], 0.5*pi/180, l1, 1);
    Al2 = A_matrix((0.0, 90.0, 0.0, 90.0), [0.17], [0.5*pi/180; 0.5*pi/180], l2, 2);
    Al3 = A_matrix((0.0, 90.0, 0.0, 90.0), [0.17], [0.5*pi/180; 0.5*pi/180], C, 2);

    A1 = Al1();
    A2 = Al2();
    A3 = Al3();
    ##函数测试全部ok
    x = randn(1000,10);
    xx = add_gaussian_noise(x, 20.0, dims = 1);
    xxx = hilbert(x, dims = 1);

    find_fft_peak(x[:,1], 44100, 0.01);
    find_fft_peak(x[:,2], 44100, 3);

    ##测试solver函数
    P1 = Position(data', A1, 1, :svd_l1!);
    # P2 = Position(data', A2, 2, :svd_l1!);
    P3 = Position(data', A3, 2, :svd_l1!);

    solver(P1,true);
    solver(P3, true);

end

@testset "plot position" begin

end


text:
function portfolios_hillclimb(thePortfolio::SparsePortfolioData, indices_new::Array{Int64,1})

  L=1e1 #Note that this parameter should be tuned by the user if the warm-start isn't performing well
  λ=0.0
  iter=0
  indices = []
  α = zeros(thePortfolio.f)
  βl= zeros(size(thePortfolio.A, 1))
  βu= copy(βl)
  ρ=zeros(thePortfolio.n)

  SoRCoeff=1.7 # Improves performance of the method.

  while (iter < 20 || indices != indices_new && iter<=50)
    iter = iter+1
    indices = indices_new
    # Maximize over α for a given s
    dual_vars= inner_dual(thePortfolio, indices)
    ρ_full=zeros(thePortfolio.n)
    ρ_full[indices]=copy(dual_vars.ρ)
    # Averaging
    α = (α*(iter-SoRCoeff) + SoRCoeff*dual_vars.α)/iter
    λ = (λ*(iter-SoRCoeff) + SoRCoeff*dual_vars.λ)/iter
    βl= (βl*(iter-SoRCoeff) + SoRCoeff*dual_vars.βl)/iter
    βu= (βu*(iter-SoRCoeff) + SoRCoeff*dual_vars.βu)/iter
    ρ = (ρ*(iter-SoRCoeff) + SoRCoeff*ρ_full)/iter
    # Maximize over s for a given set of dual variables
    # Using a discrete first-order heuristic (see Bertsekas 1999, Bertsimas and King 2015, among others).

    p = -(thePortfolio.γ'/2.0).*(α'thePortfolio.X+(βl-βu)'*thePortfolio.A+λ*fill(1.0, thePortfolio.n)'+ρ'-thePortfolio.d').^2+(thePortfolio.min_investment.*ρ)' #technically speaking we should be using w, since w>=..., but this is a heuristic, so this doesn't affect correctness/performance
    w = (thePortfolio.γ[indices]).*(thePortfolio.X[:, indices]'*α+thePortfolio.A[:, indices]'*(βl-βu)+λ*fill(1.0, size(indices, 1))+ρ[indices]-thePortfolio.d[indices])
    x=fill(0.0,thePortfolio.n)
    x[indices]= w'
    indices_new = sort(sortperm((abs.(x'-(1/L)*p)[1:end]), rev=true)[1:thePortfolio.k]) # drops additional values past k here (e.g. if called by heuristiccallback and cplex wants k+1 nonzero)
    # Clean solution if infeasible due to min_investment constraints.
    while sum(thePortfolio.min_investment[indices_new])>1.0
      index=rand(indices_new)
      indices_new=filter(e->e≠index, indices_new)
    end
  end

  dual_vars= inner_dual(thePortfolio, indices_new)
  return indices_new, thePortfolio.γ'.*dual_vars.w
end


text:
export CGPFunctions

module CGPFunctions
using Statistics

global arity = Dict()

SorX = Union{Symbol, Expr}

function scaled(x::Float64)
    if isnan(x)
        return 0.0
    end
    min(max(x, -1.0), 1.0)
end

function fgen(name::Symbol, ar::Int, s1::SorX; safe::Bool=false)
    if safe
        @eval function $name(arr::AbstractArray, x::Int16, y::Int16, p::Array{Float64,1}=Float64[])::Float64
            try
                return $s1
            catch
                return x
            end
        end
    else
        @eval function $name(arr::AbstractArray, x::Int16, y::Int16, p::Array{Float64,1}=Float64[])::Float64
            $s1
        end
    end
    arity[String(name)] = ar
end

# Mathematical
fgen(:f_add, 2, :((arr[x] + arr[y]) / 2.0))
fgen(:f_subtract, 2, :(abs(arr[x] - arr[y]) / 2.0))
fgen(:f_mult, 2, :(arr[x] * arr[y]))
fgen(:f_div, 2, :(scaled(arr[x] / arr[y])))
fgen(:f_abs, 1, :(abs(arr[x])))
fgen(:f_sqrt, 1, :(sqrt(abs(arr[x]))))
fgen(:f_pow, 2, :(abs(arr[x]) ^ abs(arr[y])))
fgen(:f_exp, 1, :((2 * (exp(arr[x]+1)-1.0))/(exp(2.0)-1.0) -1))
fgen(:f_sin, 1, :(sin(arr[x])))
fgen(:f_cos, 1, :(cos(arr[x])))
fgen(:f_tanh, 1, :(tanh(arr[x])))
fgen(:f_sqrt_xy, 2, :(sqrt(arr[x]^2 + arr[y]^2) / sqrt(2.0)))
fgen(:f_lt, 2, :(Float64(arr[x] < arr[y])))
fgen(:f_gt, 2, :(Float64(arr[x] > arr[y])))

# Logical
fgen(:f_and, 2, :(Float64((&)(Int(round(arr[x])), Int(round(arr[y]))))))
fgen(:f_or, 2, :(Float64((|)(Int(round(arr[x])), Int(round(arr[y]))))))
fgen(:f_xor, 2, :(Float64(xor(Int(abs(round(arr[x]))), Int(abs(round(arr[y])))))))
fgen(:f_not, 1, :(1 - abs(round(arr[x]))))

# Range functions
fgen(:f_avg, 3, :(mean(arr[min(x, y):max(x, y)])))
fgen(:f_max, 3, :(maximum(filter(!isnan, arr[min(x, y):max(x, y)]))))
fgen(:f_min, 3, :(minimum(filter(!isnan, arr[min(x, y):max(x, y)]))))
fgen(:f_med, 3, :(median(filter(!isnan, arr[min(x, y):max(x, y)]))))

end


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: kendra
using AWS.Compat
using AWS.UUIDs

"""
    batch_delete_document(document_id_list, index_id)
    batch_delete_document(document_id_list, index_id, params::Dict{String,<:Any})

Removes one or more documents from an index. The documents must have been added with the
BatchPutDocument operation. The documents are deleted asynchronously. You can see the
progress of the deletion by using Amazon Web Services CloudWatch. Any error messages
related to the processing of the batch are sent to you CloudWatch log.

# Arguments
- `document_id_list`: One or more identifiers for documents to delete from the index.
- `index_id`: The identifier of the index that contains the documents to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DataSourceSyncJobMetricTarget"`:
"""
batch_delete_document(DocumentIdList, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchDeleteDocument", Dict{String, Any}("DocumentIdList"=>DocumentIdList, "IndexId"=>IndexId); aws_config=aws_config)
batch_delete_document(DocumentIdList, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchDeleteDocument", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DocumentIdList"=>DocumentIdList, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    batch_get_document_status(document_info_list, index_id)
    batch_get_document_status(document_info_list, index_id, params::Dict{String,<:Any})

Returns the indexing status for one or more documents submitted with the  BatchPutDocument
operation. When you use the BatchPutDocument operation, documents are indexed
asynchronously. You can use the BatchGetDocumentStatus operation to get the current status
of a list of documents so that you can determine if they have been successfully indexed.
You can also use the BatchGetDocumentStatus operation to check the status of the
BatchDeleteDocument operation. When a document is deleted from the index, Amazon Kendra
returns NOT_FOUND as the status.

# Arguments
- `document_info_list`: A list of DocumentInfo objects that identify the documents for
  which to get the status. You identify the documents by their document ID and optional
  attributes.
- `index_id`: The identifier of the index to add documents to. The index ID is returned by
  the  CreateIndex  operation.

"""
batch_get_document_status(DocumentInfoList, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchGetDocumentStatus", Dict{String, Any}("DocumentInfoList"=>DocumentInfoList, "IndexId"=>IndexId); aws_config=aws_config)
batch_get_document_status(DocumentInfoList, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchGetDocumentStatus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DocumentInfoList"=>DocumentInfoList, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    batch_put_document(documents, index_id)
    batch_put_document(documents, index_id, params::Dict{String,<:Any})

Adds one or more documents to an index. The BatchPutDocument operation enables you to
ingest inline documents or a set of documents stored in an Amazon S3 bucket. Use this
operation to ingest your text and unstructured text into an index, add custom attributes to
the documents, and to attach an access control list to the documents added to the index.
The documents are indexed asynchronously. You can see the progress of the batch using
Amazon Web Services CloudWatch. Any error messages related to processing the batch are sent
to your Amazon Web Services CloudWatch log.

# Arguments
- `documents`: One or more documents to add to the index. Documents can include custom
  attributes. For example, 'DataSourceId' and 'DataSourceSyncJobId' are custom attributes
  that provide information on the synchronization of documents running on a data source.
  Note, 'DataSourceSyncJobId' could be an optional custom attribute as Amazon Kendra will use
  the ID of a running sync job. Documents have the following file size limits.   5 MB total
  size for inline documents   50 MB total size for files from an S3 bucket   5 MB extracted
  text for any file   For more information about file size and transaction per second quotas,
  see Quotas.
- `index_id`: The identifier of the index to add the documents to. You need to create the
  index first using the CreateIndex operation.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"RoleArn"`: The Amazon Resource Name (ARN) of a role that is allowed to run the
  BatchPutDocument operation. For more information, see IAM Roles for Amazon Kendra.
"""
batch_put_document(Documents, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchPutDocument", Dict{String, Any}("Documents"=>Documents, "IndexId"=>IndexId); aws_config=aws_config)
batch_put_document(Documents, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("BatchPutDocument", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Documents"=>Documents, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    clear_query_suggestions(index_id)
    clear_query_suggestions(index_id, params::Dict{String,<:Any})

Clears existing query suggestions from an index. This deletes existing suggestions only,
not the queries in the query log. After you clear suggestions, Amazon Kendra learns new
suggestions based on new queries added to the query log from the time you cleared
suggestions. If you do not see any new suggestions, then please allow Amazon Kendra to
collect enough queries to learn new suggestions.

# Arguments
- `index_id`: The identifier of the index you want to clear query suggestions from.

"""
clear_query_suggestions(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ClearQuerySuggestions", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
clear_query_suggestions(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ClearQuerySuggestions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    create_data_source(index_id, name, type)
    create_data_source(index_id, name, type, params::Dict{String,<:Any})

Creates a data source that you use to with an Amazon Kendra index.  You specify a name,
data source connector type and description for your data source. You also specify
configuration information such as document metadata (author, source URI, and so on) and
user context information.  CreateDataSource is a synchronous operation. The operation
returns 200 if the data source was successfully created. Otherwise, an exception is raised.

# Arguments
- `index_id`: The identifier of the index that should be associated with this data source.
- `name`: A unique name for the data source. A data source name can't be changed without
  deleting and recreating the data source.
- `type`: The type of repository that contains the data source.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A token that you provide to identify the request to create a data
  source. Multiple calls to the CreateDataSource operation with the same client token will
  create only one data source.
- `"Configuration"`: The connector configuration information that is required to access the
  repository. You can't specify the Configuration parameter when the Type parameter is set to
  CUSTOM. If you do, you receive a ValidationException exception. The Configuration parameter
  is required for all other data sources.
- `"Description"`: A description for the data source.
- `"RoleArn"`: The Amazon Resource Name (ARN) of a role with permission to access the data
  source. For more information, see IAM Roles for Amazon Kendra. You can't specify the
  RoleArn parameter when the Type parameter is set to CUSTOM. If you do, you receive a
  ValidationException exception. The RoleArn parameter is required for all other data sources.
- `"Schedule"`: Sets the frequency that Amazon Kendra will check the documents in your
  repository and update the index. If you don't set a schedule Amazon Kendra will not
  periodically update the index. You can call the StartDataSourceSyncJob operation to update
  the index. You can't specify the Schedule parameter when the Type parameter is set to
  CUSTOM. If you do, you receive a ValidationException exception.
- `"Tags"`: A list of key-value pairs that identify the data source. You can use the tags
  to identify and organize your resources and to control access to resources.
"""
create_data_source(IndexId, Name, Type; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateDataSource", Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "Type"=>Type, "ClientToken"=>string(uuid4())); aws_config=aws_config)
create_data_source(IndexId, Name, Type, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateDataSource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "Type"=>Type, "ClientToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    create_faq(index_id, name, role_arn, s3_path)
    create_faq(index_id, name, role_arn, s3_path, params::Dict{String,<:Any})

Creates an new set of frequently asked question (FAQ) questions and answers.

# Arguments
- `index_id`: The identifier of the index that contains the FAQ.
- `name`: The name that should be associated with the FAQ.
- `role_arn`: The Amazon Resource Name (ARN) of a role with permission to access the S3
  bucket that contains the FAQs. For more information, see IAM Roles for Amazon Kendra.
- `s3_path`: The S3 location of the FAQ input data.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A token that you provide to identify the request to create a FAQ.
  Multiple calls to the CreateFaqRequest operation with the same client token will create
  only one FAQ.
- `"Description"`: A description of the FAQ.
- `"FileFormat"`: The format of the input file. You can choose between a basic CSV format,
  a CSV format that includes customs attributes in a header, and a JSON format that includes
  custom attributes. The format must match the format of the file stored in the S3 bucket
  identified in the S3Path parameter. For more information, see Adding questions and answers.
- `"Tags"`: A list of key-value pairs that identify the FAQ. You can use the tags to
  identify and organize your resources and to control access to resources.
"""
create_faq(IndexId, Name, RoleArn, S3Path; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateFaq", Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "S3Path"=>S3Path, "ClientToken"=>string(uuid4())); aws_config=aws_config)
create_faq(IndexId, Name, RoleArn, S3Path, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateFaq", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "S3Path"=>S3Path, "ClientToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    create_index(name, role_arn)
    create_index(name, role_arn, params::Dict{String,<:Any})

Creates a new Amazon Kendra index. Index creation is an asynchronous operation. To
determine if index creation has completed, check the Status field returned from a call to
DescribeIndex. The Status field is set to ACTIVE when the index is ready to use. Once the
index is active you can index your documents using the BatchPutDocument operation or using
one of the supported data sources.

# Arguments
- `name`: The name for the new index.
- `role_arn`: An Identity and Access Management(IAM) role that gives Amazon Kendra
  permissions to access your Amazon CloudWatch logs and metrics. This is also the role used
  when you use the BatchPutDocument operation to index documents from an Amazon S3 bucket.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A token that you provide to identify the request to create an index.
  Multiple calls to the CreateIndex operation with the same client token will create only one
  index.
- `"Description"`: A description for the index.
- `"Edition"`: The Amazon Kendra edition to use for the index. Choose DEVELOPER_EDITION for
  indexes intended for development, testing, or proof of concept. Use ENTERPRISE_EDITION for
  your production databases. Once you set the edition for an index, it can't be changed. The
  Edition parameter is optional. If you don't supply a value, the default is
  ENTERPRISE_EDITION. For more information on quota limits for enterprise and developer
  editions, see Quotas.
- `"ServerSideEncryptionConfiguration"`: The identifier of the KMScustomer managed key
  (CMK) to use to encrypt data indexed by Amazon Kendra. Amazon Kendra doesn't support
  asymmetric CMKs.
- `"Tags"`: A list of key-value pairs that identify the index. You can use the tags to
  identify and organize your resources and to control access to resources.
- `"UserContextPolicy"`: The user context policy.  ATTRIBUTE_FILTER  All indexed content is
  searchable and displayable for all users. If there is an access control list, it is
  ignored. You can filter on user and group attributes.   USER_TOKEN  Enables SSO and
  token-based user access control. All documents with no access control and all documents
  accessible to the user will be searchable and displayable.
- `"UserTokenConfigurations"`: The user token configuration.
"""
create_index(Name, RoleArn; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateIndex", Dict{String, Any}("Name"=>Name, "RoleArn"=>RoleArn, "ClientToken"=>string(uuid4())); aws_config=aws_config)
create_index(Name, RoleArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateIndex", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name, "RoleArn"=>RoleArn, "ClientToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    create_query_suggestions_block_list(index_id, name, role_arn, source_s3_path)
    create_query_suggestions_block_list(index_id, name, role_arn, source_s3_path, params::Dict{String,<:Any})

Creates a block list to exlcude certain queries from suggestions. Any query that contains
words or phrases specified in the block list is blocked or filtered out from being shown as
a suggestion. You need to provide the file location of your block list text file in your S3
bucket. In your text file, enter each block word or phrase on a separate line. For
information on the current quota limits for block lists, see Quotas for Amazon Kendra.

# Arguments
- `index_id`: The identifier of the index you want to create a query suggestions block list
  for.
- `name`: A user friendly name for the block list. For example, the block list named
  'offensive-words' includes all offensive words that could appear in user queries and need
  to be blocked from suggestions.
- `role_arn`: The IAM (Identity and Access Management) role used by Amazon Kendra to access
  the block list text file in your S3 bucket. You need permissions to the role ARN (Amazon
  Resource Name). The role needs S3 read permissions to your file in S3 and needs to give STS
  (Security Token Service) assume role permissions to Amazon Kendra.
- `source_s3_path`: The S3 path to your block list text file in your S3 bucket. Each block
  word or phrase should be on a separate line in a text file. For information on the current
  quota limits for block lists, see Quotas for Amazon Kendra.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A token that you provide to identify the request to create a query
  suggestions block list.
- `"Description"`: A user-friendly description for the block list. For example, the
  description \"List of all offensive words that can appear in user queries and need to be
  blocked from suggestions.\"
- `"Tags"`: A tag that you can assign to a block list that categorizes the block list.
"""
create_query_suggestions_block_list(IndexId, Name, RoleArn, SourceS3Path; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateQuerySuggestionsBlockList", Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "SourceS3Path"=>SourceS3Path, "ClientToken"=>string(uuid4())); aws_config=aws_config)
create_query_suggestions_block_list(IndexId, Name, RoleArn, SourceS3Path, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateQuerySuggestionsBlockList", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "SourceS3Path"=>SourceS3Path, "ClientToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    create_thesaurus(index_id, name, role_arn, source_s3_path)
    create_thesaurus(index_id, name, role_arn, source_s3_path, params::Dict{String,<:Any})

Creates a thesaurus for an index. The thesaurus contains a list of synonyms in Solr format.

# Arguments
- `index_id`: The unique identifier of the index for the new thesaurus.
- `name`: The name for the new thesaurus.
- `role_arn`: An AWS Identity and Access Management (IAM) role that gives Amazon Kendra
  permissions to access thesaurus file specified in SourceS3Path.
- `source_s3_path`: The thesaurus file Amazon S3 source path.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A token that you provide to identify the request to create a thesaurus.
  Multiple calls to the CreateThesaurus operation with the same client token will create only
  one index.
- `"Description"`: The description for the new thesaurus.
- `"Tags"`: A list of key-value pairs that identify the thesaurus. You can use the tags to
  identify and organize your resources and to control access to resources.
"""
create_thesaurus(IndexId, Name, RoleArn, SourceS3Path; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateThesaurus", Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "SourceS3Path"=>SourceS3Path, "ClientToken"=>string(uuid4())); aws_config=aws_config)
create_thesaurus(IndexId, Name, RoleArn, SourceS3Path, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("CreateThesaurus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "Name"=>Name, "RoleArn"=>RoleArn, "SourceS3Path"=>SourceS3Path, "ClientToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    delete_data_source(id, index_id)
    delete_data_source(id, index_id, params::Dict{String,<:Any})

Deletes an Amazon Kendra data source. An exception is not thrown if the data source is
already being deleted. While the data source is being deleted, the Status field returned by
a call to the DescribeDataSource operation is set to DELETING. For more information, see
Deleting Data Sources.

# Arguments
- `id`: The unique identifier of the data source to delete.
- `index_id`: The unique identifier of the index associated with the data source.

"""
delete_data_source(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteDataSource", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
delete_data_source(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteDataSource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    delete_faq(id, index_id)
    delete_faq(id, index_id, params::Dict{String,<:Any})

Removes an FAQ from an index.

# Arguments
- `id`: The identifier of the FAQ to remove.
- `index_id`: The index to remove the FAQ from.

"""
delete_faq(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteFaq", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
delete_faq(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteFaq", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    delete_index(id)
    delete_index(id, params::Dict{String,<:Any})

Deletes an existing Amazon Kendra index. An exception is not thrown if the index is already
being deleted. While the index is being deleted, the Status field returned by a call to the
DescribeIndex operation is set to DELETING.

# Arguments
- `id`: The identifier of the index to delete.

"""
delete_index(Id; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteIndex", Dict{String, Any}("Id"=>Id); aws_config=aws_config)
delete_index(Id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteIndex", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id), params)); aws_config=aws_config)

"""
    delete_principal_mapping(group_id, index_id)
    delete_principal_mapping(group_id, index_id, params::Dict{String,<:Any})

Deletes a group so that all users and sub groups that belong to the group can no longer
access documents only available to that group. For example, after deleting the group
\"Summer Interns\", all interns who belonged to that group no longer see intern-only
documents in their search results. If you want to delete or replace users or sub groups of
a group, you need to use the PutPrincipalMapping operation. For example, if a user in the
group \"Engineering\" leaves the engineering team and another user takes their place, you
provide an updated list of users or sub groups that belong to the \"Engineering\" group
when calling PutPrincipalMapping. You can update your internal list of users or sub groups
and input this list when calling PutPrincipalMapping.

# Arguments
- `group_id`: The identifier of the group you want to delete.
- `index_id`: The identifier of the index you want to delete a group from.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DataSourceId"`: The identifier of the data source you want to delete a group from. This
  is useful if a group is tied to multiple data sources and you want to delete a group from
  accessing documents in a certain data source. For example, the groups \"Research\",
  \"Engineering\", and \"Sales and Marketing\" are all tied to the company's documents stored
  in the data sources Confluence and Salesforce. You want to delete \"Research\" and
  \"Engineering\" groups from Salesforce, so that these groups cannot access customer-related
  documents stored in Salesforce. Only \"Sales and Marketing\" should access documents in the
  Salesforce data source.
- `"OrderingId"`: The timestamp identifier you specify to ensure Amazon Kendra does not
  override the latest DELETE action with previous actions. The highest number ID, which is
  the ordering ID, is the latest action you want to process and apply on top of other actions
  with lower number IDs. This prevents previous actions with lower number IDs from possibly
  overriding the latest action. The ordering ID can be the UNIX time of the last update you
  made to a group members list. You would then provide this list when calling
  PutPrincipalMapping. This ensures your DELETE action for that updated group with the latest
  members list doesn't get overwritten by earlier DELETE actions for the same group which are
  yet to be processed. The default ordering ID is the current UNIX time in milliseconds that
  the action was received by Amazon Kendra.
"""
delete_principal_mapping(GroupId, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeletePrincipalMapping", Dict{String, Any}("GroupId"=>GroupId, "IndexId"=>IndexId); aws_config=aws_config)
delete_principal_mapping(GroupId, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeletePrincipalMapping", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GroupId"=>GroupId, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    delete_query_suggestions_block_list(id, index_id)
    delete_query_suggestions_block_list(id, index_id, params::Dict{String,<:Any})

Deletes a block list used for query suggestions for an index. A deleted block list might
not take effect right away. Amazon Kendra needs to refresh the entire suggestions list to
add back the queries that were previously blocked.

# Arguments
- `id`: The unique identifier of the block list that needs to be deleted.
- `index_id`: The identifier of the you want to delete a block list from.

"""
delete_query_suggestions_block_list(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteQuerySuggestionsBlockList", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
delete_query_suggestions_block_list(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteQuerySuggestionsBlockList", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    delete_thesaurus(id, index_id)
    delete_thesaurus(id, index_id, params::Dict{String,<:Any})

Deletes an existing Amazon Kendra thesaurus.

# Arguments
- `id`: The identifier of the thesaurus to delete.
- `index_id`: The identifier of the index associated with the thesaurus to delete.

"""
delete_thesaurus(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteThesaurus", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
delete_thesaurus(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DeleteThesaurus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_data_source(id, index_id)
    describe_data_source(id, index_id, params::Dict{String,<:Any})

Gets information about a Amazon Kendra data source.

# Arguments
- `id`: The unique identifier of the data source to describe.
- `index_id`: The identifier of the index that contains the data source.

"""
describe_data_source(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeDataSource", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
describe_data_source(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeDataSource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_faq(id, index_id)
    describe_faq(id, index_id, params::Dict{String,<:Any})

Gets information about an FAQ list.

# Arguments
- `id`: The unique identifier of the FAQ.
- `index_id`: The identifier of the index that contains the FAQ.

"""
describe_faq(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeFaq", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
describe_faq(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeFaq", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_index(id)
    describe_index(id, params::Dict{String,<:Any})

Describes an existing Amazon Kendra index

# Arguments
- `id`: The name of the index to describe.

"""
describe_index(Id; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeIndex", Dict{String, Any}("Id"=>Id); aws_config=aws_config)
describe_index(Id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeIndex", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id), params)); aws_config=aws_config)

"""
    describe_principal_mapping(group_id, index_id)
    describe_principal_mapping(group_id, index_id, params::Dict{String,<:Any})

Describes the processing of PUT and DELETE actions for mapping users to their groups. This
includes information on the status of actions currently processing or yet to be processed,
when actions were last updated, when actions were received by Amazon Kendra, the latest
action that should process and apply after other actions, and useful error messages if an
action could not be processed.

# Arguments
- `group_id`: The identifier of the group required to check the processing of PUT and
  DELETE actions for mapping users to their groups.
- `index_id`: The identifier of the index required to check the processing of PUT and
  DELETE actions for mapping users to their groups.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DataSourceId"`: The identifier of the data source to check the processing of PUT and
  DELETE actions for mapping users to their groups.
"""
describe_principal_mapping(GroupId, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribePrincipalMapping", Dict{String, Any}("GroupId"=>GroupId, "IndexId"=>IndexId); aws_config=aws_config)
describe_principal_mapping(GroupId, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribePrincipalMapping", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GroupId"=>GroupId, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_query_suggestions_block_list(id, index_id)
    describe_query_suggestions_block_list(id, index_id, params::Dict{String,<:Any})

Describes a block list used for query suggestions for an index. This is used to check the
current settings that are applied to a block list.

# Arguments
- `id`: The unique identifier of the block list.
- `index_id`: The identifier of the index for the block list.

"""
describe_query_suggestions_block_list(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeQuerySuggestionsBlockList", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
describe_query_suggestions_block_list(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeQuerySuggestionsBlockList", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_query_suggestions_config(index_id)
    describe_query_suggestions_config(index_id, params::Dict{String,<:Any})

Describes the settings of query suggestions for an index. This is used to check the current
settings applied to query suggestions.

# Arguments
- `index_id`: The identifier of the index you want to describe query suggestions settings
  for.

"""
describe_query_suggestions_config(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeQuerySuggestionsConfig", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
describe_query_suggestions_config(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeQuerySuggestionsConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    describe_thesaurus(id, index_id)
    describe_thesaurus(id, index_id, params::Dict{String,<:Any})

Describes an existing Amazon Kendra thesaurus.

# Arguments
- `id`: The identifier of the thesaurus to describe.
- `index_id`: The identifier of the index associated with the thesaurus to describe.

"""
describe_thesaurus(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeThesaurus", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
describe_thesaurus(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("DescribeThesaurus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    get_query_suggestions(index_id, query_text)
    get_query_suggestions(index_id, query_text, params::Dict{String,<:Any})

Fetches the queries that are suggested to your users.

# Arguments
- `index_id`: The identifier of the index you want to get query suggestions from.
- `query_text`: The text of a user's query to generate query suggestions. A query is
  suggested if the query prefix matches what a user starts to type as their query. Amazon
  Kendra does not show any suggestions if a user types fewer than two characters or more than
  60 characters. A query must also have at least one search result and contain at least one
  word of more than four characters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxSuggestionsCount"`: The maximum number of query suggestions you want to show to your
  users.
"""
get_query_suggestions(IndexId, QueryText; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("GetQuerySuggestions", Dict{String, Any}("IndexId"=>IndexId, "QueryText"=>QueryText); aws_config=aws_config)
get_query_suggestions(IndexId, QueryText, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("GetQuerySuggestions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "QueryText"=>QueryText), params)); aws_config=aws_config)

"""
    list_data_source_sync_jobs(id, index_id)
    list_data_source_sync_jobs(id, index_id, params::Dict{String,<:Any})

Gets statistics about synchronizing Amazon Kendra with a data source.

# Arguments
- `id`: The identifier of the data source.
- `index_id`: The identifier of the index that contains the data source.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of synchronization jobs to return in the response. If
  there are fewer results in the list, this response contains only the actual results.
- `"NextToken"`: If the result of the previous request to GetDataSourceSyncJobHistory was
  truncated, include the NextToken to fetch the next set of jobs.
- `"StartTimeFilter"`: When specified, the synchronization jobs returned in the list are
  limited to jobs between the specified dates.
- `"StatusFilter"`: When specified, only returns synchronization jobs with the Status field
  equal to the specified status.
"""
list_data_source_sync_jobs(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListDataSourceSyncJobs", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
list_data_source_sync_jobs(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListDataSourceSyncJobs", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    list_data_sources(index_id)
    list_data_sources(index_id, params::Dict{String,<:Any})

Lists the data sources that you have created.

# Arguments
- `index_id`: The identifier of the index that contains the data source.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of data sources to return.
- `"NextToken"`: If the previous response was incomplete (because there is more data to
  retrieve), Amazon Kendra returns a pagination token in the response. You can use this
  pagination token to retrieve the next set of data sources (DataSourceSummaryItems).
"""
list_data_sources(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListDataSources", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
list_data_sources(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListDataSources", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    list_faqs(index_id)
    list_faqs(index_id, params::Dict{String,<:Any})

Gets a list of FAQ lists associated with an index.

# Arguments
- `index_id`: The index that contains the FAQ lists.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of FAQs to return in the response. If there are fewer
  results in the list, this response contains only the actual results.
- `"NextToken"`: If the result of the previous request to ListFaqs was truncated, include
  the NextToken to fetch the next set of FAQs.
"""
list_faqs(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListFaqs", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
list_faqs(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListFaqs", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    list_groups_older_than_ordering_id(index_id, ordering_id)
    list_groups_older_than_ordering_id(index_id, ordering_id, params::Dict{String,<:Any})

Provides a list of groups that are mapped to users before a given ordering or timestamp
identifier.

# Arguments
- `index_id`: The identifier of the index for getting a list of groups mapped to users
  before a given ordering or timestamp identifier.
- `ordering_id`: The timestamp identifier used for the latest PUT or DELETE action for
  mapping users to their groups.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DataSourceId"`: The identifier of the data source for getting a list of groups mapped
  to users before a given ordering timestamp identifier.
- `"MaxResults"`:  The maximum results shown for a list of groups that are mapped to users
  before a given ordering or timestamp identifier.
- `"NextToken"`:  The next items in the list of groups that go beyond the maximum.
"""
list_groups_older_than_ordering_id(IndexId, OrderingId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListGroupsOlderThanOrderingId", Dict{String, Any}("IndexId"=>IndexId, "OrderingId"=>OrderingId); aws_config=aws_config)
list_groups_older_than_ordering_id(IndexId, OrderingId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListGroupsOlderThanOrderingId", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "OrderingId"=>OrderingId), params)); aws_config=aws_config)

"""
    list_indices()
    list_indices(params::Dict{String,<:Any})

Lists the Amazon Kendra indexes that you have created.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of data sources to return.
- `"NextToken"`: If the previous response was incomplete (because there is more data to
  retrieve), Amazon Kendra returns a pagination token in the response. You can use this
  pagination token to retrieve the next set of indexes (DataSourceSummaryItems).
"""
list_indices(; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListIndices"; aws_config=aws_config)
list_indices(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListIndices", params; aws_config=aws_config)

"""
    list_query_suggestions_block_lists(index_id)
    list_query_suggestions_block_lists(index_id, params::Dict{String,<:Any})

Lists the block lists used for query suggestions for an index. For information on the
current quota limits for block lists, see Quotas for Amazon Kendra.

# Arguments
- `index_id`: The identifier of the index for a list of all block lists that exist for that
  index. For information on the current quota limits for block lists, see Quotas for Amazon
  Kendra.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of block lists to return.
- `"NextToken"`: If the previous response was incomplete (because there is more data to
  retrieve), Amazon Kendra returns a pagination token in the response. You can use this
  pagination token to retrieve the next set of block lists (BlockListSummaryItems).
"""
list_query_suggestions_block_lists(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListQuerySuggestionsBlockLists", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
list_query_suggestions_block_lists(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListQuerySuggestionsBlockLists", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

Gets a list of tags associated with a specified resource. Indexes, FAQs, and data sources
can have tags associated with them.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the index, FAQ, or data source to get a
  list of tags for.

"""
list_tags_for_resource(ResourceARN; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListTagsForResource", Dict{String, Any}("ResourceARN"=>ResourceARN); aws_config=aws_config)
list_tags_for_resource(ResourceARN, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN), params)); aws_config=aws_config)

"""
    list_thesauri(index_id)
    list_thesauri(index_id, params::Dict{String,<:Any})

Lists the Amazon Kendra thesauri associated with an index.

# Arguments
- `index_id`: The identifier of the index associated with the thesaurus to list.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of thesauri to return.
- `"NextToken"`: If the previous response was incomplete (because there is more data to
  retrieve), Amazon Kendra returns a pagination token in the response. You can use this
  pagination token to retrieve the next set of thesauri (ThesaurusSummaryItems).
"""
list_thesauri(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListThesauri", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
list_thesauri(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("ListThesauri", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    put_principal_mapping(group_id, group_members, index_id)
    put_principal_mapping(group_id, group_members, index_id, params::Dict{String,<:Any})

Maps users to their groups. You can also map sub groups to groups. For example, the group
\"Company Intellectual Property Teams\" includes sub groups \"Research\" and
\"Engineering\". These sub groups include their own list of users or people who work in
these teams. Only users who work in research and engineering, and therefore belong in the
intellectual property group, can see top-secret company documents in their search results.
You map users to their groups when you want to filter search results for different users
based on their group’s access to documents. For more information on filtering search
results for different users, see Filtering on user context. If more than five PUT actions
for a group are currently processing, a validation exception is thrown.

# Arguments
- `group_id`: The identifier of the group you want to map its users to.
- `group_members`: The list that contains your users or sub groups that belong the same
  group. For example, the group \"Company\" includes the user \"CEO\" and the sub groups
  \"Research\", \"Engineering\", and \"Sales and Marketing\". If you have more than 1000
  users and/or sub groups for a single group, you need to provide the path to the S3 file
  that lists your users and sub groups for a group. Your sub groups can contain more than
  1000 users, but the list of sub groups that belong to a group (and/or users) must be no
  more than 1000.
- `index_id`: The identifier of the index you want to map users to their groups.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DataSourceId"`: The identifier of the data source you want to map users to their
  groups. This is useful if a group is tied to multiple data sources, but you only want the
  group to access documents of a certain data source. For example, the groups \"Research\",
  \"Engineering\", and \"Sales and Marketing\" are all tied to the company's documents stored
  in the data sources Confluence and Salesforce. However, \"Sales and Marketing\" team only
  needs access to customer-related documents stored in Salesforce.
- `"OrderingId"`: The timestamp identifier you specify to ensure Amazon Kendra does not
  override the latest PUT action with previous actions. The highest number ID, which is the
  ordering ID, is the latest action you want to process and apply on top of other actions
  with lower number IDs. This prevents previous actions with lower number IDs from possibly
  overriding the latest action. The ordering ID can be the UNIX time of the last update you
  made to a group members list. You would then provide this list when calling
  PutPrincipalMapping. This ensures your PUT action for that updated group with the latest
  members list doesn't get overwritten by earlier PUT actions for the same group which are
  yet to be processed. The default ordering ID is the current UNIX time in milliseconds that
  the action was received by Amazon Kendra.
- `"RoleArn"`: The Amazon Resource Name (ARN) of a role that has access to the S3 file that
  contains your list of users or sub groups that belong to a group. For more information, see
  IAM roles for Amazon Kendra.
"""
put_principal_mapping(GroupId, GroupMembers, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("PutPrincipalMapping", Dict{String, Any}("GroupId"=>GroupId, "GroupMembers"=>GroupMembers, "IndexId"=>IndexId); aws_config=aws_config)
put_principal_mapping(GroupId, GroupMembers, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("PutPrincipalMapping", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GroupId"=>GroupId, "GroupMembers"=>GroupMembers, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    query(index_id, query_text)
    query(index_id, query_text, params::Dict{String,<:Any})

Searches an active index. Use this API to search your documents using query. The Query
operation enables to do faceted search and to filter results based on document attributes.
It also enables you to provide user context that Amazon Kendra uses to enforce document
access control in the search results.  Amazon Kendra searches your index for text content
and question and answer (FAQ) content. By default the response contains three types of
results.   Relevant passages   Matching FAQs   Relevant documents   You can specify that
the query return only one type of result using the QueryResultTypeConfig parameter. Each
query returns the 100 most relevant results.

# Arguments
- `index_id`: The unique identifier of the index to search. The identifier is returned in
  the response from the CreateIndex operation.
- `query_text`: The text to search for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AttributeFilter"`: Enables filtered searches based on document attributes. You can only
  provide one attribute filter; however, the AndAllFilters, NotFilter, and OrAllFilters
  parameters contain a list of other filters. The AttributeFilter parameter enables you to
  create a set of filtering rules that a document must satisfy to be included in the query
  results.
- `"DocumentRelevanceOverrideConfigurations"`: Overrides relevance tuning configurations of
  fields or attributes set at the index level. If you use this API to override the relevance
  tuning configured at the index level, but there is no relevance tuning configured at the
  index level, then Amazon Kendra does not apply any relevance tuning. If there is relevance
  tuning configured at the index level, but you do not use this API to override any relevance
  tuning in the index, then Amazon Kendra uses the relevance tuning that is configured at the
  index level. If there is relevance tuning configured for fields at the index level, but you
  use this API to override only some of these fields, then for the fields you did not
  override, the importance is set to 1.
- `"Facets"`: An array of documents attributes. Amazon Kendra returns a count for each
  attribute key specified. You can use this information to help narrow the search for your
  user.
- `"PageNumber"`: Query results are returned in pages the size of the PageSize parameter.
  By default, Amazon Kendra returns the first page of results. Use this parameter to get
  result pages after the first one.
- `"PageSize"`: Sets the number of results that are returned in each page of results. The
  default page size is 10. The maximum number of results returned is 100. If you ask for more
  than 100 results, only 100 are returned.
- `"QueryResultTypeFilter"`: Sets the type of query. Only results for the specified query
  type are returned.
- `"RequestedDocumentAttributes"`: An array of document attributes to include in the
  response. No other document attributes are included in the response. By default all
  document attributes are included in the response.
- `"SortingConfiguration"`: Provides information that determines how the results of the
  query are sorted. You can set the field that Amazon Kendra should sort the results on, and
  specify whether the results should be sorted in ascending or descending order. In the case
  of ties in sorting the results, the results are sorted by relevance. If you don't provide
  sorting configuration, the results are sorted by the relevance that Amazon Kendra
  determines for the result.
- `"UserContext"`: The user context token.
- `"VisitorId"`: Provides an identifier for a specific user. The VisitorId should be a
  unique identifier, such as a GUID. Don't use personally identifiable information, such as
  the user's email address, as the VisitorId.
"""
query(IndexId, QueryText; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("Query", Dict{String, Any}("IndexId"=>IndexId, "QueryText"=>QueryText); aws_config=aws_config)
query(IndexId, QueryText, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("Query", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "QueryText"=>QueryText), params)); aws_config=aws_config)

"""
    start_data_source_sync_job(id, index_id)
    start_data_source_sync_job(id, index_id, params::Dict{String,<:Any})

Starts a synchronization job for a data source. If a synchronization job is already in
progress, Amazon Kendra returns a ResourceInUseException exception.

# Arguments
- `id`: The identifier of the data source to synchronize.
- `index_id`: The identifier of the index that contains the data source.

"""
start_data_source_sync_job(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("StartDataSourceSyncJob", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
start_data_source_sync_job(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("StartDataSourceSyncJob", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    stop_data_source_sync_job(id, index_id)
    stop_data_source_sync_job(id, index_id, params::Dict{String,<:Any})

Stops a running synchronization job. You can't stop a scheduled synchronization job.

# Arguments
- `id`: The identifier of the data source for which to stop the synchronization jobs.
- `index_id`: The identifier of the index that contains the data source.

"""
stop_data_source_sync_job(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("StopDataSourceSyncJob", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
stop_data_source_sync_job(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("StopDataSourceSyncJob", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    submit_feedback(index_id, query_id)
    submit_feedback(index_id, query_id, params::Dict{String,<:Any})

Enables you to provide feedback to Amazon Kendra to improve the performance of your index.

# Arguments
- `index_id`: The identifier of the index that was queried.
- `query_id`: The identifier of the specific query for which you are submitting feedback.
  The query ID is returned in the response to the Query operation.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClickFeedbackItems"`: Tells Amazon Kendra that a particular search result link was
  chosen by the user.
- `"RelevanceFeedbackItems"`: Provides Amazon Kendra with relevant or not relevant feedback
  for whether a particular item was relevant to the search.
"""
submit_feedback(IndexId, QueryId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("SubmitFeedback", Dict{String, Any}("IndexId"=>IndexId, "QueryId"=>QueryId); aws_config=aws_config)
submit_feedback(IndexId, QueryId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("SubmitFeedback", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId, "QueryId"=>QueryId), params)); aws_config=aws_config)

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Adds the specified tag to the specified index, FAQ, or data source resource. If the tag
already exists, the existing value is replaced with the new value.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the index, FAQ, or data source to tag.
- `tags`: A list of tag keys to add to the index, FAQ, or data source. If a tag already
  exists, the existing value is replaced with the new value.

"""
tag_resource(ResourceARN, Tags; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("TagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags); aws_config=aws_config)
tag_resource(ResourceARN, Tags, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags), params)); aws_config=aws_config)

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes a tag from an index, FAQ, or a data source.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the index, FAQ, or data source to
  remove the tag from.
- `tag_keys`: A list of tag keys to remove from the index, FAQ, or data source. If a tag
  key does not exist on the resource, it is ignored.

"""
untag_resource(ResourceARN, TagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UntagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys); aws_config=aws_config)
untag_resource(ResourceARN, TagKeys, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys), params)); aws_config=aws_config)

"""
    update_data_source(id, index_id)
    update_data_source(id, index_id, params::Dict{String,<:Any})

Updates an existing Amazon Kendra data source.

# Arguments
- `id`: The unique identifier of the data source to update.
- `index_id`: The identifier of the index that contains the data source to update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Configuration"`:
- `"Description"`: The new description for the data source.
- `"Name"`: The name of the data source to update. The name of the data source can't be
  updated. To rename a data source you must delete the data source and re-create it.
- `"RoleArn"`: The Amazon Resource Name (ARN) of the new role to use when the data source
  is accessing resources on your behalf.
- `"Schedule"`: The new update schedule for the data source.
"""
update_data_source(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateDataSource", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
update_data_source(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateDataSource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    update_index(id)
    update_index(id, params::Dict{String,<:Any})

Updates an existing Amazon Kendra index.

# Arguments
- `id`: The identifier of the index to update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"CapacityUnits"`: Sets the number of additional storage and query capacity units that
  should be used by the index. You can change the capacity of the index up to 5 times per
  day. If you are using extra storage units, you can't reduce the storage capacity below that
  required to meet the storage needs for your index.
- `"Description"`: A new description for the index.
- `"DocumentMetadataConfigurationUpdates"`: The document metadata to update.
- `"Name"`: The name of the index to update.
- `"RoleArn"`: A new IAM role that gives Amazon Kendra permission to access your Amazon
  CloudWatch logs.
- `"UserContextPolicy"`: The user user token context policy.
- `"UserTokenConfigurations"`: The user token configuration.
"""
update_index(Id; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateIndex", Dict{String, Any}("Id"=>Id); aws_config=aws_config)
update_index(Id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateIndex", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id), params)); aws_config=aws_config)

"""
    update_query_suggestions_block_list(id, index_id)
    update_query_suggestions_block_list(id, index_id, params::Dict{String,<:Any})

Updates a block list used for query suggestions for an index. Updates to a block list might
not take effect right away. Amazon Kendra needs to refresh the entire suggestions list to
apply any updates to the block list. Other changes not related to the block list apply
immediately. If a block list is updating, then you need to wait for the first update to
finish before submitting another update. Amazon Kendra supports partial updates, so you
only need to provide the fields you want to update.

# Arguments
- `id`: The unique identifier of a block list.
- `index_id`: The identifier of the index for a block list.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Description"`: The description for a block list.
- `"Name"`: The name of a block list.
- `"RoleArn"`: The IAM (Identity and Access Management) role used to access the block list
  text file in S3.
- `"SourceS3Path"`: The S3 path where your block list text file sits in S3. If you update
  your block list and provide the same path to the block list text file in S3, then Amazon
  Kendra reloads the file to refresh the block list. Amazon Kendra does not automatically
  refresh your block list. You need to call the UpdateQuerySuggestionsBlockList API to
  refresh you block list. If you update your block list, then Amazon Kendra asynchronously
  refreshes all query suggestions with the latest content in the S3 file. This means changes
  might not take effect immediately.
"""
update_query_suggestions_block_list(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateQuerySuggestionsBlockList", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
update_query_suggestions_block_list(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateQuerySuggestionsBlockList", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    update_query_suggestions_config(index_id)
    update_query_suggestions_config(index_id, params::Dict{String,<:Any})

Updates the settings of query suggestions for an index. Amazon Kendra supports partial
updates, so you only need to provide the fields you want to update. If an update is
currently processing (i.e. 'happening'), you need to wait for the update to finish before
making another update. Updates to query suggestions settings might not take effect right
away. The time for your updated settings to take effect depends on the updates made and the
number of search queries in your index. You can still enable/disable query suggestions at
any time.

# Arguments
- `index_id`: The identifier of the index you want to update query suggestions settings for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"IncludeQueriesWithoutUserInformation"`:  TRUE to include queries without user
  information (i.e. all queries, irrespective of the user), otherwise FALSE to only include
  queries with user information. If you pass user information to Amazon Kendra along with the
  queries, you can set this flag to FALSE and instruct Amazon Kendra to only consider queries
  with user information. If you set to FALSE, Amazon Kendra only considers queries searched
  at least MinimumQueryCount times across MinimumNumberOfQueryingUsers unique users for
  suggestions. If you set to TRUE, Amazon Kendra ignores all user information and learns from
  all queries.
- `"MinimumNumberOfQueryingUsers"`: The minimum number of unique users who must search a
  query in order for the query to be eligible to suggest to your users. Increasing this
  number might decrease the number of suggestions. However, this ensures a query is searched
  by many users and is truly popular to suggest to users. How you tune this setting depends
  on your specific needs.
- `"MinimumQueryCount"`: The the minimum number of times a query must be searched in order
  to be eligible to suggest to your users. Decreasing this number increases the number of
  suggestions. However, this affects the quality of suggestions as it sets a low bar for a
  query to be considered popular to suggest to users. How you tune this setting depends on
  your specific needs.
- `"Mode"`: Set the mode to ENABLED or LEARN_ONLY. By default, Amazon Kendra enables query
  suggestions. LEARN_ONLY mode allows you to turn off query suggestions. You can to update
  this at any time. In LEARN_ONLY mode, Amazon Kendra continues to learn from new queries to
  keep suggestions up to date for when you are ready to switch to ENABLED mode again.
- `"QueryLogLookBackWindowInDays"`: How recent your queries are in your query log time
  window. The time window is the number of days from current day to past days. By default,
  Amazon Kendra sets this to 180.
"""
update_query_suggestions_config(IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateQuerySuggestionsConfig", Dict{String, Any}("IndexId"=>IndexId); aws_config=aws_config)
update_query_suggestions_config(IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateQuerySuggestionsConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IndexId"=>IndexId), params)); aws_config=aws_config)

"""
    update_thesaurus(id, index_id)
    update_thesaurus(id, index_id, params::Dict{String,<:Any})

Updates a thesaurus file associated with an index.

# Arguments
- `id`: The identifier of the thesaurus to update.
- `index_id`: The identifier of the index associated with the thesaurus to update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Description"`: The updated description of the thesaurus.
- `"Name"`: The updated name of the thesaurus.
- `"RoleArn"`: The updated role ARN of the thesaurus.
- `"SourceS3Path"`:
"""
update_thesaurus(Id, IndexId; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateThesaurus", Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId); aws_config=aws_config)
update_thesaurus(Id, IndexId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = kendra("UpdateThesaurus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Id"=>Id, "IndexId"=>IndexId), params)); aws_config=aws_config)


text:
using OffsetArrays: fill
# ---
# title: 1449. Form Largest Integer With Digits That Add up to Target
# id: problem1449
# author: Indigo
# date: 2021-06-12
# difficulty: Hard
# categories: String, Dynamic Programming
# link: <https://leetcode.com/problems/form-largest-integer-with-digits-that-add-up-to-target/description/>
# hidden: true
# ---
#
# Given an array of integers `cost` and an integer `target`. Return the
# **maximum** integer you can paint under the following rules:
#
#   * The cost of painting a digit (i+1) is given by `cost[i]` (0 indexed).
#   * The total cost used must be equal to `target`.
#   * Integer does not have digits 0.
#
# Since the answer may be too large, return it as string.
#
# If there is no way to paint any integer given the condition, return "0".
#
#
#
# **Example 1:**
#
#
#
#     Input: cost = [4,3,2,5,6,7,2,5,5], target = 9
#     Output: "7772"
#     Explanation: The cost to paint the digit '7' is 2, and the digit '2' is 3. Then cost("7772") = 2*3+ 3*1 = 9. You could also paint "977", but "7772" is the largest number.
#     **Digit    cost**
#       1  ->   4
#       2  ->   3
#       3  ->   2
#       4  ->   5
#       5  ->   6
#       6  ->   7
#       7  ->   2
#       8  ->   5
#       9  ->   5
#
#
# **Example 2:**
#
#
#
#     Input: cost = [7,6,5,5,5,6,8,7,8], target = 12
#     Output: "85"
#     Explanation: The cost to paint the digit '8' is 7, and the digit '5' is 5. Then cost("85") = 7 + 5 = 12.
#
#
# **Example 3:**
#
#
#
#     Input: cost = [2,4,6,2,4,6,4,4,4], target = 5
#     Output: "0"
#     Explanation: It's not possible to paint any integer with total cost equal to target.
#
#
# **Example 4:**
#
#
#
#     Input: cost = [6,10,15,40,40,40,40,40,40], target = 47
#     Output: "32211"
#
#
#
#
# **Constraints:**
#
#   * `cost.length == 9`
#   * `1 <= cost[i] <= 5000`
#   * `1 <= target <= 5000`
#
#
## @lc code=start
using LeetCode

using OffsetArrays
function largest_number(cost::Vector{Int}, target::Int)::BigInt
    dp = OffsetArray(fill(typemin(Int), target + 1), -1)
    dp[0] = 0
    for c in cost, j in c:target
        dp[j] = max(dp[j], dp[j - c] + 1)
    end
    res = big(0)
    dp[end] < 0 && return res
    for i in 9:-1:1
        c = cost[i]
        while target >= c && dp[target] == dp[target - c] + 1
            res = res * 10 + i
            target -= c
        end
    end
    return res
end
## @lc code=end