<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN"
                  "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
<front>
<journal-meta>
<journal-id journal-id-type="publisher-id">jrepstat</journal-id>
<journal-title-group>
<journal-title>Journal of Reproducible Statistics</journal-title>
</journal-title-group>
<publisher>
<publisher-name>FAIR Press</publisher-name>
</publisher>
</journal-meta>
<article-meta>
<title-group>
<article-title>corrscore: Matrix-Aware Proper Scoring Rules and Significance Testing for Correlation and Covariance Forecasts in Python</article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author">
<contrib-id contrib-id-type="orcid">https://orcid.org/0009-0002-8227-5560</contrib-id>
<name>
<surname>Nguyen</surname>
<given-names>Vinh</given-names>
</name>
<aff>Independent Researcher</aff>
</contrib>
</contrib-group>
<pub-date date-type="pub" publication-format="electronic">
<year>2026</year>
</pub-date>
<volume>1</volume>
<elocation-id>3</elocation-id>
<history>
<date date-type="received" iso-8601-date="2026-09-17"><day>17</day><month>09</month><year>2026</year></date>
<date date-type="accepted" iso-8601-date="2026-10-04"><day>04</day><month>10</month><year>2026</year></date>
</history>
<permissions>
<license license-type="open-access" xlink:href="https://creativecommons.org/licenses/by/4.0/">
<license-p>This is an open access article distributed under the terms of the Creative Commons Attribution 4.0 International License (CC-BY 4.0), which permits unrestricted use, distribution and reproduction in any medium provided the original work is properly cited.</license-p>
</license>
</permissions>
<self-uri content-type="html" xlink:href="https://jrepstat.fairpressjournals.com/articles/corrscore-matrix-aware-proper-scoring-rules-and-significance-testing-for-correlation-and-covariance-forecasts-in-python/"/>
<abstract>
<p>Forecasting a correlation or covariance matrix is common in risk management and portfolio construction, but evaluating such a forecast correctly is not routine: naive matrix-comparison metrics are not proper scoring rules, walk-forward evaluation windows are easy to overlap with the estimation window in ways that silently leak information, and significance testing on serially dependent forecast-error sequences needs machinery few analysts implement from scratch. corrscore is a Python package that provides matrix-aware implementations of two established proper scoring rules for this setting -- the energy score and the variogram score -- dispatched across a closed-form tractability spectrum. The energy score is exact for point, discrete-mixture, and isotropic-Gaussian-mixture forecasts, and the variogram score is exact for point and discrete-mixture forecasts. A general Monte Carlo ensemble, and the variogram score of an isotropic-Gaussian mixture, fall back to sampling. The package also provides a geometry-aware variant of the variogram score built from the affine-invariant distance on the correlation manifold, a zero-overlap-by-construction walk-forward backtest harness, and a bundled significance-testing suite (circular block bootstrap, the Diebold-Mariano test, and the Model Confidence Set). We describe the package's design, its point of departure from the existing scoringRules and properscoring packages, and walk through a complete worked example.</p>
</abstract>
<kwd-group kwd-group-type="author">
<kwd>proper scoring rules</kwd>
<kwd>energy score</kwd>
<kwd>variogram score</kwd>
<kwd>correlation matrix</kwd>
<kwd>forecast evaluation</kwd>
<kwd>backtesting</kwd>
</kwd-group>
<custom-meta-group>
<custom-meta>
<meta-name>data-availability-route</meta-name>
<meta-value>open</meta-value>
</custom-meta>
<custom-meta>
<meta-name>founding-article</meta-name>
<meta-value>true</meta-value>
</custom-meta>
</custom-meta-group>
</article-meta>
</front>
<body>
<p><bold>Keywords</bold>: proper scoring rules, energy score, variogram
score, correlation matrix, forecast evaluation, backtesting,
<named-content content-type="sans-serif">Python</named-content>.</p>
<sec id="secU003Aintro">
  <title>Introduction</title>
  <p>A correlation or covariance matrix forecast is the object at the
  center of most portfolio construction and risk management workflows:
  it feeds mean-variance optimization, value-at-risk estimation, and
  stress testing alike. Yet, compared to forecasting a single number,
  evaluating whether one such forecast is genuinely better than another
  is not something the applied literature has settled tooling for. Three
  specific difficulties recur in practice, each with a known statistical
  fix that is nonetheless rarely implemented correctly from scratch:</p>
  <list list-type="order">
    <list-item>
      <p><bold>Naive matrix-comparison metrics are usually not proper
      scoring rules.</bold> A proper scoring rule is one under which a
      forecaster minimizes their own expected score precisely by
      reporting their true belief (Gneiting &amp; Raftery, 2007); an
      analyst who instead compares forecasts by, say, mean absolute
      entrywise error against a single point estimate has no such
      guarantee, and worse, has no principled way to score a genuinely
      probabilistic (ensemble or mixture) forecast at all. The energy
      score and the variogram score are the two established proper
      scoring rules used for this purpose in the closely related field
      of ensemble weather forecasting (Gneiting &amp; Raftery, 2007;
      Scheuerer &amp; Hamill, 2015), but neither was published with a
      matrix-valued object, or a correlation matrix’s specific structure
      (unit diagonal, boundary at <inline-formula><alternatives>
      <tex-math><![CDATA[\pm 1]]></tex-math>
      <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>±</mml:mi><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>),
      in mind.</p>
    </list-item>
    <list-item>
      <p><bold>Walk-forward evaluation windows are easy to overlap by
      construction.</bold> A backtest that estimates a forecast from
      data up to an origin <inline-formula><alternatives>
      <tex-math><![CDATA[t]]></tex-math>
      <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>t</mml:mi></mml:math></alternatives></inline-formula>,
      then checks it against a “realized” correlation matrix computed
      from a window that reaches back before or across
      <inline-formula><alternatives>
      <tex-math><![CDATA[t]]></tex-math>
      <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>t</mml:mi></mml:math></alternatives></inline-formula>,
      leaks information from the estimation window into the evaluation
      window. This is not a hypothetical failure mode: a window-overlap
      bug of exactly this kind, initially producing the opposite of a
      companion study’s eventual, correctly-measured finding, motivated
      this package’s backtest harness directly
      (Section <xref alt="4" rid="secU003Abacktest">4</xref>).</p>
    </list-item>
    <list-item>
      <p><bold>Per-origin forecast scores are serially dependent, and
      testing them like i.i.d. data overstates significance.</bold> A
      walk-forward evaluation over overlapping or adjacent-in-time
      horizons produces a sequence of score differences with genuine
      autocorrelation; a plain paired <inline-formula><alternatives>
      <tex-math><![CDATA[t]]></tex-math>
      <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>t</mml:mi></mml:math></alternatives></inline-formula>-test
      on that sequence understates its true variance. The
      Diebold–Mariano test (Diebold &amp; Mariano, 1995) and a block
      bootstrap (Politis &amp; Romano, 1992) are the standard fixes, and
      comparing more than two candidate models simultaneously needs a
      further correction for the resulting multiple-comparison problem,
      which the Model Confidence Set procedure (Hansen et al., 2011)
      supplies.</p>
    </list-item>
  </list>
  <p><named-content content-type="sans-serif">corrscore</named-content>
  packages matrix-aware implementations of both established scoring
  rules, a new geometry-aware variant of the variogram score, a backtest
  harness that makes the overlap bug in item 2 structurally impossible
  to reproduce, and the three significance-testing tools in item 3, so
  that none of this needs reimplementing per project. The package is
  deliberately narrow: it scores a forecast against a realized outcome
  and tests whether the difference between two or more forecasts’ scores
  is real; it does not fit a forecasting model, and does not fetch or
  clean market data.</p>
  <p>The remainder of this paper is organized as follows.
  Section <xref alt="2" rid="secU003Abackground">2</xref> gives the
  minimal proper-scoring-rule background needed to read the rest of the
  paper. Section <xref alt="3" rid="secU003Ascores">3</xref> describes
  the score implementations, including the closed-form tractability
  spectrum and the geometric variogram score.
  Section <xref alt="4" rid="secU003Abacktest">4</xref> describes the
  backtest harness and the significance-testing suite.
  Section <xref alt="5" rid="secU003Aexample">5</xref> works through a
  complete example. Section <xref alt="6" rid="secU003Arelated">6</xref>
  compares
  <named-content content-type="sans-serif">corrscore</named-content> to
  existing software.
  Section <xref alt="7" rid="secU003Asummary">7</xref> concludes.</p>
