Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go over Random builtins docs to get this standard #805

Merged
merged 1 commit into from
Feb 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 144 additions & 122 deletions mathics/builtin/numbers/randomnumbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,43 +101,6 @@ def randchoice(self, n, size, replace, p):
return numpy.random.choice(n, size=size, replace=replace, p=p)


class RandomState(Builtin):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomState.html</url>
<dl>
<dt>'$RandomState'
<dd>is a long number representing the internal state of the \
pseudo-random number generator.
</dl>

>> Mod[$RandomState, 10^100]
= ...
>> IntegerLength[$RandomState]
= ...

So far, it is not possible to assign values to '$RandomState'.
>> $RandomState = 42
: It is not possible to change the random state.
= 42
Not even to its own value:
>> $RandomState = $RandomState;
: It is not possible to change the random state.
"""

name = "$RandomState"
messages = {
"rndst": "It is not possible to change the random state.",
# "`1` is not a valid random state.",
}
summary_text = "internal state of the (pseudo)random number generator"

def eval(self, evaluation):
"$RandomState"

with RandomEnv(evaluation):
return Integer(get_random_state())


class _RandomBase(Builtin):
messages = {
"array": (
Expand Down Expand Up @@ -168,16 +131,22 @@ def _size_to_python(self, domain, size, evaluation):


class _RandomSelection(_RandomBase):
# implementation note: weights are clipped to numpy floats. this might be different from MMA
# where weights might be handled with full dynamic precision support through the whole computation.
# we try to limit the error by normalizing weights with full precision, and then clipping to float.
# since weights are probabilities into a finite set, this should not make a difference.
# Implementation note: weights are clipped to numpy floats. this
# might be different from MMA where weights might be handled with
# full dynamic precision support through the whole computation.
# we try to limit the error by normalizing weights with full
# precision, and then clipping to float. since weights are
# probabilities into a finite set, this should not make a
# difference.

messages = {
"wghtv": "The weights on the left-hand side of `1` has to be a list of non-negative numbers "
+ "with the same length as the list of items on the right-hand side.",
"lrwl": "`1` has to be a list of items or a rule of the form weights -> choices.",
"smplen": "RandomSample cannot choose `1` samples, as this are more samples than there are in `2`. "
"wghtv": "The weights on the left-hand side of `1` has to be a list of "
"non-negative numbers with the same length as the list of items "
"on the right-hand side.",
"lrwl": "`1` has to be a list of items or a rule of the form "
"weights -> choices.",
"smplen": "RandomSample cannot choose `1` samples, as this are more samples "
"than there are in `2`. "
+ "Use RandomChoice to choose items from a set with replacing.",
}

Expand Down Expand Up @@ -249,7 +218,7 @@ def _weights_to_python(self, weights, evaluation):
class Random(Builtin):
"""
<url>
:WMA:
:WMA link:
https://reference.wolfram.com/language/ref/Random.html</url>
<dl>
<dt>'Random[]'
Expand Down Expand Up @@ -280,18 +249,81 @@ class Random(Builtin):
summary_text = "pick a random number"


class RandomChoice(_RandomSelection):
"""
<url>
:WMA link:
https://reference.wolfram.com/language/ref/RandomChoice.html</url>

<dl>

<dt>'RandomChoice[$items$]'
<dd>randomly picks one item from $items$.

<dt>'RandomChoice[$items$, $n$]'
<dd>randomly picks $n$ items from $items$. Each pick in the $n$ picks happens \
from the given set of $items$, so each item can be picked any number of times.

<dt>'RandomChoice[$items$, {$n1$, $n2$, ...}]'
<dd>randomly picks items from $items$ and arranges the picked items in the \
nested list structure described by {$n1$, $n2$, ...}.

<dt>'RandomChoice[$weights$ -> $items$, $n$]'
<dd>randomly picks $n$ items from $items$ and uses the corresponding numeric \
values in $weights$ to determine how probable it is for each item in $items$ \
to get picked (in the long run, items with higher weights will get picked \
more often than ones with lower weight).

<dt>'RandomChoice[$weights$ -> $items$]'
<dd>randomly picks one items from $items$ using weights $weights$.

<dt>'RandomChoice[$weights$ -> $items$, {$n1$, $n2$, ...}]'
<dd>randomly picks a structured list of items from $items$ using weights \
$weights$.
</dl>

Note: 'SeedRandom' is used below so we get repeatable "random" numbers that we \
can test.

>> SeedRandom[42]
>> RandomChoice[{a, b, c}]
= {c}
>> SeedRandom[42] (* Set for repeatable randomness *)
>> RandomChoice[{a, b, c}, 20]
= {c, a, c, c, a, a, c, b, c, c, c, c, a, c, b, a, b, b, b, b}
>> SeedRandom[42]
>> RandomChoice[{"a", {1, 2}, x, {}}, 10]
= {x, {}, a, x, x, {}, a, a, x, {1, 2}}
>> SeedRandom[42]
>> RandomChoice[{a, b, c}, {5, 2}]
= {{c, a}, {c, c}, {a, a}, {c, b}, {c, c}}
>> SeedRandom[42]
>> RandomChoice[{1, 100, 5} -> {a, b, c}, 20]
= {b, b, b, b, b, b, b, b, b, b, b, c, b, b, b, b, b, b, b, b}
"""

_replace = True
summary_text = "pick items randomly from a given list"


class RandomComplex(Builtin):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomComplex.html</url>)
<url>
:WMA link:
https://reference.wolfram.com/language/ref/RandomComplex.html</url>

<dl>
<dt>'RandomComplex[{$z_min$, $z_max$}]'
<dd>yields a pseudorandom complex number in the rectangle with complex corners $z_min$ and $z_max$.
<dd>yields a pseudorandom complex number in the rectangle with complex corners \
$z_min$ and $z_max$.

<dt>'RandomComplex[$z_max$]'
<dd>yields a pseudorandom complex number in the rectangle with corners at the origin and at $z_max$.
<dd>yields a pseudorandom complex number in the rectangle with corners at the \
origin and at $z_max$.

<dt>'RandomComplex[]'
<dd>yields a pseudorandom complex number with real and imaginary parts from 0 to 1.
<dd>yields a pseudorandom complex number with real and imaginary parts from 0 \
to 1.

<dt>'RandomComplex[$range$, $n$]'
<dd>gives a list of $n$ pseudorandom complex numbers.
Expand Down Expand Up @@ -407,7 +439,9 @@ def eval_list(self, zmin, zmax, ns, evaluation):

class RandomInteger(Builtin):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomInteger.html</url>)
<url>
:WMA link:
https://reference.wolfram.com/language/ref/RandomInteger.html</url>
<dl>
<dt>'RandomInteger[{$min$, $max$}]'
<dd>yields a pseudorandom integer in the range from $min$ to \
Expand Down Expand Up @@ -485,7 +519,10 @@ def eval_list(self, rmin, rmax, ns, evaluation):

class RandomReal(Builtin):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomReal.html</url>)
<url>
:WMA link:
https://reference.wolfram.com/language/ref/RandomReal.html</url>

<dl>
<dt>'RandomReal[{$min$, $max$}]'
<dd>yields a pseudorandom real number in the range from $min$ to $max$.
Expand Down Expand Up @@ -581,9 +618,49 @@ def eval_list(self, xmin, xmax, ns, evaluation):
)


class RandomState(Builtin):
"""
<url>:WMA link:
https://reference.wolfram.com/language/ref/RandomState.html</url>
<dl>
<dt>'$RandomState'
<dd>is a long number representing the internal state of the \
pseudo-random number generator.
</dl>

>> Mod[$RandomState, 10^100]
= ...
>> IntegerLength[$RandomState]
= ...

So far, it is not possible to assign values to '$RandomState'.
>> $RandomState = 42
: It is not possible to change the random state.
= 42
Not even to its own value:
>> $RandomState = $RandomState;
: It is not possible to change the random state.
"""

name = "$RandomState"
messages = {
"rndst": "It is not possible to change the random state.",
# "`1` is not a valid random state.",
}
summary_text = "internal state of the (pseudo)random number generator"

def eval(self, evaluation):
"$RandomState"

with RandomEnv(evaluation):
return Integer(get_random_state())


class SeedRandom(Builtin):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/SeedRandom.html</url>)
<url>
:WMA link:
https://reference.wolfram.com/language/ref/SeedRandom.html</url>
<dl>
<dt>'SeedRandom[$n$]'
<dd>resets the pseudorandom generator with seed $n$.
Expand Down Expand Up @@ -651,94 +728,39 @@ def eval_empty(self, evaluation):
return SymbolNull


# If numpy is not in the system, the following classes are going to be redefined as None. flake8 complains about this.
# What should happen here is that, or the classes be defined just if numpy is there, or to use a fallback native
# implementation.


