Fix linting
Some checks failed
linter / quality (push) Failing after 6m26s
tests / ci (8.4) (push) Successful in 5m6s
tests / ci (8.5) (push) Successful in 5m38s

This commit is contained in:
2026-03-23 08:44:50 +01:00
parent 9d4b02fab5
commit ef90236adc
32 changed files with 123 additions and 113 deletions

View File

@@ -21,8 +21,7 @@ class PerceptronInitialization implements ShouldBroadcast
public ActivationsFunctions $activationFunction, public ActivationsFunctions $activationFunction,
public string $sessionId, public string $sessionId,
public string $trainingId, public string $trainingId,
) ) {
{
// //
} }
@@ -34,7 +33,7 @@ class PerceptronInitialization implements ShouldBroadcast
public function broadcastOn(): array public function broadcastOn(): array
{ {
return [ return [
new Channel($this->sessionId . '-perceptron-training'), new Channel($this->sessionId.'-perceptron-training'),
]; ];
} }

View File

@@ -4,8 +4,6 @@ namespace App\Events;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
@@ -21,8 +19,7 @@ class PerceptronTrainingEnded implements ShouldBroadcast
public string $reason, public string $reason,
public string $sessionId, public string $sessionId,
public string $trainingId, public string $trainingId,
) ) {
{
// //
} }
@@ -34,7 +31,7 @@ class PerceptronTrainingEnded implements ShouldBroadcast
public function broadcastOn(): array public function broadcastOn(): array
{ {
return [ return [
new Channel($this->sessionId . '-perceptron-training'), new Channel($this->sessionId.'-perceptron-training'),
]; ];
} }

View File

@@ -19,8 +19,7 @@ class PerceptronTrainingIteration implements ShouldBroadcast
public array $iterations, // ["epoch" => int, "exampleIndex" => int, "error" => float, "synaptic_weights" => array] public array $iterations, // ["epoch" => int, "exampleIndex" => int, "error" => float, "synaptic_weights" => array]
public string $sessionId, public string $sessionId,
public string $trainingId, public string $trainingId,
) ) {
{
// //
} }
@@ -33,7 +32,7 @@ class PerceptronTrainingIteration implements ShouldBroadcast
{ {
// Log::debug("Broadcasting on channel: " . $this->sessionId . '-perceptron-training'); // Log::debug("Broadcasting on channel: " . $this->sessionId . '-perceptron-training');
return [ return [
new Channel($this->sessionId . '-perceptron-training'), new Channel($this->sessionId.'-perceptron-training'),
]; ];
} }

View File

