adjusted_mutual_information = (A, B, simplifier = 100000) => {
const contingency = A.features.map((A_polygon) =>
B.features.map((B_polygon) => {
const intersection = turf.intersect(A_polygon, B_polygon);
return intersection
? Math.round(turf.area(intersection) / simplifier)
: 0;
})
);
const total_area = sum(contingency.flat());
const A_areas = A.features.map((polygon) =>
Math.round(turf.area(polygon) / simplifier)
);
const B_areas = B.features.map((polygon) =>
Math.round(turf.area(polygon) / simplifier)
);
const entropy_A = -sum(
A_areas.map((area) => area / total_area).map((p) => p * Math.log(p))
);
const entropy_B = -sum(
B_areas.map((area) => area / total_area).map((p) => p * Math.log(p))
);
const products = A_areas.map((A_area) =>
B_areas.map((B_area) => A_area * B_area)
);
const mutual_information = sum(
zip(contingency.flat(), products.flat()).map(
([intersection, product]) =>
(intersection / total_area) *
(intersection ? Math.log((total_area * intersection) / product) : 0)
)
);
const emi = expected_mutual_information(contingency);
return (mutual_information - emi) / (Math.max(entropy_A, entropy_B) - emi);
}