Effect of \(c\) on calibration curves#
\(\require{mathtools} \newcommand{\notag}{} \newcommand{\tag}{} \newcommand{\label}[1]{} \newcommand{\sfrac}[2]{#1/#2} \newcommand{\bm}[1]{\boldsymbol{#1}} \newcommand{\num}[1]{#1} \newcommand{\qty}[2]{#1\,#2} \renewenvironment{align} {\begin{aligned}} {\end{aligned}} \renewenvironment{alignat} {\begin{alignedat}} {\end{alignedat}} \newcommand{\pdfmspace}[1]{} % Ignore PDF-only spacing commands \newcommand{\htmlmspace}[1]{\mspace{#1}} % Ignore PDF-only spacing commands \newcommand{\scaleto}[2]{#1} % Allow to use scaleto from scalerel package \newcommand{\RR}{\mathbb R} \newcommand{\NN}{\mathbb N} \newcommand{\PP}{\mathbb P} \newcommand{\EE}{\mathbb E} \newcommand{\XX}{\mathbb X} \newcommand{\ZZ}{\mathbb Z} \newcommand{\QQ}{\mathbb Q} \newcommand{\fF}{\mathcal F} \newcommand{\dD}{\mathcal D} \newcommand{\lL}{\mathcal L} \newcommand{\gG}{\mathcal G} \newcommand{\hH}{\mathcal H} \newcommand{\nN}{\mathcal N} \newcommand{\pP}{\mathcal P} \newcommand{\BB}{\mathbb B} \newcommand{\Exp}{\operatorname{Exp}} \newcommand{\Binomial}{\operatorname{Binomial}} \newcommand{\Poisson}{\operatorname{Poisson}} \newcommand{\linop}{\mathcal{L}(\mathbb{B})} \newcommand{\linopell}{\mathcal{L}(\ell_1)} \DeclareMathOperator{\trace}{trace} \DeclareMathOperator{\Var}{Var} \DeclareMathOperator{\Span}{span} \DeclareMathOperator{\proj}{proj} \DeclareMathOperator{\col}{col} \DeclareMathOperator*{\argmin}{arg\,min} \DeclareMathOperator*{\argmax}{arg\,max} \DeclareMathOperator*{\gt}{>} \definecolor{highlight-blue}{RGB}{0,123,255} % definition, theorem, proposition \definecolor{highlight-yellow}{RGB}{255,193,7} % lemma, conjecture, example \definecolor{highlight-orange}{RGB}{253,126,20} % criterion, corollary, property \definecolor{highlight-red}{RGB}{220,53,69} % criterion \newcommand{\logL}{\ell} \newcommand{\eE}{\mathcal{E}} \newcommand{\oO}{\mathcal{O}} \newcommand{\defeq}{\stackrel{\mathrm{def}}{=}} \newcommand{\Bspec}{\mathcal{B}} % Spectral radiance \newcommand{\X}{\mathcal{X}} % X space \newcommand{\Y}{\mathcal{Y}} % Y space \newcommand{\M}{\mathcal{M}} % Model \newcommand{\Tspace}{\mathcal{T}} \newcommand{\Vspace}{\mathcal{V}} \newcommand{\Mtrue}{\mathcal{M}_{\mathrm{true}}} \newcommand{\MP}{\M_{\mathrm{P}}} \newcommand{\MRJ}{\M_{\mathrm{RJ}}} \newcommand{\qproc}{\mathfrak{Q}} \newcommand{\D}{\mathcal{D}} % Data (true or generic) \newcommand{\Dt}{\tilde{\mathcal{D}}} \newcommand{\Phit}{\widetilde{\Phi}} \newcommand{\Phis}{\Phi^*} \newcommand{\qt}{\tilde{q}} \newcommand{\qs}{q^*} \newcommand{\qh}{\hat{q}} \newcommand{\AB}[1]{\mathtt{AB}~\mathtt{#1}} \newcommand{\LP}[1]{\mathtt{LP}~\mathtt{#1}} \newcommand{\NML}{\mathrm{NML}} \newcommand{\iI}{\mathcal{I}} \newcommand{\true}{\mathrm{true}} \newcommand{\dist}{D} \newcommand{\Mtheo}[1]{\mathcal{M}_{#1}} % Model (theoretical model); index: param set \newcommand{\DL}[1][L]{\mathcal{D}^{(#1)}} % Data (RV or generic) \newcommand{\DLp}[1][L]{\mathcal{D}^{(#1')}} % Data (RV or generic) \newcommand{\DtL}[1][L]{\tilde{\mathcal{D}}^{(#1)}} % Data (RV or generic) \newcommand{\DpL}[1][L]{{\mathcal{D}'}^{(#1)}} % Data (RV or generic) \newcommand{\Dobs}[1][]{\mathcal{D}_{\mathrm{obs}}^{#1}} % Data (observed) \newcommand{\calibset}{\mathcal{C}} \newcommand{\N}{\mathcal{N}} % Normal distribution \newcommand{\Z}{\mathcal{Z}} % Partition function \newcommand{\VV}{\mathbb{V}} % Variance \newcommand{\T}{\mathsf{T}} % Transpose \newcommand{\EMD}{\mathrm{EMD}} \newcommand{\dEMD}{d_{\mathrm{EMD}}} \newcommand{\dEMDtilde}{\tilde{d}_{\mathrm{EMD}}} \newcommand{\dEMDsafe}{d_{\mathrm{EMD}}^{\text{(safe)}}} \newcommand{\e}{ε} % Model confusion threshold \newcommand{\falsifythreshold}{ε} \newcommand{\bayes}[1][]{B_{#1}} \newcommand{\bayesthresh}[1][]{B_{0}} \newcommand{\bayesm}[1][]{B^{\mathcal{M}}_{#1}} \newcommand{\bayesl}[1][]{B^l_{#1}} \newcommand{\bayesphys}[1][]{B^{{p}}_{#1}} \newcommand{\Bconf}[1]{B^{\mathrm{epis}}_{#1}} \newcommand{\Bemd}[1]{B^{\mathrm{EMD}}_{#1}} \newcommand{\BQ}[1]{B^{Q}_{#1}} \newcommand{\Bconfbin}[1][]{\bar{B}^{\mathrm{conf}}_{#1}} \newcommand{\Bemdbin}[1][]{\bar{B}_{#1}^{\mathrm{EMD}}} \newcommand{\bin}{\mathcal{B}} \newcommand{\Bconft}[1][]{\tilde{B}^{\mathrm{conf}}_{#1}} \newcommand{\fc}{f_c} \newcommand{\fcbin}{\bar{f}_c} \newcommand{\paramphys}[1][]{Θ^{{p}}_{#1}} \newcommand{\paramobs}[1][]{Θ^{ε}_{#1}} \newcommand{\test}{\mathrm{test}} \newcommand{\train}{\mathrm{train}} \newcommand{\synth}{\mathrm{synth}} \newcommand{\rep}{\mathrm{rep}} \newcommand{\MNtrue}{\mathcal{M}^{{p}}_{\text{true}}} \newcommand{\MN}[1][]{\mathcal{M}^{{p}}_{#1}} \newcommand{\MNA}{\mathcal{M}^{{p}}_{Θ_A}} \newcommand{\MNB}{\mathcal{M}^{{p}}_{Θ_B}} \newcommand{\Me}[1][]{\mathcal{M}^ε_{#1}} \newcommand{\Metrue}{\mathcal{M}^ε_{\text{true}}} \newcommand{\Meobs}{\mathcal{M}^ε_{\text{obs}}} \newcommand{\Meh}[1][]{\hat{\mathcal{M}}^ε_{#1}} \newcommand{\MNa}{\mathcal{M}^{\mathcal{N}}_a} \newcommand{\MeA}{\mathcal{M}^ε_A} \newcommand{\MeB}{\mathcal{M}^ε_B} \newcommand{\Ms}{\mathcal{M}^*} \newcommand{\MsA}{\mathcal{M}^*_A} \newcommand{\MsB}{\mathcal{M}^*_B} \newcommand{\Msa}{\mathcal{M}^*_a} \newcommand{\MsAz}{\mathcal{M}^*_{A,z}} \newcommand{\MsBz}{\mathcal{M}^*_{B,z}} \newcommand{\Msaz}{\mathcal{M}^*_{a,z}} \newcommand{\MeAz}{\mathcal{M}^ε_{A,z}} \newcommand{\MeBz}{\mathcal{M}^ε_{B,z}} \newcommand{\Meaz}{\mathcal{M}^ε_{a,z}} \newcommand{\zo}{z^{0}} \renewcommand{\lL}[2][]{\mathcal{L}_{#1|{#2}}} % likelihood \newcommand{\Lavg}[2][]{\mathcal{L}^{/#2}_{#1}} % Geometric average of likelihood \newcommand{\lLphys}[2][]{\mathcal{L}^{{p}}_{#1|#2}} \newcommand{\Lavgphys}[2][]{\mathcal{L}^{{p}/#2}_{#1}} % Geometric average of likelihood \newcommand{\lLL}[3][]{\mathcal{L}^{(#3)}_{#1|#2}} \newcommand{\lLphysL}[3][]{\mathcal{L}^{{p},(#3)}_{#1|#2}} \newcommand{\lnL}[2][]{l_{#1|#2}} % Per-sample log likelihood \newcommand{\lnLt}[2][]{\widetilde{l}_{#1|#2}} \newcommand{\lnLtt}{\widetilde{l}} % Used only in path_sampling \newcommand{\lnLh}[1][]{\hat{l}_{#1}} \newcommand{\lnLphys}[2][]{l^{{p}}_{#1|#2}} \newcommand{\lnLphysL}[3][]{l^{{p},(#3)}_{#1|#2}} \newcommand{\Elmu}[2][1]{μ_{{#2}}^{(#1)}} \newcommand{\Elmuh}[2][1]{\hat{μ}_{{#2}}^{(#1)}} \newcommand{\Elsig}[2][1]{Σ_{{#2}}^{(#1)}} \newcommand{\Elsigh}[2][1]{\hat{Σ}_{{#2}}^{(#1)}} \newcommand{\pathP}{\mathop{{p}}} % Path-sampling process (generic) \newcommand{\pathPhb}{\mathop{{p}}_{\mathrm{Beta}}} % Path-sampling process (hierarchical beta) \newcommand{\interval}{\mathcal{I}} \newcommand{\Phiset}[1]{\{\Phi\}^{\small (#1)}} \newcommand{\Phipart}[1]{\{\mathcal{I}_Φ\}^{\small (#1)}} \newcommand{\qhset}[1]{\{\qh\}^{\small (#1)}} \newcommand{\Dqpart}[1]{\{Δ\qh_{2^{#1}}\}} \newcommand{\LsAzl}{\mathcal{L}_{\smash{{}^{\,*}_A},z,L}} \newcommand{\LsBzl}{\mathcal{L}_{\smash{{}^{\,*}_B},z,L}} \newcommand{\lsA}{l_{\smash{{}^{\,*}_A}}} \newcommand{\lsB}{l_{\smash{{}^{\,*}_B}}} \newcommand{\lsAz}{l_{\smash{{}^{\,*}_A},z}} \newcommand{\lsAzj}{l_{\smash{{}^{\,*}_A},z_j}} \newcommand{\lsAzo}{l_{\smash{{}^{\,*}_A},z^0}} \newcommand{\leAz}{l_{\smash{{}^{\,ε}_A},z}} \newcommand{\lsAez}{l_{\smash{{}^{*ε}_A},z}} \newcommand{\lsBz}{l_{\smash{{}^{\,*}_B},z}} \newcommand{\lsBzj}{l_{\smash{{}^{\,*}_B},z_j}} \newcommand{\lsBzo}{l_{\smash{{}^{\,*}_B},z^0}} \newcommand{\leBz}{l_{\smash{{}^{\,ε}_B},z}} \newcommand{\lsBez}{l_{\smash{{}^{*ε}_B},z}} \newcommand{\LaszL}{\mathcal{L}_{\smash{{}^{*}_a},z,L}} \newcommand{\lasz}{l_{\smash{{}^{*}_a},z}} \newcommand{\laszj}{l_{\smash{{}^{*}_a},z_j}} \newcommand{\laszo}{l_{\smash{{}^{*}_a},z^0}} \newcommand{\laez}{l_{\smash{{}^{ε}_a},z}} \newcommand{\lasez}{l_{\smash{{}^{*ε}_a},z}} \newcommand{\lhatasz}{\hat{l}_{\smash{{}^{*}_a},z}} \newcommand{\pasz}{p_{\smash{{}^{*}_a},z}} \newcommand{\paez}{p_{\smash{{}^{ε}_a},z}} \newcommand{\pasez}{p_{\smash{{}^{*ε}_a},z}} \newcommand{\phatsaz}{\hat{p}_{\smash{{}^{*}_a},z}} \newcommand{\phateaz}{\hat{p}_{\smash{{}^{ε}_a},z}} \newcommand{\phatseaz}{\hat{p}_{\smash{{}^{*ε}_a},z}} \newcommand{\Phil}[2][]{Φ_{#1|#2}} % Φ_{\la} \newcommand{\Philt}[2][]{\widetilde{Φ}_{#1|#2}} % Φ_{\la} \newcommand{\Philhat}[2][]{\hat{Φ}_{#1|#2}} % Φ_{\la} \newcommand{\Philsaz}{Φ_{\smash{{}^{*}_a},z}} % Φ_{\lasz} \newcommand{\Phileaz}{Φ_{\smash{{}^{ε}_a},z}} % Φ_{\laez} \newcommand{\Philseaz}{Φ_{\smash{{}^{*ε}_a},z}} % Φ_{\lasez} \newcommand{\mus}[1][1]{μ^{(#1)}_*} \newcommand{\musA}[1][1]{μ^{(#1)}_{\smash{{}^{\,*}_A}}} \newcommand{\SigsA}[1][1]{Σ^{(#1)}_{\smash{{}^{\,*}_A}}} \newcommand{\musB}[1][1]{μ^{(#1)}_{\smash{{}^{\,*}_B}}} \newcommand{\SigsB}[1][1]{Σ^{(#1)}_{\smash{{}^{\,*}_B}}} \newcommand{\musa}[1][1]{μ^{(#1)}_{\smash{{}^{*}_a}}} \newcommand{\Sigsa}[1][1]{Σ^{(#1)}_{\smash{{}^{*}_a}}} \newcommand{\Msah}{{\color{highlight-red}\mathcal{M}^{*}_a}} \newcommand{\Msazh}{{\color{highlight-red}\mathcal{M}^{*}_{a,z}}} \newcommand{\Meah}{{\color{highlight-blue}\mathcal{M}^{ε}_a}} \newcommand{\Meazh}{{\color{highlight-blue}\mathcal{M}^{ε}_{a,z}}} \newcommand{\lsazh}{{\color{highlight-red}l_{\smash{{}^{*}_a},z}}} \newcommand{\leazh}{{\color{highlight-blue}l_{\smash{{}^{ε}_a},z}}} \newcommand{\lseazh}{{\color{highlight-orange}l_{\smash{{}^{*ε}_a},z}}} \newcommand{\Philsazh}{{\color{highlight-red}Φ_{\smash{{}^{*}_a},z}}} % Φ_{\lasz} \newcommand{\Phileazh}{{\color{highlight-blue}Φ_{\smash{{}^{ε}_a},z}}} % Φ_{\laez} \newcommand{\Philseazh}{{\color{highlight-orange}Φ_{\smash{{}^{*ε}_a},z}}} % Φ_{\lasez} \newcommand{\emdstd}{\tilde{σ}} \DeclareMathOperator{\Mvar}{Mvar} \DeclareMathOperator{\AIC}{AIC} \DeclareMathOperator{\epll}{epll} \DeclareMathOperator{\elpd}{elpd} \DeclareMathOperator{\MDL}{MDL} \DeclareMathOperator{\comp}{COMP} \DeclareMathOperator{\Lognorm}{Lognorm} \DeclareMathOperator{\erf}{erf} \DeclareMathOperator*{\argmax}{arg\,max} \DeclareMathOperator{\Image}{Image} \DeclareMathOperator{\sgn}{sgn} \DeclareMathOperator{\SE}{SE} % standard error \DeclareMathOperator{\Unif}{Unif} \DeclareMathOperator{\Poisson}{Poisson} \DeclareMathOperator{\SkewNormal}{SkewNormal} \DeclareMathOperator{\TruncNormal}{TruncNormal} \DeclareMathOperator{\Exponential}{Exponential} \DeclareMathOperator{\exGaussian}{exGaussian} \DeclareMathOperator{\IG}{IG} \DeclareMathOperator{\NIG}{NIG} \DeclareMathOperator{\Gammadist}{Gamma} \DeclareMathOperator{\Lognormal}{Lognormal} \DeclareMathOperator{\Beta}{Beta} \newcommand{\sinf}{{s_{\infty}}}\)
NOTE Within Jupyter Lab, this notebook is best displayed with
jupyterlab-myst
.
Libraries#
import math
The emdcmp
package
import emdcmp
Proect packages
from config import config
import utils
import viz
import viz.emdcmp
from Ex_UV import (
Bunits, Dataset, Q, gaussian_noise, CandidateModel,
L_med, data_T, data_λ_min, data_λ_max, data_noise_s,
EpistemicDistBiasSweep,
c_chosen
)
import task_bq
Visualization
import holoviews as hv
sanitize = hv.core.util.sanitize_identifier_fn
hv.extension("matplotlib")
Define the epistemic distribution#
#c_list = [2**-3, 2**-2, 2**-1, 2**0, 2**1]
c_list = [2**-15, 2**-12, 2**-9, 2**-6, 2**-3, 2**0, 2**3, 2**6]
#N = 64
#N = 256
N = 4096
Ω = EpistemicDistBiasSweep()
Setup two tasks with the same distribution: one using \(\Bemd{}\), the other using \(\BQ{}\)
Note
\(\BQ{}\) is an alternative criterion we consider in our supplementary. In the paper we use \(\BQ{}\) plots from the neuron model to illustrate how it differs from the \(\Bemd{}\), but as we show below, the same exercise can also be done with the black body radiation models.
task = emdcmp.tasks.Calibrate(
reason = "UV calibration – RJ vs Plank – bias sweep",
c_list = c_list,
#c_list = [c_chosen],
experiments = Ω.generate(N),
Ldata = 1024,
Linf = 12288
)
Show code cell source
task_BQ = task_bq.CalibrateBQ(
reason = "UV calibration – RJ vs Plank – bias sweep",
#c_list = [-2**1, -2**0, -2**-1, -2**-2, -2**-3, -2**-4, 0, 2**-4, 2**-3, 2**-2, 2**-1, 2**0, 2**1],
c_list = c_list,
experiments = Ω.generate(N),
Ldata = 1024,
Linf = 12288,
LQ = 4000
)
Run the calibration tasks#
Hint
If the tasks have not been run yet, they will refuse to run unless the notebook repository is clean. This is to ensure the results cached to disk are reproducible.
task.run(cache=True)
task_BQ.run(cache=True);
calib_results = task.unpack_results(task.run(cache=True))
calib_results_BQ = task_BQ.unpack_results(task_BQ.run(cache=True))
Plot the results#
The emdcmp
provides a plotting function under emdcmp.viz.calibration_plot
.
calib_normal = viz.emdcmp.calibration_plot(calib_results, target_bin_size=32)
task_bq.calib_point_dtype.names = ("Bemd", "Bconf") # Hack to relabel fields in the way calibration_plot expects them
calib_BQ = viz.emdcmp.calibration_plot(calib_results_BQ, target_bin_size=32)
task_bq.calib_point_dtype.names = ("BQ", "Bepis")
The object itself will render as a plot, but it actually provides a few different methods to plot the data in different ways. In particular, the different Holoviews plot elements can be accessed individually, so that users can compose their plots in the way that suits them.
Show code cell source
# CalibrationPlotElements doesn’t use LaTeX labels by default, because they aren’t supported by Bokeh
# It also doesn’t know that one of the plots is BQ instead of Bemd, so we also use `redim` to fix that
calib_normal = calib_normal.redim(Bemd =hv.Dimension("Bemd" , label="$B^{\\mathrm{EMD}}$"),
Bepis=hv.Dimension("Bepis", label="$B^{\\mathrm{epis}}$"))
calib_BQ = calib_BQ.redim(Bemd =hv.Dimension("BQ" , label="$B^Q$"),
Bepis=hv.Dimension("Bepis", label="$B^{\\mathrm{epis}}$"))
Show code cell source
fig = calib_normal.overlayed_scatters + calib_BQ.overlayed_scatters.redim(c="c_Q", Bemd="BQ")
fig
Show code cell source
(calib_normal.scatters + calib_BQ.scatters).opts(
fig_inches=2, sublabel_format="", show_title=False)
Show code cell source
calibopts = (
hv.opts.Overlay(backend="matplotlib",
#legend_cols=3,
#legend_opts={"columnspacing": .5, "alignment": "center",
# "loc": "upper center"},
#hooks=[partial(viz.despine_hook(), left=False)],
#fig_inches=config.figures.defaults.fig_inches,
aspect=1, fontscale=1.3),
hv.opts.Scatter(backend="matplotlib", s=20),
hv.opts.Layout(sublabel_format=""),
hv.opts.Layout(backend="matplotlib", hspace=0.1, vspace=0.05,
fig_inches=0.65*config.figures.defaults.fig_inches)
)
left = calib_normal.select(c=[2**-15, 2**-12])
middle = calib_normal.select(c=[2**-9, 2**-6, 2**-3])
right = calib_normal.select(c=[2**0, 2**3, 2**6])
Show code cell source
left.scatter_palette = hv.Palette("copper", range=(0., .7))
_curves = middle.calibration_curves
_curves.data = {k:_curves.data[k] for k in reversed(sorted(_curves.data))}
middle.scatter_palette = hv.Palette("copper", range=(0, .9), reverse=True) # Keep the order of colours the same: dark = smaller
_curves = right.calibration_curves
_curves.data = {k:_curves.data[k] for k in reversed(sorted(_curves.data))}
right.scatter_palette = hv.Palette("copper", range=(0, .9), reverse=True)
Show code cell source
hooks = [viz.despine_hook, viz.set_xticks_hook([0, 0.5, 1]), viz.set_yticks_hook([0, 0.5, 1]),
viz.set_xticklabels_hook(["$0$", "$0.5$", "$1$"])]
left_hooks = hooks + [viz.set_yticklabels_hook(["$0$", "$0.5$", "$1$"])]
middle_hooks = hooks + [viz.yaxis_off_hook]
right_hooks = hooks + [viz.yaxis_off_hook]
Show code cell source
fig = left.overlayed_scatters.opts(hooks=left_hooks, xlabel="") \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[-15]}", s=30)) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[-12]}", s=16)) \
+ middle.overlayed_scatters.opts(hooks=middle_hooks) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[-9]}", s=18)) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[-6]}", s=18)) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[-3]}", s=24)) \
+ right.overlayed_scatters.opts(hooks=right_hooks, xlabel="") \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[6]}", s=24)) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[3]}", s=14)) \
.opts(hv.opts.Scatter(f"Scatter.{san_labels[0]}", s=12))
fig.opts(*calibopts,
hv.opts.Overlay(xlim=(-0.05, 1.05), # Make space so the dots at edges are fully plotted
legend_position="top_left",
legend_labels={lbl: f"$c=2^{{{p}}}$" for p, lbl in labels.items()}),
)
Compute comparison tables for each \(c\) value#
Show code cell source
import math
import itertools
from addict import Dict
import emdcmp
from Ex_UV import synth_ppf, mixed_ppf
import holoviews as hv
hv.extension("matplotlib")
Draw sets of R samples for each value of \(c\).
c_list = [2**-15, 2**-12, 2**-9, 2**-6, 2**-3, 2**0, 2**3, 2**6]
def draw_R_samples(c_a):
c, a = c_a
return c, a, emdcmp.draw_R_samples(mixed_ppf[a], synth_ppf[a], c=c)
with mp.Pool(4) as pool:
R_samples_flat = pool.map(draw_R_samples,
itertools.product(c_list, synth_ppf.keys()))
R_samples = {c: Dict() for c in c_list}
for c, a, Rsamp in R_samples_flat:
R_samples[c][a] = Rsamp
Show code cell source
hm = hv.HoloMap({int(round(math.log2(c))): hv.Table(emdcmp.utils.compare_matrix(R_samples[c]).reset_index().rename(columns={"index": "models"}))
for c in c_list},
kdims=["log2(c)"])
hm
2025-07-14 git: emd-paper main #05b68aa4
emdcmp : 1.1.0