# DO NOT MODIFY: this is automatically generated by the cpptypes

import os
import ctypes as ct
import numpy as np

def _catch_errors(f):
    def wrapper(*args):
        errcode = ct.c_int32(0)
        errmsg = ct.c_char_p(0)
        output = f(*args, ct.byref(errcode), ct.byref(errmsg))
        if errcode.value != 0:
            msg = errmsg.value.decode('ascii')
            lib.free_error_message(errmsg)
            raise RuntimeError(msg)
        return output
    return wrapper

# TODO: surely there's a better way than whatever this is.
dirname = os.path.dirname(os.path.abspath(__file__))
contents = os.listdir(dirname)
lib = None
for x in contents:
    if x.startswith('_core') and not x.endswith("py"):
        lib = ct.CDLL(os.path.join(dirname, x))
        break

if lib is None:
    raise ImportError("failed to find the _core.* module")

lib.free_error_message.argtypes = [ ct.POINTER(ct.c_char_p) ]

def _np2ct(x, expected, contiguous=True):
    if not isinstance(x, np.ndarray):
        raise ValueError('expected a NumPy array')
    if x.dtype != expected:
        raise ValueError('expected a NumPy array of type ' + str(expected) + ', got ' + str(x.dtype))
    if contiguous:
        if not x.flags.c_contiguous and not x.flags.f_contiguous:
            raise ValueError('only contiguous NumPy arrays are supported')
    return x.ctypes.data

