See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Associative Memory
  Submitted by



This code shows the pattern recognition capabilities of the Hopfield Associative memory. The example provided is simple but you can easily add some more complex stuff in it. For example, the user crudely draws something on the screen, you create a bounding box of what has been drawn and then divide the box in 64 cells, filled with a '1' if there are pixels in it, a '0' if not.

Pernission to use the stuff, as it has been itself heavily inspired by the tuts at www.generation5.org

Samy aka Atma
samchan@club-internet.fr

Currently browsing [assocmem.zip] (47,038 bytes) - [Doc/truc/truc.cpp] - (2,125 bytes)

// truc.cpp : Defines the entry point for the console application.
//

#include "CAssocMem.h"
#include "stdafx.h"
#include <iostream.h>
#include <conio.h>

void myprint(int* tmp) { unsigned long cpt; for (cpt = 0; cpt<64; cpt++) { if ((cpt % 8) == 0) cout << endl; if (tmp[cpt] == 0) cout << ' '; else cout << '*';

} cout << endl; }

int main(int argc, char* argv[]) { int * set[2]; int pattern1[64] = {0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,1,0,0,0,0,1,0, 0,1,0,0,0,0,1,0, 0,1,0,0,0,0,1,0, 0,1,0,0,0,0,1,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0};

int pattern2[64] = {1,0,0,0,0,0,0,1, 0,1,0,0,0,0,1,0, 0,0,1,0,0,1,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,1,0,0,1,0,0, 0,1,0,0,0,0,1,0, 1,0,0,0,0,0,0,1};

set[0] = pattern1; set[1] = pattern2;

CAssocmem truc(64);

truc.Train(set, 2);

cout << "Recognizing:\n"; myprint(set[0]); cout << "\n and \n"; myprint(set[1]);

cout << "\nPress a key...\n" << endl; getch(); int berk[64] = {1,0,0,1,0,0,0,1, 0,1,0,0,0,0,1,0, 1,1,1,0,0,1,0,1, 0,0,0,1,1,0,1,0, 0,0,0,1,1,0,0,0, 1,0,1,0,0,1,0,0, 0,1,0,0,0,0,1,0, 1,0,0,0,1,0,0,1};

int berk2[64] = {0,0,1,0,1,0,1,0, 0,1,1,1,1,1,1,1, 1,1,0,0,0,0,1,1, 1,1,0,0,1,0,1,1, 1,1,0,0,0,0,1,0, 0,1,0,1,0,0,1,0, 1,1,1,1,1,1,1,1, 0,0,1,0,1,0,1,0};

cout << "Oh, my God, an ugly evil pattern...\n"; myprint(berk); cout << "\nThere it goes, in fact it is a...\n";

truc.Run(berk); myprint(truc.Get_Outputs()); cout << "\nPress a key...\n" << endl; getch();

cout << "Oh, my God, yet another ugly evil pattern\n"; myprint(berk2); cout << "\nAH! recognized you...\n";

truc.Run(berk2); myprint(truc.Get_Outputs());

cout << "Hooray for the associative memory\nContact me: Atma samchan@club-internet.fr\n"; cout << "Heavily inspired by the tuts at www.generation5.org\n"; return 0; }


Currently browsing [assocmem.zip] (47,038 bytes) - [Doc/truc/CAssocmem.h] - (1,920 bytes)

/*****************************************/
/*  Header Hopfield pattern learner      */
/*****************************************/

#ifndef CLASS_CASSOCMEM_ATMA #define CLASS_CASSOCMEM_ATMA

/*****************************************/

#include <stdlib.h> #include <iostream.h> #include <time.h>

/*****************************************/

#define LEARNING_RATE (float)0.5

/*****************************************/

#ifndef ULONG typedef unsigned long ULONG; #endif

/*****************************************/

#define _go_binary(x) ((x == -1) ? 0 : 1) #define _go_bipolar(x) ((x) ? 1 : -1)

/*****************************************/

/*-----------------------------------------------------------------------*\ Namespace: Atma, finally not :) \*-----------------------------------------------------------------------*/

/*namespace Atma {*/

class CAssocmem { public: /*Constructors and destructor*/ CAssocmem(); CAssocmem(ULONG size); ~CAssocmem(); /*Training function*/ void Train(int** input, ULONG nb_patterns); void Run(int* input); int* Get_Outputs(); private:

void Process_Net(); bool Process_Neuron(ULONG number);

void Set_Treshold(); ULONG nb_neurons; int** weights; int* treshold; int* outputs; };

/*-----------------------------------------------------------------------*\ End of namespace \*-----------------------------------------------------------------------*/

//} /*****************************************/

#endif

/*****************************************/ /* EOF */ /*****************************************/

Currently browsing [assocmem.zip] (47,038 bytes) - [Doc/truc/StdAfx.cpp] - (291 bytes)

// stdafx.cpp : source file that includes just the standard includes
//	truc.pch will be the pre-compiled header
//	stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H // and not in this file

