# `causalis.scenarios.synthetic_control._utils`

## Module Contents

### Functions

`rmse` | Compute root mean squared error.
`project_to_simplex` | Project a vector onto the probability simplex.
`solve_linear_system` | Solve a linear system with least-squares fallback.
`circular_shift_indices` | Generate circular-shift index permutations.
`cwz_stat_from_residuals` | Compute CWZ post-window residual aggregation statistic.
`accepted_segments` | Convert a boolean acceptance mask into contiguous grid segments.
`build_average_att_blocks` | Build consecutive pre-period holdout blocks for average ATT inference.

### API

causalis.scenarios.synthetic_control._utils.rmse(values: numpy.ndarray) → float

  Compute root mean squared error.

  Parameters

  values : numpy.ndarray Input array-like values. The input is flattened before computation.

  Returns

  float Root mean squared error. Returns `0.0` for empty input.

causalis.scenarios.synthetic_control._utils.project_to_simplex(values: numpy.ndarray) → numpy.ndarray

  Project a vector onto the probability simplex.

  The simplex is defined as non-negative vectors whose entries sum to one.

  Parameters

  values : numpy.ndarray One-dimensional coefficient vector.

  Returns

  numpy.ndarray Projected vector with non-negative entries summing to one.

  Raises

  ValueError If the input is empty or contains non-finite values.

causalis.scenarios.synthetic_control._utils.solve_linear_system(a: numpy.ndarray, b: numpy.ndarray) → numpy.ndarray

  Solve a linear system with least-squares fallback.

  Parameters

  a : numpy.ndarray Coefficient matrix. b : numpy.ndarray Right-hand side vector or matrix.

  Returns

  numpy.ndarray Exact solution when `a` is non-singular, otherwise least-squares solution.

causalis.scenarios.synthetic_control._utils.circular_shift_indices(n_total: int) → list[numpy.ndarray]

  Generate circular-shift index permutations.

  Parameters

  n_total : int Sequence length.

  Returns

  list[numpy.ndarray] All `n_total` circular shifts of `arange(n_total)`.

causalis.scenarios.synthetic_control._utils.cwz_stat_from_residuals(residuals: numpy.ndarray, *, n_pre: int) → float

  Compute CWZ post-window residual aggregation statistic.

  Parameters

  residuals : numpy.ndarray Residual vector containing pre-period entries first, then post-period entries. n_pre : int Number of pre-period residuals.

  Returns

  float `|sum(post_residuals)| / sqrt(n_post)`.

  Raises

  ValueError If `n_pre` does not satisfy `1 <= n_pre < len(residuals)`.

causalis.scenarios.synthetic_control._utils.accepted_segments(grid: numpy.ndarray, accepted_mask: numpy.ndarray) → list[tuple[float, float]]

  Convert a boolean acceptance mask into contiguous grid segments.

  Parameters

  grid : numpy.ndarray One-dimensional, ordered grid of candidate parameter values. accepted_mask : numpy.ndarray Boolean mask with the same length as `grid`.

  Returns

  list[tuple[float, float]] Closed intervals corresponding to contiguous accepted regions.

  Raises

  ValueError If `grid` and `accepted_mask` are not one-dimensional arrays of the same length.

causalis.scenarios.synthetic_control._utils.build_average_att_blocks(*, n_pre: int, n_post: int, n_folds: int) → tuple[list[numpy.ndarray], int, int]

  Build consecutive pre-period holdout blocks for average ATT inference.

  Parameters

  n_pre : int Number of pre-treatment periods `T0`. n_post : int Number of post-treatment periods `T1`. n_folds : int Requested number of folds `K`.

  Returns

  tuple[list[numpy.ndarray], int, int] `(blocks, k_used, block_length)` where `blocks` are consecutive holdout indices over the pre-period.

  Notes

  If `n_pre` is not divisible by `k_used`, the rule `r = min(floor(T0 / K), T1)` is applied on the first `K * r` periods. Remaining pre-periods are included in every fold’s training subset.

  Raises

  ValueError If the configuration cannot produce at least two folds and a positive holdout block length.