Fix(API): API number can be generate randomly

This commit is contained in:
Bertrand Benjamin 2018-12-21 17:03:12 +01:00
parent ce10db7c32
commit fd49a6c987
1 changed files with 130 additions and 11 deletions

View File

@ -10,10 +10,12 @@
Tokens representing interger and decimal Tokens representing interger and decimal
""" """
from decimal import Decimal as _Decimal
from random import random, randint
from .token import Token from .token import Token
from ...core.arithmetic import gcd
from ...core.MO import MO, MOnumber from ...core.MO import MO, MOnumber
from ...core.MO.fraction import MOFraction from ...core.MO.fraction import MOFraction
from decimal import Decimal as _Decimal
__all__ = ["Integer", "Decimal"] __all__ = ["Integer", "Decimal"]
@ -51,17 +53,49 @@ class Integer(Token):
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls): def random(cls,
raise NotImplemented name = "",
min_value = -10,
max_value = 10,
rejected = [0, 1],
reject_callbacks=[],
):
""" Generate a random Integer
:param name: name of the Integer
:param min_value: minimum value
:param max_value: maximum value
:param rejected: rejected values
:param reject_callbacks: list of function for value rejection
"""
conditions = [lambda x: x in rejected] + reject_callbacks
candidate = randint(min_value, max_value)
while any(c(candidate) for c in conditions):
candidate = randint(min_value, max_value)
return Integer(candidate, name)
class Decimal(Token): class Decimal(Token):
""" Token representing a decimal """ """ Token representing a decimal
:example:
>>> Decimal("4.3")
<Decimal 4.3>
>>> Decimal(3.3)
<Decimal 3.29999999999999982236431605997495353221893310546875>
>>> Decimal(_Decimal("2.3"))
<Decimal 2.3>
"""
def __init__(self, a, name="", ancestor=None): def __init__(self, a, name="", ancestor=None):
if not isinstance(a, MO): if not isinstance(a, MO):
if isinstance(a, (str, float)): if isinstance(a, _Decimal):
mo = MOnumber(Decimal(a)) mo = MOnumber(a)
elif isinstance(a, (str, float)):
mo = MOnumber(_Decimal(a))
else: else:
raise TypeError raise TypeError
else: else:
@ -80,12 +114,43 @@ class Decimal(Token):
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls): def random(cls,
raise NotImplemented name= "",
min_value = -10,
max_value = 10,
digits = 2,
rejected = [0, 1],
reject_callbacks=[],
):
""" Generate a random Decimal
:param name: name of the Integer
:param min_value: minimum value
:param max_value: maximum value
:param digits: digits after comas
:param rejected: rejected values
:param reject_callbacks: list of function for value rejection
"""
conditions = [lambda x: x in rejected] + reject_callbacks
float_cand = (max_value - min_value)*random() + min_value
candidate = _Decimal(f"{float_cand:.{digits}f}")
while any(c(candidate) for c in conditions):
float_cand = (max_value - min_value)*random() + min_value
candidate = _Decimal(f"{float_cand:.{digits}f}")
return Decimal(candidate, name)
class Fraction(Token): class Fraction(Token):
""" Token representing a fraction """ """ Token representing a fraction
:example:
>>> Fraction("3/4")
<Fraction 3 / 4>
"""
def __init__(self, a, name="", ancestor=None): def __init__(self, a, name="", ancestor=None):
if not isinstance(a, MO): if not isinstance(a, MO):
@ -112,8 +177,62 @@ class Fraction(Token):
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls): def random(cls,
raise NotImplemented name="",
fix_num="",
min_num=-10, max_num=10, rejected_num=[0],
reject_num_callbacks=[],
fix_denom="",
min_denom=-10, max_denom=10, rejected_denom=[0, 1, -1],
reject_denom_callbacks=[],
irreductible=False,
not_integer=True
):
""" Generate a random Fraction
:param name: Name of the fraction
:param fix_num: if set, the numerator will get this value
:param min_num: minimum value for the numerator
:param max_num: maximum value for the numerator
:param rejected_num: rejected values for the numerator
:param reject_num_callbacks: list of function for numerator rejection
:param fix_denom: if set, the denomerator will get this value
:param min_denom: minimum value for the denominator
:param max_denom: maximum value for the denominator
:param rejected_denom: rejected values for the denominator
:param reject_denom_callbacks: list of function for denomerator rejection
:param irreductible: is the generated fraction necessary irreductible
:param not_integer: can the generated fraction be egal to an interger
"""
if fix_num == "":
conditions = [lambda x: x in rejected_denom] + reject_num_callbacks
num = randint(min_num, max_num)
while any(c(num) for c in conditions):
num = randint(min_num, max_num)
else:
num = fix_num
if fix_denom == "":
conditions = [lambda x: x in rejected_denom] + reject_denom_callbacks
if irreductible:
def not_prime_with_num(denom):
return gcd(num, denom) != 1
conditions.append(not_prime_with_num)
if not_integer:
def divise_num(denom):
return num % denom == 0
conditions.append(divise_num)
denom = randint(min_denom, max_denom)
while any(c(denom) for c in conditions) :
denom = randint(min_denom, max_denom)
else:
denom = fix_denom
frac = MOFraction(num, denom)
return cls(frac, name)
@property @property
def numerator(self): def numerator(self):