def _div_op(value, sample_args, rationals_allowed):
  """Returns sampled args for `ops.Div`."""
  assert rationals_allowed  # should be True if this function gets invoked
  entropy, sample_args = sample_args.peel()

  numer = sympy.numer(value)
  denom = sympy.denom(value)

  if sample_args.count == 1:
    mult = number.integer(entropy, signed=True, min_abs=1)
    op_args = [numer * mult, denom * mult]
  elif sample_args.count == 2:
    if numer == 0 or random.choice([False, True]):
      x = number.integer(entropy, signed=True, min_abs=1, coprime_to=denom)
      op_args = [sympy.Rational(x * numer, denom), x]
    else:
      x = number.integer(entropy, signed=True, min_abs=1, coprime_to=numer)
      op_args = [x, sympy.Rational(x * denom, numer)]
  else:
    assert sample_args.count >= 3
    p2, p1 = _split_factors(numer)
    q1, q2 = _split_factors(denom)
    entropy -= _entropy_of_factor_split(numer) + _entropy_of_factor_split(denom)
    entropy_r = random.uniform(0, entropy)
    entropy_s = entropy - entropy_r
    r = number.integer(entropy_r, signed=True, min_abs=1, coprime_to=q1*p2)
    s = number.integer(entropy_s, signed=False, min_abs=1, coprime_to=p1*q2)
    op_args = [sympy.Rational(r*p1, s*q1), sympy.Rational(r*q2, s*p2)]

  return ops.Div, op_args, sample_args
Пример #2
0
def coefficients_linear_split(coefficients, entropy):
    """Finds two sets of coefficients and multipliers summing to `coefficients`.

  Given `coefficients` (an integer vector), will sample integers `a, b`, and
  two sets of coefficients `coefficients_1, coefficients_2`, such that
  `a * coefficients_1 + b * coefficients_2 == coefficients`.

  Args:
    coefficients: Array of coefficients.
    entropy: Float >= 0; the amount of randomness used to sample.

  Returns:
    Tuple (a, b, coefficients_1, coefficients_2)`.
  """
    coefficients = np.asarray(coefficients)
    coefficients_shape = coefficients.shape
    coefficients = np.reshape(coefficients, [-1])

    entropy_a = max(1, random.uniform(0, entropy / 3))
    entropy_b = max(1, random.uniform(0, entropy / 3))
    entropy -= entropy_a + entropy_b
    entropy_coefficients = entropy * np.random.dirichlet(
        np.ones(len(coefficients)))

    # For each target coefficient z, we are required to solve the linear
    # Diophantine equation a*x + b*y = c. Bezout's theorem: this has a solution if
    # and only if gcd(a, b) divides c.
    # Thus to be solvable for all coefficients, a and b must be chosen such that
    # gcd(a, b) divides the gcd of the coefficients.
    coefficients_gcd = sympy.gcd([i for i in coefficients])
    coefficients_gcd = max(1, abs(coefficients_gcd))

    a = number.integer(entropy_a, signed=True, min_abs=1)
    b = number.integer(entropy_b, signed=True, min_abs=1, coprime_to=a)
    b *= _random_factor(coefficients_gcd)
    if random.choice([False, True]):
        a, b = b, a

    coefficients_1 = np.zeros(coefficients.shape, dtype=np.object)
    coefficients_2 = np.zeros(coefficients.shape, dtype=np.object)

    for index, coefficient in enumerate(coefficients):
        entropy_coeff = entropy_coefficients[index]
        t = number.integer(entropy_coeff, signed=True)
        x, y = diophantine_solve_linear_2d(c=coefficient, a=a, b=b, t=t)
        coefficients_1[index] = x
        coefficients_2[index] = y

    # Prevent all coefficients from being zero.
    while np.all(coefficients_1 == 0) or np.all(coefficients_2 == 0):
        index = random.randint(0, len(coefficients) - 1)
        scale = random.choice([-1, 1])
        coefficients_1[index] += scale * b
        coefficients_2[index] -= scale * a

    coefficients_1 = np.reshape(coefficients_1, coefficients_shape)
    coefficients_2 = np.reshape(coefficients_2, coefficients_shape)

    return a, b, coefficients_1, coefficients_2
