Repository: mauriceling/copads (language: python)

Issue:
Pull from Kian Seng (py3_210129_restart) on 210308

+ cleared up everything to restart



Discussion / hints:

Fix patch:
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..fafb871
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+    "python.pythonPath": "C:\\ProgramData\\Anaconda3\\python.exe"
+}
\ No newline at end of file
diff --git a/copads/dsDeque.py b/copads/dsDeque.py
new file mode 100644
index 0000000..cafddf9
--- /dev/null
+++ b/copads/dsDeque.py
@@ -0,0 +1,24 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/BasicDS/ImplementingaDequeinPython.html
+"""
+class Deque:
+    def __init__(self):
+        self.items = []
+
+    def isEmpty(self):
+        return self.items == []
+
+    def addFront(self, item):
+        self.items.append(item)
+
+    def addRear(self, item):
+        self.items.insert(0,item)
+
+    def removeFront(self):
+        return self.items.pop()
+
+    def removeRear(self):
+        return self.items.pop(0)
+
+    def size(self):
+        return len(self.items)
\ No newline at end of file
diff --git a/copads/dsHashTable.py b/copads/dsHashTable.py
new file mode 100644
index 0000000..6c4c887
--- /dev/null
+++ b/copads/dsHashTable.py
@@ -0,0 +1,59 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/SortSearch/Hashing.html#implementing-the-map-abstract-data-type
+"""
+class HashTable:
+    def __init__(self):
+        self.size = 11
+        self.slots = [None] * self.size
+        self.data = [None] * self.size
+
+    def put(self,key,data):
+      hashvalue = self.hashfunction(key,len(self.slots))
+
+      if self.slots[hashvalue] == None:
+        self.slots[hashvalue] = key
+        self.data[hashvalue] = data
+      else:
+        if self.slots[hashvalue] == key:
+          self.data[hashvalue] = data  #replace
+        else:
+          nextslot = self.rehash(hashvalue,len(self.slots))
+          while self.slots[nextslot] != None and \
+                          self.slots[nextslot] != key:
+            nextslot = self.rehash(nextslot,len(self.slots))
+
+          if self.slots[nextslot] == None:
+            self.slots[nextslot]=key
+            self.data[nextslot]=data
+          else:
+            self.data[nextslot] = data #replace
+
+    def hashfunction(self,key,size):
+         return key%size
+
+    def rehash(self,oldhash,size):
+        return (oldhash+1)%size
+
+    def get(self,key):
+      startslot = self.hashfunction(key,len(self.slots))
+
+      data = None
+      stop = False
+      found = False
+      position = startslot
+      while self.slots[position] != None and  \
+                           not found and not stop:
+         if self.slots[position] == key:
+           found = True
+           data = self.data[position]
+         else:
+           position=self.rehash(position,len(self.slots))
+           if position == startslot:
+               stop = True
+      return data
+
+    def __getitem__(self,key):
+        return self.get(key)
+
+    def __setitem__(self,key,data):
+        self.put(key,data)
\ No newline at end of file
diff --git a/copads/dsOrderedList.py b/copads/dsOrderedList.py
new file mode 100644
index 0000000..b6ef44d
--- /dev/null
+++ b/copads/dsOrderedList.py
@@ -0,0 +1,83 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/BasicDS/ImplementinganOrderedList.html
+"""
+class Node:
+    def __init__(self,initdata):
+        self.data = initdata
+        self.next = None
+
+    def getData(self):
+        return self.data
+
+    def getNext(self):
+        return self.next
+
+    def setData(self,newdata):
+        self.data = newdata
+
+    def setNext(self,newnext):
+        self.next = newnext
+
+
+class OrderedList:
+    def __init__(self):
+        self.head = None
+
+    def search(self,item):
+        current = self.head
+        found = False
+        stop = False
+        while current != None and not found and not stop:
+            if current.getData() == item:
+                found = True
+            else:
+                if current.getData() > item:
+                    stop = True
+                else:
+                    current = current.getNext()
+
+        return found
+
+    def add(self,item):
+        current = self.head
+        previous = None
+        stop = False
+        while current != None and not stop:
+            if current.getData() > item:
+                stop = True
+            else:
+                previous = current
+                current = current.getNext()
+
+        temp = Node(item)
+        if previous == None:
+            temp.setNext(self.head)
+            self.head = temp
+        else:
+            temp.setNext(current)
+            previous.setNext(temp)
+
+    def isEmpty(self):
+        return self.head == None
+
+    def size(self):
+        current = self.head
+        count = 0
+        while current != None:
+            count = count + 1
+            current = current.getNext()
+
+        return count
+
+
+mylist = OrderedList()
+mylist.add(31)
+mylist.add(77)
+mylist.add(17)
+mylist.add(93)
+mylist.add(26)
+mylist.add(54)
+
+print(mylist.size())
+print(mylist.search(93))
+print(mylist.search(100))
\ No newline at end of file
diff --git a/copads/dsQueue.py b/copads/dsQueue.py
new file mode 100644
index 0000000..d0a3642
--- /dev/null
+++ b/copads/dsQueue.py
@@ -0,0 +1,18 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/BasicDS/ImplementingaQueueinPython.html
+"""
+class Queue:
+    def __init__(self):
+        self.items = []
+
+    def isEmpty(self):
+        return self.items == []
+
+    def enqueue(self, item):
+        self.items.insert(0,item)
+
+    def dequeue(self):
+        return self.items.pop()
+
+    def size(self):
+        return len(self.items)
\ No newline at end of file
diff --git a/copads/dsStack.py b/copads/dsStack.py
new file mode 100644
index 0000000..c6d101c
--- /dev/null
+++ b/copads/dsStack.py
@@ -0,0 +1,21 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/BasicDS/ImplementingaStackinPython.html
+"""
+class Stack:
+    def __init__(self):
+        self.items = []
+
+    def isEmpty(self):
+        return self.items == []
+
+    def push(self, item):
+        self.items.append(item)
+
+    def pop(self):
+        return self.items.pop()
+
+    def peek(self):
+        return self.items[len(self.items)-1]
+
+    def size(self):
+        return len(self.items)
diff --git a/copads/dsUnorderedList.py b/copads/dsUnorderedList.py
new file mode 100644
index 0000000..1c93ab4
--- /dev/null
+++ b/copads/dsUnorderedList.py
@@ -0,0 +1,69 @@
+"""
+https://runestone.academy/runestone/books/published/pythonds/BasicDS/ImplementinganUnorderedListLinkedLists.html
+"""
+class Node:
+    def __init__(self,initdata):
+        self.data = initdata
+        self.next = None
+
+    def getData(self):
+        return self.data
+
+    def getNext(self):
+        return self.next
+
+    def setData(self,newdata):
+        self.data = newdata
+
+    def setNext(self,newnext):
+        self.next = newnext
+
+
+class UnorderedList:
+
+    def __init__(self):
+        self.head = None
+
+    def isEmpty(self):
+        return self.head == None
+
+    def add(self,item):
+        temp = Node(item)
+        temp.setNext(self.head)
+        self.head = temp
+    
+    def size(self):
+        current = self.head
+        count = 0
+        while current != None:
+            count = count + 1
+            current = current.getNext()
+
+        return count
+
+    def search(self,item):
+        current = self.head
+        found = False
+        while current != None and not found:
+            if current.getData() == item:
+                found = True
+            else:
+                current = current.getNext()
+
+        return found
+
+    def remove(self,item):
+        current = self.head
+        previous = None
+        found = False
+        while not found:
+            if current.getData() == item:
+                found = True
+            else:
+                previous = current
+                current = current.getNext()
+
+        if previous == None:
+            self.head = current.getNext()
+        else:
+            previous.setNext(current.getNext())
\ No newline at end of file
diff --git a/copads/neural.py b/copads/neural.py
deleted file mode 100644
index 502ff61..0000000
--- a/copads/neural.py
+++ /dev/null
@@ -1,1033 +0,0 @@
-'''
-Framework for Neural Network Applications
-Date created: 15th June 2015
-License: Python Software Foundation License version 2
-'''
-
-import math
-import sqlite3 as s
-from random import random
-
-class BrainBase(object):
-    '''
-    Class to represent data structure of the neuronal network (also known as 
-    the brain), using SQLite database.
-    '''
-
-    def __init__(self, path):
-        '''
-        Constructor method - initialize a new brain, or connect to an existing 
-        brain.
-        
-        @param path: full path name of the brain file (implemented as an SQLite 
-        database.
-        @type path: string
-        '''
-        self.conn = s.connect(path)
-        self.cur = self.conn.cursor()
-        braincheck = self._check_brain()
-        if True not in braincheck:
-            self._format_brain()
-        elif False in braincheck:
-            self._repair_brain(braincheck)
-
-    def close_brain(self):
-        '''
-        Closing the brain file.
-        '''
-        self.conn.commit()
-        self.conn.close()
-            
-    def _check_brain(self):
-        '''
-        Private method - Checks for the presence of tables in the brain file, 
-        as a proxy for checking whether the supplied brain file (in 
-        constructor) is a new file or an existing file. If it is new brain, 
-        then the tables need to be created.
-        '''
-        results = [True, True, True, True]
-        try:
-            self.cur.execute('select max(ID) from neuron')
-        except:
-            results[0] = False
-        try:
-            self.cur.execute('select max(ID) from neuron_internal_states')
-        except:
-            results[1] = False
-        try:
-            self.cur.execute('select max(ID) from neuron_input_states')
-        except:
-            results[2] = False
-        try:
-            self.cur.execute('select max(source) from connectome')
-        except:
-            results[3] = False
-        return results
-        
-    def _format_brain(self):
-        '''
-        Private method - Setting up the tables needed for a new brain file.
-        '''
-        try: 
-            self.cur.execute('drop table logfile')
-        except s.OperationalError: 
-            pass
-        self.cur.execute('''
-            create table if not exists logfile (
-                ID integer primary key autoincrement,
-                event text not null)''')
-        try: 
-            self.cur.execute('drop table neuron')
-        except s.OperationalError: 
-            pass
-        self.cur.execute('''
-            create table if not exists neuron (
-                ID integer primary key autoincrement,
-                name text not null,
-                status text not null default 'alive')''')
-        try: 
-            self.cur.execute('drop table neuron_internal_states')
-        except s.OperationalError: 
-            pass
-        self.cur.execute('''
-            create table if not exists neuron_internal_states (
-                ID integer not null,
-                key text not null,
-                value text not null,
-                primary key (ID, key))''')
-        try: 
-            self.cur.execute('drop table neuron_input_states')
-        except s.OperationalError: 
-            pass
-        self.cur.execute('''
-            create table if not exists neuron_input_states (
-                ID integer not null,
-                sourceID text not null,
-                value text not null,
-                primary key (ID, sourceID))''')
-        try: 
-            self.cur.execute('drop table connectome')
-        except s.OperationalError: 
-            pass
-        self.cur.execute('''
-            create table if not exists connectome (
-                source integer not null,
-                destination integer not null,
-                key text not null default 'weight',
-                value text not null,
-                primary key (source, destination, key))''')
-        self.conn.commit()
-    
-    def _repair_brain(self, braincheck):
-        pass
-        
-    def log(self, message):
-        '''
-        Method to insert logging message.
-        
-        @param message: message to be logged.
-        @type message: string
-        '''
-        self.cur.execute('insert into logfile (event) values (?)', (message,))
-        self.conn.commit()
-        
-    def add_neuron(self, **kwargs):
-        '''
-        Method to add a new neuron into the brain.
-        
-        Logging messages::
-            - add neuron: ADDNEURON:<ID of new neuron>:<name of new neuron> 
-            - set initial neuron internal data: SETININED:<ID of new neuron>:
-            <initial neuronal data in dictionary string format>
-            
-        @param kwargs: initial neuronal data (as dictionary). The following 
-        mandatory fields will be added for each neuron::
-            - name: user-defined name for the neuron. Default = no_name.
-            - summation: type of summation functions. Allowable values are 
-            'summation' (averaged input values). Default = summation.
-            - transfer: type of transfer / activation functions, which will 
-            generate the output value of the neuron. Allowable values are 
-            'linear' (neuron output = output from summation function), 
-            'sigmoid' (sigmoid curve output). Default = linear.
-            - threshold: theshold value of the neuron. Default = 0.5.
-            - pstate: initial output value of the neuron. Default = generated 
-            random value between 0-1.
-        @type kwargs: dictionary
-        @return: ID of the new neuron
-        '''
-        if 'name' not in kwargs:
-            name = 'no_name'
-        else: 
-            name = str(kwargs['name'])
-            del kwargs['name']
-        if 'summation' not in kwargs:
-            kwargs['summation'] = 'summation'
-        if 'transfer' not in kwargs:
-            kwargs['transfer'] = 'linear'
-        if 'threshold' not in kwargs:
-            kwargs['threshold'] = '0.5'
-        if 'pstate' not in kwargs:
-            kwargs['pstate'] = str(random())
-        self.cur.execute('insert into neuron (name) values (?)', (name,))
-        ID = str(self.cur.lastrowid)
-        for key in kwargs:
-            self.cur.execute('''
-                insert into neuron_internal_states (ID, key, value) 
-                values (?,?,?)''', (ID, str(key), str(kwargs[key])))
-        self.log('ADDNEURON:' + ID + ':' + name)
-        self.log('SETININED:' + ID + ':' + str(kwargs))
-        self.conn.commit()
-        return ID
-        
-    def delete_neuron(self, ID):
-        '''
-        Method to delete a neuron from the brain and all associated synapses.
-        
-        Logging messages::
-            - delete source synapses: DELNES:<ID of neuron to delete>
-            - delete destination synapses: DELNED:<ID of neuron to delete>
-            - delete internal states: DELNIS:<ID of neuron to delete>
-            - delete input states: DELNIN:<ID of neuron to delete>
-            - delete neuron: DELNEU:<ID of neuron to delete>
-        
-        @param ID: ID of neuron to delete
-        @type ID: string
-        '''
-        self.cur.execute('''delete from connectome where source=:ID''', 
-                         {'ID': str(ID)})
-        self.log('DELNES:' + ID)
-        self.cur.execute('''delete from connectome where destination=:ID''',
-                         {'ID': str(ID)})
-        self.log('DELNED:' + ID)
-        self.cur.execute('''delete from neuron_internal_states where ID=:ID''',
-                         {'ID': str(ID)})
-        self.log('DELNIS:' + ID)
-        self.cur.execute('''delete from neuron_input_states where ID=:ID''',
-                         {'ID': str(ID)})
-        self.log('DELNIN:' + ID)
-        self.cur.execute('''delete from neuron where ID=:ID''',
-                         {'ID': str(ID)})
-        self.log('DELNEU:' + ID)
-        self.conn.commit()
-
-    def _check_neuron_presence(self, ID):
-        '''
-        Private method - Check whether a neuron is present (in existence).
-        
-        @param ID: ID of the neuron to check.
-        @type ID: string
-        @return: False if neuron is not found; True if neuron is found.
-        '''
-        self.cur.execute('select name from neuron where ID=:ID',
-                         {'ID': str(ID)})
-        if self.cur.fetchone() == None:
-            return False
-        else:
-            return True
-                         
-    def add_synapse(self, sourceID, destinationID):
-        '''
-        Method to add a new synapse (connection between 2 neurons) into the 
-        brain. When either of the neurons are not present in the brain, 1 or 2 
-        neurons (depending whether 1 or both neurons are not found) will be 
-        created; however, the ID(s) of the neuron(s) will not be the same as 
-        provided. A random weight between 0 to 1 (as synaptic state) will be 
-        added.
-        
-        Logging messages::
-            - add synapse: ADDSYN:<ID of source / originating neuron>:<ID of 
-            destination / sink neuron>:<initial synaptic weight in dictionary 
-            string format>
-            
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        '''
-        if self._check_neuron_presence(sourceID) == False:
-            sourceID = self.add_neuron()
-        if self._check_neuron_presence(destinationID) == False:
-            destinationID = self.add_neuron()
-        kwargs = {'weight': random()}
-        for key in kwargs:
-            self.cur.execute('''
-                insert into connectome (source, destination, key, value) 
-                values (?,?,?,?)''',
-                (sourceID, destinationID, str(key), str(kwargs[key])))
-        self.log('ADDSYN:' + sourceID + ':' + destinationID + ':' + str(kwargs))
-        self.conn.commit()
-        
-    def delete_synapse(self, sourceID, destinationID):
-        '''
-        Method to delete a synapse (connection between 2 neurons) in the brain.
-        
-        Logging messages::
-            - delete synapse: DELSYN:<ID of source / originating neuron>:<ID of 
-            destination / sink neuron>
-            
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        '''
-        self.cur.execute('''
-            delete from connectome where 
-            source=:source and destination=:destination''',
-            {'source': str(sourceID),
-             'destination': str(destinationID)})
-        self.log('DELSYN:' + sourceID + ':' + destinationID)
-        self.conn.commit()
-
-    def set_synapse_state(self, sourceID, destinationID, 
-                          value, state='weight'):
-        '''
-        Method to set a state in a synapse.
-        
-        Logging messages::
-            - set synaptic state: SETSYNST:<ID of source / originating neuron>:
-            <ID of destination / sink neuron>:<state>:<value>
-        
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param value: value of the state.
-        @type value: string
-        @param state: state name to set or update.
-        @type state: string
-        '''
-        self.cur.execute('''select value from connectome
-                            where source=:sourceID and 
-                            destination=:destinationID and 
-                            key=:key''', 
-                         {'sourceID': str(sourceID),
-                          'destinationID': str(destinationID),
-                          'key': str(state)})
-        if self.cur.fetchone() == None:
-            self.cur.execute('''insert into connectome 
-                                (source, destination, key, value) values 
-                                (?,?,?,?)''',
-                             (str(sourceID), str(destinationID), 
-                              str(state), value))
-        else: 
-            self.cur.execute('''update connectome
-                                set value=:value
-                                where source=:sourceID and 
-                                destination=:destinationID and
-                                key=:key''',
-                             {'value': value,
-                              'sourceID': str(sourceID),
-                              'destinationID': str(destinationID),
-                              'key': str(state)})
-        self.log('SETSYNST:' + sourceID + ':' + destinationID + ':' + \
-                 str(state) + ':' + str(value))
-        self.conn.commit()
-        
-    def get_synapse_state(self, sourceID, destinationID, state='weight'):
-        '''
-        Method to get value of a synaptic state.
-        
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param state: state name to set or update. Default = weight.
-        @type state: string
-        @return: value of the synaptic state (if found), or None (if state is 
-        not found)
-        '''
-        self.cur.execute('''select value from connectome
-                            where source=:sourceID and 
-                            destination=:destinationID and 
-                            key=:key''', 
-                         {'sourceID': str(sourceID),
-                          'destinationID': str(destinationID),
-                          'key': str(state)})
-        value = self.cur.fetchone()
-        if value == None:
-            return None
-        else:
-            return str(value[0])
-        
-    def get_summation(self, ID):
-        '''
-        Method to get the summation function type of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: summation function type of a neuron (as string).
-        '''
-        self.cur.execute('''select value from neuron_internal_states
-                            where ID=:ID and key=:key''',
-                         {'ID': str(ID),
-                          'key': 'summation'})
-        return self.cur.fetchone()
-
-    def get_transfer(self, ID):
-        '''
-        Method to get the transfer / activation function type of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: transfer / activation function type of a neuron (as string).
-        '''
-        self.cur.execute('''select value from neuron_internal_states
-                            where ID=:ID and key=:key''',
-                         {'ID': str(ID),
-                          'key': 'transfer'})
-        return self.cur.fetchone()
-
-    def get_input_values(self, ID):
-        '''
-        Method to get the input values vector of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: list of input values.
-        '''
-        self.cur.execute('''select value from neuron_input_states
-                            where ID=:ID''',
-                         {'ID': str(ID)})
-        return [float(str(x[0])) for x in self.cur.fetchall()]
-
-    def set_neuron_state(self, ID, state, value):
-        '''
-        Method to set a specific state of a neuron.
-        
-        Logging messages::
-            - set neuron internals: SNINTERNAL:<ID of neuron>:<state type of 
-            neuron>:<value of the state>
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @param state: type of state to set.
-        @type state: string
-        @param value: value to set for the state.
-        '''
-        self.cur.execute('''select value from neuron_internal_states
-                            where ID=:ID and key=:key''', 
-                         {'ID': str(ID),
-                          'key': str(state)})
-        if self.cur.fetchone() == None:
-            self.cur.execute('''insert into neuron_internal_states 
-                                (ID, key, value) values (?,?,?)''',
-                             (str(ID), str(state), value))
-        else: 
-            self.cur.execute('''update neuron_internal_states
-                                set value=:value
-                                where ID=:ID and key=:key''',
-                             {'value': value,
-                              'ID': str(ID),
-                              'key': str(state)})
-        self.log('SNINTERNAL:' + ID + ':' + str(state) + ':' + str(value))
-        self.conn.commit()
-        
-    def get_neuron_state(self, ID, state='pstate'):
-        '''
-        Method to get a specific state of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @param state: type of state to get. Default = pstate.
-        @type state: string
-        @return: state value (if present); None (if state is not found).
-        '''
-        self.cur.execute('''select value from neuron_internal_states
-                            where ID=:ID and key=:key''',
-                         {'ID': str(ID),
-                          'key': str(state)})
-        value = self.cur.fetchone()
-        if value == None:
-            return None
-        else:
-            return str(value[0])
-
-    def get_next_neurons(self, ID, stype='weight'):
-        '''
-        Method to get a set of next connected neurons (the destination neurons) 
-        from a source neuron.
-        
-        @param ID: ID of source neuron.
-        @type ID: string
-        @param stype: type of synaptic state of the synapse (connection) to get. 
-        Default = weight.
-        @type stype: string
-        @return: list of tuples (<ID of destination neuron>, <value of stype>)
-        '''
-        self.cur.execute('''select destination, value 
-                            from connectome
-                            where source=:source and key=:stype''',
-                         {'source': str(ID),
-                          'stype': stype})
-        return [(str(x[0]), float(str(x[1])))
-                for x in self.cur.fetchall()]
-
-    def set_input_states(self, sourceID, destinationID, value):
-        '''
-        Method to set an input value of a neuron. It is not mandatory to have 
-        established a prior input channel, though recommended.
-        
-        Logging messages::
-            - set neuron input: SNINPUT:<ID of source / originating neuron>:<ID 
-            of destination / sink neuron>:<value of input>
-            
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param value: value of the input.
-        '''
-        self.cur.execute('''select sourceID, ID 
-                            from neuron_input_states
-                            where sourceID=:sourceID and
-                            ID=:destinationID''',
-                         {'sourceID': str(sourceID),
-                          'destinationID': str(destinationID)})
-        if self.cur.fetchone() == None:
-            self.cur.execute('''insert into neuron_input_states
-                                (ID, sourceID, value) values (?,?,?)''', 
-                             (destinationID, sourceID, value))
-        else:
-            self.cur.execute('''update neuron_input_states
-                                set value=:value
-                                where sourceID=:sourceID and
-                                ID=:destinationID''',
-                             {'value': value,
-                              'sourceID': str(sourceID),
-                              'destinationID': str(destinationID)})
-        self.log('SNINPUT:' + str(sourceID) + ':' + str(destinationID) + \
-                 ':' + str(value))
-        self.conn.commit()
-
-    def add_external_input(self, source, destinationID, value):
-        '''
-        Method to set add an external input channel for a neuron or set an 
-        external input value into a neuron.
-        
-        Logging messages::
-            - add external input: AEXTIN:<ID of source / originating neuron>:
-            <ID of destination / sink neuron>:<value of input>
-            
-        @param source: ID of source / originating neuron.
-        @type source: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param value: value of the input.
-        '''
-        self.cur.execute('''select sourceID, ID 
-                            from neuron_input_states
-                            where sourceID=:source and
-                            ID=:destinationID''',
-                         {'source': str(source),
-                          'destinationID': str(destinationID)})
-        if self.cur.fetchone() == None:
-            self.cur.execute('''insert into neuron_input_states
-                                (ID, sourceID, value) values (?,?,?)''', 
-                             (destinationID, source, value))
-        else:
-            self.cur.execute('''update neuron_input_states
-                                set value=:value
-                                where sourceID=:sourceID and
-                                ID=:destinationID''',
-                             {'value': value,
-                              'sourceID': str(source),
-                              'destinationID': str(destinationID)})
-        self.log('AEXTIN:' + str(source) + ':' + str(destinationID) + \
-                 ':' + str(value))
-        self.conn.commit()
-        
-    def get_neurons(self, status='alive'):
-        '''
-        Method to get a list of neurons in the brain according to status.
-        
-        @param status: status of neurons to get. Default = alive.
-        @type status: string
-        @return: list of neuron IDs.
-        '''
-        self.cur.execute('select ID from neuron where status=:status',
-                         {'status': str(status)})
-        return [str(x[0]) for x in self.cur.fetchall()]
-        
-    def get_synapses(self, source, stype='weight'):
-        '''
-        Method to get a list of neurons with a specific input / source type and 
-        synaptic type.
-        
-        @param source: source type (can be ID of source neuron, or name of 
-        external source)
-        @type source: string
-        @param stype: type of synapse. To get all types of synapse, stype = 
-        'all'. Default = weight. 
-        @type stype: string
-        @return: list of destination neuron IDs
-        '''
-        if stype == 'all':
-            self.cur.execute('''
-                select destination from connectome 
-                where source=:source''',
-                {'source': str(source)})
-        else:
-            self.cur.execute('''
-                select destination from connectome 
-                where source=:source and key=:stype''',
-                {'source': str(source),
-                 'stype': str(stype)})
-        return [str(x[0]) for x in self.cur.fetchall()]
-        
-    def get_all_synapses(self):
-        '''
-        Method to get all synapses.
-        
-        @return: list of all synapses in tuple of (<source ID>, <destination 
-        ID>)
-        '''
-        self.cur.execute('select distinct source, destination from connectome')
-        return [(str(x[0]), str(x[1])) for x in self.cur.fetchall()]
-        
-    def get_all_synaptic_states(self, stype='weight'):
-        '''
-        Method to get all synaptic states of a specific type.
-        
-        @param stype: type of synapse. Default = weight. 
-        @type stype: string
-        @return: list of synaptic values.
-        '''
-        self.cur.execute('''
-            select value from connectome 
-            where key=:key''',
-            {'key': str(stype)})
-        return [str(x[0]) for x in self.cur.fetchall()]
-        
-    def get_neuronID_from_name(self, name):
-        '''
-        Method to get neuron ID from its name.
-        
-        @param name: name of neuron.
-        @type name: string
-        @return: ID of neuron (if present); None (if not found).
-        '''
-        self.cur.execute('''select ID from neuron
-                            where name=:name''',
-                         {'name': str(name)})
-        value = self.cur.fetchone()
-        if value == None:
-            return None
-        else:
-            return str(value[0])
-            
-    def get_name_from_neuronID(self, ID):
-        '''
-        Method to get neuron name from its ID.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: name of neuron (if present); None (if not found).
-        '''
-        self.cur.execute('''select name from neuron
-                            where ID=:ID''',
-                         {'ID': str(ID)})
-        value = self.cur.fetchone()
-        if value == None:
-            return None
-        else:
-            return str(value[0])
-        
-
-class Brain(object):
-    '''
-    Class to represent a neuronal network (also known as the brain), using 
-    SQLite database.
-    '''
-
-    def __init__(self, path):
-        '''
-        Constructor method - initialize a new brain, or connect to an existing 
-        brain.
-        
-        @param path: full path name of the brain file (implemented as an SQLite 
-        database.
-        @type path: string
-        '''
-        self.base = BrainBase(path)
-        self.sequence = {}
-        for ID in self.base.get_neurons('alive'):
-            self.sequence[ID] = None
-
-    def format(self):
-        self.base._format_brain()
-        
-    def add_neuron(self, **kwargs):
-        '''
-        Method to add a new neuron into the brain.
-            
-        @param kwargs: initial neuronal data (as dictionary). The following 
-        mandatory fields will be added for each neuron::
-            - name: user-defined name for the neuron. Default = no_name.
-            - summation: type of summation functions. Allowable values are 
-            'summation' (averaged input values). Default = summation.
-            - transfer: type of transfer / activation functions, which will 
-            generate the output value of the neuron. Allowable values are 
-            'linear' (neuron output = output from summation function), 
-            'sigmoid' (sigmoid curve output). Default = linear.
-            - threshold: theshold value of the neuron. Default = 0.5.
-            - pstate: initial output value of the neuron. Default = generated 
-            random value between 0-1.
-        @type kwargs: dictionary
-        @return: ID of the new neuron
-        '''
-        ID = self.base.add_neuron(**kwargs)
-        self.sequence[ID] = None
-        return ID
-
-    def add_synapse(self, sourceID, destinationID):
-        '''
-        Method to add a new synapse (connection between 2 neurons) into the 
-        brain. When either of the neurons are not present in the brain, 1 or 2 
-        neurons (depending whether 1 or both neurons are not found) will be 
-        created; however, the ID(s) of the neuron(s) will not be the same as 
-        provided. A random weight between 0 to 1 (as synaptic state) will be 
-        added.
-        
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        '''
-        self.base.add_synapse(sourceID, destinationID)
-        
-    def delete_neuron(self, ID):
-        '''
-        Method to delete a neuron from the brain and all associated synapses.
-        
-        @param ID: ID of neuron to delete
-        @type ID: string
-        '''
-        self.base.delete_neuron(ID)
-        del self.sequence[ID]
-        
-    def delete_synapse(self, sourceID, destinationID):
-        '''
-        Method to delete a synapse (connection between 2 neurons) in the brain.
-        
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        '''
-        self.base.delete_synapse(sourceID, destinationID)
-        
-    def _neuron_summation(self, ID):
-        '''
-        Private method - Calculate a single input (to be used as input for 
-        transfer / activation function) from a set of input vectors. If there 
-        is no summation function for the neuron or if the calculation returns 
-        an error (exception), 0.0 will be returned.
-        
-        @param ID: ID of neuron to calculate.
-        @type ID: string
-        @return: calculated input.
-        '''
-        sum_func = self.base.get_summation(ID)
-        if sum_func == None:
-            return 0.0
-        sum_func = str(sum_func[0])
-        neuron_input = self.base.get_input_values(ID)
-        try:
-            if sum_func == 'summation':
-                return sum(neuron_input) / len(neuron_input)
-        except: 
-            return 0.0
-
-    def _neuron_transfer(self, ID, neuron_input):
-        '''
-        Private method - Calculate the neuron output, using the transfer / 
-        activation function, from the calculated input of the summation 
-        function. If there is no transfer / activation function for the neuron 
-        or if the calculation returns an error (exception), 0.0 will be 
-        returned.
-        
-        @param ID: ID of neuron to calculate.
-        @type ID: string
-        @param neuron_input: output from _neuron_summation(), to be used as 
-        input for transfer / activation function.
-        @type neuron_input: float
-        @return: output of transfer / activation function.
-        '''
-        transfer = self.base.get_transfer(ID)
-        if transfer == None:
-            return 0.0
-        transfer = str(transfer[0])
-        try:
-            if transfer == 'linear':
-                return neuron_input
-            elif transfer == 'sigmoid':
-                return 1.0 / (1.0 + math.exp(-1.0 * neuron_input))
-        except: 
-            return 0.0
-
-    def _synaptic_activation(self, ID, state='pstate', stype='weight'):
-        '''
-        Private method - Calculate each synaptic activation from a source ID 
-        and log the values into the respective input vectors of the destination 
-        neurons.
-        
-        @param ID: ID of source neuron.
-        @type ID: string
-        @param state: state name of neuron as input for synaptic activation. 
-        Default = weight.
-        @type state: string
-        @param stype: name of synaptic state for activation. 
-        @type stype: string
-        '''
-        sourceID = ID
-        source_pstate = self.base.get_neuron_state(ID, state)
-        for n in self.base.get_next_neurons(ID, stype):
-            destinationID = n[0]
-            weight = n[1]
-            value = weight * float(source_pstate)
-            self.base.set_input_states(sourceID, destinationID, value)
-
-    def execute_neuron(self, ID, state='pstate', stype='weight'):
-        '''
-        Method to execute a neuron. 
-        
-        The following tasks will be executed for a neuron::
-            1. calculate a value from the set of input value vectors
-            2. calculate the neuronal output value from (1) using the transfer / 
-            activation function
-            3. set a neuronal state as the neuronal output value from (2)
-            4. activate synapses (using _synaptic_activation function) to 
-            generate input vector(s) for destination neuron(s).
-        
-        @param ID: ID of the neuron to execute.
-        @type ID: string
-        @param state: state of neuron to store output from transfer / 
-        activation function. Default = pstate.
-        @type state: string
-        @param stype: type of synapse for synaptic activation. Default = weight.
-        @type stype: string
-        '''
-        neuron_input = self._neuron_summation(ID)
-        pstate = self._neuron_transfer(ID, neuron_input)
-        self.base.set_neuron_state(ID, 'pstate', pstate)
-        self._synaptic_activation(ID, state, stype)
-
-    def add_input_channel(self, source, destinationID):
-        '''
-        Method to add an input channel into a neuron from external source. A 
-        random value will be added as the synaptic weight.
-        
-        @param source: name of external source
-        @type source: string
-        @param destinationID: ID of target neuron.
-        @type destinationID: string
-        '''
-        self.base.add_external_input(source, destinationID, random())
-        
-    def get_neurons(self, status='alive'):
-        '''
-        Method to get a list of neurons in the brain according to status.
-        
-        @param status: status of neurons to get. Default = alive.
-        @type status: string
-        @return: list of neuron IDs.
-        '''
-        return self.base.get_neurons(status)
-        
-    def get_synapses(self, source, stype='weight'):
-        '''
-        Method to get a list of neurons with a specific input / source type and 
-        synaptic type.
-        
-        @param source: source type (can be ID of source neuron, or name of 
-        external source)
-        @type source: string
-        @param stype: type of synapse. To get all types of synapse, stype = 
-        'all'. Default = weight. 
-        @type stype: string
-        @return: list of destination neuron IDs
-        '''
-        return self.base.get_synapses(source, stype)
-    
-    def get_all_synapses(self):
-        '''
-        Method to get all synapses.
-        
-        @return: list of all synapses in tuple of (<source ID>, <destination 
-        ID>)
-        '''
-        return self.base.get_all_synapses()
-        
-    def get_input_values(self, ID):
-        '''
-        Method to get the input values vector of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: list of input values.
-        '''
-        return self.base.get_input_values(ID)
-    
-    def set_neuron_state(self, ID, state, value):
-        '''
-        Method to set a specific state of a neuron.
-        
-        Logging messages::
-            - set neuron internals: SNINTERNAL:<ID of neuron>:<state type of 
-            neuron>:<value of the state>
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @param state: type of state to set.
-        @type state: string
-        @param value: value to set for the state.
-        '''
-        self.base.set_neuron_state(ID, state, value)
-        
-    def get_neuron_state(self, ID, state='pstate'):
-        '''
-        Method to get a specific state of a neuron.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @param state: type of state to get. Default = pstate.
-        @type state: string
-        @return: state value (if present); None (if state is not found).
-        '''
-        return self.base.get_neuron_state(ID, state)
-        
-    def set_synapse_state(self, sourceID, destinationID, 
-                          value, state='weight'):
-        '''
-        Method to set a state in a synapse.
-        
-        @param sourceID: ID of source / originating neuron.
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param value: value of the state.
-        @type value: string
-        @param state: state name to set or update.
-        @type state: string
-        '''
-        self.base.set_synapse_state(sourceID, destinationID, 
-                                    value, state)
-        
-    def get_synapse_state(self, sourceID, destinationID, state='weight'):
-        '''
-        Method to get value of a synaptic state.
-        
-        @type sourceID: string
-        @param destinationID: ID of destination / sink neuron.
-        @type destinationID: string
-        @param state: state name to set or update. Default = weight.
-        @type state: string
-        @return: value of the synaptic state (if found), or None (if state is 
-        not found)
-        '''
-        return self.base.get_synapse_state(sourceID, destinationID, state)
-        
-    def get_all_synaptic_states(self, stype='weight'):
-        '''
-        Method to get all synaptic states of a specific type.
-        
-        @param stype: type of synapse. Default = weight. 
-        @type stype: string
-        @return: list of synaptic values.
-        '''
-        return self.base.get_all_synaptic_states(stype)
-        
-    def set_input(self, source, inputstates):
-        '''
-        Method to set input values (from external) into neurons.
-        
-        @param source: name of external source.
-        @type source: string
-        @param inputstates: input values from the external source in 
-        dictionary; where key is the neuron ID to set the input value, and 
-        value is the value. For example, {'1': 0.9, '2': 0.5} means set input 
-        for neuron ID 1 as 0.9 and input for neuron ID 2 as 0.5.
-        @type inputstates: dictionary
-        '''
-        for destinationID in inputstates:
-            self.base.set_input_states(source, destinationID, 
-                                       inputstates[destinationID])
-            
-    def get_neuronID_from_name(self, name):
-        '''
-        Method to get neuron ID from its name.
-        
-        @param name: name of neuron.
-        @type name: string
-        @return: ID of neuron (if present); None (if not found).
-        '''
-        return self.base.get_neuronID_from_name(name)
-        
-    def get_name_from_neuronID(self, ID):
-        '''
-        Method to get neuron name from its ID.
-        
-        @param ID: ID of neuron.
-        @type ID: string
-        @return: name of neuron (if present); None (if not found).
-        '''
-        return self.base.get_name_from_neuronID(ID)
-        
-    def delete_orphaned_neurons(self):
-        '''
-        Method to delete orphaned neurons (neurons without any synapses).
-        '''
-        synapses = self.get_all_synapses()
-        connected_synapses = set([x[0] for x in synapses])
-        connected_synapses = connected_synapses | set([x[1] for x in synapses])
-        connected_synapses = list(connected_synapses)
-        orphans = [x for x in self.sequence if x not in connected_synapses]
-        for ID in orphans:
-            self.delete_neuron(ID)
-            
-    def delete_synapse_by_state(self, threshold=0.1, mode='lowest', 
-                                stype='weight'):
-        '''
-        Method to delete synapse(s) by thresholding on synaptic states. There 
-        are a number of ways (criterion) to select synapses for deletion. The 
-        criterion is determined by the 'mode' parameter. 
-        
-        The following criteria (modes) are allowed::
-            - lowest: select the lowest percentage of synapses, by state value, 
-            for deletion. Threshold will determine the ratio. For example, if 
-            threshold = 0.1, means the lowest decile of the synapses, by state 
-            value, will be deleted.
-            - below: select the synapses with state value below the threshold 
-            value for deletion. For example, if threshold = 0.1, means that 
-            synapses with state value lower than 0.1, will be deleted.
-        
-        @param threshold: threshold for use in deletion (as ratio). Default = 
-        lowest.
-        @type threshold: float
-        @param mode: criteria for deletion. Default = lowest.
-        @type mode: string
-        @param stype: synaptic state for use in deletion criterion. Default = 
-        weight.
-        @type stype: float
-        '''
-        states = [float(x) for x in self.get_all_synaptic_states(stype)]
-        states.sort()
-        if mode == 'lowest':
-            states = states[:int(len(states)*float(threshold))]
-        elif mode == 'below':
-            states = [x for x in states if x < float(threshold)]
-        for value in states:
-            self.base.cur.execute('''
-                select source, destination from connectome where 
-                key=:key and value=:value''',
-                {'key': str(stype),
-                 'value': str(value)})
-            result = self.base.cur.fetchone()
-            sourceID = str(result[0])
-            destinationID = str(result[1])
-            self.delete_synapse(sourceID, destinationID)
-            
-    def generate_random_synapses(self, count):
-        '''
-        '''
-        nIDs = self.get_neurons('alive')
-        
diff --git a/copads/randomize.py b/copads/randomize.py
new file mode 100644
index 0000000..eacff90
--- /dev/null
+++ b/copads/randomize.py
@@ -0,0 +1,306 @@
+'''!
+A collection of (pseudo)-random number generators
+
+Date created: 18th February 2016
+
+Licence: Python Software Foundation License version 2
+'''
+import sys
+import random
+
+try:
+    randgen = random.SystemRandom()
+except:
+    randgen = random
+
+
+class Randomizer(object):
+    '''!
+    Abstract class for all random number generators (RNG).
+    '''
+    def __init__(self, seed=None):
+        '''!
+        Constructor method.
+
+        @param seed integer: seed to start the RNG. Default = None,
+        a random seed will be generated.
+        '''
+        if seed == None:
+            self.seed = int(randgen.random()*1000000)
+        else:
+            self.seed = int(seed)
+
+    def _random(self):
+        '''!
+        Method to hold algorithm to generate a random integer. This 
+        method will be called by other methods.
+        
+        @return a random generated integer.
+        '''
+        raise NotImplementedError
+        
+    def randrange(self, start=0, stop=2147483647):
+        '''!
+        Method to generate a random integer between start and stop
+        (start < random_number <= stop).
+
+        @param start integer: lower boundary of random integer (not 
+        includsive) to generate. Default = 0.
+        @param stop integer: upper boundary of random integer (
+        inclusive) to generate. Default = 2147483647.
+        '''
+        x = self._random() + int(start)
+        return int(x % int(stop))
+
+    def randint(self):
+        '''!
+        Method to generate a random integer between 0 (not inclusive) 
+        and the maximum integer allowable by system (inclusive)
+        '''
+        return self.randrange()
+        
+    def random(self):
+        '''!
+        Method to generate a random float between zero (not inclusive)
+        and one (inclusive) (0 < random_float <= 1).
+        '''
+        x = float(self._random()) / float(self._random())
+        return abs(x) % 1
+
+    def choice(self, sequence):
+        '''!
+        Method to randomly select an element from a sequence.
+
+        @param sequence list: sequence to select from.
+        @return an element in sequence.
+        '''
+        index = self.randrange(0, len(sequence)-1)
+        return seq[index]
+
+    
+class MersenneTwister(Randomizer):
+    '''!
+    32-bit Mersenne twister algorithm (MT19937).
+    
+    Adapted from https://en.wikipedia.org/wiki/Mersenne_Twister
+    
+    Reference: Matsumoto, M., Nishimura, T. (1998). Mersenne twister:
+    a 623-dimensionally equidistributed uniform pseudo-random number
+    generator. ACM Transactions on Modeling and Computer Simulation 8
+    (1): 3-30. doi:10.1145/272991.272995
+    '''
+    def __init__(self, seed=None):
+        '''!
+        Constructor method.
+
+        @param seed integer: seed to start the RNG. Default = None,
+        a random seed will be generated.
+        '''
+        if seed == None:
+            self.seed = int(randgen.random()*1000000)
+        else:
+            self.seed = int(seed)
+        self.index = 624
+        self.block = [0] * 624
+        self.block[0] = int(self.seed)
+        for i in range(1, 624):
+            t = self.block[i-1] ^ (self.block[i-1] >> 30)
+            self.block[i] = self._int32(1812433253 * t + i)
+
+    def _int32(self, x):
+        '''!
+        Private method to get the 32 least significant bits.
+        '''
+        return int(0xFFFFFFFF & x)
+    
+    def random(self):
+        '''!
+        Method to generate a random integer.
+        
+        @return a random generated integer.
+        '''
+        if self.index >= 624: self._twist()
+        y = self.block[self.index]
+        # Right s+hift by 11 bits
+        y = y ^ (y >> 11)
+        # Shift y left by 7 and take the bitwise and of 2636928640
+        y = y ^ ((y << 7) & 2636928640)
+        # Shift y left by 15 and take the bitwise and of y and 4022730752
+        y = y ^ ((y << 15) & 4022730752)
+        # Right shift by 18 bits
+        y = y ^ (y >> 18)
+        self.index = self.index + 1
+        return self._int32(y)
+    
+    def _twist(self):
+        '''!
+        Private method to generate twist.
+        '''
+        for i in range(624):
+            # Get the most significant bit and add it to the less significant
+            # bits of the next number
+            t = self.block[(i+1) % 624] & 0x7fffffff
+            y = self._int32((self.block[i] & 0x80000000) + t)
+            self.block[i] = self.block[(i+397) % 624] ^ (y >> 1)
+            if y % 2 != 0:
+                self.block[i] = self.block[i] ^ 0x9908b0df
+        self.index = 0
+
+
+class LCG(Randomizer):
+    '''!
+    A set of linear congruential generators (LCG) and LCG-based generators to generate a sequence of pseudorandom numbers. LCG has the general equation of
+    
+    x(n+1) = [multiplier * x(n) + increment] % modulus
+        
+    where
+    
+        1. increment (also known as offset) and modulus are co-primes
+        2. (multiplier - 1) is divisible by all prime factors of modulus
+        3. (multiplier - 1) is divisible by 4 if modulus is divisible by 4
+        
+    Depending on the parameters, different LCGs exist. If increment is 
+    zero, the LCG is known as multiplicative congruential generator (
+    MCG). If increment is not zero, the LCG is known as mixed 
+    congruential generator.
+    '''
+    def __init__(self, seed=None, generator='mmix'):
+        '''!
+        Constructor method.
+
+        @param seed integer: seed to start the RNG. Default = None,
+        a random seed will be generated.
+        @param generator string: type of generator. Default = 'mmix'. Allowable types are:
+            - ansic: ANSI C (32-bit)
+            - borlandc: Borland C/C++ (32-bit)
+            - crc: CRC vector machine (48-bit)
+            - java: Java.utils.Random (48-bit)
+            - lehmer: Lehmer RNG (also known as MINSTD or Park-Miller RNG) (32-bit)
+            - lehmer2: Lehmer RNG (also known as MINSTD2)
+            - lehmer3: Lehmer RNG (also known as MINSTD3)
+            - mmix: MMIX by Donald Knuth (64-bit)
+            - newlib: NewLib (http://www.sourceware.org/newlib/) (64-bit)
+            - nag: Numerical Algorithms Group (64-bit)
+            - nr: defined in Numerical Recipes (32-bit)
+            - pascal: Borland Delphi/Visual Pascal (32-bit)
+            - vb6: Microsoft Visual Basic 6 and below (24-bit)
+            - visualc: Microsoft Visual C/C++ (32-bit)
+        '''
+        if seed == None:
+            self.seed = int(randgen.random()*1000000)
+        else:
+            self.seed = int(seed)
+        if generator == 'nr':
+            self.multiplier = 1664525
+            self.increment = 1013904223
+            self.modulus = 2**32
+        elif generator == 'borlandc':
+            self.multiplier = 22695477
+            self.increment = 1
+            self.modulus = 2**32
+        elif generator == 'pascal':
+            self.multiplier = 134775813
+            self.increment = 1
+            self.modulus = 2**32
+        elif generator == 'visualc':
+            self.multiplier = 214013	
+            self.increment = 2531011
+            self.modulus = 2**32
+        elif generator == 'vb6':
+            self.multiplier = 1140671485	
+            self.increment = 12820163
+            self.modulus = 2**24
+        elif generator == 'nag':
+            self.multiplier = 13**13
+            self.increment = 0
+            self.modulus = 2**59
+        elif generator == 'newlib':
+            self.multiplier = 6364136223846793005	
+            self.increment = 1
+            self.modulus = 2**64
+        elif generator == 'java':
+            self.multiplier = 25214903917
+            self.increment = 11
+            self.modulus = 2**48
+        elif generator == 'lehmer':
+            self.multiplier = 16807
+            self.increment = 0
+            self.modulus = 2**31 - 1
+        elif generator == 'lehmer2':
+            self.multiplier = 48271
+            self.increment = 0
+            self.modulus = 2**31 - 1
+        elif generator == 'lehmer3':
+            self.multiplier = 69621
+            self.increment = 0
+            self.modulus = 2**31 - 1
+        elif generator == 'ansic':
+            self.multiplier = 1103515245
+            self.increment = 12345
+            self.modulus = 2**31
+        elif generator == 'cdc':
+            self.multiplier = 5**15
+            self.increment = 0
+            self.modulus = 2**47
+        else:                               # generator == 'mmix'
+            self.multiplier = 6364136223846793005	
+            self.increment = 1442695040888963407
+            self.modulus = 2**64
+
+    def random(self):
+        '''!
+        Method to generate a random integer using the following 
+        equation where 
+        x(n+1) is a newly generated integer
+        
+        x(n+1) = [multiplier * x(n) + increment] % modulus
+        
+        @return a random generated integer.
+        '''
+        t = (self.multiplier * self.seed) + self.increment
+        self.seed = t % self.modulus
+        return self.seed
+
+
+class CLCG(Randomizer):
+    '''!
+    Combined linear congruential generator (CLCG), made by combining 2 
+    linear congruential generators.
+    '''
+    def __init__(self, seedA=None, generatorA='mmix',
+                 seedB=None, generatorB='mmix'):
+        '''!
+        Constructor method.
+
+        @param seedA integer: seed to start the the first LCG. Default 
+        = None, a random seed will be generated.
+        @param generatorA string: type of generator for first LCG. 
+        Default = 'mmix'. Allowable types are the same as LCG.
+        @param seedB integer: seed to start the the second LCG. 
+        Default = None, a random seed will be generated.
+        @param generatorB string: type of generator for second LCG. 
+        Default = 'mmix'. Allowable types are the same as LCG.
+        '''
+        self.LCG_A = LCG(seedA, generatorA)
+        self.LCG_B = LCG(seedB, generatorB)
+        self.modulus = max(self.LCG_A.modulus, self.LCG_B.modulus)
+        
+    def random(self):
+        '''!
+        Method to generate a random integer using the following 
+        equation where s is a newly generated integer
+        
+        x(n+1) = [multiplierX * x(n) + incrementX] % modulusX
+        
+        y(n+1) = [multiplierY * y(n) + incrementY] % modulusY
+        
+        s = [x(n+1) + y(n+1)] % max(modulusX, modulusY)
+        
+        @return a random generated integer.
+        '''
+        rA = self.LCG_A.random()
+        rB = self.LCG_B.random()
+        t = (rA + rB) % self.modulus
+        return t * self.modulus
+        
+


Test patch:
diff --git a/test/t_neural.py b/test/t_neural.py
deleted file mode 100644
index f9395f0..0000000
--- a/test/t_neural.py
+++ /dev/null
@@ -1,261 +0,0 @@
-import sys
-import os
-import copy
-import pprint
-import unittest
-
-sys.path.append(os.path.join(os.path.dirname(os.getcwd()), 'copads'))
-import neural as n
-
-brainfile = 'testbrain.db'
-
-class testSimpleBrain(unittest.TestCase):
-    '''
-    setUp(self): add_neuron()
-    setUp(self): add_synapse(x[0], x[1])
-
-    testAddNeuron1(self): get_neurons('alive')
-    testAddNeuron1(self): add_neuron()
-
-    testAddNeuron2(self): add_neuron(name='test', summation='sumtest', transfer='transfer_test', threshold='0.1', pstate='0.11')
-    testAddNeuron2(self): get_neuronID_from_name('test')
-    testAddNeuron2(self): get_name_from_neuronID(nID)
-    testAddNeuron2(self): get_neuron_state(nID, 'summation')
-    testAddNeuron2(self): get_neuron_state(nID, 'pstate')
-    
-    testGetSynapse(self): get_synapses('1', 'weight')
-    testGetSynapse(self): get_synapses('1', 'all')
-    testGetSynapse(self): get_synapses('2', 'weight')
-
-    testAddSynapse1(self): add_synapse('1', '8')
-
-    testDeleteNeuron(self): get_neurons('alive')
-    testDeleteNeuron(self): get_synapses('3', 'weight')
-    testDeleteNeuron(self): get_synapses('6', 'weight')
-    testDeleteNeuron(self): delete_neuron('6')
-    testDeleteNeuron(self): get_neurons('alive')
-    testDeleteNeuron(self): get_synapses('3', 'weight')
-    testDeleteNeuron(self): get_synapses('6', 'weight')
-
-    testDeleteOrphanedNeurons(self): delete_orphaned_neurons()
-
-    testDeleteSynapse(self): get_synapses('1', 'weight')
-    testDeleteSynapse(self): delete_synapse('1', '3')
-    testDeleteSynapse(self): get_synapses('1', 'weight')
-
-    testDeleteSynapseByState(self): add_synapse(x[0], x[1])
-    testDeleteSynapseByState(self): get_all_synaptic_states('weight')
-    testDeleteSynapseByState(self): delete_synapse_by_state(0.1, 'lowest', 'weight')
-    testDeleteSynapseByState(self): get_all_synaptic_states('weight')
-
-    testSetNeuronState(self): set_neuron_state('1', 'trialstate', 0.5)
-    testSetNeuronState(self): get_neuron_state('1', 'trialstate')
-
-    testSetSynapseState(self): set_synapse_state('1', '2', 'testvalue', 'teststate')
-    testSetSynapseState(self): get_synapse_state('1', '2', 'teststate')
-
-    testAddInputChannel(self): get_input_values('1')
-    testAddInputChannel(self): add_input_channel('eye', '1')
-    testAddInputChannel(self): get_input_values('1')
-
-    testSetInput(self): set_input('eye', {'1': 0.9})
-    testSetInput(self): get_input_values('1')
-    testSetInput(self): set_input('eye', {'1': 0.7})
-    testSetInput(self): get_input_values('1')
-    testSetInput(self): set_input('eye', {'1': 0.15})
-    testSetInput(self): get_input_values('1')
-
-    testExecuteNeuron1(self): set_input('eye', {'1': 0.15})
-    testExecuteNeuron1(self): get_input_values('1')
-    testExecuteNeuron1(self): get_neuron_state('1', 'pstate')
-    testExecuteNeuron1(self): get_input_values('2')
-    testExecuteNeuron1(self): get_input_values('3')
-    testExecuteNeuron1(self): execute_neuron('1', 'pstate', 'weight')
-    testExecuteNeuron1(self): get_neuron_state('1', 'pstate')
-    testExecuteNeuron1(self): get_input_values('2')
-    testExecuteNeuron1(self): get_input_values('3')
-
-    testExecuteNeuron2(self): set_input('eye', {'1': 0.15})
-    testExecuteNeuron2(self): get_input_values('1')
-    testExecuteNeuron2(self): get_neuron_state(str(ID), state='pstate') 
-    testExecuteNeuron2(self): execute_neuron(str(ID), 'pstate', 'weight')
-    testExecuteNeuron2(self): get_neuron_state(str(ID), state='pstate')
-    '''
-    def setUp(self):
-        self.brain = n.Brain(brainfile)
-        self.brain.format()
-        for i in range(10):
-            self.brain.add_neuron()
-        for x in [('1', '2'), ('1', '3'), ('2', '4'), ('4', '5'), ('3', '6'),
-                  ('5', '7'), ('6', '7')]:
-            self.brain.add_synapse(x[0], x[1])
-
-    def testAddNeuron1(self):
-        nIDs = self.brain.get_neurons('alive')
-        self.assertEqual(len(nIDs), 10)
-        for i in range(5):
-            self.brain.add_neuron()
-        nIDs = self.brain.get_neurons('alive')
-        self.assertEqual(len(nIDs), 15)
-
-    def testAddNeuron2(self):
-        nID = self.brain.add_neuron(name='test', summation='sumtest',
-                                    transfer='transfer_test', threshold='0.1',
-                                    pstate='0.11')
-        ID = self.brain.get_neuronID_from_name('test')
-        self.assertEqual(nID, ID)
-        name = self.brain.get_name_from_neuronID(nID)
-        self.assertEqual(name, 'test')
-        summation = self.brain.get_neuron_state(nID, 'summation')
-        self.assertEqual(summation, 'sumtest')
-        pstate = self.brain.get_neuron_state(nID, 'pstate')
-        self.assertEqual(pstate, '0.11')
-
-    def testGetSynapse(self):
-        nIDs = self.brain.get_synapses('1', 'weight')
-        self.assertEqual(nIDs, ['2', '3'])
-        nIDs = self.brain.get_synapses('1', 'all')
-        self.assertEqual(nIDs, ['2', '3'])
-        nIDs = self.brain.get_synapses('2', 'weight')
-        self.assertEqual(nIDs, ['4'])
-
-    def testAddSynapse1(self):
-        self.brain.add_synapse('1', '8')
-        nIDs = self.brain.get_synapses('1', 'weight')
-        self.assertEqual(nIDs, ['2', '3', '8'])
-
-    def testDeleteNeuron(self):
-        # before deleting neuron #6 - 10 neurons present
-        nIDs = self.brain.get_neurons('alive')
-        self.assertEqual(len(nIDs), 10)
-        # before deleting neuron #6 - (#3 --> #6)
-        nIDs = self.brain.get_synapses('3', 'weight')
-        self.assertEqual(nIDs, ['6'])
-        # before deleting neuron #6 - (#6 --> #7)
-        nIDs = self.brain.get_synapses('6', 'weight')
-        self.assertEqual(nIDs, ['7'])
-        # delete neuron #6
-        self.brain.delete_neuron('6')
-        # after deleting neuron #6 - 9 neurons present
-        nIDs = self.brain.get_neurons('alive')
-        self.assertEqual(len(nIDs), 9)
-        # after deleting neuron #6 - (#3 --> nothing)
-        nIDs = self.brain.get_synapses('3', 'weight')
-        self.assertEqual(nIDs, [])
-        # after deleting neuron #6 - (nothing --> #7)
-        nIDs = self.brain.get_synapses('6', 'weight')
-        self.assertEqual(nIDs, [])
-
-    def testDeleteOrphanedNeurons(self):
-        self.brain.delete_orphaned_neurons()
-        nIDs = self.brain.get_neurons('alive')
-        self.assertEqual(len(nIDs), 7)
-        self.assertEqual(nIDs, ['1', '2', '3', '4', '5', '6', '7'])
-
-    def testDeleteSynapse(self):
-        nIDs = self.brain.get_synapses('1', 'weight')
-        self.assertEqual(nIDs, ['2', '3'])
-        self.brain.delete_synapse('1', '3')
-        nIDs = self.brain.get_synapses('1', 'weight')
-        self.assertEqual(nIDs, ['2'])
-
-    def testDeleteSynapseByState(self):
-        # add 14 more synapses (only 7 in setUp) to 21
-        for x in [('6', '8'), ('6', '9'), ('6', '10'), 
-                  ('5', '8'), ('5', '9'), ('5', '10'), 
-                  ('7', '10'), ('8', '10'), ('9', '10'),
-                  ('3', '8'), ('3', '9'), ('3', '10'), 
-                  ('4', '8'), ('4', '9')]:
-            self.brain.add_synapse(x[0], x[1])
-        # remove lowest 10% of synapses - 2 synapses removed (19 remaining)
-        old_synaptic_states = self.brain.get_all_synaptic_states('weight')
-        self.brain.delete_synapse_by_state(0.1, 'lowest', 'weight')
-        new_synaptic_states = self.brain.get_all_synaptic_states('weight')
-        self.assertEqual(len(new_synaptic_states), 19)
-
-    def testSetNeuronState(self):
-        self.brain.set_neuron_state('1', 'trialstate', 0.5)
-        pstate = self.brain.get_neuron_state('1', 'trialstate')
-        self.assertEqual(pstate, '0.5')
-
-    def testSetSynapseState(self):
-        self.brain.set_synapse_state('1', '2', 'testvalue', 'teststate')
-        value = self.brain.get_synapse_state('1', '2', 'teststate')
-        self.assertEqual(value, 'testvalue')
-
-    def testAddInputChannel(self):
-        # before adding input channel - there is no input into neuron #1
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(len(input_vector), 0)
-        # adding input channel #eye
-        self.brain.add_input_channel('eye', '1')
-        # after adding input channel - there is 1 input into neuron #1
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(len(input_vector), 1)
-
-    def testSetInput(self):
-        # test 1
-        self.brain.set_input('eye', {'1': 0.9})
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(input_vector, [0.9])
-        # test 2
-        self.brain.set_input('eye', {'1': 0.7})
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(input_vector, [0.7])
-        # test 3
-        self.brain.set_input('eye', {'1': 0.15})
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(input_vector, [0.15])
-
-    def testExecuteNeuron1(self):
-        # set an input into neuron #1
-        self.brain.set_input('eye', {'1': 0.15})
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(input_vector, [0.15])
-        # get data before execution of neuron #1
-        old_pstate = self.brain.get_neuron_state('1', 'pstate')
-        old_input2 = self.brain.get_input_values('2')
-        old_input3 = self.brain.get_input_values('3')
-        # execute neuron #1
-        self.brain.execute_neuron('1', 'pstate', 'weight')
-        # after execution, neuron #1's pstate will be updated
-        new_pstate = self.brain.get_neuron_state('1', 'pstate')
-        self.assertNotEqual(old_pstate, new_pstate)
-        # after execution, neuron #2's input vector will be updated
-        new_input2 = self.brain.get_input_values('2')
-        self.assertEqual(len(old_input2), 0)
-        self.assertEqual(len(new_input2), 1)
-        self.assertNotEqual(old_input2, new_input2)
-        #print
-        #print 'Neuron #2 Input (before): ', old_input2
-        #print 'Neuron #2 Input (after): ', new_input2
-        # after execution, neuron #2's input vector will be updated
-        new_input3 = self.brain.get_input_values('3')
-        self.assertEqual(len(old_input2), 0)
-        self.assertEqual(len(new_input2), 1)
-        self.assertNotEqual(old_input3, new_input3)
-        #print 'Neuron #3 Input (before): ', old_input3
-        #print 'Neuron #3 Input (after): ', new_input3
-
-    def testExecuteNeuron2(self):
-        # set an input into neuron #1
-        self.brain.set_input('eye', {'1': 0.15})
-        input_vector = self.brain.get_input_values('1')
-        self.assertEqual(input_vector, [0.15])
-        # get data before execution of neurons
-        old_pstates = [self.brain.get_neuron_state(str(ID), state='pstate') 
-                       for ID in range(1, 11)]
-        # execute neurons #1 to #10
-        for ID in self.brain.sequence:
-            self.brain.execute_neuron(str(ID), 'pstate', 'weight')
-        # get data after execution of neurons
-        new_pstates = [self.brain.get_neuron_state(str(ID), state='pstate') 
-                       for ID in range(1, 11)]
-        self.assertNotEqual(old_pstates, new_pstates)
-        print("Execute Neuron 2")
-        print('pstates (before): ' + str(old_pstates))
-        print('pstates (after): ' + str(new_pstates)) 
-        
-  
-if __name__ == '__main__':
-    unittest.main()
\ No newline at end of file