Complete Correlation Matrix Memories (CCMM) Implementation
    d:todo
    • paragraph
      • description
    • paragraph
      • test of all properties that are described in Teuvo's paper
    • paragraph
      • abstract class which can also be used in order to implement the incomplete correlation matrix memory
    • paragraph
      • mutable version where values can be added and removed
    • paragraph
      • back end agnostic repository system
    • paragraph
      • repository distribution system
    • paragraph
      • 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
    • paragraph
      • Implementation