228 lines
6.7 KiB
Vue
228 lines
6.7 KiB
Vue
<script setup lang="ts">
|
|
import { Head } from '@inertiajs/vue3';
|
|
import { useEcho } from '@laravel/echo-vue';
|
|
import {
|
|
Chart as ChartJS,
|
|
Title,
|
|
Tooltip,
|
|
Legend,
|
|
BarElement,
|
|
CategoryScale,
|
|
LinearScale,
|
|
PointElement,
|
|
LineElement,
|
|
} from 'chart.js';
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
import LinkHeader from '@/components/LinkHeader.vue';
|
|
import type {
|
|
Dataset,
|
|
InitializationMethod,
|
|
Iteration,
|
|
PerceptronType,
|
|
} from '@/types/perceptron';
|
|
import IterationTable from '../components/IterationTable.vue';
|
|
import PerceptronDecisionGraph from '../components/PerceptronDecisionGraph.vue';
|
|
import PerceptronIterationsErrorsGraph from '../components/PerceptronIterationsErrorsGraph.vue';
|
|
import PerceptronSetup from '../components/PerceptronSetup.vue';
|
|
|
|
ChartJS.register(
|
|
Title,
|
|
Tooltip,
|
|
Legend,
|
|
BarElement,
|
|
CategoryScale,
|
|
LinearScale,
|
|
PointElement,
|
|
LineElement,
|
|
);
|
|
ChartJS.defaults.font.size = 16;
|
|
ChartJS.defaults.color = '#FFF';
|
|
ChartJS.defaults.backgroundColor = '#AAA';
|
|
|
|
const props = defineProps<{
|
|
type: PerceptronType;
|
|
sessionId: string;
|
|
datasets: Dataset[];
|
|
minError: number;
|
|
learningRate: number;
|
|
maxIterations: number;
|
|
}>();
|
|
|
|
const selectedDatasetName = ref<string>('');
|
|
const dataset = computed<number[][]>(() => {
|
|
const selected = props.datasets.find(
|
|
(d) => d.label === selectedDatasetName.value,
|
|
);
|
|
|
|
return selected ? selected.data : [];
|
|
});
|
|
const cleanedDataset = computed<
|
|
{
|
|
label: number;
|
|
data: { x: number; y: number }[];
|
|
}[]
|
|
>(() => {
|
|
if (!dataset.value) {
|
|
return [];
|
|
}
|
|
|
|
const cleanedDataset: {
|
|
label: number;
|
|
data: { x: number; y: number }[];
|
|
}[] = [];
|
|
// Separate data into each dataset based on value of the last column (label)
|
|
dataset.value.forEach((row) => {
|
|
const label = row[row.length - 1];
|
|
const dataPoint = { x: row[0], y: row[1] };
|
|
|
|
let dataset = cleanedDataset.find((d) => d.label === label);
|
|
if (!dataset) {
|
|
dataset = { label, data: [] };
|
|
cleanedDataset.push(dataset);
|
|
}
|
|
dataset.data.push(dataPoint);
|
|
});
|
|
return cleanedDataset;
|
|
});
|
|
const initializationMethod = ref<InitializationMethod>('zeros');
|
|
|
|
console.log('Session ID:', props.sessionId);
|
|
|
|
useEcho(
|
|
`${props.sessionId}-perceptron-training`,
|
|
'PerceptronTrainingIteration',
|
|
percpetronIteration,
|
|
[{}],
|
|
'public',
|
|
);
|
|
useEcho(
|
|
`${props.sessionId}-perceptron-training`,
|
|
'PerceptronTrainingEnded',
|
|
perceptronTrainingEnded,
|
|
[{}],
|
|
'public',
|
|
);
|
|
useEcho(
|
|
`${props.sessionId}-perceptron-training`,
|
|
'PerceptronInitialization',
|
|
perceptroninitialization,
|
|
[{}],
|
|
'public',
|
|
);
|
|
|
|
const iterations = ref<Iteration[]>([]);
|
|
|
|
const trainingId = ref<string>('');
|
|
function percpetronIteration(data: any) {
|
|
console.log('Received perceptron iteration data:', data);
|
|
if (data.trainingId !== trainingId.value) {
|
|
console.warn(
|
|
`Received iteration for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this iteration.`
|
|
);
|
|
return;
|
|
}
|
|
iterations.value.push(...data.iterations);
|
|
}
|
|
|
|
const trainingEnded = ref(false);
|
|
const trainingEndReason = ref('');
|
|
function perceptronTrainingEnded(data: any) {
|
|
console.log('Perceptron training ended:', data);
|
|
if (data.trainingId !== trainingId.value) {
|
|
console.warn(
|
|
`Received training ended event for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this event.`
|
|
);
|
|
return;
|
|
}
|
|
trainingEnded.value = true;
|
|
trainingEndReason.value = data.reason;
|
|
}
|
|
|
|
const activationFunction = ref<string>('');
|
|
function perceptroninitialization(data: any) {
|
|
console.log('Perceptron training initialized:', data);
|
|
if (data.trainingId !== trainingId.value) {
|
|
console.warn(
|
|
`Received initialization event for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this event.`
|
|
);
|
|
return;
|
|
}
|
|
activationFunction.value = data.activation_function;
|
|
}
|
|
function getActivationFunction(type: string): (x: number) => number {
|
|
switch (type) {
|
|
case 'step':
|
|
return (x) => (x >= 0 ? 1 : 0);
|
|
case 'sigmoid':
|
|
return (x) => 1 / (1 + Math.exp(-x));
|
|
case 'tanh':
|
|
return (x) => Math.tanh(x);
|
|
default:
|
|
return (x) => x; // Identity function as fallback
|
|
}
|
|
}
|
|
|
|
function resetTraining() {
|
|
iterations.value = [];
|
|
trainingEnded.value = false;
|
|
trainingEndReason.value = '';
|
|
activationFunction.value = '';
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Head title="Perceptron Viewer"></Head>
|
|
<main class="space-y-6">
|
|
<LinkHeader class="w-full" />
|
|
<PerceptronSetup
|
|
:type="props.type"
|
|
:datasets="props.datasets"
|
|
:selectedDataset="selectedDatasetName"
|
|
:initializationMethod="initializationMethod"
|
|
:minError="props.minError"
|
|
:sessionId="props.sessionId"
|
|
:defaultLearningRate="props.learningRate"
|
|
:defaultMaxIterations="props.maxIterations"
|
|
@update:selected-dataset="
|
|
(newValue) => {
|
|
selectedDatasetName = newValue;
|
|
}
|
|
"
|
|
@update:training-id="
|
|
(newValue) => {
|
|
trainingId = newValue;
|
|
resetTraining();
|
|
}"
|
|
/>
|
|
<div
|
|
class="align-items-start justify-content-center flex h-full min-h-dvh max-w-dvw"
|
|
v-if="selectedDatasetName || iterations.length > 0"
|
|
>
|
|
<div class="max-h-full w-full overflow-y-scroll">
|
|
<IterationTable
|
|
:iterations="iterations"
|
|
:trainingEnded="trainingEnded"
|
|
:trainingEndReason="trainingEndReason"
|
|
/>
|
|
</div>
|
|
<div class="sticky top-0 h-full w-full">
|
|
<div>
|
|
<PerceptronDecisionGraph
|
|
:cleanedDataset="cleanedDataset"
|
|
:iterations="iterations"
|
|
:activation-function="
|
|
getActivationFunction(activationFunction)
|
|
"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<PerceptronIterationsErrorsGraph
|
|
:iterations="iterations"
|
|
v-if="iterations.length > 0"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</template>
|