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 string $sessionId,
public string $trainingId,
)
{
) {
//
}
@@ -34,7 +33,7 @@ class PerceptronInitialization implements ShouldBroadcast
public function broadcastOn(): array
{
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\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
@@ -21,8 +19,7 @@ class PerceptronTrainingEnded implements ShouldBroadcast
public string $reason,
public string $sessionId,
public string $trainingId,
)
{
) {
//
}
@@ -34,7 +31,7 @@ class PerceptronTrainingEnded implements ShouldBroadcast
public function broadcastOn(): array
{
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 string $sessionId,
public string $trainingId,
)
{
) {
//
}
@@ -33,7 +32,7 @@ class PerceptronTrainingIteration implements ShouldBroadcast
{
// Log::debug("Broadcasting on channel: " . $this->sessionId . '-perceptron-training');
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') {
$dataset = [];
$dataset['label'] = str_replace('.csv', '', $file);
$dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory . '/' . $file);
$dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory.'/'.$file);
$dataset['data'] = [];
switch (count($dataSetReader->lines[0])) {
case 3:
@@ -113,12 +113,14 @@ class PerceptronController extends Controller
$datasets[] = $dataset;
}
}
return $datasets;
}
private function getDataSetReader(string $dataSet): IDataSetReader
{
$dataSetFileName = "data_sets/{$dataSet}.csv";
return new RandomOrderDataSetReader($dataSetFileName);
}
@@ -134,18 +136,17 @@ class PerceptronController extends Controller
$trainingId = $request->input('training_id');
if ($weightInitMethod === 'zeros') {
$synapticWeightsProvider = new ZeroSynapticWeights();
$synapticWeightsProvider = new ZeroSynapticWeights;
}
$iterationEventBuffer = new PerceptronIterationEventBuffer($sessionId, $trainingId);
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);
}
$datasetReader = $this->getDataSetReader($dataSet);
$networkTraining = match ($perceptronType) {
'simple' => new SimpleBinaryPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId),
'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();
$inputs_with_bias = array_merge([1], $inputs); // Add bias input
$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,
array_keys($synaptic_weights)
);
@@ -73,7 +73,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
$this->epochError /= $this->datasetReader->getEpochExamplesCount(); // Average error for the epoch
$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
@@ -86,6 +86,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
}
return $condition;
}

View File

@@ -62,14 +62,14 @@ class GradientDescentPerceptronTraining extends NetworkTraining
// Synaptic weights correction after each epoch
$synaptic_weights = $this->perceptron->getSynapticWeights();
$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,
array_keys($synaptic_weights)
);
$this->perceptron->setSynapticWeights($new_weights);
$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
@@ -82,6 +82,7 @@ class GradientDescentPerceptronTraining extends NetworkTraining
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
}
return $condition;
}

View File

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

View File

@@ -13,6 +13,7 @@ use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
class SimpleBinaryPerceptronTraining extends NetworkTraining
{
private Perceptron $perceptron;
private int $iterationErrorCounter = 0;
public ActivationsFunctions $activationFunction = ActivationsFunctions::STEP;
@@ -51,7 +52,7 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
$this->addIterationToBuffer($error, [[$this->perceptron->getSynapticWeights()]]);
}
$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
@@ -64,6 +65,7 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron ne commet plus d\'erreurs sur aucune des données', $this->sessionId, $this->trainingId));
}
return $this->iterationErrorCounter == 0;
}
@@ -79,9 +81,10 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
if ($error !== 0) { // Update synaptic weights if needed
$synaptic_weights = $this->perceptron->getSynapticWeights();
$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);
}
return $error;
}

View File

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

View File

@@ -17,10 +17,11 @@ abstract class Perceptron extends Model
$inputs = array_merge([1], $inputs); // Add bias input
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);
}

View File

@@ -2,8 +2,8 @@
namespace App\Models\Perceptrons;
class SimpleBinaryPerceptron extends Perceptron {
class SimpleBinaryPerceptron extends Perceptron
{
public function __construct(
array $synaptic_weights,
) {
@@ -14,5 +14,4 @@ class SimpleBinaryPerceptron extends Perceptron {
{
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\DB;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password;
class AppServiceProvider extends ServiceProvider
{

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,8 +4,10 @@ namespace App\Services\DatasetReader;
use App\Services\CsvReader;
class RandomOrderDataSetReader implements IDataSetReader {
class RandomOrderDataSetReader implements IDataSetReader
{
public array $lines = [];
private array $currentLines = [];
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)) {
return null; // No more lines to read

View File

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

View File

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

View File

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

View File

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

View File

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