Complete Correlation Matrix Memories (CCMM) Implementation
    d:todo
    1. paragraph
      1. description

    2. paragraph
      1. test of all properties that are described in Teuvo's paper

    3. paragraph
      1. abstract class which can also be used in order to implement the incomplete correlation matrix memory

    4. paragraph
      1. mutable version where values can be added and removed

    5. paragraph
      1. back end agnostic repository system

    6. paragraph
      1. repository distribution system

    7. paragraph
      1. Move this and related articles to a new project.

#!/usr/bin/env python3
"""This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Based on the paper "Correlation Matrix Memories" by TEUVO KOHONEN.
"""
__author__ = 'Mārtiņš Avots'
from testingArtifacts import floatTuple
import unittest
class CompleteCorrelationMatrixMemory():
	def __init__(self, keyValuePairs):
		for key in keyValuePairs:
			self.columns = len(key)
			self.rows = len(keyValuePairs[key])
			break
		self.matrix = [[0. for i in range(self.columns)] for j in range(self.rows)]
		keyValuePairs = self.convertKeyValuePairs(keyValuePairs)
		for iRow in range(self.rows):
			for iColumn in range(self.columns):
				for key in keyValuePairs:
					c = self.c(key) # Deviation from TEUVO's paper
					value = keyValuePairs[key]
					self.matrix[iRow][iColumn] += c * key[iColumn] * value[iRow]
	def convertKeyValuePairs(self, keyValuePairs):
		rVal = dict()
		for key in keyValuePairs:
			value = keyValuePairs[key]
			key = tuple(floatTuple(key))
			value = floatTuple(value)
			rVal[key] = value
		return rVal
	def c(self, vector):
		rBase = 0.
		for i in vector:
			rBase += i ** 2
		return 1. / rBase
	def recall(self, key):
		key = floatTuple(key)
		value = [0.]*self.rows
		for iRow in range(len(value)):
			for iColumn in range(len(key)):
				value[iRow]
				self.matrix[iRow][iColumn]
				key[iColumn]
				value[iRow] += self.matrix[iRow][iColumn] * key[iColumn]
		return floatTuple(value)
if __name__ == "__main__":
	from orthogonalKeyTests import OrthogonalKeyTests
	from randomKeyTests import RandomKeyTests
	from classificationTests import ClassificationTests
	unittest.main()
