# Path: pyinform/error.py
# class InformError(Exception):
#     """
#     InformError signifies an error occurred in a call to inform.
#     """
# 
#     def __init__(self, e=-1, func=None):
#         msg = error_string(e)
# 
#         if func is None:
#             msg = "an inform error occurred - \"{}\"".format(msg)
#         else:
#             msg = "an inform error occurred in `{}` - \"{}\"".format(func, msg)
# 
#         super(InformError, self).__init__(msg)
# 
#         self.error_code = e if isinstance(e, ErrorCode) else ErrorCode(e)
# 
# Path: pyinform/conditionalentropy.py
# def conditional_entropy(xs, ys, local=False):
#     """
#     Compute the (local) conditional entropy between two time series.
# 
#     This function expects the **condition** to be the first argument.
# 
#     :param xs: the time series drawn from the conditional distribution
#     :type xs: a sequence or ``numpy.ndarray``
#     :param ys: the time series drawn from the target distribution
#     :type ys: a sequence or ``numpy.ndarray``
#     :param bool local: compute the local conditional entropy
#     :return: the local or average conditional entropy
#     :rtype: float or ``numpy.ndarray``
#     :raises ValueError: if the time series have different shapes
#     :raises InformError: if an error occurs within the ``inform`` C call
#     """
#     us = np.ascontiguousarray(xs, dtype=np.int32)
#     vs = np.ascontiguousarray(ys, dtype=np.int32)
#     if us.shape != vs.shape:
#         raise ValueError("timeseries lengths do not match")
# 
#     bx = max(2, np.amax(us) + 1)
#     by = max(2, np.amax(vs) + 1)
# 
#     xdata = us.ctypes.data_as(POINTER(c_int))
#     ydata = vs.ctypes.data_as(POINTER(c_int))
#     n = us.size
# 
#     e = ErrorCode(0)
# 
#     if local is True:
#         ce = np.empty(us.shape, dtype=np.float64)
#         out = ce.ctypes.data_as(POINTER(c_double))
#         _local_conditional_entropy(xdata, ydata, c_ulong(n), c_int(bx), c_int(by), out, byref(e))
#     else:
#         ce = _conditional_entropy(xdata, ydata, c_ulong(n), c_int(bx), c_int(by), byref(e))
# 
#     error_guard(e)
# 
#     return ce


import unittest
import numpy as np
from pyinform.error import InformError
from pyinform.conditionalentropy import conditional_entropy

        with self.assertRaises(ValueError):
            conditional_entropy([1, 2, 3], [], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([], [1, 2, 3], local=True)

    def test_conditional_entropy_dimensions(self):
        with self.assertRaises(ValueError):
            conditional_entropy([[1]], [1], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([1], [[1]], local=True)

    def test_conditional_entropy_size(self):
        with self.assertRaises(ValueError):
            conditional_entropy([1, 2, 3], [1, 2], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([1, 2], [1, 2, 3], local=True)

    def test_conditional_entropy_negative_states(self):
        with self.assertRaises(InformError):
            conditional_entropy([-1, 0, 0], [0, 0, 1], local=True)

        with self.assertRaises(InformError):
            conditional_entropy([1, 0, 0], [0, 0, -1], local=True)

    def test_conditional_entropy_base_2(self):
        self.assertAlmostEqual(0.899985,

# Path: pyinform/error.py
# class InformError(Exception):
#     """
#     InformError signifies an error occurred in a call to inform.
#     """
# 
#     def __init__(self, e=-1, func=None):
#         msg = error_string(e)
# 
#         if func is None:
#             msg = "an inform error occurred - \"{}\"".format(msg)
#         else:
#             msg = "an inform error occurred in `{}` - \"{}\"".format(func, msg)
# 
#         super(InformError, self).__init__(msg)
# 
#         self.error_code = e if isinstance(e, ErrorCode) else ErrorCode(e)
# 
# Path: pyinform/conditionalentropy.py
# def conditional_entropy(xs, ys, local=False):
#     """
#     Compute the (local) conditional entropy between two time series.
# 
#     This function expects the **condition** to be the first argument.
# 
#     :param xs: the time series drawn from the conditional distribution
#     :type xs: a sequence or ``numpy.ndarray``
#     :param ys: the time series drawn from the target distribution
#     :type ys: a sequence or ``numpy.ndarray``
#     :param bool local: compute the local conditional entropy
#     :return: the local or average conditional entropy
#     :rtype: float or ``numpy.ndarray``
#     :raises ValueError: if the time series have different shapes
#     :raises InformError: if an error occurs within the ``inform`` C call
#     """
#     us = np.ascontiguousarray(xs, dtype=np.int32)
#     vs = np.ascontiguousarray(ys, dtype=np.int32)
#     if us.shape != vs.shape:
#         raise ValueError("timeseries lengths do not match")
# 
#     bx = max(2, np.amax(us) + 1)
#     by = max(2, np.amax(vs) + 1)
# 
#     xdata = us.ctypes.data_as(POINTER(c_int))
#     ydata = vs.ctypes.data_as(POINTER(c_int))
#     n = us.size
# 
#     e = ErrorCode(0)
# 
#     if local is True:
#         ce = np.empty(us.shape, dtype=np.float64)
#         out = ce.ctypes.data_as(POINTER(c_double))
#         _local_conditional_entropy(xdata, ydata, c_ulong(n), c_int(bx), c_int(by), out, byref(e))
#     else:
#         ce = _conditional_entropy(xdata, ydata, c_ulong(n), c_int(bx), c_int(by), byref(e))
# 
#     error_guard(e)
# 
#     return ce


# Path: test/test_conditionalentropy.py
import unittest
import numpy as np
from pyinform.error import InformError
from pyinform.conditionalentropy import conditional_entropy


        with self.assertRaises(ValueError):
            conditional_entropy([1, 2, 3], [], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([], [1, 2, 3], local=True)

    def test_conditional_entropy_dimensions(self):
        with self.assertRaises(ValueError):
            conditional_entropy([[1]], [1], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([1], [[1]], local=True)

    def test_conditional_entropy_size(self):
        with self.assertRaises(ValueError):
            conditional_entropy([1, 2, 3], [1, 2], local=True)

        with self.assertRaises(ValueError):
            conditional_entropy([1, 2], [1, 2, 3], local=True)

    def test_conditional_entropy_negative_states(self):
        with self.assertRaises(InformError):
            conditional_entropy([-1, 0, 0], [0, 0, 1], local=True)

        with self.assertRaises(InformError):
            conditional_entropy([1, 0, 0], [0, 0, -1], local=True)

    def test_conditional_entropy_base_2(self):
        self.assertAlmostEqual(0.899985,

                               conditional_entropy([0, 0, 1, 1, 1, 1, 0, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0], local=True).mean(), places=6)