Skip to content

Instantly share code, notes, and snippets.

@redwrasse
Last active August 12, 2017 20:19
Show Gist options
  • Save redwrasse/a2e718408b467546ecf5105179261804 to your computer and use it in GitHub Desktop.
Save redwrasse/a2e718408b467546ecf5105179261804 to your computer and use it in GitHub Desktop.
McCulloch-Pitts neural network
class McCullochPitts(
val numExcitatoryInputs: Int,
val numInhibitoryInputs: Int,
val threshold: Int,
val inhibitoryInputIndices: Option[Seq[Int]] = None)
extends NeuralNetwork {
val numImmediateInputs: Int = (numExcitatoryInputs
+ numInhibitoryInputs)
var children: Map[Int, NeuralNetwork] = Map.empty
// variable to decide logic for activation function
var isInhibited: Boolean = false
/**
* Returns the integration value. If at least one inhibitory input
* exists and at least one such input is 1, the result is 0.
* Otherwise the sum of the excitatory inputs is returned.
* The input must be given as a single array containing
* the inhibitory inputs followed by the excitatory inputs,
* unless the inhibitory indices were explicitly specified
* in the class constructor.
*/
def integration(immediateInput: Array[Double]): Double = {
require (immediateInput.size == (numExcitatoryInputs
+ numInhibitoryInputs))
if (inhibitoryInputIndices.isDefined) {
require (inhibitoryInputIndices.get.size ==
numInhibitoryInputs)
}
for (e <- immediateInput) {
require (e == 0.0 || e == 1.0)
}
var inhibitoryInputs: Array[Double] = null
var excitatoryInputs: Array[Double] = null
if (inhibitoryInputIndices.isDefined) {
inhibitoryInputs = inhibitoryInputIndices.get
.map(i => immediateInput(i)).toArray
excitatoryInputs = (0 to immediateInput.size-1)
.filter(i => !inhibitoryInputIndices.get.contains(i))
.map(j => immediateInput(j)).toArray
} else {
inhibitoryInputs = immediateInput
.slice(0, numInhibitoryInputs)
excitatoryInputs = immediateInput
.slice(numInhibitoryInputs, immediateInput.size)
}
isInhibited = inhibitoryInputs
.filter(_ == 1.0).size > 0
isInhibited match {
case true => 0.0
case false => excitatoryInputs.sum
}
}
/**
* Returns 0 if the input is inhibited, else:
* Returns 1 if the threshold is matched or exceeded, else 0
*/
def activation(e: Double): Double = {
if (isInhibited || e < threshold) 0.0 else 1.0
}
}
abstract class NeuralNetwork {
val numImmediateInputs: Int
var children: Map[Int, NeuralNetwork]
/**
* The integration function contains implicitly the weights
* for this compute unit
*/
def integration(immediateInput: Array[Double]): Double
/**
* The activation function
*/
def activation(e: Double): Double
/**
* Compute the output given the specified input
*/
def compute(input: Array[Double]): Double = {
// require (input.size == getNumInputs())
val numInputs = getNumInputs()
var inputsToPeelOff: Array[Double] = input
var immediateInputs: Array[Double] = Array.empty
var childNetwork: Option[NeuralNetwork] = None
var childInput: Array[Double] = null
var childOutput: Double = 0.0
var j: Int = 0
for (i <- (0 to numImmediateInputs-1)) {
childNetwork = child(i)
if (childNetwork.isDefined) {
j = childNetwork.get.getNumInputs()
childInput = inputsToPeelOff.slice(0, j)
inputsToPeelOff = inputsToPeelOff.slice(j, numInputs)
childOutput = childNetwork.get.compute(childInput)
immediateInputs = immediateInputs :+ childOutput
} else {
immediateInputs = immediateInputs :+ inputsToPeelOff.head
inputsToPeelOff = inputsToPeelOff.tail
}
}
// require (inputsToPeelOff.size == 0)
activation(integration(immediateInputs))
}
/**
* Add child nodes at the specified input indices.
* Children are added at immediate input indices, *not*
* leaf indices
*/
def addChildren(m: Map[Int, NeuralNetwork]) = {
children = children ++ m
}
/**
* Returns a potential child at the given index;
* potential children can exist at any of 0 to numImmediateInputs-1
* indices.
*/
def child(i: Int): Option[NeuralNetwork] = {
children.get(i)
}
/**
* Returns the number of children for this compute unit
*/
def getNumChildren(): Int = {
(0 to numImmediateInputs-1).filter(i => child(i).isDefined).size
}
/**
* Returns the number of incoming vertices for this compute unit
*/
def getNumImmediateInputs(): Int = {
numImmediateInputs
}
/**
* Returns the number of leaf incoming vertices for
* the composite neural network
*/
def getNumInputs(): Int = {
(0 to numImmediateInputs-1)
.map(i => child(i))
.map { c => c match {
case None => 1
case _ => c.get.getNumInputs()
}
}.sum
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment