Datafiles

Unit 1
    map
    perceptron

Unit 2
    logicgts
    perceptron


UNIT 1

map.cpp

/*This program declares a 5 x 5 two-dimensional array
called 'map' which is used to represent numerals. The
representation is achieved by entering the value 1 in
the appropriate location in the array to form the shape
of the numeral. For example, the numeral '7' is represented
in the following way (for the sake of clarity '1' has been
replaced by '*' in the diagram below):

        00000
        0***0
        00*00
        0*000
        00000.

The map array is a much simplified simulation of the way in
which computer screen images are represented in pixellated form.
In reality, the representation of even a low resolution image
would require a 320 x 240 two-dimensional array. In the map array,
'0' is chosen to represent a white pixel and '1' a black pixel.

WHAT THE PROGRAM DOES

The program initialises the map array to the empty screen
where all the pixels are white:

        00000
        00000
        00000
        00000
        00000.

The empty screen is displayed and the program then searches
the array locations to check whether the shape of the numeral
'1' has been entered (this numeral has been chosen for the sake
of simplicity). The program displays confirmation that the
representation of the numeral '1' has not been entered.

The program then enters the value 1 in the appropriate map
array locations to form the shape of the numeral '1':

        00000
        00100
        00100
        00100
        00000.

The screen representing the numeral '1' is displayed and the
program then searches the array locations to check whether
the shape of the numeral '1' has been entered. It displays
confirmation that the representation of the numeral '1' has
been entered.*/


map.cpp

//map.cpp
#include <iostream.h>

void main()
{
    int a, i, j;
     // two-dimensional array representing numeral shapes
    int map [5] [5];

    // enter 0 in all array positions and display map
    for (i=0; i<5; i++)
    {
        for (j=0; j<5; j++)
        {
            map [i] [j] = 0;
            cout << map [i] [j];
        }
        cout << endl;
    }
    cout << endl;

    // check relevant array positions for shape of numeral '1'
    a = 0;
    i=2;
    for (j=1; j<=3; j++)
    {
        if(map[j] [i] == 1)
        {
            a++;
        }
    }

    // display result
    if(a==3)
        cout << "This numeral is 1";
    else
        cout << "This numeral is not 1";

    cout << endl << endl;

    // enter 1 in relevant array positions to form shape of
    // numeral '1' and display map.
    i = 2;
    for (j=1; j<=3; j++)
    {
        map [j] [i] = 1;
    }

    for (i=0; i<5; i++)
    {
        for (j=0; j<5; j++)
        {
            cout << map [i] [j];
        }
        cout << endl;
    }

    cout << endl;

    // check relevant array positions for shape of numeral '1'
    a = 0;
    i=2;
    for (j=1; j<=3; j++)
    {
        if(map[j] [i] == 1)
        {
            a++;
        }
    }

    // display result
    if(a==3)
        cout << "This numeral is 1";
    else
        cout << "This numeral is not 1";
}


UNIT 2

    logicgts
    perceptron


logicgts.cpp

//logicgts.cpp
//program for demonstrating "supervised learning"

#include <iomanip.h>
#include <iostream.h>
#include <string.h>
#include <conio.h>


//declaration of functions for OR, AND, XOR logic gates
int or_func(int inputs[]);
int and_func(int inputs[]);
int xor_func(int inputs[]);

