Repository: ELIFE-ASU/Neet

Issue:
logic network update function fails with large number of nodes
Above about 62 nodes, the update function for logic networks fails due to an issue with encoding states of the network.

Discussion:

Patch:
diff --git a/neet/boolean/logicnetwork.py b/neet/boolean/logicnetwork.py
index 69f44fc..9f1123b 100644
--- a/neet/boolean/logicnetwork.py
+++ b/neet/boolean/logicnetwork.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a MIT
 # license that can be found in the LICENSE file.
 import re
+from neet.python3 import *
 from neet.statespace import StateSpace
 from neet.exceptions import FormatError
 
@@ -88,7 +89,7 @@ class LogicNetwork(object):
                 raise ValueError("Invalid table format")
             conditions = set()
             for condition in row[1]:
-                conditions.add(''.join([str(int(s)) for s in condition]))
+                conditions.add(''.join([str(long(s)) for s in condition]))
             self.table.append((row[0], conditions))
 
         if reduced:
@@ -105,15 +106,15 @@ class LogicNetwork(object):
         self._encoded_table = []
         for indices, conditions in self.table:
             # Encode the mask.
-            mask_code = 0
+            mask_code = long(0)
             for idx in indices:
                 mask_code += 2 ** idx  # Low order, low index.
             # Encode each condition of truth table.
             encoded_sub_table = set()
             for condition in conditions:
-                encoded_condition = 0
+                encoded_condition = long(0)
                 for idx, state in zip(indices, condition):
-                    encoded_condition += 2 ** idx if int(state) else 0
+                    encoded_condition += 2 ** idx if long(state) else 0
                 encoded_sub_table.add(encoded_condition)
             self._encoded_table.append((mask_code, encoded_sub_table))
 
@@ -134,7 +135,7 @@ class LogicNetwork(object):
         for state in sub_table[1]:
             # State excluding source.
             state_sans_source = state[:i] + state[i + 1:]
-            if int(state[i]) == 1:
+            if long(state[i]) == 1:
                 counter[state_sans_source] = counter.get(
                     state_sans_source, 0) + 1
             else:
diff --git a/neet/python3.py b/neet/python3.py
new file mode 100644
index 0000000..b3b118d
--- /dev/null
+++ b/neet/python3.py
@@ -0,0 +1,9 @@
+# Copyright 2018 ELIFE. All rights reserved.
+# Use of this source code is governed by a MIT
+# license that can be found in the LICENSE file.
+
+import sys
+if sys.version_info > (3,):
+    long = int
+    unicode = str
+
diff --git a/neet/statespace.py b/neet/statespace.py
index fc8230b..609c2c8 100644
--- a/neet/statespace.py
+++ b/neet/statespace.py
@@ -1,6 +1,7 @@
 # Copyright 2016-2017 ELIFE. All rights reserved.
 # Use of this source code is governed by a MIT
 # license that can be found in the LICENSE file.
+from .python3 import *
 import numpy as np
 
 class StateSpace(object):
@@ -201,7 +202,7 @@ class StateSpace(object):
         :returns: a unique integer encoding of the state
         :raises ValueError: if ``state`` has an incorrect length
         """
-        encoded, place = 0, 1
+        encoded, place = long(0), long(1)
 
         base = self.__base
         if self.is_uniform:
@@ -213,7 +214,7 @@ class StateSpace(object):
                 encoded += place * x
                 place *= b
 
-        return encoded
+        return long(encoded)
 
     def encode(self, state):
         """


Test patch:
diff --git a/test/test_asynchronous.py b/test/test_asynchronous.py
index 2dce250..5b6b7b1 100644
--- a/test/test_asynchronous.py
+++ b/test/test_asynchronous.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a MIT
 # license that can be found in the LICENSE file.
 import unittest
+from neet.python3 import *
 from neet.asynchronous import transitions
 from neet.automata import ECA
 from neet.boolean.examples import s_pombe, s_cerevisiae, c_elegans
@@ -68,7 +69,7 @@ class TestAsync(unittest.TestCase):
         for net in [s_pombe, s_cerevisiae, c_elegans]:
             for states, _ in transitions(net, encoded=True):
                 for state in states:
-                    self.assertIsInstance(state, int)
+                    self.assertIsInstance(state, (int, long))
             for states, _ in transitions(net, encoded=False):
                 for state in states:
                     self.assertIsInstance(state, list)
@@ -77,7 +78,7 @@ class TestAsync(unittest.TestCase):
             for size in [5, 8, 10]:
                 for states, _ in transitions(net, size, encoded=True):
                     for state in states:
-                        self.assertIsInstance(state, int)
+                        self.assertIsInstance(state, (int, long))
                 for states, _ in transitions(net, size, encoded=False):
                     for state in states:
                         self.assertIsInstance(state, list)
diff --git a/test/test_statespace.py b/test/test_statespace.py
index 813597d..80b77f3 100644
--- a/test/test_statespace.py
+++ b/test/test_statespace.py
@@ -2,10 +2,10 @@
 # Use of this source code is governed by a MIT
 # license that can be found in the LICENSE file.
 import unittest
+from neet.python3 import *
 from neet.statespace import StateSpace
 import numpy as np
 
-
 class TestStateSpace(unittest.TestCase):
     def test_invalid_spec_type(self):
         with self.assertRaises(TypeError):
@@ -277,3 +277,17 @@ class TestStateSpace(unittest.TestCase):
         self.assertFalse([0, 2, 1] not in StateSpace([2, 3, 2]))
         self.assertTrue([0, 1] not in StateSpace([2, 2, 3]))
         self.assertTrue([1, 1, 6] not in StateSpace([2, 3, 4]))
+
+    def test_long_encoding(self):
+        state_space = StateSpace(10)
+        code = state_space.encode(np.ones(10, dtype=int))
+        print(type(code))
+        self.assertIsInstance(code, long)
+
+        state_space = StateSpace(68)
+        code = state_space.encode(np.ones(68, dtype=int))
+        self.assertIsInstance(code, long)
+
+        state_space = StateSpace(100)
+        code = state_space.encode(np.ones(100, dtype=int))
+        self.assertIsInstance(code, long)