package cs437.som.network;

import cs437.som.Dimension;
import cs437.som.SOMError;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A simple self-organizing map, using a square grid for the neurons.
 *
 * An simple example usage:
 *
 * <code>
 * <pre>
 * private static final int iterations = 500;
 *
 * public static void main(String[] args) {
 *     TrainableSelfOrganizingMap som = new BasicSquareGridSOM(7, 2, iterations);
 *     Random r = new SecureRandom();
 *
 *     for (int i = 0; i < iterations; i++) {
 *         double[] in = {r.nextDouble() * 10, r.nextDouble() * 10};
 *         som.trainWith(in);
 *     }
 *
 *     // At this point, the SOM would be queried for it's BMU.
 * }
 * </pre>
 * </code>
 */
public class BasicSquareGridSOM extends NetworkBase {

    /**
     * Create a new BasicSquareGridSOM.
     *
     * @param gridSize The neuron grid dimensions.
     * @param inputVectorSize The input vector size.
     * @param expectedIterations The expected number of training iterations.
     */
    public BasicSquareGridSOM(Dimension gridSize, int inputVectorSize,
                              int expectedIterations) {
        super(gridSize, inputVectorSize, expectedIterations);
    }

    @Override
    protected double neuronDistance(int neuron0, int neuron1) {
        int row0 = neuron0 / gridSize.x;
        int col0 = neuron0 % gridSize.x;
        int row1 = neuron1 / gridSize.x;
        int col1 = neuron1 % gridSize.x;

        int dr = row1 - row0;
        int dc = col1 - col0;

        return Math.sqrt((dr * dr) + (dc * dc));
    }

    @Override
    public String toString() {
        return "BasicSquareGridSOM{time=" + time +
                ", weightMatrix=" +
                (weightMatrix == null ? null : Arrays.asList(weightMatrix)) +
                ", neuronCount=" + neuronCount +
                ", inputSize=" + inputVectorSize + '}';
    }

    @Override
    public void write(OutputStreamWriter destination) throws IOException {
        destination.write(String.format("Map type: BasicSquareGridSOM%n"));
        super.write(destination);
        destination.flush();
    }

    /**
     * Read a BasicSquareGridSOM from an input stream.
     *
     * @param input The stream to read from.  This stream should be passed in
     * as soon as it is known to represent a BasicSquareGridSOM.
     * @return A BasicSquareGridSOM as represented by the contents of
     * {@code input}.
     * @throws IOException if something fails while reading the stream.
     */
    public static BasicSquareGridSOM read(BufferedReader input) throws IOException {
        Pattern dimensionRegEx = Pattern.compile(
                "(?:grid)?\\s*dimensions\\s*:\\s*(\\d+)\\s*,\\s*(\\d+)",
                Pattern.CASE_INSENSITIVE);
        Pattern inputVectorSizeRegEx = Pattern.compile(
            "(?:input)?\\s*length\\s*:\\s*(\\d+)",
            Pattern.CASE_INSENSITIVE);
        Pattern iterationsRegEx = Pattern.compile("iterations\\s*:\\s*(\\d+)",
                Pattern.CASE_INSENSITIVE);
        Pattern weightRegEx = Pattern.compile("weights\\s*(?::)",
                Pattern.CASE_INSENSITIVE);

        Dimension dimension = null;
        int inputVectorSize = 0;
        int iterations = 0;

        String line = input.readLine();
        Matcher match = weightRegEx.matcher(line);
        while (! match.matches() && input.ready()) {
            Matcher dimMatch = dimensionRegEx.matcher(line);
            if (dimMatch.matches()) {
                dimension = new Dimension(Integer.parseInt(dimMatch.group(1)),
                        Integer.parseInt(dimMatch.group(2)));
            }

            Matcher inputMatch = inputVectorSizeRegEx.matcher(line);
            if (inputMatch.matches()) {
                inputVectorSize = Integer.parseInt(inputMatch.group(1));
            }

            Matcher iterationsMatch = iterationsRegEx.matcher(line);
            if (iterationsMatch.matches()) {
                iterations = Integer.parseInt(iterationsMatch.group(1));
            }
            line = input.readLine();
            match = weightRegEx.matcher(line);
        }

        if (dimension == null || inputVectorSize < 1) {
            throw new SOMError("A valid dimension and input vector size must" +
                    " appear in a map's configuration%nand they must appear " +
                    "before the weight matrix.");
        }

        BasicSquareGridSOM bhgsom =
                new BasicSquareGridSOM(dimension, inputVectorSize, iterations);
        bhgsom.weightMatrix =
                readWeightMatrix(input, dimension.area, inputVectorSize);
        return bhgsom;
    }
}

