Skip to content

Eqcorr2d API Reference

The below contains documentation for all relevant functions available for import with the eqcorr2d package.

High-Level Interface

The eqcorr2d_interface module provides a user-friendly Python wrapper around the C engine with support for geometric rotations and result aggregation.

eqcorr2d.eqcorr2d_interface

High-level Python interface around the eqcorr2d C engine.

This module provides a thin but well-documented wrapper that: - Accepts dictionaries of binary handle/antihandle occupancy arrays (1D or 2D) keyed by user-facing identifiers. - Orchestrates optional geometric rotations in Python (0/90/180/270 for square lattices; 0/60/120/180/240/300 for triangular lattices) by pre-rotating the antihandle arrays before delegating to the C engine. The C core always computes for a fixed orientation; we rotate inputs instead of changing the core. - Aggregates per-rotation outputs into a single, stable result dictionary that is easier to consume than the legacy tuple.

Key terms: - handle_dict: dict[key -> np.ndarray] of uint8 with shape (H, W) or (L,) for 1D slats. Non-zero entries indicate occupied positions. - antihandle_dict: same as handle_dict, but for the opposing set. - "matchtype": an integer bin used by the C engine to bucket similarity counts. Larger values typically represent worse similarity.

Modes: - classic: only 0° and 180° rotations (historical behavior for 1D slats). - square_grid: 0°, 90°, 180°, 270°. - triangle_grid: 0°, 60°, 120°, 180°, 240°, 300° (implemented via rotate_array_tri60).

Smart mode (do_smart): - If enabled, we still compute 0°/180°. - For square_grid, 90°/270° are only computed when at least one side of a pair is truly 2D (H >= 2 and W >= 2). This keeps compute costs lower for pure 1D data. - For triangle_grid, the same idea applies to the six-fold rotation set.

Note: This module adds extensive comments and docstrings only. The C code is not modified by this interface.

comprehensive_score_analysis

comprehensive_score_analysis(
    handle_dict,
    antihandle_dict,
    match_counts,
    connection_graph,
    connection_angle,
    do_worst=False,
    fudge_dg=10,
    request_similarity_score=True,
)

Compute all relevant match count metrics for a megastructure's slat handles.

When provided with a megastructure's slat handles/antihandles and connection graphs, this function computes all relevant match count metrics including worst match, mean log score, similarity score, and a compensated match histogram.

PARAMETER DESCRIPTION
handle_dict

Dictionary mapping slat identifiers to handle arrays (can be 1D or 2D uint8 arrays).

TYPE: dict[Any, ndarray]

antihandle_dict

Dictionary mapping slat identifiers to antihandle arrays (can be 1D or 2D uint8 arrays).

TYPE: dict[Any, ndarray]

match_counts

Dictionary with counts of expected matches due to connections between slats. Keys are match counts (int), values are the number of such matches expected.

TYPE: dict[int, int]

connection_graph

Dictionary mapping match types to lists of (handle_key, antihandle_key) pairs that are expected to match due to connections.

TYPE: dict[int, list[tuple]]

connection_angle

Either '60' or '90' indicating the connection geometry (triangular or square grid).

TYPE: str

do_worst

If True, return which slat pairs contributed to the worst match score. Defaults to False.

TYPE: bool DEFAULT: False

fudge_dg

Fudge factor for mean log score computation. Defaults to 10.

TYPE: float DEFAULT: 10

request_similarity_score

If True, computes a similarity score to check for slat duplication risk. Defaults to True.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
dict

Dictionary containing:

  • worst_match_score (int): The highest non-zero match count in the compensated histogram.
  • mean_log_score (float): Logarithmic weighted score normalized by number of pairs.
  • match_histogram (numpy.ndarray): Compensated histogram of match counts.
  • uncompensated_match_histogram (numpy.ndarray): Raw histogram before connection compensation.
  • similarity_score (int, optional): Highest match count within handle/antihandle sets (if requested).
  • worst_slat_combos (list, optional): List of (handle_key, antihandle_key, count) tuples (if do_worst=True).

compensate_histogram

compensate_histogram(hist, connection_hist)

Subtract the connection occupancy from the total histogram safely.