class RandomChoice(_RandomSelection):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomChoice.html</url>

<dl>

<dt>'RandomChoice[$items$]'
<dd>randomly picks one item from $items$.

<dt>'RandomChoice[$items$, $n$]'
<dd>randomly picks $n$ items from $items$. Each pick in the $n$ picks happens from the \
given set of $items$, so each item can be picked any number of times.

<dt>'RandomChoice[$items$, {$n1$, $n2$, ...}]'
<dd>randomly picks items from $items$ and arranges the picked items in the nested list \
structure described by {$n1$, $n2$, ...}.

<dt>'RandomChoice[$weights$ -> $items$, $n$]'
<dd>randomly picks $n$ items from $items$ and uses the corresponding numeric values in \
$weights$ to determine how probable it is for each item in $items$ to get picked (in the \
long run, items with higher weights will get picked more often than ones with lower weight).

<dt>'RandomChoice[$weights$ -> $items$]'
<dd>randomly picks one items from $items$ using weights $weights$.

<dt>'RandomChoice[$weights$ -> $items$, {$n1$, $n2$, ...}]'
<dd>randomly picks a structured list of items from $items$ using weights $weights$.
</dl>

Note: 'SeedRandom' is used below so we get repeatable "random" numbers that we can test.

>> SeedRandom[42]
>> RandomChoice[{a, b, c}]
= {c}
>> SeedRandom[42] (* Set for repeatable randomness *)
>> RandomChoice[{a, b, c}, 20]
= {c, a, c, c, a, a, c, b, c, c, c, c, a, c, b, a, b, b, b, b}
>> SeedRandom[42]
>> RandomChoice[{"a", {1, 2}, x, {}}, 10]
= {x, {}, a, x, x, {}, a, a, x, {1, 2}}
>> SeedRandom[42]
>> RandomChoice[{a, b, c}, {5, 2}]
= {{c, a}, {c, c}, {a, a}, {c, b}, {c, c}}
>> SeedRandom[42]
>> RandomChoice[{1, 100, 5} -> {a, b, c}, 20]
= {b, b, b, b, b, b, b, b, b, b, b, c, b, b, b, b, b, b, b, b}
"""

_replace = True
summary_text = "pick items randomly from a given list"


class RandomSample(_RandomSelection):
"""
<url>:WMA: https://reference.wolfram.com/language/ref/RandomSample.html</url>
<url>:WMA link:
https://reference.wolfram.com/language/ref/RandomSample.html</url>

<dl>
<dt>'RandomSample[$items$]'
<dd>randomly picks one item from $items$.

<dt>'RandomSample[$items$, $n$]'
<dd>randomly picks $n$ items from $items$. Each pick in the $n$ picks happens after the \
previous items picked have been removed from $items$, so each item can be picked at most \
once.
<dd>randomly picks $n$ items from $items$. Each pick in the $n$ picks happens \
after the previous items picked have been removed from $items$, so each item \
can be picked at most once.

<dt>'RandomSample[$items$, {$n1$, $n2$, ...}]'
<dd>randomly picks items from $items$ and arranges the picked items in the nested list \
structure described by {$n1$, $n2$, ...}. \
<dd>randomly picks items from $items$ and arranges the picked items in the \
nested list structure described by {$n1$, $n2$, ...}. \
Each item gets picked at most once.

<dt>'RandomSample[$weights$ -> $items$, $n$]'
<dd>randomly picks $n$ items from $items$ and uses the corresponding numeric values in \
$weights$ to determine how probable it is for each item in $items$ to get picked (in the \
long run, items with higher weights will get picked more often than ones with lower weight). \
Each item gets picked at most once.
<dd>randomly picks $n$ items from $items$ and uses the corresponding numeric \
values in $weights$ to determine how probable it is for each item in $items$ \
to get picked (in the long run, items with higher weights will get \
picked more often than ones with lower weight). Each item gets picked at\
most once.

<dt>'RandomSample[$weights$ -> $items$]'
<dd>randomly picks one items from $items$ using weights $weights$. \
Each item gets picked at most once.

<dt>'RandomSample[$weights$ -> $items$, {$n1$, $n2$, ...}]'
<dd>randomly picks a structured list of items from $items$ using weights $weights$. Each \
item gets picked at most once.
<dd>randomly picks a structured list of items from $items$ using weights $weights$.
Each item gets picked at most once.
</dl>

>> SeedRandom[42]
Expand Down