@@ -2749,1818 +2749,123 @@
     
-Pattern dimensionRegEx = Pattern.compile(%0A                %22(?:grid)?%5C%5Cs*dimensions%5C%5Cs*:%5C%5Cs*(%5C%5Cd+)%5C%5Cs*,%5C%5Cs*(%5C%5Cd+)%22,%0A                Pattern.CASE_INSENSITIVE);%0A        Pattern inputVectorSizeRegEx = Pattern.compile(%0A            %22(?:input)?%5C%5Cs*length%5C%5Cs*:%5C%5Cs*(%5C%5Cd+)%22,%0A            Pattern.CASE_INSENSITIVE);%0A        Pattern iterationsRegEx = Pattern.compile(%22iterations%5C%5Cs*:%5C%5Cs*(%5C%5Cd+)%22,%0A                Pattern.CASE_INSENSITIVE);%0A        Pattern weightRegEx = Pattern.compile(%22weights%5C%5Cs*(?::)%22,%0A                Pattern.CASE_INSENSITIVE);%0A%0A        Dimension dimension = null;%0A        int inputVectorSize = 0;%0A        int iterations = 0;%0A%0A        String line = input.readLine();%0A        Matcher match = weightRegEx.matcher(line);%0A        while (! match.matches() && input.ready()) %7B%0A            Matcher dimMatch = dimensionRegEx.matcher(line);%0A            if (dimMatch.matches()) %7B%0A                dimension = new Dimension(Integer.parseInt(dimMatch.group(1)),%0A                        Integer.parseInt(dimMatch.group(2)));%0A            %7D%0A%0A            Matcher inputMatch = inputVectorSizeRegEx.matcher(line);%0A            if (inputMatch.matches()) %7B%0A                inputVectorSize = Integer.parseInt(inputMatch.group(1));%0A            %7D%0A%0A            Matcher iterationsMatch = iterationsRegEx.matcher(line);%0A            if (iterationsMatch.matches()) %7B%0A                iterations = Integer.parseInt(iterationsMatch.group(1));%0A            %7D%0A            line = input.readLine();%0A            match = weightRegEx.matcher(line);%0A        %7D%0A%0A        if (dimension == null %7C%7C inputVectorSize %3C 1) %7B%0A            throw new SOMError(%22A valid dimension and input vector size must%22 +%0A                    %22 appear in a map's configuration%25nand they must appear %22 +%0A                    %22before the weight matrix.%22);%0A        %7D%0A%0A       
+SOMFileReader sfr = new SOMFileReader();%0A                sfr.parse(input);%0A%0A        BasicSquareGridSOM bsgsom = new
  Bas
@@ -2883,17 +2883,9 @@
 dSOM
- bhgsom =
+(
 %0A   
@@ -2897,39 +2897,20 @@
         
-new BasicSquareGridSOM(
+sfr.
 dimensio
@@ -2912,16 +2912,20 @@
 ension, 
+sfr.
 inputVec
@@ -2933,16 +2933,20 @@
 orSize, 
+sfr.
 iteratio
@@ -2959,17 +2959,17 @@
        b
-h
+s
 gsom.wei
@@ -2979,32 +2979,16 @@
 Matrix =
-%0A               
  readWei
@@ -3001,15 +3001,36 @@
 rix(
+%0A                
 input, 
+sfr.
 dime
@@ -3041,16 +3041,20 @@
 n.area, 
+sfr.
 inputVec
@@ -3079,17 +3079,17 @@
 return b
-h
+s
 gsom;%0A  

Change BasicSquareGridSOM to use SOMFileReader for creation from a file.