Added configuration panel datasets, back-end refactor and others
Some checks failed
linter / quality (push) Failing after 7s
tests / ci (8.4) (push) Failing after 6s
tests / ci (8.5) (push) Failing after 5s

This commit is contained in:
2026-03-12 16:38:50 +01:00
parent 650cf56045
commit 83b7aa3f3a
39 changed files with 3176 additions and 425 deletions

View File

@@ -0,0 +1,188 @@
<script setup lang="ts">
import type {
ChartDataset,
ChartTypeRegistry,
BubbleDataPoint,
Point,
} from 'chart.js';
import { Chart } from 'vue-chartjs';
import type { Iteration } from '@/types/perceptron';
import { colors } from '@/types/graphs';
import { computed } from 'vue';
const props = defineProps<{
cleanedDataset: { label: number; data: { x: number; y: number }[] }[];
iterations: Iteration[];
activationFunction: (x: number) => number;
}>();
const farLeftDataPointX = computed(() => {
if (props.cleanedDataset.length === 0) {
return 0;
}
const minX = Math.min(...props.cleanedDataset.flatMap((d) => d.data.map((point) => point.x)));
return minX;
});
const farRightDataPointX = computed(() => {
if (props.cleanedDataset.length === 0) {
return 0;
}
const maxX = Math.max(...props.cleanedDataset.flatMap((d) => d.data.map((point) => point.x)));
return maxX;
});
function getPerceptronDecisionBoundaryDataset(
networkWeights: number[][][],
activationFunction: (x: number) => number = (x) => x,
): ChartDataset<
keyof ChartTypeRegistry,
number | Point | [number, number] | BubbleDataPoint | null
> {
const label = 'Ligne de décision du Perceptron';
console.log('Calculating decision boundary with weights:', networkWeights);
if (
networkWeights.length == 1 &&
networkWeights[0].length == 1 &&
networkWeights[0][0].length == 3
) {
// Unique, 3 weights perceptron
const perceptronWeights = networkWeights[0][0]; // We take the unique
function perceptronLine(x: number): number {
// w0 + w1*x + w2*y = 0 => y = -(w1/w2)*x - w0/w2
return -(perceptronWeights[1] / perceptronWeights[2]) * x - perceptronWeights[0] / perceptronWeights[2];
}
// Simple line
return {
type: 'line',
label: label,
data: [
{
x: farLeftDataPointX.value - 1,
y: perceptronLine(farLeftDataPointX.value - 1),
},
{
x: farRightDataPointX.value + 1,
y: perceptronLine(farRightDataPointX.value + 1),
},
],
borderColor: '#FFF',
borderWidth: 2,
pointRadius: 0,
};
} else {
function forward(x1: number, x2: number): number {
let activations: number[] = [x1, x2];
for (const layer of networkWeights) {
const nextActivations: number[] = [];
for (const neuron of layer) {
const bias = neuron[0];
const weights = neuron.slice(1);
let sum = bias;
for (let i = 0; i < weights.length; i++) {
sum += weights[i] * activations[i];
}
const activated = activationFunction(sum);
nextActivations.push(activated);
}
activations = nextActivations;
}
return activations[0]; // on suppose sortie unique
}
// -------- 2⃣ Échantillonnage grille --------
const decisionBoundary: Point[] = [];
const min = -2;
const max = 2;
const step = 0.03;
const epsilon = 0.01;
for (let x = min; x <= max; x += step) {
for (let y = min; y <= max; y += step) {
const value = forward(x, y);
if (Math.abs(value) < epsilon) {
decisionBoundary.push({ x, y });
}
}
}
// -------- 3⃣ Dataset ChartJS --------
return {
type: 'scatter',
label: label,
data: decisionBoundary,
backgroundColor: '#FFFFFF',
pointRadius: 1,
};
}
}
</script>
<template>
<Chart
v-if="props.cleanedDataset.length > 0 || props.iterations.length > 0"
class="flex"
:options="{
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Ligne de décision du Perceptron',
},
},
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 10,
},
},
scales: {
x: {
type: 'linear',
position: 'bottom',
},
y: {
type: 'linear',
position: 'left',
},
},
}"
:data="{
datasets: [
// Points from the dataset
...props.cleanedDataset.map((dataset, index) => ({
type: 'scatter',
label: `Label ${dataset.label}`,
data: dataset.data,
backgroundColor:
colors[index] || '#AAA',
})),
// Perceptron decision boundary
getPerceptronDecisionBoundaryDataset(
props.iterations.length > 0
? props.iterations[props.iterations.length - 1].weights
: [[[0, 0, 0]]],
props.activationFunction,
),
],
}"
/>
</template>