text:
@enum(Stage,
      STAGE_INIT = 1,    # no reference; all proposals
      STAGE_FRAME = 2,   # reference; indel proposals
      STAGE_REFINE = 3,  # no reference; substitutions
      STAGE_SCORE = 4)

function next_stage(s::Stage)
    return Stage(Int(s) + 1)
end

"""
Estimated error probabilities of a consensus sequence.

# Fields
- `sub::Array{Prob,2}`: Probabilities for all four bases.
- `del::Array{Prob,1}`: Probabilities for a deletion
- `ins::Array{Prob,2}`: Probabilities for all insertions.

"""
struct EstimatedProbs
    sub::Array{Prob,2}
    del::Array{Prob,1}
    ins::Array{Prob,2}
end

"""
The parameters for a RIFRAF run.

# Fields
- `scores::Scores = Scores(ErrorModel(1.0, 2.0, 2.0, 0.0, 0.0))`

- `ref_scores::Scores = Scores(ErrorModel(10.0, 1e-1, 1e-1, 1.0, 1.0))`

- `ref_indel_mult::Score = 3.0`: multiplier for single indel penalties
  in alignment with the reference

- `max_ref_indel_mults::Int = 5`: maximum multiplier increases for
  single indel penalty

- `ref_error_mult::Float64 = 1.0`: multiplier for estimated reference
  error rate.

- `do_init::Bool = true`: enable initialization stage

- `do_frame::Bool = true`: enable frame correction stage

- `do_refine::Bool = true`: enable refinement stage

- `do_score::Bool = false`: enable scoring stage

- `do_alignment_proposals::Bool = true`: only propose changes that
  occur in pairwise alignments

- `seed_indels::Bool = true`: seed indel locations from the alignment
  to reference

- `indel_correction_only::Bool = true`: only propose indels during
  frame correction stage

- `use_ref_for_qvs::Bool = false`: use reference alignment when
  estimating quality scores

- `bandwidth::Int = (3 * CODON_LENGTH)`: alignment bandwidth

- `bandwidth_pvalue::Float64 = 0.1`: p-value for increasing bandwidth

- `min_dist::Int = (5 * CODON_LENGTH)`: distance between accepted
  candidate proposals

- `batch_fixed::Bool = true`: use top sequences for initial stage and
  frame correction

- `batch_fixed_size::Int = 5`: size of fixed batch

- `batch_size::Int = 20`: batch size; if <= 1, no batching is used

- `batch_randomness::Float64 = 0.9`: batch randomness
  -  `0`: top n get picked
  -  `0.5`: weight according to estimated errors
  -  `1`: completely random

- `batch_mult::Float64 = 0.7`: multiplier to reduce batch randomness

- `batch_threshold::Float64 = 0.1`: score threshold for increasing
  batch size

- `max_iters::Int = 100`: maximum total iterations across all stages
  before giving up

- `verbose::Int = 0`: verbosity level
  - `0`: nothing
  - `1`: print iteration and score
  - `2`: also print step within each iteration
  - `3`: also print full consensus sequence

"""
@with_kw mutable struct RifrafParams
    scores::Scores = Scores(ErrorModel(1.0, 2.0, 2.0, 0.0, 0.0))
    ref_scores::Scores = Scores(ErrorModel(10.0, 1e-1, 1e-1, 1.0, 1.0))

    # multiplier for single indel penalty
    ref_indel_mult::Score = 3

    # limit for single indel penalty
    max_ref_indel_mults::Score = 5

    # multiplier for estimated reference error rate
    ref_error_mult::Float64 = 1.0

    # enable or disable various stages of the run
    do_init::Bool = true
    do_frame::Bool = true
    do_refine::Bool = true
    do_score::Bool = false

    # only propose changes that occur in pairwise alignments
    do_alignment_proposals::Bool = true

    # seed indel locations from the alignment to reference
    seed_indels::Bool = true

    # only propose indels during frame correction stage
    indel_correction_only::Bool = true

    # use reference alignment when estimating quality scores
    use_ref_for_qvs::Bool = false

    # alignment bandwidth
    bandwidth::Int = (3 * CODON_LENGTH)

    # p-value for increasing bandwidth
    bandwidth_pvalue::Float64 = 0.1

    # distance between accepted candidate proposals
    min_dist::Int = (5 * CODON_LENGTH)

    # use top sequences for initial stage and frame correction
    batch_fixed::Bool = true
    batch_fixed_size::Int = 5

    # if <= 1, no batching is used
    batch_size::Int = 20

    # 0: top n get picked
    # 0.5: weight according to estimated errors
    # 1: completely random
    batch_randomness::Float64 = 0.9

    # multiplier to reduce batch randomness
    batch_mult::Float64 = 0.7

    # score threshold for increasing batch size
    batch_threshold::Float64 = 0.1

    # maximum total iterations across all stages before giving up
    max_iters::Int = 100

    # verbosity level
    # 0: nothing
    # 1: print iteration and score
    # 2: also print step within each iteration
    # 3: also print full consensus sequence
    verbose::Int = 0
end

"""The mutable state that keeps track of a RIFRAF run."""
@with_kw mutable struct RifrafState
    score::Score = -Inf
    consensus::DNASeq
    ref_scores::Scores
    ref_error_rate::Float64 = -Inf
    n_ref_indel_mults::Int = 0
    reference::RifrafSequence
    batch_fixed_size::Int
    batch_size::Int
    base_batch_size::Int
    batch_randomness::Float64 = 0.9
    sequences::Vector{RifrafSequence}
    batch_seqs::Vector{RifrafSequence} = RifrafSequence[]
    maxlen::Int
    As::Vector{BandedArray{Score}}
    Bs::Vector{BandedArray{Score}}
    Amoves::Vector{BandedArray{Trace}}
    A_ref::BandedArray{Score}
    B_ref::BandedArray{Score}
    Amoves_ref::BandedArray{Trace}
    realign_As::Bool = true
    realign_Bs::Bool = true
    penalties_increased::Bool = false
    stage::Stage = STAGE_INIT
    stage_iterations::Vector{Int} = zeros(Int, Int(typemax(Stage)))
    converged::Bool = false
end

"""
    RifrafResult()

The result of a RIFRAF run.

# Fields
- `consensus::DNASeq`: the consensus found by RIFRAF.

- `params::RifrafParams`: the parameters used for this run.

- `state::RifrafState`: the final state of the run.

- `consensus_stages::Vector{Vector{DNASeq}}`:

- `error_probs::EstimatedProbs`: estimated per-base probabilities for
  each position. Only available if `params.do_score` is `true`.

- `aln_error_probs::Vector{Float64}`: combined per-base error
  probabilities. Only available if `params.do_score` is `true`.

"""
@with_kw mutable struct RifrafResult
    consensus::DNASeq
    params::RifrafParams
    state::RifrafState
    consensus_stages::Vector{Vector{DNASeq}}
    error_probs::EstimatedProbs = EstimatedProbs(Array{Prob,2}(0, 0),
                                                 Array{Prob,1}(0),
                                                 Array{Prob,2}(0, 0))
    aln_error_probs::Vector{Float64} = Float64[]
end

function seq_score_deletion(A::BandedArray{Score}, B::BandedArray{Score},
                            acol::Int, bcol::Int)
    Acol = sparsecol(A, acol)
    Bcol = sparsecol(B, bcol)
    (amin, amax), (bmin, bmax) = equal_ranges(row_range(A, acol),
                                              row_range(B, bcol))
    asub = view(Acol, amin:amax)
    bsub = view(Bcol, bmin:bmax)
    return summax(asub, bsub)
end

const BOFFSETS = Dict(Substitution => 2,
                      Insertion => 1,
                      Deletion => 2)

function score_nocodon(proposal::Proposal,
                       A::BandedArray{Score}, B::BandedArray{Score},
                       pseq::RifrafSequence,
                       newcols::Array{Score,2})
    if size(A)[1] != length(pseq) + 1
        error("wrong size array")
    end
    t = typeof(proposal)
    if t == Deletion
        # nothing to recompute
        acol = proposal.pos
        bcol = proposal.pos + 1
        return seq_score_deletion(A, B, acol, bcol)
    end
    # need to compute new columns
    nrows, ncols = size(A)

    # last valid A column
    acol = proposal.pos + (t == Substitution ? 0 : 1)
    new_acol = acol + 1
    amin, amax = row_range(A, min(new_acol, ncols))
    for i in amin:amax
        seq_base = i > 1 ? pseq.seq[i - 1] : DNA_Gap
        newcols[i, 1], _ = update(A, i, new_acol,
                                  seq_base, proposal.base, pseq;
                                  newcols=newcols, acol=acol)
    end

    # add up results
    imin, imax = row_range(A, min(new_acol, ncols))
    Acol = view(newcols, imin:imax, 1)

    bj = proposal.pos + 1
    Bcol = sparsecol(B, bj)
    (amin, amax), (bmin, bmax) = equal_ranges((imin, imax),
                                              row_range(B, bj))
    asub = view(Acol, amin:amax)
    bsub = view(Bcol, bmin:bmax)
    score = summax(asub, bsub)
    if score == -Inf
        error("failed to compute a valid score")
    end
    return score
end

function get_consensus_substring(proposal::Proposal, seq::DNASeq,
                                 n_after::Int)
    # next valid position in sequence after this proposal
    prefix = if typeof(proposal) in (Substitution, Insertion)
        DNASeq([proposal.base])
    else
        DNASeq()
    end
    pos = proposal.pos
    next_posn = pos + 1
    stop = min(next_posn + n_after - 1, length(seq))
    suffix = seq[next_posn:stop]
    return DNASeq(prefix, suffix)
end