Пример #3
0
def evaluate(value, sample_args, context=None):
    """Entity for evaluating an integer-valued polynomial at a given point."""
    is_question = context is None
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()

    if value is None:
        entropy_value = random.uniform(1, 1 + entropy / 3)
        entropy = max(0, entropy - entropy_value)
        value = number.integer(entropy_value, signed=True)

    entropy_input = random.uniform(1, 1 + entropy / 3)
    entropy = max(0, entropy - entropy_input)
    input_ = number.integer(entropy_input, signed=True)

    degree = random.randint(1, 3)

    entropies = entropy * np.random.dirichlet(list(range(1, degree + 1)))
    # Calculate coefficients in reverse order.
    target = value
    coeffs_reversed = []
    for i, coeff_entropy in enumerate(entropies):
        power = degree - i
        coeff = number.integer(coeff_entropy, signed=True)
        if input_ != 0:
            coeff += int(round(target / input_**power))
        if coeff == 0 and i == 0:
            # Don't allow zero in leading coefficient.
            coeff += random.choice([-1, 1])
        coeffs_reversed.append(coeff)
        target -= coeff * (input_**power)
    coeffs_reversed.append(target)

    coefficients = list(reversed(coeffs_reversed))

    (polynomial_entity,
     input_) = context.sample(sample_args,
                              [composition.Polynomial(coefficients), input_])
    composed = polynomial_entity.handle.apply(input_.handle)

    if is_question:
        template = random.choice(_TEMPLATES)
        return example.Problem(question=example.question(context,
                                                         template,
                                                         composed=composed),
                               answer=value)
    else:
        return composition.Entity(context=context,
                                  value=value,
                                  expression=composed,
                                  description='Пусть {self} {composed}.',
                                  composed=composed)
Пример #4
0
def _pair_with_large_hidden_factor(entropy):
    """Returns pair of numbers with possibly large common factor hidden."""
    entropy_p, entropy_q, _ = entropy * np.random.dirichlet([1, 1, 1])
    # Min entropy on p and q to minimize trivial solutions.
    entropy_p = max(1, entropy_p)
    entropy_q = max(1, entropy_q)
    entropy_mult = max(0, entropy - entropy_p - entropy_q)

    p = number.integer(entropy_p, False, min_abs=1)
    q = number.integer(entropy_q, False, min_abs=1)
    mult = number.integer(entropy_mult, False, min_abs=1)
    p *= mult
    q *= mult
    return p, q
Пример #5
0
def sample_with_small_evaluation(variable, degree, max_abs_input, entropy):
    """Generates a (canonically ordered) polynomial, with bounded evaluation.

  The coefficients are chosen to make use of the entropy, with the scaling
  adjusted so that all give roughly the same contribution to the output of the
  polynomial when the input is bounded in magnitude by `max_abs_input`.

  Args:
    variable: Variable to use in polynomial.
    degree: Degree of polynomial.
    max_abs_input: Number >= 1; max absolute value of input.
    entropy: Float; randomness for generating polynomial.

  Returns:
    Instance of `ops.Add`.
  """
    assert max_abs_input >= 1
    entropies = entropy * np.random.dirichlet(np.ones(degree + 1))
    coeffs = []

    for power in range(degree + 1):
        # This scaling guarantees that the terms give roughly equal contribution
        # to the typical magnitude of the polynomial when |input| <= max_abs_input.
        delta = 0.5 * (degree - 2 * power) * math.log10(max_abs_input)
        power_entropy = entropies[power] + delta
        min_abs = 1 if power == degree else 0
        coeff = number.integer(power_entropy, signed=True, min_abs=min_abs)
        coeffs.append(coeff)

    terms = [
        monomial(coeff, variable, power) for power, coeff in enumerate(coeffs)
    ]
    return ops.Add(*terms)
Пример #6
0
 def mul_by_integer():
   entropy_k = min(1, entropy)
   left = number.integer(entropy_k, signed=True, min_abs=1)
   right = _sample_surd(base, entropy - entropy_k, max_power, multiples_only)
   if random.choice([False, True]):
     left, right = right, left
   return ops.Mul(left, right)
