80 lines
1.7 KiB
PHP
80 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)];
|
||
|
}
|
||
|
|
||
|
|
||
|
?>
|