# Path: dnacc/utils.py
# class SymDict(dict):
#     """
#     A dictionary for 2-tuples whose order is irrelevant.
# 
#     Use exactly as a dict.
#     """
#     def __setitem__(self, key, value):
#         dict.__setitem__(self, key, value)
#         if key[0] != key[1]:
#             dict.__setitem__(self, (key[1], key[0]), value)
# 
#     def __delitem__(self, key):
#         dict.__delitem__(self, key)
#         if key[0] != key[1]:
#             dict.__delitem__(self, (key[1], key[0]))
# 
# class csr_matrix_from_dict(object):
#     """
#     Bare-bones implementation of a CSR-format sparse matrix.
# 
#     Notes
#     -----
#     I wrote this to avoid SciPy's horrendous performance when creating
#     a CSR matrix from a dictionary of keys.  See documentation for
#     csr_matrix for a discussion of the shape, indptr, indices and data
#     attributes.
# 
#     In DNACC, we only use sparse matrices for keeping track of values, as
#     all the arithmetic is done in the C extension module.
# 
#     For iterating through matrix items, use csr_matrix_items().
# 
#     Parameters
#     ----------
#     shape : 2-tuple
#         a tuple (M, N) specifying the shape of the matrix
#     d : dictionary
#         a dictionary mapping (row, col) tuples to values
# 
#     Attributes
#     ----------
#     shape
#     indptr
#     indices
#     data
# 
#     Examples
#     --------
#     >>> mtx = csr_matrix_from_dict((3, 3), {(1, 2): 3, (0, 0): 4})
#     >>> mtx[1, 2]
#     >>> for (i, j), v in csr_matrix_items(mtx): print( i, j, v )
#     >>> for (i, j), v in csr_matrix_items(mtx, row=1): print( i, j, v )
#     """
# 
#     def __init__(self, shape, d):
#         # CSR matrices are laid out so that column indices for row i are
#         # stored in indices[indptr[i]:indptr[i+1]] and their corresponding
#         # values are stored in data[indptr[i]:indptr[i+1]].
#         M, N = shape
#         nnz_in_row = np.zeros(M, dtype='int32')
#         for (i, j) in d:
#             nnz_in_row[i] += 1
#         nnz = len(d)
# 
#         indptr = np.zeros(M + 1, dtype='int32')
#         for i in xrange(M):
#             indptr[i + 1] = indptr[i] + nnz_in_row[i]
# 
#         indices = np.zeros(nnz, dtype='int32')
#         data = np.zeros(nnz)
# 
#         next_indptr = np.array(indptr, copy=True)
#         for (i, j), v in d.iteritems():
#             assert 0 <= i < M
#             assert 0 <= j < N
#             ind = next_indptr[i]
#             indices[ind] = j
#             data[ind] = v
#             next_indptr[i] += 1
# 
#         self.shape = shape
#         self.indptr = indptr
#         self.indices = indices
#         self.data = data
# 
#     def __getitem__(self, key):
#         """Retrive item (i,j) from the matrix.  VERY SLOW."""
#         i, j = key
#         M, N = self.shape
#         if not (0 <= i < M) or not (0 <= j < N):
#             raise KeyError('Item (%d,%d) out of range (matrix is %dx%d)' %
#                            (i, j, M, N))
# 
#         for ind in xrange(self.indptr[i], self.indptr[i + 1]):
#             if self.indices[ind] == j:
#                 return self.data[ind]
#         else:
#             return 0.0


import unittest
import numpy as np
from dnacc.utils import SymDict, csr_matrix_from_dict
from math import *
from dnacc.generic import *
## Unit testing
## ------------

# DNACC logic
class TestGeneric(unittest.TestCase):
    """Unit test for DNACC logic."""

    def test_simple_dnacc(self):
        cases = [

            dict(beta_DeltaG0=-10, weights=None,
                 binding_free_energy=-9.01,
                 p_bound_0_1=0.99327740159843414),

            dict(beta_DeltaG0=-10, weights=[0.8, 0.6, 3.7],
                 binding_free_energy=-5.54,
                 p_bound_0_1=0.8 * 1.2497165073687115 * 0.6),

            dict(beta_DeltaG0=-1, weights=None,
                 binding_free_energy=-1.05,
                 p_bound_0_1=0.55013119441689895),

            dict(beta_DeltaG0=-1, weights=[0.8, 0.6, 3.7],
                 binding_free_energy=-0.59,
                 p_bound_0_1=0.8 * 0.69788894233575782 * 0.6)]

        for case in cases:
            N = 3
            boltz_bind = SymDict()
            boltz_bind[0, 1] = exp(-case['beta_DeltaG0'])