Пример #7
0
def base_conversion(min_entropy, max_entropy):
    """E.g., "What is 17 base 8 in base 10?"."""
    context = composition.Context()

    from_base = random.randint(2, 16)
    while True:
        to_base = random.randint(2, 16)
        if to_base != from_base:
            break

    # Entropy used up in selecting bases.
    entropy_used = math.log10(16 * 15)
    entropy = random.uniform(min_entropy - entropy_used,
                             max_entropy - entropy_used)

    value = number.integer(entropy, signed=True)
    template = random.choice([
        # '{from_str} (base {from_base}) to base {to_base}',
        'Приведите {from_str} (по основанию {from_base}) к основанию {to_base}.',
        # 'What is {from_str} (base {from_base}) in base {to_base}?',
    ])
    return example.Problem(question=example.question(
        context,
        template,
        from_str=display.NumberInBase(value, from_base),
        from_base=from_base,
        to_base=to_base),
                           answer=display.NumberInBase(value, to_base))
Пример #8
0
def nearest_integer_root(sample_args):
  """E.g., "Calculate the cube root of 35 to the nearest integer."."""
  context = composition.Context()

  # With at least 50% probability, pick square or cube root (these are most
  # important roots!).
  if random.choice([False, True]):
    one_over_exponent = random.randint(2, 3)
  else:
    one_over_exponent = random.randint(2, 10)

  entropy, sample_args = sample_args.peel()
  value = number.integer(entropy, signed=False)
  answer = int(round(value ** (1 / one_over_exponent)))

  # templates = [
  #     'What is {value} to the power of 1/{one_over_exponent}, to the nearest'
  #     ' integer?',
  # ]
  templates = [
      'Сколько получится, если {value} возвести в степень 1/{one_over_exponent} и округлить до целого числа?',
  ]


  if one_over_exponent != 2:  # "What is the second root of 4?" never used.
    ordinal = str()
    # templates += [
    #     'What is the {ordinal} root of {value} to the nearest integer?',
    # ]

    templates += [
        'Чему равен {ordinal} корень от {value}? Ответ округлите до целого числа.',
    ]

  if one_over_exponent == 2:
    # templates += [
        # 'What is the square root of {value} to the nearest integer?',
    # ]
    templates += [
        'Чему равен квадратный корень {value}? Ответ округлите до целого числа.',
    ]
  elif one_over_exponent == 3:
    # templates += [
    #     'What is the cube root of {value} to the nearest integer?',
    # ]
    templates += [
        'Чему равен корень кубический {value}? Ответ округлите до целого числа.',
    ]

  template = random.choice(templates)

  ordinal = display.StringOrdinal(one_over_exponent)
  return example.Problem(
      question=example.question(
          context, template, value=value, ordinal=ordinal,
          one_over_exponent=one_over_exponent),
      answer=answer)
Пример #9
0
 def surd_plus_integer():
   """Do surd + integer."""
   entropy_k = min(1, entropy)
   left = number.integer(entropy_k, signed=True)
   assert not multiples_only
   right = _sample_surd(base, entropy - entropy_k, max_power, False)
   if random.choice([True, False]):
     left, right = right, left
   return ops.Add(left, right)
Пример #10
0
def lcm(value, sample_args, context=None):
    """Question for least common multiple of p and q."""
    del value  # unused
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()

    p, q = _pair_with_large_hidden_factor(entropy)
    answer = sympy.lcm(p, q)

    if random.choice([False, True]):
        p, q = context.sample(sample_args, [p, q])
        # Ask the question directly.
        adjective = random.choice(['наименьший'])
        template = random.choice([
            'Найдите {adjective} общий множитель {p} и {q}.',
            'Какой {adjective} общий множитель у {p} и {q}?',
        ])
        return example.Problem(question=example.question(
            context,
            template,
            adjective=adjective,
            p=p.expression_else_handle,
            q=q.expression_else_handle),
                               answer=answer)
    else:
        # Phrase the question as finding the common denominator of two fractions.
        p = number.integer(2, signed=True, coprime_to=p) / p
        q = number.integer(2, signed=True, coprime_to=q) / q
        p, q = context.sample(sample_args, [p, q])

        template = random.choice([
            'Найдите общий знаменатель {p} и {q}.',
            'Чему равен общий знаменатель {p} и {q}?',
            # 'Calculate the common denominator of {p} and {q}.',
        ])
        return example.Problem(question=example.question(
            context,
            template,
            p=p.expression_else_handle,
            q=q.expression_else_handle),
                               answer=answer)
