// NeuronNetwork.java /** A Java program to read and output a textual description of a neuron network. * @Author Douglas W. Jones * @Version Mar. 4, 2015 */ import java.io.File; import java.io.FileNotFoundException; import java.util.LinkedList; import java.util.Scanner; // Utility classes /** Error reporting methods */ class Errors { static void fatal( String message ) { System.err.println( "Fatal error: " + message ); System.exit( 1 ); } static void warning( String message ) { System.err.println( "Error: " + message ); } } /** Input scanning support methods */ class ScanSupport { /** Force there to be a line end here, complain if not */ static void lineEnd( Scanner sc, String message ) { String skip = sc.nextLine(); if (!"".equals( skip )) { // Bug: do we want to allow comments here Errors.warning( message + " -- expected a newline" ); } // Bug: what if sc.nextLine() was illegal (illegal state) } /** Get the next float, or complain if there isn't one */ static String nextName( Scanner sc, String message ) { if (sc.hasNext( "[a-zA-Z]\\w*" )) { return sc.next(); } else { Errors.warning( message + " -- expected a name" ); return null; } } /** Get the next float, or complain if there isn't one */ static float nextFloat( Scanner sc, String message ) { if (sc.hasNextFloat()) { return sc.nextFloat(); } else { Errors.warning( message + " -- expected a number" ); return 99.99f; } } } // Simulation classes /** Neurons are the vertices in the neuron network * @see Synapse */ class Neuron { String name; // name of this neuron private float threshold; // voltage at which the neuron fires private float voltage; // voltage at the given time private float time; // (see above) private LinkedList synapses; // the outputs of this neuron public class IllegalNameException extends Exception {} // initializer public Neuron( Scanner sc ) throws IllegalNameException { // scan and process one neuron name = ScanSupport.nextName( sc, "Neuron ??" ); if (name == null) { sc.nextLine(); throw new IllegalNameException(); } if (NeuronNetwork.findNeuron( name ) != null) { Errors.warning( "Neuron " + name + " -- duplicate declaration" ); sc.nextLine(); throw new IllegalNameException(); } threshold = ScanSupport.nextFloat( sc, "Neuron " + name ); voltage = ScanSupport.nextFloat( sc, "Neuron " + name ); time = 0.0f; ScanSupport.lineEnd( sc, "Neuron " + name ); } // other methods public String toString() { return ( "Neuron " + name + " " + threshold + " " + voltage ); } } /** Synapses join neurons * @see Neuron */ class Synapse { Neuron source; Neuron destination; Float delay; Float strength; // name is source destination public Synapse( Scanner sc ) { // scan and process one synapse String sourceName = ScanSupport.nextName( sc, "Synapse ??" ); String dstName = ScanSupport.nextName( sc, "Synapse " + ( sourceName != null ? sourceName : "??" ) + " ??" ); delay = ScanSupport.nextFloat( sc, "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + " ??" ); strength = ScanSupport.nextFloat( sc, "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + " " + delay + " ??" ); ScanSupport.lineEnd( sc, "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + delay + " " + strength ); // check correctness of fields source = NeuronNetwork.findNeuron( sourceName ); if (source == null) { Errors.warning( "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + " -- no such source" ); } destination = NeuronNetwork.findNeuron( dstName ); if (destination == null) { Errors.warning( "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + " -- no such destination" ); } if (delay < 0.0f) { Errors.warning( "Synapse " + ( sourceName != null ? sourceName : "??" ) + " " + ( dstName != null ? dstName : "??" ) + " " + delay + " " + strength + " -- illegal negative delay" ); delay = 99.99f; } } // other methods public String toString() { return ( "Synapse " + ( source != null ? source.name : "---" ) + " " + ( destination != null ? destination.name : "---" ) + " " + delay + " " + strength ); } } /** NeuronNetwork is the main class that builds the whole model * @see Neuron * @see Synapse */ public class NeuronNetwork { // the sets of all neurons and all synapses static LinkedList neurons = new LinkedList (); static LinkedList synapses = new LinkedList (); /** Look up s in neurons, find that Neuron if it exists * return null if not. */ public static Neuron findNeuron( String s ) { for (Neuron n: neurons) { if (n.name.equals(s)) { return n; } } return null; } /** Initialize the neuron network by scanning its description */ static void initializeNetwork( Scanner sc ) { while (sc.hasNext()) { String command = sc.next(); if ("neuron".equals( command )) { try { neurons.add( new Neuron( sc ) ); } catch (Neuron.IllegalNameException e) { // no action required } } else if ("synapse".equals( command )) { synapses.add( new Synapse( sc ) ); } else { Errors.warning( command + " -- what is that" ); sc.nextLine(); } } } /** Print out the neuron network from the data structure */ static void printNetwork() { for (Neuron n:neurons) { System.out.println( n.toString() ); } for (Synapse s:synapses) { System.out.println( s.toString() ); } } /** Main program * @see initializeNetwork */ public static void main(String[] args) { try { if (args.length < 1) { Errors.fatal( "-- missing file name" ); } if (args.length > 1) { Errors.fatal( "-- too many arguments" ); } initializeNetwork( new Scanner(new File(args[0])) ); } catch (FileNotFoundException e) { Errors.fatal( "" + args[0] + " -- file not found" ); } printNetwork(); } }