text:
lattice = load_lattice(joinpath(@__DIR__, "CrFe2Ga_qe.in"))
atoms   = load_atoms(  joinpath(@__DIR__, "CrFe2Ga_qe.in"))
atoms   = attach_pseudos(atoms, Cr="hgh/pbe/cr-q14.hgh",
                                Fe="hgh/pbe/fe-q16.hgh",
                                Ga="hgh/pbe/ga-q3.hgh")
magnetic_moments = build_magnetic_moments(atoms; Ga=0.0, Fe=5.0, Cr=5.0)

cases = Dict(
    "maxcond_1e2" => (damping=DFTK.FixedDamping(0.3), diagtol_max=1e-8,
                      acceleration=DFTK.AndersonAcceleration(; maxcond=1e2)),
    "maxcond_1e4" => (damping=DFTK.FixedDamping(0.3), diagtol_max=1e-8,
                      acceleration=DFTK.AndersonAcceleration(; maxcond=1e4)),
    "maxcond_1e6" => (damping=DFTK.FixedDamping(0.3), diagtol_max=1e-8,
                      acceleration=DFTK.AndersonAcceleration(; maxcond=1e6)),
    "maxcond_1e8" => (damping=DFTK.FixedDamping(0.3), diagtol_max=1e-8,
                      acceleration=DFTK.AndersonAcceleration(; maxcond=1e8)),
    "maxcond_1e10" => (damping=DFTK.FixedDamping(0.3), diagtol_max=1e-8,
                       acceleration=DFTK.AndersonAcceleration(; maxcond=1e10)),
)

function load_Fe2CrGa_potential_40(basis)
    guessfile = joinpath(@__DIR__, "Fe2CrGa40_initV.jld2")
    if !isfile(guessfile)
        ρ, ψ0, V = load_guess(basis, joinpath(@__DIR__, "../Fe2CrGa/init.jld2"))
        resultsfile = joinpath(@__DIR__, "init.scfres.json")

        scfres = run_dftk(basis, resultsfile; ρ=ρ, ψ0=ψ0, V=V,
                          mixing=KerkerMixing(), damping=DFTK.FixedDamping(0.3),
                          acceleration=DFTK.AndersonAcceleration(; maxcond=1e6), maxiter=40)
        V = DFTK.total_local_potential(scfres.ham)
        jldopen(guessfile, "w") do file
            file["V"] = V
        end
    end
    jldopen(file -> file["V"], guessfile, "r")
end

config[@__DIR__] = (
    directory        =  @__DIR__,
    lattice          = lattice,
    atoms            = atoms,
    magnetic_moments = magnetic_moments,
    #
    kwargs_model     = (smearing=Smearing.Gaussian(), temperature=0.01),
    Ecut             = 45,
    kgrid            = [13, 13, 13],
    supersampling    = 2.0,
    potential        = load_Fe2CrGa_potential_40,
    kwargs_scf       = (; ),
    mixing           = KerkerMixing(),
    cases            = cases,
)

max_stars_repo_name: mfherbst/supporting-adaptive-damping

max_issues_repo_name: mfherbst/supporting-adaptive-damping

max_forks_repo_name: mfherbst/supporting-adaptive-damping


text:
# Julia wrapper for header: /usr/local/include/libavcodec/xvmc.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

export

ext: jl

max_stars_repo_name: asafasban/AAVideoIO

max_issues_repo_name: asafasban/AAVideoIO

max_forks_repo_name: asafasban/AAVideoIO


text:
using Gen
import LinearAlgebra: eigvals
import DifferentialEquations: solve, ODEProblem, OrdinaryDiffEq

# --------------------------------------------------------------------------------------------
# We create a type for the parameter associated to the predator-prey differential equation
# --------------------------------------------------------------------------------------------
mutable struct PredatorPreyParameter
  P0::Float64
  Q0::Float64
  r::Float64
  K::Float64
  s::Float64
  a::Float64
  u::Float64
  v::Float64
  start_time::Float64
  stop_time::Float64
  solution::Union{Nothing, OrdinaryDiffEq.ODECompositeSolution}
end
Base.Array(p::PredatorPreyParameter) = [
  p.P0, p.Q0, p.r, p.K, p.s, p.a, p.u, p.v, p.start_time, p.stop_time, p.solution
]
init(p::PredatorPreyParameter) = [p.P0, p.Q0]
ode_params(p::PredatorPreyParameter) = [p.r, p.K, p.s, p.a, p.u, p.v]
times(p::PredatorPreyParameter) = (p.start_time, p.stop_time)
Base.display(p::PredatorPreyParameter) = print(
"""
PredatorPreyParameter ($(isnothing(p.solution) ? "without" : "with") solution):
  P0: $(p.P0)
  Q0: $(p.Q0)
  r: $(p.r)
  K: $(p.K)
  s: $(p.s)
  a: $(p.a)
  u: $(p.u)
  v: $(p.v)
  start_time: $(p.start_time)
  stop_time: $(p.stop_time)
""")

struct PredatorPreyPrior <: Gen.Distribution{PredatorPreyParameter} end
const predator_prey_prior = PredatorPreyPrior()

# --------------------------------------------------------------------------------------------
# Use DifferentialEquations.jl to simulate solutions
# --------------------------------------------------------------------------------------------
function predator_prey_system(dy, y, p, t)
  r, K, s, a, u, v = p
  dy[1] = r * y[1] * (1 - y[1] / K) - s * y[1] * y[2] / (a + y[1])
  dy[2] = u * y[1] * y[2] / (a + y[1]) - v * y[2]
end

function predator_prey_problem(parameter::PredatorPreyParameter)
  ODEProblem(predator_prey_system, init(parameter), times(parameter), ode_params(parameter))
end

# --------------------------------------------------------------------------------------------
# Prior distribution imposes domain knowledge: parameters must produce stable populations
# --------------------------------------------------------------------------------------------
function stable!(parameter::PredatorPreyParameter)::Bool
  # if we have a solution already, we are good
  if !isnothing(parameter.solution)
    return true
  end

  # unpack the parameter
  P0, Q0 = init(parameter)
  r, K, s, a, u, v = ode_params(parameter)

  # if P0 > K, population is already above carrying capacity
  if P0 > K
    return false
  end

  # stable point must be positive and under carrying capacity
  Pf = a * v / (u - v)
  Qf = a * r * (1 + v / (u - v)) * (K - a * v / (u - v)) / (K * s)
  if (Pf <= 0 || Pf > K || Qf <= 0)
    return false
  end

  # Jacobian at stable point must have eigenvalues with (almost) positive real components
  jacobian = [
    (r - 2r*Pf/K - s*((a+Pf)*Qf - Pf*Qf)/(a+Pf)^2) (-s*Pf/(a+Pf)) ;
    (u*((a+Pf)*Qf - Pf*Qf)/(a+Pf)^2) (u*Pf/(a+Pf) - v)
  ]
  lam, = eigvals(jacobian)
  if real(lam) < -1e-14
    return false
  end

  # we passed cyclic condition; check if numerically stable
  solution = solve(predator_prey_problem(parameter), verbose=false)
  if solution.retcode === :Success
    parameter.solution = solution
    return true
  end
  return false
end

function Gen.random(
  dist::PredatorPreyPrior,
  lower::Float64,
  upper::Float64,
  start_time::Float64,
  stop_time::Float64
)
  # parse arguments
  if lower <= 0
    throw(ArgumentError("PredatorPreyPrior must assume positive parameters"))
  end

  # rejection sample uniform
  while true
    Q0, r, K, s, a, u, v = [rand() * (upper-lower) + lower for _=1:7]
    P0 = rand() * (K - lower) + lower
    p = PredatorPreyParameter(P0, Q0, r, K, s, a, u, v, start_time, stop_time, nothing)

    if stable!(p)
      return p
    end
  end
end

function Gen.logpdf(
  dist::PredatorPreyPrior,
  param::PredatorPreyParameter,
  lower::Float64,
  upper::Float64,
  start_time::Float64,
  stop_time::Float64
)
  is_stable = stable!(param)
  same_times = (start_time, stop_time) == times(param)
  possible = same_times && all(x -> x >= lower && x <= upper, Array(param)[1:8]) && is_stable
  possible ? -Inf : 0.0
end
Gen.has_output_grad(dist::PredatorPreyPrior) = true
Gen.has_argument_grads(dist::PredatorPreyPrior) = (true, true)
Gen.logpdf_grad(dist::PredatorPreyPrior, value::PredatorPreyParameter, lower::Float64, upper::Float64) = (0.0, 1.0, -1.0)

@gen function measurement(mu::Vector{Float64}, var::Float64)
  @trace(mvnormal(mu, [var 0.0 ; 0.0 var]), :z)
end

@gen function predator_prey_model(
  lower_prior::Float64,
  upper_prior::Float64,
  start_time::Float64,
  stop_time::Float64,
  timesteps::Int64,
  measurement_noise::Float64
)
  # sample our custom prior
  parameter = @trace(
    predator_prey_prior(lower_prior, upper_prior, start_time, stop_time),
    :predator_prey_parameter
  )

  # simulate measurements
  times = LinRange(start_time, stop_time, timesteps+1)[2:end]
  means = map(t -> parameter.solution(t), times)
  noises = fill(measurement_noise, timesteps)
  @trace(Map(measurement)(means, noises), :measurements)
end

max_stars_repo_name: mvarble/gen-transport-mcmc

max_issues_repo_name: mvarble/gen-transport-mcmc

max_forks_repo_name: mvarble/gen-transport-mcmc


text:
mutable struct ForceOrderedLikelihood <: MyXMLElement
    el::XMLOrNothing
    parameter::MyXMLElement

    function ForceOrderedLikelihood(p::MyXMLElement)
        return new(nothing, p)
    end
end

function make_xml(fol::ForceOrderedLikelihood)
    el = new_element("forceOrderedLikelihood")
    make_xml(fol.parameter)
    param_id = get_id(fol.parameter.el)
    add_ref_el(el, fol.parameter.el)
    set_id!(el, param_id * ".forceDescending")
    fol.el = el
    return el
end

function get_priors(fol::ForceOrderedLikelihood)
    make_xml(fol)
    return [fol.el]
end

mutable struct ColumnSwapOperator <: OperatorXMLElement
    el::XMLOrNothing
    matparam::MatrixParameter
    weight::Float64

    function ColumnSwapOperator(mp::MatrixParameter, weight::Float64)
        return new(nothing, mp, weight)
    end
end

function make_xml(cso::ColumnSwapOperator)
    el = new_element("columnSwapOperator")
    make_xml(cso.matparam)
    add_ref_el(el, cso.matparam.el)
    set_attribute(el, bn.WEIGHT, cso.weight)
    cso.el = el
    return el
end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

# This file contains the minimal support of RandomDevice for Base's own usage.
# The actual RandomDevice type that makes use of this infrastructure is defined
# in the Random stdlib.

module DevRandomState
    if !Sys.iswindows()
        mutable struct FileRef
            @atomic file::Union{IOStream, Nothing}
        end
        const DEV_RANDOM  = FileRef(nothing)
        const DEV_URANDOM = FileRef(nothing)
    end
    function __init__()
        if !Sys.iswindows()
            @atomic DEV_RANDOM.file = nothing
            @atomic DEV_URANDOM.file = nothing
        end
    end
end

if Sys.iswindows()
    function RtlGenRandom!(A::Union{Array, Ref})
        Base.windowserror("SystemFunction036 (RtlGenRandom)", 0 == ccall(
            (:SystemFunction036, :Advapi32), stdcall, UInt8, (Ptr{Cvoid}, UInt32),
              A, sizeof(A)))
    end

    # Manually implemented to work without the Random machinery
    function _rand_uint()
        r = Ref{Cuint}()
        RtlGenRandom!(r)
        return r[]
    end
else # !windows
    function _get_dev_random_fd(unlimited::Bool)
        ref = unlimited ? DevRandomState.DEV_URANDOM : DevRandomState.DEV_RANDOM
        fd = ref.file
        if fd === nothing
            fd = open(unlimited ? "/dev/urandom" : "/dev/random")
            old, ok = @atomicreplace ref.file nothing => fd
            if !ok
                close(fd)
                fd = old::IOStream
            end
        end
        return fd
    end

    # Manually implemented to work without the Random machinery
    function _rand_uint()
        return read(_get_dev_random_fd(true), Cuint)
    end
end # os-test

function _ad_hoc_entropy()
    println(stderr,
        "Entropy pool not available to seed RNG; using ad-hoc entropy sources.")
    seed = reinterpret(UInt64, time())
    seed = hash(seed, getpid() % UInt)
    try
        seed = hash(seed, parse(UInt64,
                                read(pipeline(`ifconfig`, `sha1sum`), String)[1:40],
                                base = 16) % UInt)
    catch
    end
    return seed
end