Handles unequal lengths by padding the shorter array with zeros.

PARAMETER DESCRIPTION
hist

The total match histogram to compensate.

TYPE: ndarray

connection_hist

Histogram of expected matches due to slat connections.

TYPE: ndarray

RETURNS DESCRIPTION
numpy.ndarray

Compensated histogram with connection matches subtracted.

RAISES DESCRIPTION
ValueError

If subtraction noflank_results in negative values (over-subtraction).

make_connection_histogram

make_connection_histogram(connection_graph)

Create a histogram from a connection graph.

PARAMETER DESCRIPTION
connection_graph

Dictionary mapping match types (int) to lists of connection pairs.

TYPE: dict[int, list]

RETURNS DESCRIPTION
numpy.ndarray

Histogram where each index corresponds to a match type and the value is the number of connections for that type.

wrap_eqcorr2d

wrap_eqcorr2d(
    handle_dict,
    antihandle_dict,
    mode="classic",
    hist=True,
    local_histogram=False,
    report_full=False,
    do_smart=False,
)

Run eqcorr2d on all handle/antihandle pairs, optionally across rotations.

This function is the preferred high-level entry point. It accepts two dictionaries mapping arbitrary keys (e.g., slat ids) to binary occupancy arrays, prepares them for the low-level C engine, optionally pre-rotates the antihandles for the requested angle set, and then aggregates all outputs into a single, well-structured result dictionary.

PARAMETER DESCRIPTION
handle_dict

Dictionary mapping keys to binary arrays (uint8), either 1D with shape (L,) or 2D with shape (H, W). Non-zeros mark occupied positions. Each array is converted to C-contiguous uint8 and reshaped to (1, L) for 1D inputs.

TYPE: dict[Any, ndarray]

antihandle_dict

Same rules as handle_dict, but for the opposing handle set.

TYPE: dict[Any, ndarray]

mode

Rotation mode determining which angles are computed:

  • 'classic': [0, 180] degrees only
  • 'square_grid': [0, 90, 180, 270] degrees
  • 'triangle_grid': [0, 60, 120, 180, 240, 300] degrees

Defaults to 'classic'.

TYPE: str DEFAULT: 'classic'

hist

If True, request histogram accumulation from the C engine. The top-level 'hist_total' returned is the sum across all considered rotations. Defaults to True.

TYPE: bool DEFAULT: True

local_histogram

If True, compute per-pair histograms in addition to the global histogram. Results stored in 'local_hist_total'. Defaults to False.

TYPE: bool DEFAULT: False

report_full

If True, per-rotation raw outputs are included under result['rotations'][angle]['full']. Defaults to False.

TYPE: bool DEFAULT: False

do_smart

Heuristic compute saver. For square/triangle grids, 90°/270° (and the non-axial 60° steps) are only evaluated for pairs where at least one operand is truly 2D (H >= 2 and W >= 2). 0°/180° are always evaluated. Defaults to False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
dict .. note:: The low-level C engine always computes a single orientation. Rotations are handled by pre-rotating the antihandle arrays before calling the C engine. For triangle_grid, rotations are performed via :func:`rotate_array_tri60`.

Dictionary containing:

  • angles (list[int]): Angles actually computed.
  • hist_total (numpy.ndarray or None): Summed histogram if hist=True.
  • rotations (dict): Per-rotation data (if report_full=True).
  • handle_keys (list): Keys from handle_dict in order.
  • anti_handle_keys (list): Keys from antihandle_dict in order.
  • local_hist_total (numpy.ndarray or None): 3D array (nA, nB, L) if local_histogram=True.

get_worst_match

get_worst_match(c_results)

Return the worst (highest non-zero) matchtype from a result.

PARAMETER DESCRIPTION
c_results

Result dictionary from :func:wrap_eqcorr2d containing 'hist_total'.

TYPE: dict

RETURNS DESCRIPTION
int | None

The highest non-zero bin index in the histogram, or None if histogram is empty.

get_sum_score

get_sum_score(c_results, fudge_dg=10)

Compute an exponentially weighted sum score from histogram.

The score is computed as: sum(count * exp(fudge_dg * matchtype)) for all bins.