Пример #11
0
def _semi_prime(entropy):
    """Generates a semi-prime with the given entropy."""
    # Add on extra entropy to account for the sparsity of the primes; we don't
    # actually use the integers sampled, but rather a random prime close to them;
    # thus some entropy is lost, which we must account for
    entropy += math.log10(max(1, entropy * math.log(10)))

    # We intentionally uniformy sample the "entropy" (i.e., approx number digits)
    # of the two factors.
    entropy_1, entropy_2 = entropy * np.random.dirichlet([1, 1])

    # Need >= 2 for randprime to always work (Betrand's postulate).
    approx_1 = number.integer(entropy_1, signed=False, min_abs=2)
    approx_2 = number.integer(entropy_2, signed=False, min_abs=2)

    factor_1 = sympy.ntheory.generate.randprime(approx_1 / 2, approx_1 * 2)
    factor_2 = sympy.ntheory.generate.randprime(approx_2 / 2, approx_2 * 2)

    return factor_1 * factor_2
Пример #12
0
 def div_by_sqrt_k():
   """Do sqrt(k * base) / sqrt(k)."""
   entropy_k = min(1, entropy)
   k = number.integer(entropy_k, signed=False, min_abs=2)
   entropy_left, entropy_right = _surd_split_entropy_two(entropy - entropy_k)
   k_base_expr = _sample_surd(k * base, entropy_left, max_power, True)
   while True:
     k_expr = _sample_surd(k, entropy_right, max_power, True)
     if k_expr.sympy() != 0:
       break
   return ops.Div(k_base_expr, k_expr)
def _sub_op(value, sample_args, rationals_allowed):
  """Returns sampled args for `ops.Sub`."""
  entropy, sample_args = sample_args.peel()
  if rationals_allowed and sample_args.count >= 3:
    x = number.integer_or_rational(entropy, True)
  else:
    x = number.integer(entropy, True)
  if random.choice([False, True]):
    op_args = [x, x - value]
  else:
    op_args = [value + x, x]
  return ops.Sub, op_args, sample_args
Пример #14
0
def sample_coefficients(degrees, entropy, min_non_zero=0, max_non_zero=None):
    """Generates grid of coefficients with shape `degrees + 1`.

  This corresponds to univariate if degrees has length 1, otherwise
  multivariate.

  Args:
    degrees: List of integers containing max degrees of variables.
    entropy: Float >= 0; entropy for generating entries.
    min_non_zero: Optional integer >= 1; the minimum number of non-zero coeffs.
    max_non_zero: Optional integer >= 1; the maximum number of non-zero coeffs.

  Returns:
    NumPy int array of shape `degrees + 1`.
  """
    if isinstance(degrees, int):
        degrees = [degrees]
    degrees = np.asarray(degrees)

    def random_index():
        return [random.randint(0, degrees[i]) for i in range(len(degrees))]

    indices = set()
    # Ensure a variable of degree `degrees[i]` occurs for every axis i.
    for i, degree in enumerate(degrees):
        if degree > 0:
            index = random_index()
            index[i] = degree
            indices.add(tuple(index))

    abs_max_non_zero = np.prod(degrees + 1)

    min_non_zero = max(min_non_zero, 1, len(indices))
    if max_non_zero is None:
        max_non_zero = min_non_zero + int(entropy / 2)

    min_non_zero = min(min_non_zero, abs_max_non_zero)
    max_non_zero = min(max_non_zero, abs_max_non_zero)
    max_non_zero = max(min_non_zero, max_non_zero)

    num_non_zero = random.randint(min_non_zero, max_non_zero)

    while len(indices) < num_non_zero:
        indices.add(tuple(random_index()))

    coeffs = np.zeros(degrees + 1, dtype=np.int64)
    entropies = entropy * np.random.dirichlet(np.ones(num_non_zero))

    for index, entry_entropy in zip(indices, entropies):
        value = number.integer(entry_entropy, signed=True, min_abs=1)
        coeffs.itemset(index, value)

    return coeffs
Пример #15
0
def div_remainder(value, sample_args, context=None):
    """E.g., "What is the remainder when 27 is divided by 5?"."""
    is_question = context is None
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()

    if value is None:
        entropy_value = 1 + random.uniform(0, entropy / 3)
        entropy = max(0, entropy - entropy_value)
        value = number.integer(entropy_value, signed=False)

    entropy_a, entropy_q = entropy * np.random.dirichlet([1, 1])
    a = number.integer(entropy_a, signed=False, min_abs=1)
    q = value + number.integer(entropy_q, signed=False, min_abs=1)

    p = a * q + value
    assert p % q == value
    p, q = context.sample(sample_args, [p, q])

    if is_question:
        template = random.choice([
            'Расчитайте остаток от деления {p} на {q}.',
            'Чему равен остаток деления {p} на {q}?',
        ])
        return example.Problem(question=example.question(
            context,
            template,
            p=p.expression_else_handle,
            q=q.expression_else_handle),
                               answer=value)
    else:
        return composition.Entity(
            context=context,
            value=value,
            description='Пусть {self} - остаток от деления {p} на {q}.',
            p=p,
            q=q)
 def testInteger_allowZero(self, signed):
     saw_zero = False
     saw_nonzero = False
     for _ in range(1000):
         sample = number.integer(1, signed=signed)
         if sample == 0:
             saw_zero = True
         else:
             saw_nonzero = True
         if saw_zero and saw_nonzero:
             break
     self.assertTrue(saw_zero)
     self.assertTrue(saw_nonzero)
