<?php
error_reporting(-1);
define('DEBUG', true);
trait T
{
function __get($name)
{
throw new Exception('get');
}
function __set($name, $value)
{
throw new Exception('set');
}
}
interface IPropagationFunc
{
function f(ILearnable $neuron);
function fPrimeW(ILearnable $neuron, $i);
function fPrimeO(ILearnable $neuron, $i);
}
interface ILearnableFunc
{
function f($x);
function fPrime($x);
}
interface IActivationFunc extends ILearnableFunc
{
}
interface IOutputFunc extends ILearnableFunc
{
}
class LinearFunc implements IPropagationFunc
{
private $weights;
function __construct(array &$weights)
{
$this->weights = &$weights;
}
function f(ILearnable $neuron)
{
$net = 0;
$count = count($neuron->predecessors);
for($p = 0; $p < $count; ++$p)
{
$predecessor = $neuron->predecessors[$p];
$net += $predecessor->getO() * $this->weights[$predecessor->getId()][$neuron->getId()];
}
return $net;
}
function fPrimeW(ILearnable $neuron, $i)
{
return $neuron->predecessors[$i]->getO();
}
function fPrimeO(ILearnable $neuron, $i)
{
return $this->weights[$neuron->predecessors[$i]->getId()][$neuron->getId()];
}
}
class SigmoidFunc implements IActivationFunc
{
private $c;
function __construct($c)
{
$this->c = $c;
}
function f($x)
{
return 1 / (1 + exp(-$this->c * $x));
}
function fPrime($x)
{
$exp = exp(-$this->c * $x);
return $this->c * $exp / pow(1 + $exp, 2);
}
}
class IdentityFunc implements IOutputFunc
{
function f($x)
{
return $x;
}
function fPrime($x)
{
return 1;
}
}
interface IUpdateable
{
}
interface ILearnable
{
}
abstract class Neuron
{
use T;
protected $id;
protected $o;
public $layer = 0;
function getId()
{
return $this->id;
}
function getO()
{
return $this->o;
}
}
trait TUpdate
{
public $successors = [];
}
trait TLearn
{
public $predecessors = [];
private $pF;
private $aF;
private $oF;
private $net;
private $a;
private $errSig;
function __construct($id, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
{
$this->id = $id;
$this->pF = $pF;
$this->aF = $aF;
$this->oF = $oF;
}
function setO()
{
$this->net = $this->pF->f($this);
$this->a = $this->aF->f($this->net);
$this->o = $this->oF->f($this->a);
if(DEBUG)
{
echo "Neuron ", $this->id, " net: ", $this->net, "\n";
echo "Neuron ", $this->id, " o: ", $this->o, "\n";
}
}
function _setErrSig($err)
{
$this->errSig = $err * $this->oF->fPrime($this->a) * $this->aF->fPrime($this->net);
if(DEBUG)
{
echo "Neuron ", $this->id, " fSig: ", $this->errSig, "\n";
}
}
function getErrSig()
{
return $this->errSig;
}
}
class InputNeuron extends Neuron implements IUpdateable
{
use TUpdate;
function __construct($id)
{
$this->id = $id;
}
function setO($o)
{
$this->o = $o;
}
}
class HiddenNeuron extends Neuron implements IUpdateable, ILearnable
{
use TUpdate;
use TLearn;
function setErrSig(array &$weights)
{
$err = 0;
for($s = 0; $s < count($this->successors); ++$s)
{
$successor = $this->successors[$s];
$err += $weights[$this->id][$successor->id] * $successor->getErrSig();
}
$this->_setErrSig($err);
}
}
class OutputNeuron extends Neuron implements ILearnable
{
use TLearn;
function setErrSig($target)
{
$this->_setErrSig($target - $this->o);
}
}
class OnNeuron extends Neuron implements IUpdateable
{
use TUpdate;
function __construct($id)
{
$this->id = $id;
$this->o = 1;
}
}
class Layers
{
use T;
private static function isInputNeuron(array &$weights, $x)
{
$count = count($weights);
for($y = 0; $y < $count; ++$y)
{
if($weights[$y][$x] != 0)
{
return false;
}
}
return true;
}
private static function isOutputNeuron(array &$weights, $y)
{
$count = count($weights);
for($x = 0; $x < $count; ++$x)
{
if($weights[$y][$x] != 0)
{
return false;
}
}
return true;
}
private static function createNeurons(array &$weights, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
{
$neurons = [];
$count = count($weights);
for($i = 0; $i < $count; ++$i)
{
if(self::isInputNeuron($weights, $i))
{
$neurons[] = new InputNeuron($i);
}
elseif(self::isOutputNeuron($weights, $i))
{
$neurons[] = new OutputNeuron($i, $pF, $aF, $oF);
}
else
{
$neurons[] = new HiddenNeuron($i, $pF, $aF, $oF);
}
}
return $neurons;
}
private static function defineNeuronRelations(array &$weights, array &$neurons)
{
$countI = count($weights);
for($i = 0; $i < $countI; ++$i)
{
$neuron = $neurons[$i];
if($neuron instanceof IUpdateable)
{
$countX = count($weights[$i]);
for($x = 0; $x < $countX; ++$x)
{
if($weights[$i][$x] != 0)
{
$neuron->successors[] = $neurons[$x];
}
}
}
if($neuron instanceof ILearnable)
{
$countY = count($weights[$i]);
for($y = 0; $y < $countY; ++$y)
{
if($weights[$y][$i] != 0)
{
$neuron->predecessors[] = $neurons[$y];
}
}
}
}
}
private static function defineNeuronLayers(array &$neurons)
{
$countI = count($neurons);
for($i = 0; $i < $countI; ++$i)
{
$neuron = $neurons[$i];
if($neuron instanceof IUpdateable)
{
$successors = $neuron->successors;
$countS = count($successors);
for($s = 0; $s < $countS; ++$s)
{
$successor = $successors[$s];
$successor->layer = max($neuron->layer + 1, $successor->layer);
}
}
}
}
static function get(array &$weights, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
{
$neurons = self::createNeurons($weights, $pF, $aF, $oF);
self::defineNeuronRelations($weights, $neurons);
self::defineNeuronLayers($neurons);
$count = count($neurons);
for($i = 0; $i < $count; ++$i)
{
$neuron = $neurons[$i];
$layers[$neuron->layer][] = $neuron;
}
if(DEBUG)
{
for($i = 0; $i < $count; ++$i)
{
$neuron = $neurons[$i];
if($neuron instanceof InputNeuron)
{
echo "Neuron ", $i, " ist ein input-Neuron.\n";
}
elseif($neuron instanceof HiddenNeuron)
{
echo "Neuron ", $i, " ist ein Neuron einer verdeckten Schicht.\n";
}
else
{
echo "Neuron ", $i, " ist ein output-Neuron.\n";
}
}
for($i = 0; $i < $count; ++$i)
{
$neuron = $neurons[$i];
if($neuron instanceof IUpdateable)
{
echo "Nachfolger von Neuron ", $neuron->getId(), ": ";
$countS = count($neuron->successors);
for($s = 0; $s < $countS; ++$s)
{
echo $neuron->successors[$s]->getId(), " ";
}
echo "\n";
}
if($neuron instanceof ILearnable)
{
echo "Vorgänger von Neuron ", $neuron->getId(), ": ";
$countP = count($neuron->predecessors);
for($p = 0; $p < $countP; ++$p)
{
echo $neuron->predecessors[$p]->getId(), " ";
}
echo "\n";
}
}
$countL = count($layers);
for($l = 0; $l < $countL; ++$l)
{
echo "Ebene ", $l, ": ";
$countN = count($layers[$l]);
for($n = 0; $n < $countN; ++$n)
{
$neuron = $layers[$l][$n];
echo $neuron->layer, "/", $neuron->getId(), " ";
}
echo "\n";
}
}
return $layers;
}
}