Currently browsing [assocmem.zip] (47,038 bytes) - [Doc/truc/StdAfx.h] - (769 bytes)

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__9B66AE34_4762_11D4_9F0D_00508B62A795__INCLUDED_)
#define AFX_STDAFX_H__9B66AE34_4762_11D4_9F0D_00508B62A795__INCLUDED_

#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include <stdio.h>

// TODO: reference additional headers your program requires here //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_STDAFX_H__9B66AE34_4762_11D4_9F0D_00508B62A795__INCLUDED_)

Currently browsing [assocmem.zip] (47,038 bytes) - [Doc/truc/CAssocmem.cpp] - (5,128 bytes)

/*****************************************/
/*  Class Hopfield pattern learner       */
/*****************************************/

#include "CAssocmem.h"

/*****************************************/

/*-----------------------------------------------------------------------*\ using namespace: ... \*-----------------------------------------------------------------------*/

//using namespace Atma; // NOT :) // A lil' comment: this is an old version of the stuff: one should use exceptions and automatic stack unwinding // for the class ( see www.relisoft.com -> tuts for info on automatic stack unwinding) CAssocmem::CAssocmem() { srand(time(NULL)); weights =NULL; treshold =NULL; outputs =NULL; nb_neurons =NULL; }

CAssocmem::CAssocmem(ULONG size) { ULONG cpt; ULONG tmp; srand(time(NULL)); nb_neurons =size; treshold =new int[size]; if (treshold==NULL) { cerr << "Error allocating memory" << endl; nb_neurons =0; weights =NULL; outputs =NULL; return; } outputs =new int[size]; if (outputs==NULL) { cerr << "Error allocating memory" << endl; nb_neurons =0; weights =NULL; delete[] treshold; treshold =NULL; return; }

weights =new int*[size]; if (weights==NULL) { cerr << "Error allocating memory" << endl; nb_neurons =0; delete[] treshold; treshold =NULL; delete[] outputs; outputs =NULL; return; }

for (cpt=0; cpt<size; cpt++) { weights[cpt]=new int[size]; if (weights[cpt]==NULL) { cerr << "Error allocating memory" << endl; nb_neurons =0; delete[] treshold; treshold =NULL; delete[] outputs; outputs =NULL; for (tmp=0; tmp<cpt; tmp++) { delete[] weights[tmp]; } delete[] weights; weights =NULL; return; } } Set_Treshold(); }

CAssocmem::~CAssocmem() { ULONG cpt; if (treshold!=NULL) /*We need to test just one, cause if one is, the others are too*/ { delete[] treshold; delete[] outputs; for (cpt=0; cpt<nb_neurons; cpt++) { delete[] weights[cpt]; } delete[] weights; treshold=NULL; outputs =NULL; weights =NULL; nb_neurons=0; } }

/*****************************************/

void CAssocmem::Train(int** input, ULONG nb_patterns) { ULONG cpt1; ULONG cpt2; ULONG nb; int cur_weight; for(cpt1=0; cpt1<nb_neurons; cpt1++) { for (cpt2=0; cpt2<nb_neurons; cpt2++) { cur_weight=0;

if (cpt1 != cpt2) { for (nb=0; nb<nb_patterns; nb++) { cur_weight += _go_bipolar(input[nb][cpt1]) * _go_bipolar(input[nb][cpt2]); } }

weights[cpt1][cpt2] = cur_weight; } } }

/*****************************************/

void CAssocmem::Set_Treshold() { ULONG cpt; if (treshold!=NULL) { for (cpt=0; cpt<nb_neurons; cpt++) { treshold[cpt]=0; } } }

/*****************************************/

void CAssocmem::Process_Net() { ULONG chosen_neuron; ULONG current; ULONG last; current =0; last =0; do { current++; chosen_neuron=rand()%nb_neurons; if (Process_Neuron(chosen_neuron)==true) { last=current; } } while (current-last < 10*nb_neurons); }

/*****************************************/

bool CAssocmem::Process_Neuron(ULONG number) { ULONG cpt; int sum; int result; bool is_changed; sum=0; is_changed=false; for (cpt=0; cpt<nb_neurons; cpt++) { sum+=weights[number][cpt]*outputs[cpt]; } if (sum!=treshold[number]) { if (sum>treshold[number]) result=1; else result=-1; if (result!=outputs[number]) { is_changed=true; outputs[number]=result; } } return is_changed; }

/*****************************************/

int* CAssocmem::Get_Outputs() { ULONG cpt; for (cpt=0; cpt<nb_neurons; cpt++) { outputs[cpt]=_go_binary(outputs[cpt]); } return outputs; }

/*****************************************/

void CAssocmem::Run(int* input) { ULONG cpt; for (cpt=0; cpt<nb_neurons; cpt++) { outputs[cpt]=_go_bipolar(input[cpt]); } Process_Net(); }

/*****************************************/ /* EOF */ /*****************************************/

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.