PARAMETER DESCRIPTION
c_results

Result dictionary from :func:wrap_eqcorr2d containing 'hist_total'.

TYPE: dict

fudge_dg

Exponential weighting factor. Higher values penalize high match counts more. Defaults to 10.

TYPE: float DEFAULT: 10

RETURNS DESCRIPTION
float

Weighted sum score.

get_seperate_worst_lists

get_seperate_worst_lists(c_results)

Return separate lists of worst handle and antihandle identifiers.

Extracts the handle and antihandle keys that contributed to the worst (highest) match count bin.

PARAMETER DESCRIPTION
c_results

Result dictionary from :func:wrap_eqcorr2d containing 'hist_total', 'handle_keys', 'anti_handle_keys', and 'local_hist_total'.

TYPE: dict

RETURNS DESCRIPTION
tuple[list, list] | tuple[None, None]

Tuple of (handle_list, antihandle_list) where each list contains the keys that contributed to the worst match bin. Returns (None, None) if required data is missing.

get_worst_keys_combos

get_worst_keys_combos(c_results)

Return a list of key pairs that contributed to the global worst histogram bin.

Relies on the 'local_hist_total' 3D array of shape (nA, nB, L) and the key lists.

PARAMETER DESCRIPTION
c_results

Result dictionary from :func:wrap_eqcorr2d containing 'hist_total', 'handle_keys', 'anti_handle_keys', and 'local_hist_total'.

TYPE: dict

RETURNS DESCRIPTION
list[tuple] | None

List of (handle_key, antihandle_key, count) tuples for pairs that contributed to the worst match bin. Returns None if required data is missing.

get_compensated_worst_keys_combos

get_compensated_worst_keys_combos(c_results, connection_graph)

Return worst key pairs after compensating for expected connections.

Similar to :func:get_worst_keys_combos, but subtracts expected matches from the connection graph to identify truly problematic pairs.

PARAMETER DESCRIPTION
c_results

Result dictionary from :func:wrap_eqcorr2d containing 'hist_total', 'handle_keys', 'anti_handle_keys', and 'local_hist_total'.

TYPE: dict

connection_graph

Dictionary mapping match types to lists of expected (handle_key, antihandle_key) connection pairs.

TYPE: dict[int, list[tuple]]

RETURNS DESCRIPTION
list[tuple]

List of (handle_key, antihandle_key, adjusted_count) tuples for pairs that contributed to the worst match bin after compensation.

RAISES DESCRIPTION
ValueError

If over-subtraction is detected (more skips than actual matches).

RuntimeError

If expected skips don't match found pairs.

get_similarity_hist

get_similarity_hist(handle_dict, antihandle_dict, mode='square_grid', do_smart=True)

Build a library-level similarity histogram (handles+antihandles).

This helper runs :func:wrap_eqcorr2d twice, once within the handle set and once within the antihandle set, then sums the resulting histograms. Finally it subtracts a simple self-match correction so that exact self-pairs do not inflate the counts.

PARAMETER DESCRIPTION
handle_dict

Dictionary mapping keys to handle arrays.

TYPE: dict[Any, ndarray]

antihandle_dict

Dictionary mapping keys to antihandle arrays.

TYPE: dict[Any, ndarray]

mode

Rotation mode for comparisons. One of 'classic', 'square_grid', or 'triangle_grid'. Defaults to 'square_grid'.

TYPE: str DEFAULT: 'square_grid'

do_smart

If True, skip unnecessary rotation computations for 1D arrays. Defaults to True.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
dict .. note:: The self-match correction subtracts one count at matchtype = number of nonzeros for each individual array.

Dictionary containing:

  • hist_total (numpy.ndarray): Combined similarity histogram with self-match correction.
  • angles (list): Empty list (no per-rotation info for this helper).
  • rotations (dict): Empty dict.
  • worst_keys_combos (None): Not computed for similarity analysis.

Slat Standardized Mapping

Utilities for converting slat data into standardized formats for the C engine.

eqcorr2d.slat_standardized_mapping

convert_to_triangular

convert_to_triangular(coord)

Convert Cartesian coordinates to triangular lattice coordinates.