Пример #17
0
def add_or_sub_in_base(sample_args):
  """Module for addition and subtraction in another base."""
  context = composition.Context()
  entropy, sample_args = sample_args.peel()
  entropy_p, entropy_q = _entropy_for_pair(entropy)
  p = number.integer(entropy_p, signed=True)
  q = number.integer(entropy_q, signed=True)
  base = random.randint(2, 16)
  if random.choice([False, True]):
    answer = p + q
    template = 'По основанию {base}, чему равно {p} + {q}?'
  else:
    answer = p - q
    template = 'По основанию {base}, чему равно {p} - {q}?'
  return example.Problem(
      question=example.question(
          context,
          template,
          base=base,
          p=display.NumberInBase(p, base),
          q=display.NumberInBase(q, base)),
      answer=display.NumberInBase(answer, base))
Пример #18
0
def div(value, sample_args, context=None):
  """Returns random question for dividing two numbers."""
  del value  # unused
  is_question = context is None
  if context is None:
    context = composition.Context()

  entropy, sample_args = sample_args.peel()
  entropy_1, entropy_q = _entropy_for_pair(entropy)

  q = number.integer(entropy_q, True, min_abs=1)

  if random.choice([False, True]):
    # Pick p/q with nice integer result.
    answer = number.integer(entropy_1, True)
    p = answer * q
  else:
    p = number.integer(entropy_1, True)
    answer = p / q

  p, q = context.sample(sample_args, [p, q])

  if is_question:
    template = random.choice([
        'Разделите {p} на {q}.',
        'Чему равно {p} разделить на {q}',
        'Сколько получится, если {p} поделить на {q}?',
        'Чему равен результат деления {p} на {q}.',
    ])
    return example.Problem(
        question=example.question(context, template, p=p, q=q),
        answer=answer
    )
  else:
    return composition.Entity(
        context=context,
        value=answer,
        description='Пусть {self} равно {p} разделить на {q}.',
        p=p, q=q)
Пример #19
0
def is_factor(value, sample_args, context=None):
    """E.g., "Is 5 a factor of 48?"."""
    del value  # unused
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()

    entropy_factor = 1 + random.uniform(0, entropy / 3)
    entropy = max(0, entropy - entropy_factor)
    maybe_factor = number.integer(entropy_factor, False, min_abs=2)

    integer = maybe_factor * number.integer(entropy, False, min_abs=1)
    # Produce balanced classes.
    if random.choice([False, True]):
        # The following makes it not a factor.
        integer += random.randint(1, maybe_factor - 1)

    (entity, ) = context.sample(sample_args, [integer])

    templates = [
        # 'Is {maybe_factor} a factor of {value}?',
        # 'Is {value} a multiple of {maybe_factor}?',
        'Является ли {maybe_factor} делителем {value}?',
    ]
    if maybe_factor == 2:
        templates += [
            'Является ли {value} четным?',
        ]
    template = random.choice(templates)

    answer = integer % maybe_factor == 0
    return example.Problem(question=example.question(
        context,
        template,
        maybe_factor=maybe_factor,
        value=entity.expression_else_handle),
                           answer=answer)