@@ -57,7 +57,7 @@ class PerceptronController extends Controller
if (pathinfo($file, PATHINFO_EXTENSION) === 'csv') { if (pathinfo($file, PATHINFO_EXTENSION) === 'csv') {
$dataset = []; $dataset = [];
$dataset['label'] = str_replace('.csv', '', $file); $dataset['label'] = str_replace('.csv', '', $file);
$dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory . '/' . $file); $dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory.'/'.$file);
$dataset['data'] = []; $dataset['data'] = [];
switch (count($dataSetReader->lines[0])) { switch (count($dataSetReader->lines[0])) {
case 3: case 3:
@@ -113,12 +113,14 @@ class PerceptronController extends Controller
$datasets[] = $dataset; $datasets[] = $dataset;
} }
} }
return $datasets; return $datasets;
} }
private function getDataSetReader(string $dataSet): IDataSetReader private function getDataSetReader(string $dataSet): IDataSetReader
{ {
$dataSetFileName = "data_sets/{$dataSet}.csv"; $dataSetFileName = "data_sets/{$dataSet}.csv";
return new RandomOrderDataSetReader($dataSetFileName); return new RandomOrderDataSetReader($dataSetFileName);
} }
@@ -134,18 +136,17 @@ class PerceptronController extends Controller
$trainingId = $request->input('training_id'); $trainingId = $request->input('training_id');
if ($weightInitMethod === 'zeros') { if ($weightInitMethod === 'zeros') {
$synapticWeightsProvider = new ZeroSynapticWeights(); $synapticWeightsProvider = new ZeroSynapticWeights;
} }
$iterationEventBuffer = new PerceptronIterationEventBuffer($sessionId, $trainingId); $iterationEventBuffer = new PerceptronIterationEventBuffer($sessionId, $trainingId);
if ($maxEpochs > config('perceptron.limited_broadcast_iterations')) { if ($maxEpochs > config('perceptron.limited_broadcast_iterations')) {
$iterationsInterval = (int)($maxEpochs / config('perceptron.limited_broadcast_iterations')); $iterationsInterval = (int) ($maxEpochs / config('perceptron.limited_broadcast_iterations'));
$iterationEventBuffer = new PerceptronLimitedEpochEventBuffer($sessionId, $trainingId, $iterationsInterval); $iterationEventBuffer = new PerceptronLimitedEpochEventBuffer($sessionId, $trainingId, $iterationsInterval);
} }
$datasetReader = $this->getDataSetReader($dataSet); $datasetReader = $this->getDataSetReader($dataSet);
$networkTraining = match ($perceptronType) { $networkTraining = match ($perceptronType) {
'simple' => new SimpleBinaryPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId), 'simple' => new SimpleBinaryPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId),
'gradientdescent' => new GradientDescentPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError), 'gradientdescent' => new GradientDescentPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError),

View File

@@ -52,7 +52,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
$synaptic_weights = $this->perceptron->getSynapticWeights(); $synaptic_weights = $this->perceptron->getSynapticWeights();
$inputs_with_bias = array_merge([1], $inputs); // Add bias input $inputs_with_bias = array_merge([1], $inputs); // Add bias input
$new_weights = array_map( $new_weights = array_map(
fn($weight, $weightIndex) => $weight + ($this->learningRate * $iterationError * $inputs_with_bias[$weightIndex]), fn ($weight, $weightIndex) => $weight + ($this->learningRate * $iterationError * $inputs_with_bias[$weightIndex]),
$synaptic_weights, $synaptic_weights,
array_keys($synaptic_weights) array_keys($synaptic_weights)
); );
@@ -73,7 +73,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
$this->epochError /= $this->datasetReader->getEpochExamplesCount(); // Average error for the epoch $this->epochError /= $this->datasetReader->getEpochExamplesCount(); // Average error for the epoch
$this->datasetReader->reset(); // Reset the dataset for the next iteration $this->datasetReader->reset(); // Reset the dataset for the next iteration
} while ($this->epoch < $this->maxEpochs && !$this->stopCondition()); } while ($this->epoch < $this->maxEpochs && ! $this->stopCondition());
$this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend $this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend
@@ -86,6 +86,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
if ($condition === true) { if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId)); event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
} }
return $condition; return $condition;
} }

View File

@@ -62,14 +62,14 @@ class GradientDescentPerceptronTraining extends NetworkTraining
// Synaptic weights correction after each epoch // Synaptic weights correction after each epoch
$synaptic_weights = $this->perceptron->getSynapticWeights(); $synaptic_weights = $this->perceptron->getSynapticWeights();
$new_weights = array_map( $new_weights = array_map(
fn($weight, $weightIndex) => $weight + $this->learningRate * array_sum($epochCorrectorPerWeight[$weightIndex]), fn ($weight, $weightIndex) => $weight + $this->learningRate * array_sum($epochCorrectorPerWeight[$weightIndex]),
$synaptic_weights, $synaptic_weights,
array_keys($synaptic_weights) array_keys($synaptic_weights)
); );
$this->perceptron->setSynapticWeights($new_weights); $this->perceptron->setSynapticWeights($new_weights);
$this->datasetReader->reset(); // Reset the dataset for the next iteration $this->datasetReader->reset(); // Reset the dataset for the next iteration
} while ($this->epoch < $this->maxEpochs && !$this->stopCondition()); } while ($this->epoch < $this->maxEpochs && ! $this->stopCondition());
$this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend $this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend
@@ -82,6 +82,7 @@ class GradientDescentPerceptronTraining extends NetworkTraining
if ($condition === true) { if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId)); event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
} }
return $condition; return $condition;
} }

