Refactored into folders

This commit is contained in:
2026-03-22 10:42:08 +01:00
parent 977c259cb9
commit 4717254da4
18 changed files with 258 additions and 44 deletions

View File

@@ -5,12 +5,14 @@ namespace App\Http\Controllers;
use App\Events\PerceptronInitialization;
use App\Models\GradientDescentPerceptronTraining;
use App\Models\SimpleBinaryPerceptronTraining;
use App\Services\DataSetReader;
use App\Services\ISynapticWeightsProvider;
use App\Services\PerceptronIterationEventBuffer;
use App\Services\PerceptronLimitedEpochEventBuffer;
use App\Services\ZeroSynapticWeights;
use App\Services\DatasetReader\IDataSetReader;
use App\Services\DatasetReader\LinearOrderDataSetReader;
use App\Services\IterationEventBuffer\PerceptronIterationEventBuffer;
use App\Services\IterationEventBuffer\PerceptronLimitedEpochEventBuffer;
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
use App\Services\SynapticWeightsProvider\ZeroSynapticWeights;
use Illuminate\Http\Request;
use Tests\Services\IterationEventBuffer\DullIterationEventBuffer;
class PerceptronController extends Controller
{
@@ -23,7 +25,7 @@ class PerceptronController extends Controller
$learningRate = 0.01;
$maxIterations = 200;
$minError = 0.6;
$minError = 0.1;
switch ($perceptronType) {
case 'simple':
@@ -53,7 +55,7 @@ class PerceptronController extends Controller
if (pathinfo($file, PATHINFO_EXTENSION) === 'csv') {
$dataset = [];
$dataset['label'] = str_replace('.csv', '', $file);
$dataSetReader = new DataSetReader($dataSetsDirectory . '/' . $file);
$dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory . '/' . $file);
$dataset['data'] = [];
switch (count($dataSetReader->lines[0])) {
case 3:
@@ -84,6 +86,7 @@ class PerceptronController extends Controller
switch ($perceptronType) {
case 'gradientdescent':
$dataset['defaultLearningRate'] = 0.3;
$dataset['defaultMinError'] = 0.125;
break;
}
break;
@@ -94,7 +97,6 @@ class PerceptronController extends Controller
break;
case 'gradientdescent':
$dataset['defaultLearningRate'] = 0.001;
$dataset['defaultMinError'] = 2.0;
break;
}
break;
@@ -108,10 +110,10 @@ class PerceptronController extends Controller
return $datasets;
}
private function getDataSetReader(string $dataSet): DataSetReader
private function getDataSetReader(string $dataSet): IDataSetReader
{
$dataSetFileName = "data_sets/{$dataSet}.csv";
return new DataSetReader($dataSetFileName);
return new LinearOrderDataSetReader($dataSetFileName);
}
public function run(Request $request, ISynapticWeightsProvider $synapticWeightsProvider)
@@ -141,6 +143,16 @@ class PerceptronController extends Controller
$networkTraining = match ($perceptronType) {
'simple' => new SimpleBinaryPerceptronTraining($dataSetReader, $learningRate, $maxIterations, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId),
'gradientdescent' => new GradientDescentPerceptronTraining($dataSetReader, $learningRate, $maxIterations, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError),
'gradientdescentTest' => new GradientDescentPerceptronTraining(
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and_gradient.csv')),
learningRate: 0.2,
maxEpochs: 100,
synapticWeightsProvider: new ZeroSynapticWeights(),
iterationEventBuffer: $iterationEventBuffer,
sessionId: 'test-session',
trainingId: 'test-training',
minError: 0.125001,
),
default => null,
};

View File

@@ -3,10 +3,9 @@
namespace App\Models;
use App\Events\PerceptronTrainingEnded;
use App\Services\DataSetReader;
use App\Services\IPerceptronIterationEventBuffer;
use App\Services\ISynapticWeightsProvider;
use App\Services\PerceptronIterationEventBuffer;
use App\Services\DatasetReader\IDataSetReader;
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
class GradientDescentPerceptronTraining extends NetworkTraining
{
@@ -17,7 +16,7 @@ class GradientDescentPerceptronTraining extends NetworkTraining
private float $epochError;
public function __construct(
DataSetReader $datasetReader,
IDataSetReader $datasetReader,
protected float $learningRate,
int $maxEpochs,
protected ISynapticWeightsProvider $synapticWeightsProvider,
@@ -38,7 +37,7 @@ class GradientDescentPerceptronTraining extends NetworkTraining
$epochCorrectorPerWeight = [];
$this->epoch++;
while ($nextRow = $this->datasetReader->getRandomLine()) {
while ($nextRow = $this->datasetReader->getNextLine()) {
$inputs = array_slice($nextRow, 0, -1);
$correctOutput = (float) end($nextRow);
@@ -89,4 +88,9 @@ class GradientDescentPerceptronTraining extends NetworkTraining
return $error;
}
public function getSynapticWeights(): array
{
return [[$this->perceptron->getSynapticWeights()]];
}
}

View File

@@ -3,8 +3,8 @@
namespace App\Models;
use App\Events\PerceptronTrainingEnded;
use App\Services\DataSetReader;
use App\Services\IPerceptronIterationEventBuffer;
use App\Services\DatasetReader\IDataSetReader;
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
abstract class NetworkTraining
{
@@ -17,7 +17,7 @@ abstract class NetworkTraining
public ActivationsFunctions $activationFunction;
public function __construct(
protected DataSetReader $datasetReader,
protected IDataSetReader $datasetReader,
protected int $maxEpochs,
protected IPerceptronIterationEventBuffer $iterationEventBuffer,
protected string $sessionId,
@@ -42,4 +42,11 @@ abstract class NetworkTraining
protected function addIterationToBuffer(float $error, array $synapticWeights) {
$this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights);
}
public function getEpoch(): int
{
return $this->epoch;
}
abstract public function getSynapticWeights(): array;
}

View File

@@ -3,9 +3,9 @@
namespace App\Models;
use App\Events\PerceptronTrainingEnded;
use App\Services\DataSetReader;
use App\Services\IPerceptronIterationEventBuffer;
use App\Services\ISynapticWeightsProvider;
use App\Services\DatasetReader\IDataSetReader;
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
class SimpleBinaryPerceptronTraining extends NetworkTraining
{
@@ -17,7 +17,7 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
public const MIN_ERROR = 0;
public function __construct(
DataSetReader $datasetReader,
IDataSetReader $datasetReader,
protected float $learningRate,
int $maxEpochs,
protected ISynapticWeightsProvider $synapticWeightsProvider,
@@ -81,4 +81,9 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
}
return $error;
}
public function getSynapticWeights(): array
{
return [[$this->perceptron->getSynapticWeights()]];
}
}

View File

@@ -2,8 +2,8 @@
namespace App\Providers;
use App\Services\ISynapticWeightsProvider;
use App\Services\RandomSynapticWeights;
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
use App\Services\SynapticWeightsProvider\RandomSynapticWeights;
use Illuminate\Support\ServiceProvider;
class InitialSynapticWeightsProvider extends ServiceProvider

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Services\DatasetReader;
interface IDataSetReader {
public function getNextLine(): array | null;
public function getInputSize(): int;
public function reset(): void;
public function getLastReadLineIndex(): int;
public function getEpochExamplesCount(): int;
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Services\DatasetReader;
use App\Services\CsvReader;
class LinearOrderDataSetReader implements IDataSetReader {
public array $lines = [];
private array $currentLines = [];
private int $lastReadLineIndex = -1;
public function __construct(
public string $filename,
) {
// For now, we only support CSV files, so we can delegate to CsvReader
$csvReader = new CsvReader($filename);
$this->readEntireFile($csvReader);
$this->reset();
}
private function readEntireFile(CsvReader $reader): void
{
while ($line = $reader->readNextLine()) {
$newLine = [];
foreach ($line as $value) { // Transform to float
$newLine[] = (float) $value;
}
// if the dataset is for regression, we add a fake label of 0
if (count($newLine) === 2) {
$newLine[] = 0.0;
}
$this->lines[] = $newLine;
}
}
public function getNextLine(): array | null {
if (!isset($this->currentLines[0])) {
return null; // No more lines to read
}
$this->lastReadLineIndex = array_search($this->currentLines[0], $this->lines, true);
return array_shift($this->currentLines);
}
public function getInputSize(): int
{
return count($this->lines[0]) - 1; // Don't count the label
}
public function reset(): void
{
$this->currentLines = $this->lines;
}
public function getLastReadLineIndex(): int
{
return $this->lastReadLineIndex;
}
public function getEpochExamplesCount(): int
{
return count($this->lines);
}
}

View File

@@ -1,8 +1,10 @@
<?php
namespace App\Services;
namespace App\Services\DatasetReader;
class DataSetReader {
use App\Services\CsvReader;
class RandomOrderDataSetReaders implements IDataSetReader {
public array $lines = [];
private array $currentLines = [];
@@ -34,7 +36,7 @@ class DataSetReader {
}
}
public function getRandomLine(): array | null
public function getNextLine(): array | null
{
if (empty($this->currentLines)) {
return null; // No more lines to read
@@ -51,16 +53,6 @@ class DataSetReader {
return $randomLine;
}
public function getNextLine(): array | null {
if (!isset($this->currentLines[0])) {
return null; // No more lines to read
}
$this->lastReadLineIndex = array_search($this->currentLines[0], $this->lines, true);
return array_shift($this->currentLines);
}
public function getInputSize(): int
{
return count($this->lines[0]) - 1; // Don't count the label
@@ -75,4 +67,9 @@ class DataSetReader {
{
return $this->lastReadLineIndex;
}
public function getEpochExamplesCount(): int
{
return count($this->lines);
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\IterationEventBuffer;
interface IPerceptronIterationEventBuffer {

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\IterationEventBuffer;
class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer {
private $data;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\IterationEventBuffer;
class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuffer {
private array $data;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\SynapticWeightsProvider;
interface ISynapticWeightsProvider {
public function generate(int $input_size): array;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\SynapticWeightsProvider;
class RandomSynapticWeights implements ISynapticWeightsProvider {
public function generate(int $input_size): array

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Services;
namespace App\Services\SynapticWeightsProvider;
class ZeroSynapticWeights implements ISynapticWeightsProvider {
public function generate(int $input_size): array