void main()
{
    //initial weights for neuron with two binary inputs
    int weight_a = 0, weight_b = 0;

    //input variables for neuron with two binary inputs
    int input_a, input_b;

    //variables for correct output and actual output of neuron
    int correct_output, actual_output;

    //display intial value of weights
    cout << "initial value of weights: " << endl;
    cout << "weight_a = " << weight_a << endl;
    cout << "weight_b = " << weight_b << endl << endl;

    //allow user to enter training data (two binary inputs)
    for (int i = 0; i<20; i++)
    {
        cout << "enter two inputs separated by a space: ";
        cin >> input_a >> input_b;

        //enter the training data in an AND gate
        int input[]={input_a, input_b};
        and_func(input);

        //define correct output as output of AND gate
        correct_output = and_func(input);

        //activation function (threshold value: > 1)
        if ((weight_a * input_a) + (weight_b * input_b) > 1)
        actual_output = 1;
        else
        actual_output = 0;

        //display actual output and correct output
        cout << "actual output: " << actual_output << endl;
        cout << "correct output: " << correct_output << endl;

        //adjust weights if actual output incorrect
        if (actual_output != correct_output)
        {
            weight_a = weight_a + (1 * input_a *(correct_output - actual_output));
            weight_b = weight_b + (1 * input_b*(correct_output - actual_output));
        }

        //display adjusted weights
        cout << "weight_a: " << weight_a << endl;
        cout << "weight_b: " << weight_b << endl << endl;
    }
}

    // function definitions of OR, AND, XOR logic gates

    // OR function (takes 2 inputs)
    int or_func(int inputs[])
    {
        if(inputs[0] || inputs[1])
        return 1;
        else
        return 0;
    }

    // AND function (takes 2 inputs)
    int and_func(int inputs[])
    {
        if(inputs[0] && inputs[1])
        return 1;
    else
        return 0;
    }

    // XOR (exclusive OR) function (takes 2 inputs)
    int xor_func(int inputs[])
    {
        if (!(inputs[0] && inputs[1]) &&
            ((inputs[0] || inputs[1]) || (inputs[1] || inputs[0])))
        return 1;
        else
        return 0;
    }


PERCEPTRON

function.hpp
function.cpp
percept.hpp
percept.cpp


Copy the code for the Perceptron program. Separate the individual files and save them as function.hpp, function.cpp, percept.hpp and percept.cpp in the directory you normally use for C++ programs. Create a project called 'perceptron_1' in your C++ compiler and make the function.cpp and percept.cpp files the nodes of that project.

WHAT THE PROGRAM DOES

The following edited details are taken from the description of the Perceptron program given in http://www-cse.uta.edu/~holder/courses/ai2cpp/code/mydean/05.Learning/C++Code/Perceptron/.

This program demonstrates the perceptron learning algorithm with a very simple perceptron network, a logic threshold unit. This code was written by Jon Monsarrat, [email protected].

The program is described in the following four sections:

1. The problem
2. Compiling the program
3. Running the program
4. The solution and how to read the source code

1. The problem

We have some function (let's pretend it's unknown or takes a long time to compute). We want a perceptron network to simulate the function. Unfortunately, a perceptron network must be configured with a bunch of weights that tell the network how to work. This program solves the
problem by learning the weights.

2. Compiling the program

The source code in this directory is complete and uses standard libraries which should come with any C++ compiler.

3. Running the program

Once you have created the 'perceptron_1' project in your C++ compiler, run the program and choose the function you want the network to learn. The network has been programmed to learn the following logic functions: 'OR', 'AND' and 'XOR' (i.e. 'exclusive or'). The program regards these functions as having two inputs which can be either 1 or 0.

The OR, AND and XOR functions come with the perceptron program, but you are welcome to create additional functions and add extra inputs. You'll need to write extra code to do this.

4. The solution 
- and how to read the source code

The 'functions' in the program are real C++ functions. To get all combinations of inputs, they must be generated. The perceptron program does this. It is not possible to have a partially defined
function which does not return values for some inputs.
  
The classes in the program are:

perceptron:    this holds the entire perceptron, and runs the learning algorithm;
function:         this holds a single function, which is a pointer to a real C++ function.

There are four files in this directory:

the function class:
1. function.hpp
2. function.cpp

the perceptron class:      
3. percept.hpp
4. percept.cpp.

function.hpp

/* function.hpp
 *
 * A function is a mapping from inputs to a boolean output. We read
 * this is from a file. Note the weird syntax "int (*function)(int input[])"
 * refers to a pointer to a C++ function that takes an array of inputs
 * and returns a boolean. This function pointer is called "function"
 * and can be executed by calling "int x = (*function)(inputs);".
 */