View File

@@ -3,9 +3,9 @@
namespace App\Models\NetworksTraining; namespace App\Models\NetworksTraining;
use App\Events\PerceptronTrainingEnded; use App\Events\PerceptronTrainingEnded;
use App\Models\ActivationsFunctions;
use App\Services\DatasetReader\IDataSetReader; use App\Services\DatasetReader\IDataSetReader;
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer; use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
use App\Models\ActivationsFunctions;
abstract class NetworkTraining abstract class NetworkTraining
{ {
@@ -13,7 +13,6 @@ abstract class NetworkTraining
/** /**
* @abstract * @abstract
* @var ActivationsFunctions
*/ */
public ActivationsFunctions $activationFunction; public ActivationsFunctions $activationFunction;
@@ -23,13 +22,14 @@ abstract class NetworkTraining
protected IPerceptronIterationEventBuffer $iterationEventBuffer, protected IPerceptronIterationEventBuffer $iterationEventBuffer,
protected string $sessionId, protected string $sessionId,
protected string $trainingId, protected string $trainingId,
) { ) {}
}
abstract public function start(): void;
abstract public function start() : void;
abstract protected function stopCondition(): bool; abstract protected function stopCondition(): bool;
protected function checkPassedMaxIterations(?float $finalError) { protected function checkPassedMaxIterations(?float $finalError)
{
if ($this->epoch >= $this->maxEpochs) { if ($this->epoch >= $this->maxEpochs) {
$message = 'Le nombre maximal d\'epoch a été atteint'; $message = 'Le nombre maximal d\'epoch a été atteint';
if ($finalError) { if ($finalError) {
@@ -40,7 +40,8 @@ abstract class NetworkTraining
} }
} }
protected function addIterationToBuffer(float $error, array $synapticWeights) { protected function addIterationToBuffer(float $error, array $synapticWeights)
{
$this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights); $this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights);
} }

View File

@@ -13,6 +13,7 @@ use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
class SimpleBinaryPerceptronTraining extends NetworkTraining class SimpleBinaryPerceptronTraining extends NetworkTraining
{ {
private Perceptron $perceptron; private Perceptron $perceptron;
private int $iterationErrorCounter = 0; private int $iterationErrorCounter = 0;
public ActivationsFunctions $activationFunction = ActivationsFunctions::STEP; public ActivationsFunctions $activationFunction = ActivationsFunctions::STEP;
@@ -51,7 +52,7 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
$this->addIterationToBuffer($error, [[$this->perceptron->getSynapticWeights()]]); $this->addIterationToBuffer($error, [[$this->perceptron->getSynapticWeights()]]);
} }
$this->datasetReader->reset(); // Reset the dataset for the next iteration $this->datasetReader->reset(); // Reset the dataset for the next iteration
} while ($this->epoch < $this->maxEpochs && !$this->stopCondition()); } while ($this->epoch < $this->maxEpochs && ! $this->stopCondition());
$this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend $this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend
@@ -64,6 +65,7 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
if ($condition === true) { if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron ne commet plus d\'erreurs sur aucune des données', $this->sessionId, $this->trainingId)); event(new PerceptronTrainingEnded('Le perceptron ne commet plus d\'erreurs sur aucune des données', $this->sessionId, $this->trainingId));
} }
return $this->iterationErrorCounter == 0; return $this->iterationErrorCounter == 0;
} }
@@ -79,9 +81,10 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
if ($error !== 0) { // Update synaptic weights if needed if ($error !== 0) { // Update synaptic weights if needed
$synaptic_weights = $this->perceptron->getSynapticWeights(); $synaptic_weights = $this->perceptron->getSynapticWeights();
$inputs_with_bias = array_merge([1], $inputs); // Add bias input $inputs_with_bias = array_merge([1], $inputs); // Add bias input
$new_weights = array_map(fn($weight, $input) => $weight + $this->learningRate * $error * $input, $synaptic_weights, $inputs_with_bias); $new_weights = array_map(fn ($weight, $input) => $weight + $this->learningRate * $error * $input, $synaptic_weights, $inputs_with_bias);
$this->perceptron->setSynapticWeights($new_weights); $this->perceptron->setSynapticWeights($new_weights);
} }
return $error; return $error;
} }

