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

304 lines
5.4 KiB
PHP

<?php
namespace alveolata\random;
/**
* @return float in interval [0,1[
*/
function generate_unit(
) : float
{
$max = \getrandmax();
return (rand(0, $max) / $max);
}
/**
* generate an integer value
*
* @param float $probability the probability with which the result is "true"
* @return bool
*/
function generate_boolean(
$probability = 0.5
) : bool
{
return (generate_unit() < $probability);
}
/**
* generate an integer value
*
* @param int $min the lowest possible generated value
* @param int $max the highest possible generated value
* @return int
*/
function generate_integer(
int $min,
int $max
) : int
{
$t = generate_unit();
return \intval(\floor($min + ($t * ($max - $min + 1))));
}
/**
* generate a string value
*
* @return string
*/
function generate_string(
int $length = 16
) : string
{
$string = '';
for ($index = 0; $index < $length; $index += 1) {
$string .= sprintf("%X", generate_integer(0, 15));
}
return $string;
}
/**
* choose an element from a list with equal probabilities for all elements
*
* @template type_element
* @param array $list {list<§type_element>}
* @return type_element
*/
function choose_uniformly(
array $list
)
{
$index = generate_integer(0, count($list)-1);
return $list[$index];
}
/**
* chooses a value randomly from a list of values with weights (a higher weight means a higher probability to be chosen)
*
* @template type_element
* @param array $list {list<record<element:§type_element,weight:float>>}
* @return type_element
*/
function choose_weighted(
array $sets
)
{
$sum = array_reduce(
$sets,
function (float $sum, array $entry) : float {return ($sum + $entry['weight']);},
0
);
if ($sum === 0) {
throw (new \Exception('weights sum up to zero; are all zero or are negative weights included?'));
}
else {
$position = generate_unit();
return array_reduce(
$sets,
function ($current, $set) use ($sum, $position) {
$next = ['index' => null, 'value' => null];
$next['index'] = ($current['index'] + ($set['weight'] / $sum));
$next['value'] = (
(($current['index'] <= $position) && ($position < $next['index']))
? $set['value']
: $current['value']
);
return $next;
},
['index' => 0, 'value' => null]
)['value'];
}
}
/**
* @return string
*/
function generate_vowel(
) : string
{
return choose_weighted([
['value' => 'i', 'weight' => 1],
['value' => 'e', 'weight' => 2],
['value' => 'a', 'weight' => 3],
['value' => 'o', 'weight' => 2],
['value' => 'u', 'weight' => 1],
]);
}
/**
* @return string
*/
function generate_semivowel(
) : string
{
return choose_weighted([
['value' => 'y', 'weight' => 2],
['value' => 'w', 'weight' => 1],
]);
}
/**
* @return string
*/
function generate_lateral_approximant(
) : string
{
return choose_weighted([
['value' => 'l', 'weight' => 1],
]);
}
/**
* @return string
*/
function generate_nasal(
) : string
{
return choose_weighted([
['value' => 'n', 'weight' => 4],
['value' => 'm', 'weight' => 2],
['value' => 'q', 'weight' => 1],
]);
}
/**
* @return string
*/
function generate_plosive(
) : string
{
return choose_weighted([
['value' => 'b', 'weight' => 1],
['value' => 'p', 'weight' => 2],
['value' => 'd', 'weight' => 1],
['value' => 't', 'weight' => 2],
['value' => 'g', 'weight' => 1],
['value' => 'k', 'weight' => 2],
]);
}
/**
* @return string
*/
function generate_fricative(
) : string
{
return choose_weighted([
['value' => 'r', 'weight' => 2],
['value' => 'h', 'weight' => 1],
['value' => 'x', 'weight' => 1],
['value' => 'j', 'weight' => 1],
['value' => 'c', 'weight' => 1],
['value' => 'v', 'weight' => 2],
['value' => 'f', 'weight' => 2],
['value' => 's', 'weight' => 2],
['value' => 'z', 'weight' => 2],
]);
}
/**
* @return string
*/
function generate_consonant(
) : string
{
return choose_weighted([
['value' => generate_lateral_approximant(), 'weight' => 1],
['value' => generate_nasal(), 'weight' => 1],
['value' => generate_plosive(), 'weight' => 1],
['value' => generate_fricative(), 'weight' => 1],
]);
}
/**
* @return string
*/
function generate_syllable(
) : string
{
/*
+---+---+---+---+---+---+---+
| | L | N | P | F | S | V |
+---+---+---+---+---+---+---+
| L | | o | x | x | o | x |
+---+---+---+---+---+---+---+
| N | | | o | x | | x |
+---+---+---+---+---+---+---+
| P | x | o | o | x | x | x |
+---+---+---+---+---+---+---+
| F | x | o | | o | x | x |
+---+---+---+---+---+---+---+
| S | x | x | x | x | | x |
+---+---+---+---+---+---+---+
| V | x | x | x | x | x | o |
+---+---+---+---+---+---+---+
{L,N,P,F}
{LP,LF,NF,NP,PL,PF,FL}
{LPF,NPL,NPF,PFL}
pflantze
glas
crayb-tic
*/
$length1 = choose_weighted([
['value' => 1, 'weight' => 3],
['value' => 2, 'weight' => 4],
['value' => 3, 'weight' => 1],
]);
return sprintf(
'%s%s%s',
generate_consonant(),
generate_vowel(),
(generate_boolean(0.125) ? generate_semivowel() : '')
);
}
/**
* @return string
*/
function generate_word(
) : string
{
$length = generate_integer(1, 4);
$syllables = [];
for ($index = 0; $index < $length; $index += 1) {
$syllables[] = generate_syllable();
}
return implode('', $syllables);
}
/**
* @return string
*/
function generate_text(
) : string
{
$length = generate_integer(8, 32);
$words = [];
for ($index = 0; $index < $length; $index += 1) {
$words[] = generate_word();
}
return implode(' ', $words);
}
?>