Skip to content

fix: correct merger premium indexing, crisis correlation loss, and noise bound API - #3

Merged
hongjin-he merged 1 commit into
hongjin-he:mainfrom
Shoryamishra61:fix/event-operator-bugs
Aug 3, 2026
Merged

fix: correct merger premium indexing, crisis correlation loss, and noise bound API#3
hongjin-he merged 1 commit into
hongjin-he:mainfrom
Shoryamishra61:fix/event-operator-bugs

Conversation

@Shoryamishra61

@Shoryamishra61 Shoryamishra61 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

Three bugs affect core financial event operators and the dual-noise module:

  1. merger_operator data corruption — the deal premium, volume spike, leverage shift, and elevated price uncertainty were hardcoded at output row 0. With a nonzero acquirer index, these shifts silently landed on an unrelated pass-through asset.
  2. systemic_crisis_operator silent math error — the implementation constructed cross-asset price covariance, then discarded every off-diagonal through np.diag(...). Crisis simulations therefore generated independent rather than correlated asset moves.
  3. DualNoiseParams.cramer_rao_bound API defect — the function was decorated with @property despite accepting h, making the horizon inaccessible and causing explicit calls to raise TypeError.

Closes #2.

Root cause

  • Merger shifts used b[0 * d + ...] instead of tracking the acquirer's row after the target is removed.
  • np.diag(matrix) extracted the diagonal before the noise factor was rebuilt, erasing the intended price covariance.
  • Python properties cannot accept call-time parameters.
  • state/noise.py also retained an unused import and imprecise NumPy return annotations that produced editor/static-analysis errors.

Implementation

  • Compute acq_out_idx from the merger output mapping and use it for the premium, volume, leverage, and price-uncertainty entries.
  • Build a proper covariance matrix with the original variance on every state component and severity-dependent cross-asset correlation only in the price block, then use its Cholesky factor as Sigma_w.
  • Remove @property from cramer_rao_bound, retaining h=1.0 as the default.
  • Make the NumPy array/float return types in state/noise.py explicit and remove the unused import.

Why this approach

The patch is local to the faulty indexing, covariance construction, and API declaration. It adds no dependency and preserves the operator equation T_w(s) = A_w s + b_w + Sigma_w epsilon. Cholesky factorization is used because Sigma_w @ Sigma_w.T must reproduce the desired covariance rather than storing covariance entries directly as noise coefficients.

Before and after

  • Before: a merger with acquirer_idx != 0 modifies output row 0. After: all deal shifts follow the acquirer into its output row.
  • Before: crisis price covariance is diagonal. After: price correlation is rho = 0.5 + 0.4 * severity.
  • Before: params.cramer_rao_bound(h=5) raises TypeError. After: it returns (sigma_tau^2 + lambda_eta * m2_eta) * 5.

Tests

Eleven regression tests cover:

  • merger premium placement and backward compatibility
  • volume and leverage placement
  • nonzero crisis cross-asset correlation
  • covariance validity and preserved component variance
  • severity/correlation monotonicity
  • the single-asset edge case
  • callable/default/scaling/formula behavior for the Cramér-Rao bound

Commands run:

python -m pytest tests/test_noise.py tests/test_events.py -q
46 passed

python -m pytest tests/ -q
61 passed, 6 pre-existing warnings

uv run --python 3.11 --with numpy --with scipy --with pytest python -m pytest tests/ -q
61 passed, 6 pre-existing warnings

uv run --python 3.12 --with numpy --with scipy --with pytest python -m pytest tests/ -q
61 passed, 6 pre-existing warnings

python -m mypy state/noise.py --strict
Success: no issues found in 1 source file

python -m ruff check state/noise.py tests/test_noise.py
All checks passed

python -m py_compile state/noise.py events/operators.py
passed

python -c "<CI import checks>"
noise OK
events OK
features OK

The six warnings come from the pre-existing build_feature_matrix NaN handling and are unrelated to this patch.

Compatibility, performance, and risk

  • merger_operator(acquirer_idx=0, ...) is unchanged.
  • No in-repository caller uses cramer_rao_bound; the corrected method form therefore has no internal migration.
  • Cholesky factorization is O((nd)^3), but these event matrices are constructed once per event and are small in existing usage.
  • Non-price crisis components keep their original independent variance; only price components gain cross-asset correlation.
  • No dependency, data, serialization, security, or device-placement behavior changes.

Reviewer notes

The eleven tests were checked against the original behaviors: the primary regression assertions fail before the patch and pass after it. The final diff is limited to events/operators.py, state/noise.py, and their two test modules.

Copilot AI review requested due to automatic review settings July 29, 2026 17:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes three correctness defects in the financial event operator algebra and dual-noise utilities: (1) merger operator output-row indexing for deal-related shifts, (2) systemic crisis operator losing intended cross-asset price correlation, and (3) an invalid @property API on DualNoiseParams.cramer_rao_bound. It also adds regression tests to prevent reintroducing these behaviors.

Changes:

  • Fix merger_operator to apply premium/volume/leverage/price-uncertainty shifts at the acquirer’s output row rather than hardcoded row 0.
  • Rework systemic_crisis_operator noise construction to preserve variances while introducing cross-asset correlation in the price block via a Cholesky factor.
  • Convert DualNoiseParams.cramer_rao_bound from a property to a callable method and tighten NumPy typing/return types in state/noise.py; add regression tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
events/operators.py Fixes merger output indexing and rebuilds systemic crisis noise to include cross-asset price correlation via Cholesky.
state/noise.py Fixes cramer_rao_bound API and improves NumPy typing/explicit float returns.
tests/test_events.py Adds regression tests covering merger indexing and systemic crisis cross-asset correlation/PSD/edge cases.
tests/test_noise.py Adds regression tests for callable/default/scaling/formula behavior of cramer_rao_bound.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread events/operators.py
Comment on lines 492 to +494
rho = 0.5 + 0.4 * severity
Sigma = np.zeros((n * d, n * d))
sigma_p = severity * 0.08 # per-asset price std dev
Cov = np.eye(n * d) * sigma_p ** 2
Comment thread state/noise.py
Comment on lines 32 to 34
def cramer_rao_bound(self, h: float = 1.0) -> float:
"""Prediction variance lower bound for horizon h (Theorem III.1)."""
return (self.sigma_tau**2 + self.lambda_eta * self.m2_eta) * h
Comment thread events/operators.py
Comment on lines +629 to +634
# Compute acquirer's output row index
acq_out_idx = 0
for i in range(acquirer_idx):
if i != target_idx:
acq_out_idx += 1

@hongjin-he
hongjin-he merged commit f812318 into hongjin-he:main Aug 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect merger indexing, crisis covariance, and Cramér-Rao horizon API

3 participants