# xtbreak API Reference Complete reference for the public Python API of `xtbreak`. The three entry points (`test`, `estimate`, `select`) accept time-series or panel data with covariance options `ssr`, `hc`, `hac`, `np`, and `wpn`. Panel-specific options include factor controls (`csa=`, `csanobreak=`, `kfactors=`, `nbkfactors=`, `csd=True`). The `select()` function provides oracle-backed sequential break selection; it requires caller-supplied critical values rather than shipping built-in tables. ## Runtime Dependencies The package depends on **Python ≥ 3.10** and **NumPy** at runtime. Optional: - `scipy` — Chow test p-values - `pandas` — DataFrame input/output - `matplotlib` — plotting functions Stata is used by the test suite as a numerical parity oracle but is not a runtime dependency. ## Source Authority The API follows this authority order: 1. Methodology paper: `paper/arXiv-2211.06707v2/Multiple_Breaks_Main.tex` 2. Stata software paper: `paper/arXiv-2110.14550v3/xtbreak_article.tex` 3. Stata package and fixtures: `xtbreak-2.2/` 4. Tested Python public contract ## Public API and Deprecation Policy The public API is the `xtbreak` namespace: `__all__`, `__version__`, `test`, `estimate`, `select`, result classes, and exception classes. Underscored modules (`_api`, `_result`, `_panel`, `_covariance`, `_benchmark`, `_numerics`) are internal. No deprecated aliases exist. Unsupported requests fail with `XTBreakValidationError`. Future deprecations must identify the deprecated symbol, its replacement, the first warning release, and the earliest removal release. ## Stata Migration Boundaries The Python API is a documented subset of Stata `xtbreak`, not a command-line clone. Known gaps: - `xtbreak.test(...)` does not expose Stata's full `hypothesis()`, `level`, `sequential`, `cvalue`, or built-in critical-value table surface. Public H2 and WDmax diagnostics are available through `xtbreak.select(...)` only when callers provide the required critical-value inputs. - Stata deterministic and panel-model options such as `breakconstant`, `noconstant`, and `breakfixedeffects` are not public Python keyword arguments. Users who need these designs must construct the corresponding columns explicitly in `x` or wait for a documented public API. Note: `trend` and `breaktrend` are now supported as public keyword arguments on `test()`, `estimate()`, and `select()` (see New Parameters below). - Stata `region()` and date-list breakpoint parsing with `index` or `fmt()` are not public Python surfaces. Python `breakpoints=` values are sample-axis break indexes; callers must map calendar labels outside the package. - Python post-estimation exposes JSON-safe payloads, single-break SSR path data, `regime_statistics`, `chow_tests`, `to_dataframe()`, and `break_date_labels()` where available. It does not expose a public multi-break segment-SSR matrix equivalent to Stata `e(SSRvmat)` unless `return_segment_ssr=True` is passed to `estimate()`/`select()`. - Public `vce` accepts only `ssr`, `hc`, `hac`, `np`, and `wpn`. Stata HAC routing aliases such as `kw` and `nw` are not public Python option values; use `vce="hac"` for HAC covariance requests. ## Public Entry Points The public API consists of the `xtbreak` namespace: `__all__`, `__version__`, `test`, `estimate`, `select`, result classes, and exception classes. Underscored modules are internal. Unsupported requests raise `XTBreakValidationError`. Any future deprecation must document the deprecated symbol, the replacement, the first warning release, and the earliest removal release. ### `xtbreak.test(...)` Tests for structural breaks in a time-series or panel design matrix. Current behavior: - requires raw `y` and `x` arrays; - accepts matching `entity=` and `time=` arrays for the public panel slice; - accepts `breakpoints=` for known-breakpoint `vce="ssr"` Chow/F tests and known-breakpoint `vce="hc"`/`vce="hac"` Wald tests, plus explicit-panel `vce="np"`/`vce="wpn"` Wald tests; - accepts the `vce` option; - allows `ssr`, `hac`, `hc`, `np`, and `wpn`; - raises `XTBreakValidationError` for unknown `vce` values; - returns `XTBreakResult` for `vce="ssr"` and robust `XTBreakResult` snapshots for time-series and explicit panel covariance paths; - records `metadata["df_semantics"]` so `denominator_df` and `numerator_df` are not ambiguous: SSR tests use `ssr_model_degrees_of_freedom`, while non-SSR Wald tests use `q_normalized_wald_restriction_degrees_of_freedom`; - raises `XTBreakValidationError` for time-series `np`/`wpn` because those panel covariance estimators require explicit `entity=` and `time=` arrays; - accepts panel `csa=`, `csanobreak=`, `kfactors=`, `nbkfactors=`, and `csd=True` controls, rejecting observed factors that vary across entities within a time period; SSR `test(...)` statistics count entity-specific common-factor nuisance loadings in the numerator and denominator degrees of freedom for the same factor surface used by the segment SSR objective; - accepts `nobreak_x=` only for the narrow known-break panel partial path `test(..., nobreak_x=..., breakpoints=(single,), entity=..., time=..., vce="ssr")` and the narrow single-break unknown path `test(..., nobreak_x=..., entity=..., time=..., breaks=1, vce="ssr")`; robust covariance is explicitly unsupported for panel partial `nobreak_x` and `vce="hc"`, `vce="hac"`, `vce="np"`, and `vce="wpn"` fail fast; these paths also reject multi-break tests, factor controls including `csa`, `csanobreak`, `kfactors`, `nbkfactors`, `csd`, and `fixed_effects=False`; on balanced panels they accept `reweigh=False` with the same SSR/F objective as `reweigh=True`; - rejects `csd=True` combined with manual `csa=` or `csanobreak=` because the shortcut already defines those cross-sectional-average lists; - records separate breaking and non-breaking factor metadata plus `source_governed_common_factor_covariance` for supported robust factor paths. ### `xtbreak.estimate(...)` Estimates break dates by SSR-minimizing dynamic programming, for time-series or panel data (when `entity=` and `time=` arrays are supplied). Current behavior: - accepts the same strict `vce` contract as `xtbreak.test(...)`; - accepts matching `entity=` and `time=` arrays for panel raw-data SSR execution; - accepts `nobreak_x=` only for the narrow panel partial path `estimate(..., nobreak_x=..., entity=..., time=..., breaks=1, vce="ssr")`; this path requires balanced panels with fixed effects and currently rejects robust covariance is explicitly unsupported for panel partial `nobreak_x` and `vce="hc"`, `vce="hac"`, `vce="np"`, and `vce="wpn"` fail fast; confidence-interval parity, multi-break, factor controls including `csa`, `csanobreak`, `kfactors`, `nbkfactors`, `csd`, and `fixed_effects=False` also remain unsupported; it accepts `reweigh=False` on balanced panels, where the reweighting factors are identical to `reweigh=True`; its public payload is row-order invariant and JSON-serializable through `EstimateResult.to_dict()`; CI bounds are nullable when `ci_method="not_computed_panel_partial"`; rejects `time_values=` because panel partial paths use `time=`; - maps panel break indexes to the common time axis, not raw observation rows; - records the SSR-minimizing dynamic-programming objective in `metadata["break_search_objective"]` and the source anchor in `metadata["break_search_source"]`; - does not silently fall back to SSR for unknown covariance names; - returns `EstimateResult` for supported time-series and explicit-panel covariance paths; - computes homoskedastic plug-in break-date confidence intervals for supported time-series and explicit-panel samples; pass `ci_level=` to choose the interval level, with a degenerate fallback and `ci_error` metadata when the plug-in cannot be formed; - records non-SSR covariance metadata through `metadata["covariance_estimator"]`, `metadata["bandwidth"]`, and `metadata["covariance"]`; the covariance payload is computed on the post-break unrestricted regime-interaction design and contains coefficients, standard errors, a covariance matrix, residual SSR, residual degrees of freedom, and source-governed limitation flags where applicable; - records separate `csa`, `csanobreak`, `kfactors`, `nbkfactors`, and `csd` expansion counts and `metadata["csa_covariance_status"] == "source_governed_common_factor_covariance"` when supported panel factor controls are supplied on robust paths; - exposes `metadata["solver_diagnostics"]` for the break-search design so callers can audit the normalized solver name, rank, condition number, and fallback flag without changing the current estimator contract; - raises `XTBreakValidationError` for time-series `np`/`wpn` because those panel covariance estimators require explicit `entity=` and `time=` arrays. ### `xtbreak.select(...)` Provides oracle-backed sequential break selection and selected break counts via caller-supplied critical values. This is not a built-in critical-value-table replacement. It: - accepts the same raw-data and panel axes as `xtbreak.estimate(...)`; - accepts the same panel factor controls, including `csd=True` for all-breaking RHS cross-sectional-average expansion; - accepts `nobreak_x=` only for the narrow panel partial path `select(..., nobreak_x=..., entity=..., time=..., max_breaks=1, critical_values={1: ...})`; this path evaluates one caller-supplied critical-value `F(1|0)` step from the public unknown-break panel partial statistic and currently rejects omitted or multi-break `max_breaks`, including the explicit `max_breaks=0` boundary, factor controls, `csd`, and `fixed_effects=False`; missing `critical_values` is reported before this panel partial max-breaks boundary; it accepts `reweigh=False` on balanced panels with zero statistic drift relative to `reweigh=True` and records `reweigh=False` on the selector metadata as well as the promoted estimate metadata; rejects `time_values=` because panel partial paths use `time=`; public selection has no `vce` keyword for panel partial `nobreak_x` and remains the single-step SSR selector; H2 diagnostic components use `level_critical_values` metadata when `skip_h2=False`, so their critical-value level, source, and rejection flag are separate from the sequential `critical_values` decision; - evaluates the sequential `F(k+1|k)` path up to `max_breaks`; selector step and H2 component payloads record `df_semantics="ssr_model_degrees_of_freedom"` because public selection statistics are SSR/F comparisons rather than robust Wald restrictions; - when `max_breaks` is omitted, uses the methodology-paper rule `floor(1 / trimming) - 2` from `paper/arXiv-2211.06707v2/Multiple_Breaks_Main.tex` line 374, then applies the public guard `max(1, ...)` so the omitted-default path never returns a nonpositive break count. The software paper's US example footnote uses a `ceil` convention; PyXTBreak follows the higher-authority methodology paper and records the source boundary in result metadata. The live Stata 18 `xtbreak-2.2` probe in `artifacts/verification/stata/phase40_default_maxbreaks_probe.txt` records `default_r_f_rows: 5` at `trimming=0.15`; PyXTBreak keeps the methodology-paper default of `4` and treats the Stata row count as an explicit parity boundary; - can optionally compute the H2 double-maximum diagnostic through `wdmax`; H2 diagnostic components expose critical-value level, source, rejection flag, weighted statistic, and weight from `level_critical_values` across raw-data, `common_x`, and panel partial `nobreak_x` selector paths; weighted H2 component rejection flags use the WDmax baseline critical value `level_critical_values[1]`, while unweighted H2 component rejection flags use each component's own `level_critical_values[k]`; H2 `selected_breaks` is `0` when no H2 component rejects and otherwise reports the strongest rejected H2 component count. For panel selections, sequential steps and H2/WDmax diagnostics use the same panel sample-size, fixed-effect, and common-factor nuisance degrees of freedom; - returns `BreakSelectionResult` with the evaluated steps, selected break count, selected min/max range, optional H2 payload, and optional `EstimateResult` for the selected count. In non-strict ambiguous ranges, `selected_breaks` follows the conservative lower terminal rejection used for estimate handoff while `selected_min_breaks` and `selected_max_breaks` preserve the full range. For `common_x` selections, nested promoted estimates match the conservative `selected_breaks` handoff count rather than the upper ambiguous bound, and their metadata reports the actual brute-force partial break-search algorithm. When partial structural-change confidence intervals are not computed, promoted estimates keep nullable CI bounds rather than synthetic zero-width intervals. `num_fixed_regressors` must match `common_x.shape[1]` for non-empty `common_x`; every `common_x` column enters the partial structural-change design as a non-breaking regressor and is counted in the statistic denominator degrees of freedom. A zero-column `common_x` matrix is invalid; omit `common_x` when there are no non-breaking regressors. Selector metadata records `num_fixed_regressors` and `num_breaking_regressors`, matching the non-breaking `common_x` columns and the breaking `x` columns used by the promoted estimate and sequential degrees of freedom. Common-X selections expose a dual SSR contract: selector steps and promoted estimate SSR keep the paper-style free/refit common-X objective, while `EstimateResult.ssr_path`, `ssr_path_plot_data()`, and `metadata["ssr_path_objective"]` expose the Stata `e(SSRvec)` fixed-selected-common oracle semantics used for `estat ssr` display. `BreakSelectionResult.to_dict()` preserves `selection_ssr_objective` and the nested estimate `ssr_path_objective` labels alongside the selected SSR and fixed-common SSR path values. The nested `ssr_path_objective` is present only for selected one-break estimates with an actual SSR path; multi-break common-X promoted estimates keep `ssr_path` absent and do not claim Stata `estat ssr` path semantics. Weighted and unweighted common-X H2 diagnostics expose `ssr_objective="free_common_coefficients_candidate_refit"` so diagnostic SSR values are not confused with the one-break Stata display path. Zero-break common-X selections omit promoted estimates, selected breakpoint lists, and SSR-path objective metadata, while preserving `selection_ssr_objective` and H2/component `ssr_objective` labels for evaluated diagnostics. H2 `selected_breaks` is diagnostic and independent of the conservative sequential `selected_breaks` used for promoted estimate handoff, so the two counts may differ on non-strict ambiguous selections. Strict sequential stopping does not truncate H2 diagnostics, which still evaluate the admissible hypothesis-(2) components and remain independent of promoted estimate handoff. - reports the narrow public panel partial `estimate(..., nobreak_x=...)` search as `break_search_algorithm="initialized_dynamicpartial_helper_ssr"`, matching the initialized dynamicpartial helper-matrix SSR path rather than the generic raw-data dynamic-programming optimizer. ## New Parameters (test / estimate / select) The following parameters are available on `xtbreak.test()`, `xtbreak.estimate()`, and `xtbreak.select()` unless otherwise noted: | Parameter | Type | Default | Available In | Description | |-----------|------|---------|--------------|-------------| | `data` | `pd.DataFrame \| None` | `None` | test, estimate, select | Pandas DataFrame input. When provided, `y`/`x`/`entity`/`time` should be column name strings (or lists of strings for `x`). | | `trend` | `bool` | `False` | test, estimate, select | Add a linear trend to non-breaking regressors (fixed trend across regimes). | | `breaktrend` | `bool` | `False` | test, estimate, select | Add a linear trend to breaking regressors (trend allowed to shift at breakpoints). | | `n_jobs` | `int` | `1` | estimate, select | Number of parallel workers. When >1, parallelizes the dynamic-programming break search. | | `lazy_ssr` | `bool \| None` | `None` | estimate, select | Memory optimization for segment SSR computation. `None` = auto (enabled when T > 5000), `True` = force lazy evaluation, `False` = force full matrix. | | `return_segment_ssr` | `bool` | `False` | estimate, select | When `True`, includes the full segment SSR matrix in result metadata. Not available with `lazy_ssr=True`. | | `information_criterion` | `str \| None` | `None` | select | Information criterion for model selection. Accepted values: `'bic'` or `'aic'`. When set, the selector uses the specified criterion instead of the sequential F procedure. | ## Result Containers ### `xtbreak.CommandType` `Literal["test", "estimate", "select"]` — a type alias constraining the `command` field on `XTBreakResult`, `EstimateResult`, and `BreakSelectionResult`. ### `xtbreak.XTBreakResult` Immutable snapshot container for future test results. It stores command metadata, hypothesis number, break indexes, a statistic, a p-value, critical values, and arbitrary metadata. Use `to_dict()` for JSON-safe serialization. When metadata includes any SSR/df contract field (`restricted_ssr`, `unrestricted_ssr`, `denominator_df`, `numerator_df`, or `df_semantics`), it must include the complete set: SSR values must be finite and nonnegative, unrestricted SSR cannot exceed restricted SSR, degrees of freedom must be positive integers, and `df_semantics` must be one of the documented public semantics. This keeps `xtbreak.test(...)` result payloads fail-closed instead of allowing partial or ambiguous statistical metadata. ### `xtbreak.EstimateResult` Immutable result surface for Stata-shaped `xtbreak estimate` output. It supports the current parity and documentation examples and is also returned by the first raw-data `estimate(...)` runtime slice. Create it with: ```python result = xtbreak.EstimateResult.from_break_matrices( command=payload["command"], break_matrix=payload["results"]["breaks"], ci_matrix=payload["results"]["ci"], ssr=payload["results"]["ssr"], metadata={"scenario_id": payload["scenario_id"]}, ) ``` Pass `sample_time_values=...` when an oracle or runtime result carries the full time axis. The result validates that every break index points to the same time value recorded in the Stata-shaped break matrix. For single-break `estat ssr` payloads, pass both `ssr_path` and `sample_time_values`. Phase 140 locks EstimateResult break-index order validation: break estimate indexes must be strictly increasing even when no `sample_time_values` axis is attached. Duplicate or decreasing indexes fail with `break estimate indexes must be strictly increasing.` rather than being serialized into impossible break tables or post-estimation regimes. Phase 141 locks EstimateResult time-axis validation: `sample_time_values` and `FittedSample.time_axis` entries must be strictly increasing. Duplicate or decreasing time axes fail with `sample_time_values entries must be strictly increasing.` or `time_axis entries must be strictly increasing.` so regime boundaries and `ssr_path_plot_data()` cannot contradict the ordered `t=1..T` sample index. Phase 142 locks EstimateResult terminal-break validation when a sample axis is attached: a break index must be smaller than `len(sample_time_values)` so the post-break regime is non-empty. Terminal sample-axis breaks fail with `break estimate index must leave a non-empty post-break regime.` Phase 143 locks EstimateResult CI-axis validation when a sample axis is attached: non-null confidence-interval index bounds must be positive, and confidence-interval time bounds must equal `sample_time_values` when the CI index falls on the attached axis. Positive CI bounds outside a candidate SSR axis remain allowed for source oracles whose confidence interval extends beyond that display axis. Mismatches fail with `break estimate ci_index must align with sample_time_values.` or `break estimate ci_time_value must align with sample_time_values.` Phase 144 locks EstimateResult SSR-path selected-value validation: single-break `ssr_path` payloads must have a finite value at the selected break index, and that value must match `EstimateResult.ssr` within machine precision. Missing or contradictory selected path values fail with `selected ssr_path value must match ssr.` Phase 145 locks FittedSample row-id validation: fitted-sample row IDs must be unique and hashable at construction time, because post-estimation indicator, split, and scatter payloads use them as observation identity keys. Invalid row IDs fail with `row_ids entries must be unique.` or `row_ids entries must be hashable.` Phase 146 locks FittedSample variable-name validation: fitted-sample `regressor_names` and `break_variable_names` must each be unique, because post-estimation split and scatter payloads resolve fitted columns by name. Duplicate names fail with `regressor_names entries must be unique.` or `break_variable_names entries must be unique.` Available fields: - `regime_statistics`: `tuple[RegimeStatistics, ...]` — per-regime OLS statistics (coefficients, standard errors, t-statistics, R², adjusted R², SSR) computed from the estimated break partition. Empty when regime statistics are not computed. - `chow_tests`: `tuple[ChowTestResult, ...]` — between-regime Chow F test results for coefficient equality across each pair of adjacent regimes. Empty when Chow tests are not computed. Available methods: - `to_dataframe() -> pd.DataFrame` converts regime statistics to a tidy DataFrame with one row per variable per regime, containing columns: `regime`, `variable_index`, `coefficient`, `std_error`, `t_statistic`, `regime_start`, `regime_end`, `n_obs`, `r_squared`, `adjusted_r_squared`, `ssr`. Raises `ImportError` if pandas is not installed. Returns an empty DataFrame when `regime_statistics` is empty. - `break_date_labels(time_labels=None) -> tuple[str, ...]` maps break indices to human-readable date labels. If `time_labels` (a sequence of strings matching each time period) is provided, uses those; otherwise falls back to `time_value` from each `EstimateBreak`, or formats as `"t={index}"`. - `break_table()` returns one row per break with index, time value, and confidence-interval bounds. - `plot_data()` returns breakpoint, confidence-interval, and optional sample-axis payloads for downstream plotting. - `regime_indicators()` returns a JSON-safe `command="indicator"` payload with Stata-style regime labels, row IDs, time values, optional entity values, and an explicit outside-sample policy. - `split_design()` returns a JSON-safe `command="split"` payload with regime-specific columns for fitted variables listed in `fitted_sample.break_variable_names` and any requested breaking constant; non-breaking fitted regressors are retained in the fitted sample but are not eligible for regime splitting. - `scatter_plot_data()` returns a JSON-safe `command="scatter"` payload with row-level points, regime-grouped traces, break lines, confidence intervals, legend labels, and source anchors. For common-X promoted estimates, `scatter_plot_data()` only accepts breaking variables as the x-axis variable, matching Stata `estat scatter`; non-breaking common-X regressors remain inspectable through `FittedSample` but are not valid scatter x variables. - `summary()` returns a compact text summary. - `ssr_path_plot_data()` returns a JSON-safe `command="ssr"` payload when `ssr_path` and `sample_time_values` were supplied for a single-break result. The post-estimation helpers return data only. They do not require matplotlib, plotly, or any plotting backend; callers pass the returned payloads into their own plotting or reporting tools. For promoted estimates from `select(..., common_x=..., num_fixed_regressors=common_x.shape[1])`, the fitted sample metadata distinguishes breaking `x` columns from non-breaking `common_x` columns. Default `split_design()` uses only the breaking `x` columns, and explicit requests for non-breaking `common_x` columns fail clearly instead of creating incoherent regime-specific common-X columns. `scatter_plot_data()` has the same boundary: `scatter_plot_data("common_x*")` fails because Stata `estat scatter` is defined for a variable with breaks on the x-axis. Historical non-common-X fitted-sample scatter payloads keep their existing compatibility. ### `xtbreak.BreakSelectionResult` Immutable automatic-selection payload. It stores the sequential evidence, selected break counts, optional H2 diagnostic, optional `EstimateResult`, and selection metadata. `selected_breaks` is the estimate-handoff count; in non-strict ambiguous ranges the full span remains available as `selected_min_breaks` and `selected_max_breaks`. Use `to_dict()` for JSON-safe serialization. For `common_x` selectors, nested promoted estimates match `selected_breaks`, metadata reports the actual brute-force partial break-search algorithm, and promoted estimates use nullable CI bounds when partial structural-change confidence intervals are not computed. `num_fixed_regressors` must match the number of `common_x` columns, and zero-column `common_x` designs are rejected. Top-level metadata records both `BreakSelectionResult.metadata["num_fixed_regressors"]` and `BreakSelectionResult.metadata["num_breaking_regressors"]` so serialized payloads carry the denominator and numerator regressor counts used by the selection statistics. Optional H2/WDmax diagnostic `selected_breaks` can differ from the conservative sequential `BreakSelectionResult.selected_breaks` used for promoted estimates. Strict sequential stopping does not truncate H2 diagnostics; nested H2 components continue to represent the independent hypothesis-(2) diagnostic surface. Raw-data, `common_x`, and panel partial selectors use the same public separation between sequential estimate handoff and H2 diagnostics. Strict sequential stopping can return `selected_breaks == 0` and omit a promoted estimate while the nested H2 payload still reports its independently evaluated diagnostic components. Raw-data H2 diagnostics report `ssr_objective="standard_segment_ssr_candidate_refit"`; panel partial `nobreak_x` diagnostics report `ssr_objective="initialized_dynamicpartial_helper_ssr"`. Count metadata keeps the same distinction: `selection_steps_evaluated` records returned sequential steps, `selection_statistics_computed` records evaluated selection statistics, and `h2_components_evaluated` records evaluated H2 components. Manually constructed `BreakSelectionResult` objects validate their public payloads at construction time. Break-count fields must be non-bool integers in their admissible ranges, `max_breaks` must be at least one, and selected ranges must either be zero or refer to returned sequential steps. Critical-value levels must be finite probabilities with real boolean exact-match flags, and reserved metadata mirrors such as `requested_cvalue`, `requested_level`, and `max_breaks` must match the canonical top-level fields. Positive selections may omit a promoted estimate, but a supplied `estimate` must be an `EstimateResult` whose `num_breaks` equals top-level `selected_breaks`. Sequential steps are SSR/F payloads. Each step must be a mapping with finite nonnegative SSR values, positive integer numerator and denominator degrees of freedom, `df_semantics="ssr_model_degrees_of_freedom"`, finite nonnegative `statistic`, positive finite `critical_value`, and a boolean `rejected` field that matches `statistic > critical_value`. The returned step family must be the contiguous sequence `1..len(steps)`, and `selected_min_breaks` / `selected_max_breaks` must match the step decisions under strict or non-strict selection. When present, `h2` must be a mapping, must be omitted when `skip_h2=True`, and must carry a real boolean `weighted` flag matching `wdmax`. H2 payloads include `selected_breaks` with `selected_breaks_role="h2_diagnostic_not_estimate_handoff"`, a finite top-level `statistic`, a non-empty ordered component family, and a top-level `ssr_objective` shared by all components. H2 selected-break counts are diagnostic counts: they must be nonnegative integers no larger than `max_breaks`, and they aggregate the strongest rejected component rather than overwriting the top-level estimate handoff. Each H2 component must include finite `statistic` and `weighted_statistic` fields, an integer `breaks` value in the contiguous sequence `1..len(components)`, positive finite `critical_value` and `weight`, a boolean `rejected` decision, finite nonnegative restricted and unrestricted SSR values, positive integer numerator and denominator degrees of freedom, and `df_semantics="ssr_model_degrees_of_freedom"`. Component algebra is checked: unrestricted SSR cannot exceed restricted SSR, `weighted_statistic` must equal `statistic * weight`, `rejected` must match the H2/WDmax decision rule, and the top-level H2 statistic and selected-break count must match the component evidence. ### `xtbreak.EstimateBreak` Represents one estimated break date. It stores the break number, one-based break index, time-axis value, confidence interval in indexes, and confidence interval in time values. Public constructors require positive one-based break numbers and indexes, ordered nullable confidence-interval bounds, and matching nullable index/time confidence-interval shape. Inside `EstimateResult`, break entries must be `EstimateBreak` objects with contiguous `break_number == 1..num_breaks`, and SSR plus SSR-path values must be nonnegative. ### `xtbreak.FittedSample` Immutable fitted-sample metadata used by `EstimateResult` post-estimation helpers. Runtime `estimate(...)` results populate it when fitted row IDs, time values, optional entity values, dependent values, regressor values, regressor names, break-variable names, and the aligned time axis are available. Users normally consume this through `regime_indicators()`, `split_design()`, and `scatter_plot_data()` rather than constructing it directly. Direct construction validates that `row_ids` are non-empty, unique, and hashable before serialization or post-estimation mapping. It also validates that `regressor_names` and `break_variable_names` are unique, so split and scatter helpers do not silently choose the first of multiple same-named fitted columns. ### `xtbreak.RegimeStatistics` Frozen dataclass holding per-regime OLS regression statistics computed from the estimated break partition. One instance per regime (0-based indexing). Fields: - `regime_index`: `int` — regime number (0-based). - `start_index`: `int` — first observation index in this regime. - `end_index`: `int` — end observation index (exclusive). - `n_observations`: `int` — number of observations in this regime. - `coefficients`: `tuple[float, ...]` — OLS coefficient estimates β̂_j. - `standard_errors`: `tuple[float, ...]` — standard errors SE(β̂_j). - `t_statistics`: `tuple[float, ...]` — t-statistics for each coefficient. - `r_squared`: `float` — R² for this regime. - `adjusted_r_squared`: `float` — adjusted R² for this regime. - `ssr`: `float` — regime-specific residual sum of squares. ### `xtbreak.ChowTestResult` Frozen dataclass holding the result of a between-regime Chow F test for coefficient equality across adjacent regimes. Fields: - `regime_j`: `int` — index of the first regime in the pair. - `regime_j_plus_1`: `int` — index of the second regime in the pair. - `f_statistic`: `float` — the Chow F statistic. - `p_value`: `float | None` — p-value from the F distribution (`None` if scipy unavailable). - `degrees_of_freedom`: `tuple[int, int]` — `(numerator_df, denominator_df)`. ### `xtbreak.LazySegmentSSR` Lazy SSR matrix that computes segment-level OLS residual sums of squares on demand with caching. For large T, avoids precomputing the full T×T matrix. Only segments that are actually requested are computed. Instances behave like a 2-D array (shape `(T, T+1)`, `ndim == 2`) and support `[i, j]` indexing. ```python from xtbreak import LazySegmentSSR import numpy as np y = np.random.randn(200) x = np.ones((200, 1)) ssr_matrix = LazySegmentSSR(y, x, min_segment=10) print(ssr_matrix[0, 100]) # SSR for segment [0, 100) ``` ## Plotting Functions All plotting functions require `matplotlib` as an optional dependency. ### `xtbreak.plot_breaks` ```python plot_breaks(y, *, break_indices, time_values=None, ci_indices=None, title="Structural Breaks", figsize=(12, 5), ax=None) ``` Plot a time series with vertical lines at estimated break dates and optional confidence-interval shading. Returns the matplotlib `Figure`. ### `xtbreak.plot_regime_fit` ```python plot_regime_fit(y, x, *, break_indices, time_values=None, title="Regime-Specific Fitted Values", figsize=(12, 5), ax=None) ``` Plot raw data with per-regime OLS fitted values (different colors per regime). Returns the matplotlib `Figure`. ### `xtbreak.plot_ssr_path` ```python plot_ssr_path(ssr_path, *, time_values=None, break_index=None, title="SSR Path (Single Break)", figsize=(10, 5), ax=None) ``` Plot the SSR path for single-break estimation, showing SSR as a function of candidate break position with a vertical line at the optimal break. Returns the matplotlib `Figure`. ## Utility Functions ### `xtbreak.get_blas_info` ```python get_blas_info() -> dict[str, str] ``` Detect the BLAS library backing NumPy operations. Returns a dict with keys `'library'` (mkl, openblas, accelerate, blas, or unknown), `'version'`, and `'threading'`. ### `xtbreak.recommend_blas_optimization` ```python recommend_blas_optimization() -> str | None ``` Return an optimization recommendation string if a suboptimal BLAS is detected. Returns `None` when an optimized BLAS (MKL, OpenBLAS, Accelerate) is already in use. ### `xtbreak.LazySegmentSSR` Lazy SSR matrix that computes segment-level OLS residual sums of squares on demand with caching. For large T, avoids precomputing the full T×T matrix. Only segments that are actually requested are computed. Instances behave like a 2-D array (shape `(T, T+1)`, `ndim == 2`) and support `[i, j]` indexing. ```python from xtbreak import LazySegmentSSR import numpy as np y = np.random.randn(200) x = np.ones((200, 1)) ssr_matrix = LazySegmentSSR(y, x, min_segment=10) print(ssr_matrix[0, 100]) # SSR for segment [0, 100) ``` ## Plotting Functions All plotting functions require `matplotlib` as an optional dependency. ### `xtbreak.plot_breaks` ```python plot_breaks(y, *, break_indices, time_values=None, ci_indices=None, title="Structural Breaks", figsize=(12, 5), ax=None) ``` Plot a time series with vertical lines at estimated break dates and optional confidence-interval shading. Returns the matplotlib `Figure`. ### `xtbreak.plot_regime_fit` ```python plot_regime_fit(y, x, *, break_indices, time_values=None, title="Regime-Specific Fitted Values", figsize=(12, 5), ax=None) ``` Plot raw data with per-regime OLS fitted values (different colors per regime). Returns the matplotlib `Figure`. ### `xtbreak.plot_ssr_path` ```python plot_ssr_path(ssr_path, *, time_values=None, break_index=None, title="SSR Path (Single Break)", figsize=(10, 5), ax=None) ``` Plot the SSR path for single-break estimation, showing SSR as a function of candidate break position with a vertical line at the optimal break. Returns the matplotlib `Figure`. ## Utility Functions ### `xtbreak.get_blas_info` ```python get_blas_info() -> dict[str, str] ``` Detect the BLAS library backing NumPy operations. Returns a dict with keys `'library'` (mkl, openblas, accelerate, blas, or unknown), `'version'`, and `'threading'`. ### `xtbreak.recommend_blas_optimization` ```python recommend_blas_optimization() -> str | None ``` Return an optimization recommendation string if a suboptimal BLAS is detected. Returns `None` when an optimized BLAS (MKL, OpenBLAS, Accelerate) is already in use. ## Exceptions ### `xtbreak.XTBreakError` Base package exception. ### `xtbreak.XTBreakValidationError` Raised for invalid user-facing options or malformed matrix-shaped result payloads. ## Internal Modules The following modules are internal. They appear here only for auditability: - `xtbreak._segments`: segment-level OLS SSR and SSR matrices. - `xtbreak._breakpoints`: trimming-aware breakpoint enumeration. - `xtbreak._dynamic`: dynamic-programming break search and brute-force oracles. - `xtbreak._statistics`: SSR-based known-break F, `supF`, double-maximum, and additional-break statistics. - `xtbreak._critical`: critical-value records and sequential decision helpers. - `xtbreak._result`: result containers and Stata-shaped estimate hydration. - `xtbreak._confidence`: homoskedastic plug-in break-date confidence intervals for the current time-series and explicit-panel raw-data estimate slices. - `xtbreak._panel`: panel indexing, fixed-effect transforms, cross-section averages, panel segment SSR, and panel covariance grids. - `xtbreak._covariance`: SSR, HC0, Bartlett HAC OLS covariance helpers, plus explicit-panel `np` and `wpn` covariance helpers. - `xtbreak._partial`: partial structural-change search where selected regressors break and common regressors do not. Outside the narrow single-break balanced-panel fixed-effects `vce="ssr"` `nobreak_x` slice, panel raw-data partial structural-change requests that require Stata `nobreakvariables(...)` semantics remain a public validation boundary. The Phase 45 crosswalk at `.planning/phases/45-panel-partial-structural-change-crosswalk/45-CONTEXT.md` records the methodology-paper `x`/`w` split, Stata `dynamicpartial` handoff, and future oracle prerequisites. Internal module names and signatures can still change before a public release.