247 lines
9.5 KiB
PHP
247 lines
9.5 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\Services\Scheduling\DatasetLoader;
|
|
use App\Services\Scheduling\GeneticAlgorithmEngine;
|
|
|
|
class TestGaEngineCommand extends Command
|
|
{
|
|
protected $signature = 'ga:test-parameters
|
|
{--semester= : Semester dataset}
|
|
{--tahun= : Tahun ajaran dataset}';
|
|
|
|
protected $description = 'Jalankan pengujian otomatis hyperparameter GA (Populasi, Crossover, Mutasi, Iterasi, & Pengujian Akhir) dan tampilkan tabel Bab 4';
|
|
|
|
public function handle()
|
|
{
|
|
$this->info("================================──────────────────────────");
|
|
$this->info("🚀 MEMULAI OTOMASI PENGUJIAN ALGORITMA GENETIKA (BAB 4)");
|
|
$this->info("================================──────────────────────────");
|
|
|
|
$semester = $this->option('semester');
|
|
$tahun = $this->option('tahun');
|
|
|
|
$datasetLoader = new DatasetLoader();
|
|
$dataset = $datasetLoader->load($semester, $tahun);
|
|
|
|
$this->comment("Dataset berhasil dimuat: " . count($dataset->kelasList) . " Kelas, " . count($dataset->guruList) . " Guru, " . count($dataset->ruanganRobotkuIds) . " Ruangan.");
|
|
|
|
// 1. TAHAP 1: UJI POPULASI
|
|
$this->newLine();
|
|
$this->info("📌 1. MENJALANKAN TABEL 4.1: PENGUJIAN JUMLAH POPULASI");
|
|
$popVariations = [10, 20, 30, 40, 50];
|
|
$tabel1 = [];
|
|
$bestPop = 20;
|
|
$bestPopFitness = -1;
|
|
|
|
foreach ($popVariations as $idx => $pop) {
|
|
$engine = new GeneticAlgorithmEngine(
|
|
populationSize: $pop,
|
|
crossoverRate: 0.5,
|
|
mutationRate: 0.5,
|
|
maxGenerations: 500,
|
|
tournamentSize: 3,
|
|
elitismCount: 2
|
|
);
|
|
$res = $engine->run($dataset);
|
|
$fitness = $res['bestChromosome']->fitness;
|
|
|
|
if ($fitness > $bestPopFitness) {
|
|
$bestPopFitness = $fitness;
|
|
$bestPop = $pop;
|
|
}
|
|
|
|
$tabel1[] = [
|
|
'Uji Ke-' => $idx + 1,
|
|
'Populasi' => $pop,
|
|
'Pc' => 0.5,
|
|
'Pm' => 0.5,
|
|
'Iterasi' => 500,
|
|
'Fitness Max' => round($fitness, 6),
|
|
'Total Penalti' => $res['bestChromosome']->totalPenalty,
|
|
'Waktu (s)' => round($res['executionTime'], 4),
|
|
];
|
|
}
|
|
$this->table(['Uji Ke-', 'Populasi', 'Pc', 'Pm', 'Iterasi', 'Fitness Max', 'Penalti', 'Waktu (s)'], $tabel1);
|
|
$this->info("✅ Populasi Terbaik Terpilih: {$bestPop} (Fitness: {$bestPopFitness})");
|
|
|
|
// 2. TAHAP 2: UJI CROSSOVER RATE
|
|
$this->newLine();
|
|
$this->info("📌 2. MENJALANKAN TABEL 4.2: PENGUJIAN CROSSOVER RATE (Pc)");
|
|
$pcVariations = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9];
|
|
$tabel2 = [];
|
|
$bestPc = 0.6;
|
|
$bestPcFitness = -1;
|
|
|
|
foreach ($pcVariations as $idx => $pc) {
|
|
$engine = new GeneticAlgorithmEngine(
|
|
populationSize: $bestPop,
|
|
crossoverRate: $pc,
|
|
mutationRate: 0.5,
|
|
maxGenerations: 500,
|
|
tournamentSize: 3,
|
|
elitismCount: 2
|
|
);
|
|
$res = $engine->run($dataset);
|
|
$fitness = $res['bestChromosome']->fitness;
|
|
|
|
if ($fitness > $bestPcFitness) {
|
|
$bestPcFitness = $fitness;
|
|
$bestPc = $pc;
|
|
}
|
|
|
|
$tabel2[] = [
|
|
'Uji Ke-' => $idx + 1,
|
|
'Populasi' => $bestPop,
|
|
'Pc' => $pc,
|
|
'Pm' => 0.5,
|
|
'Iterasi' => 500,
|
|
'Fitness Max' => round($fitness, 6),
|
|
'Total Penalti' => $res['bestChromosome']->totalPenalty,
|
|
'Waktu (s)' => round($res['executionTime'], 4),
|
|
];
|
|
}
|
|
$this->table(['Uji Ke-', 'Populasi', 'Pc', 'Pm', 'Iterasi', 'Fitness Max', 'Penalti', 'Waktu (s)'], $tabel2);
|
|
$this->info("✅ Crossover Rate Terbaik Terpilih: {$bestPc} (Fitness: {$bestPcFitness})");
|
|
|
|
// 3. TAHAP 3: UJI MUTATION RATE
|
|
$this->newLine();
|
|
$this->info("📌 3. MENJALANKAN TABEL 4.3: PENGUJIAN MUTATION RATE (Pm)");
|
|
$pmVariations = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9];
|
|
$tabel3 = [];
|
|
$bestPm = 0.3;
|
|
$bestPmFitness = -1;
|
|
|
|
foreach ($pmVariations as $idx => $pm) {
|
|
$engine = new GeneticAlgorithmEngine(
|
|
populationSize: $bestPop,
|
|
crossoverRate: $bestPc,
|
|
mutationRate: $pm,
|
|
maxGenerations: 500,
|
|
tournamentSize: 3,
|
|
elitismCount: 2
|
|
);
|
|
$res = $engine->run($dataset);
|
|
$fitness = $res['bestChromosome']->fitness;
|
|
|
|
if ($fitness > $bestPmFitness) {
|
|
$bestPmFitness = $fitness;
|
|
$bestPm = $pm;
|
|
}
|
|
|
|
$tabel3[] = [
|
|
'Uji Ke-' => $idx + 1,
|
|
'Populasi' => $bestPop,
|
|
'Pc' => $bestPc,
|
|
'Pm' => $pm,
|
|
'Iterasi' => 500,
|
|
'Fitness Max' => round($fitness, 6),
|
|
'Total Penalti' => $res['bestChromosome']->totalPenalty,
|
|
'Waktu (s)' => round($res['executionTime'], 4),
|
|
];
|
|
}
|
|
$this->table(['Uji Ke-', 'Populasi', 'Pc', 'Pm', 'Iterasi', 'Fitness Max', 'Penalti', 'Waktu (s)'], $tabel3);
|
|
$this->info("✅ Mutation Rate Terbaik Terpilih: {$bestPm} (Fitness: {$bestPmFitness})");
|
|
|
|
// 4. TAHAP 4: UJI ITERASI / GENERASI
|
|
$this->newLine();
|
|
$this->info("📌 4. MENJALANKAN TABEL 4.4: PENGUJIAN JUMLAH ITERASI");
|
|
$iterVariations = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000];
|
|
$tabel4 = [];
|
|
$bestIter = 500;
|
|
$bestIterFitness = -1;
|
|
|
|
foreach ($iterVariations as $idx => $iter) {
|
|
$engine = new GeneticAlgorithmEngine(
|
|
populationSize: $bestPop,
|
|
crossoverRate: $bestPc,
|
|
mutationRate: $bestPm,
|
|
maxGenerations: $iter,
|
|
tournamentSize: 3,
|
|
elitismCount: 2
|
|
);
|
|
$res = $engine->run($dataset);
|
|
$fitness = $res['bestChromosome']->fitness;
|
|
|
|
if ($fitness > $bestIterFitness && $bestIterFitness < 1.0) {
|
|
$bestIterFitness = $fitness;
|
|
$bestIter = $iter;
|
|
}
|
|
|
|
$tabel4[] = [
|
|
'Uji Ke-' => $idx + 1,
|
|
'Populasi' => $bestPop,
|
|
'Pc' => $bestPc,
|
|
'Pm' => $bestPm,
|
|
'Iterasi' => $iter,
|
|
'Fitness Max' => round($fitness, 6),
|
|
'Total Penalti' => $res['bestChromosome']->totalPenalty,
|
|
'Waktu (s)' => round($res['executionTime'], 4),
|
|
];
|
|
}
|
|
$this->table(['Uji Ke-', 'Populasi', 'Pc', 'Pm', 'Iterasi', 'Fitness Max', 'Penalti', 'Waktu (s)'], $tabel4);
|
|
$this->info("✅ Iterasi Terbaik Terpilih: {$bestIter} (Fitness: {$bestIterFitness})");
|
|
|
|
// 5. TAHAP 5: PENGUJIAN AKHIR (RUN 10 KALI)
|
|
$this->newLine();
|
|
$this->info("📌 5. MENJALANKAN TABEL 4.5: PENGUJIAN AKHIR (10 KALI EKSEKUSI)");
|
|
$tabel5 = [];
|
|
$totalFitness = 0;
|
|
$totalTime = 0;
|
|
|
|
for ($run = 1; $run <= 10; $run++) {
|
|
$engine = new GeneticAlgorithmEngine(
|
|
populationSize: $bestPop,
|
|
crossoverRate: $bestPc,
|
|
mutationRate: $bestPm,
|
|
maxGenerations: $bestIter,
|
|
tournamentSize: 3,
|
|
elitismCount: 2
|
|
);
|
|
$res = $engine->run($dataset);
|
|
$fitness = $res['bestChromosome']->fitness;
|
|
$time = $res['executionTime'];
|
|
|
|
$totalFitness += $fitness;
|
|
$totalTime += $time;
|
|
|
|
$tabel5[] = [
|
|
'Uji Ke-' => $run,
|
|
'Populasi' => $bestPop,
|
|
'Pc' => $bestPc,
|
|
'Pm' => $bestPm,
|
|
'Iterasi' => $bestIter,
|
|
'Fitness Terbaik' => round($fitness, 6),
|
|
'Total Penalti' => $res['bestChromosome']->totalPenalty,
|
|
'Run Time (s)' => round($time, 4),
|
|
];
|
|
}
|
|
|
|
$avgFitness = round($totalFitness / 10, 6);
|
|
$avgTime = round($totalTime / 10, 4);
|
|
|
|
$tabel5[] = [
|
|
'Uji Ke-' => 'Rata-rata',
|
|
'Populasi' => $bestPop,
|
|
'Pc' => $bestPc,
|
|
'Pm' => $bestPm,
|
|
'Iterasi' => $bestIter,
|
|
'Fitness Terbaik' => $avgFitness,
|
|
'Total Penalti' => 0,
|
|
'Run Time (s)' => $avgTime,
|
|
];
|
|
|
|
$this->table(['Uji Ke-', 'Populasi', 'Pc', 'Pm', 'Iterasi', 'Fitness Terbaik', 'Penalti', 'Run Time (s)'], $tabel5);
|
|
|
|
$this->newLine();
|
|
$this->info("================================──────────────────────────");
|
|
$this->info("🎉 PENGUJIAN GA SELESAI DENGAN SUKSES!");
|
|
$this->info("⭐ KOMBINASI TERBAIK: Populasi = {$bestPop}, Pc = {$bestPc}, Pm = {$bestPm}, Iterasi = {$bestIter}");
|
|
$this->info("⭐ RATA-RATA FITNESS : {$avgFitness}");
|
|
$this->info("⭐ RATA-RATA WAKTU : {$avgTime} detik");
|
|
$this->info("================================──────────────────────────");
|
|
}
|
|
}
|