Applies the transformation: x(new) = (x+y)/2, y(new) = -x

PARAMETER DESCRIPTION
coord

Tuple of (y, x) Cartesian coordinates.

TYPE: tuple[int, int]

RETURNS DESCRIPTION
tuple[int, int]

Tuple of (y_new, x_new) triangular coordinates.

convert_triangular_coords_to_array

convert_triangular_coords_to_array(coords)

Convert a list of triangular coordinates into a numpy array.

Creates a 2D array where each coordinate position contains its 1-based index. Coordinates are shifted so the minimum values become 0.

PARAMETER DESCRIPTION
coords

List of (x, y) coordinate tuples in triangular space.

TYPE: list[tuple[int, int]]

RETURNS DESCRIPTION
numpy.ndarray

2D array with coordinate positions marked by their 1-based indices.

generate_standardized_slat_handle_array

generate_standardized_slat_handle_array(slat_1D_array, slat_type)

Map slat handles to a standardized 2D shape for match calculations.

Given a list of slat handles in order, assigns handles to their corresponding standardized slat shape, which can then be used downstream in handle match valency calculations.

PARAMETER DESCRIPTION
slat_1D_array

1D numpy array containing slat handle values in order.

TYPE: ndarray

slat_type

Slat type identifier (e.g., 'DB-L-120', 'DB-L-60', 'DB-R-60', 'DB-R-120'). Must be a key in :data:standardized_slat_mappings.

TYPE: str

RETURNS DESCRIPTION
numpy.ndarray

2D numpy array containing slat handles arranged in standardized shape.

Triangular Grid Rotation Utilities

Rotation utilities for triangular (60°) grid geometries.

eqcorr2d.rot60

rotate_coords_tri60

rotate_coords_tri60(i: ndarray, j: ndarray, k: int = 1)

Rotate lattice coordinates by k×60° on a triangular (axial) grid.

This implements the closed-form rotations for the axial coordinate system commonly used with triangular/hexagonal grids. It is fully vectorized and supports broadcasting; i and j can be scalars or arrays of the same shape.

The six distinct rotations (k mod 6) are:

  • R: (i, j) -> (-j, i + j)
  • R^2: (i, j) -> (-(i+j), i)
  • R^3: (i, j) -> (-i, -j)
  • R^4: (i, j) -> (j, -i - j)
  • R^5: (i, j) -> (i + j, -i)
  • R^0: identity (i, j)
PARAMETER DESCRIPTION
i

Row indices in the axial coordinate system. Can be scalar or array.

TYPE: ndarray

j

Column indices in the axial coordinate system. Must be broadcastable with i.

TYPE: ndarray

k

Number of 60° rotation steps. Can be any integer; reduced mod 6 internally. Defaults to 1.

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
tuple[numpy.ndarray, numpy.ndarray]

Tuple (x, y) of rotated coordinates with the same broadcasted shape as inputs.

rotate_array_tri60

rotate_array_tri60(
    arr: ndarray, k: int = 1, map_only_nonzero: bool = False, return_shift: bool = False
)

Rotate a 2D occupancy array by k×60° on a triangular lattice.

The array is assumed to live on axial coordinates (i=row, j=col). Rotation is implemented by transforming indices, shifting them to be non-negative, and scattering values into a tightly sized output array.

PARAMETER DESCRIPTION
arr

2D input array (e.g., uint8 occupancy). The dtype and sparsity are preserved in the output; shape generally changes with rotation.

TYPE: ndarray

k

Number of 60° rotation steps. Any integer; reduced mod 6 internally. Defaults to 1.

TYPE: int DEFAULT: 1

map_only_nonzero

If True, only non-zero entries are transformed and written, which is typically faster for sparse integer masks. Defaults to False.

TYPE: bool DEFAULT: False

return_shift

If True, returns a tuple (rotated, shift_x, shift_y) where shift_* are the offsets added to make all indices >= 0. Defaults to False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
numpy.ndarray | tuple[numpy.ndarray, int, int] .. note:: Because rotation is done in index space, the output shape depends on k and the input's footprint on the lattice. Expect different bounding boxes.

Rotated array, optionally with integer shifts if return_shift=True.