Пример #20
0
def integers_with_sum(value, count, entropy):
    """Returns list of integers with a given sum.

  Args:
    value: Target value.
    count: Integer >= 1; the number of integers to use.
    entropy: Entropy to use (in total).

  Returns:
    List of numbers summing to `value`.

  Raises:
    ValueError: If `value` is not an integer.
  """
    # Special cases.
    if count == 0:
        assert value == 0
        assert entropy == 0
        return []
    if count == 1:
        assert entropy == 0
        return [value]

    if not number.is_integer(value):
        raise ValueError('value={} (type={}) is not an integer'.format(
            value, type(value)))

    # Because e.g., (1, 1) and (2, 2) will both map to the same set of integers
    # when we normalize to have sum equal to `value`.
    entropy *= count / (count - 1)

    min_term_entropy = max(
        1, number.entropy_of_value(int(math.ceil(value / count))))
    term_entropies = entropy * np.random.dirichlet(np.ones(count))
    term_entropies = np.maximum(min_term_entropy, term_entropies)

    terms = [
        number.integer(term_entropy, signed=True)
        for term_entropy in term_entropies
    ]

    delta = value - sum(terms)
    deltas = _split_value_equally(delta, count)
    terms = [term + delta for term, delta in zip(terms, deltas)]
    random.shuffle(terms)
    return terms
Пример #21
0
def place_value(value, sample_args, context=None):
    """E.g., "Q: What is the tens digit of 31859? A: 5."""
    del value  # unused for now
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()
    integer = number.integer(entropy, signed=False, min_abs=1)
    (entity, ) = context.sample(sample_args, [integer])

    integer_as_string = str(integer)
    num_digits = len(integer_as_string)

    firsts = ['', 'десятков ', 'сотен ']
    seconds = [
        'тысяч',
        'миллионов',
        'миллиардов',
        'триллионов',
        'квадриллионов',
        'квинтиллионов',
        'секстиллионов',
        'септиллионов',
        'октиллионов',
        'нониллионов',
        'дециллионов',
    ]
    place_names = ['единиц', 'десятков', 'сотен']
    for second in seconds:
        for first in firsts:
            place_names.append(first + second)

    place = random.randint(1, num_digits)  # 1 = units, 2 = tens, etc.
    place_name = place_names[place - 1]
    answer = sympy.Integer(integer_as_string[num_digits - place])

    return example.Problem(question=example.question(
        context,
        np.random.choice([
            'Какая цифра в числе {integer} соответствует разряду {place_name}.',
            'Какая цифра стоит в разряде {place_name} в числе {integer}?',
        ]),
        place_name=place_name,
        integer=entity.expression_else_handle),
                           answer=answer)
Пример #22
0
def gcd(value, sample_args, context=None):
    """Question for greatest common divisor of p and q."""
    is_question = context is None
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()
    if value is None:
        value_entropy = 1 + random.uniform(0, entropy / 3)
        entropy = max(1, entropy - value_entropy)
        value = number.integer(value_entropy, False, min_abs=1)

    p_mult, q_mult = _random_coprime_pair(entropy)

    p = value * p_mult
    q = value * q_mult
    assert sympy.gcd(p, q) == value

    p, q = context.sample(sample_args, [p, q])

    adjective = (random.choice(['наибольший', 'самый большой']) + ' общий ' +
                 random.choice(['знаменатель']))

    if is_question:
        template = random.choice([
            'Расчитайте {adjective} {p} и {q}.',
            'Чему равен {adjective} {p} и {q}?',
        ])
        return example.Problem(question=example.question(context,
                                                         template,
                                                         adjective=adjective,
                                                         p=p,
                                                         q=q),
                               answer=value)
    else:
        return composition.Entity(
            context=context,
            value=value,
            description='Пусть {self} - это {adjective} {p} и {q}.',
            adjective=adjective,
            p=p,
            q=q)
Пример #23
0
def list_prime_factors(value, sample_args, context=None):
    """E.g., "What are the prime factors of 36?"."""
    del value  # unused for now
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()
    entropy = max(1, entropy)

    integer = number.integer(entropy, signed=False, min_abs=2)

    (entity, ) = context.sample(sample_args, [integer])
    prime_factors = sorted(sympy.factorint(integer).keys())
    template = random.choice([
        # 'What are the prime factors of {integer}?',
        # 'List the prime factors of {integer}.',
        'Найдите простые делители числа {integer}?',
        'Перечислите простые делители числа {integer}.',
    ])
    return example.Problem(question=example.question(
        context, template, integer=entity.expression_else_handle),
                           answer=display.NumberList(prime_factors))
