package neuralnets;


import java.util.*;

import java.io.*;

 

/**
 * 
 * @author Dustin
 * 
 * 
 * original code create  by Eric J. Hilz
 *
 */

 

public class BinaryHopfield {

 

    int totalRows = 12;

    int totalColumns = 10;

    int black = 1, white = -1;

    int maxIterations = 10;   // used in the event that the network doesn't converge

    int noiseRange = 0;   // range that random number generation will use to determine bits to flip

    boolean converged = false;  // convergence is tested later

 

    // The Network

    int neuron[][] = new int[totalRows][totalColumns];   // the units

    int netInput[][] = new int[totalRows][totalColumns];  // net input to each unit

    int connection[][][][] = new int[totalRows][totalColumns][totalRows][totalColumns];  // weights

 

    BinaryHopfield() {

 

            int i, j, x, y;

 

            // initialize weights to 0

            for (i = 0; i < totalRows; ++i)

                for (j = 0; j < totalColumns; ++j)

                        for (x = 0; x < totalRows; ++x)

                            for (y = 0; y < totalColumns; ++y)

                                    connection[i][j][x][y] = 0;

    }

 

    // constructs a perfect 0 pattern by turning appropriate bits black and others white

    public void imposePerfect0() {

            int i, j;

 

            for (i = 0; i < 2; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                for (j = 2; j < 8; ++j)

                        neuron[i][j] = black;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 2; i < 10; ++i) {

                for (j = 0; j < 3; ++j)

                        neuron[i][j] = black;

                for (j = 3; j < 7; ++j)

                        neuron[i][j] = white;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 10; i < totalRows; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                for (j = 2; j < 8; ++j)

                        neuron[i][j] = black;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

    }

 

    // constructs a perfect 1 pattern by turning appropriate bits black and others white

    public void imposePerfect1() {

            int i, j;

 

            for (i = 0; i < 2; ++i) {

                for (j = 0; j < 3; ++j)

                        neuron[i][j] = white;

                for (j = 3; j < 7; ++j)

                        neuron[i][j] = black;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 2; i < 4; ++i) {

                neuron[i][0] = white;

                for (j = 1; j < 7; ++j)

                        neuron[i][j] = black;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 4; i < 10; ++i) {

                for (j = 0; j < 3; ++j)

                        neuron[i][j] = white;

                for (j = 3; j < 7; ++j)

                        neuron[i][j] = black;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 10; i < totalRows; ++i)

                for (j = 0; j < totalColumns; ++j)

                        neuron[i][j] = black;

    }

 

    // constructs a perfect 2 pattern by turning appropriate bits black and others white

    public void imposePerfect2() {

            int i, j;

 

            for (i = 0; i < 2; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                for (j = 2; j < 8; ++j)

                        neuron[i][j] = black;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 2; i < 4; ++i) {

                for (j = 0; j < 4; ++j)

                        neuron[i][j] = black;

                for (j = 4; j < 7; ++j)

                        neuron[i][j] = white;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 4; i < 5; ++i) {

                for (j = 0; j < 7; ++j)

                        neuron[i][j] = white;

                for (j = 7; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 5; i < 7; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                for (j = 2; j < 8; ++j)

                        neuron[i][j] = black;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 7; i < 8; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                neuron[i][2] = black;

                for (j = 3; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 8; i < 10; ++i) {

                for (j = 0; j < 3; ++j)

                        neuron[i][j] = black;

                for (j = 3; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 10; i < totalRows; ++i)

                for (j = 0; j < totalColumns; ++j)

                        neuron[i][j] = black;     

    }

 

    // constructs a perfect 3 pattern by turning appropriate bits black and others white

    public void imposePerfect3() {

            int i, j;

 

            for (i = 0; i < 2; ++i) {

                for (j = 0; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 2; i < 5; ++i) {

                for (j = 0; j < 8; ++j)

                        neuron[i][j] = white;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 5; i < 7; ++i) {

                for (j = 0; j < 2; ++j)

                        neuron[i][j] = white;

                for (j = 2; j < 9; ++j)

                        neuron[i][j] = black;

                for (j = 9; j < totalColumns; ++j)

                        neuron[i][j] = white;

            }

 

            for (i = 7; i < 10; ++i) {

                for (j = 0; j < 8; ++j)

                        neuron[i][j] = white;

                for (j = 8; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

            for (i = 10; i < totalRows; ++i) {

                for (j = 0; j < totalColumns; ++j)

                        neuron[i][j] = black;

            }

 

    }

 

    // Adjusts connection weights based on activations

    public void adjustWeights() {

            int i, j, x, y;

 

            for (i = 0; i < totalRows; ++i)

                for (j = 0; j < totalColumns; ++j)

                        for (x = 0; x < totalRows; ++x)

                            for (y = 0; y < totalColumns; ++y)

                                    if ((i == x) && (j == y))

                                       connection[i][j][x][y] = 0;  // self connection

                                    else if (neuron[i][j] == neuron[x][y])

                                       connection[i][j][x][y] += 1; // increment if activations are the same

                                    else

                                       connection[i][j][x][y] += -1;  // decrement if activations are different

    }

 

    // Graphically depicts the activations

    public void printPattern() {

            int i, j;

 

            for (i = 0; i < totalRows; ++i) {

                for (j = 0; j < totalColumns; ++j)

                        if (neuron[i][j] == black)

                           System.out.print("*");

                        else

                           System.out.print(" ");

                System.out.println();

            }

    }

 

    // Stores the patterns in the network's memory

    public void train() {

            // imprint a 0 pattern and adjust weights

            imposePerfect0();

            adjustWeights();

 

            // imprint a 1 pattern and adjust weights

            imposePerfect1();

            adjustWeights();

           

            // imprint a 2 pattern and adjust weights

            imposePerfect2();

            adjustWeights();

 

            // imprint a 3 pattern and adjust weights

            imposePerfect3();

            adjustWeights();

    }

 

    // Updates the activations

    public void update() {

            int i, j, x, y, sum;

 

            converged = true;  // assume no change will occur

 

            for (i = 0; i < totalRows; ++i)

                for (j = 0; j < totalColumns; ++j) {

                    sum = 0;

                        // compute net input

                        for (x = 0; x < totalRows; ++x)

                            for (y = 0; y < totalColumns; ++y)

                                    sum += neuron[x][y] * connection[i][j][x][y];

                        netInput[i][j] = sum;

                        // Update individual neuron asynchronously

                        if ((netInput[i][j] > 0) && (neuron[i][j] == white)) {

                           neuron[i][j] = black;

                           converged = false;  // a change has been made

                        }

                        else if ((netInput[i][j] < 0) && (neuron[i][j] == black)) {

                           neuron[i][j] = white;

                           converged = false;  // a change has been made

                        }

                        // else no change occurs for this neuron

                }

    }

 

    // After training, this is used to initialize the network with perfect patterns

    public void initialize() {

            int i;

 

            imposePerfect0(); // impose a perfect 0 pattern

            printPattern();  // show it

            System.out.println();

            // while not converged or maxIterations not reached, update and print the updated pattern

            for (i = 0; (i < maxIterations) && (!converged); ++i) {

                update();

                printPattern();

                System.out.println();

            }

            converged = false;  // reset converged

 

            // repeat procedure above for perfect 1, 2, and 3 patterns

 

            imposePerfect1();

            printPattern();

            System.out.println();

            for (i = 0; (i < maxIterations) && (!converged); ++i) {

                update();

               printPattern();

                System.out.println();

            }

            converged = false;

 

            imposePerfect2();

           printPattern();

            System.out.println();

            for (i = 0; (i < maxIterations) && (!converged); ++i) {

                update();

               printPattern();

                System.out.println();

            }

            converged = false;

 

            imposePerfect3();

            printPattern();

           System.out.println();

            for (i = 0; (i < maxIterations) && (!converged); ++i) {

                update();

                printPattern();

               System.out.println();

            }

            converged = false;

    }

 

    // flip a bit chosen for noise

    public void flip(int i, int j) {

            if (neuron[i][j] == black)

               neuron[i][j] = white;

            else

               neuron[i][j] = black;

    }

 

    // constructs a noisy 0 pattern based on noise range  

    public void imposeNoisy0() {

            // x is the next random number

            // gotcha is the "ticket" for a bit to be flipped

            int i, j, x, gotcha = 0;

            Random random = new Random();


            imposePerfect0();  // start with perfection

            // check to see if there is a noise range

            if (noiseRange > 0)

 

                // choose bits for flipping

                for (i = 0; i < totalRows; ++i)

                    for (j = 0; j < totalColumns; ++j) {

                            x = random.nextInt(noiseRange);

                            if (x == gotcha)

                               flip(i, j);  // flip this bit!

                        }

    }

 

    // Constructs a noisy 1 pattern using similar procedure to imposeNoisy0

    public void imposeNoisy1() {

            int i, j, x, gotcha = 0;

            Random random = new Random();

 

            imposePerfect1();

            if (noiseRange > 0)

                for (i = 0; i < totalRows; ++i)

                    for (j = 0; j < totalColumns; ++j) {

                            x = random.nextInt(noiseRange);

                            if (x == gotcha)

                               flip(i, j);

                        }

    }

 

    // Constructs a noisy 2 pattern using similar procedure to those directly above

    public void imposeNoisy2() {

            int i, j, x, gotcha = 0;

            Random random = new Random();

 

            imposePerfect2();

            if (noiseRange > 0)

                for (i = 0; i < totalRows; ++i)

                    for (j = 0; j < totalColumns; ++j) {

                            x = random.nextInt(noiseRange);

                            if (x == gotcha)

                               flip(i, j);

                        }

    }

 

    // Constructs a noisy 3 pattern using similar procedure to those directly above

    public void imposeNoisy3() {

            int i, j, x, gotcha = 0;

            Random random = new Random();

 

            imposePerfect3();

            if (noiseRange > 0)

                for (i = 0; i < totalRows; ++i)

                    for (j = 0; j < totalColumns; ++j) {

                            x = random.nextInt(noiseRange);

                            if (x == gotcha)

                               flip(i, j);

                        }

    }

 

    // After training, tests the network using noisy patterns

    public void test(float noiseLevel) {

            // maxCases is the number of times each pattern is tested

            int i, j, maxCases = 5;

            float x;

 

            // if noiseLevel > 0, then compute the range for random integer generation

            if (noiseLevel > 0) {

               x = noiseLevel;  // x is range as float 

               Float y = new Float(x); 

               //System.out.println("here is noise value" + y); 
               noiseRange = y.intValue();  // cast y as an int for noiseRange
               System.out.println("here is noise value" + noiseRange); 
            }

 

            // Test 0 pattern maxCases times

            for (i = 0; i < maxCases; ++i) {

                System.out.println("Noisy 0 case " + i);

                System.out.println("--------------");

                imposeNoisy0();  // initialize net with a noisy 0 pattern

                printPattern();  // show the pattern

                System.out.println();

                // Update activations and print next pattern until convergence or maxIterations reached

                for (j = 0; (j < maxIterations) && (!converged); ++j) {

                    update();

                    printPattern();

                    System.out.println();

                }

                converged = false;  // reset converged

            }

 

            // Repeat procedure directly above for noisy 1, 2, and 3 patterns

 

           for (i = 0; i < maxCases; ++i) {

                System.out.println("Noisy 1 case " + i);

                System.out.println("--------------");

                imposeNoisy1();

                printPattern();

                System.out.println();

                for (j = 0; (j < maxIterations) && (!converged); ++j) {

                    update();

                    printPattern();

                    System.out.println();

                }

                converged = false;

           }

 

            for (i = 0; i < maxCases; ++i) {

                System.out.println("Noisy 2 case " + i);

                System.out.println("--------------");

                imposeNoisy2();

                printPattern();

                System.out.println();

                for (j = 0; (j < maxIterations) && (!converged); ++j) {

                    update();

                    printPattern();

                    System.out.println();

                }

                converged = false;

            }

 

          for (i = 0; i < maxCases; ++i) {

                System.out.println("Noisy 3 case " + i);

                System.out.println("--------------");

                imposeNoisy3();

                printPattern();

                System.out.println();

                for (j = 0; (j < maxIterations) && (!converged); ++j) {

                    update();

                    printPattern();

                    System.out.println();

                }

                converged = false;

            }    

    }

 

    public static void main(String args []) {

            float noiseLevel;

          
            //noiseLevel =5; // get noiseLevel 
            //noiseLevel =10; // get noiseLevel 
            //noiseLevel =20; // get noiseLevel 
            noiseLevel =25; // get noiseLevel 

            BinaryHopfield net = new BinaryHopfield();

            net.train();  // train the network

             // used to initialize network with perfect patterns

            //net.initialize();

 

            net.test(noiseLevel);  // test network using noisy patterns

    }

 

};

 
