"));
+
+ newVector.addAll(Collections.list(super.listOptions()));
+
+ return newVector.elements();
+ }
+
+ /**
+ * Parses a given list of options.
+ *
+ *
+ * Valid options are:
+ *
+ *
+ *
+ * -N <int>
+ * Number of hidden units (default is 2).
+ *
+ *
+ *
+ * -R <double>
+ * Ridge factor for quadratic penalty on weights (default is 0.01).
+ *
+ *
+ *
+ * -O <double>
+ * Tolerance parameter for delta values (default is 1.0e-6).
+ *
+ *
+ *
+ * -G
+ * Use conjugate gradient descent (recommended for many attributes).
+ *
+ *
+ *
+ * -P <int>
+ * The size of the thread pool, for example, the number of cores in the CPU. (default 1)
+ *
+ *
+ *
+ * -E <int>
+ * The number of threads to use, which should be >= size of thread pool. (default 1)
+ *
+ *
+ *
+ * -S <num>
+ * Random number seed.
+ * (default 1)
+ *
+ *
+ *
+ *
+ * Options after -- are passed to the designated classifier.
+ *
+ *
+ * @param options the list of options as an array of strings
+ * @throws Exception if an option is not supported
+ */
+ @Override
+ public void setOptions(String[] options) throws Exception {
+
+ String numFunctions = Utils.getOption('N', options);
+ if (numFunctions.length() != 0) {
+ setNumFunctions(Integer.parseInt(numFunctions));
+ } else {
+ setNumFunctions(2);
+ }
+ String Ridge = Utils.getOption('R', options);
+ if (Ridge.length() != 0) {
+ setRidge(Double.parseDouble(Ridge));
+ } else {
+ setRidge(0.01);
+ }
+ String Tolerance = Utils.getOption('O', options);
+ if (Tolerance.length() != 0) {
+ setTolerance(Double.parseDouble(Tolerance));
+ } else {
+ setTolerance(1.0e-6);
+ }
+ m_useCGD = Utils.getFlag('G', options);
+ String PoolSize = Utils.getOption('P', options);
+ if (PoolSize.length() != 0) {
+ setPoolSize(Integer.parseInt(PoolSize));
+ } else {
+ setPoolSize(1);
+ }
+ String NumThreads = Utils.getOption('E', options);
+ if (NumThreads.length() != 0) {
+ setNumThreads(Integer.parseInt(NumThreads));
+ } else {
+ setNumThreads(1);
+ }
+
+ super.setOptions(options);
+
+ Utils.checkForRemainingOptions(options);
+ }
+
+ /**
+ * Gets the current settings of the Classifier.
+ *
+ * @return an array of strings suitable for passing to setOptions
+ */
+ @Override
+ public String[] getOptions() {
+
+ Vector options = new Vector();
+
+ options.add("-N");
+ options.add("" + getNumFunctions());
+
+ options.add("-R");
+ options.add("" + getRidge());
+
+ options.add("-O");
+ options.add("" + getTolerance());
+
+ if (m_useCGD) {
+ options.add("-G");
+ }
+
+ options.add("-P");
+ options.add("" + getPoolSize());
+
+ options.add("-E");
+ options.add("" + getNumThreads());
+
+ Collections.addAll(options, super.getOptions());
+
+ return options.toArray(new String[0]);
+ }
+
+ /**
+ * Outputs the network as a string.
+ */
+ @Override
+ public String toString() {
+
+ if (m_ZeroR != null) {
+ return m_ZeroR.toString();
+ }
+
+ if (m_MLPParameters == null) {
+ return "Classifier not built yet.";
+ }
+
+ String s = "MLPClassifier with ridge value " + getRidge() + " and "
+ + getNumFunctions() + " hidden units (useCGD=" + getUseCGD() + ")\n\n";
+
+ for (int i = 0; i < m_numUnits; i++) {
+ for (int j = 0; j < m_numClasses; j++) {
+ s += "Output unit " + j + " weight for hidden unit " + i + ": "
+ + m_MLPParameters[OFFSET_WEIGHTS + j * (m_numUnits + 1) + i] + "\n";
+ }
+ s += "\nHidden unit " + i + " weights:\n\n";
+ for (int j = 0; j < m_numAttributes; j++) {
+ if (j != m_classIndex) {
+ s += m_MLPParameters[OFFSET_ATTRIBUTE_WEIGHTS + (i * m_numAttributes)
+ + j]
+ + " " + m_data.attribute(j).name() + "\n";
+ }
+ }
+ s += "\nHidden unit "
+ + i
+ + " bias: "
+ + m_MLPParameters[OFFSET_ATTRIBUTE_WEIGHTS
+ + (i * m_numAttributes + m_classIndex)] + "\n\n";
+ }
+ for (int j = 0; j < m_numClasses; j++) {
+ s += "Output unit " + j + " bias: "
+ + m_MLPParameters[OFFSET_WEIGHTS + j * (m_numUnits + 1) + m_numUnits]
+ + "\n";
+ }
+
+ return s;
+ }
+
+ /**
+ * Main method to run the code from the command-line using the standard WEKA
+ * options.
+ */
+ public static void main(String[] argv) {
+
+ runClassifier(new MLPClassifier(), argv);
+ }
+}
diff --git a/src/weka/classifiers/functions/neural/NeuralConnection.java b/src/weka/classifiers/functions/neural/NeuralConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..3aea9c7a304d28c791c6b38704e2ecf88a94b3a2
--- /dev/null
+++ b/src/weka/classifiers/functions/neural/NeuralConnection.java
@@ -0,0 +1,746 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * NeuralConnection.java
+ * Copyright (C) 2000 University of Waikato, Hamilton, New Zealand
+ */
+
+package weka.classifiers.functions.neural;
+
+import weka.core.RevisionHandler;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.io.Serializable;
+
+/**
+ * Abstract unit in a NeuralNetwork.
+ *
+ * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
+ * @version $Revision: 5402 $
+ */
+public abstract class NeuralConnection
+ implements Serializable, RevisionHandler {
+
+ /** for serialization */
+ private static final long serialVersionUID = -286208828571059163L;
+
+ //bitwise flags for the types of unit.
+
+ /** This unit is not connected to any others. */
+ public static final int UNCONNECTED = 0;
+
+ /** This unit is a pure input unit. */
+ public static final int PURE_INPUT = 1;
+
+ /** This unit is a pure output unit. */
+ public static final int PURE_OUTPUT = 2;
+
+ /** This unit is an input unit. */
+ public static final int INPUT = 4;
+
+ /** This unit is an output unit. */
+ public static final int OUTPUT = 8;
+
+ /** This flag is set once the unit has a connection. */
+ public static final int CONNECTED = 16;
+
+ /** This unit is a feedback unit. */
+ public static final int FEEDBACK = 32;
+
+ /////The difference between pure and not is that pure is used to feed
+ /////the neural network the attribute values and the errors on the outputs
+ /////Beyond that they do no calculations, and have certain restrictions
+ /////on the connections they can make.
+
+
+
+ /** The list of inputs to this unit. */
+ protected NeuralConnection[] m_inputList;
+
+ /** The list of outputs from this unit. */
+ protected NeuralConnection[] m_outputList;
+
+ /** The numbering for the connections at the other end of the input lines. */
+ protected int[] m_inputNums;
+
+ /** The numbering for the connections at the other end of the out lines. */
+ protected int[] m_outputNums;
+
+ /** The number of inputs. */
+ protected int m_numInputs;
+
+ /** The number of outputs. */
+ protected int m_numOutputs;
+
+ /** The output value for this unit, NaN if not calculated. */
+ protected double m_unitValue;
+
+ /** The error value for this unit, NaN if not calculated. */
+ protected double m_unitError;
+
+ /** True if the weights have already been updated. */
+ protected boolean m_weightsUpdated;
+
+ /** The string that uniquely (provided naming is done properly) identifies
+ * this unit. */
+ protected String m_id;
+
+ /** The type of unit this is. */
+ protected int m_type;
+
+ /** The x coord of this unit purely for displaying purposes. */
+ protected double m_x;
+
+ /** The y coord of this unit purely for displaying purposes. */
+ protected double m_y;
+
+
+
+
+ /**
+ * Constructs The unit with the basic connection information prepared for
+ * use.
+ *
+ * @param id the unique id of the unit
+ */
+ public NeuralConnection(String id) {
+
+ m_id = id;
+ m_inputList = new NeuralConnection[0];
+ m_outputList = new NeuralConnection[0];
+ m_inputNums = new int[0];
+ m_outputNums = new int[0];
+
+ m_numInputs = 0;
+ m_numOutputs = 0;
+
+ m_unitValue = Double.NaN;
+ m_unitError = Double.NaN;
+
+ m_weightsUpdated = false;
+ m_x = 0;
+ m_y = 0;
+ m_type = UNCONNECTED;
+ }
+
+
+ /**
+ * @return The identity string of this unit.
+ */
+ public String getId() {
+ return m_id;
+ }
+
+ /**
+ * @return The type of this unit.
+ */
+ public int getType() {
+ return m_type;
+ }
+
+ /**
+ * @param t The new type of this unit.
+ */
+ public void setType(int t) {
+ m_type = t;
+ }
+
+ /**
+ * Call this to reset the unit for another run.
+ * It is expected by that this unit will call the reset functions of all
+ * input units to it. It is also expected that this will not be done
+ * if the unit has already been reset (or atleast appears to be).
+ */
+ public abstract void reset();
+
+ /**
+ * Call this to get the output value of this unit.
+ * @param calculate True if the value should be calculated if it hasn't been
+ * already.
+ * @return The output value, or NaN, if the value has not been calculated.
+ */
+ public abstract double outputValue(boolean calculate);
+
+ /**
+ * Call this to get the error value of this unit.
+ * @param calculate True if the value should be calculated if it hasn't been
+ * already.
+ * @return The error value, or NaN, if the value has not been calculated.
+ */
+ public abstract double errorValue(boolean calculate);
+
+ /**
+ * Call this to have the connection save the current
+ * weights.
+ */
+ public abstract void saveWeights();
+
+ /**
+ * Call this to have the connection restore from the saved
+ * weights.
+ */
+ public abstract void restoreWeights();
+
+ /**
+ * Call this to get the weight value on a particular connection.
+ * @param n The connection number to get the weight for, -1 if The threshold
+ * weight should be returned.
+ * @return This function will default to return 1. If overridden, it should
+ * return the value for the specified connection or if -1 then it should
+ * return the threshold value. If no value exists for the specified
+ * connection, NaN will be returned.
+ */
+ public double weightValue(int n) {
+ return 1;
+ }
+
+ /**
+ * Call this function to update the weight values at this unit.
+ * After the weights have been updated at this unit, All the
+ * input connections will then be called from this to have their
+ * weights updated.
+ * @param l The learning Rate to use.
+ * @param m The momentum to use.
+ */
+ public void updateWeights(double l, double m) {
+
+ //the action the subclasses should perform is upto them
+ //but if they coverride they should make a call to this to
+ //call the method for all their inputs.
+
+ if (!m_weightsUpdated) {
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ m_inputList[noa].updateWeights(l, m);
+ }
+ m_weightsUpdated = true;
+ }
+
+ }
+
+ /**
+ * Use this to get easy access to the inputs.
+ * It is not advised to change the entries in this list
+ * (use the connecting and disconnecting functions to do that)
+ * @return The inputs list.
+ */
+ public NeuralConnection[] getInputs() {
+ return m_inputList;
+ }
+
+ /**
+ * Use this to get easy access to the outputs.
+ * It is not advised to change the entries in this list
+ * (use the connecting and disconnecting functions to do that)
+ * @return The outputs list.
+ */
+ public NeuralConnection[] getOutputs() {
+ return m_outputList;
+ }
+
+ /**
+ * Use this to get easy access to the input numbers.
+ * It is not advised to change the entries in this list
+ * (use the connecting and disconnecting functions to do that)
+ * @return The input nums list.
+ */
+ public int[] getInputNums() {
+ return m_inputNums;
+ }
+
+ /**
+ * Use this to get easy access to the output numbers.
+ * It is not advised to change the entries in this list
+ * (use the connecting and disconnecting functions to do that)
+ * @return The outputs list.
+ */
+ public int[] getOutputNums() {
+ return m_outputNums;
+ }
+
+ /**
+ * @return the x coord.
+ */
+ public double getX() {
+ return m_x;
+ }
+
+ /**
+ * @return the y coord.
+ */
+ public double getY() {
+ return m_y;
+ }
+
+ /**
+ * @param x The new value for it's x pos.
+ */
+ public void setX(double x) {
+ m_x = x;
+ }
+
+ /**
+ * @param y The new value for it's y pos.
+ */
+ public void setY(double y) {
+ m_y = y;
+ }
+
+
+ /**
+ * Call this function to determine if the point at x,y is on the unit.
+ * @param g The graphics context for font size info.
+ * @param x The x coord.
+ * @param y The y coord.
+ * @param w The width of the display.
+ * @param h The height of the display.
+ * @return True if the point is on the unit, false otherwise.
+ */
+ public boolean onUnit(Graphics g, int x, int y, int w, int h) {
+
+ int m = (int)(m_x * w);
+ int c = (int)(m_y * h);
+ if (x > m + 10 || x < m - 10 || y > c + 10 || y < c - 10) {
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * Call this function to draw the node.
+ * @param g The graphics context.
+ * @param w The width of the drawing area.
+ * @param h The height of the drawing area.
+ */
+ public void drawNode(Graphics g, int w, int h) {
+
+ if ((m_type & OUTPUT) == OUTPUT) {
+ g.setColor(Color.orange);
+ }
+ else {
+ g.setColor(Color.red);
+ }
+ g.fillOval((int)(m_x * w) - 9, (int)(m_y * h) - 9, 19, 19);
+ g.setColor(Color.gray);
+ g.fillOval((int)(m_x * w) - 5, (int)(m_y * h) - 5, 11, 11);
+ }
+
+ /**
+ * Call this function to draw the node highlighted.
+ * @param g The graphics context.
+ * @param w The width of the drawing area.
+ * @param h The height of the drawing area.
+ */
+ public void drawHighlight(Graphics g, int w, int h) {
+
+ drawNode(g, w, h);
+ g.setColor(Color.yellow);
+ g.fillOval((int)(m_x * w) - 5, (int)(m_y * h) - 5, 11, 11);
+ }
+
+ /**
+ * Call this function to draw the nodes input connections.
+ * @param g The graphics context.
+ * @param w The width of the drawing area.
+ * @param h The height of the drawing area.
+ */
+ public void drawInputLines(Graphics g, int w, int h) {
+
+ g.setColor(Color.black);
+
+ int px = (int)(m_x * w);
+ int py = (int)(m_y * h);
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ g.drawLine((int)(m_inputList[noa].getX() * w)
+ , (int)(m_inputList[noa].getY() * h)
+ , px, py);
+ }
+ }
+
+ /**
+ * Call this function to draw the nodes output connections.
+ * @param g The graphics context.
+ * @param w The width of the drawing area.
+ * @param h The height of the drawing area.
+ */
+ public void drawOutputLines(Graphics g, int w, int h) {
+
+ g.setColor(Color.black);
+
+ int px = (int)(m_x * w);
+ int py = (int)(m_y * h);
+ for (int noa = 0; noa < m_numOutputs; noa++) {
+ g.drawLine(px, py
+ , (int)(m_outputList[noa].getX() * w)
+ , (int)(m_outputList[noa].getY() * h));
+ }
+ }
+
+
+ /**
+ * This will connect the specified unit to be an input to this unit.
+ * @param i The unit.
+ * @param n It's connection number for this connection.
+ * @return True if the connection was made, false otherwise.
+ */
+ protected boolean connectInput(NeuralConnection i, int n) {
+
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ if (i == m_inputList[noa]) {
+ return false;
+ }
+ }
+ if (m_numInputs >= m_inputList.length) {
+ //then allocate more space to it.
+ allocateInputs();
+ }
+ m_inputList[m_numInputs] = i;
+ m_inputNums[m_numInputs] = n;
+ m_numInputs++;
+ return true;
+ }
+
+ /**
+ * This will allocate more space for input connection information
+ * if the arrays for this have been filled up.
+ */
+ protected void allocateInputs() {
+
+ NeuralConnection[] temp1 = new NeuralConnection[m_inputList.length + 15];
+ int[] temp2 = new int[m_inputNums.length + 15];
+
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ temp1[noa] = m_inputList[noa];
+ temp2[noa] = m_inputNums[noa];
+ }
+ m_inputList = temp1;
+ m_inputNums = temp2;
+ }
+
+ /**
+ * This will connect the specified unit to be an output to this unit.
+ * @param o The unit.
+ * @param n It's connection number for this connection.
+ * @return True if the connection was made, false otherwise.
+ */
+ protected boolean connectOutput(NeuralConnection o, int n) {
+
+ for (int noa = 0; noa < m_numOutputs; noa++) {
+ if (o == m_outputList[noa]) {
+ return false;
+ }
+ }
+ if (m_numOutputs >= m_outputList.length) {
+ //then allocate more space to it.
+ allocateOutputs();
+ }
+ m_outputList[m_numOutputs] = o;
+ m_outputNums[m_numOutputs] = n;
+ m_numOutputs++;
+ return true;
+ }
+
+ /**
+ * Allocates more space for output connection information
+ * if the arrays have been filled up.
+ */
+ protected void allocateOutputs() {
+
+ NeuralConnection[] temp1
+ = new NeuralConnection[m_outputList.length + 15];
+
+ int[] temp2 = new int[m_outputNums.length + 15];
+
+ for (int noa = 0; noa < m_numOutputs; noa++) {
+ temp1[noa] = m_outputList[noa];
+ temp2[noa] = m_outputNums[noa];
+ }
+ m_outputList = temp1;
+ m_outputNums = temp2;
+ }
+
+ /**
+ * This will disconnect the input with the specific connection number
+ * From this node (only on this end however).
+ * @param i The unit to disconnect.
+ * @param n The connection number at the other end, -1 if all the connections
+ * to this unit should be severed.
+ * @return True if the connection was removed, false if the connection was
+ * not found.
+ */
+ protected boolean disconnectInput(NeuralConnection i, int n) {
+
+ int loc = -1;
+ boolean removed = false;
+ do {
+ loc = -1;
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ if (i == m_inputList[noa] && (n == -1 || n == m_inputNums[noa])) {
+ loc = noa;
+ break;
+ }
+ }
+
+ if (loc >= 0) {
+ for (int noa = loc+1; noa < m_numInputs; noa++) {
+ m_inputList[noa-1] = m_inputList[noa];
+ m_inputNums[noa-1] = m_inputNums[noa];
+ //set the other end to have the right connection number.
+ m_inputList[noa-1].changeOutputNum(m_inputNums[noa-1], noa-1);
+ }
+ m_numInputs--;
+ removed = true;
+ }
+ } while (n == -1 && loc != -1);
+
+ return removed;
+ }
+
+ /**
+ * This function will remove all the inputs to this unit.
+ * In doing so it will also terminate the connections at the other end.
+ */
+ public void removeAllInputs() {
+
+ for (int noa = 0; noa < m_numInputs; noa++) {
+ //this command will simply remove any connections this node has
+ //with the other in 1 go, rather than seperately.
+ m_inputList[noa].disconnectOutput(this, -1);
+ }
+
+ //now reset the inputs.
+ m_inputList = new NeuralConnection[0];
+ setType(getType() & (~INPUT));
+ if (getNumOutputs() == 0) {
+ setType(getType() & (~CONNECTED));
+ }
+ m_inputNums = new int[0];
+ m_numInputs = 0;
+
+ }
+
+
+
+ /**
+ * Changes the connection value information for one of the connections.
+ * @param n The connection number to change.
+ * @param v The value to change it to.
+ */
+ protected void changeInputNum(int n, int v) {
+
+ if (n >= m_numInputs || n < 0) {
+ return;
+ }
+
+ m_inputNums[n] = v;
+ }
+
+ /**
+ * This will disconnect the output with the specific connection number
+ * From this node (only on this end however).
+ * @param o The unit to disconnect.
+ * @param n The connection number at the other end, -1 if all the connections
+ * to this unit should be severed.
+ * @return True if the connection was removed, false if the connection was
+ * not found.
+ */
+ protected boolean disconnectOutput(NeuralConnection o, int n) {
+
+ int loc = -1;
+ boolean removed = false;
+ do {
+ loc = -1;
+ for (int noa = 0; noa < m_numOutputs; noa++) {
+ if (o == m_outputList[noa] && (n == -1 || n == m_outputNums[noa])) {
+ loc =noa;
+ break;
+ }
+ }
+
+ if (loc >= 0) {
+ for (int noa = loc+1; noa < m_numOutputs; noa++) {
+ m_outputList[noa-1] = m_outputList[noa];
+ m_outputNums[noa-1] = m_outputNums[noa];
+
+ //set the other end to have the right connection number
+ m_outputList[noa-1].changeInputNum(m_outputNums[noa-1], noa-1);
+ }
+ m_numOutputs--;
+ removed = true;
+ }
+ } while (n == -1 && loc != -1);
+
+ return removed;
+ }
+
+ /**
+ * This function will remove all outputs to this unit.
+ * In doing so it will also terminate the connections at the other end.
+ */
+ public void removeAllOutputs() {
+
+ for (int noa = 0; noa < m_numOutputs; noa++) {
+ //this command will simply remove any connections this node has
+ //with the other in 1 go, rather than seperately.
+ m_outputList[noa].disconnectInput(this, -1);
+ }
+
+ //now reset the inputs.
+ m_outputList = new NeuralConnection[0];
+ m_outputNums = new int[0];
+ setType(getType() & (~OUTPUT));
+ if (getNumInputs() == 0) {
+ setType(getType() & (~CONNECTED));
+ }
+ m_numOutputs = 0;
+
+ }
+
+ /**
+ * Changes the connection value information for one of the connections.
+ * @param n The connection number to change.
+ * @param v The value to change it to.
+ */
+ protected void changeOutputNum(int n, int v) {
+
+ if (n >= m_numOutputs || n < 0) {
+ return;
+ }
+
+ m_outputNums[n] = v;
+ }
+
+ /**
+ * @return The number of input connections.
+ */
+ public int getNumInputs() {
+ return m_numInputs;
+ }
+
+ /**
+ * @return The number of output connections.
+ */
+ public int getNumOutputs() {
+ return m_numOutputs;
+ }
+
+
+ /**
+ * Connects two units together.
+ * @param s The source unit.
+ * @param t The target unit.
+ * @return True if the units were connected, false otherwise.
+ */
+ public static boolean connect(NeuralConnection s, NeuralConnection t) {
+
+ if (s == null || t == null) {
+ return false;
+ }
+ //this ensures that there is no existing connection between these
+ //two units already. This will also cause the current weight there to be
+ //lost
+
+ disconnect(s, t);
+ if (s == t) {
+ return false;
+ }
+ if ((t.getType() & PURE_INPUT) == PURE_INPUT) {
+ return false; //target is an input node.
+ }
+ if ((s.getType() & PURE_OUTPUT) == PURE_OUTPUT) {
+ return false; //source is an output node
+ }
+ if ((s.getType() & PURE_INPUT) == PURE_INPUT
+ && (t.getType() & PURE_OUTPUT) == PURE_OUTPUT) {
+ return false; //there is no actual working node in use
+ }
+ if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT && t.getNumInputs() > 0) {
+ return false; //more than 1 node is trying to feed a particular output
+ }
+
+ if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT &&
+ (s.getType() & OUTPUT) == OUTPUT) {
+ return false; //an output node already feeding out a final answer
+ }
+
+ if (!s.connectOutput(t, t.getNumInputs())) {
+ return false;
+ }
+ if (!t.connectInput(s, s.getNumOutputs() - 1)) {
+
+ s.disconnectOutput(t, t.getNumInputs());
+ return false;
+
+ }
+
+ //now ammend the type.
+ if ((s.getType() & PURE_INPUT) == PURE_INPUT) {
+ t.setType(t.getType() | INPUT);
+ }
+ else if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT) {
+ s.setType(s.getType() | OUTPUT);
+ }
+ t.setType(t.getType() | CONNECTED);
+ s.setType(s.getType() | CONNECTED);
+ return true;
+ }
+
+ /**
+ * Disconnects two units.
+ * @param s The source unit.
+ * @param t The target unit.
+ * @return True if the units were disconnected, false if they weren't
+ * (probably due to there being no connection).
+ */
+ public static boolean disconnect(NeuralConnection s, NeuralConnection t) {
+
+ if (s == null || t == null) {
+ return false;
+ }
+
+ boolean stat1 = s.disconnectOutput(t, -1);
+ boolean stat2 = t.disconnectInput(s, -1);
+ if (stat1 && stat2) {
+ if ((s.getType() & PURE_INPUT) == PURE_INPUT) {
+ t.setType(t.getType() & (~INPUT));
+ }
+ else if ((t.getType() & (PURE_OUTPUT)) == PURE_OUTPUT) {
+ s.setType(s.getType() & (~OUTPUT));
+ }
+ if (s.getNumInputs() == 0 && s.getNumOutputs() == 0) {
+ s.setType(s.getType() & (~CONNECTED));
+ }
+ if (t.getNumInputs() == 0 && t.getNumOutputs() == 0) {
+ t.setType(t.getType() & (~CONNECTED));
+ }
+ }
+ return stat1 && stat2;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+