</sec>
<sec id="secU003Abackground">
  <title>Background: Proper Scoring Rules for Matrix-Valued
  Forecasts</title>
  <p>Let <inline-formula><alternatives>
  <tex-math><![CDATA[F]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>F</mml:mi></mml:math></alternatives></inline-formula>
  be a predictive distribution over <inline-formula><alternatives>
  <tex-math><![CDATA[K \times K]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>×</mml:mo><mml:mi>K</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
  correlation (or covariance) matrices, and let
  <inline-formula><alternatives>
  <tex-math><![CDATA[y]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>y</mml:mi></mml:math></alternatives></inline-formula>
  be the realized outcome. A scoring rule <inline-formula><alternatives>
  <tex-math><![CDATA[S(F, y)]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>S</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
  is <italic>proper</italic> relative to a class
  <inline-formula><alternatives>
  <tex-math><![CDATA[\mathcal{P}]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi mathvariant="script">𝒫</mml:mi></mml:math></alternatives></inline-formula>
  of forecast distributions if, for <inline-formula><alternatives>
  <tex-math><![CDATA[Y \sim G]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>Y</mml:mi><mml:mo>∼</mml:mo><mml:mi>G</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>,
  <inline-formula><alternatives>
  <tex-math><![CDATA[\mathsf{E}_G[S(G, Y)] \le \mathsf{E}_G[S(F, Y)]]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>G</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">[</mml:mo><mml:mi>S</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>G</mml:mi><mml:mo>,</mml:mo><mml:mi>Y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo stretchy="false" form="postfix">]</mml:mo><mml:mo>≤</mml:mo><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>G</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">[</mml:mo><mml:mi>S</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>Y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo stretchy="false" form="postfix">]</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
  for all <inline-formula><alternatives>
  <tex-math><![CDATA[F, G \in \mathcal{P}]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>G</mml:mi><mml:mo>∈</mml:mo><mml:mi mathvariant="script">𝒫</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
  (Gneiting &amp; Raftery, 2007): the forecaster who reports their own
  true belief <inline-formula><alternatives>
  <tex-math><![CDATA[G]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>G</mml:mi></mml:math></alternatives></inline-formula>
  never does worse, in expectation, than one who reports anything else.
  Both scores implemented here are instances of the general
  <italic>energy-distance</italic> recipe,
  <styled-content id="eqU003Aenergydistance"><disp-formula><alternatives>
  <tex-math><![CDATA[\begin{equation}
    S_\psi(F, y) \;=\; \mathsf{E}_F[\psi(X, y)] \;-\; \tfrac{1}{2}\,\mathsf{E}_F[\psi(X, X')], \qquad
    X, X' \overset{\text{iid}}{\sim} F, \label{eq:energydistance}
  \end{equation} \qquad(1)]]></tex-math>
  <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mrow><mml:msub><mml:mi>S</mml:mi><mml:mi>ψ</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mo>=</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">[</mml:mo><mml:mi>ψ</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>X</mml:mi><mml:mo>,</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo stretchy="false" form="postfix">]</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mo>−</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mstyle displaystyle="false"><mml:mfrac><mml:mn>1</mml:mn><mml:mn>2</mml:mn></mml:mfrac></mml:mstyle><mml:mspace width="0.167em"></mml:mspace><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">[</mml:mo><mml:mi>ψ</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>X</mml:mi><mml:mo>,</mml:mo><mml:msup><mml:mi>X</mml:mi><mml:mo>′</mml:mo></mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo stretchy="false" form="postfix">]</mml:mo><mml:mo>,</mml:mo><mml:mspace width="2.0em"></mml:mspace><mml:mi>X</mml:mi><mml:mo>,</mml:mo><mml:msup><mml:mi>X</mml:mi><mml:mo>′</mml:mo></mml:msup><mml:mover><mml:mo>∼</mml:mo><mml:mtext mathvariant="normal">iid</mml:mtext></mml:mover><mml:mi>F</mml:mi><mml:mo>,</mml:mo></mml:mrow><mml:mspace width="2.0em"></mml:mspace><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></disp-formula></styled-content>
  which is proper whenever the kernel <inline-formula><alternatives>
  <tex-math><![CDATA[\psi]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ψ</mml:mi></mml:math></alternatives></inline-formula>
  is <italic>conditionally negative definite</italic> (Gneiting &amp;
  Raftery, 2007; Székely &amp; Rizzo, 2013). Setting
  <inline-formula><alternatives>
  <tex-math><![CDATA[\psi]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ψ</mml:mi></mml:math></alternatives></inline-formula>
  to the Frobenius distance between two matrices gives the
  <italic>energy score</italic>; the <italic>variogram score</italic>
  instead scores a vector of pairwise absolute differences directly
  (Section <xref alt="3.3" rid="secU003Avs">3.3</xref>) and is proper by
  a separate, simpler argument that does not require the
  conditional-negative-definiteness condition at all. A companion paper
  (Nguyen, 2026) gives the complete propriety proofs, including for the
  geometric variant of
  Section <xref alt="3.4" rid="secU003Ageovs">3.4</xref>; this paper
  describes the software, not the underlying theory, and cites that
  proof rather than repeating it.</p>
</sec>
<sec id="secU003Ascores">
  <title>Score Definitions and the Closed-Form Tractability
  Spectrum</title>
  <sec id="secU003Aforecastrep">
    <title>Forecast representation</title>
    <p>Every score in
    <named-content content-type="sans-serif">corrscore</named-content>
    takes a forecast as a plain <monospace>dict</monospace> tagged by a
    <monospace>&quot;kind&quot;</monospace> key, rather than a class
    hierarchy, so that a caller’s own forecasting code needs no
    dependency on the package beyond producing this shape:</p>
    <preformat>{&quot;kind&quot;: &quot;point&quot;, &quot;Q&quot;: Q}
{&quot;kind&quot;: &quot;mixture&quot;, &quot;components&quot;: [(p_1, Q_1), ..., (p_J, Q_J)]}
{&quot;kind&quot;: &quot;isotropic_gaussian_mixture&quot;, &quot;components&quot;: [(p_1, Q_1, sigma_1), ...]}
{&quot;kind&quot;: &quot;ensemble&quot;, &quot;draws&quot;: [Q_1, ..., Q_M]}</preformat>
    <p>These four kinds span a genuine closed-form tractability
    spectrum, not an arbitrary API choice. A
    <monospace>&quot;point&quot;</monospace> forecast is a single
    deterministic matrix (<inline-formula><alternatives>
    <tex-math><![CDATA[M = 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>M</mml:mi><mml:mo>=</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>).
    A <monospace>&quot;mixture&quot;</monospace> is any number of
    discrete atoms with associated probabilities – exactly determined,
    so every expectation in
    Equation <xref alt="(1)" rid="eqU003Aenergydistance">(1)</xref>
    reduces to a finite weighted sum, at <inline-formula><alternatives>
    <tex-math><![CDATA[O(J^2)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>O</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:msup><mml:mi>J</mml:mi><mml:mn>2</mml:mn></mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
    cost, where <inline-formula><alternatives>
    <tex-math><![CDATA[J]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>J</mml:mi></mml:math></alternatives></inline-formula>
    is the number of atoms, with no simulation. An
    <monospace>&quot;isotropic_gaussian_mixture&quot;</monospace> adds
    an isotropic Gaussian scatter around each atom in the
    <inline-formula><alternatives>
    <tex-math><![CDATA[K(K-1)/2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>K</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mi>/</mml:mi><mml:mn>2</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>-dimensional
    space of free (upper-triangle) matrix entries; for the energy score
    this remains exactly computable, via the mean-norm formula for a
    noncentral chi distribution (Johnson et al., 1994), evaluated
    through the confluent hypergeometric function
    <inline-formula><alternatives>
    <tex-math><![CDATA[{}_1F_1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mrow></mml:mrow><mml:mn>1</mml:mn></mml:msub><mml:msub><mml:mi>F</mml:mi><mml:mn>1</mml:mn></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>
    (<monospace>scipy.special.hyp1f1</monospace>) rather than simulated.
    The convention is as follows. A draw is a symmetric, zero-diagonal
    perturbation of an atom: a vector <inline-formula><alternatives>
    <tex-math><![CDATA[u \sim \mathcal{N}(\mu, \sigma^2 I_n)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>u</mml:mi><mml:mo>∼</mml:mo><mml:mi mathvariant="script">𝒩</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>μ</mml:mi><mml:mo>,</mml:mo><mml:msup><mml:mi>σ</mml:mi><mml:mn>2</mml:mn></mml:msup><mml:msub><mml:mi>I</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
    with <inline-formula><alternatives>
    <tex-math><![CDATA[n = K(K-1)/2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mi>K</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>K</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mi>/</mml:mi><mml:mn>2</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>,
    placed into both triangles. The Frobenius norm of such a matrix
    counts each free entry twice, so <inline-formula><alternatives>
    <tex-math><![CDATA[\lVert A \rVert_F = \sqrt{2}\,\lVert u \rVert_2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mrow><mml:mo stretchy="true" form="prefix">‖</mml:mo><mml:mi>A</mml:mi><mml:mo stretchy="true" form="postfix">‖</mml:mo></mml:mrow><mml:mi>F</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msqrt><mml:mn>2</mml:mn></mml:msqrt><mml:mspace width="0.167em"></mml:mspace><mml:msub><mml:mrow><mml:mo stretchy="true" form="prefix">‖</mml:mo><mml:mi>u</mml:mi><mml:mo stretchy="true" form="postfix">‖</mml:mo></mml:mrow><mml:mn>2</mml:mn></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>.
    The noncentral-chi mean is therefore taken with
    <inline-formula><alternatives>
    <tex-math><![CDATA[n]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>n</mml:mi></mml:math></alternatives></inline-formula>
    degrees of freedom and scale <inline-formula><alternatives>
    <tex-math><![CDATA[\sigma]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>σ</mml:mi></mml:math></alternatives></inline-formula>,
    and multiplied by <inline-formula><alternatives>
    <tex-math><![CDATA[\sqrt{2}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:msqrt><mml:mn>2</mml:mn></mml:msqrt></mml:math></alternatives></inline-formula>.
    Because the scatter lives in the free-entry space, a draw need not
    be positive semidefinite or lie in <inline-formula><alternatives>
    <tex-math><![CDATA[[-1, 1]]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mo stretchy="false" form="prefix">[</mml:mo><mml:mi>−</mml:mi><mml:mn>1</mml:mn><mml:mo>,</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">]</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>.
    The forecast is thus a distribution over symmetric matrices that may
    leave the set of valid correlation matrices, and the score remains
    well defined because the realized outcome
    <inline-formula><alternatives>
    <tex-math><![CDATA[y]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>y</mml:mi></mml:math></alternatives></inline-formula>
    is valid. An <monospace>&quot;ensemble&quot;</monospace> is a
    general Monte Carlo draw set with no assumed structure – the only
    kind with no closed form, falling back to the direct
    <inline-formula><alternatives>
    <tex-math><![CDATA[O(M^2)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>O</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:msup><mml:mi>M</mml:mi><mml:mn>2</mml:mn></mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
    pairwise sum in
    Equation <xref alt="(1)" rid="eqU003Aenergydistance">(1)</xref>.</p>
  </sec>
  <sec id="secU003Aes">
    <title>The energy score</title>
    <p><monospace>matrix_energy_score(forecast, y)</monospace>
    implements
    Equation <xref alt="(1)" rid="eqU003Aenergydistance">(1)</xref> with
    <inline-formula><alternatives>
    <tex-math><![CDATA[\psi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ψ</mml:mi></mml:math></alternatives></inline-formula>
    the Frobenius distance between two <inline-formula><alternatives>
    <tex-math><![CDATA[K \times K]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>×</mml:mo><mml:mi>K</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    matrices, dispatched across all four forecast kinds of
    Section <xref alt="3.1" rid="secU003Aforecastrep">3.1</xref>. For a
    <monospace>&quot;point&quot;</monospace> forecast this reduces to
    plain Frobenius distance to the realized outcome
    <inline-formula><alternatives>
    <tex-math><![CDATA[y]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>y</mml:mi></mml:math></alternatives></inline-formula>;
    for a <monospace>&quot;mixture&quot;</monospace> forecast with
    components <inline-formula><alternatives>
    <tex-math><![CDATA[(p_j, Q_j)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:msub><mml:mi>p</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:msub><mml:mi>Q</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[j = 1, \dots, J]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>j</mml:mi><mml:mo>=</mml:mo><mml:mn>1</mml:mn><mml:mo>,</mml:mo><mml:mi>…</mml:mi><mml:mo>,</mml:mo><mml:mi>J</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>,
    <disp-formula><alternatives>
    <tex-math><![CDATA[\begin{equation}
      S_{\text{ES}}(F, y) \;=\; \sum_j p_j \lVert Q_j - y \rVert_F \;-\; \tfrac{1}{2} \sum_{j,l} p_j
      p_l \lVert Q_j - Q_l \rVert_F. \label{eq:esmixture}
    \end{equation}]]></tex-math>
    <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi>S</mml:mi><mml:mtext mathvariant="normal">ES</mml:mtext></mml:msub><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mo>=</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:munder><mml:mo>∑</mml:mo><mml:mi>j</mml:mi></mml:munder><mml:msub><mml:mi>p</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msub><mml:mrow><mml:mo stretchy="true" form="prefix">‖</mml:mo><mml:msub><mml:mi>Q</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="true" form="postfix">‖</mml:mo></mml:mrow><mml:mi>F</mml:mi></mml:msub><mml:mspace width="0.278em"></mml:mspace><mml:mo>−</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mstyle displaystyle="false"><mml:mfrac><mml:mn>1</mml:mn><mml:mn>2</mml:mn></mml:mfrac></mml:mstyle><mml:munder><mml:mo>∑</mml:mo><mml:mrow><mml:mi>j</mml:mi><mml:mo>,</mml:mo><mml:mi>l</mml:mi></mml:mrow></mml:munder><mml:msub><mml:mi>p</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msub><mml:mi>p</mml:mi><mml:mi>l</mml:mi></mml:msub><mml:msub><mml:mrow><mml:mo stretchy="true" form="prefix">‖</mml:mo><mml:msub><mml:mi>Q</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>Q</mml:mi><mml:mi>l</mml:mi></mml:msub><mml:mo stretchy="true" form="postfix">‖</mml:mo></mml:mrow><mml:mi>F</mml:mi></mml:msub><mml:mi>.</mml:mi></mml:mrow></mml:math></alternatives></disp-formula></p>
  </sec>
  <sec id="secU003Avs">
    <title>The variogram score</title>
    <preformat>matrix_variogram_score(forecast, y, p=0.5, weights=None,
                        n_samples=500, random_state=None)</preformat>
    <p>implements the variogram score (Scheuerer &amp; Hamill, 2015),
    <styled-content id="eqU003Avs"><disp-formula><alternatives>
    <tex-math><![CDATA[\begin{equation}
      S_{\text{VS}}(F, y) \;=\; \sum_{i < j} w_{ij} \Big( |y_i - y_j|^p - \mathsf{E}_F|X_i - X_j|^p
      \Big)^2, \label{eq:vs}
    \end{equation} \qquad(2)]]></tex-math>
    <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mrow><mml:msub><mml:mi>S</mml:mi><mml:mtext mathvariant="normal">VS</mml:mtext></mml:msub><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>F</mml:mi><mml:mo>,</mml:mo><mml:mi>y</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mo>=</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:munder><mml:mo>∑</mml:mo><mml:mrow><mml:mi>i</mml:mi><mml:mo>&lt;</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:munder><mml:msub><mml:mi>w</mml:mi><mml:mrow><mml:mi>i</mml:mi><mml:mi>j</mml:mi></mml:mrow></mml:msub><mml:mo minsize="180%" maxsize="180%" stretchy="true" form="prefix">(</mml:mo><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>y</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>y</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup><mml:mo>−</mml:mo><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup><mml:msup><mml:mo minsize="180%" maxsize="180%" stretchy="true" form="postfix">)</mml:mo><mml:mn>2</mml:mn></mml:msup><mml:mo>,</mml:mo></mml:mrow><mml:mspace width="2.0em"></mml:mspace><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mn>2</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></disp-formula></styled-content>
    adapted to index <inline-formula><alternatives>
    <tex-math><![CDATA[i, j]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>i</mml:mi><mml:mo>,</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    over the <inline-formula><alternatives>
    <tex-math><![CDATA[K(K-1)/2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>K</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mi>/</mml:mi><mml:mn>2</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    free upper-triangle entries of the correlation matrix, rather than
    over the original <inline-formula><alternatives>
    <tex-math><![CDATA[K]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>K</mml:mi></mml:math></alternatives></inline-formula>-vector
    the published formula was defined for: the diagonal (always exactly
    <inline-formula><alternatives>
    <tex-math><![CDATA[1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>1</mml:mn></mml:math></alternatives></inline-formula>
    for a correlation matrix) and the mirrored lower triangle both carry
    no information and are excluded. <monospace>p</monospace> defaults
    to <inline-formula><alternatives>
    <tex-math><![CDATA[0.5]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.5</mml:mn></mml:math></alternatives></inline-formula>,
    matching Scheuerer &amp; Hamill (2015)’s own recommended default;
    <monospace>weights</monospace> defaults to uniform. The score is
    exact (no sampling) for <monospace>&quot;point&quot;</monospace> and
    <monospace>&quot;mixture&quot;</monospace> forecasts, since both are
    fully determined by a finite set of deterministic atoms. For
    <monospace>&quot;ensemble&quot;</monospace> and
    <monospace>&quot;isotropic_gaussian_mixture&quot;</monospace>
    forecasts, <inline-formula><alternatives>
    <tex-math><![CDATA[\mathsf{E}_F|X_i - X_j|^p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup></mml:mrow></mml:math></alternatives></inline-formula>
    has no known closed form for general <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>
    and is instead estimated by Monte Carlo with
    <monospace>n_samples</monospace> draws (default
    <inline-formula><alternatives>
    <tex-math><![CDATA[500]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>500</mml:mn></mml:math></alternatives></inline-formula>);
    cost and memory scale as <inline-formula><alternatives>
    <tex-math><![CDATA[O(n_{\text{samples}} \times K^2(K-1)^2/4)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>O</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:msub><mml:mi>n</mml:mi><mml:mtext mathvariant="normal">samples</mml:mtext></mml:msub><mml:mo>×</mml:mo><mml:msup><mml:mi>K</mml:mi><mml:mn>2</mml:mn></mml:msup><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>K</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn><mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mn>2</mml:mn></mml:msup><mml:mi>/</mml:mi><mml:mn>4</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>,
    which the default keeps modest through
    <inline-formula><alternatives>
    <tex-math><![CDATA[K = 16]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>=</mml:mo><mml:mn>16</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>.</p>
    <p>The Monte Carlo path is slightly biased upward.
    Equation <xref alt="(2)" rid="eqU003Avs">(2)</xref> squares a
    residual that contains the estimated <inline-formula><alternatives>
    <tex-math><![CDATA[\mathsf{E}_F|X_i - X_j|^p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi mathvariant="sans-serif">𝖤</mml:mi><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup></mml:mrow></mml:math></alternatives></inline-formula>,
    and squaring a noisy estimate adds its variance, so the expected
    Monte Carlo score exceeds the exact one by
    <inline-formula><alternatives>
    <tex-math><![CDATA[\sum_{i<j} w_{ij}\,\mathrm{Var}_F(|X_i - X_j|^p)/M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mo>∑</mml:mo><mml:mrow><mml:mi>i</mml:mi><mml:mo>&lt;</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:msub><mml:msub><mml:mi>w</mml:mi><mml:mrow><mml:mi>i</mml:mi><mml:mi>j</mml:mi></mml:mrow></mml:msub><mml:mspace width="0.167em"></mml:mspace><mml:msub><mml:mrow><mml:mi mathvariant="normal">V</mml:mi><mml:mi mathvariant="normal">a</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:mrow><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mi>/</mml:mi><mml:mi>M</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>,
    where <inline-formula><alternatives>
    <tex-math><![CDATA[M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>M</mml:mi></mml:math></alternatives></inline-formula>
    is the number of draws (<monospace>n_samples</monospace>, or the
    ensemble size for an <monospace>&quot;ensemble&quot;</monospace>
    forecast). This is always nonnegative and shrinks as
    <inline-formula><alternatives>
    <tex-math><![CDATA[1/M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>1</mml:mn><mml:mi>/</mml:mi><mml:mi>M</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>.
    For an outcome drawn from the forecast itself, the exact expected
    score equals <inline-formula><alternatives>
    <tex-math><![CDATA[\sum_{i<j} w_{ij}\,\mathrm{Var}_F(|X_i - X_j|^p)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mo>∑</mml:mo><mml:mrow><mml:mi>i</mml:mi><mml:mo>&lt;</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:msub><mml:msub><mml:mi>w</mml:mi><mml:mrow><mml:mi>i</mml:mi><mml:mi>j</mml:mi></mml:mrow></mml:msub><mml:mspace width="0.167em"></mml:mspace><mml:msub><mml:mrow><mml:mi mathvariant="normal">V</mml:mi><mml:mi mathvariant="normal">a</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:mrow><mml:mi>F</mml:mi></mml:msub><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>X</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msup><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>p</mml:mi></mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>,
    so the relative inflation is <inline-formula><alternatives>
    <tex-math><![CDATA[1/M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>1</mml:mn><mml:mi>/</mml:mi><mml:mi>M</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>,
    or <inline-formula><alternatives>
    <tex-math><![CDATA[0.2\%]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>0.2</mml:mn><mml:mi>%</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    at the default <inline-formula><alternatives>
    <tex-math><![CDATA[M = 500]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>M</mml:mi><mml:mo>=</mml:mo><mml:mn>500</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>.
    A simulation with <inline-formula><alternatives>
    <tex-math><![CDATA[K = 4]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    and an isotropic Gaussian mixture matched this to within Monte Carlo
    error at <inline-formula><alternatives>
    <tex-math><![CDATA[M = 50]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>M</mml:mi><mml:mo>=</mml:mo><mml:mn>50</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    to <inline-formula><alternatives>
    <tex-math><![CDATA[2000]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>2000</mml:mn></mml:math></alternatives></inline-formula>.
    The bias is negligible against typical score gaps, but it tilts a
    backtest that compares a Monte Carlo–scored forecast against a
    closed-form one (<monospace>&quot;point&quot;</monospace> or
    <monospace>&quot;mixture&quot;</monospace>) against the former. When
    the forecasts being compared differ by less than about
    <inline-formula><alternatives>
    <tex-math><![CDATA[1/M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>1</mml:mn><mml:mi>/</mml:mi><mml:mi>M</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    in relative score, give every candidate the same kind or raise
    <inline-formula><alternatives>
    <tex-math><![CDATA[M]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>M</mml:mi></mml:math></alternatives></inline-formula>.</p>
  </sec>
  <sec id="secU003Ageovs">
    <title>A geometric variogram score</title>
    <p>A correlation matrix is constrained to a curved region (the
    <italic>elliptope</italic>), not an ordinary Euclidean cube, and
    that constraint becomes increasingly binding as any entry approaches
    <inline-formula><alternatives>
    <tex-math><![CDATA[\pm 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>±</mml:mi><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>.
    Pinson &amp; Tastu (2013) show the energy score is close to blind to
    this kind of boundary-proximate danger for Gaussian forecasts;
    Nguyen (2026) shows the flat variogram score of
    Section <xref alt="3.3" rid="secU003Avs">3.3</xref> inherits a
    related blind spot – its concave power transform saturates once two
    entries are already far apart, which is exactly what happens near
    the boundary. A second, unrelated blind spot follows directly from
    Equation <xref alt="(2)" rid="eqU003Avs">(2)</xref>’s reindexing
    over free entries: because the score is built entirely from
    differences between entries, it is exactly invariant to a uniform
    shift in the overall level of correlation – a forecast that is
    systematically biased high or low by the same amount across every
    pair scores identically to one that is not, since only the relative
    structure across pairs, never the shared level, is compared. Nguyen
    (2026) derives a fix for the saturation blind spot:
    <monospace>matrix_geodesic_variogram_score</monospace> runs the
    identical machinery of
    Equation <xref alt="(2)" rid="eqU003Avs">(2)</xref>, but with every
    free entry <inline-formula><alternatives>
    <tex-math><![CDATA[\rho]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ρ</mml:mi></mml:math></alternatives></inline-formula>
    first passed through <disp-formula><alternatives>
    <tex-math><![CDATA[\begin{equation}
      \phi(\rho) \;=\; \operatorname{sign}(\rho) \sqrt{\tfrac{1}{2} \Big[ \log(1+|\rho|)^2 +
      \log(1-|\rho|)^2 \Big]}, \label{eq:phi}
    \end{equation}]]></tex-math>
    <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>ϕ</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mo>=</mml:mo><mml:mspace width="0.278em"></mml:mspace><mml:mrow><mml:mi mathvariant="normal">sign</mml:mi><mml:mo>&#8289;</mml:mo></mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:msqrt><mml:mrow><mml:mstyle displaystyle="false"><mml:mfrac><mml:mn>1</mml:mn><mml:mn>2</mml:mn></mml:mfrac></mml:mstyle><mml:mo minsize="180%" maxsize="180%" stretchy="true" form="prefix">[</mml:mo><mml:mrow><mml:mi mathvariant="normal">log</mml:mi><mml:mo>&#8289;</mml:mo></mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mn>1</mml:mn><mml:mo>+</mml:mo><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mn>2</mml:mn></mml:msup><mml:mo>+</mml:mo><mml:mrow><mml:mi mathvariant="normal">log</mml:mi><mml:mo>&#8289;</mml:mo></mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mn>1</mml:mn><mml:mo>−</mml:mo><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="prefix">|</mml:mo><mml:msup><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mn>2</mml:mn></mml:msup><mml:mo minsize="180%" maxsize="180%" stretchy="true" form="postfix">]</mml:mo></mml:mrow></mml:msqrt><mml:mo>,</mml:mo></mml:mrow></mml:math></alternatives></disp-formula>
    the signed affine-invariant (Fisher–Rao) geodesic distance from
    independence, treating each entry as its own isolated
    <inline-formula><alternatives>
    <tex-math><![CDATA[2 \times 2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>2</mml:mn><mml:mo>×</mml:mo><mml:mn>2</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    correlation matrix. <inline-formula><alternatives>
    <tex-math><![CDATA[\phi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ϕ</mml:mi></mml:math></alternatives></inline-formula>
    is smooth, odd, and strictly increasing on
    <inline-formula><alternatives>
    <tex-math><![CDATA[(-1, 1) \to \mathbb{R}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>−</mml:mi><mml:mn>1</mml:mn><mml:mo>,</mml:mo><mml:mn>1</mml:mn><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>→</mml:mo><mml:mi mathvariant="double-struck">ℝ</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>,
    and stretches the scale specifically near
    <inline-formula><alternatives>
    <tex-math><![CDATA[\pm 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>±</mml:mi><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    where the untransformed score has already saturated – a close cousin
    of the century-old Fisher <inline-formula><alternatives>
    <tex-math><![CDATA[z]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>z</mml:mi></mml:math></alternatives></inline-formula>-transform
    <inline-formula><alternatives>
    <tex-math><![CDATA[\operatorname{arctanh}(\rho)]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mrow><mml:mi mathvariant="normal">arctanh</mml:mi><mml:mo>&#8289;</mml:mo></mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>.
    Both diverge logarithmically as <inline-formula><alternatives>
    <tex-math><![CDATA[\rho \to \pm 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>ρ</mml:mi><mml:mo>→</mml:mo><mml:mi>±</mml:mi><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>,
    at the same order: <inline-formula><alternatives>
    <tex-math><![CDATA[\phi(\rho)/\operatorname{arctanh}(\rho) \to \sqrt{2}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>ϕ</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mi>/</mml:mi><mml:mrow><mml:mi mathvariant="normal">arctanh</mml:mi><mml:mo>&#8289;</mml:mo></mml:mrow><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>ρ</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>→</mml:mo><mml:msqrt><mml:mn>2</mml:mn></mml:msqrt></mml:mrow></mml:math></alternatives></inline-formula>.
    Because <inline-formula><alternatives>
    <tex-math><![CDATA[\phi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ϕ</mml:mi></mml:math></alternatives></inline-formula>
    is nonlinear, <monospace>matrix_geodesic_variogram_score</monospace>
    does not leave the level-shift blind spot above fully intact either,
    but the repair is asymmetric: it is strongest for a shift that
    pushes correlations further from independence, where
    <inline-formula><alternatives>
    <tex-math><![CDATA[\phi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ϕ</mml:mi></mml:math></alternatives></inline-formula>’s
    slope is steepest, and weakest for one that pulls them toward
    independence, where <inline-formula><alternatives>
    <tex-math><![CDATA[\phi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ϕ</mml:mi></mml:math></alternatives></inline-formula>
    is nearly linear and the flat score’s exact invariance is closely
    approximated. Because
    Equation <xref alt="(2)" rid="eqU003Avs">(2)</xref>’s propriety
    argument holds for <italic>any</italic> fixed measurable per-entry
    transform, not only ones with a metric interpretation (Nguyen,
    2026), <monospace>matrix_geodesic_variogram_score</monospace> needs
    no separate propriety proof: it is
    <monospace>matrix_variogram_score</monospace> itself, unmodified,
    called on <inline-formula><alternatives>
    <tex-math><![CDATA[\phi]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>ϕ</mml:mi></mml:math></alternatives></inline-formula>-transformed
    entries, and shares that function’s exact/Monte-Carlo split by
    forecast kind and its
    <monospace>p</monospace>/<monospace>weights</monospace>/
    <monospace>n_samples</monospace> semantics. Nguyen (2026) validates
    this construction on real, walk-forward regime-switching correlation
    forecasts. The geometric variant’s advantage over the flat variogram
    score is real but conditional: it is concentrated in market episodes
    where the realized correlation genuinely approaches the boundary,
    and is not present uniformly across an unconditional average. We
    report this precisely rather than claim an unconditional
    improvement. For the full propriety proof, the open questions it
    leaves, and the complete empirical picture, we refer the reader to
    that paper. One such open question is that a companion geometric
    energy score does not, to date, demonstrate a comparable real-data
    advantage.</p>
  </sec>
  <sec id="secU003Achoosing">
    <title>Choosing between the scores</title>
    <p>All three scores are proper, so none rewards a dishonest
    forecast, but they penalize different errors, and the choice should
    follow what the evaluation is meant to catch. The energy score
    compares whole matrices through the Frobenius distance, so it is
    sensitive to the overall level of correlation: a forecast biased
    uniformly high or low is penalized. It is the natural choice when
    the level itself matters, as in a risk forecast that should not be
    systematically too optimistic, and it is the only one of the three
    with an exact form for an isotropic Gaussian mixture
    (Section <xref alt="3.1" rid="secU003Aforecastrep">3.1</xref>). The
    flat variogram score compares differences between entries, so it is
    built to judge the relative structure across pairs and is exactly
    blind to a uniform shift in level
    (Section <xref alt="3.4" rid="secU003Ageovs">3.4</xref>). It suits a
    question about which pairs move together more than others, and it
    should not be used alone where a common bias would matter. The
    geometric variogram score keeps that focus on relative structure and
    corrects the flat score’s saturation near the boundary, so it is the
    better candidate when forecasts are compared during episodes where
    correlations approach <inline-formula><alternatives>
    <tex-math><![CDATA[\pm 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>±</mml:mi><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>.
    Its advantage there is conditional (Nguyen, 2026), and it only
    partly repairs the level-shift blind spot. Because the scores answer
    different questions, a backtest that reports the energy score
    alongside one variogram score is more informative than either alone,
    and a disagreement between them is itself a finding about where a
    forecast is wrong. Where a forecast has to be scored by sampling,
    the variogram scores’ small upward bias
    (Section <xref alt="3.3" rid="secU003Avs">3.3</xref>) is a further
    reason to compare candidates of the same forecast kind.</p>
  </sec>
</sec>
<sec id="secU003Abacktest">
  <title>Backtesting and Significance Testing</title>
  <sec id="secU003Azerooverlap">
    <title>The zero-overlap backtest harness</title>
    <p><monospace>backtest_zero_overlap</monospace> runs a walk-forward
    evaluation across a sequence of forecast origins and scores one or
    more named forecasting methods against a shared, model-independent
    ground truth:</p>
    <preformat>backtest_zero_overlap(forecast_fns, ground_truth_fn, origins, horizon,
                       purge_gap=0, score_fn=matrix_energy_score,
                       severity_fn=None)</preformat>
    <p>For each <monospace>origin</monospace> in
    <monospace>origins</monospace>, the harness computes ground truth
    from a window starting strictly after the origin:</p>
    <preformat>y = ground_truth_fn(origin + 1 + purge_gap,
                     origin + 1 + purge_gap + horizon)</preformat>
    <p>then scores every
    <monospace>forecast_fns[name](origin)</monospace> against that same
    <monospace>y</monospace>. The specific design choice worth calling
    out is what the harness <italic>cannot</italic> and does not attempt
    to police: how much history a caller’s own
    <monospace>forecast_fn</monospace> consults internally is opaque to
    it (a full-history discounted filter and a short trailing window are
    both permitted), exactly the same responsibility boundary
    <named-content content-type="sans-serif">scikit-learn</named-content>’s
    <monospace>TimeSeriesSplit</monospace> leaves to its own caller.
    What the harness <italic>does</italic> enforce, unconditionally and
    by construction, is that <monospace>ground_truth_fn</monospace> is
    only ever called with a start point strictly after the origin. This
    specific guarantee exists because of a real bug. An earlier
    walk-forward evaluation, in the companion regime-switching
    correlation study this package grew out of, computed “realized”
    ground truth from a window <italic>ending</italic> near the forecast
    origin, not one <italic>starting</italic> strictly after it. That
    silently leaked information back into the evaluation. It made a
    naive persistence forecast look decisively better than a genuine
    forecasting model, the opposite of the study’s eventual,
    correctly-measured finding.
    <monospace>backtest_zero_overlap</monospace>’s API makes that
    specific mistake structurally impossible to reproduce: the caller
    never controls, and never sees, the start point passed to
    <monospace>ground_truth_fn</monospace>.</p>
    <p>One cost of this design deserves stating. The realized outcome
    that <monospace>ground_truth_fn</monospace> returns is itself a
    windowed sample estimate of the correlation, not the true
    correlation, so it carries its own sampling error, which is larger
    the shorter the <monospace>horizon</monospace>. Scoring-rule theory
    treats the outcome as a draw from the true law, whereas here that
    estimation error is added to the forecast’s own error and enters
    every reported score. It also adds noise to the per-origin score
    differences, so a short horizon calls for more origins before two
    forecasts can be separated. The <monospace>horizon=10</monospace>
    window of <inline-formula><alternatives>
    <tex-math><![CDATA[K = 4]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    series in Section <xref alt="5" rid="secU003Aexample">5</xref> is
    short in exactly this sense.</p>
  </sec>
  <sec id="secU003Asigtest">
    <title>Significance testing</title>
    <p>Three complementary significance tests operate on the per-origin
    score arrays a <monospace>BacktestResult</monospace> returns.</p>
    <preformat>circular_block_bootstrap(scores_a, scores_b, block_lengths,
                          n_boot=2000, seed=None)</preformat>
    <p>runs a percentile circular block bootstrap (Politis &amp; Romano,
    1992) on the paired differential <inline-formula><alternatives>
    <tex-math><![CDATA[d_i = a_i - b_i]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi>d</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msub><mml:mi>a</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>−</mml:mo><mml:msub><mml:mi>b</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>,
    where <inline-formula><alternatives>
    <tex-math><![CDATA[a_i, b_i]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:msub><mml:mi>a</mml:mi><mml:mi>i</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:msub><mml:mi>b</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>
    are the <inline-formula><alternatives>
    <tex-math><![CDATA[i]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>i</mml:mi></mml:math></alternatives></inline-formula>th
    entries of <monospace>scores_a</monospace>,
    <monospace>scores_b</monospace>, via
    <named-content content-type="sans-serif">arch</named-content>’s
    <monospace>CircularBlockBootstrap</monospace> (Sheppard, 2024),
    swept across a list of candidate block lengths as a sensitivity
    check rather than relying on one automatically “optimal” length. The
    range of <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-values
    and intervals across the swept lengths is the result to report. If a
    single headline entry is wanted, the
    largest-<inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>
    one is a conservative choice, but it is a choice made after looking
    at the sweep, and a block length picked by a data-driven rule (for
    example
    <named-content content-type="sans-serif">arch</named-content>’s
    <monospace>optimal_block_length</monospace>) is the cleaner
    alternative to state in advance.</p>
    <preformat>diebold_mariano(loss_a, loss_b, h=1, varestimator=&quot;acf&quot;)</preformat>
    <p>implements the Diebold–Mariano test (Diebold &amp; Mariano, 1995)
    on the same paired differential, including the
    Harvey–Leybourne–Newbold small-sample correction (Harvey et al.,
    1997) and a Student-<inline-formula><alternatives>
    <tex-math><![CDATA[t]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>t</mml:mi></mml:math></alternatives></inline-formula>
    (not asymptotic normal) reference distribution with
    <inline-formula><alternatives>
    <tex-math><![CDATA[n-1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>n</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    degrees of freedom, matching
    <named-content content-type="sans-serif">R</named-content>’s
    <monospace>forecast::dm.test</monospace> (Hyndman &amp; Khandakar,
    2008) formula for formula rather than following the original 1995
    paper’s asymptotic-normal reference directly. The
    <monospace>h</monospace> argument sets how many autocovariance lags
    enter the long-run variance (<inline-formula><alternatives>
    <tex-math><![CDATA[h - 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>),
    and it also drives the correction factor. It should reflect the
    serial dependence in the per-origin score differences, not be set
    mechanically to the forecast horizon. When origins are spaced so
    that evaluation windows are adjacent and do not overlap, the
    differences are close to serially independent and
    <monospace>h</monospace> near <inline-formula><alternatives>
    <tex-math><![CDATA[1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>1</mml:mn></mml:math></alternatives></inline-formula>
    is appropriate, while a larger <monospace>h</monospace> widens the
    variance estimate and costs power. This vendored implementation is
    deliberately cross-checked against
    <monospace>forecast::dm.test</monospace>’s own output on fixed
    synthetic data as a development-time oracle: doing so caught a
    genuine normalization bug during development, where the package’s
    long-run-variance estimator initially normalized each sample
    autocovariance by <inline-formula><alternatives>
    <tex-math><![CDATA[n - \text{lag}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>n</mml:mi><mml:mo>−</mml:mo><mml:mtext mathvariant="normal">lag</mml:mtext></mml:mrow></mml:math></alternatives></inline-formula>
    (the textbook “unbiased” convention) rather than by the full sample
    size <inline-formula><alternatives>
    <tex-math><![CDATA[n]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>n</mml:mi></mml:math></alternatives></inline-formula>
    at every lag, the convention
    <named-content content-type="sans-serif">R</named-content>’s own
    <monospace>acf()</monospace> function – and hence
    <monospace>forecast::dm.test</monospace> – actually uses. The two
    conventions coincide at lag <inline-formula><alternatives>
    <tex-math><![CDATA[0]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0</mml:mn></mml:math></alternatives></inline-formula>,
    so this discrepancy was invisible at horizon
    <inline-formula><alternatives>
    <tex-math><![CDATA[h=1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>=</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    and only surfaced once the test suite exercised
    <inline-formula><alternatives>
    <tex-math><![CDATA[h > 1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>&gt;</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    against the oracle. The oracle is stored with the package as fixed
    data (<monospace>tests/_reference/</monospace>): six cases at
    <inline-formula><alternatives>
    <tex-math><![CDATA[h \in \{1, 5, 10\}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>∈</mml:mo><mml:mo stretchy="false" form="prefix">{</mml:mo><mml:mn>1</mml:mn><mml:mo>,</mml:mo><mml:mn>5</mml:mn><mml:mo>,</mml:mo><mml:mn>10</mml:mn><mml:mo stretchy="false" form="postfix">}</mml:mo></mml:mrow></mml:math></alternatives></inline-formula>
    with both variance estimators, giving
    <named-content content-type="sans-serif">R</named-content>’s own
    random draws together with the statistic and
    <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-value
    <monospace>forecast::dm.test</monospace> returned, which the test
    suite matches to <inline-formula><alternatives>
    <tex-math><![CDATA[10^{-6}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:msup><mml:mn>10</mml:mn><mml:mrow><mml:mi>−</mml:mi><mml:mn>6</mml:mn></mml:mrow></mml:msup></mml:math></alternatives></inline-formula>.
    The comparison therefore runs from
    <named-content content-type="sans-serif">Python</named-content>
    alone, with no
    <named-content content-type="sans-serif">R</named-content>
    installation. With
    <named-content content-type="sans-serif">R</named-content> 4.6.0 and
    <named-content content-type="sans-serif">forecast</named-content>
    9.0.2, regenerating the fixture reproduces it byte for byte
    (<monospace>make check-oracles</monospace>).</p>
    <preformat>model_confidence_set(scores, alpha=0.10, block_len=5,
                      n_boot=1000, seed=None)</preformat>
    <p>implements the Model Confidence Set (Hansen et al., 2011) via its
    range-statistic elimination algorithm: repeatedly test whether the
    current candidate set of models is statistically distinguishable
    from its own best member, and if so, drop the single
    worst-performing model and repeat, until the surviving set cannot be
    rejected at level <monospace>alpha</monospace>. The null
    distribution and each round’s studentizing standard errors both come
    from the same joint circular block bootstrap of the full loss
    matrix, reusing the identical
    <named-content content-type="sans-serif">arch</named-content>
    machinery Section <xref alt="4.2" rid="secU003Asigtest">4.2</xref>’s
    bootstrap function depends on. This is the package’s own reasonable
    operationalization of Hansen et al.’s procedure, not a line-by-line
    port of any specific existing implementation’s internal choices –
    <named-content content-type="sans-serif">R</named-content>’s
    <named-content content-type="sans-serif">MCS</named-content>
    package’s automatic block-length selection, for instance, is not
    reproduced, and <monospace>block_len</monospace> is instead a
    required, caller-chosen parameter, swept manually if robustness to
    it matters. The test suite accordingly cross-checks this
    implementation’s <italic>verdict</italic> (which models survive)
    against <named-content content-type="sans-serif">R</named-content>’s
    <monospace>MCS::MCSprocedure</monospace> on fixed synthetic data
    where the correct verdict is unambiguous by construction, rather
    than requiring byte-exact statistic or
    <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-value
    agreement. The fixed loss matrix, drawn in
    <named-content content-type="sans-serif">R</named-content>, and
    <named-content content-type="sans-serif">R</named-content>’s full
    output for it
    (<named-content content-type="sans-serif">MCS</named-content> 0.2.0)
    are stored alongside the Diebold–Mariano fixture. On that matrix
    both implementations keep the same two models and drop the same two,
    and the final Model Confidence Set <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-value
    is about <inline-formula><alternatives>
    <tex-math><![CDATA[0.89]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.89</mml:mn></mml:math></alternatives></inline-formula>
    here against <inline-formula><alternatives>
    <tex-math><![CDATA[0.90]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.90</mml:mn></mml:math></alternatives></inline-formula>
    in <named-content content-type="sans-serif">R</named-content>,
    although the two eliminate the dropped models in a different
    order.</p>
  </sec>
</sec>
<sec id="secU003Aexample">
  <title>Illustrative Example</title>
  <sec id="two-point-forecasts-end-to-end">
    <title>Two point forecasts, end to end</title>
    <p>The following example simulates a <inline-formula><alternatives>
    <tex-math><![CDATA[K = 4]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    asset panel whose true pairwise correlation drifts slowly between
    roughly <inline-formula><alternatives>
    <tex-math><![CDATA[0.15]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.15</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[0.50]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.50</mml:mn></mml:math></alternatives></inline-formula>
    over 900 trading days, and compares two deliberately simple
    forecasting rules: <monospace>persistence</monospace>, which
    forecasts tomorrow’s correlation matrix as the sample correlation of
    the trailing 60-day window, and <monospace>shrinkage</monospace>,
    which additionally shrinks that estimate 30% of the way toward the
    identity matrix. Because the underlying process has real,
    substantial, slowly-varying correlation, shrinking toward
    independence is the wrong thing to do here by construction – the
    example is deliberately built so that one forecast is genuinely
    worse, to show what a decisive verdict from the full toolchain looks
    like end to end.</p>
    <p>The output below was produced with
    <named-content content-type="sans-serif">corrscore</named-content>
    0.1.2 on
    <named-content content-type="sans-serif">Python</named-content>
    3.12.7 with
    <named-content content-type="sans-serif">NumPy</named-content>
    1.26.4,
    <named-content content-type="sans-serif">SciPy</named-content>
    1.13.1 and
    <named-content content-type="sans-serif">arch</named-content> 7.0.0.
    Every random draw is seeded (the data with
    <monospace>default_rng(0)</monospace>, the bootstrap with
    <monospace>seed=1</monospace>, the Model Confidence Set with
    <monospace>seed=2</monospace>) and every forecast is a
    <monospace>&quot;point&quot;</monospace> forecast, so the output is
    deterministic for fixed library versions on a fixed platform. It
    does depend on both.
    <named-content content-type="sans-serif">NumPy</named-content> 2.x
    draws different returns from the same seed, and the same script then
    prints a mean variogram score of <inline-formula><alternatives>
    <tex-math><![CDATA[3.0639]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>3.0639</mml:mn></mml:math></alternatives></inline-formula>
    for <monospace>persistence</monospace>, not
    <inline-formula><alternatives>
    <tex-math><![CDATA[3.0274]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>3.0274</mml:mn></mml:math></alternatives></inline-formula>.
    The numbers below were produced on macOS (Apple silicon, arm64). On
    Linux (aarch64) with the same pinned versions, 13 of the 29 printed
    lines differ: the mean variogram score of
    <monospace>persistence</monospace> is <inline-formula><alternatives>
    <tex-math><![CDATA[3.0974]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>3.0974</mml:mn></mml:math></alternatives></inline-formula>,
    and in the near-tie of
    Section <xref alt="5.3" rid="secU003Aneartie">5.3</xref> the Model
    Confidence Set drops <monospace>win35</monospace> at all three block
    lengths, while the verdict of this first example is unchanged. The
    cause is the draw:
    <monospace>Generator.multivariate_normal</monospace> factorises the
    correlation matrix by a singular value decomposition, the matrix
    here has an eigenvalue of multiplicity three, and the macOS and
    Linux builds of
    <named-content content-type="sans-serif">NumPy</named-content>
    1.26.4 return different bases for it on 16 of the 900 simulated
    days. Passing <monospace>method=&quot;cholesky&quot;</monospace>
    makes both platforms print the same lines, but the numbers reported
    here are those of the default method. The script is
    <monospace>examples/section5_example.py</monospace> in the
    repository, and running <monospace>make paper-example</monospace>
    from the repository root builds the pinned environment of
    <monospace>requirements-paper.txt</monospace> and prints the numbers
    below, followed by those of
    Sections <xref alt="5.2" rid="secU003Aclosedform">5.2</xref>
    and <xref alt="5.3" rid="secU003Aneartie">5.3</xref>. Release 0.1.2
    is archived at
    <ext-link ext-link-type="uri" xlink:href="https://doi.org/10.5281/zenodo.23078623">https://doi.org/10.5281/zenodo.23078623</ext-link>,
    so these results attach to a fixed snapshot.</p>
    <preformat>import numpy as np
from corrscore import (backtest_zero_overlap, circular_block_bootstrap,
                        diebold_mariano, matrix_geodesic_variogram_score,
                        matrix_variogram_score, model_confidence_set)

rng = np.random.default_rng(0)
K, n_days = 4, 900
true_rho = 0.15 + 0.35 * (0.5 + 0.5 * np.sin(np.arange(n_days) / 60.0))
returns = np.empty((n_days, K))
for t in range(n_days):
    corr = np.full((K, K), true_rho[t]); np.fill_diagonal(corr, 1.0)
    returns[t] = rng.multivariate_normal(np.zeros(K), corr)

def sample_corr(start, end):
    return np.corrcoef(returns[start:end], rowvar=False)

def persistence_forecast(origin, window=60):
    return {&quot;kind&quot;: &quot;point&quot;, &quot;Q&quot;: sample_corr(origin - window + 1, origin + 1)}

def shrinkage_forecast(origin, window=60, alpha=0.3):
    q = sample_corr(origin - window + 1, origin + 1)
    return {&quot;kind&quot;: &quot;point&quot;, &quot;Q&quot;: (1 - alpha) * q + alpha * np.eye(K)}

origins, horizon = list(range(120, n_days - 10, 10)), 10
result = backtest_zero_overlap(
    forecast_fns={&quot;persistence&quot;: persistence_forecast, &quot;shrinkage&quot;: shrinkage_forecast},
    ground_truth_fn=sample_corr, origins=origins, horizon=horizon,
    score_fn=matrix_variogram_score)

print(&quot;mean VS, persistence:&quot;, result.scores[&quot;persistence&quot;].mean())
print(&quot;mean VS, shrinkage:  &quot;, result.scores[&quot;shrinkage&quot;].mean())

boot = circular_block_bootstrap(result.scores[&quot;shrinkage&quot;], result.scores[&quot;persistence&quot;],
                                 block_lengths=[5, 10], seed=1)
def fmt_boot_p(r):
    # A percentile bootstrap with n_boot resamples cannot resolve a p-value
    # below 2/n_boot (two tails of one resample each); report an upper bound.
    floor = 2.0 / r.n_boot
    return f&quot;p&lt;{floor:g}&quot; if r.p_value &lt; floor else f&quot;p={r.p_value:.4f}&quot;

for block_len, r in boot.items():
    print(f&quot;bootstrap block_len={block_len}: mean diff={r.obs:.4f}, &quot;
          f&quot;95% CI=({r.ci_lo:.4f}, {r.ci_hi:.4f}), {fmt_boot_p(r)}&quot;)

dm = diebold_mariano(result.scores[&quot;shrinkage&quot;], result.scores[&quot;persistence&quot;], h=horizon)
print(f&quot;Diebold-Mariano: stat={dm.statistic:.3f}, p={dm.p_value:.1e}&quot;)

mcs = model_confidence_set(result.scores, alpha=0.10, block_len=10, seed=2)
print(&quot;MCS survivors:&quot;, mcs.survivors, &quot; eliminated:&quot;, mcs.eliminated)</preformat>
    <preformat>mean VS, persistence: 3.0274186774073626
mean VS, shrinkage:   3.52280921068856
bootstrap block_len=5: mean diff=0.4954, 95% CI=(0.4302, 0.5600), p&lt;0.001
bootstrap block_len=10: mean diff=0.4954, 95% CI=(0.4267, 0.5592), p&lt;0.001
Diebold-Mariano: stat=13.026, p=4.7e-21
MCS survivors: ['persistence']  eliminated: [('shrinkage', 0.0)]</preformat>
    <p>All three significance tools agree that
    <monospace>shrinkage</monospace> scores worse than
    <monospace>persistence</monospace> on this panel, and the Model
    Confidence Set eliminates it at <inline-formula><alternatives>
    <tex-math><![CDATA[\alpha = 0.10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>=</mml:mo><mml:mn>0.10</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>.
    The bootstrap <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-values
    are upper bounds. With <monospace>n_boot=2000</monospace> the
    smallest nonzero two-sided value is <inline-formula><alternatives>
    <tex-math><![CDATA[2/2000 = 0.001]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>2</mml:mn><mml:mi>/</mml:mi><mml:mn>2000</mml:mn><mml:mo>=</mml:mo><mml:mn>0.001</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>,
    and a smaller reported value means no resample crossed zero. The
    Model Confidence Set’s <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-value
    of <inline-formula><alternatives>
    <tex-math><![CDATA[0.0]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.0</mml:mn></mml:math></alternatives></inline-formula>
    is limited by its own resample count in the same way (its default of
    <inline-formula><alternatives>
    <tex-math><![CDATA[1000]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>1000</mml:mn></mml:math></alternatives></inline-formula>
    resamples resolves no finer than <inline-formula><alternatives>
    <tex-math><![CDATA[1/1000]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>1</mml:mn><mml:mi>/</mml:mi><mml:mn>1000</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>).
    The Diebold–Mariano <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-value
    comes from a Student-<inline-formula><alternatives>
    <tex-math><![CDATA[t]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>t</mml:mi></mml:math></alternatives></inline-formula>
    reference distribution and is not limited by a resample count.</p>
    <p>Three caveats apply to how this example should be read. First, it
    demonstrates the toolchain end to end and is not evidence about the
    geometric score. Every off-diagonal entry shares one true level and
    shrinkage rescales that level, which is close to the level-shift
    configuration of
    Section <xref alt="3.4" rid="secU003Ageovs">3.4</xref>, and the
    panel does not exercise the boundary-proximate case where that
    section says the geometric variant helps. Second, the bootstrap and
    Diebold–Mariano tests assume a covariance-stationary loss
    differential, and a correlation that drifts between
    <inline-formula><alternatives>
    <tex-math><![CDATA[0.15]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.15</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[0.50]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.50</mml:mn></mml:math></alternatives></inline-formula>
    makes the per-origin differences plausibly nonstationary in mean.
    The printed <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-values
    therefore demonstrate the toolchain and are not a validated
    inference. Third, <monospace>h=10</monospace> equals the horizon and
    origins are spaced <inline-formula><alternatives>
    <tex-math><![CDATA[10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>10</mml:mn></mml:math></alternatives></inline-formula>
    apart, so adjacent evaluation windows just abut. The
    Harvey–Leybourne–Newbold correction and the
    <inline-formula><alternatives>
    <tex-math><![CDATA[n-1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>n</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    degrees of freedom are applied as in
    <monospace>forecast::dm.test</monospace>, but here the
    <inline-formula><alternatives>
    <tex-math><![CDATA[h-1 = 9]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>−</mml:mo><mml:mn>1</mml:mn><mml:mo>=</mml:mo><mml:mn>9</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    lags estimate near-zero autocovariances (the lag-1 autocorrelation
    of the differential is <inline-formula><alternatives>
    <tex-math><![CDATA[-0.09]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>−</mml:mi><mml:mn>0.09</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>),
    which makes <inline-formula><alternatives>
    <tex-math><![CDATA[h=10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>=</mml:mo><mml:mn>10</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    conservative: <inline-formula><alternatives>
    <tex-math><![CDATA[h=1]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>h</mml:mi><mml:mo>=</mml:mo><mml:mn>1</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    gives a statistic of <inline-formula><alternatives>
    <tex-math><![CDATA[14.206]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>14.206</mml:mn></mml:math></alternatives></inline-formula>
    in place of <inline-formula><alternatives>
    <tex-math><![CDATA[13.026]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>13.026</mml:mn></mml:math></alternatives></inline-formula>,
    with the same verdict.</p>
    <p>Passing <monospace>matrix_geodesic_variogram_score</monospace> as
    the <monospace>score_fn</monospace> argument to
    <monospace>backtest_zero_overlap</monospace> reuses every other line
    unchanged, since
    Section <xref alt="3.4" rid="secU003Ageovs">3.4</xref>’s geometric
    score shares the flat variogram score’s exact call signature – a
    deliberate design consequence of implementing it as a transform
    composed with existing machinery rather than a parallel code
    path.</p>
  </sec>
  <sec id="secU003Aclosedform">
    <title>Closed form against the Monte Carlo fallback</title>
    <p>The example above uses only
    <monospace>&quot;point&quot;</monospace> forecasts. This one
    exercises the closed-form kinds of
    Section <xref alt="3.1" rid="secU003Aforecastrep">3.1</xref>. It
    scores a two-atom forecast (a calm and a stress correlation matrix
    with probabilities <inline-formula><alternatives>
    <tex-math><![CDATA[0.7]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.7</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[0.3]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.3</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[K = 4]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>)
    against a fixed outcome <inline-formula><alternatives>
    <tex-math><![CDATA[y]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>y</mml:mi></mml:math></alternatives></inline-formula>,
    once through its exact kind and once as an
    <monospace>&quot;ensemble&quot;</monospace> of
    <inline-formula><alternatives>
    <tex-math><![CDATA[M = 2000]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>M</mml:mi><mml:mo>=</mml:mo><mml:mn>2000</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    draws from it. For the
    <monospace>&quot;isotropic_gaussian_mixture&quot;</monospace> kind
    each draw adds symmetric Gaussian scatter with
    <inline-formula><alternatives>
    <tex-math><![CDATA[\sigma = 0.05]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>σ</mml:mi><mml:mo>=</mml:mo><mml:mn>0.05</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    to the free entries of its atom, following the convention of
    Section <xref alt="3.1" rid="secU003Aforecastrep">3.1</xref>. The
    ensemble score is averaged over 50 independent seeds, and the
    difference from the closed form is expressed in standard errors of
    that average.</p>
    <preformat>mixture = {&quot;kind&quot;: &quot;mixture&quot;, &quot;components&quot;: [(0.7, q_calm), (0.3, q_stress)]}
iso = {&quot;kind&quot;: &quot;isotropic_gaussian_mixture&quot;,
       &quot;components&quot;: [(0.7, q_calm, 0.05), (0.3, q_stress, 0.05)]}

matrix_energy_score(mixture, y)                 # exact
matrix_energy_score(ensemble_from(mixture), y)  # M = 2000 draws
matrix_energy_score(iso, y)                     # exact (noncentral chi)
matrix_energy_score(ensemble_from(iso), y)
matrix_variogram_score(mixture, y, p=0.5)       # exact
matrix_variogram_score(ensemble_from(mixture), y, p=0.5)
matrix_variogram_score(iso, y, p=0.5, n_samples=2000)  # Monte Carlo
matrix_variogram_score(ensemble_from(iso), y, p=0.5)</preformat>
    <preformat>K=4, ensemble size M=2000, mean over 50 seeds
energy, mixture                exact=0.26990  ens=0.27003+-0.00027  (+0.5 se)
energy, isotropic Gauss. mix.  exact=0.22600  ens=0.22622+-0.00035  (+0.6 se)
variogram, mixture             exact=0.03327  ens=0.03277+-0.00036  (-1.4 se)
variogram, isotropic (both MC) sampler=0.04213+-0.00030  ens=0.04202+-0.00034  (+0.2 se)</preformat>
    <p>(<monospace>ensemble_from</monospace> stands for the
    draw-and-average loop in the script
    <monospace>examples/closed_form_vs_mc.py</monospace>, which also
    contains the exact matrices and seeds.) Both energy scores agree
    with their closed forms to within one standard error, about
    <inline-formula><alternatives>
    <tex-math><![CDATA[0.1\%]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>0.1</mml:mn><mml:mi>%</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    of the score, which checks the isotropic-Gaussian-mixture formula,
    including its <inline-formula><alternatives>
    <tex-math><![CDATA[\sqrt{2}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:msqrt><mml:mn>2</mml:mn></mml:msqrt></mml:math></alternatives></inline-formula>
    Frobenius bookkeeping, against direct simulation. The variogram
    score of the discrete mixture agrees within
    <inline-formula><alternatives>
    <tex-math><![CDATA[1.4]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>1.4</mml:mn></mml:math></alternatives></inline-formula>
    standard errors. That row is noisy because the score itself is
    small, and a run with 600 seeds narrows the gap to
    <inline-formula><alternatives>
    <tex-math><![CDATA[0.8]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.8</mml:mn></mml:math></alternatives></inline-formula>
    standard errors. The Monte Carlo bias of
    Section <xref alt="3.3" rid="secU003Avs">3.3</xref> is a
    <inline-formula><alternatives>
    <tex-math><![CDATA[4 \times 10^{-5}]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>4</mml:mn><mml:mo>×</mml:mo><mml:msup><mml:mn>10</mml:mn><mml:mrow><mml:mi>−</mml:mi><mml:mn>5</mml:mn></mml:mrow></mml:msup></mml:mrow></mml:math></alternatives></inline-formula>
    effect in this setting, far below the seed noise. The
    isotropic-Gaussian-mixture variogram score has no closed form, so
    the last row compares the kind’s own sampler with an ensemble of
    independent draws, and the two agree within
    <inline-formula><alternatives>
    <tex-math><![CDATA[0.2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.2</mml:mn></mml:math></alternatives></inline-formula>
    standard errors.</p>
  </sec>
  <sec id="secU003Aneartie">
    <title>A near-tie among six models</title>
    <p>The verdict in
    Section <xref alt="5" rid="secU003Aexample">5</xref>’s first example
    was decided by construction. This one is not. It uses the same
    simulated panel and six candidates that differ only in the length of
    the trailing window of their persistence forecast
    (<inline-formula><alternatives>
    <tex-math><![CDATA[20]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>20</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[25]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>25</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[30]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>30</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[35]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>35</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[40]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>40</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[60]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>60</mml:mn></mml:math></alternatives></inline-formula>
    days). Windows near the best length give score differences that
    change sign from origin to origin, so the outcome is not known in
    advance. The <monospace>win60</monospace> model is the
    <monospace>persistence</monospace> model of
    Section <xref alt="5" rid="secU003Aexample">5</xref>, and its mean
    score of <inline-formula><alternatives>
    <tex-math><![CDATA[3.027]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>3.027</mml:mn></mml:math></alternatives></inline-formula>
    matches. Each model is compared with <monospace>win30</monospace>,
    with the bootstrap swept over block lengths
    <inline-formula><alternatives>
    <tex-math><![CDATA[2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>2</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[5]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>5</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>10</mml:mn></mml:math></alternatives></inline-formula>
    and the Diebold–Mariano test run at <monospace>h=1</monospace>,
    since the evaluation windows are adjacent and do not overlap
    (Section <xref alt="4.2" rid="secU003Asigtest">4.2</xref>).</p>
    <preformat>scores = backtest_zero_overlap(forecast_fns={f&quot;win{w}&quot;: persistence(w) for w in windows},
                               ground_truth_fn=sample_corr, origins=origins,
                               horizon=10, score_fn=matrix_variogram_score).scores
dm = diebold_mariano(scores[m], scores[&quot;win30&quot;], h=1)
boot = circular_block_bootstrap(scores[m], scores[&quot;win30&quot;],
                                block_lengths=[2, 5, 10], seed=1)
mcs = model_confidence_set(scores, alpha=0.10, block_len=b, seed=2)   # b in 2, 5, 10</preformat>
    <preformat>77 origins, horizon 10; mean variogram score:
  win20=2.496  win25=2.545  win30=2.550  win35=2.682  win40=2.815  win60=3.027

Each model against win30 (mean diff &gt; 0 means worse than win30):
  model   diff    DM p   bootstrap p at block 2 / 5 / 10
  win20  -0.054   0.604   0.576 / 0.520 / 0.566
  win25  -0.005   0.949   0.906 / 0.906 / 0.943
  win35  +0.132   0.053   0.035 / 0.044 / 0.013
  win40  +0.265   0.003   0.001 / 0.002 / &lt;0.001
  win60  +0.477  &lt;0.001   &lt;0.001 / &lt;0.001 / &lt;0.001

Model Confidence Set, alpha=0.10 (elimination path, with p at each step):
  block  2: survivors ['win20', 'win25', 'win30', 'win35']
            eliminated: win60 (p=0.001) -&gt; win40 (p=0.015)
  block  5: survivors ['win20', 'win25', 'win30', 'win35']
            eliminated: win60 (p&lt;0.001) -&gt; win40 (p=0.008)
  block 10: survivors ['win20', 'win25', 'win30']
            eliminated: win60 (p&lt;0.001) -&gt; win40 (p=0.004) -&gt; win35 (p=0.078)</preformat>
    <p>Three readings follow. First, <monospace>win20</monospace> has
    the lowest mean score (<inline-formula><alternatives>
    <tex-math><![CDATA[2.496]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>2.496</mml:mn></mml:math></alternatives></inline-formula>
    against <inline-formula><alternatives>
    <tex-math><![CDATA[2.550]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>2.550</mml:mn></mml:math></alternatives></inline-formula>
    for <monospace>win30</monospace>), but the gap is far from
    distinguishable from zero (Diebold–Mariano
    <inline-formula><alternatives>
    <tex-math><![CDATA[p = 0.604]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>p</mml:mi><mml:mo>=</mml:mo><mml:mn>0.604</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>,
    bootstrap <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>
    between <inline-formula><alternatives>
    <tex-math><![CDATA[0.52]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.52</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[0.58]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.58</mml:mn></mml:math></alternatives></inline-formula>),
    and <monospace>win25</monospace> is a tie as well. The ordering of
    windows <inline-formula><alternatives>
    <tex-math><![CDATA[20]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>20</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[25]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>25</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[30]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>30</mml:mn></mml:math></alternatives></inline-formula>
    is not supported by the data. Second, <monospace>win35</monospace>
    is borderline: the Diebold–Mariano test gives
    <inline-formula><alternatives>
    <tex-math><![CDATA[p = 0.053]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>p</mml:mi><mml:mo>=</mml:mo><mml:mn>0.053</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    while the bootstrap gives <inline-formula><alternatives>
    <tex-math><![CDATA[0.013]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.013</mml:mn></mml:math></alternatives></inline-formula>
    to <inline-formula><alternatives>
    <tex-math><![CDATA[0.044]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.044</mml:mn></mml:math></alternatives></inline-formula>
    depending on block length, so whether it crosses the
    <inline-formula><alternatives>
    <tex-math><![CDATA[5\%]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>5</mml:mn><mml:mi>%</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
    line depends on a choice the user makes. This is the situation in
    which Section <xref alt="4.2" rid="secU003Asigtest">4.2</xref>’s
    advice to report the whole sweep, and not one entry, matters. Third,
    <monospace>win40</monospace> and <monospace>win60</monospace> are
    worse under every test. The Model Confidence Set drops
    <monospace>win60</monospace> and then <monospace>win40</monospace>
    at every block length. It keeps <monospace>win35</monospace> at
    block lengths <inline-formula><alternatives>
    <tex-math><![CDATA[2]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>2</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[5]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>5</mml:mn></mml:math></alternatives></inline-formula>
    (final <inline-formula><alternatives>
    <tex-math><![CDATA[p]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>
    of <inline-formula><alternatives>
    <tex-math><![CDATA[0.17]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.17</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[0.15]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>0.15</mml:mn></mml:math></alternatives></inline-formula>)
    and drops it at block length <inline-formula><alternatives>
    <tex-math><![CDATA[10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>10</mml:mn></mml:math></alternatives></inline-formula>
    (<inline-formula><alternatives>
    <tex-math><![CDATA[p = 0.078]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>p</mml:mi><mml:mo>=</mml:mo><mml:mn>0.078</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>).
    The set at <inline-formula><alternatives>
    <tex-math><![CDATA[\alpha = 0.10]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>=</mml:mo><mml:mn>0.10</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
    is therefore either four or three models, always containing windows
    <inline-formula><alternatives>
    <tex-math><![CDATA[20]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>20</mml:mn></mml:math></alternatives></inline-formula>,
    <inline-formula><alternatives>
    <tex-math><![CDATA[25]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>25</mml:mn></mml:math></alternatives></inline-formula>
    and <inline-formula><alternatives>
    <tex-math><![CDATA[30]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>30</mml:mn></mml:math></alternatives></inline-formula>
    and never <inline-formula><alternatives>
    <tex-math><![CDATA[40]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>40</mml:mn></mml:math></alternatives></inline-formula>
    or <inline-formula><alternatives>
    <tex-math><![CDATA[60]]></tex-math>
    <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>60</mml:mn></mml:math></alternatives></inline-formula>,
    and membership of <monospace>win35</monospace> is not settled by
    this panel.</p>
    <p>The candidates were chosen to produce a near-tie, so this panel
    shows how to read the output and is not a finding about window
    lengths. The stationarity caveat of
    Section <xref alt="5" rid="secU003Aexample">5</xref>’s first example
    applies here as well.</p>
  </sec>
</sec>
<sec id="secU003Arelated">
  <title>Comparison with Existing Software</title>
  <p><named-content content-type="sans-serif">properscoring</named-content>
  (The Climate Corporation, 2015) is a mature
  <named-content content-type="sans-serif">Python</named-content>
  package for the continuous ranked probability score and the Brier
  score, both fundamentally univariate (or applied marginally, series by
  series); it has no multivariate energy or variogram score, and no
  correlation-matrix-specific concept at all.
  <named-content content-type="sans-serif">scoringRules</named-content>
  (Jordan et al., 2019), an
  <named-content content-type="sans-serif">R</named-content> package, is
  the closer relative: its <monospace>es_sample</monospace> and
  <monospace>vs_sample</monospace> functions compute the energy score
  and variogram score for a general <inline-formula><alternatives>
  <tex-math><![CDATA[d]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>d</mml:mi></mml:math></alternatives></inline-formula>-dimensional
  vector from a Monte Carlo ensemble sample.
  <named-content content-type="sans-serif">corrscore</named-content>
  differs in four concrete ways relevant to the correlation-matrix use
  case specifically: (i) a closed-form tractability spectrum across
  point, discrete-mixture, and (for the energy score)
  isotropic-Gaussian-mixture forecasts
  (Section <xref alt="3.1" rid="secU003Aforecastrep">3.1</xref>), where
  <named-content content-type="sans-serif">scoringRules</named-content>
  always samples; (ii) a <inline-formula><alternatives>
  <tex-math><![CDATA[K \times K]]></tex-math>
  <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>K</mml:mi><mml:mo>×</mml:mo><mml:mi>K</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>-matrix-native
  API with a free-upper-triangle indexing convention built in, rather
  than requiring the caller to flatten a matrix into a generic vector
  and manage that convention themselves; (iii) the geometric variogram
  score of Section <xref alt="3.4" rid="secU003Ageovs">3.4</xref>, with
  no analog in either package; and (iv) a bundled walk-forward backtest
  harness and significance-testing suite
  (Section <xref alt="4" rid="secU003Abacktest">4</xref>) purpose-built
  around this evaluation workflow, which neither package provides – a
  <named-content content-type="sans-serif">scoringRules</named-content>
  user must still write their own backtest loop and reach for a separate
  package
  (e.g. <named-content content-type="sans-serif">R</named-content>’s
  <named-content content-type="sans-serif">MCS</named-content>) for
  multi-model significance testing.</p>
</sec>
<sec id="secU003Asummary">
  <title>Summary</title>
  <p><named-content content-type="sans-serif">corrscore</named-content>
  packages matrix-aware proper scoring rules, a geometry-aware variant
  motivated and validated in a companion paper, and a
  backtest-plus-significance-testing bundle purpose-built for evaluating
  correlation and covariance-matrix forecasts, closing a real, specific
  gap left by existing general-purpose scoring-rule software.</p>
</sec>
<sec id="data-and-code-availability" sec-type="data-availability">
  <title>Data and Code Availability</title>
  <p>The package is available under the MIT license at
  <ext-link ext-link-type="uri" xlink:href="https://github.com/vinhnguyen3455/corrscore">https://github.com/vinhnguyen3455/corrscore</ext-link>.
  The version described here, 0.1.2, is archived with a persistent
  identifier at
  <ext-link ext-link-type="uri" xlink:href="https://doi.org/10.5281/zenodo.23078623">https://doi.org/10.5281/zenodo.23078623</ext-link>.
  Its 62 tests, including property-based tests via
  <named-content content-type="sans-serif">Hypothesis</named-content>
  (MacIver et al., 2019) and, for the vendored Diebold–Mariano and Model
  Confidence Set implementations, cross-checks against
  <named-content content-type="sans-serif">R</named-content> reference
  implementations, pass on
  <named-content content-type="sans-serif">Python</named-content> 3.10
  and later. The printed output of
  Section <xref alt="5" rid="secU003Aexample">5</xref> was produced on
  macOS (arm64); on Linux (aarch64) it differs in 13 of 29 lines (see
  Section <xref alt="5" rid="secU003Aexample">5</xref>).</p>
</sec>
<sec id="competing-interests">
  <title>Competing interests</title>
  <p>The author is an independent researcher who wrote and released the
  <named-content content-type="sans-serif">corrscore</named-content>
  package. The author declares no financial or non-financial competing
  interests.</p>
</sec>
</body>
<back><ref-list><ref id="ref1"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Diebold</surname><given-names>Francis X.</given-names></name><name><surname>Mariano</surname><given-names>Roberto S.</given-names></name></person-group><article-title>Comparing Predictive Accuracy</article-title><source>Journal of Business &amp; Economic Statistics</source><year>1995</year><volume>13</volume><issue>3</issue><fpage>253</fpage><lpage>263</lpage><publisher-name>Informa UK Limited</publisher-name><pub-id pub-id-type="doi">10.1080/07350015.1995.10524599</pub-id></element-citation></ref><ref id="ref2"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Gneiting</surname><given-names>Tilmann</given-names></name><name><surname>Raftery</surname><given-names>Adrian E</given-names></name></person-group><article-title>Strictly Proper Scoring Rules, Prediction, and Estimation</article-title><source>Journal of the American Statistical Association</source><year>2007</year><volume>102</volume><issue>477</issue><fpage>359</fpage><lpage>378</lpage><publisher-name>Informa UK Limited</publisher-name><pub-id pub-id-type="doi">10.1198/016214506000001437</pub-id></element-citation></ref><ref id="ref3"><mixed-citation>Hansen, P. R., Lunde, A., &amp; Nason, J. M. (2011). The Model Confidence Set. Econometrica, 79(2), 453–497.</mixed-citation></ref><ref id="ref4"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Harvey</surname><given-names>David</given-names></name><name><surname>Leybourne</surname><given-names>Stephen</given-names></name><name><surname>Newbold</surname><given-names>Paul</given-names></name></person-group><article-title>Testing the equality of prediction mean squared errors</article-title><source>International Journal of Forecasting</source><year>1997</year><volume>13</volume><issue>2</issue><fpage>281</fpage><lpage>291</lpage><publisher-name>Elsevier BV</publisher-name><pub-id pub-id-type="doi">10.1016/s0169-2070(96)00719-4</pub-id></element-citation></ref><ref id="ref5"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Hyndman</surname><given-names>Rob J.</given-names></name><name><surname>Khandakar</surname><given-names>Yeasmin</given-names></name></person-group><article-title>Automatic Time Series Forecasting: The
                    forecast
                    Package for
                    &lt;i&gt;R&lt;/i&gt;</article-title><source>Journal of Statistical Software</source><year>2008</year><volume>27</volume><issue>3</issue><publisher-name>Foundation for Open Access Statistic</publisher-name><pub-id pub-id-type="doi">10.18637/jss.v027.i03</pub-id></element-citation></ref><ref id="ref6"><mixed-citation>Johnson, N. L., Kotz, S., &amp; Balakrishnan, N. (1994). Continuous univariate distributions, volume 1 (2nd ed.). Wiley.</mixed-citation></ref><ref id="ref7"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Jordan</surname><given-names>Alexander</given-names></name><name><surname>Krüger</surname><given-names>Fabian</given-names></name><name><surname>Lerch</surname><given-names>Sebastian</given-names></name></person-group><article-title>Evaluating Probabilistic Forecasts with
                    scoringRules</article-title><source>Journal of Statistical Software</source><year>2019</year><volume>90</volume><issue>12</issue><publisher-name>Foundation for Open Access Statistic</publisher-name><pub-id pub-id-type="doi">10.18637/jss.v090.i12</pub-id></element-citation></ref><ref id="ref8"><mixed-citation>MacIver, D. R., Hatfield-Dodds, Z., &amp; Many Other Contributors. (2019). Hypothesis: A new approach to property-based testing. Journal of Open Source Software, 4(43), 1891.</mixed-citation></ref><ref id="ref9"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Nguyen</surname><given-names>Vinh</given-names></name></person-group><article-title>Proper Scoring Rules for Correlation Matrix Forecasts on the SPD Manifold: Theory and Empirical Evidence</article-title><year>2026</year><publisher-name>Elsevier BV</publisher-name><pub-id pub-id-type="doi">10.2139/ssrn.7358640</pub-id></element-citation></ref><ref id="ref10"><mixed-citation>Pinson, P., &amp; Tastu, J. (2013). Discrimination ability of the energy score (2013-No. 15). Technical University of Denmark, DTU Compute.</mixed-citation></ref><ref id="ref11"><mixed-citation>Politis, D. N., &amp; Romano, J. P. (1992). A circular block-resampling procedure for stationary data. In R. LePage &amp; L. Billard (Eds.), Exploring the limits of bootstrap (pp. 263–270). Wiley.</mixed-citation></ref><ref id="ref12"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Scheuerer</surname><given-names>Michael</given-names></name><name><surname>Hamill</surname><given-names>Thomas M.</given-names></name></person-group><article-title>Variogram-Based Proper Scoring Rules for Probabilistic Forecasts of Multivariate Quantities*</article-title><source>Monthly Weather Review</source><year>2015</year><volume>143</volume><issue>4</issue><fpage>1321</fpage><lpage>1334</lpage><publisher-name>American Meteorological Society</publisher-name><pub-id pub-id-type="doi">10.1175/mwr-d-14-00269.1</pub-id></element-citation></ref><ref id="ref13"><mixed-citation>Sheppard, K. (2024). Arch: ARCH models in Python, version 7.0.0 [software]. https://doi.org/10.5281/zenodo.10981635</mixed-citation></ref><ref id="ref14"><element-citation publication-type="journal"><person-group person-group-type="author"><name><surname>Székely</surname><given-names>Gábor J.</given-names></name><name><surname>Rizzo</surname><given-names>Maria L.</given-names></name></person-group><article-title>Energy statistics: A class of statistics based on distances</article-title><source>Journal of Statistical Planning and Inference</source><year>2013</year><volume>143</volume><issue>8</issue><fpage>1249</fpage><lpage>1272</lpage><publisher-name>Elsevier BV</publisher-name><pub-id pub-id-type="doi">10.1016/j.jspi.2013.03.018</pub-id></element-citation></ref><ref id="ref15"><mixed-citation>The Climate Corporation. (2015). Properscoring: Proper Scoring Rules in Python [software]. https://github.com/properscoring/properscoring</mixed-citation></ref></ref-list>
<ref-list>
  <title>References</title>
  <ref id="ref-dieboldmariano1995">
    <mixed-citation>Diebold, F. X., &amp; Mariano, R. S. (1995).
    Comparing predictive accuracy. <italic>Journal of Business and
    Economic Statistics</italic>, <italic>13</italic>(3),
    253–263.</mixed-citation>
  </ref>
  <ref id="ref-gneiting2007">
    <mixed-citation>Gneiting, T., &amp; Raftery, A. E. (2007). Strictly
    proper scoring rules, prediction, and estimation. <italic>Journal of
    the American Statistical Association</italic>,
    <italic>102</italic>(477), 359–378.</mixed-citation>
  </ref>
  <ref id="ref-hansenlundenason2011">
    <mixed-citation>Hansen, P. R., Lunde, A., &amp; Nason, J. M. (2011).
    The Model Confidence Set. <italic>Econometrica</italic>,
    <italic>79</italic>(2), 453–497.</mixed-citation>
  </ref>
  <ref id="ref-harveyleybournenewbold1997">
    <mixed-citation>Harvey, D., Leybourne, S., &amp; Newbold, P. (1997).
    Testing the equality of prediction mean squared errors.
    <italic>International Journal of Forecasting</italic>,
    <italic>13</italic>(2), 281–291.</mixed-citation>
  </ref>
  <ref id="ref-hyndman2008forecast">
    <mixed-citation>Hyndman, R. J., &amp; Khandakar, Y. (2008).
    Automatic time series forecasting: The forecast package for R.
    <italic>Journal of Statistical Software</italic>,
    <italic>27</italic>(3), 1–22.</mixed-citation>
  </ref>
  <ref id="ref-johnsonkotzbalakrishnan1994">
    <mixed-citation>Johnson, N. L., Kotz, S., &amp; Balakrishnan, N.
    (1994). <italic>Continuous univariate distributions, volume
    1</italic> (2nd ed.). Wiley.</mixed-citation>
  </ref>
  <ref id="ref-scoringrules2019">
    <mixed-citation>Jordan, A., Krüger, F., &amp; Lerch, S. (2019).
    Evaluating probabilistic forecasts with scoringRules.
    <italic>Journal of Statistical Software</italic>,
    <italic>90</italic>(12), 1–37.</mixed-citation>
  </ref>
  <ref id="ref-maciver2019hypothesis">
    <mixed-citation>MacIver, D. R., Hatfield-Dodds, Z., &amp; Many Other
    Contributors. (2019). Hypothesis: A new approach to property-based
    testing. <italic>Journal of Open Source Software</italic>,
    <italic>4</italic>(43), 1891.</mixed-citation>
  </ref>
  <ref id="ref-nguyen2026geodesic">
    <mixed-citation>Nguyen, V. (2026). <italic>Proper scoring rules for
    correlation matrix forecasts on the SPD manifold: Theory and
    empirical evidence</italic>.
    <ext-link ext-link-type="uri" xlink:href="http://dx.doi.org/10.2139/ssrn.7358640">http://dx.doi.org/10.2139/ssrn.7358640</ext-link></mixed-citation>
  </ref>
  <ref id="ref-pinsontastu2013">
    <mixed-citation>Pinson, P., &amp; Tastu, J. (2013).
    <italic>Discrimination ability of the energy score</italic>
    (2013-No. 15). Technical University of Denmark, DTU
    Compute.</mixed-citation>
  </ref>
  <ref id="ref-politisromano1992">
    <mixed-citation>Politis, D. N., &amp; Romano, J. P. (1992). A
    circular block-resampling procedure for stationary data. In R.
    LePage &amp; L. Billard (Eds.), <italic>Exploring the limits of
    bootstrap</italic> (pp. 263–270). Wiley.</mixed-citation>
  </ref>
  <ref id="ref-scheuererhamill2015">
    <mixed-citation>Scheuerer, M., &amp; Hamill, T. M. (2015).
    Variogram-based proper scoring rules for probabilistic forecasts of
    multivariate quantities. <italic>Monthly Weather Review</italic>,
    <italic>143</italic>, 1321–1334.</mixed-citation>
  </ref>
  <ref id="ref-arch2015">
    <mixed-citation>Sheppard, K. (2024). <italic>Arch: ARCH models in
    Python, version 7.0.0 [software]</italic>.
    <ext-link ext-link-type="uri" xlink:href="https://doi.org/10.5281/zenodo.10981635">https://doi.org/10.5281/zenodo.10981635</ext-link></mixed-citation>
  </ref>
  <ref id="ref-szekelyrizzo2013">
    <mixed-citation>Székely, G. J., &amp; Rizzo, M. L. (2013). Energy
    statistics: A class of statistics based on distances.
    <italic>Journal of Statistical Planning and Inference</italic>,
    <italic>143</italic>(8), 1249–1272.</mixed-citation>
  </ref>
  <ref id="ref-properscoring2015">
    <mixed-citation>The Climate Corporation. (2015).
    <italic>Properscoring: Proper Scoring Rules in Python
    [software]</italic>.
    <ext-link ext-link-type="uri" xlink:href="https://github.com/properscoring/properscoring">https://github.com/properscoring/properscoring</ext-link></mixed-citation>
  </ref>
</ref-list>
</back>
</article>