function _make_uint_seed()
    try
        _rand_uint()
    catch
        return _ad_hoc_entropy() % Cuint
    end
end

max_stars_repo_name: BSnelling/julia

max_issues_repo_name: BSnelling/julia

max_forks_repo_name: BSnelling/julia


text:
function DataFrame(array::Array{T, 1}) where T <: TwitterType

    #Empty df as container for results
    resultdf = DataFrame()

    #Get array of field names as symbols from composite type
    cols = fieldnames(T)

    #For each field in composite type...
    for column in cols

        #Temp array to hold results
        temp = []

        #Loop over array of composite type, get individual field value from outer loop value
        for value in array
            push!(temp, getfield(value, column))
        end

        #Append each column to df
        resultdf = hcat(resultdf, temp, makeunique=true)

    end

    #Use cols array above to properly name df columns
    try
      names!(resultdf, [x for x in cols])
    catch err
      if isa(err, UndefVarError)
        rename!(resultdf, [x for x in cols])
      else
        throw(err)
      end
    end

    return resultdf

end

#Convert single returned composite type to array
DataFrame(response::T) where T <: TwitterType = DataFrame([response])


text:
struct Node
	name :: String
	size :: String
end

struct Edge
	sideA :: Node
	sideB :: Node
end

issmall(n :: Node) = n.size == "small"
isbig(n :: Node) = n.size == "big"
other(edge :: Edge, node :: Node) = node == edge.sideA ? edge.sideB : node == edge.sideB ? edge.sideA : error("node not on either edge")
isstart(n :: Node) = n.name == "start"
isend(n :: Node) = n.name == "end"
getedges(n :: Node, edges :: Vector{Edge}) = [edge for edge in edges if edge.sideA == n || edge.sideB == n]

function makenode(name :: String)
	size = all(isuppercase(n) for n in name) ? "big" : "small"

	return Node(name, size)
end

function setup()
	edges = Edge[]
	nodes = Node[]
	lines = readlines("inputD12.txt")
	for line in lines
		sideA, sideB = string.(split(line, "-"))

		existingA = [n for n in nodes if n.name == sideA]
		if isempty(existingA)
			nodeA = makenode(sideA)
			push!(nodes, nodeA)
		else
			nodeA = first(existingA)
		end

		existingB = [n for n in nodes if n.name == sideB]
		if isempty(existingB)
			nodeB = makenode(sideB)
			push!(nodes, nodeB)
		else
			nodeB = first(existingB)
		end

		push!(edges, Edge(nodeA, nodeB))
	end

	return (edges, nodes)
end

function part1()
	edges, nodes = setup()

	start = first([n for n in nodes if isstart(n)])
	paths = [[start]]
	finished_paths = Vector{Node}[]

	while !isempty(paths)
		new_paths = Vector{Node}[]
		for path in paths
			current_node = last(path)
			node_edges = getedges(current_node, edges)
			targets = [other(ne, current_node) for ne in node_edges]
			for target in targets
				# decide if valid target
				if !isstart(target) && (isbig(target) || (issmall(target) && !(target in path)))
					new_path = push!(copy(path), target)

					isend(target) ? push!(finished_paths, new_path) : push!(new_paths, new_path)
				end
			end
		end

		paths = copy(new_paths)
	end

	return length(finished_paths)
end

function countdoubledsmallcaves(path :: Vector{Node})
	small_nodes = [node for node in path if issmall(node)]
	return length(small_nodes) - length(Set(small_nodes))
end

function part2()
	edges, nodes = setup()

	start = first([n for n in nodes if isstart(n)])
	paths = [[start]]
	finished_paths = Vector{Node}[]

	while !isempty(paths)
		new_paths = Vector{Node}[]
		for path in paths
			current_node = last(path)
			node_edges = getedges(current_node, edges)
			targets = [other(ne, current_node) for ne in node_edges]
			for target in targets
				# decide if valid target
				small_doubles = countdoubledsmallcaves(path)
				if !isstart(target) && (isbig(target) || (issmall(target) && (small_doubles == 0 || (small_doubles == 1 && !(target in path)))))
					new_path = push!(copy(path), target)

					isend(target) ? push!(finished_paths, new_path) : push!(new_paths, new_path)
				end
			end
		end

		paths = copy(new_paths)
	end

	return length(finished_paths)
end

println(part1())
println(part2())


text:
#=

# 115: 1D heterogeneous catalysis
 ([source code](SOURCE_URL))

Let $\Omega=(0,1)$, $\Gamma_1=\{0\}$, $\Gamma_2=\{1\}$
Regard a system of three species: $A,B,C$ and let
$u_A=[A]$, $u_B=[B]$ and $u_C=[C]$ be their corresponding concentrations.

Species $A$ and $B$ exist in the interior of the domain, species $C$
lives a the boundary $\Gamma_1$.  We assume a heterogeneous reaction scheme
where $A$ reacts to $C$ and $C$ reacts to $B$:

```math
\begin{aligned}
      A &\leftrightarrow C\\
      C &\leftrightarrow B
\end{aligned}
```
with reaction constants $k_{AC}^\pm$ and k_{BC}^\pm$.

In $\Omega$, both $A$ and $B$ are transported through diffusion:

```math
\begin{aligned}
\partial_t u_B - \nabla\cdot D_A \nabla u_A & = f_A\\
\partial_t u_B - \nabla\cdot D_B \nabla u_B & = 0\\
\end{aligned}
```
Here, $f(x)$ is a source term creating $A$.
On $\Gamma_2$, we set boundary conditions
```math
\begin{aligned}
D_A \nabla u_A & = 0\\
u_B&=0
\end{aligned}
```
describing no normal flux for $A$ and zero concentration of $B$.
On $\Gamma_1$, we use the mass action law to describe the boundary reaction and
the evolution of the boundary concentration $C$. We assume that there is a limited
amount of surface sites $S$ for species C, so in fact A has to react with a free
surface site in order to become $C$ which reflected by the factor $1-u_C$. The same
is true for $B$.
```math
\begin{aligned}
R_{AC}(u_A, u_C)&=k_{AC}^+ u_A(1-u_C) - k_{AC}^-u_C\\
R_{BC}(u_C, u_B)&=k_{BC}^+ u_B(1-u_C) - k_{BC}^-u_C\\
- D_A \nabla u_A  + S R_{AC}(u_A, u_C)& =0 \\
- D_B \nabla u_B  + S R_{BC}(u_B, u_C)& =0 \\
\partial_t C  - R_{AC}(u_A, u_C) - R_{BC}(u_B, u_C) &=0
\end{aligned}
```

=#

module Example115_HeterogeneousCatalysis1D
using Printf
using VoronoiFVM
using ExtendableGrids
using GridVisualize
using LinearAlgebra

function main(;n=10,Plotter=nothing,verbose=false,tend=1, unknown_storage=:sparse)

    h=1.0/convert(Float64,n)
    X=collect(0.0:h:1.0)
    N=length(X)

    grid=VoronoiFVM.Grid(X)
    ## By default, \Gamma_1 at X[1] and \Gamma_2 is at X[end]

    ## Species numbers
    iA=1
    iB=2
    iC=3

    ## Diffusion flux for species A and B
    D_A=1.0
    D_B=1.0e-2
    function flux!(f,u0,edge)
        u=unknowns(edge,u0)
        f[iA]=D_A*(u[iA,1]-u[iA,2])
        f[iB]=D_B*(u[iB,1]-u[iB,2])
    end

    ## Storage term of species A and B
    function storage!(f,u,node)
        f[iA]=u[iA]
        f[iB]=u[iB]
    end

    ## Source term for species a around 0.5
    function source!(f,node)
        x1=node[1]-0.5
        f[iA]=exp(-100*x1^2)
    end

    ## Reaction constants (p = + , m = -)
    ## Choosen to prefer path A-> C -> B
    ## More over, A reacts faster than to C than C to B
    ## leading to "catalyst poisoning", i.e. C taking up most of the
    ## available catalyst sites
    kp_AC=100.0
    km_AC=1.0

    kp_BC=0.1
    km_BC=1.0

    S=0.01

    R_AC(u_A, u_C)=kp_AC*u_A*(1-u_C) - km_AC*u_C
    R_BC(u_B, u_C)=kp_BC*u_B*(1-u_C) - km_BC*u_C

    function breaction!(f,u,node)
        if  node.region==1
            f[iA]=S*R_AC(u[iA], u[iC])
            f[iB]=S*R_BC(u[iB], u[iC])
            f[iC]=-R_BC(u[iB], u[iC])-R_AC(u[iA], u[iC])
        end
    end

    ## This is for the term \partial_t u_C at the boundary
    function bstorage!(f,u,node)
        if  node.region==1
            f[iC]=u[iC]
        end
    end

    physics=VoronoiFVM.Physics(
        num_species=3,
        breaction=breaction!,
        bstorage=bstorage!,
        flux=flux!,
        storage=storage!,
        source=source!
    )

    sys=VoronoiFVM.System(grid,physics,unknown_storage=unknown_storage)

    ## Enable species in bulk resp
    enable_species!(sys,iA,[1])
    enable_species!(sys,iB,[1])

    ## Enable surface species
    enable_boundary_species!(sys,iC,[1])

    ## Set Dirichlet bc for species B on \Gamma_2
    boundary_dirichlet!(sys,iB,2,0.0)

    ## Initial values
    inival=unknowns(sys)
    inival.=0.0
    U=unknowns(sys)

    tstep=0.01
    time=0.0

    ## Data to store surface concentration vs time

    p=GridVisualizer(Plotter=Plotter,layout=(3,1))

    control=fixed_timesteps!(VoronoiFVM.NewtonControl(),tstep)
    tsol=solve(inival,sys,[0,tend],control=control)

    p=GridVisualizer(Plotter=Plotter,layout=(3,1),fast=true)
    for it=1:length(tsol)
        time=tsol.t[it]
        scalarplot!(p[1,1],grid,tsol[iA,:,it],clear=true,title=@sprintf("[A]: (%.3f,%.3f)",extrema(tsol[iA,:,it])...))
        scalarplot!(p[2,1],grid,tsol[iB,:,it],clear=true,title=@sprintf("[B]: (%.3f,%.3f)",extrema(tsol[iB,:,it])...))
        scalarplot!(p[3,1],tsol.t[1:it],tsol[iC,1,1:it],title=@sprintf("[C]"),clear=true,show=true)
    end

    return tsol[iC,1,end]
end

function test()
    testval=0.87544440641274
    isapprox(main(unknown_storage=:sparse),testval,rtol=1.0e-12)&&
    isapprox(main(unknown_storage=:dense),testval,rtol=1.0e-12)
end
end


text:
@inline function ExaTronKernels.dcopy(n::Int,dx,incx::Int,
                       dy,incy::Int,
                       tx)
    # Ignore incx and incy for now.
    if tx <= n
        @inbounds dy[tx] = dx[tx]
    end
    @synchronize

    return
end


text:
@enum(FtpTransferMode,
FtpBinary,
FtpAscii,
FtpEbcdic)

@enum(FtpStatus,
    # 1xx: the requested action is being initiated,
    # expect another reply before proceeding with a new command
    FtpRestartMarkerReply          = 110, # Restart marker reply
    FtpServiceReadySoon            = 120, # Service ready in N minutes
    FtpDataConnectionAlreadyOpened = 125, # Data connection already opened, transfer starting
    FtpOpeningDataConnection       = 150, # File status ok, about to open data connection

    # 2xx: the requested action has been successfully completed
    FtpOk                    = 200, # Command ok
    FtpPointlessCommand      = 202, # Command not implemented
    FtpSystemStatus          = 211, # System status, or system help reply
    FtpDirectoryStatus       = 212, # Directory status
    FtpFileStatus            = 213, # File status
    FtpHelpMessage           = 214, # Help message
    FtpSystemType            = 215, # NAME system type, where NAME is an official system name from the list in the Assigned Numbers document
    FtpServiceReady          = 220, # Service ready for new user
    FtpClosingConnection     = 221, # Service closing control connection
    FtpDataConnectionOpened  = 225, # Data connection open, no transfer in progress
    FtpClosingDataConnection = 226, # Closing data connection, requested file action successful
    FtpEnteringPassiveMode   = 227, # Entering passive mode
    FtpLoggedIn              = 230, # User logged in, proceed. Logged out if appropriate
    FtpFileActionOk          = 250, # Requested file action ok
    FtpDirectoryOk           = 257, # PATHNAME created

    # 3xx: the command has been accepted, but the requested action
    # is dormant, pending receipt of further information
    FtpNeedPassword       = 331, # User name ok, need password
    FtpNeedAccountToLogIn = 332, # Need account for login
    FtpNeedInformation    = 350, # Requested file action pending further information

    # 4xx: the command was not accepted and the requested action did not take place,
    # but the error condition is temporary and the action may be requested again
    FtpServiceUnavailable        = 421, # Service not available, closing control connection
    FtpDataConnectionUnavailable = 425, # Can't open data connection
    FtpTransferAborted           = 426, # Connection closed, transfer aborted
    FtpFileActionAborted         = 450, # Requested file action not taken
    FtpLocalError                = 451, # Requested action aborted, local error in processing
    FtpInsufficientStorageSpace  = 452, # Requested action not taken; insufficient storage space in system, file unavailable

    # 5xx: the command was not accepted and
    # the requested action did not take place
    FtpCommandUnknown          = 500, # Syntax error, command unrecognized
    FtpParametersUnknown       = 501, # Syntax error in parameters or arguments
    FtpCommandNotImplemented   = 502, # Command not implemented
    FtpBadCommandSequence      = 503, # Bad sequence of commands
    FtpParameterNotImplemented = 504, # Command not implemented for that parameter
    FtpNotLoggedIn             = 530, # Not logged in
    FtpNeedAccountToStore      = 532, # Need account for storing files
    FtpFileUnavailable         = 550, # Requested action not taken, file unavailable
    FtpPageTypeUnknown         = 551, # Requested action aborted, page type unknown
    FtpNotEnoughMemory         = 552, # Requested file action aborted, exceeded storage allocation
    FtpFilenameNotAllowed      = 553, # Requested action not taken, file name not allowed

    # 10xx: SFML custom codes
    FtpInvalidResponse  = 1000, # Response is not a valid FTP one
    FtpConnectionFailed = 1001, # Connection with server failed
    FtpConnectionClosed = 1002, # Connection with server closed
    FtpInvalidFile      = 1003  # Invalid file to upload / download
)