# Path: dnacc/utils.py
# class SymDict(dict):
#     """
#     A dictionary for 2-tuples whose order is irrelevant.
# 
#     Use exactly as a dict.
#     """
#     def __setitem__(self, key, value):
#         dict.__setitem__(self, key, value)
#         if key[0] != key[1]:
#             dict.__setitem__(self, (key[1], key[0]), value)
# 
#     def __delitem__(self, key):
#         dict.__delitem__(self, key)
#         if key[0] != key[1]:
#             dict.__delitem__(self, (key[1], key[0]))
# 
# class csr_matrix_from_dict(object):
#     """
#     Bare-bones implementation of a CSR-format sparse matrix.
# 
#     Notes
#     -----
#     I wrote this to avoid SciPy's horrendous performance when creating
#     a CSR matrix from a dictionary of keys.  See documentation for
#     csr_matrix for a discussion of the shape, indptr, indices and data
#     attributes.
# 
#     In DNACC, we only use sparse matrices for keeping track of values, as
#     all the arithmetic is done in the C extension module.
# 
#     For iterating through matrix items, use csr_matrix_items().
# 
#     Parameters
#     ----------
#     shape : 2-tuple
#         a tuple (M, N) specifying the shape of the matrix
#     d : dictionary
#         a dictionary mapping (row, col) tuples to values
# 
#     Attributes
#     ----------
#     shape
#     indptr
#     indices
#     data
# 
#     Examples
#     --------
#     >>> mtx = csr_matrix_from_dict((3, 3), {(1, 2): 3, (0, 0): 4})
#     >>> mtx[1, 2]
#     >>> for (i, j), v in csr_matrix_items(mtx): print( i, j, v )
#     >>> for (i, j), v in csr_matrix_items(mtx, row=1): print( i, j, v )
#     """
# 
#     def __init__(self, shape, d):
#         # CSR matrices are laid out so that column indices for row i are
#         # stored in indices[indptr[i]:indptr[i+1]] and their corresponding
#         # values are stored in data[indptr[i]:indptr[i+1]].
#         M, N = shape
#         nnz_in_row = np.zeros(M, dtype='int32')
#         for (i, j) in d:
#             nnz_in_row[i] += 1
#         nnz = len(d)
# 
#         indptr = np.zeros(M + 1, dtype='int32')
#         for i in xrange(M):
#             indptr[i + 1] = indptr[i] + nnz_in_row[i]
# 
#         indices = np.zeros(nnz, dtype='int32')
#         data = np.zeros(nnz)
# 
#         next_indptr = np.array(indptr, copy=True)
#         for (i, j), v in d.iteritems():
#             assert 0 <= i < M
#             assert 0 <= j < N
#             ind = next_indptr[i]
#             indices[ind] = j
#             data[ind] = v
#             next_indptr[i] += 1
# 
#         self.shape = shape
#         self.indptr = indptr
#         self.indices = indices
#         self.data = data
# 
#     def __getitem__(self, key):
#         """Retrive item (i,j) from the matrix.  VERY SLOW."""
#         i, j = key
#         M, N = self.shape
#         if not (0 <= i < M) or not (0 <= j < N):
#             raise KeyError('Item (%d,%d) out of range (matrix is %dx%d)' %
#                            (i, j, M, N))
# 
#         for ind in xrange(self.indptr[i], self.indptr[i + 1]):
#             if self.indices[ind] == j:
#                 return self.data[ind]
#         else:
#             return 0.0


# Path: dnacc/tests/test_generic.py
import unittest
import numpy as np
from dnacc.utils import SymDict, csr_matrix_from_dict
from math import *
from dnacc.generic import *

## Unit testing
## ------------

# DNACC logic
class TestGeneric(unittest.TestCase):
    """Unit test for DNACC logic."""

    def test_simple_dnacc(self):
        cases = [

            dict(beta_DeltaG0=-10, weights=None,
                 binding_free_energy=-9.01,
                 p_bound_0_1=0.99327740159843414),

            dict(beta_DeltaG0=-10, weights=[0.8, 0.6, 3.7],
                 binding_free_energy=-5.54,
                 p_bound_0_1=0.8 * 1.2497165073687115 * 0.6),

            dict(beta_DeltaG0=-1, weights=None,
                 binding_free_energy=-1.05,
                 p_bound_0_1=0.55013119441689895),

            dict(beta_DeltaG0=-1, weights=[0.8, 0.6, 3.7],
                 binding_free_energy=-0.59,
                 p_bound_0_1=0.8 * 0.69788894233575782 * 0.6)]

        for case in cases:
            N = 3
            boltz_bind = SymDict()
            boltz_bind[0, 1] = exp(-case['beta_DeltaG0'])

            boltz_bind = csr_matrix_from_dict((N, N), boltz_bind)