def _mul_op(value, sample_args, rationals_allowed):
  """Returns sampled args for `ops.Mul`."""
  if sample_args.count >= 3:
    _, op_args, sample_args = _div_op(value, sample_args, rationals_allowed)
    op_args = [op_args[0], sympy.Integer(1) / op_args[1]]
  elif sample_args.count == 1:
    entropy, sample_args = sample_args.peel()
    assert _entropy_of_factor_split(value) >= entropy
    op_args = _split_factors(value)
  else:
    assert sample_args.count == 2
    entropy, sample_args = sample_args.peel()
    numer = sympy.numer(value)
    denom = sympy.denom(value)
    p1, p2 = _split_factors(numer)
    entropy -= _entropy_of_factor_split(numer)
    mult = number.integer(entropy, signed=True, min_abs=1, coprime_to=p1)
    op_args = [p1 / (mult * denom), p2 * mult]

  if random.choice([False, True]):
    op_args = list(reversed(op_args))

  return ops.Mul, op_args, sample_args
Пример #25
0
def _random_coprime_pair(entropy):
    """Returns a pair of random coprime integers."""
    coprime_product = number.integer(entropy, False, min_abs=1)
    factors = sympy.factorint(coprime_product)

    def take():
        prime = random.choice(list(factors.keys()))
        power = factors[prime]
        del factors[prime]
        return prime**power

    if random.random() < 0.8 and len(factors) >= 2:
        # Disallow trivial factoring where possible.
        count_left = random.randint(1, len(factors) - 1)
        count_right = len(factors) - count_left
    else:
        count_left = random.randint(0, len(factors))
        count_right = len(factors) - count_left

    left = sympy.prod([take() for _ in range(count_left)])
    right = sympy.prod([take() for _ in range(count_right)])
    assert left * right == coprime_product
    return left, right
class NumberTest(parameterized.TestCase):
    def testCoprimeDensity(self):
        self.assertEqual(number._coprime_density(1), 1.0)
        self.assertEqual(number._coprime_density(2), 0.5)
        self.assertLess(abs(number._coprime_density(3) - 2 / 3), 1e-6)
        self.assertLess(abs(number._coprime_density(6) - 1 / 3), 1e-6)

    @parameterized.parameters(False, True)
    def testInteger_allowZero(self, signed):
        saw_zero = False
        saw_nonzero = False
        for _ in range(1000):
            sample = number.integer(1, signed=signed)
            if sample == 0:
                saw_zero = True
            else:
                saw_nonzero = True
            if saw_zero and saw_nonzero:
                break
        self.assertTrue(saw_zero)
        self.assertTrue(saw_nonzero)

    def testNonIntegerRational(self):
        for _ in range(1000):
            entropy = random.uniform(0, 10)
            signed = random.choice([False, True])
            sample = number.non_integer_rational(entropy, signed)
            self.assertNotEqual(sympy.denom(sample), 1)

    @parameterized.parameters(False, True)
    def testIntegerOrRational(self, signed):
        # Tests we can call it. Do it a few times so both code paths get executed.
        for _ in range(10):
            number.integer_or_rational(2, signed)

    def testNonIntegerDecimal(self):
        for _ in range(1000):
            sample = number.non_integer_decimal(1, False)
            self.assertNotEqual(sympy.denom(sample), 1)
            self.assertLen(str(sample), 3)  # should be of form "0.n"
            self.assertGreater(sample, 0)  # positive

    def testNonIntegerDecimal_size(self):
        saw_bigger_one = False
        saw_smaller_one = False
        for _ in range(1000):
            sample = number.non_integer_decimal(2, False)
            if sample > 1:
                saw_bigger_one = True
            else:
                saw_smaller_one = True
            if saw_bigger_one and saw_smaller_one:
                break
        self.assertTrue(saw_bigger_one)
        self.assertTrue(saw_smaller_one)

    @parameterized.parameters(lambda: number.integer(0, True),
                              lambda: number.integer(1, True),
                              lambda: number.non_integer_rational(2, True),
                              lambda: number.non_integer_decimal(1, True))
    def testGenerate_signed(self, generator):
        saw_positive = False
        saw_negative = False
        for _ in range(1000):
            sample = generator()
            saw_positive |= sample > 0
            saw_negative |= sample < 0
            if saw_positive and saw_negative:
                break

        self.assertTrue(saw_positive)
        self.assertTrue(saw_negative)

    @parameterized.parameters(lambda: number.integer(2, False),
                              lambda: number.non_integer_rational(2, False))
    def testIntegerRational_distinctCount(self, generator):
        seen = set()
        for _ in range(3000):
            seen.add(generator())
        self.assertGreaterEqual(len(seen), 10**2)

    @parameterized.parameters(number.integer, number.non_integer_decimal)
    def testEntropyOfValue(self, generator):
        for entropy in [1, 2, 4, 8, 16]:
            sum_entropy = 0.0
            count = 2000
            for _ in range(count):
                value = generator(entropy, signed=True)
                sum_entropy += number.entropy_of_value(value)
            avg_entropy = sum_entropy / count
            error = abs(entropy - avg_entropy) / entropy
            self.assertLess(error, 0.2)
