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

233 lines
4.1 KiB
PHP

<?php
namespace alveolata\math;
/**
* modulo operator
*
* @author Christian Fraß <frass@greenscale.de>
*/
function mod(
int $number,
int $modulus
) : int
{
// return (x - (div(x, y) * y));
if ($modulus <= 0) {
throw (new \Exception('invalid divisor'));
}
else {
return (
($number >= 0)
? ($number%$modulus)
: (($modulus-((-$number)%$modulus))%$modulus)
);
}
}
/**
* computes the power of a number in a residue class ring via square and multiply
*
* @author Christian Fraß <frass@greenscale.de>
*/
function modpow(
int $base,
int $exponent,
int $modulus
) : int
{
if ($exponent === 0) {
return 1;
}
else {
$a = modpow($base, $exponent >> 1, $modulus);
$a = mod(($a * $a), $modulus);
if (($exponent & 1) != 0) {
$a = mod(($a * $base), $modulus);
}
return $a;
}
}
/**
* @template TypeElement
* @param \Closure {function<pair<type_element,type_element>,boolean>}
* @param array $set1 {list<type_element>}
* @param array $set2 {list<type_element>}
* @return array {list<type_element>}
* @author Christian Fraß <frass@greenscale.de>
*/
function set_sub/*<type_element>*/(
\Closure $collation,
array $set1,
array $set2
) : bool
{
foreach ($set1 as $element1) {
$present = false;
foreach ($set2 as $element2) {
if ($collation($element1, $element2)) {
$present = true;
break;
}
}
if (! $present) {
return false;
break;
}
}
return true;
}
/**
* @param \Closure function<pair<type_element,type_element>,boolean>
* @param array $set1 {list<type_element>}
* @param array $set2 {list<type_element>}
* @return array {list<type_element>}
* @author Christian Fraß <frass@greenscale.de>
*/
function set_union/*<type_element>*/(
\Closure $collation,
array $set1,
array $set2
) : array
{
$set3 = [];
foreach ([$set1, $set2] as $source) {
foreach ($source as $element) {
$add = true;
foreach ($set3 as $element_) {
if ($collation($element, $element_)) {
$add = false;
break;
}
}
if ($add) {
array_push($set3, $element);
}
}
}
return $set3;
}
/**
* @param \Closure function<pair<type_element,type_element>,boolean>
* @param array $set1 {list<type_element>}
* @param array $set2 {list<type_element>}
* @return array {list<type_element>}
* @author Christian Fraß <frass@greenscale.de>
*/
function set_intersection/*<type_element>*/(
\Closure $collation,
array $set1,
array $set2
) : array
{
$set3 = [];
foreach ($set1 as $element1) {
$add = false;
foreach ($set2 as $element2) {
if ($collation($element1, $element2)) {
$add = true;
break;
}
}
if ($add) {
array_push($set3, $element1);
}
}
return $set3;
}
/**
* @param \Closure function<pair<type_element,type_element>,boolean>
* @param array $set1 {list<type_element>}
* @param array $set2 {list<type_element>}
* @return array {list<type_element>}
* @author Christian Fraß <frass@greenscale.de>
*/
function set_difference/*<type_element>*/(
\Closure $collation,
array $set1,
array $set2
) : array
{
$set3 = [];
foreach ($set1 as $element1) {
$add = true;
foreach ($set2 as $element2) {
if ($collation($element1, $element2)) {
$add = false;
break;
}
}
if ($add) {
array_push($set3, $element1);
}
}
return $set3;
}
/**
* applies the lexicographic order
*
* @template type_element
* @param order Closure {function<type_element,type_element,boolean>}
* @param array $list1 {list<type_element>}
* @param array $list2 {list<type_element>}
* @return boolean
* @author Christian Fraß <frass@greenscale.de>
*/
function order_lexicographic(
\Closure $order,
array $list1,
array $list2
) : bool
{
if (empty($list1)) {
if (empty($list2)) {
return true;
}
else {
return true;
}
}
else {
if (empty($list2)) {
return false;
}
else {
$le = $order($list1[0], $list2[0]);
$ge = $order($list2[0], $list1[0]);
if (! $le) {
if (! $ge) {
// impossible: badly defined order
}
else {
return false;
}
}
else {
if (! $ge) {
return true;
}
else {
return order_lexicographic(
$order,
array_slice($list1, 1),
array_slice($list2, 1)
);
}
}
}
}
}
?>