/*
 * Copyright 1994, Brown University, Providence, RI
 * See end of file for full copyright information
 */

class Function {
    int num_inputs;                 // The number of inputs this function takes
    int (* function)(int input[]);   // An actual C++ function

public:
    Function(int _num_inputs, int (* _function)(int input[]));  // constructor
    ~Function();                    // Destroy the function
    int execute(int *input);        // Execute the function, returning a boolean
    int get_num_inputs();           // Get the number of inputs for the function
};


function.cpp


 /* function.cpp
 *
 * A function is a mapping from inputs to a boolean output. We read
 * this is from a file. Note the weird syntax "int (*function)(int input[])"
 * refers to a pointer to a C++ function that takes an array of inputs
 * and returns a boolean. This function pointer is called "function"
 * and can be executed by calling "int x = (*function)(inputs);".
 */

/*
 * Copyright 1994, Brown University, Providence, RI
 * See end of file for full copyright information
 */

#include "function.hpp"

// Construct a function, given a pointer to a real C++ function and
// the number of inputs it will take
Function::Function(int _num_inputs, int (* _function)(int input[]))
{
   num_inputs = _num_inputs;
   function = _function;
}

// Destroy the function
Function::~Function()
{
}

// Execute the function, by calling the real C++ function
int Function::execute(int input[])
{
    return (*function)(input);
}

// Get the number of boolean inputs for the function
int Function::get_num_inputs()
{
   return num_inputs;
}


percept.hpp

/* percept.hpp
 *
 * This class encapsulates the entire perceptron program.
 */

/*
 * Copyright 1994, Brown University, Providence, RI
 * See end of file for full copyright information
 */

const int MAX_INPUTS = 100;
const int MAX_ADJUSTMENTS = 3000;  // Should be higher for several bit functions

class Function;
class Perceptron {
    Function *function;   // The function to be learned
   int *weights;         // The weights of the perceptron network
   int num_inputs;       // the number of inputs to the function
   int *inputs;          // An array of inputs to be given to the function

    int ltu(int input[]); // output of logic threshold unit with current weights
    int success();

public:
   void test(Function *function, int *weights);  // Learn the given function
};


percept.cpp

/* percept.cpp
 *
 * This class encapsulates the entire perceptron program.
 */

 /*
 * Copyright 1994, Brown University, Providence, RI
 * See end of file for full copyright information
 */

#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <time.h>
#include "percept.hpp"
#include "function.hpp"

// A function that takes 2 inputs.
int or_func(int inputs[])
{
    if(inputs[0] || inputs[1])
        return 1;
    else
        return 0;
}

// A function that takes 2 inputs.
int and_func(int inputs[])
{
    if(inputs[0] && inputs[1])
        return 1;
    else
        return 0;
}

// A function that takes 2 inputs.
int xor_func(int inputs[])
{
    if(inputs[0] ^ inputs[1])
        return 1;
    else
        return 0;
}

// The main() function is the first function called in this program.
// You are welcome to add more functions
// yourself, with inputs of more than just 2 bits. However, you'll
// have to compile them in. There is no example file to read.

int main()
{
    // Initialize random number generator.
#ifndef DEBUG
    srand((unsigned int) time(0));
#endif

    Perceptron perceptron;
    Function *function;

    // choose which function to test
    int choice;

    cout << "1. 'or' function" << endl;
    cout << "2. 'and' function" << endl;
    cout << "3. 'x-or' function" << endl << endl;
    cout << "Enter function to test: ";
    cin >> choice;
    cout << endl;

        switch(choice) {
        case 1:
            function = new Function(2, or_func);
            break;
        case 2:
            function = new Function(2, and_func);
            break;
        case 3:
            function = new Function(2, xor_func);
            break;
        }

    int weights[MAX_INPUTS];

    // Initialize all weights to zero
    for(int x = 0; x < function->get_num_inputs(); x++)
        weights[x] = 0;

    perceptron.test(function, weights);    // Try to learn the function

    delete function;

    return 0;
}