type FtpListingResponse
    ptr::Ptr{Void}

    function FtpListingResponse(ptr::Ptr{Void})
        self = new(ptr)
        finalizer(self, destroy)
        self
    end
end

function destroy(response::FtpListingResponse)
    ccall((:sfFtpListingResponse_destroy, libcsfml_network), Void, (Ptr{Void},), response.ptr)
end

function isok(response::FtpListingResponse)
    ccall((:sfFtpListingResponse_isOk, libcsfml_network), Bool, (Ptr{Void},), response.ptr)
end

function get_status(response::FtpListingResponse)
    FtpStatus(ccall((:sfFtpListingResponse_getStatus, libcsfml_network), Int32, (Ptr{Void},), response.ptr))
end

function get_message(response::FtpListingResponse)
    bytestring(ccall((:sfFtpListingResponse_getMessage, libcsfml_network), Ptr{Cchar}, (Ptr{Void},), response.ptr))
end

function get_count(response::FtpListingResponse)
    ccall((:sfFtpListingResponse_getCount, libcsfml_network), Csize_t, (Ptr{Void},), response.ptr)
end

function get_name(response::FtpListingResponse, index::Integer)
    bytestring(ccall((:sfFtpListingResponse_getName, libcsfml_network), Ptr{Cchar}, (Ptr{Void}, Csize_t,), response.ptr, index))
end

type FtpDirectoryResponse
    ptr::Ptr{Void}

    function FtpDirectoryResponse(ptr::Ptr{Void})
        self = new(ptr)
        finalizer(self, destroy)
        self
    end
end

function destroy(response::FtpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_destroy, libcsfml_network), Void, (Ptr{Void},), response.ptr)
end

function isok(response::FtpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_isOk, libcsfml_network), Bool, (Ptr{Void},), response.ptr)
end

function get_status(response::FtpDirectoryResponse)
    FtpStatus(ccall((:sfFtpDirectoryResponse_getStatus, libcsfml_network), Int32, (Ptr{Void},), response.ptr))
end

function get_message(response::FtpDirectoryResponse)
    bytestring(ccall((:sfFtpDirectoryResponse_getMessage, libcsfml_network), Ptr{Cchar}, (Ptr{Void},), response.ptr))
end

function get_directory(response::FtpDirectoryResponse)
    bytestring(ccall((:sfFtpDirectoryResponse_getDirectory, libcsfml_network), Ptr{Cchar}, (Ptr{Void},), response.ptr))
end

type FtpResponse
    ptr::Ptr{Void}

    function FtpResponse(ptr::Ptr{Void})
        self = new(ptr)
        finalizer(self, destroy)
        self
    end
end

function destroy(response::FtpResponse)
    ccall((:sfFtpResponse_destroy, libcsfml_network), Void, (Ptr{Void},), response.ptr)
end

function isok(response::FtpResponse)
    ccall((:sfFtpResponse_isOk, libcsfml_network), Bool, (Ptr{Void},), response.ptr)
end

function get_status(response::FtpResponse)
    FtpStatus(ccall((:sfFtpResponse_getStatus, libcsfml_network), Int32, (Ptr{Void},), response.ptr))
end

function get_message(response::FtpResponse)
    bytestring(ccall((:sfFtpResponse_getMessage, libcsfml_network), Ptr{Cchar}, (Ptr{Void},), response.ptr))
end

type Ftp
    ptr::Ptr{Void}

    function Ftp(ptr::Ptr{Void})
        self = new(ptr)
        finalizer(self, destroy)
        self
    end
end

function Ftp()
    Ftp(ccall((:sfFtp_create, libcsfml_network), Ptr{Void}, ()))
end

function destroy(ftp::Ftp)
    ccall((:sfFtp_destroy, libcsfml_network), Void, (Ptr{Void},), ftp.ptr)
end

function connect(ftp::Ftp, server::IpAddress, port::Integer=21, timeout::Time=Time(0))
    FtpResponse(ccall((:sfFtp_connect, libcsfml_network), Ptr{Void}, (Ptr{Void}, IpAddress, UInt16, Time), ftp.ptr, server, port, timeout))
end

function login_anonymous(ftp::Ftp)
    FtpResponse(ccall((:sfFtp_loginAnonymous, libcsfml_network), Ptr{Void}, (Ptr{Void},), ftp.ptr))
end

function login(ftp::Ftp, username::AbstractString, password::AbstractString)
    FtpResponse(ccall((:sfFtp_login, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar}, Ptr{Cchar}), ftp.ptr, username, password))
end

function disconnect(ftp::Ftp)
    FtpResponse(ccall((:sfFtp_disconnect, libcsfml_network), Ptr{Void}, (Ptr{Void},), ftp.ptr))
end

function keep_alive(ftp::Ftp)
    FtpResponse(ccall((:sfFtp_keepAlive, libcsfml_network), Ptr{Void}, (Ptr{Void},), ftp.ptr))
end

function get_working_directory(ftp::Ftp)
    FtpDirectoryResponse(ccall((:sfFtp_getWorkingDirectory, libcsfml_network), Ptr{Void}, (Ptr{Void},), ftp.ptr))
end

function get_directory_listing(ftp::Ftp, directory::AbstractString)
    FtpListingResponse(ccall((:sfFtp_getDirectoryListing, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar}), ftp.ptr, directory))
end

function change_directory(ftp::Ftp, dir::AbstractString)
    FtpResponse(ccall((:sfFtp_changeDirectory, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar},), ftp.ptr, dir))
end

# Go to the parent directory
function parent_directory(ftp::Ftp)
    FtpResponse(ccall((:sfFtp_parentDirectory, libcsfml_network), Ptr{Void}, (Ptr{Void},), ftp.ptr))
end

function create_directory(ftp::Ftp, name::AbstractString)
    FtpResponse(ccall((:sfFtp_createDirectory, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar},), ftp.ptr, name))
end

function delete_directory(ftp::Ftp, name::AbstractString)
    FtpResponse(ccall((:sfFtp_deleteDirectory, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar},), ftp.ptr, name))
end

function rename_file(ftp::Ftp, file::AbstractString, newname::AbstractString)
    FtpResponse(ccall((:sfFtp_renameFile, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar}, Ptr{Cchar}), ftp.ptr, file, newname))
end

function delete_file(ftp::Ftp, name::AbstractString)
    FtpResponse(ccall((:sfFtp_deleteFile, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar},), ftp.ptr, name))
end

function download(ftp::Ftp, distantfile::AbstractString, destpath::AbstractString, mode::FtpTransferMode)
    FtpResponse(ccall((:sfFtp_download, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar}, Ptr{Cchar}, Int32), ftp.ptr, distantfile, destpath, Int32(mode)))
end

function upload(ftp::Ftp, localfile::AbstractString, destpath::AbstractString, mode::FtpTransferMode)
    FtpResponse(ccall((:sfFtp_upload, libcsfml_network), Ptr{Void}, (Ptr{Void}, Ptr{Cchar}, Ptr{Cchar}, Int32), ftp.ptr, localfile, destpath, Int32(mode)))
end


text:
function try_parse(s)
    if all(isnumeric, s)
        parse(Int, s)
    else
        s
    end
end

struct BinaryOp
    op
    in_1
    in_2
    out

    BinaryOp(op, in_1::AbstractString, in_2::AbstractString, out) = new(op, try_parse(in_1), try_parse(in_2), out)
end

struct UnaryOp
    op
    in_
    out

    UnaryOp(op, in_::AbstractString, out) = new(op, try_parse(in_), out)
end

function parse_line(l)
    m_simple = match(r"^(?<op>NOT)? ?(?<in_>\S+) -> (?<out>\w+)$", l)
    m_double = match(r"^(?<in_1>\S+) (?<op>AND|OR|RSHIFT|LSHIFT) (?<in_2>\S+) -> (?<out>\w+)$", l)

    if !isnothing(m_simple)
        UnaryOp(m_simple[:op], m_simple[:in_], m_simple[:out])
    elseif !isnothing(m_double)
        BinaryOp(m_double[:op],m_double[:in_1], m_double[:in_2], m_double[:out])
    else
        @error "Did not parse $l"
    end
end

data = readlines() .|> parse_line

function apply(assgn::UnaryOp, mem)
    in_ = assgn.in_
    if in_ isa AbstractString
        in_ = mem[in_]
    end
    if !isnothing(assgn.op)
        ~in_
    else
        in_
    end
end

function apply(assgn::BinaryOp, mem)
    in_1 = assgn.in_1
    if in_1 isa AbstractString
        in_1 = mem[in_1]
    end
    in_2 = assgn.in_2
    if in_2 isa AbstractString
        in_2 = mem[in_2]
    end

    if assgn.op == "AND"
        in_1 & in_2
    elseif assgn.op == "OR"
        in_1 | in_2
    elseif assgn.op == "RSHIFT"
        in_1 >> in_2
    elseif assgn.op == "LSHIFT"
        in_1 << in_2
    else
        @error "No operation in $assgn"
    end
end

function compute(assgn::UnaryOp, circuit, mem)
    out_key = assgn.out
    if haskey(mem, out_key)
        return mem[out_key]
    end

    in_ = assgn.in_
    if in_ isa AbstractString && !haskey(mem, in_)
        compute(circuit[in_], circuit, mem)
    end
    out = apply(assgn, mem)
    mem[out_key] = out
    return out
end

function compute(assgn::BinaryOp, circuit, mem)
    out_key = assgn.out
    if haskey(mem, out_key)
        return mem[out_key]
    end

    in_1 = assgn.in_1
    if in_1 isa AbstractString && !haskey(mem, in_1)
        compute(circuit[in_1], circuit, mem)
    end

    in_2 = assgn.in_2
    if in_2 isa AbstractString && !haskey(mem, in_2)
        compute(circuit[in_2], circuit, mem)
    end

    out = apply(assgn, mem)
    mem[out_key] = out
    return out
end

function solve_1()
    g_struct = Dict{String, Union{UnaryOp, BinaryOp}}()
    g_val = Dict{String, Int}()
    for line in data
        g_struct[line.out] = line
    end

    compute(g_struct["a"], g_struct, g_val)

end

solve_1() |> println

max_stars_repo_name: pLOPeGG/JuliaOfCode

max_issues_repo_name: pLOPeGG/JuliaOfCode

max_forks_repo_name: pLOPeGG/JuliaOfCode


text:
# Copyright (c) 2020 California Institute of Technology (“Caltech”). U.S.
# Government sponsorship acknowledged.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#   • Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#   • Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
#   • Neither the name of Caltech nor its operating division, the Jet
#   Propulsion Laboratory, nor the names of its contributors may be used to
#   endorse or promote products derived from this software without specific
#   prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Purpose: This module deals with the way objects are stored in memory, as well
# as the aspects of binning into bandpowers. This is accessed by exporting
# three structures: AnlmModes, ClnnModes, and ClnnBinnedModes.

# TODO:
#
# - When binning, we should only consider Δℓ and Δn, where the resulting bin
# contains the modes within a volume Δℓ⋅Δn². That is, we need to consider what
# the actual binning strategy in the n-n′ direction shall be. Probably, we want
# to do something simple such as hafl the modes in n-n′=1 go to the diagonal,
# the other half to the first off-diagonal in binned space. However, this is
# lower priority, because we have rₘᵢₙ boundary conditions.

