rosavox/lib/alveolata/algorithm/functions.php
2025-05-23 07:33:29 +00:00

79 lines
1.7 KiB
PHP

<?php
namespace alveolata\algorithm;
require_once(DIR_ALVEOLATA . '/list/functions.php');
/**
* @param array $order {map<§x,list<§x>>}
* @return array {list<§x>}
* @throw \Exception if not possible
*/
function topsort(
array $order
) : array
{
if (empty($order)) {
return [];
}
else {
foreach ($order as $member => $dependencies) {
if (count($dependencies) <= 0) {
$order_ = [];
foreach ($order as $member_ => $dependencies_) {
if ($member === $member_) {
// do nothing
}
else {
$order_[$member_] = \alveolata\list_\filter/*<§x,bool>*/(
$dependencies_,
function ($dependency_) use ($member) : bool {
return (! ($member === $dependency_));
}
);
}
}
return array_merge([$member], topsort($order_));
}
}
throw (new \Exception('not sortable'));
}
}
/**
* calculates the levenshtein distance between two strings
*/
function levenshtein(string $x, string $y) : int
{
$u = str_split($x);
$v = str_split($y);
// init
$matrix = array_map(
fn($i) => array_map(fn($j) => null, \alveolata\list_\sequence(count($u)+1)),
\alveolata\list_\sequence(count($v)+1)
);
foreach (\alveolata\list_\sequence(count($u)+1) as $i) {$matrix[$i][0] = $i;}
foreach (\alveolata\list_\sequence(count($v)+1) as $j) {$matrix[0][$j] = $j;}
// feed
foreach (\alveolata\list_\sequence(count($u)) as $i) {
foreach (\alveolata\list_\sequence(count($v)) as $j) {
$matrix[$i+1][$j+1] = min(
min(
($matrix[$i+1][$j+0] + 1),
($matrix[$i+0][$j+1] + 1)
),
($matrix[$i+0][$j+0] + (($u[$i] === $v[$j]) ? 0 : 1))
);
}
}
// return
return $matrix[count($u)][count($v)];
}
?>