function score_proposal(proposal::Proposal,
                        A::BandedArray{Score}, B::BandedArray{Score},
                        consensus::DNASeq,
                        pseq::RifrafSequence,
                        newcols::Array{Score,2})
    if !do_codon_moves(pseq)
        return score_nocodon(proposal, A, B, pseq, newcols)
    end
    t = typeof(proposal)
    # last valid column of A
    acol_offset = t == Insertion ? 0 : -1
    acol = proposal.pos + acol_offset + 1

    # first column of B to use
    first_bcol = acol + BOFFSETS[t]
    # last column of B to use
    last_bcol = first_bcol + CODON_LENGTH - 1

    if t == Deletion && acol == (size(A)[2] - 1)
        # suffix deletions do not need recomputation
        return A[end, end - 1]
    end

    nrows, ncols = size(A)

    # if we'd go to or past the last column of B, just recompute the
    # rest of A, including A[end, end]
    just_a = last_bcol >= ncols

    # number of columns after new columns to also recompute.
    n_after = !just_a ? CODON_LENGTH : length(consensus) - proposal.pos

    # number of bases changed/inserted
    n_new_bases = (t == Deletion ? 0 : 1)
    if n_new_bases == 0 && n_after == 0
        error("no new columns need to be recomputed.")
    end

    n_new = n_new_bases + n_after
    sub_consensus = get_consensus_substring(proposal, consensus, n_after)
    # compute new columns
    for j in 1:n_new
        range_col = min(acol + j, ncols)
        amin, amax = row_range(A, range_col)
        for i in amin:amax
            seq_base = i > 1 ? pseq.seq[i - 1] : DNA_Gap
            newcols[i, j], _ = update(A, i, acol + j,
                                      seq_base, sub_consensus[j], pseq;
                                      newcols=newcols, acol=acol)
        end
    end

    if just_a
        return newcols[nrows, n_new]
    end

    # add up results
    best_score = -Inf
    for j in 1:CODON_LENGTH
        new_j = n_new - CODON_LENGTH + j
        imin, imax = row_range(A, min(acol + new_j, ncols))
        Acol = newcols[imin:imax, new_j]
        bj = first_bcol + j - 1
        if bj > size(B)[2]
            error("wrong column")
        else
            Bcol = sparsecol(B, bj)
            (amin, amax), (bmin, bmax) = equal_ranges((imin, imax),
                                                      row_range(B, bj))
            asub = view(Acol, amin:amax)
            bsub = view(Bcol, bmin:bmax)
            score = summax(asub, bsub)
        end
        if score > best_score
            best_score = score
        end
    end
    if best_score == -Inf
        error("failed to compute a valid score")
    end
    return best_score
end

function score_proposal(m::Proposal,
                        state::RifrafState,
                        newcols::Array{Score,2},
                        use_ref::Bool)
    score = 0.0
    for si in 1:length(state.batch_seqs)
        score += score_proposal(m, state.As[si], state.Bs[si], state.consensus,
                                state.batch_seqs[si], newcols)
    end
    if use_ref
        score += score_proposal(m, state.A_ref, state.B_ref, state.consensus,
                                state.reference, newcols)
    end
    return score
end

function all_proposals(stage::Stage,
                       consensus::DNASeq,
                       indel_correction_only::Bool,
                       indel_seeds::Vector{Proposal}=Proposal[],
                       seed_neighborhood::Int=CODON_LENGTH)
    # FIXME: look into reducing allocations by not producing new
    # instances of every possible proposal
    len = length(consensus)
    ins_positions = Set{Int}()
    del_positions = Set{Int}()

    for p in indel_seeds
        if typeof(p) == Insertion
            for idx in max(p.pos - seed_neighborhood, 0):min(p.pos + seed_neighborhood, len)
                push!(ins_positions, idx)
            end
        else
            for idx in max(p.pos - seed_neighborhood, 1):min(p.pos + seed_neighborhood, len)
                push!(del_positions, idx)
            end
        end
    end
    do_subs = stage != STAGE_FRAME || !indel_correction_only
    do_indels = stage == STAGE_INIT ||
                stage == STAGE_FRAME ||
                stage == STAGE_SCORE
    no_seeds = length(indel_seeds) == 0
    results = Proposal[]
    if do_indels
        for base in BASES
            push!(results, Insertion(0, base))
        end
    end
    for j in 1:len
        if do_subs
            # substitutions
            for base in BASES
                if consensus[j] != base
                    push!(results, Substitution(j, base))
                end
            end
        end
        if do_indels
            # single indels
            if no_seeds || j in del_positions
                push!(results, Deletion(j))
            end
            if no_seeds || j in ins_positions
                for base in BASES
                    push!(results, Insertion(j, base))
                end
            end
        end
    end
    results
end

function moves_to_proposals(moves::Vector{Trace},
                            consensus::DNASeq, seq::RifrafSequence)
    proposals = Proposal[]
    i, j = (0, 0)
    for move in moves
        i, j = offset_forward(move, i, j)

        score = seq.match_scores[max(i, 1)]
        next_score = seq.match_scores[min(i + 1, length(seq))]
        del_score = min(score, next_score)

        if move == TRACE_MATCH
            if seq.seq[i] != consensus[j]
                push!(proposals, Substitution(j, seq.seq[i]))
            end
        elseif move == TRACE_INSERT
            push!(proposals, Insertion(j, seq.seq[i]))
        elseif move == TRACE_DELETE
            push!(proposals, Deletion(j))
        end
    end
    return proposals
end

"""Only get proposals that appear in at least one alignment"""
function alignment_proposals(Amoves::Vector{BandedArray{Trace}},
                             consensus::DNASeq,
                             sequences::Vector{RifrafSequence},
                             do_indels::Bool)
    result = Set{Proposal}()
    for (Amoves, seq) in zip(Amoves, sequences)
        moves = backtrace(Amoves)
        for proposal in moves_to_proposals(moves, consensus, seq)
            if do_indels || typeof(proposal) == Substitution
                push!(result, proposal)
            end
        end
    end
    return collect(result)
end

function get_candidates(state::RifrafState, params::RifrafParams;
                        indel_seeds::Vector{Proposal}=Proposal[])
    use_ref = (state.stage == STAGE_FRAME)

    maxlen = maximum(length(s) for s in state.batch_seqs)
    nrows = max(maxlen, length(state.reference)) + 1
    newcols = zeros(Score, (nrows, CODON_LENGTH + 1))

    # multi-line ternary
    proposals = if (state.stage == STAGE_INIT ||
        state.stage == STAGE_REFINE) && params.do_alignment_proposals
        do_indels = state.stage == STAGE_INIT
        alignment_proposals(state.Amoves, state.consensus,
                            state.batch_seqs, do_indels)
    else
        all_proposals(state.stage, state.consensus,
                      params.indel_correction_only, indel_seeds)
    end

    candidates = ScoredProposal[]
    for p in proposals
        score = score_proposal(p, state, newcols, use_ref)
        if score > state.score
            push!(candidates, ScoredProposal(p, score))
        end
    end
    return candidates
end

function base_consensus(d::Dict{DNA,Score})
    return minimum((v, k) for (k, v) in d)[2]
end

function has_single_indels(consensus::DNASeq,
                           reference::RifrafSequence)
    moves = align_moves(consensus, reference)
    return TRACE_INSERT in moves || TRACE_DELETE in moves
end

function single_indel_proposals(consensus::DNASeq,
                                reference::RifrafSequence)
    moves = align_moves(consensus, reference,
                        skew_matches=true)
    results = Proposal[]
    cons_idx = 0
    ref_idx = 0
    for move in moves
        if move == TRACE_MATCH
            cons_idx += 1
            ref_idx += 1
        elseif move == TRACE_INSERT
            ref_idx += 1
            push!(results, Insertion(cons_idx, reference.seq[ref_idx]))
        elseif move == TRACE_DELETE
            cons_idx += 1
            push!(results, Deletion(cons_idx))
        elseif move == TRACE_CODON_INSERT
            ref_idx += 3
        elseif move == TRACE_CODON_DELETE
            cons_idx += 3
        end
    end
    return results
end

function initial_state(consensus::DNASeq,
                       sequences::Vector{RifrafSequence},
                       reference::DNASeq,
                       params::RifrafParams)
    # batch size calculations
    batch_size = params.batch_size > 1 ? params.batch_size : length(sequences)
    batch_size = min(batch_size, length(sequences))
    batch_fixed_size = min(params.batch_fixed_size,
                           length(sequences))
    base_batch_size = batch_size

    if length(consensus) == 0
        # choose highest-quality sequence as initial consensus
        idx = indmax([logsumexp10(s.match_scores) for s in sequences])
        consensus = sequences[idx].seq
    end

    maxlen = maximum(map(length, sequences))
    rlen = length(reference)

    # initialize sequence banded arrays
    As = BandedArray{Score}[]
    Bs = BandedArray{Score}[]
    Amoves = BandedArray{Trace}[]

    # initialize reference alignment arrays
    ref_shape = (maxlen + 1, rlen + 1)
    ref_bandwidth = params.bandwidth
    if length(reference) == 0
        ref_shape = (1, 1)
        ref_bandwidth = 1
    end
    A_ref = BandedArray(Score, ref_shape, ref_bandwidth, default=-Inf)
    B_ref = BandedArray(Score, ref_shape, ref_bandwidth, default=-Inf)
    Amoves_ref = BandedArray(Trace, ref_shape, ref_bandwidth)

    # just a placeholder for now
    ref_error_log_p = fill(0.0, length(reference))
    refseq = RifrafSequence(reference, ref_error_log_p,
                            params.bandwidth, params.ref_scores)

    return RifrafState(consensus=consensus,
                       reference=refseq,
                       ref_scores=params.ref_scores,
                       batch_fixed_size=batch_fixed_size,
                       batch_size=batch_size,
                       base_batch_size=base_batch_size,
                       maxlen=maxlen,
                       sequences=sequences,
                       As=As, Bs=Bs, Amoves=Amoves,
                       A_ref=A_ref, B_ref=B_ref, Amoves_ref=Amoves_ref)
end

function use_ref(ref, stage, use_ref_for_qvs)
    if length(ref) == 0
        return false
    end
    if stage == STAGE_FRAME
        return true
    end
    if stage == STAGE_SCORE && use_ref_for_qvs
        return true
    end
    return false
end

function rescore!(state::RifrafState, use_ref_for_qvs::Bool)
    state.score = sum(A[end, end] for A in state.As)
    if use_ref(state.reference, state.stage, use_ref_for_qvs)
        state.score += state.A_ref[end, end]
    end
end

