Coverage Report - weka.classifiers.functions.neural.NeuralConnection
 
Classes in this File Line Coverage Branch Coverage Complexity
NeuralConnection
0%
0/198
0%
0/136
3.158
 
 1  
 /*
 2  
  *   This program is free software: you can redistribute it and/or modify
 3  
  *   it under the terms of the GNU General Public License as published by
 4  
  *   the Free Software Foundation, either version 3 of the License, or
 5  
  *   (at your option) any later version.
 6  
  *
 7  
  *   This program is distributed in the hope that it will be useful,
 8  
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 9  
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10  
  *   GNU General Public License for more details.
 11  
  *
 12  
  *   You should have received a copy of the GNU General Public License
 13  
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 14  
  */
 15  
 
 16  
 /*
 17  
  *    NeuralConnection.java
 18  
  *    Copyright (C) 2000-2012 University of Waikato, Hamilton, New Zealand
 19  
  */
 20  
 
 21  
 package weka.classifiers.functions.neural;
 22  
 
 23  
 import java.awt.Color;
 24  
 import java.awt.Graphics;
 25  
 import java.io.Serializable;
 26  
 
 27  
 import weka.core.RevisionHandler;
 28  
 
 29  
 /** 
 30  
  * Abstract unit in a NeuralNetwork.
 31  
  *
 32  
  * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
 33  
  * @version $Revision: 8034 $
 34  
  */
 35  
 public abstract class NeuralConnection
 36  
   implements Serializable, RevisionHandler {
 37  
 
 38  
   /** for serialization */
 39  
   private static final long serialVersionUID = -286208828571059163L;
 40  
 
 41  
   //bitwise flags for the types of unit.
 42  
 
 43  
   /** This unit is not connected to any others. */
 44  
   public static final int UNCONNECTED = 0;
 45  
   
 46  
   /** This unit is a pure input unit. */
 47  
   public static final int PURE_INPUT = 1;
 48  
   
 49  
   /** This unit is a pure output unit. */
 50  
   public static final int PURE_OUTPUT = 2;
 51  
   
 52  
   /** This unit is an input unit. */
 53  
   public static final int INPUT = 4;
 54  
   
 55  
   /** This unit is an output unit. */
 56  
   public static final int OUTPUT = 8;
 57  
   
 58  
   /** This flag is set once the unit has a connection. */
 59  
   public static final int CONNECTED = 16;
 60  
 
 61  
 
 62  
 
 63  
   /////The difference between pure and not is that pure is used to feed 
 64  
   /////the neural network the attribute values and the errors on the outputs
 65  
   /////Beyond that they do no calculations, and have certain restrictions
 66  
   /////on the connections they can make.
 67  
 
 68  
 
 69  
 
 70  
   /** The list of inputs to this unit. */
 71  
   protected NeuralConnection[] m_inputList;
 72  
 
 73  
   /** The list of outputs from this unit. */
 74  
   protected NeuralConnection[] m_outputList;
 75  
 
 76  
   /** The numbering for the connections at the other end of the input lines. */
 77  
   protected int[] m_inputNums;
 78  
   
 79  
   /** The numbering for the connections at the other end of the out lines. */
 80  
   protected int[] m_outputNums;
 81  
 
 82  
   /** The number of inputs. */
 83  
   protected int m_numInputs;
 84  
 
 85  
   /** The number of outputs. */
 86  
   protected int m_numOutputs;
 87  
 
 88  
   /** The output value for this unit, NaN if not calculated. */
 89  
   protected double m_unitValue;
 90  
 
 91  
   /** The error value for this unit, NaN if not calculated. */
 92  
   protected double m_unitError;
 93  
   
 94  
   /** True if the weights have already been updated. */
 95  
   protected boolean m_weightsUpdated;
 96  
   
 97  
   /** The string that uniquely (provided naming is done properly) identifies
 98  
    * this unit. */
 99  
   protected String m_id;
 100  
 
 101  
   /** The type of unit this is. */
 102  
   protected int m_type;
 103  
 
 104  
   /** The x coord of this unit purely for displaying purposes. */
 105  
   protected double m_x;
 106  
   
 107  
   /** The y coord of this unit purely for displaying purposes. */
 108  
   protected double m_y;
 109  
   
 110  
 
 111  
   
 112  
   
 113  
   /**
 114  
    * Constructs The unit with the basic connection information prepared for
 115  
    * use. 
 116  
    * 
 117  
    * @param id the unique id of the unit
 118  
    */
 119  0
   public NeuralConnection(String id) {
 120  
     
 121  0
     m_id = id;
 122  0
     m_inputList = new NeuralConnection[0];
 123  0
     m_outputList = new NeuralConnection[0];
 124  0
     m_inputNums = new int[0];
 125  0
     m_outputNums = new int[0];
 126  
 
 127  0
     m_numInputs = 0;
 128  0
     m_numOutputs = 0;
 129  
 
 130  0
     m_unitValue = Double.NaN;
 131  0
     m_unitError = Double.NaN;
 132  
 
 133  0
     m_weightsUpdated = false;
 134  0
     m_x = 0;
 135  0
     m_y = 0;
 136  0
     m_type = UNCONNECTED;
 137  0
   }
 138  
   
 139  
   
 140  
   /**
 141  
    * @return The identity string of this unit.
 142  
    */
 143  
   public String getId() {
 144  0
     return m_id;
 145  
   }
 146  
 
 147  
   /**
 148  
    * @return The type of this unit.
 149  
    */
 150  
   public int getType() {
 151  0
     return m_type;
 152  
   }
 153  
 
 154  
   /**
 155  
    * @param t The new type of this unit.
 156  
    */
 157  
   public void setType(int t) {
 158  0
     m_type = t;
 159  0
   }
 160  
 
 161  
   /**
 162  
    * Call this to reset the unit for another run.
 163  
    * It is expected by that this unit will call the reset functions of all 
 164  
    * input units to it. It is also expected that this will not be done
 165  
    * if the unit has already been reset (or atleast appears to be).
 166  
    */
 167  
   public abstract void reset();
 168  
 
 169  
   /**
 170  
    * Call this to get the output value of this unit. 
 171  
    * @param calculate True if the value should be calculated if it hasn't been
 172  
    * already.
 173  
    * @return The output value, or NaN, if the value has not been calculated.
 174  
    */
 175  
   public abstract double outputValue(boolean calculate);
 176  
 
 177  
   /**
 178  
    * Call this to get the error value of this unit.
 179  
    * @param calculate True if the value should be calculated if it hasn't been
 180  
    * already.
 181  
    * @return The error value, or NaN, if the value has not been calculated.
 182  
    */
 183  
   public abstract double errorValue(boolean calculate);
 184  
   
 185  
   /**
 186  
    * Call this to have the connection save the current
 187  
    * weights.
 188  
    */
 189  
   public abstract void saveWeights();
 190  
   
 191  
   /**
 192  
    * Call this to have the connection restore from the saved
 193  
    * weights.
 194  
    */
 195  
   public abstract void restoreWeights();
 196  
 
 197  
   /**
 198  
    * Call this to get the weight value on a particular connection.
 199  
    * @param n The connection number to get the weight for, -1 if The threshold
 200  
    * weight should be returned.
 201  
    * @return This function will default to return 1. If overridden, it should
 202  
    * return the value for the specified connection or if -1 then it should 
 203  
    * return the threshold value. If no value exists for the specified 
 204  
    * connection, NaN will be returned.
 205  
    */
 206  
   public double weightValue(int n) {
 207  0
     return 1;
 208  
   }
 209  
 
 210  
   /**
 211  
    * Call this function to update the weight values at this unit.
 212  
    * After the weights have been updated at this unit, All the
 213  
    * input connections will then be called from this to have their
 214  
    * weights updated.
 215  
    * @param l The learning Rate to use.
 216  
    * @param m The momentum to use.
 217  
    */
 218  
   public void updateWeights(double l, double m) {
 219  
     
 220  
     //the action the subclasses should perform is upto them 
 221  
     //but if they coverride they should make a call to this to
 222  
     //call the method for all their inputs.
 223  
     
 224  0
     if (!m_weightsUpdated) {
 225  0
       for (int noa = 0; noa < m_numInputs; noa++) {
 226  0
         m_inputList[noa].updateWeights(l, m);
 227  
       }
 228  0
       m_weightsUpdated = true;
 229  
     }
 230  
     
 231  0
   }
 232  
 
 233  
   /**
 234  
    * Use this to get easy access to the inputs.
 235  
    * It is not advised to change the entries in this list
 236  
    * (use the connecting and disconnecting functions to do that)
 237  
    * @return The inputs list.
 238  
    */
 239  
   public NeuralConnection[] getInputs() {
 240  0
     return m_inputList;
 241  
   }
 242  
 
 243  
   /**
 244  
    * Use this to get easy access to the outputs.
 245  
    * It is not advised to change the entries in this list
 246  
    * (use the connecting and disconnecting functions to do that)
 247  
    * @return The outputs list.
 248  
    */
 249  
   public NeuralConnection[] getOutputs() {
 250  0
     return m_outputList;
 251  
   }
 252  
 
 253  
   /**
 254  
    * Use this to get easy access to the input numbers.
 255  
    * It is not advised to change the entries in this list
 256  
    * (use the connecting and disconnecting functions to do that)
 257  
    * @return The input nums list.
 258  
    */
 259  
   public int[] getInputNums() {
 260  0
     return m_inputNums;
 261  
   }
 262  
 
 263  
   /**
 264  
    * Use this to get easy access to the output numbers.
 265  
    * It is not advised to change the entries in this list
 266  
    * (use the connecting and disconnecting functions to do that)
 267  
    * @return The outputs list.
 268  
    */
 269  
   public int[] getOutputNums() {
 270  0
     return m_outputNums;
 271  
   }
 272  
 
 273  
   /**
 274  
    * @return the x coord.
 275  
    */
 276  
   public double getX() {
 277  0
     return m_x;
 278  
   }
 279  
   
 280  
   /**
 281  
    * @return the y coord.
 282  
    */
 283  
   public double getY() {
 284  0
     return m_y;
 285  
   }
 286  
   
 287  
   /**
 288  
    * @param x The new value for it's x pos.
 289  
    */
 290  
   public void setX(double x) {
 291  0
     m_x = x;
 292  0
   }
 293  
   
 294  
   /**
 295  
    * @param y The new value for it's y pos.
 296  
    */
 297  
   public void setY(double y) {
 298  0
     m_y = y;
 299  0
   }
 300  
   
 301  
   
 302  
   /**
 303  
    * Call this function to determine if the point at x,y is on the unit.
 304  
    * @param g The graphics context for font size info.
 305  
    * @param x The x coord.
 306  
    * @param y The y coord.
 307  
    * @param w The width of the display.
 308  
    * @param h The height of the display.
 309  
    * @return True if the point is on the unit, false otherwise.
 310  
    */
 311  
   public boolean onUnit(Graphics g, int x, int y, int w, int h) {
 312  
 
 313  0
     int m = (int)(m_x * w);
 314  0
     int c = (int)(m_y * h);
 315  0
     if (x > m + 10 || x < m - 10 || y > c + 10 || y < c - 10) {
 316  0
       return false;
 317  
     }
 318  0
     return true;
 319  
 
 320  
   }
 321  
   
 322  
   /**
 323  
    * Call this function to draw the node.
 324  
    * @param g The graphics context.
 325  
    * @param w The width of the drawing area.
 326  
    * @param h The height of the drawing area.
 327  
    */
 328  
   public void drawNode(Graphics g, int w, int h) {
 329  
     
 330  0
     if ((m_type & OUTPUT) == OUTPUT) {
 331  0
       g.setColor(Color.orange);
 332  
     }
 333  
     else {
 334  0
       g.setColor(Color.red);
 335  
     }
 336  0
     g.fillOval((int)(m_x * w) - 9, (int)(m_y * h) - 9, 19, 19);
 337  0
     g.setColor(Color.gray);
 338  0
     g.fillOval((int)(m_x * w) - 5, (int)(m_y * h) - 5, 11, 11);
 339  0
   }
 340  
 
 341  
   /**
 342  
    * Call this function to draw the node highlighted.
 343  
    * @param g The graphics context.
 344  
    * @param w The width of the drawing area.
 345  
    * @param h The height of the drawing area.
 346  
    */
 347  
   public void drawHighlight(Graphics g, int w, int h) {
 348  
    
 349  0
     drawNode(g, w, h);
 350  0
     g.setColor(Color.yellow);
 351  0
     g.fillOval((int)(m_x * w) - 5, (int)(m_y * h) - 5, 11, 11);
 352  0
   }
 353  
 
 354  
   /** 
 355  
    * Call this function to draw the nodes input connections.
 356  
    * @param g The graphics context.
 357  
    * @param w The width of the drawing area.
 358  
    * @param h The height of the drawing area.
 359  
    */
 360  
   public void drawInputLines(Graphics g, int w, int h) {
 361  
 
 362  0
     g.setColor(Color.black);
 363  
     
 364  0
     int px = (int)(m_x * w);
 365  0
     int py = (int)(m_y * h);
 366  0
     for (int noa = 0; noa < m_numInputs; noa++) {
 367  0
       g.drawLine((int)(m_inputList[noa].getX() * w)
 368  
                  , (int)(m_inputList[noa].getY() * h)
 369  
                  , px, py);
 370  
     }
 371  0
   }
 372  
 
 373  
   /**
 374  
    * Call this function to draw the nodes output connections.
 375  
    * @param g The graphics context.
 376  
    * @param w The width of the drawing area.
 377  
    * @param h The height of the drawing area.
 378  
    */
 379  
   public void drawOutputLines(Graphics g, int w, int h) {
 380  
     
 381  0
     g.setColor(Color.black);
 382  
     
 383  0
     int px = (int)(m_x * w);
 384  0
     int py = (int)(m_y * h);
 385  0
     for (int noa = 0; noa < m_numOutputs; noa++) {
 386  0
       g.drawLine(px, py
 387  
                  , (int)(m_outputList[noa].getX() * w)
 388  
                  , (int)(m_outputList[noa].getY() * h));
 389  
     }
 390  0
   }
 391  
 
 392  
 
 393  
   /**
 394  
    * This will connect the specified unit to be an input to this unit.
 395  
    * @param i The unit.
 396  
    * @param n It's connection number for this connection.
 397  
    * @return True if the connection was made, false otherwise.
 398  
    */
 399  
   protected boolean connectInput(NeuralConnection i, int n) {
 400  
     
 401  0
     for (int noa = 0; noa < m_numInputs; noa++) {
 402  0
       if (i == m_inputList[noa]) {
 403  0
         return false;
 404  
       }
 405  
     }
 406  0
     if (m_numInputs >= m_inputList.length) {
 407  
       //then allocate more space to it.
 408  0
       allocateInputs();
 409  
     }
 410  0
     m_inputList[m_numInputs] = i;
 411  0
     m_inputNums[m_numInputs] = n;
 412  0
     m_numInputs++;
 413  0
     return true;
 414  
   }
 415  
   
 416  
   /**
 417  
    * This will allocate more space for input connection information
 418  
    * if the arrays for this have been filled up.
 419  
    */
 420  
   protected void allocateInputs() {
 421  
     
 422  0
     NeuralConnection[] temp1 = new NeuralConnection[m_inputList.length + 15];
 423  0
     int[] temp2 = new int[m_inputNums.length + 15];
 424  
 
 425  0
     for (int noa = 0; noa < m_numInputs; noa++) {
 426  0
       temp1[noa] = m_inputList[noa];
 427  0
       temp2[noa] = m_inputNums[noa];
 428  
     }
 429  0
     m_inputList = temp1;
 430  0
     m_inputNums = temp2;
 431  0
   }
 432  
 
 433  
   /** 
 434  
    * This will connect the specified unit to be an output to this unit.
 435  
    * @param o The unit.
 436  
    * @param n It's connection number for this connection.
 437  
    * @return True if the connection was made, false otherwise.
 438  
    */
 439  
   protected boolean connectOutput(NeuralConnection o, int n) {
 440  
     
 441  0
     for (int noa = 0; noa < m_numOutputs; noa++) {
 442  0
       if (o == m_outputList[noa]) {
 443  0
         return false;
 444  
       }
 445  
     }
 446  0
     if (m_numOutputs >= m_outputList.length) {
 447  
       //then allocate more space to it.
 448  0
       allocateOutputs();
 449  
     }
 450  0
     m_outputList[m_numOutputs] = o;
 451  0
     m_outputNums[m_numOutputs] = n;
 452  0
     m_numOutputs++;
 453  0
     return true;
 454  
   }
 455  
   
 456  
   /**
 457  
    * Allocates more space for output connection information
 458  
    * if the arrays have been filled up.
 459  
    */
 460  
   protected void allocateOutputs() {
 461  
     
 462  0
     NeuralConnection[] temp1 
 463  
       = new NeuralConnection[m_outputList.length + 15];
 464  
     
 465  0
     int[] temp2 = new int[m_outputNums.length + 15];
 466  
     
 467  0
     for (int noa = 0; noa < m_numOutputs; noa++) {
 468  0
       temp1[noa] = m_outputList[noa];
 469  0
       temp2[noa] = m_outputNums[noa];
 470  
     }
 471  0
     m_outputList = temp1;
 472  0
     m_outputNums = temp2;
 473  0
   }
 474  
   
 475  
   /**
 476  
    * This will disconnect the input with the specific connection number
 477  
    * From this node (only on this end however).
 478  
    * @param i The unit to disconnect.
 479  
    * @param n The connection number at the other end, -1 if all the connections
 480  
    * to this unit should be severed.
 481  
    * @return True if the connection was removed, false if the connection was 
 482  
    * not found.
 483  
    */
 484  
   protected boolean disconnectInput(NeuralConnection i, int n) {
 485  
     
 486  0
     int loc = -1;
 487  0
     boolean removed = false;
 488  
     do {
 489  0
       loc = -1;
 490  0
       for (int noa = 0; noa < m_numInputs; noa++) {
 491  0
         if (i == m_inputList[noa] && (n == -1 || n == m_inputNums[noa])) {
 492  0
           loc = noa;
 493  0
           break;
 494  
         }
 495  
       }
 496  
       
 497  0
       if (loc >= 0) {
 498  0
         for (int noa = loc+1; noa < m_numInputs; noa++) {
 499  0
           m_inputList[noa-1] = m_inputList[noa];
 500  0
           m_inputNums[noa-1] = m_inputNums[noa];
 501  
           //set the other end to have the right connection number.
 502  0
           m_inputList[noa-1].changeOutputNum(m_inputNums[noa-1], noa-1);
 503  
         }
 504  0
         m_numInputs--;
 505  0
         removed = true;
 506  
       }
 507  0
     } while (n == -1 && loc != -1);
 508  
 
 509  0
     return removed;
 510  
   }
 511  
 
 512  
   /**
 513  
    * This function will remove all the inputs to this unit.
 514  
    * In doing so it will also terminate the connections at the other end.
 515  
    */
 516  
   public void removeAllInputs() {
 517  
     
 518  0
     for (int noa = 0; noa < m_numInputs; noa++) {
 519  
       //this command will simply remove any connections this node has
 520  
       //with the other in 1 go, rather than seperately.
 521  0
       m_inputList[noa].disconnectOutput(this, -1);
 522  
     }
 523  
     
 524  
     //now reset the inputs.
 525  0
     m_inputList = new NeuralConnection[0];
 526  0
     setType(getType() & (~INPUT));
 527  0
     if (getNumOutputs() == 0) {
 528  0
       setType(getType() & (~CONNECTED));
 529  
     }
 530  0
     m_inputNums = new int[0];
 531  0
     m_numInputs = 0;
 532  
     
 533  0
   }
 534  
 
 535  
  
 536  
 
 537  
   /**
 538  
    * Changes the connection value information for one of the connections.
 539  
    * @param n The connection number to change.
 540  
    * @param v The value to change it to.
 541  
    */
 542  
   protected void changeInputNum(int n, int v) {
 543  
     
 544  0
     if (n >= m_numInputs || n < 0) {
 545  0
       return;
 546  
     }
 547  
 
 548  0
     m_inputNums[n] = v;
 549  0
   }
 550  
   
 551  
   /**
 552  
    * This will disconnect the output with the specific connection number
 553  
    * From this node (only on this end however).
 554  
    * @param o The unit to disconnect.
 555  
    * @param n The connection number at the other end, -1 if all the connections
 556  
    * to this unit should be severed.
 557  
    * @return True if the connection was removed, false if the connection was
 558  
    * not found.
 559  
    */  
 560  
   protected boolean disconnectOutput(NeuralConnection o, int n) {
 561  
     
 562  0
     int loc = -1;
 563  0
     boolean removed = false;
 564  
     do {
 565  0
       loc = -1;
 566  0
       for (int noa = 0; noa < m_numOutputs; noa++) {
 567  0
         if (o == m_outputList[noa] && (n == -1 || n == m_outputNums[noa])) {
 568  0
           loc =noa;
 569  0
           break;
 570  
         }
 571  
       }
 572  
       
 573  0
       if (loc >= 0) {
 574  0
         for (int noa = loc+1; noa < m_numOutputs; noa++) {
 575  0
           m_outputList[noa-1] = m_outputList[noa];
 576  0
           m_outputNums[noa-1] = m_outputNums[noa];
 577  
 
 578  
           //set the other end to have the right connection number
 579  0
           m_outputList[noa-1].changeInputNum(m_outputNums[noa-1], noa-1);
 580  
         }
 581  0
         m_numOutputs--;
 582  0
         removed = true;
 583  
       }
 584  0
     } while (n == -1 && loc != -1);
 585  
     
 586  0
     return removed;
 587  
   }
 588  
 
 589  
   /**
 590  
    * This function will remove all outputs to this unit.
 591  
    * In doing so it will also terminate the connections at the other end.
 592  
    */
 593  
   public void removeAllOutputs() {
 594  
     
 595  0
     for (int noa = 0; noa < m_numOutputs; noa++) {
 596  
       //this command will simply remove any connections this node has
 597  
       //with the other in 1 go, rather than seperately.
 598  0
       m_outputList[noa].disconnectInput(this, -1);
 599  
     }
 600  
     
 601  
     //now reset the inputs.
 602  0
     m_outputList = new NeuralConnection[0];
 603  0
     m_outputNums = new int[0];
 604  0
     setType(getType() & (~OUTPUT));
 605  0
     if (getNumInputs() == 0) {
 606  0
       setType(getType() & (~CONNECTED));
 607  
     }
 608  0
     m_numOutputs = 0;
 609  
     
 610  0
   }
 611  
 
 612  
   /**
 613  
    * Changes the connection value information for one of the connections.
 614  
    * @param n The connection number to change.
 615  
    * @param v The value to change it to.
 616  
    */
 617  
   protected void changeOutputNum(int n, int v) {
 618  
     
 619  0
     if (n >= m_numOutputs || n < 0) {
 620  0
       return;
 621  
     }
 622  
 
 623  0
     m_outputNums[n] = v;
 624  0
   }
 625  
   
 626  
   /**
 627  
    * @return The number of input connections.
 628  
    */
 629  
   public int getNumInputs() {
 630  0
     return m_numInputs;
 631  
   }
 632  
 
 633  
   /**
 634  
    * @return The number of output connections.
 635  
    */
 636  
   public int getNumOutputs() {
 637  0
     return m_numOutputs;
 638  
   }
 639  
 
 640  
 
 641  
   /**
 642  
    * Connects two units together.
 643  
    * @param s The source unit.
 644  
    * @param t The target unit.
 645  
    * @return True if the units were connected, false otherwise.
 646  
    */
 647  
   public static boolean connect(NeuralConnection s, NeuralConnection t) {
 648  
     
 649  0
     if (s == null || t == null) {
 650  0
       return false;
 651  
     }
 652  
     //this ensures that there is no existing connection between these 
 653  
     //two units already. This will also cause the current weight there to be 
 654  
     //lost
 655  
  
 656  0
     disconnect(s, t);
 657  0
     if (s == t) {
 658  0
       return false;
 659  
     }
 660  0
     if ((t.getType() & PURE_INPUT) == PURE_INPUT) {
 661  0
       return false;   //target is an input node.
 662  
     }
 663  0
     if ((s.getType() & PURE_OUTPUT) == PURE_OUTPUT) {
 664  0
       return false;   //source is an output node
 665  
     }
 666  0
     if ((s.getType() & PURE_INPUT) == PURE_INPUT 
 667  
         && (t.getType() & PURE_OUTPUT) == PURE_OUTPUT) {      
 668  0
       return false;   //there is no actual working node in use
 669  
     }
 670  0
     if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT && t.getNumInputs() > 0) {
 671  0
       return false; //more than 1 node is trying to feed a particular output
 672  
     }
 673  
 
 674  0
     if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT &&
 675  
         (s.getType() & OUTPUT) == OUTPUT) {
 676  0
       return false; //an output node already feeding out a final answer
 677  
     }
 678  
 
 679  0
     if (!s.connectOutput(t, t.getNumInputs())) {
 680  0
       return false;
 681  
     }
 682  0
     if (!t.connectInput(s, s.getNumOutputs() - 1)) {
 683  
       
 684  0
       s.disconnectOutput(t, t.getNumInputs());
 685  0
       return false;
 686  
 
 687  
     }
 688  
 
 689  
     //now ammend the type.
 690  0
     if ((s.getType() & PURE_INPUT) == PURE_INPUT) {
 691  0
       t.setType(t.getType() | INPUT);
 692  
     }
 693  0
     else if ((t.getType() & PURE_OUTPUT) == PURE_OUTPUT) {
 694  0
       s.setType(s.getType() | OUTPUT);
 695  
     }
 696  0
     t.setType(t.getType() | CONNECTED);
 697  0
     s.setType(s.getType() | CONNECTED);
 698  0
     return true;
 699  
   }
 700  
 
 701  
   /**
 702  
    * Disconnects two units.
 703  
    * @param s The source unit.
 704  
    * @param t The target unit.
 705  
    * @return True if the units were disconnected, false if they weren't
 706  
    * (probably due to there being no connection).
 707  
    */
 708  
   public static boolean disconnect(NeuralConnection s, NeuralConnection t) {
 709  
     
 710  0
     if (s == null || t == null) {
 711  0
       return false;
 712  
     }
 713  
 
 714  0
     boolean stat1 = s.disconnectOutput(t, -1);
 715  0
     boolean stat2 = t.disconnectInput(s, -1);
 716  0
     if (stat1 && stat2) {
 717  0
       if ((s.getType() & PURE_INPUT) == PURE_INPUT) {
 718  0
         t.setType(t.getType() & (~INPUT));
 719  
       }
 720  0
       else if ((t.getType() & (PURE_OUTPUT)) == PURE_OUTPUT) {
 721  0
         s.setType(s.getType() & (~OUTPUT));
 722  
       }
 723  0
       if (s.getNumInputs() == 0 && s.getNumOutputs() == 0) {
 724  0
         s.setType(s.getType() & (~CONNECTED));
 725  
       }
 726  0
       if (t.getNumInputs() == 0 && t.getNumOutputs() == 0) {
 727  0
         t.setType(t.getType() & (~CONNECTED));
 728  
       }
 729  
     }
 730  0
     return stat1 && stat2;
 731  
   }
 732  
 }
 733  
 
 734  
 
 735  
 
 736  
 
 737  
 
 738  
 
 739  
 
 740  
 
 741  
 
 742  
 
 743  
 
 744