Fuzzy Cognitive Maps in C++

Here is some code I wrote to compute FCM. I used this while learning about Fuzzy Systems. Just posted here for storage.

FCM is one of the technologies in field of Soft Computing.

// *************************************************************************
// File:  FCM2.H  ver. 0.03   Date:  September 25, 1993
// By:    Josef Betancourt    System:  Borland C++ ver. 2.0.
// *************************************************************************
/*
Purpose:  Illustrate the Fuzzy Cognitive Map computations.

This is a very very simple implementation of the FCM example found in:
"Neural Networks and Fuzzy Systems". Kosko, B. page 154.
"Fuzzy Thinking, the new science of fuzzy logic". Kosko, B. page 222.
"Fuzzy Logic". McNeill D., Freiberger, P. page 237.

I used a very nice matrix class called Beginner's Understandable Matrix Package, 
BUMP.ZIP, by Clopper Almon. It is found in the Borland C++ forum on CIS. 

This version of my FCM implementation allows the setting of more than one
policy variable in the policy vector.  This is accomplished by loading
a state setting i by 2 matrix.  If column one is zero than cell i in the
policy vector is not reset by the state vector, else during the reasoning
process that cell is reset to the value in column two.

 -------------------------------------------------------------------------
 Of course, a general purpose interactive graphical system where the FCM
 can be entered graphically by multiple experts and the inference process
 is visually presented would be nice.  It should be a FCM CAD system!
 But are FCMs really useful?  How are they used in control systems?

--------------------------------------------------------------------------
USE:  This must be compiled and linked with BUMP.CPP. Large memory model.

        Example       FCM file       Policy        State
    ------------------------------------------------------------------
      Africa         AFRICA.TXT     INVEST.TXT    INVEST2.TXT
      Africa         AFRICA.TXT     DIVEST.TXT    DIVEST2.TXT
      Cocaine        COCAINE.TXT    INTERDIC.TXT  INTERDI2.TXT

    To test the africa example,
    Use the syntax:  FCM africa.txt invest.txt invest2.txt 9 .5
    or               FCM africa.txt divest.txt divest2.txt 9 .5

    To test the cocaine example in the book Fuzzy Thinking,
    Use the syntax: FCM cocaine.txt interdic.txt interdi2.txt 11 .5
    ( this example does not result in cocaine supply falling as stated in
    the book.)
*/
#ifndef FCM2_H
#define FCM2_H

// -----------------------
// dependencies
#include <iostream.h>   // for cout
#include <ctype.h>      // for isdigit()
#include <stdio.h>      // for fgets()
#include <alloc.h>      // for coreleft()
#include <stdlib.h>     // for atof()
#include <conio.h>      // for cprintf()
#include "bump.h"       // for Matrix class
// -----------------------

#define TRUE (1==1)
#define FALSE (!TRUE)

class FCM;  // forward reference.

// Prototypes
void Reason( FCM &fcm);
void Again(void);
void ThresholdMF( Matrix & mat, float thresh = .5);
void ConvertMat( Matrix & matDest, Matrix &matSrc);
void ResetPolicy( Matrix & matDest, Matrix &matSrc);
void ShowCondenseMP( Matrix &Mat);
void DrawBorder(void);


class FCM{  // Fuzzy Cognitive Map
    protected:
        Matrix *pmatFCM;    // directed graph.
        Matrix *pmatPolicy; // initial policy.
        Matrix *pmatState;  // policies to reset after epoch.
        char *Names[];      // the labels of each node.
        int   nPolicies;     // number of nodes.
        float fThreshold;
    public:
        FCM( int n);  // constructor.
        // FCM( FCM other); // copy constructor.
        // ~FCM(); // destructor.
        void  SetSizeI( int size){ nPolicies = size;}
        void  SetThresh( float fthr){ fThreshold = fthr; }
        int   IGetSize( void){ return nPolicies;}
        void  SetFCM( Matrix *fcm){ pmatFCM = fcm;}
        void  SetPolicy( Matrix *Policy){ pmatPolicy = Policy;}
        void  SetState( Matrix *State){ pmatState = State; }
        void  ReadFCM( char *psz);
        float &Cell( Matrix *pmat, int i, int j);
        float GetCell( Matrix *pmat, int i, int j);
        void  ReasonStep( void);
        void  ThresholdMF(void);
        void  ResetPolicy( void );
        void  DisplayPolicy( char *msg);
        Matrix &WhatIsPolicy( void){  return *pmatPolicy ; }
        void  DumpPolicy(void);
};

// end of file FCM2.H
#endif

// *************************************************************************
// File:  FCM2.CPP  ver. 0.03               Date:  September 25, 1993
// By:  Josef Betancourt  tcmits1@cs.com    System:  Borland C++ 4.0
// *************************************************************************
/*
Purpose:  Illustrate the Fuzzy Cognitive Map computations.

*/
// dependencies....

#include "fcm2.h"