"""Forward alignment with bandwidth checking.

If the number of errors is greater than the `1 - pvalue` right tail of
a Poisson with `μ = seq.error_rate`, increase bandwidth.

"""
function smart_forward_moves!(consensus::DNASeq, seq::RifrafSequence,
                              A::BandedArray{Score},
                              B::BandedArray{Score},
                              Amoves::BandedArray{Trace},
                              pvalue::Float64)
    max_bandwidth = min(seq.bandwidth * 2^5, length(consensus), length(seq))
    if seq.bandwidth_fixed
        max_bandwidth = seq.bandwidth
    end
    n_errors = typemax(Int)
    old_n_errors = typemax(Int)
    while true
        forward_moves!(consensus, seq, A, Amoves)
        if seq.bandwidth_fixed || seq.bandwidth >= max_bandwidth
            break
        end
        old_n_errors = n_errors
        n_errors = count_errors(Amoves, consensus, seq.seq)
        threshold = cquantile(Poisson(seq.est_n_errors), pvalue)
        if n_errors > threshold && n_errors < old_n_errors
            seq.bandwidth = min(seq.bandwidth * 2, max_bandwidth)
            newbandwidth!(A, seq.bandwidth)
            newbandwidth!(B, seq.bandwidth)
            newbandwidth!(Amoves, seq.bandwidth)
        else
            break
        end
    end
    seq.bandwidth_fixed = true
end

"""Do forward and backward alignments, and compute scores.

Do smart bandwidth updating.

"""
function realign!(state::RifrafState, params::RifrafParams)
    seqs = state.batch_seqs
    shape = (state.maxlen + 1, state.maxlen + 1)
    # add new arrays, in case batch size increased
    for i in (length(state.As) + 1):length(seqs)
        push!(state.As, BandedArray(Score, shape, seqs[i].bandwidth))
        push!(state.Bs, BandedArray(Score, shape, seqs[i].bandwidth))
        push!(state.Amoves, BandedArray(Trace, shape, seqs[i].bandwidth))
    end

    if state.realign_As
        if params.verbose >= 2
            println(STDERR, "    realigning As")
        end
        for (s, A, B, Amoves) in zip(seqs, state.As, state.Bs, state.Amoves)
            smart_forward_moves!(state.consensus, s, A, B, Amoves,
                                 params.bandwidth_pvalue)
        end
        if use_ref(state.reference, state.stage, params.use_ref_for_qvs)
            smart_forward_moves!(state.consensus, state.reference,
                                 state.A_ref, state.B_ref, state.Amoves_ref,
                                 params.bandwidth_pvalue)
        end
    end
    if state.realign_Bs
        if params.verbose >= 2
            println(STDERR, "    realigning Bs")
        end
        for (s, B) in zip(seqs, state.Bs)
            backward!(state.consensus, s, B)
        end
        if use_ref(state.reference, state.stage, params.use_ref_for_qvs)
            backward!(state.consensus, state.reference, state.B_ref)
        end
    end
end

function realign_rescore!(state::RifrafState, params::RifrafParams)
    realign!(state, params)
    rescore!(state, params.use_ref_for_qvs)
end

"""convert per-proposal log differences to a per-base error rate"""
function normalize_log_differences(sub_scores,
                                   del_scores,
                                   ins_scores,
                                   state_score)
    # per-base insertion score is mean of neighboring insertions
    pos_scores = hcat(sub_scores, del_scores)
    pos_exp = exp10.(pos_scores)
    pos_probs = broadcast(/, pos_exp, sum(pos_exp, 2))
    ins_exp = exp10.(ins_scores)
    ins_probs = broadcast(/, ins_exp, exp10.(state_score) + sum(ins_exp, 2))
    sub_probs = pos_probs[:, 1:4]
    del_probs = pos_probs[:, 5]
    return EstimatedProbs(sub_probs, del_probs, ins_probs)
end

function estimate_probs(state::RifrafState,
                        use_ref_for_qvs::Bool)
    sequences = state.batch_seqs
    reference = state.reference
    # `sub_scores[i]` gives the following log probabilities
    # for `consensus[i]`: [A, C, G, T, -]
    sub_scores = zeros(length(state.consensus), 4) + state.score
    del_scores = zeros(length(state.consensus)) + state.score
    # `ins_scores[i]` gives the following log probabilities for an
    # insertion before `consensus[i]` of [A, C, G, T]
    ins_scores = zeros(length(state.consensus) + 1, 4)

    # TODO: should we modify penalties before using reference?
    # - do not penalize mismatches
    # - use max indel penalty

    maxlen = maximum(length(s) for s in sequences)
    nrows = max(maxlen, length(reference)) + 1
    newcols = zeros(Score, (nrows, CODON_LENGTH + 1))

    use_ref = (length(reference) > 0) && use_ref_for_qvs
    # do not want to penalize indels too harshly, otherwise consensus
    # appears too likely.
    # TODO: how to set scores correctly for estimating qvs?
    # qv_ref_scores = Scores(ErrorModel(1.0, 1.0, 1.0, 0.0, 0.0))
    for m in all_proposals(STAGE_SCORE, state.consensus, false)
        score = score_proposal(m, state, newcols, use_ref)
        if typeof(m) == Substitution
            sub_scores[m.pos, BASEINTS[m.base]] = score
        elseif typeof(m) == Deletion
            del_scores[m.pos] = score
        elseif typeof(m) == Insertion
            ins_scores[m.pos + 1, BASEINTS[m.base]] = score
        end
    end
    max_score = maximum([maximum(sub_scores),
                         maximum(del_scores),
                         maximum(ins_scores)])
    sub_scores -= max_score
    del_scores -= max_score
    ins_scores -= max_score
    if maximum(sub_scores) > 0.0
        error("sub scores cannot be positive")
    end
    if maximum(del_scores) > 0.0
        error("deletion scores cannot be positive")
    end
    if maximum(ins_scores) > 0.0
        error("insertion scores cannot be positive")
    end
    return normalize_log_differences(sub_scores,
                                     del_scores,
                                     ins_scores,
                                     state.score - max_score)
end

function estimate_point_probs(probs::EstimatedProbs)
    pos_probs = hcat(probs.sub, probs.del)
    no_point_error_prob = maximum(pos_probs, 2)
    # multiple by 0.5 to avoid double counting.
    no_ins_error_prob = 1.0 - 0.5 * sum(probs.ins, 2)
    result = 1.0 - broadcast(*, no_point_error_prob,
                             no_ins_error_prob[1:end - 1],
                             no_ins_error_prob[2:end])
    return reshape(result, length(result))
end

function base_distribution(base::DNA, ilp)
    lp = log10(1.0 - exp10(ilp))
    result = fill(lp - log10(3), 4)
    result[BASEINTS[base]] = ilp
    return result
end

"""Assign error probabilities to consensus bases.

Compute posterior error probability from all sequence bases
that aligned to the consensus base.

"""
function alignment_error_probs(tlen::Int,
                               seqs::Vector{RifrafSequence},
                               Amoves::Vector{BandedArray{Trace}})
    # FIXME: incorporate scores
    # FIXME: account for indels
    probs = zeros(tlen, 4)
    for (s, Am) in zip(seqs, Amoves)
        moves = backtrace(Am)
        result = zeros(Int, tlen + 1)
        i, j = (1, 1)
        for move in moves
            i, j = offset_forward(move, i, j)
            s_i = i - 1
            t_j = j - 1
            if move == TRACE_MATCH
                probs[t_j, 1:4] += base_distribution(s.seq[s_i],
                                                     s.match_scores[s_i])
            end
        end
    end
    probs = exp10.(probs)
    probs = 1.0 - maximum(probs ./ sum(probs, 2), 2)
    return vec(probs)
end

function check_params(scores, reference, params)
    if (scores.mismatch >= 0.0 || scores.mismatch == -Inf ||
        scores.insertion >= 0.0 || scores.insertion == -Inf ||
        scores.deletion >= 0.0 || scores.deletion == -Inf)
        error("scores must be between -Inf and 0.0")
    end
    if scores.codon_insertion > -Inf || scores.codon_deletion > -Inf
        error("error model cannot allow codon indels")
    end

    if length(reference) > 0
        if params.ref_error_mult <= 0.0
            error("ref_error_mult must be > 0.0")
        end
        if params.ref_indel_mult <= 0.0
            error("ref_indel_mult must be > 0.0")
        end
        if (params.ref_scores.mismatch >= 0.0 ||
            params.ref_scores.insertion >= 0.0 ||
            params.ref_scores.deletion >= 0.0 ||
            params.ref_scores.codon_insertion >= 0.0 ||
            params.ref_scores.codon_deletion >= 0.0)
            error("ref scores cannot be >= 0")
        end
        if (params.ref_scores.mismatch == -Inf ||
            params.ref_scores.insertion == -Inf ||
            params.ref_scores.deletion == -Inf ||
            params.ref_scores.codon_insertion == -Inf ||
            params.ref_scores.codon_deletion == -Inf)
            error("ref scores cannot be -Inf")
        end
        if (params.max_ref_indel_mults < 0)
            error("ref_indel_increases must be >= 0")
        end
    end

    if !any([params.do_init, params.do_frame, params.do_refine, params.do_score])
        error("no stages enabled")
    end
    if params.max_iters < 1
        error("invalid max iters: $(params.max_iters)")
    end
    if params.batch_fixed && params.batch_fixed_size <= 1
        error("batch_fixed_size must be > 1")
    end
    if params.batch_randomness < 0.0 || params.batch_randomness > 1.0
        error("batch_randomness must be between 0.0 and 1.0")
    end
    if params.batch_mult < 0.0 || params.batch_mult > 1.0
        error("batch_mult must be between 0.0 and 1.0")
    end
    if params.batch_threshold < 0.0 || params.batch_mult > 1.0
        error("batch_threshold must be between 0.0 and 1.0")
    end
end

function handle_candidates!(candidates::Vector{ScoredProposal},
                            state::RifrafState,
                            params::RifrafParams)
    old_consensus = state.consensus
    chosen_cands = choose_candidates(candidates, params.min_dist)
    if params.verbose >= 2
        println(STDERR, "    found $(length(candidates)) candidates; filtered to $(length(chosen_cands))")
    end
    if params.verbose >= 3
        println(STDERR, "    chosen: $chosen_cands")
    end
    state.consensus = apply_proposals(old_consensus,
                                      Proposal[c.proposal
                                               for c in chosen_cands])
    state.realign_As = true
    state.realign_Bs = false
    realign_rescore!(state, params)
    # detect if a single proposal is better
    # note: this may not always be correct, because score_proposal() is not exact
    if length(chosen_cands) > 1 &&
        (state.score < chosen_cands[1].score ||
         isapprox(state.score, chosen_cands[1].score))
        if params.verbose >= 2
            println(STDERR, "    rejecting multiple candidates in favor of best")
        end
        chosen_cands = ScoredProposal[chosen_cands[1]]
        state.consensus = apply_proposals(old_consensus,
                                          Proposal[c.proposal
                                                   for c in chosen_cands])
    else
        # no need to realign As unless batch changes
        state.realign_As = false
    end
    state.realign_Bs = true
    proposal_counts = [length(filter(c -> (typeof(c.proposal) == t),
                                     chosen_cands))
                       for t in [Substitution, Insertion, Deletion]]