View File

@@ -2,8 +2,8 @@
namespace App\Models\Perceptrons; namespace App\Models\Perceptrons;
class GradientDescentPerceptron extends Perceptron { class GradientDescentPerceptron extends Perceptron
{
public function __construct( public function __construct(
array $synaptic_weights, array $synaptic_weights,
) { ) {
@@ -14,5 +14,4 @@ class GradientDescentPerceptron extends Perceptron {
{ {
return $weighted_sum; return $weighted_sum;
} }
} }

View File

@@ -17,10 +17,11 @@ abstract class Perceptron extends Model
$inputs = array_merge([1], $inputs); // Add bias input $inputs = array_merge([1], $inputs); // Add bias input
if (count($inputs) !== count($this->synaptic_weights)) { // Check if (count($inputs) !== count($this->synaptic_weights)) { // Check
throw new \InvalidArgumentException("Number of inputs must match number of synaptic weights."); throw new \InvalidArgumentException('Number of inputs must match number of synaptic weights.');
} }
$weighted_sum = array_sum(array_map(fn($input, $weight) => $input * $weight, $inputs, $this->synaptic_weights)); $weighted_sum = array_sum(array_map(fn ($input, $weight) => $input * $weight, $inputs, $this->synaptic_weights));
return $this->activationFunction($weighted_sum); return $this->activationFunction($weighted_sum);
} }

View File

