Convert a dictionary whose keys are pairs (k1, k2) into a sparse
    or incomplete array.

    Parameters
    ----------
    pair_dict : dict
        Dictionary from pairs of keys to values.

    array_fn : function
        Takes shape and dtype as arguments, returns empty array.

    dtype : dtype
        NumPy dtype of result array

    square_result : bool
        Combine keys from rows and columns

    Returns array and sorted lists of the row and column keys.

def array_from_pair_dictionary(
        pair_dict,
        array_fn,
        dtype="float32",
        square_result=False):
    """
    Convert a dictionary whose keys are pairs (k1, k2) into a sparse
    or incomplete array.

    Parameters
    ----------
    pair_dict : dict
        Dictionary from pairs of keys to values.

    array_fn : function
        Takes shape and dtype as arguments, returns empty array.

    dtype : dtype
        NumPy dtype of result array

    square_result : bool
        Combine keys from rows and columns

    Returns array and sorted lists of the row and column keys.
    """
    row_key_set, column_key_set = pair_dict_key_sets(pair_dict)

    if square_result:
        combined_key_set = row_key_set.union(column_key_set)
        row_key_list = column_key_list = list(sorted(combined_key_set))
        row_key_indices = column_key_indices = {
            k: i for (i, k) in enumerate(row_key_list)
        }
    else:
        row_key_list = list(sorted(row_key_set))
        column_key_list = list(sorted(column_key_set))
        row_key_indices = {k: i for (i, k) in enumerate(row_key_list)}
        column_key_indices = {k: i for (i, k) in enumerate(column_key_list)}

    n_rows = len(row_key_indices)
    n_cols = len(column_key_indices)
    shape = (n_rows, n_cols)
    result = array_fn(shape, dtype)
    for (row_key, column_key), value in pair_dict.items():
        i = row_key_indices[row_key]
        j = column_key_indices[column_key]
        result[i, j] = value
    return result, row_key_list, column_key_list