end

function finish_stage!(state::RifrafState,
                       params::RifrafParams)
    if params.verbose >= 2
        println(STDERR, "    no candidates found in $(state.stage).")
    end
    if state.stage == STAGE_INIT
        if length(state.reference) == 0 || !(params.do_frame)
            state.converged = true
        else
            state.stage = STAGE_FRAME
            # estimate reference error rate
            edit_dist = edit_distance(state.consensus, state.reference.seq)
            ref_error_rate = edit_dist / max(length(state.reference),
                                             length(state.consensus))
            ref_error_rate *= params.ref_error_mult
            # needs to be < 0.5, otherwise matches aren't rewarded at all
            state.ref_error_rate = min(max(ref_error_rate, 1e-10), 0.5)
            ref_error_log_p = fill(log10(state.ref_error_rate), length(state.reference))
            state.reference = RifrafSequence(state.reference.seq, ref_error_log_p,
                                             params.bandwidth, state.ref_scores)

            # check if we've already converged
            if !has_single_indels(state.consensus, state.reference)
                state.converged = true
            end
        end
    elseif state.stage == STAGE_FRAME
        if !has_single_indels(state.consensus, state.reference)
            state.stage = STAGE_REFINE
        elseif (state.n_ref_indel_mults == params.max_ref_indel_mults)
            if params.verbose >= 2
                println(STDERR, "    NOTE: alignment had single indels but reached penalty limit.")
            end
            state.stage = STAGE_REFINE
        else
            state.penalties_increased = true
            if state.n_ref_indel_mults < params.max_ref_indel_mults
                state.n_ref_indel_mults += 1
            else
                error("Tried to illegally increase n_ref_indel_mults")
            end
            # TODO: this is not probabilistically correct
            mult = params.ref_indel_mult ^ state.n_ref_indel_mults
            state.ref_scores = Scores(state.ref_scores.mismatch,
                                      state.ref_scores.insertion * mult,
                                      state.ref_scores.deletion * mult,
                                      state.ref_scores.codon_insertion,
                                      state.ref_scores.codon_deletion)
            state.reference = RifrafSequence(state.reference, state.ref_scores)
            if params.verbose >= 2
                println(STDERR, "    NOTE: alignment to reference had single indels. increasing penalty.")
            end
        end
    elseif state.stage == STAGE_REFINE
        state.converged = true
    else
        error("  invalid stage: $(state.stage)")
    end
end

"""Samble a subset of `data`"""
function resample(data, n, wv)
    # TODO: optionally softmax the weight vector
    if n < length(data)
        return StatsBase.sample(data, wv, n, replace=false)
    else
        return data
    end
end

"""Reweight weight vector to increase or decrease the weights of the
top `n` values.

`randomness` can be between 0 and 1

0: top n get picked
0.5: weight according to estimated errors
1: completely random

"""
function reweight(wv, n, randomness)
    # TODO: there is probably a one liner that does all this
    if randomness < 0.0 || randomness > 1.0
        error("randomness must be between 0.0 and 1.0")
    end
    wv = wv ./ sum(wv)
    indices = reverse(sortperm(wv))[1:n]
    endpoint = wv
    weight = 0.0
    if randomness > 0.5
        weight = (randomness - 0.5) * 2.0
        endpoint = fill(1.0 / length(wv), length(wv))
    elseif randomness < 0.5
        weight = 1.0 - randomness * 2.0
        endpoint = zeros(length(wv))
        endpoint[indices] = 1.0 / n
    end
    result = weight * endpoint + (1.0 - weight) * wv
    return result
end

function resample!(state::RifrafState, params::RifrafParams;
                   verbose::Int=0)
    err_weights = [s.est_n_errors for s in state.sequences]
    if ((state.stage == STAGE_INIT || state.stage == STAGE_FRAME) &&
        params.batch_fixed)
        # always return the top `n`
        # TODO: when to switch to random batches?
        indices = sortperm(err_weights)[1:state.batch_fixed_size]
        state.batch_seqs = state.sequences[indices]
        if verbose >= 2
            println(STDERR, "    kept fixed batch")
        end
        return
    end
    wv = Weights(reweight(1.0 - err_weights ./ sum(err_weights),
                          state.batch_size, state.batch_randomness))
    state.batch_seqs = resample(state.sequences, state.batch_size, wv)
    did_sample = state.batch_size < length(state.sequences)
    if did_sample
        state.realign_As = true
    end
    if verbose >= 2
        if did_sample
            println(STDERR, "    sampled $(state.batch_size) new sequences")
        else
            println(STDERR, "    sampled all sequences")
        end
    end
end

"""Check that score did not decrease.

If it did dicrease too much, increase batch size, resample, and
realign again.

"""
function check_score!(state::RifrafState, params::RifrafParams,
                      old_score::Float64)
    if params.verbose >= 2
        println(STDERR, "    score: $(state.score)")
    end

    if (!state.penalties_increased &&
        state.batch_size == length(state.sequences) &&
        state.stage_iterations[Int(state.stage)] > 1)
        if state.score < old_score
            if params.verbose >= 2
                println(STDERR, "    WARNING: not using batches, but score decreased.")
            end
        elseif state.score == old_score
            if params.verbose >= 2
                println(STDERR, "    score did not change. ending stage.")
            end
            return false
        end
    end
    if ((state.score - old_score) / old_score > params.batch_threshold &&
        !state.penalties_increased &&
        state.batch_size < length(state.sequences) &&
        state.stage_iterations[Int(state.stage)] > 1)
        # TODO: could speed this up by adding new sequences and
        # realigning only the new ones
        state.batch_size = min(state.batch_size + state.base_batch_size,
                               length(state.sequences))
        if params.verbose >= 2
            println(STDERR, "    NOTE: increased batch size to $(state.batch_size).")
        end
        resample!(state, params, verbose=params.verbose)
        state.realign_As = true
        state.realign_Bs = true
        realign_rescore!(state, params)
        if params.verbose >= 2
            println(STDERR, "    new score: $(state.score)")
        end
    end
    return true
end

function rifraf(dnaseqs::Vector{DNASeq},
                error_log_ps::Vector{Vector{LogProb}};
                consensus::DNASeq=DNASeq(),
                reference::DNASeq=DNASeq(),
                params::RifrafParams=RifrafParams())
    check_params(params.scores, reference, params)

    sequences = RifrafSequence[RifrafSequence(s, p, params.bandwidth, params.scores)
                               for (s, p) in zip(dnaseqs, error_log_ps)]

    state = initial_state(consensus, sequences, reference, params)

    # TODO: this is ugly
    enabled_stages = Set{Stage}()
    if params.do_init
        push!(enabled_stages, STAGE_INIT)
    end
    if params.do_frame
        push!(enabled_stages, STAGE_FRAME)
    end
    if params.do_refine
        push!(enabled_stages, STAGE_REFINE)
    end
    if params.do_score
        push!(enabled_stages, STAGE_SCORE)
    end

    # keep track of every iteration's consensus
    consensus_stages = [[] for _ in 1:(Int(typemax(Stage)) - 1)]

    state.realign_As = true
    state.realign_Bs = true
    old_score = -Inf

    for iter in 1:params.max_iters
        # skip to next valid stage
        while state.stage < STAGE_SCORE && !(state.stage in enabled_stages)
            state.stage = next_stage(state.stage)
        end
        if state.stage == STAGE_SCORE
            break
        end
        state.stage_iterations[Int(state.stage)] += 1
        push!(consensus_stages[Int(state.stage)], state.consensus)

        if params.verbose >= 1
            println(STDERR, "iteration $iter : $(state.stage) : $(state.score)")
        end
        if params.verbose >= 3
            println(STDERR, "  consensus: $(state.consensus)")
        elseif params.verbose >= 2
            println(STDERR, "  consensus length: $(length(state.consensus))")
        end

        # resample sequences, realign, and possibly adjust batch size
        if params.verbose >= 2
            println(STDERR, "  step: resample")
        end
        resample!(state, params; verbose=params.verbose)

        if params.verbose >= 2
            println(STDERR, "  step: realign and rescore")
        end
        realign_rescore!(state, params)

        if params.verbose >= 2
            println(STDERR, "  step: check score")
        end
        if check_score!(state, params, old_score)
            old_score = state.score

            # get candidate changes to consensus
            state.penalties_increased = false

            indel_seeds = if state.stage == STAGE_FRAME && params.seed_indels
                single_indel_proposals(state.consensus, state.reference)
            else
                Proposal[]
            end
            candidates = get_candidates(state, params; indel_seeds=indel_seeds)

            # handle candidates
            state.realign_As = true
            if length(candidates) > 0
                if params.verbose >= 2
                    println(STDERR, "  step: handle candidates")
                end
                handle_candidates!(candidates, state, params)
            else
                if params.verbose >= 2
                    println(STDERR, "  step: finish_stage")
                end
                finish_stage!(state, params)
            end
        else
            finish_stage!(state, params)
        end
        if state.converged
            break
        end

        # update batch randomness
        if ((!params.batch_fixed ||
            (state.stage == STAGE_REFINE &&
             state.stage_iterations[Int(STAGE_REFINE)] > 1)) &&
            state.batch_size < length(state.sequences))
            state.batch_randomness *= params.batch_mult
            if params.verbose >= 2
                println(STDERR, "  batch randomness decreased to $(state.batch_randomness)")
            end
        end
    end
    state.stage = STAGE_SCORE

    result = RifrafResult(consensus=state.consensus,
                          params=params,
                          state=state,
                          consensus_stages=consensus_stages)

    if params.do_score
        if params.verbose >= 2
            println(STDERR, "computing consensus quality scores")
        end

        # FIXME: recomputing for all sequences is costly, but using batch
        # is less accurate
        # possibly use top n sequences here
        state.realign_As = true
        state.realign_Bs = true
        realign_rescore!(state, params)
        result.error_probs = estimate_probs(state, params.use_ref_for_qvs)
        result.aln_error_probs = alignment_error_probs(length(state.consensus),
                                                     state.batch_seqs, state.Amoves)
    end
    if params.verbose >= 1
        println(STDERR, "done. converged: $(state.converged)")
    end
    return result