Пример #27
0
 def square_k():
   """Do sqrt(k * k * base)."""
   entropy_k = min(1, entropy)
   k = number.integer(entropy_k, signed=False, min_abs=2)
   return _sample_surd(
       k * k * base, entropy - entropy_k, max_power, multiples_only)
Пример #28
0
 def integers_close():
     entropy_diff, entropy_left = entropy * np.random.dirichlet([1, 3])
     left = number.integer(entropy_left, True)
     right = left + number.integer(entropy_diff, True)
     return left, right
 def gen(i, j):
     return number.integer(matrix_entropies[i, j], True)
Пример #30
0
def round_number(value, sample_args, context=None):
    """Question for rounding integers and decimals."""
    del value  # unused for now
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()

    # This is the power of 10 to round to. E.g., power == 0 corresponds to
    # rounding to the nearest integer; power == -2 corresponds to rounding to two
    # decimal places, and power == 3 corresponds to rounding to the nearest 1000.
    power = random.randint(-7, 6)

    answer_entropy = 1 + random.uniform(0, entropy / 2)
    entropy = max(1, entropy - answer_entropy)
    value_integer = number.integer(answer_entropy, signed=True)

    remainder_divisor = 10**int(math.ceil(entropy))
    remainder_range_lower = -remainder_divisor / 2
    remainder_range_upper = remainder_divisor / 2

    if value_integer <= 0:
        remainder_range_lower += 1
    if value_integer >= 0:
        remainder_range_upper -= 1

    remainder = random.randint(remainder_range_lower, remainder_range_upper)
    input_ = value_integer + sympy.Rational(remainder, remainder_divisor)
    scale = 10**power if power >= 0 else sympy.Rational(1, 10**(-power))
    input_ = input_ * scale
    value = value_integer * scale
    if not number.is_integer(input_):
        input_ = display.Decimal(input_)
    if not number.is_integer(value):
        value = display.Decimal(value)

    (input_, ) = context.sample(sample_args, [input_])
    des = False
    if power > 0:
        # Rounding to a power of ten.
        round_to = 10**power

        if round_to in [100, 1000]:
            if random.choice([False, True]):
                # Write the rounding value as a word instead.
                if round_to == 10:
                    des = True
                round_to = display.StringNumber(
                    round_to,
                    case='do',
                    desyatok=des,
                    join_number_words_with_hyphens=False,
                    singular=True)
            description = 'ближайшей {round_to}'.format(round_to=round_to)

        elif round_to in [1000000, 1000000000]:
            if random.choice([False, True]):
                # Write the rounding value as a word instead.
                if round_to == 10:
                    des = True
                round_to = display.StringNumber(
                    round_to,
                    case='do',
                    desyatok=des,
                    join_number_words_with_hyphens=False,
                    singular=True)
            description = 'ближайшего {round_to}'.format(round_to=round_to)

        else:
            if random.choice([False, True]):
                # Write the rounding value as a word instead.
                if round_to == 10:
                    des = True
                round_to = display.StringNumber(
                    round_to,
                    case='do',
                    desyatok=des,
                    join_number_words_with_hyphens=False)
            description = 'ближайших {round_to}'.format(round_to=round_to)

    elif power == 0 and random.choice([False, True]):
        # Round to nearest integer.
        description = 'ближайшего целого числа'
    else:
        # Round to decimal places.
        description = '{dps} знак{ending} после запятой'
        # if power == 1:
        #   # Plural
        #   description += 's'
        dps = -power

        ending = ['а', 'ов', "ов"][check_one_ending(dps)]

        if random.choice([False, True]):
            dps = display.StringNumber(dps, case='do')
        description = description.format(dps=dps, ending=ending)

    template = random.choice([
        'Округлите {input} до {description}.',
        'Сколько получится, если {input} округлить до {description}?',
    ])

    return example.Problem(question=example.question(context,
                                                     template,
                                                     input=input_,
                                                     description=description),
                           answer=value)