ahp-calc
Version:
AHP (Analytical Hierarchy Process) is a decision-making method that helps break down complex problems into a hierarchy of simpler comparisons. It uses pairwise comparisons and mathematical calculations to rank alternatives based on criteria.
170 lines (169 loc) • 6.9 kB
JavaScript
;
/**
* AHP (Analytic Hierarchy Process) class untuk menghitung bobot dan konsistensi matriks perbandingan berpasangan.
* Mendukung konversi nilai string ke number, normalisasi matriks, perhitungan bobot lokal/global, dan uji konsistensi tidak mendukung sub kriteriia.
*
* @module AHP
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AHPCrit = void 0;
const utils_1 = require("./utils");
/**
* Kelas utama untuk mengimplementasikan metode Analytic Hierarchy Process (AHP).
*/
class AHPCrit {
constructor() {
this.ri = new Map([
[1, 0.0],
[2, 0.0],
[3, 0.58],
[4, 0.9],
[5, 1.12],
[6, 1.24],
[7, 1.32],
[8, 1.41],
[9, 1.45],
[10, 1.49],
]);
}
/**
* Mengubah matriks string bertingkat (nested) menjadi matriks number.
* @param matrix Matriks string atau nested matrix
* @returns Matriks angka
*/
static convertStringMatrixToNumber(matrix) {
if (typeof matrix === "string")
return (0, utils_1.convertCell)(matrix);
if (Array.isArray(matrix)) {
return matrix.map((item) => this.convertStringMatrixToNumber(item));
}
throw new Error("Invalid matrix input.");
}
/**
* Menghitung ordo matriks 2D persegi.
* Fungsi ini menganggap bahwa matriks sudah dalam bentuk angka (bukan string).
* @param matrix Matriks 2D persegi
* @returns Ordo matriks (jumlah baris/kolom)
*/
static getMatrixOrders(matrix) {
// Mengecek apakah input adalah matriks 2D dan valid
if (!Array.isArray(matrix) ||
matrix.length === 0 ||
!Array.isArray(matrix[0])) {
throw new Error("Input bukan matriks 2D.");
}
const n = matrix.length; // Jumlah baris
for (let i = 0; i < n; i++) {
// Mengecek apakah semua baris memiliki panjang yang sama
if (matrix[i].length !== n) {
throw new Error(`Matrix is not square at row ${i}`);
}
}
return n; // Mengembalikan ordo matriks
}
/**
* Menghitung total dari setiap kolom pada matriks 2D.
* @param matrix Matriks angka 2D
* @returns Array total dari tiap kolom
*/
static countTotalEachColumn(matrix) {
if (!Array.isArray(matrix) ||
matrix.length === 0 ||
!Array.isArray(matrix[0])) {
throw new Error("Matrix must be a non-empty 2D array.");
}
const columnCount = matrix[0].length;
const totals = new Array(columnCount).fill(0);
for (let row = 0; row < matrix.length; row++) {
if (matrix[row].length !== columnCount) {
throw new Error(`Row ${row} has inconsistent column count.`);
}
for (let col = 0; col < columnCount; col++) {
const value = matrix[row][col];
if (typeof value !== "number" || isNaN(value)) {
throw new Error(`Invalid number at matrix[${row}][${col}].`);
}
totals[col] += value;
}
}
return totals.map((total) => parseFloat(total.toFixed(3)));
}
/**
* Menormalisasi matriks berdasarkan jumlah kolom.
* @param matrix Matriks angka
* @returns Matriks ternormalisasi
*/
static normalizeMatrix(matrix) {
const columnSums = matrix[0].map((_, colIndex) => matrix.reduce((sum, row) => sum + row[colIndex], 0));
return matrix.map((row) => row.map((value, colIndex) => Number((value / columnSums[colIndex]).toFixed(4))));
}
/**
* Menghitung bobot kriteria atau eignvector dari matriks ternormalisasi.
* simbol (w)
* @param normalize
* @returns Array priority
*/
static calculateCriteriaWeight(normalize) {
const weights = normalize.map((row) => {
const sum = row.reduce((a, b) => a + b, 0);
return Number((sum / row.length).toFixed(3));
});
// Optional: Normalisasi ulang untuk menghindari error floating point
const total = weights.reduce((a, b) => a + b, 0);
return weights.map((w) => Number((w / total).toFixed(4)));
}
/**
* Menghitung nilai λ maks (Lamda Max) untuk matriks perbandingan berpasangan menggunakan metode AHP.
*
* Langkah-langkah:
* 1. Menghitung hasil perkalian matriks perbandingan berpasangan (A) dengan vektor bobot (w).
* 2. Membagi hasil perkalian dengan bobot masing-masing untuk mendapatkan nilai lambda untuk setiap baris.
* 3. Menghitung rata-rata dari nilai lambda untuk memperoleh λ maks.
*
* @param {CritMatriks} matrix - Matriks perbandingan berpasangan (A), dimana setiap elemen A[i][j] menunjukkan perbandingan antara kriteria i dan kriteria j.
* @param {Bobot} bobot - Vektor bobot (w), dimana setiap elemen w[i] adalah bobot dari kriteria i.
*
* @returns {number} λ maks - Nilai λ maks yang dihitung sebagai rata-rata dari hasil pembagian antara hasil perkalian matriks dan bobot.
*/
static calculateLamdaMax(matrix, bobot) {
const result = matrix.map((row) => {
return row.reduce((acc, val, index) => acc + val * bobot[index], 0);
});
const lambdaValues = result.map((value, index) => value / bobot[index]);
const lambdaMax = lambdaValues.reduce((acc, val) => acc + val, 0) / lambdaValues.length;
return Math.round(lambdaMax * 1000) / 1000;
}
/**
* Menghitung Consistency Index (CI) untuk metode AHP.
*
* @param {number} lambdaMax - Nilai λ maks yang telah dihitung sebelumnya.
* @param {number} n - Jumlah kriteria (dimensi matriks perbandingan berpasangan).
*
* @returns {number} CI - Consistency Index yang dihitung berdasarkan rumus: CI = (λ maks - n) / (n - 1)
*/
static calculateConsistencyIndex(lambdaMax, n) {
const CI = (lambdaMax - n) / (n - 1);
return Math.round(CI * 1000) / 1000;
}
/**
* Menghitung Consistency Ratio (CR) dan menentukan apakah perbandingan konsisten.
*
* @param {number} CI - Consistency Index yang telah dihitung.
* @param {number | undefined} RI - Random Index berdasarkan jumlah kriteria (n), bisa undefined.
*
* @returns {{
* CR: number;
* isConsistent: boolean;
* }} Object berisi nilai CR dan status konsistensinya.
*/
static calculateConsistencyRatio(CI, RI) {
if (RI === undefined || RI === 0) {
return { CR: 0, isConsistent: true };
}
const rawCR = CI / RI;
const roundedCR = Math.round(rawCR * 1000) / 1000;
const isConsistent = roundedCR < 0.1;
return { CR: roundedCR, isConsistent };
}
}
exports.AHPCrit = AHPCrit;