end

"""
    rifraf(dnaseqs, phreds; kwargs...)

Find a consensus sequence for a set of DNA sequences.

Returns an instance of `RifrafResult`.

# Arguments
- `dnaseqs::Vector{DNASeq}`: reads for which to find a consensus

- `phreds::Vector{Vector{Phred}}`: Phred scores for `dnaseqs`

- `consensus::DNASeq=DNASeq()`: initial consensus; if not given,
  defaults to the sequence in `dnaseqs` with the lowest mean error
  rate

- `reference::DNASeq=DNASeq()`: reference for frame correction

- `params::RifrafParams=RifrafParams()`

"""
function rifraf(dnaseqs::Vector{DNASeq},
                phreds::Vector{Vector{Phred}};
                kwargs...)
    # TODO: do not require DNASeq only!
    if any(minimum(p) < 0 for p in phreds)
        error("phred score cannot be negative")
    end
    error_log_ps = phred_to_log_p(phreds)
    myseqs = DNASeq[DNASeq(s) for s in dnaseqs]
    return rifraf(myseqs, error_log_ps; kwargs...)
end

"""

Adjust error probabilities so that the expected number of errors
matches the edit distance to the consensus sequence.

"""
function calibrate_phreds(s::DNASeq, phred::Vector{Phred}, consensus::DNASeq)
    # TODO: should use our own alignments here
    n_errors = edit_distance(consensus, s)
    errors = phred_to_p(phred)
    return errors * float(n_errors) / sum(errors)
end

"""rifraf-style fast frameshift correction"""
function correct_shifts(consensus::DNASeq,
                        reference::DNASeq;
                        log_p::LogProb=-1.0,
                        bandwidth::Int=-1,
                        scores::Scores=Scores(ErrorModel(10.0, 1e-5, 1e-5, 1.0, 1.0)))
    log_ps = fill(log_p, length(reference))
    if bandwidth < 0
        bandwidth = Int(ceil(min(length(consensus), length(reference)) * 0.1))
    end
    refseq = RifrafSequence(reference, log_ps, bandwidth, scores)
    a, b = align(consensus, refseq)
    proposals = single_indel_proposals(consensus, refseq)
    result = apply_proposals(consensus, proposals)
end


text:
for N in [Float64, Float32]
    # random ball
    rand(Ball2)

    # 1D Ball2
    b = Ball2(N[0], N(1))
    # Test Dimension
    @test dim(b) == 1
    # Test Support Vector
    d = N[1]
    @test σ(d, b) == N[1]
    d = N[-1]
    @test σ(d, b) == N[-1]

    # 2D Ball2
    b = Ball2(N[0, 0], N(1))
    # Test Dimension
    @test dim(b) == 2
    # Test Support Vector
    d = N[1, 0]
    @test σ(d, b) == N[1, 0]
    d = N[-1, 0]
    @test σ(d, b) == N[-1, 0]
    d = N[0, 1]
    @test σ(d, b) == N[0, 1]
    d = N[0, -1]
    @test σ(d, b) == N[0, -1]
    d = N[0, 0]
    @test σ(d, b) == N[0, 0]

    # 2D Ball2 not 0-centered
    b = Ball2(N[1, 2], N(1))
    # Test Dimension
    @test dim(b) == 2
    # Test Support Vector
    d = N[1, 0]
    @test σ(d, b) == N[2, 2]
    d = N[-1, 0]
    @test σ(d, b) == N[0, 2]
    d = N[0, 1]
    @test σ(d, b) == N[1, 3]
    d = N[0, -1]
    @test σ(d, b) == N[1, 1]

    # 2D Ball2 radius =/= 1
    b = Ball2(N[0, 0], N(2))
    # Test Dimension
    @test dim(b) == 2
    # Test Support Vector
    d = N[1, 0]
    @test σ(d, b) == N[2, 0]
    d = N[-1, 0]
    @test σ(d, b) == N[-2, 0]
    d = N[0, 1]
    @test σ(d, b) == N[0, 2]
    d = N[0, -1]
    @test σ(d, b) == N[0, -2]

    # boundedness
    @test isbounded(b) && isboundedtype(typeof(b))

    # is_polyhedral
    @test !is_polyhedral(b)

    # isempty
    @test !isempty(b)

    # isuniversal
    answer, w = isuniversal(b, true)
    @test !isuniversal(b) && !answer && w ∉ b

    # an_element function
    b = Ball2(N[1, 2], N(2))
    @test an_element(b) ∈ b

    # translation
    @test translate(b, N[1, 2]) == Ball2(N[2, 4], N(2))
    bb = Ball2(N[0, 0], N(1))
    @test translate!(bb, N[1, 1]) == Ball2(N[1, 1], N(1)) == bb

    # inclusion of a Ball2 in a Ball2
    b1 = Ball2(N[1, 2], N(2))
    b2 = Ball2(N[1, 2], N(0))
    b3 = Ball2(N[1.7, 2.7], N(1))
    s1 = Singleton(N[1, 2])
    s2 = Singleton(N[2, 2])
    subset, point = ⊆(b1, s1, true)
    @test b1 ⊈ s1 && !subset && point ∈ b1 && point ∉ s1
    @test b2 ⊆ s1 && ⊆(b2, s1, true)[1]
    subset, point = ⊆(b1, s2, true)
    @test b1 ⊈ s2 && !subset && point ∈ b1 && point ∉ s2
    @test b1 ⊈ BallInf(N[1, 2], N(1))
    @test b2 ⊆ BallInf(N[1, 2], N(2))
    subset, point = ⊆(b1, b3, true)
    @test b1 ⊈ b3 && !subset && point ∈ b1 && point ∉ b3
    @test b3 ⊆ b1 && ⊆(b3, b1, true)[1]
    # inclusion of a Ball2 in a polyhedral LazySet
    b = Ball2(zeros(N, 4), N(1))
    p = BallInf(zeros(N, 2), N(1)) × BallInf(zeros(N, 2), N(1))
    subset, point = ⊆(b, p, true)
    @test subset && b ⊆ p && point == N[]
    p = BallInf(ones(N, 2), N(1)) × BallInf(zeros(N, 2), N(1))
    subset, point = ⊆(b, p, true)
    @test !subset && b ⊈ p && point ∈ b && point ∉ p

    # intersection
    b1 = Ball2(N[0, 0], N(2))
    b2 = Ball2(N[2, 2], N(2))
    b3 = Ball2(N[4, 4], N(2))
    b4 = Ball2(N[1, 1], N(1))
    intersection_empty, point = is_intersection_empty(b1, b2, true)
    @test !is_intersection_empty(b1, b2) && !intersection_empty && point ∈ b1 && point ∈ b2
    @test is_intersection_empty(b1, b3) && is_intersection_empty(b1, b3, true)[1]
    intersection_empty, point = is_intersection_empty(b2, b1, true)
    @test !is_intersection_empty(b2, b1) && !intersection_empty && point ∈ b2 && point ∈ b1
    intersection_empty, point = is_intersection_empty(b1, b4, true)
    @test !is_intersection_empty(b1, b4) && !intersection_empty && point ∈ b1 && point ∈ b4

    # uniform sampling
    B = Ball2(N[1, 2, 3], N(0.5))
    s = sample(B, 100) # get 100 random elements in B
    @test all(si -> si ∈ B, s)
    # sampling without arguments returns a single vector
    s = sample(B)
    @test s isa AbstractVector{N} && s ∈ B

    # Chebyshev center
    @test chebyshev_center(B) == center(B)

    # volume in dimension 2
    B = Ball2(zeros(N, 2), N(2))
    @test volume(B) ≈ pi * radius(B)^2

    # volume in dimension 3
    B = Ball2(zeros(N, 3), N(2))
    @test volume(B) ≈ 4/3 * pi * radius(B)^3

    # projection
    b4 = Ball2(N[4, 3, 2, 1], N(2))
    @test project(b4, [2, 4]) == Ball2(N[3, 1], N(2))

    # low/high
    B = Ball2(N[1, 2], N(2))
    l1 = low(B, 1)
    l2 = low(B, 2)
    h1 = high(B, 1)
    h2 = high(B, 2)
    @test l1 == N(-1) && l2 == N(0) && h1 == N(3) && h2 == N(4)
    @test box_approximation(B) ≈ Hyperrectangle(low=[l1, l2], high=[h1, h2])
    @test low(B) == [N(-1), N(0)]
    @test high(B) == [N(3), N(4)]
end

ext: jl