module Modes

using ..GNL
using Statistics
using LinearAlgebra
using SparseArrays

export AnlmModes, ClnnModes, ClnnBinnedModes
export estimate_nside, estimate_nr
export getnlmsize, getlmsize, getnlm, getidx
export getlnnsize, getlnn, isvalidlnn
export getlkk, getidxapprox
export bandpower_binning_weights, bandpower_eigen_weights
export get_incomplete_bins, find_most_hi_k_convolved_mode, find_klarge, get_hi_k_affection

import Base.length, Base.iterate

########################## AnlmModes: define ordering of modes in data vector ########

## Note: The maximum is lmax=3*nside-1, which is OK for bandpower limited
## functions. In general, it may be better to use lmax=2*nside. Furthermore,
## our algorithms frequently need to reference quantities up to L=2*lmax.
#estimate_nside(lmax) = 2^max(2, ceil(Int, log2((lmax + 1) / 3)))
estimate_nside(lmax) = 2^max(2, ceil(Int, log2((2*lmax + 1) / 2)))
#estimate_nside(lmax) = 4 * 2^max(2, ceil(Int, log2((lmax + 1) / 3)))
#estimate_nside(lmax) = 32 * 2^max(2, ceil(Int, log2((lmax + 1) / 3)))

@doc raw"""
    AnlmModes

This is where we define which modes are included. As our criterium, we set a
maximum qmax = kmax * rmax, and we include all modes below that.

The modes are arranged in the following order. The fastest loop is through 'm',
then 'l', finally 'n', from small number to larger number. We restrict 'm' to
m > 0, and we assume a real field.

Example:
```julia-repl
julia> kmax = 0.2
julia> rmax = 1000.0
julia> modes = AnlmModes(kmax * rmax)
```

"""
struct AnlmModes{T}
    rmin::Float64
    rmax::Float64
    kmax::Float64
    basisfunctions::T

    # calculated, public:
    nmax::Int64
    lmax::Int64
    nmax_l::Array{Int64,1}
    lmax_n::Array{Int64,1}
    nside::Int64
    knl::Array{Float64,2}
end

# for the @__dot syntax:
length(s::AnlmModes) = 1
iterate(s::AnlmModes) = s, nothing
iterate(s::AnlmModes, x) = nothing

function AnlmModes(kmax::Real, rmin::Real, rmax::Real; cache=true, nside=nothing)
    sphbesg = SphericalBesselGnl(kmax, rmin, rmax, cache=cache)
    knl = sphbesg.knl
    nmax, lmax = size(knl) .- (0,1)
    modes = @. knl <= kmax
    mylmax(n) = begin
        last = findlast(modes[n,:]) - 1
        isa(last, Integer) || return -1
        return last
    end
    mynmax(l) = begin
        last = findlast(modes[:,l+1])
        isa(last, Integer) || return -1
        return last
    end
    nmax = findlast(modes[:,1])
    lmax_n = [mylmax(n) for n=1:nmax]
    lmax = findlast(modes[1,:]) - 1
    nmax_l = [mynmax(l) for l=0:lmax]
    if !all(nmax_l .> 0)
        lbad = findfirst(nmax_l .<= 0) - 1
        @error "nmax_l out of range" kmax rmin rmax cache lbad nmax_l[lbad+1] knl[:,lbad+1]
    end
    @assert all(lmax_n .>= 0)
    #@show nmax lmax lmax_n nmax_l
    if nside == nothing
        nside = estimate_nside(lmax)
    end
    kmax = maximum(x->isnan(x) ? -Inf : x, knl)
    return AnlmModes(rmin, rmax, kmax, sphbesg, nmax, lmax, nmax_l, lmax_n, nside, knl)
end

function AnlmModes(nmax::Int, lmax::Int, rmin::Real, rmax::Real; cache=true, nside=nothing)
    lmax_n = [lmax for n=1:nmax]
    nmax_l = [nmax for l=0:lmax]
    sphbesg = SphericalBesselGnl(nmax, lmax, rmin, rmax, cache=cache)
    if nside == nothing
        nside = estimate_nside(lmax)
    end
    knl = sphbesg.knl
    kmax = maximum(x->isnan(x) ? -Inf : x, knl)
    return AnlmModes(rmin, rmax, kmax, sphbesg, nmax, lmax, nmax_l, lmax_n, nside, knl)
end

function getlmsize(lmax)
    return lmax * (lmax + 1) ÷ 2 + lmax + 1
end

function getnlmsize(modes::AnlmModes, nmax=modes.nmax)
    s = 0
    for n=1:nmax
        s += getlmsize(modes.lmax_n[n])
    end
    return s
end

function getnlm(modes::AnlmModes, idx)
    n = 1
    nmodes = getlmsize(modes.lmax_n[n])
    while idx > nmodes
        idx -= nmodes
        n += 1
        nmodes = getlmsize(modes.lmax_n[n])
    end
    l = 0
    nmodes = l + 1
    while idx > nmodes
        idx -= nmodes
        l += 1
        nmodes = l + 1
    end
    m = idx - 1
    return n, l, m
end

function getidx(modes::AnlmModes, n, l, m)
    @assert n >= 1
    @assert l >= 0
    @assert m >= 0
    idx = 1
    idx += getnlmsize(modes, n-1)
    idx += getlmsize(l-1)
    idx += m
    return idx
end

########################## ClnnModes: define ordering of modes in data vector ########

@doc raw"""
    ClnnModes(::AnlmModes)

This is where we define which modes are included in the power spectrum, given a
`AnlmModes` struct.

The modes are arranged in the following order. The fastest loop is through 'n̄',
then 'Δn', finally 'ℓ', from small number to larger number.
"""
struct ClnnModes
    amodes::AnlmModes
    knl::Array{Float64,2}
    Δnmax::Int64
    Δnmax_l::Array{Int64,1}
    Δnmax_n::Array{Int64,1}
    symmetric::Bool
end

# for the @__dot syntax:
length(s::ClnnModes) = 1
iterate(s::ClnnModes) = s, nothing
iterate(s::ClnnModes, x) = nothing

function ClnnModes(amodes::AnlmModes; Δnmax=typemax(Int64), symmetric=true)
    @assert symmetric  # cross-correlations are not yet implemented
    Δnmax = min(Δnmax, amodes.nmax-1)
    knl = amodes.knl
    Δnmax_l = fill(0, amodes.lmax+1)
    Δnmax_n = fill(0, amodes.nmax)
    for l=0:amodes.lmax
        Δnmax_l[l+1] = min(Δnmax, amodes.nmax_l[l+1]-1)
        for Δn=0:Δnmax_l[l+1]
            for n=1:amodes.nmax_l[l+1]-Δn
                Δnmax_n[n] = max(Δnmax_n[n], Δn)
            end
        end
    end
    return ClnnModes(amodes, knl, Δnmax, Δnmax_l, Δnmax_n, symmetric)
end

function getnsize(modes::ClnnModes, l, Δn, n̄max=modes.amodes.nmax_l[l+1]-Δn)
    symfac = (modes.symmetric || Δn==0) ? 1 : 2
    return symfac * n̄max
end

function getnΔnsize(modes::ClnnModes, l, Δnmax=modes.Δnmax_l[l+1])
    n̄center = modes.amodes.nmax_l[l+1]
    n̄offdiag = n̄center * (n̄center - 1) ÷ 2 - (n̄center - Δnmax) * (n̄center - Δnmax - 1) ÷ 2
    symfac = (modes.symmetric) ? 1 : 2
    s2 = n̄center + symfac * n̄offdiag
    if Δnmax < 0
        s2 = 0
    end
    return s2
end

function getlnnsize(modes::ClnnModes, lmax=modes.amodes.lmax)
    s = 0
    for l=0:lmax
        s += getnΔnsize(modes, l)
    end
    return s
end

function getlnn(cmodes::ClnnModes, idx)
    l = 0
    nmodes = getnΔnsize(cmodes, l)
    while idx > nmodes
        idx -= nmodes
        l += 1
        nmodes = getnΔnsize(cmodes, l)
    end
    Δn = 0
    nmodes = getnsize(cmodes, l, Δn)
    while idx > nmodes
        idx -= nmodes
        Δn += 1
        nmodes = getnsize(cmodes, l, Δn)
    end
    n̄ = idx
    n1 = n̄
    n2 = n1 + Δn
    return l, n1, n2
end

function isvalidlnn(cmodes::ClnnModes, l, n1, n2)
    @assert cmodes.symmetric
    Δn = abs(n1 - n2)
    n̄ = min(n1, n2)
    return (0 <= l <= cmodes.amodes.lmax &&
            0 <= Δn <= cmodes.Δnmax_l[l+1] &&
            1 <= n̄ <= cmodes.amodes.nmax - Δn)
end

function check_isvalidclnn(cmodes::ClnnModes, l, n1, n2)
    if !isvalidlnn(cmodes, l, n1, n2)
        lmax = cmodes.amodes.lmax
        nmax = cmodes.amodes.nmax
        nmax_l = cmodes.amodes.nmax_l
        nmax_li = nmax_l[max(1,min(l+1,length(nmax_l)))]
        Δnmax = cmodes.Δnmax
        Δnmax_l = cmodes.Δnmax_l
        Δnmax_li = Δnmax_l[max(1,min(l+1,length(Δnmax_l)))]
        Δnmax_n = cmodes.Δnmax_n
        Δnmax_n1i = Δnmax_n[max(1,min(n1,length(Δnmax_n)))]
        Δnmax_n2i = Δnmax_n[max(1,min(n2,length(Δnmax_n)))]
        @error "lnn not valid" l,n1,n2 lmax nmax,nmax_li Δnmax,Δnmax_li,Δnmax_n1i,Δnmax_n2i
        error("lnn not valid")
    end
end

function getidx(cmodes::ClnnModes, l, n1, n2)
    check_isvalidclnn(cmodes, l, n1, n2)
    Δn = abs(n1 - n2)
    n̄ = min(n1, n2)
    idx = 0
    idx += getlnnsize(cmodes, l-1)
    idx += getnΔnsize(cmodes, l, Δn-1)
    idx += n̄
    return idx
end

@doc raw"""
    getlkk(::ClnnModes, [i])
    getlkk(::ClnnBinnedModes, [i])

Get the physical modes ℓ, k, and k' corresponding to the index `i`. If `i` is
left out, an array `lkk` of all modes is returned so that `lkk[1,:]` are all
the ℓ-values, `lkk[2,:]` all the k-values, and `lkk[3,:]` are all the
k'-values.
"""
function getlkk(cmodes::ClnnModes, i)
    l, n1, n2 = getlnn(cmodes, i)
    k1 = cmodes.knl[n1,l+1]
    k2 = cmodes.knl[n2,l+1]
    return l, k1, k2
end

function getlkk(cmodes::ClnnModes)
    l, k1, k2 = getlkk(cmodes, 1)
    lkk = fill(eltype(promote(l, k1, k2))(0), 3, getlnnsize(cmodes))
    for i=1:size(lkk,2)
        l, k1, k2 = getlkk(cmodes, i)
        lkk[1,i] = l
        lkk[2,i] = k1
        lkk[3,i] = k2
    end
    return lkk
end

function estimate_nr(cmodes::ClnnModes)
    # Note this is a pretty shitty algorithm. Speeding it up should be fairly easy.
    lnnsize = getlnnsize(cmodes)
    Nsampmax = 1
    for i=1:lnnsize, i′=1:lnnsize
        l, n, n′ = getlnn(cmodes, i)
        L, N, N′ = getlnn(cmodes, i′)
        Nsamp1 = 8 * (n + N) + l + L
        Nsamp2 = 8 * (n′ + N′) + l + L
        Nsampmax = max(Nsampmax, Nsamp1, Nsamp2)
    end
    return Nsampmax
end

############################### ClnnBinnedModes ###########################
# The ClnnBinnedModes struct is basically the same as the ClnnModes struct.
# However, it adds to it functionality that allows the modes to be different
# from the indices. That is, if the actual mode is ℓ and its index l, then we
# don't require ℓ=l.

struct ClnnBinnedModes{T}
    cmodes::ClnnModes
    LKK::Array{T,2}  # l=LKK[1,:], k1=LKK[2,:], k2=LKK[3,:]
end

# for the @__dot syntax:
length(s::ClnnBinnedModes) = 1
iterate(s::ClnnBinnedModes) = s, nothing
iterate(s::ClnnBinnedModes, x) = nothing

function ClnnBinnedModes(w̃, v, cmodes::ClnnModes)
    (w̃ != I) && @assert all(sum(w̃, dims=2) .≈ 1)  # ensure w̃ is normalized
    LKK = getlkk(cmodes) * w̃'
    if cmodes.symmetric
        # ensure k1 <= k2
        for i=1:size(LKK,2)
            LKK[2:3,i] .= extrema(LKK[2:3,i])
        end
    end
    return ClnnBinnedModes(cmodes, LKK)
