~ubuntu-branches/ubuntu/trusty/weka/trusty-proposed

« back to all changes in this revision

Viewing changes to weka/classifiers/functions/neural/NeuralConnection.java

  • Committer: Bazaar Package Importer
  • Author(s): Soeren Sonnenburg
  • Date: 2008-02-24 09:18:45 UTC
  • Revision ID: james.westby@ubuntu.com-20080224091845-1l8zy6fm6xipbzsr
Tags: upstream-3.5.7+tut1
ImportĀ upstreamĀ versionĀ 3.5.7+tut1

Show diffs side-by-side

added added

removed removed

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