// Try to learn the function, given the initial weights, by iterating.
// After each iteration, test to see if we have successfully learned the
// function.
void Perceptron::test(Function *_function, int *_weights)
{
    function = _function;
    weights = _weights;
    num_inputs = function->get_num_inputs();

    inputs = new int[num_inputs];

    int result;
    int x;

    // Try to adjust the network until successful, or until too many adjustments
    for(int adjustments = 0; !success() && adjustments < MAX_ADJUSTMENTS;
         adjustments++) {

        // Choose a training example by generating inputs randomly
        cout << "Training example:";
        for(x = 0; x < num_inputs; x++) {    // Try a random input
            inputs[x] = rand() % 2;
            cout << " " << inputs[x];
        }
        cout << endl;

        result = ltu(inputs);  // Put training example into the network. Correct?

        // Now, adjust the weights
        if(result != function->execute(inputs)) {
            if(result == 0)
                for(x = 0; x < num_inputs; x++)
                    weights[x] += inputs[x];
            else
                for(x = 0; x < num_inputs; x++)
                    weights[x] -= inputs[x];
        }

        cout << "Adjusted weights:";
        for(x = 0; x < num_inputs; x++)     // Print out the weights
            cout << " " << weights[x];
        cout << endl;
    }

    delete [] inputs;

    if(adjustments < MAX_ADJUSTMENTS)
        cout << "Number of adjustments: " << adjustments << endl;
    else
        cout << "Could not learn function in "
              << MAX_ADJUSTMENTS << " adjustments." << endl;
}

// test the network against the function for all combinations of
//  inputs. For a 2-bit input function, this is no big deal, but of
//  course you couldn't do this for a 50-bit function. It would take too
//  long to generate all the inputs. So you'd probably just take a
//  random sample. This program doesn't do random sampling.
int Perceptron::success()
{
    for(int x = 0; x < num_inputs; x++)
        inputs[x] = 0;

    // This loop generates all combinations of inputs.
    // The logic threshold unit is tested for each input combination.
    x = 0;
    while(x >= 0) {
        if(ltu(inputs) != function->execute(inputs)) // test network
            return 0;
        for(x = num_inputs - 1; x >= 0; x--) {       // generate next input combo
            inputs[x] = !inputs[x];
            if(inputs[x] == 1)
                break;
        }
    }

    return 1;
}

// Here is a straight-through logic threshold unit with a fixed
// threshold of one for any length of input and weight vectors.
// Return the output given the current weights and current input
int Perceptron::ltu(int input[])
{
    int sum = 0;
    for(int x = 0; x < num_inputs; x++)
        sum += inputs[x] * weights[x];

    if(sum > 1)
        return 1;
    else
        return 0;
}

/*
 * Copyright 1994, Brown University, Providence, RI
 *
 * Permission to use and modify this software and its documentation for
 * any purpose other than its incorporation into a commercial product is
 * hereby granted without fee.  Permission to copy and distribute this
 * software and its documentation only for non-commercial use is also
 * granted without fee, provided, however, that the above copyright notice
 * appear in all copies, that both that copyright notice and this permission
 * notice appear in supporting documentation, that the name of Brown
 * University not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission,
 * and that the person doing the distribution notify Brown University of
 * such distributions outside of his or her organization. Brown University
 * makes no representations about the suitability of this software for
 * any purpose.  It is provided "as is" without express or implied warranty.
 * Brown University requests notification of any modifications to this
 * software or its documentation.
 *
 * Send the following redistribution information:
 *
 *    Name:
 *    Organization:
 *    Address (postal and/or electronic):
 *
 * To:
 *    Software Librarian
 *    Computer Science Department, Box 1910
 *    Brown University
 *    Providence, RI 02912
 *
 *        or
 *
 *    [email protected]
 *
 * We will acknowledge all electronic notifications.
 */