end

getlnnsize(bcmodes::ClnnBinnedModes) = size(bcmodes.LKK,2)

getlkk(bcmodes::ClnnBinnedModes, i) = begin
    #@show i,bcmodes.LKK[2,i]
    bcmodes.LKK[1,i], bcmodes.LKK[2,i], bcmodes.LKK[3,i]
end

getlkk(bcmodes::ClnnBinnedModes) = bcmodes.LKK

# _getcblnn_helper(): get surrounding interval range
_getcblnn_helper(arr, i) = begin
    lo = arr[max(1, i - 1)]
    mi = arr[i]
    hi = arr[min(i + 1, length(arr))]
    if mi < lo && mi < hi
        hi = min(lo, hi)
        lo = mi - (hi - mi) / 2
    elseif mi > lo && mi > hi
        lo = max(lo, hi)
        hi = mi + (mi - lo) / 2
    end
    @assert lo <= mi <= hi
    lo = (lo + mi) / 2
    hi = (hi + mi) / 2
    return lo, hi
end

getidxapprox(bcmodes::ClnnBinnedModes, ℓ, k1in, k2in) = begin
    @assert bcmodes.cmodes.symmetric
    k1 = min(k1in, k2in)
    k2 = max(k1in, k2in)
    i = findfirst(i -> begin
                      ℓ_lo, ℓ_hi = _getcblnn_helper(bcmodes.LKK[1,:], i)
                      (ℓ_lo <= ℓ <= ℓ_hi) || return false
                      #@show i,ℓ_lo,ℓ_hi

                      k1_lo, k1_hi = _getcblnn_helper(bcmodes.LKK[2,:], i)
                      #@show i,k1_lo,k1_hi
                      (k1_lo <= k1 <= k1_hi) || return false

                      k2_lo, k2_hi = _getcblnn_helper(bcmodes.LKK[3,:], i)
                      (k2_lo <= k2 <= k2_hi) || return false
                      #@show i,k2_lo,k2_hi
                      return true
                  end,
                  1:getlnnsize(bcmodes))
    return i
end

# Same as getidxapprox(), except that the agreement needs to be ~machine precision.
getidx(bcmodes::ClnnBinnedModes, ℓ, k1in, k2in) = begin
    @assert bcmodes.cmodes.symmetric
    return getidx(bcmodes.LKK, ℓ, k1in, k2in)
end
getidx(LKK::AbstractArray{T,2}, ℓ, k1in, k2in) where {T<:Real} = begin
    lnnsize = size(LKK,2)
    k1 = min(k1in, k2in)
    k2 = max(k1in, k2in)
    i = findfirst(i -> begin
                      L = LKK[1,i]
                      (L ≈ ℓ) || return false
                      k1 = LKK[2,i]
                      (k1 ≈ k1in) || return false
                      k2 = LKK[3,i]
                      (k2 ≈ k2in) || return false
                      return true
                  end,
                  1:lnnsize)
    return i
end

########## calculate binning and debinning matrices

function bandpower_binning_weights(cmodes::ClnnModes; Δℓ=1, Δn=1)
    # Note: Should really change this to bin in only Δℓ and Δn. Binning in ΔΔn
    # and Δn̄ is untested.
    ΔΔn, Δn̄ = Δn, Δn
    @show Δℓ, ΔΔn, Δn̄
    lmax = cmodes.amodes.lmax
    Δnmax_l = cmodes.Δnmax_l
    n̄max_l = cmodes.amodes.nmax_l
    nmax = cmodes.amodes.nmax

    LNNsizemax = 0
    for l=0:Δℓ:lmax
        lrange = l:min(l+Δℓ-1,lmax)
        for Δn=0:ΔΔn:maximum(Δnmax_l[lrange.+1]), n̄=1:Δn̄:maximum(n̄max_l[lrange.+1])
            LNNsizemax += 1
        end
    end
    lnnsize = getlnnsize(cmodes)
    @show LNNsizemax lnnsize

    w̃ = fill(0.0, LNNsizemax, lnnsize)
    i = 1
    for llo=0:Δℓ:lmax
        lrange = llo:min(llo+Δℓ-1,lmax)
        @show lrange
        for Δnlo=0:ΔΔn:maximum(Δnmax_l[lrange.+1]), n̄lo=1:Δn̄:maximum(n̄max_l[lrange.+1])
            Δnrange = [Δnlo:min(Δnlo+ΔΔn-1,Δnmax_l[l+1]) for l in lrange]
            n̄range = [n̄lo:min(n̄lo+Δn̄-1,n̄max_l[l+1]) for l in lrange]
            #@show Δnrange n̄range
            num = 0
            for il=1:length(lrange), Δn in Δnrange[il], n̄ in n̄range[il]
                #@error "Mode ignored" i lrange Δnrange n̄range
                l = lrange[il]
                n1 = n̄
                n2 = n̄ + Δn
                isvalidlnn(cmodes, l, n1, n2) || continue
                j = getidx(cmodes, l, n1, n2)
                #@show i,j, l,Δn,n̄
                w̃[i,j] += 1
                num += 1
            end
            if num != 0
                i += 1
            end
        end
    end
    LNNsize = i - 1
    w̃ = w̃[1:LNNsize,:]
    @show LNNsize

    w̃ = w̃ ./ sum(w̃, dims=2)  # normalize

    v = pinv(w̃)

    @assert all(sum(w̃, dims=2) .≈ 1)

    w̃, v = sparse(w̃), sparse(v)
    return w̃, v
end

function bandpower_eigen_weights(cmix; ϱ=1.5)
    @show cmix
    @show issymmetric(cmix)
    # we assume only positive eigenvalues are allowed
    f = eigen(cmix)
    λ = f.values
    @show λ
    @show f.vectors
    n = findlast(@. λ[end] / λ > ϱ)
    n = isnothing(n) ? 1 : n+1
    R = f.vectors[:,n:end]'
    @show λ[n:end]
    @show isposdef(cmix) det(cmix)
    @show isposdef(f.vectors) det(f.vectors)
    @show size(R)
    for i=1:size(f.vectors,2), j=1:size(f.vectors,2)
        @show i,j,dot(f.vectors[:,i], f.vectors[:,j])
    end
    Rinv = inv(f.vectors)[n:end,:]'
    @show R R' Rinv
    @show R*R' R'*R
    @show R*Rinv Rinv*R
    D = inv(diagm(sum(R, dims=2)[:]))
    @show diag(D)
    @show maximum(diag(D)) / minimum(diag(D))
    @show maximum(abs.(diag(D))) / minimum(abs.(diag(D)))
    w = D * R
    Θ = Rinv * inv(D)
    @show w Θ
    @show sum(w, dims=2)
    @show logabsdet(Θ*w)
    @show w*Θ (w*Θ)^10 (w*Θ)^100 (w*Θ)^1000
    @show Θ*w (Θ*w)^10 (Θ*w)^100 (Θ*w)^1000
    @show sum(Θ*w, dims=1)
    @show sum(Θ*w, dims=2)
    @assert R * Rinv ≈ I
    return w, Θ
end

function get_incomplete_bins(w̃; nmodes_per_bin=nothing)
    if isnothing(nmodes_per_bin)
        # Guess normal number of modes per bin
        nbins = Int[]  # histogram of number of modes per bin
        for i=1:size(w̃, 1)
            nmodes = sum(@. w̃[i,:] != 0)
            if nmodes > length(nbins)
                append!(nbins, fill(0, nmodes - length(nbins)))
            end
            nbins[nmodes] += 1
        end
        nmodes_per_bin = length(nbins)
        @show nbins
    end
    @show nmodes_per_bin

    incomplete_bins = Int[]
    for i=1:size(w̃, 1)
        nmodes = sum(@. w̃[i,:] != 0)
        if nmodes != nmodes_per_bin
            push!(incomplete_bins, i)
        end
    end
    return incomplete_bins
end

# find_most_hi_k_convolved_mode(): Here find the mode that is most affected by
# mode mixing from hi-k modes. This is useful to find the maximum k that is
# needed to get unbiased results from the deconvolution step. `bcmixinv` is the
# inverse of the mixing matrix, `lkk` describes the modes, `kmax` is the
# maximum mode we are interested in, and `ktrans` is the current best estimate
# for the largest needed k.
function find_most_hi_k_convolved_mode(bcmixinv, lkk, kmax, ktrans)
    s_hi = @. lkk[2,:] > ktrans
    s_lo = @. lkk[2,:] <= ktrans
    idxmax = 1
    ratiomax = 0.0
    for idx in 1:size(lkk, 2)
        (lkk[2,idx] <= kmax) || continue
        hi = sum(abs.(bcmixinv[idx,s_hi]))
        lo = sum(abs.(bcmixinv[idx,s_lo]))
        ratio = hi / (lo + hi)
        if ratio >= ratiomax
            idxmax = idx
            ratiomax = ratio
        end
    end
    return idxmax, ratiomax
end

function find_klarge(bcmixinv, lkk, kmax; threshold=0.01)
    zerofn(klarge) = begin
        idx, hifraction = find_most_hi_k_convolved_mode(bcmixinv, lkk, kmax, klarge)
        return hifraction - threshold
    end

    karr = sort(lkk[2,:])

    idx = findfirst(k -> zerofn(k) < 0, karr)

    klarge = nextfloat(karr[idx])

    return klarge
end

function get_hi_k_affection(bcmixinv, lkk, klarge)
    s_hi = @. lkk[2,:] > klarge
    s_lo = @. lkk[2,:] <= klarge
    lnnsize = length(lkk[2,:])
    hifracts = fill(NaN, lnnsize)
    for idx in 1:lnnsize
        hi = sum(abs.(bcmixinv[idx,s_hi]))
        lo = sum(abs.(bcmixinv[idx,s_lo]))
        hifracts[idx] = hi / (lo + hi)
    end
    return hifracts
end

end

# vim: set sw=4 et sts=4 :


text:
# Produce benchmarks comparing all functions with each other
using DrWatson
@quickactivate :FractalDimension # uses DynamicalSystems, PyPlot
include(srcdir("style.jl"))

file = wload(datadir("benchmarks", "benchmarks.jld2"))
@unpack Di, Ni, Ds, Ns, BN, BD, methods = file
BD = log10.(BD) # better to display timings in log scale
BN = log10.(BN) # better to display timings in log scale

fig, axs = subplots(2,1)

for (i, m) in enumerate(methods)
    axs[1].plot(log10.(Ns), BN[:, i];
    label = m, ls = LINESTYLES[i], alpha = 0.9, marker = MARKERS[i], ms = 8)
    axs[2].plot(Ds, BD[:, i], ls = LINESTYLES[i], alpha = 0.9, marker = MARKERS[i], ms = 8)
end
leg = axs[1].legend(
    bbox_to_anchor=(0., 1.02, 1., .102), loc="lower left",
    ncol=3, mode="expand", borderaxespad=0,
)

axs[1].set_xlabel("\$\\log_{10}(N)\$")
axs[1].set_ylabel("\$\\log_{10}(t \\mathrm{[sec]})\$")
axs[2].set_xlabel("\$D\$")
axs[2].set_ylabel("\$\\log_{10}(t \\mathrm{[sec]})\$")
fig.tight_layout(pad=0.3)

max_stars_repo_name: Datseris/FractalDimension

max_issues_repo_name: Datseris/FractalDimension

max_forks_repo_name: Datseris/FractalDimension


text:
addprocs(2)

using Base.Test
using Dagger

include("domain.jl")
include("array.jl")
include("cache.jl")


text:
include("../coin-or-common.jl")

# Collection of sources required to build SYMPHONY
sources = [
    GitSource("https://github.com/coin-or/SYMPHONY.git", SYMPHONY_gitsha),
]

# Bash recipe for building across all platforms
script = raw"""
export CPPFLAGS="${CPPFLAGS} -I${includedir} -I${includedir}/coin"
if [[ "${target}" == *mingw* ]]; then
    export LDFLAGS="-L${bindir}"
elif [[ "${target}" == *linux* ]]; then
    export LDFLAGS="-ldl -lrt"
fi

cd $WORKSPACE/srcdir/SYMPHONY
update_configure_scripts
sed -i s/elf64ppc/elf64lppc/ configure
mkdir build
cd build
../configure \
    --prefix=${prefix} \
    --build=${MACHTYPE} \
    --host=${target} \
    --with-pic \
    --disable-pkg-config \
    --disable-debug \
    --disable-dependency-tracking \
    --enable-shared \
    lt_cv_deplibs_check_method=pass_all \
    --with-coindepend-lib="-lOsi -lCoinUtils" \
    --with-clp-lib="-lClp -lOsiClp" \
    --with-cgl-lib="-lCgl"
make -j${nproc}
make install
"""