#!/usr/bin/env python3
"""This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
__author__ = 'Mārtiņš Avots'
from random import uniform, choice
def floatTuple(vector):
	rVal = []
	for e in vector:
		rVal.append(float(e))
	return rVal
def difference(a, b):
	rVal = 0.
	for i in range(len(a)):
		rVal += abs(a[i] - b[i])
	return rVal
def randomVector(length):
	rVal = []
	for i in range(length):
		rVal.append(
			uniform(-1000, 1000) # TODO Random chosen magic constants
		)
	return rVal
def randomZeroOneVector(length):
	rVal = []
	for i in range(length):
		rVal.append(choice([0,1]))
	return rVal
def randomZeroOnePositiveAndNegativeVector(length):
	rVal = []
	for i in range(length):
		rVal.append(choice([-1,0,1]))
	return rVal
def printImage(matrix, length):
	rows=int(len(matrix) / length)
	for row in range(rows):
		rowStr = ""
		for i in range(length):
			rowStr += " " + str(round(matrix[row * length + i], 2))
		print(rowStr)
	print("")
images3x3 = {
	"cross" : (1,0,1, 0,1,0, 1,0,1), # cross
	"vertical" : (0,1,0, 0,1,0, 0,1,0), # vertical
	"horizontal" : (0,0,0, 1,1,1, 0,0,0), # horizontal
	"zero" : (1,1,1, 1,0,1, 1,1,1), # zero
	"one" : (0,0,1, 0,1,1, 0,0,1), # one
	"v" : (1,0,1, 1,0,1, 0,1,0), # v
 	"seven" : (1,1,1, 0,1,0, 1,0,0), # seven
	"t" : (1,1,1, 0,1,0, 0,1,0), # t
	"h" : (1,0,1, 1,1,1, 1,0,1) # h
	}
#!/usr/bin/env python3
"""This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Based on the paper "Correlation Matrix Memories" by TEUVO KOHONEN.
"""
__author__ = 'Mārtiņš Avots'
import unittest
from completeCorrelationMatrixMemories import CompleteCorrelationMatrixMemory
from testingArtifacts import randomVector, randomZeroOneVector, difference, images3x3, randomZeroOnePositiveAndNegativeVector
from random import uniform, sample
class RandomKeyTests(unittest.TestCase):
	def testRandomKeys(self): # TODO This test fails randomly.
		self.__randomKeysTest(9, 9, lambda:randomVector(9))
	def testRandomZeroOneKeys(self): # TODO This test fails randomly.
		self.__randomKeysTest(9, 9, lambda:randomZeroOnePositiveAndNegativeVector(9))
	def __randomKeysTest(self, keySize, valueCount, randomKeyGenerator):
		values = sample(list(images3x3.values()), valueCount)
		mapping = {}
		for i in range(valueCount):
			tmpRandomVector = tuple(randomKeyGenerator())
			while tmpRandomVector in mapping:
				tmpRandomxVector = tuple(randomKeyGenerator())
			mapping[tmpRandomVector] = values[i]
		testSubject = CompleteCorrelationMatrixMemory(mapping)
		overallDifference = 0.
		for key in mapping:
			overallDifference += difference(testSubject.recall(key), mapping[key])
		meanDifference = overallDifference / (9 * 9)
		print("testRandomKeys: meanDifference = " + str(meanDifference)) # TODO make logs instead of console prints
		# Randomly generated vectors are assumed to be not orthogonal.
		# TODO check orthogonality during test and change assertions accordingly
		self.assertTrue(meanDifference < .6)
		self.assertTrue(meanDifference > .4)
#!/usr/bin/env python3
"""This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Based on the paper "Correlation Matrix Memories" by TEUVO KOHONEN.
"""
__author__ = 'Mārtiņš Avots'
from completeCorrelationMatrixMemories import CompleteCorrelationMatrixMemory
from unittest import TestCase, expectedFailure
from testingArtifacts import floatTuple, difference, images3x3
class ClassificationTests(TestCase):
	# TODO high resolution image tests
	def testClassificationOf2Images(self):
		self.__testOrthogonalKeys({
			images3x3["cross"] : (0,),
			images3x3["zero"] : (2,),
		})
	def testClassificationOf2OtherImages(self):
		self.__testOrthogonalKeys({
			images3x3["cross"] : (0,),
			images3x3["zero"] : (2,),
		})
	@expectedFailure
	def testClassificationOf9Images(self):
		"""It is not expected to work, as the keys are most propably not orthogonal"""
		self.__testOrthogonalKeys({
			images3x3["cross"] : (0,),
			images3x3["vertical"] : (1,),
			images3x3["horizontal"] : (2,),
			images3x3["zero"] : (3,),
			images3x3["one"] : (4,)
		})
	def __testOrthogonalKeys(self, mapping):
		testSubject = CompleteCorrelationMatrixMemory(mapping)
		for key in mapping:
			self.assertEqual(mapping[key][0], self.__nearestNumber(mapping.values(), testSubject.recall(key)[0]))
	def __nearestNumber(self, candidates, number):
		"""Candidate is an tuple with 1 element."""
		diff = 1000000000 # TODO magic number
		candidate = None
		for i in candidates:
			currentDiff = abs(i[0] - number)
			if currentDiff < diff:
				diff = currentDiff
				candidate = i[0]
		return candidate
    d:todo
    1. paragraph
      1. Implementation

Meta

I implemented the complete correlation matrix memories as  decribed by Teuvo Kohonen.  Tests regarding its properties are included.