lib.py_compute_column_maxs.restype = None
lib.py_compute_column_maxs.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_medians.restype = None
lib.py_compute_column_medians.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_medians_by_group.restype = None
lib.py_compute_column_medians_by_group.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_mins.restype = None
lib.py_compute_column_mins.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_nan_counts.restype = None
lib.py_compute_column_nan_counts.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_ranges.restype = None
lib.py_compute_column_ranges.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_sums.restype = None
lib.py_compute_column_sums.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_sums_by_group.restype = None
lib.py_compute_column_sums_by_group.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_column_variances.restype = None
lib.py_compute_column_variances.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_maxs.restype = None
lib.py_compute_row_maxs.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_medians.restype = None
lib.py_compute_row_medians.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_medians_by_group.restype = None
lib.py_compute_row_medians_by_group.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_mins.restype = None
lib.py_compute_row_mins.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_nan_counts.restype = None
lib.py_compute_row_nan_counts.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_ranges.restype = None
lib.py_compute_row_ranges.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_sums.restype = None
lib.py_compute_row_sums.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_sums_by_group.restype = None
lib.py_compute_row_sums_by_group.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_compute_row_variances.restype = None
lib.py_compute_row_variances.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_column.restype = None
lib.py_extract_column.argtypes = [
    ct.c_void_p,
    ct.c_int32,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_dense_full.restype = None
lib.py_extract_dense_full.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_dense_subset.restype = None
lib.py_extract_dense_subset.argtypes = [
    ct.c_void_p,
    ct.c_uint8,
    ct.c_void_p,
    ct.c_int32,
    ct.c_uint8,
    ct.c_void_p,
    ct.c_int32,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_ncol.restype = ct.c_int
lib.py_extract_ncol.argtypes = [
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_nrow.restype = ct.c_int
lib.py_extract_nrow.argtypes = [
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_row.restype = None
lib.py_extract_row.argtypes = [
    ct.c_void_p,
    ct.c_int32,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_sparse.restype = ct.c_int
lib.py_extract_sparse.argtypes = [
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_extract_sparse_subset.restype = None
lib.py_extract_sparse_subset.argtypes = [
    ct.c_void_p,
    ct.c_uint8,
    ct.c_void_p,
    ct.c_int32,
    ct.c_uint8,
    ct.c_void_p,
    ct.c_int32,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_free_mat.restype = None
lib.py_free_mat.argtypes = [
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_compressed_sparse_matrix.restype = ct.c_void_p
lib.py_initialize_compressed_sparse_matrix.argtypes = [
    ct.c_int32,
    ct.c_int32,
    ct.c_uint64,
    ct.c_char_p,
    ct.c_void_p,
    ct.c_char_p,
    ct.c_void_p,
    ct.c_void_p,
    ct.c_uint8,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_binary_isometric_op.restype = ct.c_void_p
lib.py_initialize_delayed_binary_isometric_op.argtypes = [
    ct.c_void_p,
    ct.c_void_p,
    ct.c_char_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_combine.restype = ct.c_void_p
lib.py_initialize_delayed_combine.argtypes = [
    ct.c_int32,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_subset.restype = ct.c_void_p
lib.py_initialize_delayed_subset.argtypes = [
    ct.c_void_p,
    ct.c_int32,
    ct.c_void_p,
    ct.c_int32,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_transpose.restype = ct.c_void_p
lib.py_initialize_delayed_transpose.argtypes = [
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_unary_isometric_op_simple.restype = ct.c_void_p
lib.py_initialize_delayed_unary_isometric_op_simple.argtypes = [
    ct.c_void_p,
    ct.c_char_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_unary_isometric_op_with_scalar.restype = ct.c_void_p
lib.py_initialize_delayed_unary_isometric_op_with_scalar.argtypes = [
    ct.c_void_p,
    ct.c_char_p,
    ct.c_bool,
    ct.c_double,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_delayed_unary_isometric_op_with_vector.restype = ct.c_void_p
lib.py_initialize_delayed_unary_isometric_op_with_vector.argtypes = [
    ct.c_void_p,
    ct.c_char_p,
    ct.c_uint8,
    ct.c_int32,
    ct.c_void_p,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

lib.py_initialize_dense_matrix.restype = ct.c_void_p
lib.py_initialize_dense_matrix.argtypes = [
    ct.c_int32,
    ct.c_int32,
    ct.c_char_p,
    ct.c_void_p,
    ct.c_uint8,
    ct.POINTER(ct.c_int32),
    ct.POINTER(ct.c_char_p)
]

def compute_column_maxs(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_maxs)(rawmat, output, num_threads)

def compute_column_medians(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_medians)(rawmat, output, num_threads)

def compute_column_medians_by_group(rawmat, grouping, output, num_threads):
    return _catch_errors(lib.py_compute_column_medians_by_group)(rawmat, grouping, output, num_threads)

def compute_column_mins(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_mins)(rawmat, output, num_threads)

def compute_column_nan_counts(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_nan_counts)(rawmat, output, num_threads)

def compute_column_ranges(rawmat, min_output, max_output, num_threads):
    return _catch_errors(lib.py_compute_column_ranges)(rawmat, min_output, max_output, num_threads)

def compute_column_sums(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_sums)(rawmat, output, num_threads)

def compute_column_sums_by_group(rawmat, grouping, output, num_threads):
    return _catch_errors(lib.py_compute_column_sums_by_group)(rawmat, grouping, output, num_threads)

def compute_column_variances(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_column_variances)(rawmat, output, num_threads)

def compute_row_maxs(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_maxs)(rawmat, output, num_threads)

def compute_row_medians(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_medians)(rawmat, output, num_threads)

def compute_row_medians_by_group(rawmat, grouping, output, num_threads):
    return _catch_errors(lib.py_compute_row_medians_by_group)(rawmat, grouping, output, num_threads)

def compute_row_mins(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_mins)(rawmat, output, num_threads)

def compute_row_nan_counts(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_nan_counts)(rawmat, output, num_threads)

def compute_row_ranges(rawmat, min_output, max_output, num_threads):
    return _catch_errors(lib.py_compute_row_ranges)(rawmat, min_output, max_output, num_threads)

def compute_row_sums(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_sums)(rawmat, output, num_threads)

def compute_row_sums_by_group(rawmat, grouping, output, num_threads):
    return _catch_errors(lib.py_compute_row_sums_by_group)(rawmat, grouping, output, num_threads)

def compute_row_variances(rawmat, output, num_threads):
    return _catch_errors(lib.py_compute_row_variances)(rawmat, output, num_threads)

def extract_column(rawmat, c, output):
    return _catch_errors(lib.py_extract_column)(rawmat, c, output)

def extract_dense_full(rawmat, output):
    return _catch_errors(lib.py_extract_dense_full)(rawmat, output)

def extract_dense_subset(rawmat, row_noop, row_sub, row_len, col_noop, col_sub, col_len, output):
    return _catch_errors(lib.py_extract_dense_subset)(rawmat, row_noop, row_sub, row_len, col_noop, col_sub, col_len, output)

def extract_ncol(mat):
    return _catch_errors(lib.py_extract_ncol)(mat)

def extract_nrow(mat):
    return _catch_errors(lib.py_extract_nrow)(mat)

def extract_row(rawmat, r, output):
    return _catch_errors(lib.py_extract_row)(rawmat, r, output)

def extract_sparse(mat):
    return _catch_errors(lib.py_extract_sparse)(mat)

def extract_sparse_subset(rawmat, row_noop, row_sub, row_len, col_noop, col_sub, col_len, output_count, output_indices, output_values):
    return _catch_errors(lib.py_extract_sparse_subset)(rawmat, row_noop, row_sub, row_len, col_noop, col_sub, col_len, output_count, output_indices, output_values)

def free_mat(mat):
    return _catch_errors(lib.py_free_mat)(mat)

def initialize_compressed_sparse_matrix(nr, nc, nz, dtype, dptr, itype, iptr, indptr, byrow):
    return _catch_errors(lib.py_initialize_compressed_sparse_matrix)(nr, nc, nz, dtype, dptr, itype, iptr, indptr, byrow)

def initialize_delayed_binary_isometric_op(left, right, op):
    return _catch_errors(lib.py_initialize_delayed_binary_isometric_op)(left, right, op)

def initialize_delayed_combine(n, ptrs, dim):
    return _catch_errors(lib.py_initialize_delayed_combine)(n, ptrs, dim)

def initialize_delayed_subset(ptr, dim, subset, len):
    return _catch_errors(lib.py_initialize_delayed_subset)(ptr, dim, _np2ct(subset, np.int32), len)

def initialize_delayed_transpose(ptr):
    return _catch_errors(lib.py_initialize_delayed_transpose)(ptr)

def initialize_delayed_unary_isometric_op_simple(ptr, op):
    return _catch_errors(lib.py_initialize_delayed_unary_isometric_op_simple)(ptr, op)

def initialize_delayed_unary_isometric_op_with_scalar(ptr, op, right, arg):
    return _catch_errors(lib.py_initialize_delayed_unary_isometric_op_with_scalar)(ptr, op, right, arg)

def initialize_delayed_unary_isometric_op_with_vector(ptr, op, right, along, args):
    return _catch_errors(lib.py_initialize_delayed_unary_isometric_op_with_vector)(ptr, op, right, along, _np2ct(args, np.float64))

def initialize_dense_matrix(nr, nc, type, ptr, byrow):
    return _catch_errors(lib.py_initialize_dense_matrix)(nr, nc, type, ptr, byrow)