// -----------------------------------------
//  constructor.
FCM::FCM( int size){
    SetSizeI(size );
    fThreshold = .5;
}
// -----------------------------------------
// get address of Cell.
float &FCM::Cell( Matrix *pmat, int i, int j){
    return pmat->operator[](i)[j];
}
// -----------------------------------------
// get cell contents.
float FCM::GetCell( Matrix *pmat, int i, int j){
    return pmat->operator[](i)[j];
}
// -----------------------------------------
//
void FCM::ReasonStep( void){
   // Matrix multiply.  Nice syntax!
    *pmatPolicy = (*pmatPolicy)*(*pmatFCM);
   //DisplayPolicy( "policy after multiply: ");

    ThresholdMF();
   //DisplayPolicy( "policy after threshold: ");

    ResetPolicy();
   //DisplayPolicy( "policy after reset: ");
}
// -----------------------------------------
// threshold policy vector.
void FCM::ThresholdMF( void ){
    // apply thresh to policy matrix, default thresh is 0.5.
    for( int i = 1; i < nPolicies + 1; i++){
        if( GetCell( pmatPolicy, 1, i) >= fThreshold ){
            Cell(pmatPolicy, 1, i) = 1.;
        }else{
            Cell( pmatPolicy, 1, i) = 0;
        }
    }
}
// -----------------------------------------
// reset policy with state vector.
void FCM::ResetPolicy( void ){
    for( int i = 1; i < nPolicies+1; i++){
        if( GetCell( pmatState, i,1) == 1){
            Cell( pmatPolicy, 1, i) = GetCell(pmatState, i, 2) ;
        }
    }
}
// -----------------------------------------
// show policy using matrix library display routine.
void FCM::DisplayPolicy( char *message){
    pmatPolicy->Display(message);
}
// -----------------------------------------
// dump policy as simple number dump.
void FCM::DumpPolicy(void){
    for( int i=1; i < nPolicies+1; i++){
        cout << GetCell( pmatPolicy, 1, i);
    }
}
// -----------------------
int main(int argc, char * argv[]){
    cout << "\n*** Fuzzy Cognitive Map example.  By Josef Betancourt ***\n";
    if( argc != 6 ){
     cerr << "\nUsage: fcm <FCM file> <policy file> <state file>";
     cerr << "<matrix size> <thresh>\n";
     cerr << "         Where cell and value refer to policy vector.\n";
     exit (-1);
    }
    // convert strings to integers...........
    int iSize = atoi(argv[4]); // matrix order.
    float fThresh = atof( argv[5]); // threshold value.

    FCM theFCM( iSize);

   // create the helper matrices.
    Matrix matFCM(iSize,iSize), matPolicy(1, iSize),
            matVPolicy(1,iSize), matState( iSize, 2);

   // link them into the FCM
    theFCM.SetFCM( &matFCM);
    theFCM.SetPolicy( &matPolicy);
    theFCM.SetState( &matState);
    theFCM.SetThresh( fThresh);

    // populate using files
    matFCM.ReadA( argv[1] );
    matPolicy.ReadA( argv[2] );
    matState.ReadA( argv[3] );

   // and show matrices ..........
    matFCM.Display("This is the FCM matrix:");
    matPolicy.Display("This is the policy matrix: ");
   matState.Display("This is the state matrix: ");

    cout << "test of dump\n" ;
    theFCM.DumpPolicy();

    Again();    // wait for key tap or escape.

   // perform the FCM process using the object.
    Reason(theFCM );

    return FALSE;
}  // end of main.
// -----------------------
void Reason( FCM &fcm ){
    // apply simple FCM computation using matrices.
    int i = 1;  // epoch counter.
    while( 1){
        cout << "Epoch " << i << '\n';
        fcm.ReasonStep();
        fcm.DisplayPolicy("New policy vector: ");

      // for ease in seeing limit cycles.
        ShowCondenseMP( fcm.WhatIsPolicy() );
        DrawBorder();

        Again();   // wait for key tap or escape.
        i++;
    }
} // reason end.
// -----------------------
void ShowCondenseMP( Matrix &Mat){
    // print policy vector in a more visual pattern.
    cout << "\nPattern: ";
    char temp ;
    for( int i=1; i< Mat.columns()+1; i++){
        if( Mat[1][i] > 0 ){
            temp = 0x2;
        }else{
            if( Mat[1][i] < 0){
                temp = 0x1F;
            }else{
                temp = 0x1;
            }
        }
        cout.put( temp);
    }
    cout << '\n' ;
}
// -----------------------
void DrawBorder(void){
    cout << '\n';
    for( int i=0; i<75; i++){
        cout.put( char(0xDF) );
    }
    cout << '\n';
}
// -----------------------
void Again(void){
    // query user for continuation or end of run.
    cerr << "\n\t\t\t< Tap a key to continue.  ESC to exit. >\n";
    if(getch() == 27){
        exit(0);
    }
}
// ----------------------------------------------------------------------
/*  computing Eigenvectors is similar to computing a FCM without the
     thresholding.  Here is such an algorithm.

void EigenTest(int size, char *pszName){
    // algorithim from Computational Linear Algebra with Models.
    // Williams, Gareth.  Allyn and Bacon, Massachusetts. 1978. page 449.
     float e, s, t;
     int i, j, k, M;
     Matrix A(size,size), X(size,1),Y(size,1),Z(size,1);
     A.ReadA(pszName);
     A.Display("Here is the B matrix:");
     AllOnes( X);
     while(1){
        cout << "Iteration " << i << "\n";
        Y = A * X;
        Y.Display("Here is the Y matrix:");
        k=1;
        for( j=2; j < Y.rows()+1;j++){
            if( fabs( Y[k][1]) >= fabs( Y[j][1]) ){
                continue;
            }
            k= j;
        }
        Y = ( 1/ fabs( Y[k][1])) * Y;
        X = Y;
        X.Display("the adjusted vector is:");
        Z = A*X;
        s=0;
        t=0;
        for( M=1; M<size + 1; M++){
            s += X[M][1] * Z[M][1];
            t += X[M][1] * X[M][1];
        }
        e = s/t;
        cout << "Approx eigenvalue is " << e << "\n" ;
        Again();
    }
}
*/
// -----------------------
// End of file FCM.CPP *********************************

Off topic
There are a lot of examples of connectionist presentations. I wonder if these could be coupled with the FCM technique to create computable structures. For example, look at the work of Mark Lombardi.

Links