text:
export iauC2tcio
"""
Assemble the celestial to terrestrial matrix from CIO-based
components (the celestial-to-intermediate matrix, the Earth Rotation
Angle and the polar motion matrix).

This function is part of the International Astronomical Union's
SOFA (Standards Of Fundamental Astronomy) software collection.

Status:  support function.

Given:
   rc2i     double[3][3]    celestial-to-intermediate matrix
   era      double          Earth rotation angle (radians)
   rpom     double[3][3]    polar-motion matrix

Returned:
   rc2t     double[3][3]    celestial-to-terrestrial matrix

Notes:

   1. This function constructs the rotation matrix that transforms
   vectors in the celestial system into vectors in the terrestrial
   system.  It does so starting from precomputed components, namely
   the matrix which rotates from celestial coordinates to the
   intermediate frame, the Earth rotation angle and the polar motion
   matrix.  One use of the present function is when generating a
   series of celestial-to-terrestrial matrices where only the Earth
   Rotation Angle changes, avoiding the considerable overhead of
   recomputing the precession-nutation more often than necessary to
   achieve given accuracy objectives.

   2. The relationship between the arguments is as follows:

      [TRS] = RPOM * R_3(ERA) * rc2i * [CRS]

            = rc2t * [CRS]

   where [CRS] is a vector in the Geocentric Celestial Reference
   System and [TRS] is a vector in the International Terrestrial
   Reference System (see IERS Conventions 2003).

Called:
   iauCr        copy r-matrix
   iauRz        rotate around Z-axis
   iauRxr       product of two r-matrices

Reference:

   McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003),
   IERS Technical Note No. 32, BKG

This revision:  2013 August 24

SOFA release 2018-01-30

Copyright (C) 2018 IAU SOFA Board.  See notes at end.
"""
# void iauC2tcio(double rc2i[3][3], double era, double rpom[3][3],
#                double rc2t[3][3])
function iauC2tcio(rc2i::AbstractMatrix{<:Real}, era::Real, rpom::AbstractMatrix{<:Real})

   # Allocate return value
   rc2t = zeros(Float64, 3, 3)

   ccall((:iauC2tcio, libsofa_c), Cvoid,
         (Ptr{Cdouble}, Cdouble, Ptr{Cdouble},
         Ptr{Cdouble}),
         convert(Array{Float64, 2}, rc2i'), convert(Float64, era),
         convert(Array{Float64, 2}, rpom'),
         rc2t)

   return SMatrix{3,3}(rc2t')
end


text:
"""
A module which provides types for common
state representations in astrodynamics,
including Cartesian and Keplerian states,
and orbital states which include epoch and
coordinate frame information.

# Extended Help

**Exports**

$(EXPORTS)

**Imports**

$(IMPORTS)
"""
module States

export CartesianState, CartesianStateWithSTM, KeplerianState
export R2BPParameters, CR3BPParameters
export Orbit, state, system, epoch, frame
export position, velocity, statevector
export R2BPOrbit, KeplerianR2BPOrbit, CartesianR2BPOrbit, CartesianOrbitWithSTM, CR3BPOrbit
export lengthunit, timeunit, angularunit, velocityunit, massparamunit, name
export Sun, Mercury, Venus, Earth, Moon, Luna, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto
export SunVenus, SunEarth, EarthMoon, SunMars, SunJupiter, SunSaturn
export model, vectorfield

import Dates: now
import AstroTime: TAIEpoch
import Requires: @require
import LinearAlgebra: norm, I

using Unitful, UnitfulAstro
using StaticArrays
using ArrayInterface
using LabelledArrays
using DocStringExtensions

using ..CoordinateFrames
using ..Calculations

@template (FUNCTIONS, METHODS, MACROS) =
    """
    $(SIGNATURES)
    $(DOCSTRING)
    """

@template (TYPES, CONSTANTS) =
    """
    $(TYPEDEF)
    $(DOCSTRING)
    """

include(joinpath("Common","ParameterizedLabelledArrays.jl"))
include(joinpath("States", "StateVectors.jl"))
include(joinpath("Systems", "ParameterVectors.jl"))
include(joinpath("Orbits", "OrbitDescriptions.jl"))
include(joinpath("Systems", "R2BPSystems.jl"))
include(joinpath("Systems", "CR3BPSystems.jl"))

include("Calculations/Calculations.jl")

function __init__()
    @require AstrodynamicalModels="4282b555-f590-4262-b575-3e516e1493a7" include(joinpath(@__DIR__, "Hooks", "AstrodynamicalModels.jl"))
    @require SymbolicUtils="d1185830-fcd6-423d-90d6-eec64667417b" include(joinpath(@__DIR__, "Hooks", "SymbolicUtils.jl"))
end

end # module


text:
# MIT License
#
# Copyright (c) 2018 Martin Biel
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

struct SingleDecision <: MOI.AbstractScalarFunction
    decision::MOI.VariableIndex
end

struct VectorOfDecisions <: MOI.AbstractVectorFunction
    decisions::Vector{MOI.VariableIndex}
end
MOI.output_dimension(f::VectorOfDecisions) = length(f.decisions)

# Base overrides #
# ========================== #
Base.copy(f::SingleDecision) = f
Base.copy(f::VectorOfDecisions) = VectorOfDecisions(copy(f.decisions))

Base.iszero(::SingleDecision) = false
Base.isone(::SingleDecision) = false

function Base.:(==)(f::VectorOfDecisions, g::VectorOfDecisions)
    return f.decisions == g.decisions
end

function Base.isapprox(f::Union{SingleDecision,VectorOfDecisions},
                       g::Union{SingleDecision,VectorOfDecisions};
                       kwargs...)
    return f == g
end

function Base.convert(::Type{MOI.ScalarAffineFunction{T}},
                      f::SingleDecision) where T
    return MOI.ScalarAffineFunction{T}(MOI.SingleVariable(f.decision))
end

# JuMP overrides #
# ========================== #
function DecisionRef(model::Model, f::SingleDecision)
    return DecisionRef(model, f.decision)
end

SingleDecision(dref::DecisionRef) = SingleDecision(index(dref))
function JuMP.moi_function(dref::DecisionRef)
    return SingleDecision(dref)
end
function JuMP.moi_function_type(::Type{DecisionRef})
    return SingleDecision
end
JuMP.jump_function_type(::Model, ::Type{SingleDecision}) = DecisionRef
function JuMP.jump_function(model::Model, decision::SingleDecision)
    return DecisionRef(model, decision)
end

is_decision_type(::Type{SingleDecision}) = true

VectorOfDecisions(dvars::Vector{DecisionRef}) = VectorOfDecisions(index.(dvars))
function JuMP.moi_function(decisions::Vector{<:DecisionRef})
    return VectorOfDecisions(index.(decisions))
end
function JuMP.moi_function_type(::Type{<:Vector{<:DecisionRef}})
    return VectorOfDecisions
end
JuMP.jump_function_type(::Model, ::Type{VectorOfDecisions}) = Vector{DecisionRef}
function JuMP.jump_function(model::Model, decisions::VectorOfDecisions)
    return map(decisions.decisions) do decision
        DecisionRef(model, decision)
    end
end

is_decision_type(::Type{VectorOfDecisions}) = true

# MOI Function interface #
# ========================== #
MOI.constant(f::SingleDecision, T::DataType) = zero(T)

function MOIU.eval_variables(varval::Function, f::SingleDecision)
    return varval(f.decision)
end
function MOIU.eval_variables(varval::Function, f::VectorOfDecisions)
    return varval.(f.decisions)
end

function MOIU.map_indices(index_map::Function, f::SingleDecision)
    return SingleDecision(index_map(f.decision))
end
function MOIU.map_indices(index_map::Function, f::VectorOfDecisions)
    return VectorOfDecisions(index_map.(f.decisions))
end

function Base.getindex(it::MOIU.ScalarFunctionIterator{VectorOfDecisions},
                       output_index::Integer)
    return SingleDecision(it.f.decisions[output_index])
end
function Base.getindex(it::MOIU.ScalarFunctionIterator{VectorOfDecisions},
                       output_indices::AbstractVector)
    return VectorOfDecisions(it.f.decisions[output_indices])
end

Base.eltype(it::MOIU.ScalarFunctionIterator{VectorOfDecisions}) = SingleDecision

MOIU.scalar_type(::Type{VectorOfDecisions}) = SingleDecision

MOIU.canonicalize!(f::Union{SingleDecision, VectorOfDecisions}) = f

function MOIU.filter_variables(keep::Function, f::SingleDecision)
    if !keep(f.decision)
        error("Cannot remove decision from a `SingleDecision` function of the",
              " same decision.")
    end
    return f
end

function MOIU.filter_variables(keep::Function, f::VectorOfDecisions)
    return VectorOfDecisions(MOIU._filter_variables(keep, f.decisions))
end

function MOIU.vectorize(funcs::AbstractVector{SingleDecision})
    decisions = MOI.VariableIndex[f.decision for f in funcs]
    return VectorOfDecisions(decisions)
end

function MOIU.scalarize(f::VectorOfDecisions, ignore_constants::Bool = false)
    SingleDecision.(f.decisions)
end


text:
using DependencyParser.DependencyParsing

# Build gold tree for sentence: "He wrote her a letter."
function build_gold_tree()
  root = TreeNode(0)
  nodes = vec(
    [
      TreeNode(1, "SBJ", 2),
      TreeNode(2, "PRD", 0),
      TreeNode(3, "IOBJ", 2),
      TreeNode(4, "DET", 5),
      TreeNode(5, "DOBJ", 2),
      TreeNode(6, "P", 2)
    ]
  )
  length = 6

  DependencyTree(root, nodes, length)
end

# Tree for "He wrote her a letter." after: SH, LA, RA, RA
function build_uncomplete_tree()
  root = TreeNode(0)
  nodes = vec(
    [
      TreeNode(1, "SBJ", 2),
      TreeNode(2, "PRD", 0),
      TreeNode(3, "IOBJ", 2),
      TreeNode(4, EMPTY_LABEL, EMPTY_NODE),
      TreeNode(5, EMPTY_LABEL, EMPTY_NODE),
      TreeNode(6, EMPTY_LABEL, EMPTY_NODE)
    ]
  )
  length = 6

  DependencyTree(root, nodes, length)
end

max_stars_repo_name: LarsWl/DependencyParser

max_issues_repo_name: LarsWl/DependencyParser

max_forks_repo_name: LarsWl/DependencyParser


text:
struct TikzPlotScatter <: AbstractTikzPlot
	x::AbstractVector{Number}
	y::AbstractVector{Number}
	named_attributes::Dict{String, String} # Attributes that are defined using name = value syntax (I.E line width = 3)
	value_attributes::Vector{String} # Attributes that are specified by simply being present (I.E 'only marks' for a scatter plot)
end

function scatter!(axis::TikzAxis, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, named_attributes::Dict{String,String}=Dict{String,String}(), value_attributes::Vector{String}=Vector{String}(["only marks"]))
	push!(axis.plots, TikzPlotScatter(x, y, named_attributes, value_attributes))
	return axis
end

function scatter!(figure::TikzFigure, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, named_attributes::Dict{String,String}=Dict{String,String}(), value_attributes::Vector{String}=Vector{String}(["only marks"]))
	scatter!(figure.axes[begin], x, y, named_attributes, value_attributes)
	return figure
end

function scatter(x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, named_attributes::Dict{String,String}=Dict{String,String}(), value_attributes::Vector{String}=Vector{String}(["only marks"]))
	return scatter!(EmptyTikzFigure(), x, y, named_attributes, value_attributes)
end

function ToTikzString(plot::TikzPlotScatter)
	retString = ""
	retString *= "\\addplot[\n"
	for (k,v) in plot.named_attributes
		retString *= "$k = $v,\n"
	end
	for a in plot.value_attributes
		retString *= "$a,\n"
	end
	retString *= "]\n"
	retString *= "coordinates\n{\n"
	for pt_i in range(1, length(plot.x))
		retString *= "($(plot.x[pt_i]), $(plot.y[pt_i]))\n"
	end
	retString *= "};\n"
	return retString
end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

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

                     @variable(m, -51.708688423784224 <= q <= 53.49505517188359)

                     add_NL_constraint(m, :(1/(1 + exp(-(0.12651985253467002 + 0.8800990177661969*1/(1 + exp(-(0.9367289958343452 + 0.010085610540752743*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.46191185446397043*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.4430556996324988*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.9244167282970754*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.15008923933940022*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.9059509477084742*1/(1 + exp(-(-0.9076856947519341 + 0.6427398296015978*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.5974696839876872*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.3127996929073351*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.8921846648994118*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.8861141904898706*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.7662733112940292*1/(1 + exp(-(0.014219790982957559 + -0.1830460372609095*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.18937048380167898*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.48856019606524415*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.6243584215460145*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.6378733350620909*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.3066544631255512*1/(1 + exp(-(0.37873800689777815 + 0.3786798527526116*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.15214183164812667*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.4531653277321981*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + -0.2698943947473773*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.8205030207972928*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.673637701918695*1/(1 + exp(-(0.41028851710489267 + 0.3789873528571355*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.13395473418456794*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.9211828416113521*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.005265087561311166*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.6679558602332873*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4])))))))))) + 1/(1 + exp(-(-0.8950204772394628 + -0.19603919659654778*1/(1 + exp(-(0.9367289958343452 + 0.010085610540752743*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.46191185446397043*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.4430556996324988*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.9244167282970754*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.15008923933940022*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.902347490498435*1/(1 + exp(-(-0.9076856947519341 + 0.6427398296015978*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.5974696839876872*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.3127996929073351*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.8921846648994118*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.8861141904898706*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.30440629677970144*1/(1 + exp(-(0.014219790982957559 + -0.1830460372609095*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.18937048380167898*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.48856019606524415*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.6243584215460145*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.6378733350620909*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.6770808003403048*1/(1 + exp(-(0.37873800689777815 + 0.3786798527526116*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.15214183164812667*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.4531653277321981*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + -0.2698943947473773*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.8205030207972928*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.03232239144278681*1/(1 + exp(-(0.41028851710489267 + 0.3789873528571355*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.13395473418456794*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.9211828416113521*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.005265087561311166*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.6679558602332873*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4])))))))))) + 1/(1 + exp(-(-0.11076390433121786 + 0.7661103402200116*1/(1 + exp(-(0.9367289958343452 + 0.010085610540752743*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.46191185446397043*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.4430556996324988*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.9244167282970754*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.15008923933940022*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.9009199905889229*1/(1 + exp(-(-0.9076856947519341 + 0.6427398296015978*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.5974696839876872*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.3127996929073351*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.8921846648994118*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.8861141904898706*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.5631507797475948*1/(1 + exp(-(0.014219790982957559 + -0.1830460372609095*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.18937048380167898*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.48856019606524415*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.6243584215460145*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.6378733350620909*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.4163802251888926*1/(1 + exp(-(0.37873800689777815 + 0.3786798527526116*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.15214183164812667*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.4531653277321981*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + -0.2698943947473773*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.8205030207972928*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.17662226846197893*1/(1 + exp(-(0.41028851710489267 + 0.3789873528571355*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.13395473418456794*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.9211828416113521*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.005265087561311166*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.6679558602332873*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4])))))))))) + 1/(1 + exp(-(0.8242960442017702 + -0.7506191216499181*1/(1 + exp(-(0.9367289958343452 + 0.010085610540752743*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.46191185446397043*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.4430556996324988*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.9244167282970754*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.15008923933940022*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.31521888864028513*1/(1 + exp(-(-0.9076856947519341 + 0.6427398296015978*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.5974696839876872*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.3127996929073351*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.8921846648994118*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.8861141904898706*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.5308637261158768*1/(1 + exp(-(0.014219790982957559 + -0.1830460372609095*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.18937048380167898*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.48856019606524415*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.6243584215460145*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.6378733350620909*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.6654841763336146*1/(1 + exp(-(0.37873800689777815 + 0.3786798527526116*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.15214183164812667*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.4531653277321981*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + -0.2698943947473773*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.8205030207972928*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.2645412007156045*1/(1 + exp(-(0.41028851710489267 + 0.3789873528571355*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.13395473418456794*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.9211828416113521*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.005265087561311166*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.6679558602332873*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4])))))))))) + 1/(1 + exp(-(-0.6657453597374303 + 0.46323784626870257*1/(1 + exp(-(0.9367289958343452 + 0.010085610540752743*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.46191185446397043*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.4430556996324988*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.9244167282970754*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.15008923933940022*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.7128966868012561*1/(1 + exp(-(-0.9076856947519341 + 0.6427398296015978*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.5974696839876872*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.3127996929073351*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.8921846648994118*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.8861141904898706*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.43240821263487783*1/(1 + exp(-(0.014219790982957559 + -0.1830460372609095*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + 0.18937048380167898*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.48856019606524415*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.6243584215460145*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.6378733350620909*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + -0.6998749584965918*1/(1 + exp(-(0.37873800689777815 + 0.3786798527526116*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.15214183164812667*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + 0.4531653277321981*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + -0.2698943947473773*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + -0.8205030207972928*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4]))))))) + 0.6177298271304656*1/(1 + exp(-(0.41028851710489267 + 0.3789873528571355*1/(1 + exp(-(-0.5507415348587976 + -0.9382157052845588*$(x[1]) + 0.32792621601464056*$(x[2]) + 0.04402367930308282*$(x[3]) + 0.8348925442898456*$(x[4])))) + -0.13395473418456794*1/(1 + exp(-(0.4569151270063867 + 0.9855428533575652*$(x[1]) + 0.27576336558204195*$(x[2]) + 0.024724286249658167*$(x[3]) + -0.4115946180479595*$(x[4])))) + -0.9211828416113521*1/(1 + exp(-(0.5124722980797523 + -0.021522352811447654*$(x[1]) + 0.09961216478582813*$(x[2]) + -0.5936461652265081*$(x[3]) + 0.7973439553626904*$(x[4])))) + 0.005265087561311166*1/(1 + exp(-(0.16894693163358276 + -0.35673489881937037*$(x[1]) + 0.5082818593140526*$(x[2]) + 0.7581208342644015*$(x[3]) + -0.6603822729791307*$(x[4])))) + 0.6679558602332873*1/(1 + exp(-(-0.5086292355642796 + -0.9220327700183186*$(x[1]) + 0.16243082406428888*$(x[2]) + 0.7781879917830965*$(x[3]) + 0.45589624224566805*$(x[4])))))))))) - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions


text:
using Mosek, Mosek.Ext, Test
import Pkg

mosekbase = dirname(dirname(pathof(Mosek)))

@testset "[show]" begin
    for fname in [ "25fv47.task", "lj-inner.task"]
        maketask(filename=joinpath(mosekbase,"test",fname)) do t
            open(joinpath(mosekbase,"test",join("show-",fname)),"w") do f
                println(f,t)

                n = getnumvar(t)
                m = getnumcon(t)
                numcone = getnumcone(t)
                numbarvar = getnumbarvar(t)

                if n > 0
                    for j in 1:n
                        println(f,t[Var(j)])
                    end
                end

                if m > 0
                    for j in 1:m
                        println(f,t[Con(j)])
                    end
                end

                if numcone > 0
                    for j in 1:numcone
                        println(f,t[Cone(j)])
                    end
                end

                if numbarvar > 0
                    for j in 1:getnumbarvar(t)
                        println(f,t[Barvar(j)])
                    end
                end

                for which in Soltype
                    if solutiondef(t,which)
                        sol = t[Sol(which)]

                        println(f,sol)

                        if n > 0
                            for j in 1:n
                                println(f,sol[Var(j)])
                            end
                        end

                        if m > 0
                            for j in 1:m
                                println(f,sol[Con(j)])
                            end
                        end

                        if numbarvar > 0
                            for j in 1:getnumbarvar(t)
                                println(f,sol[Barvar(j)])
                            end
                        end
                    end
                end
            end
        end
    end
end


text:
using JET.JETInterfaces

# customized report pass
# ======================

struct IgnoreAllPass <: ReportPass end
(::IgnoreAllPass)(::Type{<:InferenceErrorReport}, @nospecialize(_...)) = return
let
    analyzer, = @report_call report_pass=IgnoreAllPass() sum("julia")
    @test isempty(get_reports(analyzer))
end

struct IgnoreAllExceptGlobalUndefVar <: ReportPass end
(::IgnoreAllExceptGlobalUndefVar)(::Type{<:InferenceErrorReport}, @nospecialize(_...)) = return
function (::IgnoreAllExceptGlobalUndefVar)(::Type{GlobalUndefVarErrorReport}, @nospecialize(args...))
    BasicPass()(GlobalUndefVarErrorReport, args...)
end
let
    analyzer, = report_call(; report_pass=IgnoreAllExceptGlobalUndefVar()) do
        sum("julia") # should be ignored
        undefvar
    end
    @test length(get_reports(analyzer)) == 1
    let r = first(get_reports(analyzer))
        @test isa(r, GlobalUndefVarErrorReport)
        @test r.name === :undefvar
    end
end

# AbstractAnalyzer API
# ====================

# NOTE actual functionalities are tested by documentation

struct APIValidator <: AbstractAnalyzer
    state::AnalyzerState
end

function compute_sins(i)
    n = 1000000
    out = Vector{Float64}(undef, n)
    Threads.@threads for itr in 1:n
        i = itr
        out[i] = sin(i)
    end
    return out
end

@test_throws ErrorException @report_call analyzer=APIValidator compute_sins(10)

# `APIValidator(; jetconfigs...) -> APIValidator`
APIValidator(; jetconfigs...) = APIValidator(AnalyzerState(; jetconfigs...))

@test_throws ErrorException @report_call analyzer=APIValidator compute_sins(10)

# `AnalyzerState(analyzer::APIValidator) -> AnalyzerState`
AnalyzerState(analyzer::APIValidator) = analyzer.state

@test_throws ErrorException @report_call analyzer=APIValidator compute_sins(10)

# `ReportPass(analyzer::APIValidator) -> ReportPass`
ReportPass(analyzer::APIValidator) = IgnoreAllPass()

@test_throws ErrorException @report_call analyzer=APIValidator compute_sins(10)

# `AbstractAnalyzer(analyzer::APIValidator, state::AnalyzerState) -> APIValidator`
AbstractAnalyzer(analyzer::APIValidator, state::AnalyzerState) = APIValidator(state)

# because `APIValidator` uses `IgnoreAllPass`, we won't get any reports
analyzer, = @report_call analyzer=APIValidator compute_sins(10)
@test isempty(get_reports(analyzer))


text:
# ZeroOneLoss

using LaTeXStrings, LossFunctions, Measures, Latexify

Plots.plot(ZeroOneLoss(), leg=:topright, c=:olive, linewidth=2)

max_stars_repo_name: Ellon-M/visualizations

max_issues_repo_name: Ellon-M/visualizations

max_forks_repo_name: Ellon-M/visualizations


text: somevar = 10

max_stars_repo_name: PacktPublishing/Julia-Projects

max_issues_repo_name: PacktPublishing/Julia-Projects

max_forks_repo_name: PacktPublishing/Julia-Projects


text:
#---------------------------------------------------------
# # [Parameters guide](@id parameters)
#---------------------------------------------------------

#md # [![](https://mybinder.org/badge_logo.svg)](@__BINDER_ROOT_URL__/notebooks/1_parameters.ipynb)
#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/notebooks/1_parameters.ipynb)

#md # !!! note
#md #     All the AIBECS tutorials and how-to guides are available as Jupyter notebooks.
#md #     You can view them with [nbviewer](https://nbviewer.jupyter.org/)or execute them online with [binder](https://mybinder.org/) by clicking on the badges above!
#md #     (Note that binder can be slow to launch and its memory caps can be a problem when running.)

# Here we will describe the AIBECS interface.
# This guide will take you through some examples of setting up model parameters.

#md # !!! note
#md #     The parameters features in AIBECS essentially come from other packages.
#md #     These include [Parameters.jl](https://github.com/mauro3/Parameters.jl), [FieldMetadata.jl](https://github.com/rafaqz/FieldMetadata.jl), [Flatten.jl](https://github.com/rafaqz/Flatten.jl), [Unitful.jl](https://github.com/PainterQubits/Unitful.jl).

#nb # > **Note:**
#nb # > The parameters features in AIBECS essentially come from other packages.
#nb # > These include [Parameters.jl](https://github.com/mauro3/Parameters.jl), [FieldMetadata.jl](https://github.com/rafaqz/FieldMetadata.jl), [Flatten.jl](https://github.com/rafaqz/Flatten.jl), [Unitful.jl](https://github.com/PainterQubits/Unitful.jl).

# As usual, make sure you are using AIBECS

using AIBECS

# ## Abstract parameters type

# The AIBECS provides a set of features to create and use parameters.
# This features are implemented as functions that must be provided with a parameters type.
# But each set of parameters is different, and AIBECS cannot know beforehand what parameters you want to use.
# The AIBECS thus provides an abstract parameters type, called `AbstractParameters`, upon which all the AIBECS functionality is built.
# This is why when you create a set of parameters in AIBECS, you must declare it as a subtype of `AbstractParameters`.
# Here is an example.

struct SimpleParams{T} <: AbstractParameters{T}
    α::T
    β::T
end

# Once the type, which here simply defines the symbols (`α` and `β`), is constructed, we can *instantiate* a parameter variable.

p = SimpleParams(1.0, 2.0)

# As you can see, the AIBECS will display `p` as a table.
# This is because the `show` method converts `p` to a table (a `DataFrame` to be specific) under the hood:

AIBECS.table(p)

# If you do not remember the order in which you created the parameters (`α` is first, `β` is second), AIBECS has got your back: keyword arguments are supported.

p = SimpleParams(β = 2.0, α = 1.0)

# ## Unpacking

# Probably the most useful feature in AIBECS is the ability to elegantly unpack parameters, thanks to [Parameters.jl](https://github.com/mauro3/Parameters.jl).

@unpack α, β = p
α, β

# unpacks the parameters on the left (`α` and `β`) from the parameter type `p`.

# ## Units

# One of the main features of parameters in AIBECS is that you can use units and let AIBECS do the conversions for you.
# Before you use units, though, you **must** import the `@units` and `units` functions from AIBECS.
# Here is an example.

import AIBECS: @units, units
@units struct UnitfulParams{T} <: AbstractParameters{T}
    α::T | u"m/s"
    β::T | u"d"
end

# Cretaing an instance is just as easy

p = UnitfulParams(1.0, 2.0)

# And in this case the parameters are shown with units.
# You can rely on AIBECS to convert units on the fly.

p = UnitfulParams(3.0u"km/hr", 24.0u"hr")

# And use keyword arguments

p = UnitfulParams(β = 24.0u"hr", α = 3.0u"km/hr")

# Unpacking parameters that have units first converts them to SI units.

@unpack β = p
β

# and `β` (which is equal to 1 day) here is expressed in seconds after being unpacked.

# ## Initial values

# Another useful feature is to set initial (or default) values.
# Again, you **must** import the functions for them to work properly

import AIBECS: @initial_value, initial_value
@initial_value struct ParamsWithInitialValue{T} <: AbstractParameters{T}
    α::T | 1.0
    β::T | 2.0
end

# This is handy in many applications.

# You can instantiate `p` with the initial values as, well, its values.

p = ParamsWithInitialValue()

# You could also just set one parameter to a different value

p = ParamsWithInitialValue(β = 10.0)

# ## Combining initial values and units

# You can combine both features in parameters.

@initial_value @units struct UnitfulParamsWithInitialValue{T} <: AbstractParameters{T}
    α::T | 1.0 | u"m/s"
    β::T | 2.0 | u"d"
end

# And instantiate `p` from just one parameter with its unit

p = UnitfulParamsWithInitialValue(β = 1.0u"yr")

# ## Optimizable parameters

import AIBECS: @flattenable, flattenable
@flattenable struct OptimizableParams{T} <: AbstractParameters{T}
    α::T | true
    β::T | false
    γ::T | true
end

# Then the "flattenable" parameters will be the only ones to remain when converting `OptimizableParams` to a vector

p = OptimizableParams(1.0, 2.0, 3.0)
v = vec(p)

# The `vec` function uses the `@unpack` function in AIBECS, so that units are converted when vectorizing.
# Here is an example of that by first combining `units` and `flattenable`.

@initial_value @units @flattenable struct OptimizableParamsWithUnits{T} <: AbstractParameters{T}
    α::T | 1.0 | u"m/s" | true
    β::T | 2.0 | u"d"   | false
    γ::T | 3.0 | u"km"  | true
end
p = OptimizableParamsWithUnits()

# And then vectorizing the parameters

vec(p)

# Note how `γ` (the third parameter, but the second flattenable one), is converted to meters.

# ## Other features

# Coming soon!


text:
using Kattis
using Test

include("origami.jl")
include("zeroone.jl")
include("maxflow.jl")


text:
using HackerNewsSlackApp

monitor, task = monitor_hackernews([
           "julia", "python", "typescript", "javascript", "hong kong",
           "google", "facebook", "paypal"
       ], interval = 300)

wait(task)


text:
using Test

using MathOptInterface
const MOI = MathOptInterface
const MOIT = MOI.DeprecatedTest
const MOIU = MOI.Utilities
const MOIB = MOI.Bridges

import SDPA
const optimizer = SDPA.Optimizer()
MOI.set(optimizer, MOI.Silent(), true)

@testset "SolverName" begin
    @test MOI.get(optimizer, MOI.SolverName()) == "SDPA"
end

# UniversalFallback is needed for starting values, even if they are ignored by SDPA
const cache = MOIU.UniversalFallback(MOIU.Model{Float64}())
const cached = MOIU.CachingOptimizer(cache, optimizer)
const bridged = MOIB.full_bridge_optimizer(cached, Float64)
# test 1e-3 because of rsoc3 test, otherwise, 1e-5 is enough
const config = MOIT.Config(atol=1e-3, rtol=1e-3)

@testset "Unit" begin
    MOIT.unittest(bridged, config, [
        # TODO(odow): FIX THIS
        "solve_twice",
        # `NumberOfThreads` not supported.
        "number_threads",
        # `TimeLimitSec` not supported.
        "time_limit_sec",
        # SingleVariable objective of bridged variables, will be solved by objective bridges
        "solve_time",
        "raw_status_string",
        "solve_singlevariable_obj",
        # Quadratic functions are not supported
        "solve_qcp_edge_cases",
        "solve_qp_edge_cases",
        "solve_qp_zero_offdiag",
        # Integer and ZeroOne sets are not supported
        "solve_integer_edge_cases",
        "solve_objbound_edge_cases",
        "solve_zero_one_with_bounds_1",
        "solve_zero_one_with_bounds_2",
        "solve_zero_one_with_bounds_3",
        # FarkasDual tests: SDPA doesn't like proving infeasibility for these...
        # Expression: MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
        #  Evaluated: MathOptInterface.INFEASIBLE_OR_UNBOUNDED == MathOptInterface.INFEASIBLE
        "solve_farkas_equalto_upper",
        "solve_farkas_equalto_lower",
        "solve_farkas_lessthan",
        "solve_farkas_greaterthan",
        "solve_farkas_interval_lower",
        "solve_farkas_interval_upper",
        "solve_farkas_variable_lessthan",
        "solve_farkas_variable_lessthan_max",
        "solve_start_soc", # RSOCtoPSDBridge seems to be incorrect for dimension-2 RSOC cone.
    ])
end

@testset "Linear tests" begin
    # See explanation in `MOI/test/Bridges/lazy_bridge_optimizer.jl`.
    # This is to avoid `Variable.VectorizeBridge` which does not support
    # `ConstraintSet` modification.
    MOIB.remove_bridge(bridged, MOIB.Constraint.ScalarSlackBridge{Float64})
    MOIT.contlineartest(bridged, config, [
        # `MOI.UNKNOWN_RESULT_STATUS` instead of `MOI.INFEASIBILITY_CERTIFICATE`
        "linear8a",
        "linear12"
    ])
end
@testset "Conic tests" begin
    MOIT.contconictest(bridged, config, [
        "lin3", "soc3", "normone2", "norminf2",
        # Missing bridges
        "rootdets",
        # Does not support power and exponential cone
        "pow", "dualpow", "logdet", "exp", "dualexp", "relentr"])
end