# The products that we will ensure are always built
products = [
    LibraryProduct("libSym", :libsym),
    LibraryProduct("libOsiSym", :libosisym),
    ExecutableProduct("symphony", :symphony),
]

# Dependencies that must be installed before this package can be built
dependencies = [
    Dependency("CoinUtils_jll", CoinUtils_version),
    Dependency("Osi_jll", Osi_version),
    Dependency("Clp_jll", Clp_version),
    Dependency("Cgl_jll", Cgl_version),
    Dependency("CompilerSupportLibraries_jll"),
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(
    ARGS,
    "SYMPHONY",
    SYMPHONY_version,
    sources,
    script,
    expand_gfortran_versions(platforms),
    products,
    dependencies;
    preferred_gcc_version=gcc_version,
)

max_stars_repo_name: plut/Yggdrasil

max_issues_repo_name: plut/Yggdrasil

max_forks_repo_name: plut/Yggdrasil


text:
# Example functions from Dietmar Ratz - An Optimized Interval Slope Arithmetic and its Application

dr1(x) = (x + sin(x)) * exp(-x^2)
dr2(x) = x^4 - 10x^3 + 35x^2 - 50x + 24
dr3(x) = (log(x + 1.25) - 0.84x) ^ 2
dr4(x) = 0.02x^2 - 0.03exp(-(20(x - 0.875))^2)
dr5(x) = exp(x^2)
dr6(x) = x^4 - 12x^3 + 47x^2 - 60x - 20exp(-x)
dr7(x) = x^6 - 15x^4 + 27x^2 + 250
dr8(x) = atan(cos(tan(x)))
dr9(x) = asin(cos(acos(sin(x))))

dr_functions = [dr1, dr2, dr3, dr4, dr5, dr6, dr7, dr8, dr9]


text:
const WORDS = Dict{Char, Char}(
    #### ㄅ ####
    # ㄅㄚ
    '罢' => '罷',
    # ㄅㄛ
    '拨' => '撥',
    '驳' => '駁',
    # ㄅㄞ
    '摆' => '擺',
    '败' => '敗',
    # ㄅㄟ
    '贝' => '貝',
    '呗' => '唄',
    '狈' => '狽',
    '备' => '備',
    '惫' => '憊',
    '辈' => '輩',
    # ㄅㄠ
    '宝' => '寶',
    '报' => '報',
    '饱' => '飽',
    # ㄅㄢ
    '办' => '辦',
    '绊' => '絆',
    # ㄅㄤ
    '帮' => '幫',
    '绑' => '綁',
    # ㄅㄥ
    '绷' => '繃',
    # ㄅㄧ
    '笔' => '筆',
    '闭' => '閉',
    '毙' => '斃',
    '毕' => '畢',
    # ㄅㄧㄠ
    '标' => '標',
    '飙' => '飆',
    # ㄅㄧㄢ
    '边' => '邊',
    '变' => '變',
    '辩' => '辯',
    '编' => '編',
    '贬' => '貶',
    # ㄅㄧㄣ
    '濒' => '瀕',
    '鬓' => '鬢',
    # ㄅㄧㄥ
    '并' => '並',
    # ㄅㄨ
    '补' => '補',
    #### ㄆ ####
    # ㄆㄛ
    '颇' => '頗',
    '泼' => '潑',
    # ㄆㄟ
    '赔' => '賠',
    # ㄆㄢ
    '盘' => '盤',
    # ㄆㄣ
    '喷' => '噴',
    # ㄆㄤ
    '庞' => '龐',
    # ㄆㄥ
    '鹏' => '鵬',
    # ㄆㄧ
    '纰' => '紕',
    # ㄆㄧㄠ
    '飘' => '飄',
    # ㄆㄧㄢ
    '骗' => '騙',
    # ㄆㄧㄥ
    '评' => '評',
    '凭' => '憑',
    '苹' => '蘋',
    # ㄆㄨ
    '仆' => '僕',
    '扑' => '撲',
    '铺' => '舖',
    '谱' => '譜',
    #### ㄇ ####
    # ㄇㄚ
    '马' => '馬',
    '吗' => '嗎',
    '妈' => '媽',
    '码' => '碼',
    '骂' => '罵',
    # ㄇㄛ
    '谋' => '謀',
    # ㄇㄜ
    '么' => '麼',
    # ㄇㄞ
    '买' => '買',
    '卖' => '賣',
    '脉' => '脈',
    '迈' => '邁',
    '麦' => '麥',
    # ㄇㄢ
    '瞒' => '瞞',
    '蛮' => '蠻',
    # ㄇㄣ
    '门' => '門',
    '们' => '們',
    '闷' => '悶',
    # ㄇㄥ
    '梦' => '夢',
    # ㄇㄧ
    '觅' => '覓',
    '弥' => '彌',
    # ㄇㄧㄝ
    '灭' => '滅',
    # ㄇㄧㄠ
    '庙' => '廟',
    # ㄇㄧㄢ
    '绵' => '綿',
    '缅' => '緬',
    # ㄇㄧㄣ
    '悯' => '憫',
    # ㄇㄧㄥ
    '鸣' => '鳴',
    #### ㄈ ####
    # ㄈㄚ
    '发' => '發',
    '罚' => '罰',
    # ㄈ乁',
    '飞' => '飛',
    '费' => '費',
    '废' => '廢',
    '绯' => '緋',
    # ㄈㄢ
    '烦' => '煩',
    '饭' => '飯',
    '贩' => '販',
    # ㄈㄣ
    '奋' => '奮',
    '粪' => '糞',
    '愤' => '憤',
    '纷' => '紛',
    # ㄈㄤ
    '访' => '訪',
    # ㄈㄥ
    '丰' => '豐',
    '凤' => '鳳',
    '风' => '風',
    '疯' => '瘋',
    '讽' => '諷',
    '缝' => '縫',
    '锋' => '鋒',
    # ㄈㄨ
    '负' => '負',
    '妇' => '婦',
    '肤' => '膚',
    '抚' => '撫',
    '复' => '復',
    '缚' => '縛',
    '辅' => '輔',
    '赋' => '賦',
    #### ㄉ ####
    # ㄉㄚ
    '达' => '達',
    # ㄉㄞ
    '带' => '帶',
    '贷' => '貸',
    # ㄉㄠ
    '捣' => '搗',
    '导' => '導',
    '盗' => '盜',
    # ㄉㄡ
    '窦' => '竇',
    # ㄉㄢ
    '单' => '單',
    '惮' => '憚',
    '掸' => '撣',
    '弹' => '彈',
    '殚' => '殫',
    '担' => '擔',
    '胆' => '膽',
    '诞' => '誕',
    # ㄉㄤ
    '当' => '當',
    '挡' => '擋',
    '档' => '檔',
    '荡' => '蕩',
    '党' => '黨',
    # ㄉㄥ
    '镫' => '鐙',
    # ㄉㄧ
    '敌' => '敵',
    '递' => '遞',
    # ㄉㄧㄝ
    '叠' => '疊',
    # ㄉㄧㄠ
    '调' => '調',
    # ㄉㄧㄢ
    '点' => '點',
    '电' => '電',
    '淀' => '澱',
    '颠' => '顛',
    '巅' => '巔',
    '垫' => '墊',
    # ㄉㄧㄥ
    '订' => '訂',
    '钉' => '釘',
    '顶' => '頂',
    '锭' => '錠',
    # ㄉㄨ
    '独' => '獨',
    '赌' => '賭',
    '渎' => '瀆',
    '读' => '讀',
    '镀' => '鍍',
    # ㄉㄨㄛ
    '夺' => '奪',
    '堕' => '墮',
    # ㄉㄨㄟ
    '对' => '對',
    '怼' => '懟',
    '队' => '隊',
    # ㄉㄨㄢ
    '缎' => '緞',
    '锻' => '鍛',
    '断' => '斷',
    # ㄉㄨㄣ
    '钝' => '鈍',
    '顿' => '頓',
    # ㄉㄨㄥ
    '动' => '動',
    '东' => '東',
    '冻' => '凍',
    #### ㄊ ####
    # ㄊㄞ
    '态' => '態',
    # ㄊㄠ
    '讨' => '討',
    # ㄊㄡ
    '头' => '頭',
    # ㄊㄢ
    '叹' => '嘆',
    '摊' => '攤',
    '瘫' => '癱',
    '贪' => '貪',
    '谈' => '談',
    '坛' => '壇',
    # ㄊㄤ
    '汤' => '湯',
    '烫' => '燙',
    # ㄊㄥ
    '腾' => '騰',
    # ㄊㄧ
    '体' => '體',
    '题' => '題',
    # ㄊㄧㄝ
    '贴' => '貼',
    '铁' => '鐵',
    # ㄊㄧㄠ
    '条' => '條',
    # ㄊㄧㄥ
    '听' => '聽',
    '厅' => '廳',
    # ㄊㄨ
    '图' => '圖',
    # ㄊㄨㄛ
    '椭' => '橢',
    # ㄊㄨㄟ
    '颓' => '頹',
    # ㄊㄨㄢ
    '团' => '團',
    # ㄊㄨㄥ
    '统' => '統',
    '铜' => '銅',
    #### ㄋ ####
    # ㄋㄚ
    '纳' => '納',
    # ㄋㄜ
    '讷' => '訥',
    # ㄋㄟ
    '馁' => '餒',
    # ㄋㄠ
    '恼' => '惱',
    '脑' => '腦',
    '闹' => '鬧',
    # ㄋㄢ
    '难' => '難',
    # ㄋㄧ
    '拟' => '擬',
    '腻' => '膩',
    # ㄋㄧㄝ
    '蹑' => '躡',
    # ㄋㄧㄠ
    '鸟' => '鳥',
    '袅' => '裊',
    # ㄋㄧㄢ
    '粘' => '黏',
    '辇' => '輦',
    # ㄋㄧㄤ
    '酿' => '釀',
    # ㄋㄧㄥ
    '宁' => '寧',
    '泞' => '濘',
    '拧' => '擰',
    '狞' => '獰',
    # ㄋㄨㄛ
    '诺' => '諾',
    # ㄋㄨㄥ
    '农' => '農',
    '浓' => '濃',
    '脓' => '膿',
    # ㄋㄩㄝ
    '谑' => '謔',
    #### ㄌ ####
    # ㄌㄚ
    '腊' => '臘',
    # ㄌㄞ
    '来' => '來',
    '睐' => '睞',
    '赖' => '賴',
    '籁' => '籟',
    # ㄌㄟ
    '泪' => '淚',
    '类' => '類',
    # ㄌㄠ
    '劳' => '勞',
    '捞' => '撈',
    # ㄌㄡ
    '偻' => '僂',
    '搂' => '摟',
    '髅' => '髏',
    # ㄌㄢ
    '兰' => '蘭',
    '拦' => '攔',
    '烂' => '爛',
    '栏' => '欄',
    '澜' => '瀾',
    '蓝' => '藍',
    '滥' => '濫',
    '览' => '覧',
    '揽' => '攬',
    '岚' => '嵐',
    '懒' => '懶',
    # ㄌㄧ
    '里' => '裡',
    '离' => '離',
    '历' => '歷',
    '厉' => '厲',
    '励' => '勵',
    '雳' => '靂',
    '丽' => '麗',
    '隶' => '隸',
    # ㄌㄧㄝ
    '猎' => '獵',
    # ㄌㄧㄠ
    '疗' => '療',
    '缭' => '繚',
    # ㄌㄧㄡ
    '刘' => '劉',
    '浏' => '瀏',
    # ㄌㄧㄢ
    '联' => '聯',
    '脸' => '臉',
    '敛' => '斂',
    '怜' => '憐',
    '帘' => '簾',
    '炼' => '煉',
    '练' => '練',
    '连' => '連',
    '莲' => '蓮',
    '涟' => '漣',
    '恋' => '戀',
    # ㄌㄧㄣ
    '临' => '臨',
    '躏' => '躪',
    '邻' => '鄰',
    # ㄌㄧㄤ
    '俩' => '倆',
    '辆' => '輛',
    '谅' => '諒',
    '粮' => '糧',
    # ㄌㄧㄥ
    '灵' => '靈',
    '铃' => '鈴',
    '领' => '領',
    '龄' => '齡',
    # ㄌㄨ
    '炉' => '爐',
    '庐' => '廬',
    '芦' => '蘆',
    '录' => '錄',
    '陆' => '陸',
    '鲁' => '魯',
    '噜' => '嚕',
    '虏' => '虜',
    '掳' => '擄',
    '辘' => '轆',
    '卤' => '鹵',
    # ㄌㄨㄛ
    '络' => '絡',
    '喽' => '囉',
    '罗' => '羅',
    '逻' => '邏',
    '箩' => '籮',
    # ㄌㄨㄢ
    '乱' => '亂',
    # ㄌㄨㄣ
    '伦' => '倫',
    '沦' => '淪',
    '抡' => '掄',
    '论' => '論',
    '轮' => '輪',
    # ㄌㄨㄥ
    '龙' => '龍',
    '拢' => '攏',
    '珑' => '瓏',
    '胧' => '朧',
    '笼' => '籠',
    '咙' => '嚨',
    # ㄌㄩ
    '绿' => '綠',
    '缕' => '縷',
    '屡' => '屢',
    '虑' => '慮',
    '滤' => '濾',
    '驴' => '驢',
    #### ㄍ ####
    # ㄍㄜ
    '个' => '個',
    '阁' => '閣',
    '搁' => '擱',
    # ㄍㄞ
    '该' => '該',
    '盖' => '蓋',
    # ㄍㄟ
    '给' => '給',
    # ㄍㄡ
    '钩' => '鉤',
    '沟' => '溝',
    '构' => '構',
    '购' => '購',
    # ㄍㄢ
    '干' => '乾',
    '赶' => '趕',
    '尴' => '尷',
    # ㄍㄤ
    '刚' => '剛',
    '岗' => '崗',
    '纲' => '綱',
    '钢' => '鋼',
    # ㄍㄥ
    '鲠' => '鯁',
    # ㄍㄨ
    '锢' => '錮',
    '蛊' => '蠱',
    '轱' => '軲',
    '顾' => '顧',
    # ㄍㄨㄚ
    '挂' => '掛',
    '剐' => '剮',
    # ㄍㄨㄛ
    '过' => '過',
    '国' => '國',
    '锅' => '鍋',
    # ㄍㄨㄟ
    '轨' => '軌',
    '诡' => '詭',
    '归' => '歸',
    '规' => '規',
    '贵' => '貴',
    '龟' => '龜',
    '柜' => '櫃',
    '闺' => '閨',
    # ㄍㄨㄢ
    '关' => '關',
    '馆' => '館',
    '观' => '觀',
    '贯' => '貫',
    '惯' => '慣',
    '掼' => '摜',
    # ㄍㄨㄣ
    '滚' => '滾',
    # ㄍㄨㄤ
    '广' => '廣',
    #### ㄎ ####
    # ㄎㄜ
    '课' => '課',
    '颗' => '顆',
    '壳' => '殼',
    # ㄎㄞ
    '开' => '開',
    # ㄎㄢ
    '槛' => '檻',
    # ㄎㄣ
    '恳' => '懇',
    # ㄎㄨ
    '库' => '庫',
    '裤' => '褲',
    '绔' => '絝',
    # ㄎㄨㄚ
    '夸' => '誇',
    # ㄎㄨㄛ
    '扩' => '擴',
    '阔' => '闊',
    # ㄎㄨㄞ
    '块' => '塊',
    # ㄎㄨㄟ
    '亏' => '虧',
    '溃' => '潰',
    '馈' => '饋',
    '窥' => '窺',
    # ㄎㄨㄢ
    '宽' => '寬',
    # ㄎㄨㄣ
    '鲲' => '鯤',
    # ㄎㄨㄤ
    '况' => '況',
    '旷' => '曠',
    #### ㄏ ####
    # ㄏㄜ
    '贺' => '賀',
    '鹤' => '鶴',
    # ㄏㄞ
    '还' => '還',
    '骇' => '駭',
    # ㄏㄠ
    '号' => '號',
    # ㄏㄡ
    '后' => '後',
    # ㄏㄢ
    '汉' => '漢',
    '颔' => '頷',
    '韩' => '韓',
    # ㄏㄥ
    '横' => '橫',
    # ㄏㄨ
    '壶' => '壺',
    '护' => '護',
    # ㄏㄨㄚ
    '话' => '話',
    '华' => '華',
    '哗' => '嘩',
    '划' => '劃',
    '画' => '畫',
    # ㄏㄨㄛ
    '祸' => '禍',
    '货' => '貨',
    '获' => '獲',
    # ㄏㄨㄞ
    '坏' => '壞',
    '怀' => '懷',
    # ㄏㄨㄟ
    '会' => '會',
    '绘' => '繪',
    '汇' => '匯',
    '挥' => '揮',
    '辉' => '輝',
    '讳' => '諱',
    '诲' => '誨',
    # ㄏㄨㄢ
    '奂' => '奐',
    '唤' => '喚',
    '换' => '換',
    '涣' => '渙',
    '缓' => '緩',
    '环' => '環',
    '欢' => '歡',
    # ㄏㄨㄣ
    '浑' => '渾',
    '荤' => '葷',
    # ㄏㄨㄤ
    '黄' => '黃',
    '谎' => '謊',
    # ㄏㄨㄥ
    '红' => '紅',
    '轰' => '轟',
    #### ㄐ ####
    # ㄐㄧ
    '计' => '計',
    '击' => '擊',
    '积' => '積',
    '绩' => '績',
    '级' => '級',
    '记' => '記',
    '纪' => '紀',
    '迹' => '跡',
    '继' => '繼',
    '际' => '際',
    '几' => '幾',
    '叽' => '嘰',
    '机' => '機',
    '讥' => '譏',
    '极' => '極',
    '剂' => '劑',
    '济' => '濟',
    '挤' => '擠',
    '辑' => '輯',
    '鸡' => '雞',
    # ㄐㄧㄚ
    '夹' => '夾',
    '浃' => '浹',
    '荚' => '莢',
    '颊' => '頰',
    '价' => '價',
    '驾' => '駕',
    '贾' => '賈',
    # ㄐㄧㄝ
    '届' => '屆',
    '节' => '節',
    '结' => '結',
    '洁' => '潔',
    '阶' => '階',
    # ㄐㄧㄠ
    '娇' => '嬌',
    '矫' => '矯',
    '骄' => '驕',
    '轿' => '轎',
    '胶' => '膠',
    '绞' => '絞',
    '较' => '較',
    '侥' => '僥',
    '浇' => '澆',
    '脚' => '腳',
    '搅' => '攪',
    # ㄐㄧㄡ
    '旧' => '舊',
    '纠' => '糾',
    '厩' => '廄',
    # ㄐㄧㄢ
    '见' => '見',
    '间' => '間',
    '简' => '簡',
    '剑' => '劍',
    '渐' => '漸',
    '捡' => '撿',
    '检' => '檢',
    '拣' => '揀',
    '减' => '減',
    '监' => '監',
    '艰' => '艱',
    '坚' => '堅',
    '鉴' => '鑑',
    '贱' => '賤',
    '荐' => '薦',
    '键' => '鍵',
    # ㄐㄧㄣ
    '尽' => '盡',
    '进' => '進',
    '锦' => '錦',
    '紧' => '緊',
    '谨' => '謹',
    '仅' => '僅',
    # ㄐㄧㄤ
    '讲' => '講',
    '将' => '將',
    '奖' => '獎',
    '缰' => '繮',
    # ㄐㄧㄥ
    '径' => '徑',
    '迳' => '逕',
    '劲' => '勁',
    '颈' => '頸',
    '经' => '經',
    '净' => '淨',
    '静' => '靜',
    '靓' => '靚',
    '镜' => '鏡',
    '竞' => '競',
    '惊' => '驚',
    # ㄐㄩ
    '剧' => '劇',
    '据' => '據',
    '惧' => '懼',
    '举' => '舉',
    # ㄐㄩㄝ
    '决' => '決',
    '觉' => '覺',
    '绝' => '絕',
    # ㄐㄩㄣ
    '钧' => '鈞',
    '军' => '軍',
    '骏' => '駿',
    #### ㄑ ####
    # ㄑㄧ
    '气' => '氣',
    '弃' => '棄',
    '齐' => '齊',
    '绮' => '綺',
    '锜' => '錡',
    '骑' => '騎',
    '岂' => '豈',
    '栖' => '棲',
    '凄' => '淒',
    '启' => '啟',
    '颀' => '頎',
    # ㄑㄧㄝ
    '窃' => '竊',
    '锲' => '鍥',
    # ㄑㄧㄠ
    '诮' => '誚',
    '跷' => '蹺',
    '翘' => '翹',
    '桥' => '橋',
    '窍' => '竅',
    # ㄑㄧㄢ
    '签' => '簽',
    '牵' => '牽',
    '浅' => '淺',
    '钱' => '錢',
    '谦' => '謙',
    '潜' => '潛',
    '迁' => '遷',
    # ㄑㄧㄣ
    '亲' => '親',
    '寝' => '寢',
    # ㄑㄧㄤ
    '墙' => '牆',
    '呛' => '嗆',
    '抢' => '搶',
    '枪' => '槍',
    # ㄑㄧㄥ
    '轻' => '輕',
    '请' => '請',
    '顷' => '頃',
    '倾' => '傾',
    '庆' => '慶',
    # ㄑㄩ
    '区' => '區',
    '驱' => '驅',
    '躯' => '軀',
    '趋' => '趨',
    '觑' => '覷',
    # ㄑㄩㄝ
    '确' => '確',
    # ㄑㄩㄢ
    '权' => '權',
    '劝' => '勸',
    # ㄑㄩㄥ
    '穷' => '窮',
    #### ㄒ ####
    # ㄒㄧ
    '习' => '習',
    '细' => '細',
    '戏' => '戲',
    '袭' => '襲',
    '玺' => '璽',
    # ㄒㄧㄚ
    '侠' => '俠',
    '狭' => '狹',
    '吓' => '嚇',
    '虾' => '蝦',
    # ㄒㄧㄝ
    '写' => '寫',
    '挟' => '挾',
    '协' => '協',
    '胁' => '脅',
    '谐' => '諧',
    '谢' => '謝',
    '亵' => '褻',
    # ㄒㄧㄠ
    '晓' => '曉',
    '销' => '銷',
    '潇' => '瀟',
    '啸' => '嘯',
    '嚣' => '囂',
    # ㄒㄧㄡ
    '绣' => '繡',
    '馐' => '饈',
    # ㄒㄧㄢ
    '现' => '現',
    '闲' => '閑',
    '娴' => '嫻',
    '险' => '險',
    '衔' => '銜',
    '鲜' => '鮮',
    '线' => '線',
    '县' => '縣',
    '纤' => '纖',
    '显' => '顯',
    '贤' => '賢',
    '宪' => '憲',
    '羡' => '羨',
    # ㄒㄧㄣ
    '衅' => '釁',
    # ㄒㄧㄤ
    '乡' => '鄉',
    '项' => '項',
    '响' => '響',
    '饷' => '餉',
    '详' => '詳',
    # ㄒㄧㄥ
    '兴' => '興',
    # ㄒㄩ
    '许' => '許',
    '须' => '須',
    '绪' => '緒',
    '嘘' => '噓',
    '续' => '續',
    # ㄒㄩㄝ
    '学' => '學',
    # ㄒㄩㄢ
    '选' => '選',
    '悬' => '懸',
    # ㄒㄩㄣ
    '训' => '訓',
    '寻' => '尋',
    '询' => '詢',
    '勋' => '勛',
    '逊' => '遜',
    '讯' => '訊',
    # ㄒㄩㄥ
    '汹' => '洶',
    #### ㄓ ####
    '执' => '執',
    '纸' => '紙',
    '职' => '職',
    '织' => '織',
    '质' => '質',
    '滞' => '滯',
    '蛰' => '蟄',
    # ㄓㄚ
    '杂' => '雜',
    '诈' => '詐',
    # ㄓㄜ
    '这' => '這',
    # ㄓㄞ
    '斋' => '齋',
    # ㄓㄠ
    '赵' => '趙',
    '诏' => '詔',
    # ㄓㄡ
    '昼' => '晝',
    '轴' => '軸',
    '皱' => '皺',
    # ㄓㄢ
    '占' => '佔',
    '斩' => '斬',
    '绽' => '綻',
    '战' => '戰',
    '暂' => '暫',
    '颤' => '顫',
    '毡' => '氊',
    '盏' => '盞',
    # ㄓㄣ
    '贞' => '貞',
    '侦' => '偵',
    '阵' => '陣',
    '针' => '針',
    '镇' => '鎮',
    # ㄓㄤ
    '帐' => '帳',
    '张' => '張',
    '胀' => '脹',
    '账' => '賬',
    '涨' => '漲',
    # ㄓㄥ
    '争' => '爭',
    '挣' => '掙',
    '狰' => '猙',
    '睁' => '睜',
    '铮' => '錚',
    '证' => '證',
    '郑' => '鄭',
    # ㄓㄨ
    '诸' => '諸',
    '诛' => '誅',
    '驻' => '駐',
    '嘱' => '囑',
    '瞩' => '矚',
    '铸' => '鑄',
    '烛' => '燭',
    # ㄓㄨㄟ
    '坠' => '墜',
    '赘' => '贅',
    # ㄓㄨㄢ
    '专' => '專',
    '砖' => '磚',
    '转' => '轉',
    '钻' => '鑽',
    '赚' => '賺',
    # ㄓㄨㄣ
    '准' => '準',
    '谆' => '諄',
    # ㄓㄨㄤ
    '壮' => '壯',
    '状' => '狀',
    '装' => '裝',
    # ㄓㄨㄥ
    '众' => '眾',
    '种' => '種',
    '肿' => '腫',
    '钟' => '鐘',
    '终' => '終',
    #### ㄔ ####
    '齿' => '齒',
    '迟' => '遲',
    '驰' => '馳',
    # ㄔㄚ
    '诧' => '詫',
    # ㄔㄜ
    '车' => '車',
    '彻' => '徹',
    # ㄔㄞ
    '钗' => '釵',
    # ㄔㄡ
    '筹' => '籌',
    '踌' => '躊',
    '绸' => '綢',
    # ㄔㄢ
    '蝉' => '蟬',
    '婵' => '嬋',
    '阐' => '闡',
    '缠' => '纏',
    '搀' => '攙',
    '馋' => '饞',
    '产' => '產',
    '铲' => '鏟',
    # ㄔㄣ
    '尘' => '塵',
    '陈' => '陳',
    '衬' => '襯',
    # ㄔㄤ
    '长' => '長',
    '场' => '場',
    '肠' => '腸',
    '尝' => '嘗',
    '偿' => '償',
    '畅' => '暢',
    # ㄔㄥ
    '称' => '稱',
    '诚' => '誠',
    # ㄔㄨ
    '处' => '處',
    '础' => '礎',
    '触' => '觸',
    '储' => '儲',
    '厨' => '廚',
    '雏' => '雛',
    # ㄔㄨㄟ
    '锤' => '錘',
    # ㄔㄨㄢ
    '传' => '傳',
    # ㄔㄨㄣ
    '纯' => '純',
    # ㄔㄨㄤ
    '创' => '創',
    '怆' => '愴',
    '疮' => '瘡',
    '闯' => '闖',
    # ㄔㄨㄥ
    '冲' => '衝',
    '虫' => '蟲',
    '宠' => '寵',
    #### ㄕ ####
    '时' => '時',
    '视' => '視',
    '适' => '適',
    '实' => '實',
    '师' => '師',
    '识' => '識',
    '试' => '試',
    '诗' => '詩',
    '尸' => '屍',
    '湿' => '濕',
    '饰' => '飾',
    '势' => '勢',
    '释' => '釋',
    '驶' => '駛',
    '蚀' => '蝕',
    # ㄕㄚ
    '杀' => '殺',
    '纱' => '紗',
    # ㄕㄜ
    '设' => '設',
    '舍' => '捨',
    '摄' => '攝',
    # ㄕㄞ
    '晒' => '曬',
    # ㄕㄟ
    '谁' => '誰',
    # ㄕㄠ
    '绍' => '紹',
    '烧' => '燒',
    # ㄕㄡ
    '兽' => '獸',
    '寿' => '壽',
    # ㄕㄢ
    '闪' => '閃',
    '禅' => '襌',
    # ㄕㄣ
    '审' => '審',
    '婶' => '嬸',
    '肾' => '腎',
    # ㄕㄤ
    '伤' => '傷',
    '赏' => '賞',
    # ㄕㄥ
    '声' => '聲',
    '圣' => '聖',
    '绳' => '繩',
    '胜' => '勝',
    # ㄕㄨ
    '书' => '書',
    '术' => '術',
    '竖' => '豎',
    '树' => '樹',
    '输' => '輸',
    '属' => '屬',
    '赎' => '贖',
    '枢' => '樞',
    # ㄕㄨㄛ
    '说' => '說',
    '烁' => '爍',
    # ㄕㄨㄞ
    '帅' => '帥',
    # ㄕㄨㄣ
    '顺' => '順',
    # ㄕㄨㄤ
    '双' => '雙',
    #### ㄖ ####
    # ㄖㄜ
    '热' => '熱',
    # ㄖㄠ
    '挠' => '撓',
    '绕' => '繞',
    '饶' => '饒',
    '扰' => '擾',
    # ㄖㄣ
    '认' => '認',
    '韧' => '韌',
    '饪' => '飪',
    # ㄖㄤ
    '让' => '讓',
    # ㄖㄨㄟ
    '锐' => '銳',
    # ㄖㄨㄢ
    '软' => '軟',
    # ㄖㄨㄣ
    '润' => '潤',
    # ㄖㄨㄥ
    '荣' => '榮',
    #### ㄗ ####
    '资' => '資',
    '辎' => '輜',
    # ㄗㄜ
    '则' => '則',
    '责' => '責',
    '啧' => '嘖',
    '择' => '擇',
    '泽' => '澤',
    # ㄗㄞ
    '灾' => '災',
    '载' => '載',
    # ㄗㄟ
    '贼' => '賊',
    # ㄗㄠ
    '枣' => '棗',
    # ㄗㄡ
    '骤' => '驟',
    # ㄗㄢ
    '赞' => '讚',
    # ㄗㄤ
    '脏' => '髒',
    '赃' => '贓',
    # ㄗㄥ
    '赠' => '贈',
    # ㄗㄨ
    '诅' => '詛',
    '组' => '組',
    # ㄗㄨㄥ
    '总' => '總',
    '综' => '綜',
    '纵' => '縱',
    #### ㄘ ####
    '词' => '詞',
    '辞' => '辭',
    # ㄘㄜ
    '侧' => '側',
    '厕' => '廁',
    '测' => '測',
    # ㄘㄞ
    '财' => '財',
    # ㄘㄡ
    '凑' => '湊',
    # ㄘㄢ
    '残' => '殘',
    '参' => '參',
    '惨' => '慘',
    '掺' => '摻',
    '惭' => '慚',
    '灿' => '燦',
    # ㄘㄤ
    '仓' => '倉',
    '苍' => '蒼',
    # ㄘㄥ
    '层' => '層',
    # ㄘㄨㄛ
    '错' => '錯',
    # ㄘㄨㄢ
    '攒' => '攢',
    '窜' => '竄',
    '蹿' => '躥',
    # ㄘㄨㄥ
    '从' => '從',
    '丛' => '叢',
    '聪' => '聰',
    #### ㄙ ####
    '丝' => '絲',
    '赐' => '賜',
    # ㄙㄚ
    '洒' => '灑',
    # ㄙㄜ
    '涩' => '澀',
    # ㄙㄞ
    '赛' => '賽',
    # ㄙㄠ
    '扫' => '掃',
    '骚' => '騷',
    # ㄙㄡ
    '馊' => '餿',
    '擞' => '擻',
    # ㄙㄢ
    '伞' => '傘',
    # ㄙㄤ
    '丧' => '喪',
    # ㄙㄨ
    '诉' => '訴',
    '苏' => '蘇',
    '肃' => '肅',
    # ㄙㄨㄛ
    '锁' => '鎖',
    '琐' => '瑣',
    '缩' => '縮',
    # ㄙㄨㄟ
    '虽' => '雖',
    '岁' => '歲',
    '随' => '隨',
    # ㄙㄨㄣ
    '损' => '損',
    '孙' => '孫',
    # ㄙㄨㄥ
    '怂' => '慫',
    '耸' => '聳',
    '诵' => '誦',
    #### ㄛ ####
    #### ㄜ ####
    '恶' => '惡',
    '饿' => '餓',
    '额' => '額',
    '鹅' => '鵝',
    #### ㄞ ####
    '爱' => '愛',
    '暧' => '曖',
    '碍' => '礙',
    #### ㄟ ####
    '诶' => '誒',
    #### ㄠ ####
    '袄' => '襖',
    #### ㄡ ####
    '殴' => '毆',
    '欧' => '歐',
    #### ㄢ ####
    '谙' => '諳',
    #### ㄦ ####
    '儿' => '兒',
    '尔' => '爾',
    #### ㄧ ####
    '义' => '義',
    '仪' => '儀',
    '蚁' => '蟻',
    '议' => '議',
    '忆' => '憶',
    '艺' => '藝',
    '呓' => '囈',
    '绎' => '繹',
    '谊' => '誼',
    '遗' => '遺',
    '异' => '異',
    # ㄧㄚ
    '讶' => '訝',
    '压' => '壓',
    '亚' => '亞',
    '哑' => '啞',
    '鸦' => '鴉',
    '鸭' => '鴨',
    # ㄧㄝ
    '页' => '頁',
    '叶' => '葉',
    '业' => '業',
    '爷' => '爺',
    # ㄧㄠ
    '摇' => '搖',
    '谣' => '謠',
    '遥' => '遙',
    '瑶' => '瑤',
    '跃' => '躍',
    '药' => '藥',
    '哟' => '喲',
    '钥' => '鑰',
    # ㄧㄡ
    '邮' => '郵',
    '优' => '優',
    '忧' => '憂',
    '犹' => '猶',
    '诱' => '誘',
    # ㄧㄢ
    '烟' => '煙',
    '厌' => '厭',
    '严' => '嚴',
    '俨' => '儼',
    '颜' => '顏',
    '验' => '驗',
    '盐' => '鹽',
    '艳' => '艷',
    '魇' => '魘',
    '阉' => '閹',
    # ㄧㄣ
    '银' => '銀',
    '阴' => '陰',
    '荫' => '蔭',
    '饮' => '飲',
    '隐' => '隱',
    '瘾' => '癮',
    # ㄧㄤ
    '扬' => '揚',
    '杨' => '楊',
    '样' => '樣',
    '痒' => '癢',
    '阳' => '陽',
    '养' => '養',
    '鸯' => '鴦',
    # ㄧㄥ
    '应' => '應',
    '荧' => '熒',
    '莹' => '瑩',
    '营' => '營',
    '萤' => '螢',
    '萦' => '縈',
    '莺' => '鶯',
    '颖' => '穎',
    '嘤' => '嚶',
    '樱' => '櫻',
    '鹦' => '鸚',
    '赢' => '贏',
    #### ㄨ ####
    '无' => '無',
    '妩' => '嫵',
    '芜' => '蕪',
    '乌' => '烏',
    '呜' => '嗚',
    '误' => '誤',
    '诬' => '誣',
    '务' => '務',
    '雾' => '霧',
    '鹉' => '鵡',
    # ㄨㄛ
    '窝' => '窩',
    # ㄨㄟ
    '卫' => '衛',
    '为' => '為',
    '伪' => '偽',
    '伟' => '偉',
    '围' => '圍',
    '违' => '違',
    '闱' => '闈',
    '谓' => '謂',
    '维' => '維',
    '诿' => '諉',
    # ㄨㄢ
    '万' => '萬',
    '纨' => '紈',
    '顽' => '頑',
    '弯' => '彎',
    # ㄨㄣ
    '问' => '問',
    '闻' => '聞',
    '纹' => '紋',
    '稳' => '穩',
    # ㄨㄤ
    '网' => '網',
    #### ㄩ ####
    '于' => '於',
    '与' => '與',
    '语' => '語',
    '预' => '預',
    '鱼' => '魚',
    '余' => '餘',
    '钰' => '鈺',
    '狱' => '獄',
    '誉' => '譽',
    # ㄩㄝ
    '乐' => '樂',
    '约' => '約',
    '阅' => '閱',
    # ㄩㄢ
    '员' => '員',
    '圆' => '圓',
    '园' => '園',
    '远' => '遠',
    '缘' => '緣',
    '愿' => '願',
    '渊' => '淵',
    '鸳' => '鴛',
    # ㄩㄣ
    '云' => '雲',
    '运' => '運',
    '酝' => '醞',
    '韵' => '韻',
    '蕴' => '蘊',
    '恽' => '惲',
    '晕' => '暈',
    # ㄩㄥ
    '咏' => '詠',
    '拥' => '擁',
    '涌' => '湧',
    '鳙' => '鱅',
    #### 異體 ####
    # ㄅ
    '剥' => '剝',
    # ㄇ
    '没' => '沒',
    '猫' => '貓',
    '满' => '滿',
    # ㄉ
    '兑' => '兌',
    '灯' => '燈',
    # ㄊ
    '脱' => '脫',
    # ㄌ
    '两' => '兩',
    '侣' => '侶',
    '礼' => '禮',
    '楼' => '樓',
    '凉' => '涼',
    # ㄍ
    '够' => '夠',
    # ㄏ
    '户' => '戶',
    '毁' => '毀',
    # ㄑ
    '却' => '卻',
    '强' => '強',
    # ㄒ
    '泄' => '洩',
    '虚' => '虛',
    '携' => '攜',
    # ㄓ
    '着' => '著',
    '猪' => '豬',
    # ㄕ
    '数' => '數',
    # ㄗ
    '踪' => '蹤',
    # ㄘ
    '册' => '冊',
    # ㄙ
    '厮' => '廝',
    '騒' => '騷',
    # ㄧ
    '檐' => '簷',
    # ㄨ
    '温' => '溫',
    # ㄩ
    '悦' => '悅',
    '娱' => '娛'
)