@@ -2,8 +2,8 @@
namespace App\Models\Perceptrons; namespace App\Models\Perceptrons;
class SimpleBinaryPerceptron extends Perceptron { class SimpleBinaryPerceptron extends Perceptron
{
public function __construct( public function __construct(
array $synaptic_weights, array $synaptic_weights,
) { ) {
@@ -14,5 +14,4 @@ class SimpleBinaryPerceptron extends Perceptron {
{ {
return $weighted_sum >= 0.0 ? 1.0 : 0.0; return $weighted_sum >= 0.0 ? 1.0 : 0.0;
} }
} }

View File

@@ -6,7 +6,6 @@ use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {

View File

@@ -14,7 +14,7 @@ class InitialSynapticWeightsProvider extends ServiceProvider
public function register(): void public function register(): void
{ {
$this->app->singleton(ISynapticWeightsProvider::class, function ($app) { $this->app->singleton(ISynapticWeightsProvider::class, function ($app) {
return new RandomSynapticWeights(); return new RandomSynapticWeights;
}); });
} }

View File

@@ -2,7 +2,8 @@
namespace App\Services; namespace App\Services;
class CsvReader { class CsvReader
{
private $file; private $file;
// private array $headers; // private array $headers;
@@ -10,11 +11,10 @@ class CsvReader {
public function __construct( public function __construct(
public string $filename, public string $filename,
) ) {
{ $this->file = fopen($filename, 'r');
$this->file = fopen($filename, "r"); if (! $this->file) {
if (!$this->file) { throw new \RuntimeException('Failed to open file: '.$filename);
throw new \RuntimeException("Failed to open file: " . $filename);
} }
// $this->headers = $this->readNextLine(); // $this->headers = $this->readNextLine();
@@ -22,9 +22,10 @@ class CsvReader {
public function readNextLine(): ?array public function readNextLine(): ?array
{ {
if (($data = fgetcsv($this->file, 1000, ",")) !== FALSE) { if (($data = fgetcsv($this->file, 1000, ',')) !== false) {
return $data; return $data;
} }
return null; // End of file or error return null; // End of file or error
} }
} }

View File

@@ -2,10 +2,15 @@
namespace App\Services\DatasetReader; namespace App\Services\DatasetReader;
interface IDataSetReader { interface IDataSetReader
public function getNextLine(): array | null; {
public function getNextLine(): ?array;
public function getInputSize(): int; public function getInputSize(): int;
public function reset(): void; public function reset(): void;
public function getLastReadLineIndex(): int; public function getLastReadLineIndex(): int;
public function getEpochExamplesCount(): int; public function getEpochExamplesCount(): int;
} }

View File

@@ -4,8 +4,10 @@ namespace App\Services\DatasetReader;
use App\Services\CsvReader; use App\Services\CsvReader;
class LinearOrderDataSetReader implements IDataSetReader { class LinearOrderDataSetReader implements IDataSetReader
{
public array $lines = []; public array $lines = [];
private array $currentLines = []; private array $currentLines = [];
private int $lastReadLineIndex = -1; private int $lastReadLineIndex = -1;
@@ -36,8 +38,9 @@ class LinearOrderDataSetReader implements IDataSetReader {
} }
} }
public function getNextLine(): array | null { public function getNextLine(): ?array
if (!isset($this->currentLines[0])) { {
if (! isset($this->currentLines[0])) {
return null; // No more lines to read return null; // No more lines to read
} }

View File

@@ -4,8 +4,10 @@ namespace App\Services\DatasetReader;
use App\Services\CsvReader; use App\Services\CsvReader;
class RandomOrderDataSetReader implements IDataSetReader { class RandomOrderDataSetReader implements IDataSetReader
{
public array $lines = []; public array $lines = [];
private array $currentLines = []; private array $currentLines = [];
private int $lastReadLineIndex = -1; private int $lastReadLineIndex = -1;
@@ -36,7 +38,7 @@ class RandomOrderDataSetReader implements IDataSetReader {
} }
} }
public function getNextLine(): array | null public function getNextLine(): ?array
{ {
if (empty($this->currentLines)) { if (empty($this->currentLines)) {
return null; // No more lines to read return null; // No more lines to read

View File

@@ -2,9 +2,9 @@
namespace App\Services\IterationEventBuffer; namespace App\Services\IterationEventBuffer;
interface IPerceptronIterationEventBuffer { interface IPerceptronIterationEventBuffer
{
public function flush(): void;
public function flush(): void ; public function addIteration(int $iteration, int $exampleIndex, float $error, array $synaptic_weights): void;
public function addIteration(int $iteration, int $exampleIndex, float $error, array $synaptic_weights): void ;
} }

View File

@@ -2,9 +2,12 @@
namespace App\Services\IterationEventBuffer; namespace App\Services\IterationEventBuffer;
class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer { class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer
{
private $data; private $data;
private int $nextSizeIncreaseThreshold; private int $nextSizeIncreaseThreshold;
private int $underSizeIncreaseCount = 0; private int $underSizeIncreaseCount = 0;
public function __construct( public function __construct(
@@ -17,24 +20,25 @@ class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer
$this->nextSizeIncreaseThreshold = $sizeIncreaseStart; $this->nextSizeIncreaseThreshold = $sizeIncreaseStart;
} }
public function flush(): void { public function flush(): void
{
event(new \App\Events\PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId)); event(new \App\Events\PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
$this->data = []; $this->data = [];
} }
public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void { public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void
{
$this->data[] = [ $this->data[] = [
"epoch" => $epoch, 'epoch' => $epoch,
"exampleIndex" => $exampleIndex, 'exampleIndex' => $exampleIndex,
"error" => $error, 'error' => $error,
"weights" => $synaptic_weights, 'weights' => $synaptic_weights,
]; ];
if ($this->underSizeIncreaseCount <= $this->sizeIncreaseStart) { // We can still send a single date because we are under the increase start threshold if ($this->underSizeIncreaseCount <= $this->sizeIncreaseStart) { // We can still send a single date because we are under the increase start threshold
$this->underSizeIncreaseCount++; $this->underSizeIncreaseCount++;
$this->flush(); $this->flush();
} } elseif (count($this->data) >= $this->nextSizeIncreaseThreshold) {
else if (count($this->data) >= $this->nextSizeIncreaseThreshold) {
$this->flush(); $this->flush();
$this->nextSizeIncreaseThreshold *= $this->sizeIncreaseFactor; $this->nextSizeIncreaseThreshold *= $this->sizeIncreaseFactor;

View File

@@ -2,8 +2,10 @@
namespace App\Services\IterationEventBuffer; namespace App\Services\IterationEventBuffer;
class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuffer { class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuffer
{
private array $data; private array $data;
private int $underSizeIncreaseCount = 0; private int $underSizeIncreaseCount = 0;
public function __construct( public function __construct(
@@ -15,23 +17,26 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
$this->data = []; $this->data = [];
} }
public function flush(): void { public function flush(): void
{
event(new \App\Events\PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId)); event(new \App\Events\PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
$this->data = []; $this->data = [];
} }
public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void { public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void
{
$newData = [ $newData = [
"epoch" => $epoch, 'epoch' => $epoch,
"exampleIndex" => $exampleIndex, 'exampleIndex' => $exampleIndex,
"error" => $error, 'error' => $error,
"weights" => $synaptic_weights, 'weights' => $synaptic_weights,
]; ];
if ($this->underSizeIncreaseCount <= $this->sizeIncreaseStart) { // Special case where we need to send each iteration separately if ($this->underSizeIncreaseCount <= $this->sizeIncreaseStart) { // Special case where we need to send each iteration separately
$this->underSizeIncreaseCount++; $this->underSizeIncreaseCount++;
$this->data[] = $newData; $this->data[] = $newData;
$this->flush(); $this->flush();
return; return;
} }
@@ -39,8 +44,7 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
if ($this->data && $lastEpoch !== $epoch) { // Current Epoch has changed from the last one if ($this->data && $lastEpoch !== $epoch) { // Current Epoch has changed from the last one
if ($lastEpoch % $this->epochInterval === 0) { // The last epoch need to be sent if ($lastEpoch % $this->epochInterval === 0) { // The last epoch need to be sent
$this->flush(); // Flush all data from the previous epoch $this->flush(); // Flush all data from the previous epoch
} } else {
else {
$this->data = []; $this->data = [];
} }

View File

@@ -2,6 +2,7 @@
namespace App\Services\SynapticWeightsProvider; namespace App\Services\SynapticWeightsProvider;
interface ISynapticWeightsProvider { interface ISynapticWeightsProvider
{
public function generate(int $input_size): array; public function generate(int $input_size): array;
} }

View File

@@ -2,13 +2,15 @@
namespace App\Services\SynapticWeightsProvider; namespace App\Services\SynapticWeightsProvider;
class RandomSynapticWeights implements ISynapticWeightsProvider { class RandomSynapticWeights implements ISynapticWeightsProvider
{
public function generate(int $input_size): array public function generate(int $input_size): array
{ {
$weights = []; $weights = [];
for ($i = 0; $i < $input_size + 1; $i++) { // +1 for bias weight for ($i = 0; $i < $input_size + 1; $i++) { // +1 for bias weight
$weights[] = rand(-100, 100) / 100; // Random weights between -1 and 1 $weights[] = rand(-100, 100) / 100; // Random weights between -1 and 1
} }
return $weights; return $weights;
} }
} }

View File

@@ -2,13 +2,15 @@
namespace App\Services\SynapticWeightsProvider; namespace App\Services\SynapticWeightsProvider;
class ZeroSynapticWeights implements ISynapticWeightsProvider { class ZeroSynapticWeights implements ISynapticWeightsProvider
{
public function generate(int $input_size): array public function generate(int $input_size): array
{ {
$weights = []; $weights = [];
for ($i = 0; $i < $input_size + 1; $i++) { // +1 for bias weight for ($i = 0; $i < $input_size + 1; $i++) { // +1 for bias weight
$weights[] = 0; // Zero weights $weights[] = 0; // Zero weights
} }
return $weights; return $weights;
} }
} }

View File

@@ -11,8 +11,6 @@ const props = defineProps<{
iterations: Iteration[]; iterations: Iteration[];
}>(); }>();
const page = usePage();
const epochErrorOnly = ref<boolean>(false); const epochErrorOnly = ref<boolean>(false);
/** /**

View File

@@ -1,7 +1,6 @@
<?php <?php
use App\Http\Controllers\PerceptronController; use App\Http\Controllers\PerceptronController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::post('perceptron/run', [PerceptronController::class, 'run'])->name('perceptron.run'); Route::post('perceptron/run', [PerceptronController::class, 'run'])->name('perceptron.run');

View File

@@ -2,6 +2,6 @@
use Illuminate\Support\Facades\Broadcast; use Illuminate\Support\Facades\Broadcast;
Broadcast::channel(session()->getId() . '-perceptron-training', function ($user) { Broadcast::channel(session()->getId().'-perceptron-training', function ($user) {
return $user; return $user;
}); });

View File

@@ -4,19 +4,13 @@ namespace Tests\Services\IterationEventBuffer;
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer; use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
class DullIterationEventBuffer implements IPerceptronIterationEventBuffer { class DullIterationEventBuffer implements IPerceptronIterationEventBuffer
{
public function __construct( public function __construct(
) { ) {}
} public function flush(): void {}
public function flush(): void { public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void {}
return;
}
public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void {
return;
}
} }

View File

@@ -9,15 +9,14 @@ use Tests\Services\IterationEventBuffer\DullIterationEventBuffer;
class ADALINEPerceptronTest extends TrainingTestCase class ADALINEPerceptronTest extends TrainingTestCase
{ {
public function test_adaline_perceptron_training_logic_and() public function test_adaline_perceptron_training_logic_and()
{ {
$training = new ADALINEPerceptronTraining( $training = new ADALINEPerceptronTraining(
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and_gradient.csv')), datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and_gradient.csv')),
learningRate: 0.03, learningRate: 0.03,
maxEpochs: 10000, maxEpochs: 10000,
synapticWeightsProvider: new ZeroSynapticWeights(), synapticWeightsProvider: new ZeroSynapticWeights,
iterationEventBuffer: new DullIterationEventBuffer(), iterationEventBuffer: new DullIterationEventBuffer,
sessionId: 'test-session', sessionId: 'test-session',
trainingId: 'test-training', trainingId: 'test-training',
minError: 0.1251, minError: 0.1251,
@@ -57,8 +56,8 @@ class ADALINEPerceptronTest extends TrainingTestCase
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/table_2_10.csv')), datasetReader: new LinearOrderDataSetReader(public_path('data_sets/table_2_10.csv')),
learningRate: 0.0015, learningRate: 0.0015,
maxEpochs: 1000, maxEpochs: 1000,
synapticWeightsProvider: new ZeroSynapticWeights(), synapticWeightsProvider: new ZeroSynapticWeights,
iterationEventBuffer: new DullIterationEventBuffer(), iterationEventBuffer: new DullIterationEventBuffer,
sessionId: 'test-session', sessionId: 'test-session',
trainingId: 'test-training', trainingId: 'test-training',
// minError: 16.597077, // Impossible pour un dataset avec des labels -1 et 1 d'avoir une erreur moyenne supérieure à 2 // minError: 16.597077, // Impossible pour un dataset avec des labels -1 et 1 d'avoir une erreur moyenne supérieure à 2

View File

@@ -9,15 +9,14 @@ use Tests\Services\IterationEventBuffer\DullIterationEventBuffer;
class GradientDescentPerceptronTest extends TrainingTestCase class GradientDescentPerceptronTest extends TrainingTestCase
{ {
public function test_gradient_descent_perceptron_training_logic_and() public function test_gradient_descent_perceptron_training_logic_and()
{ {
$training = new GradientDescentPerceptronTraining( $training = new GradientDescentPerceptronTraining(
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and_gradient.csv')), datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and_gradient.csv')),
learningRate: 0.2, learningRate: 0.2,
maxEpochs: 100, maxEpochs: 100,
synapticWeightsProvider: new ZeroSynapticWeights(), synapticWeightsProvider: new ZeroSynapticWeights,
iterationEventBuffer: new DullIterationEventBuffer(), iterationEventBuffer: new DullIterationEventBuffer,
sessionId: 'test-session', sessionId: 'test-session',
trainingId: 'test-training', trainingId: 'test-training',
minError: 0.125001, minError: 0.125001,
@@ -56,8 +55,8 @@ class GradientDescentPerceptronTest extends TrainingTestCase
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/table_2_10.csv')), datasetReader: new LinearOrderDataSetReader(public_path('data_sets/table_2_10.csv')),
learningRate: 0.0015, learningRate: 0.0015,
maxEpochs: 1000, maxEpochs: 1000,
synapticWeightsProvider: new ZeroSynapticWeights(), synapticWeightsProvider: new ZeroSynapticWeights,
iterationEventBuffer: new DullIterationEventBuffer(), iterationEventBuffer: new DullIterationEventBuffer,
sessionId: 'test-session', sessionId: 'test-session',
trainingId: 'test-training', trainingId: 'test-training',
// minError: 16.388103, // Impossible pour un dataset avec des labels -1 et 1 d'avoir une erreur moyenne supérieure à 2 // minError: 16.388103, // Impossible pour un dataset avec des labels -1 et 1 d'avoir une erreur moyenne supérieure à 2

View File

@@ -9,15 +9,14 @@ use Tests\Services\IterationEventBuffer\DullIterationEventBuffer;
class SimplePerceptronTest extends TrainingTestCase class SimplePerceptronTest extends TrainingTestCase
{ {
public function test_simple_perceptron_training_logic_and() public function test_simple_perceptron_training_logic_and()
{ {
$training = new SimpleBinaryPerceptronTraining( $training = new SimpleBinaryPerceptronTraining(
datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and.csv')), datasetReader: new LinearOrderDataSetReader(public_path('data_sets/logic_and.csv')),
learningRate: 1.0, learningRate: 1.0,
maxEpochs: 100, maxEpochs: 100,
synapticWeightsProvider: new ZeroSynapticWeights(), synapticWeightsProvider: new ZeroSynapticWeights,
iterationEventBuffer: new DullIterationEventBuffer(), iterationEventBuffer: new DullIterationEventBuffer,
sessionId: 'test-session', sessionId: 'test-session',
trainingId: 'test-training', trainingId: 'test-training',
); );

View File

@@ -13,7 +13,6 @@ class TrainingTestCase extends TestCase
{ {
$training->start(); $training->start();
// Assert that the final synaptic weights are as expected withing the margin of error // Assert that the final synaptic weights are as expected withing the margin of error
// $finalWeights = $training->getSynapticWeights(); // $finalWeights = $training->getSynapticWeights();
// $this->assertEqualsWithDelta($expectedWeights, $finalWeights, $marginOfError, "Final synaptic weights do not match expected values."); // $this->assertEqualsWithDelta($expectedWeights, $finalWeights, $marginOfError, "Final synaptic weights do not match expected values.");
@@ -21,5 +20,4 @@ class TrainingTestCase extends TestCase
// Assert that the number of epochs taken is as expected // Assert that the number of epochs taken is as expected
$this->assertEquals($expectedEpochs, $training->getEpoch(), "Expected training to take $expectedEpochs epochs, but it took {$training->getEpoch()} epochs."); $this->assertEquals($expectedEpochs, $training->getEpoch(), "Expected training to take $expectedEpochs epochs, but it took {$training->getEpoch()} epochs.");
} }
} }