コード例 #1
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
コード例 #2
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='Misalkan {self} be {composed}.',
                                  composed=composed)
コード例 #3
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
コード例 #4
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} (basis {from_base}) ke basis {to_base}',
        'Ubah {from_str} (basis {from_base}) menjadi basis {to_base}.',
        'Apa {from_str} (basis {from_base}) di basis {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))
コード例 #5
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)
コード例 #6
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)
コード例 #7
0
def _sample_roots(entropy):
    """Generates `num_distinct + num_repeated` polynomial roots."""
    num_roots = random.randint(2, 5)

    num_repeated = np.random.binomial(num_roots - 1,
                                      _POLY_PROBABILITY_REPEATED_ROOT)
    # Slight hack: don't allow all the roots to be repeated when the entropy is
    # high, as this can create very large coefficients.
    if entropy > 4:
        num_repeated = min(num_repeated, int(num_roots / 2))

    num_distinct = num_roots - num_repeated

    entropies = entropy * np.random.dirichlet(np.ones(num_distinct))

    roots = []

    for root_entropy in entropies:
        # Generates a root with small probability of being rational.
        # (Otherwise when we multiply out the denominators, we get really large
        # coefficients in our polynomial.)
        if random.random() < 0.1:
            root = number.non_integer_rational(root_entropy, True)
        else:
            root = number.integer(root_entropy, True)
        roots.append(root)

    for _ in range(num_repeated):
        roots.append(random.choice(roots[:num_distinct]))

    return roots
コード例 #8
0
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
コード例 #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(
            ['paling sedikit', 'paling rendah', 'paling kecil'])
        template = random.choice([
            'Hitung kelipatan persekutuan {adjective} dari {p} dan {q}.',
            'Berapa {adjective} kelipatan persekutuan dari {p} dan {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([
            'Berapa penyebut dari {p} dan {q}?',
            'Temukan penyebut yang sama dari {p} dan {q}.',
            'Hitung penyebut dari {p} dan {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 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(['least', 'lowest', 'smallest'])
        template = random.choice([
            'Calculate the {adjective} common multiple of {p} and {q}.',
            'What is the {adjective} common multiple of {p} and {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([
            'What is the common denominator of {p} and {q}?',
            'Find the common denominator of {p} and {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)
コード例 #13
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)
コード例 #14
0
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
コード例 #15
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
コード例 #16
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([
            'Hitung sisanya ketika {p} dibagi dengan {q}.',
            'Berapa sisa jika {p} dibagi dengan {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=
            'Biarkan {self} menjadi sisa saat {p} dibagi dengan {q}.',
            p=p,
            q=q)
コード例 #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 = 'In base {base}, what is {p} + {q}?'
  else:
    answer = p - q
    template = 'In base {base}, what is {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 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)
コード例 #19
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([
        'Divide {p} by {q}.',
        '{p} divided by {q}',
        'What is {p} divided by {q}?',
        'Calculate {p} divided by {q}.',
    ])
    return example.Problem(
        question=example.question(context, template, p=p, q=q),
        answer=answer
    )
  else:
    return composition.Entity(
        context=context,
        value=answer,
        description='Let {self} be {p} divided by {q}.',
        p=p, q=q)
コード例 #20
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 = [
        'Apakah {maybe_factor} merupakan faktor dari {value}?',
        'Apakah {value} adalah kelipatan dari {maybe_factor}?',
        'Apakah {maybe_factor} membagi {value}?',
    ]
    if maybe_factor == 2:
        templates += [
            'Apakah {value} genap?',
        ]
    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)
コード例 #21
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
コード例 #22
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?',
  ]

  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?',
    ]

  if one_over_exponent == 2:
    templates += [
        'What is the square root of {value} to the nearest integer?',
    ]
  elif one_over_exponent == 3:
    templates += [
        'What is the cube root of {value} to the nearest integer?',
    ]

  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)
コード例 #23
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(['greatest', 'highest']) + ' common ' +
                 random.choice(['divisor', 'factor']))

    if is_question:
        template = random.choice([
            'Calculate the {adjective} of {p} and {q}.',
            'What is the {adjective} of {p} and {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='Let {self} be the {adjective} of {p} and {q}.',
            adjective=adjective,
            p=p,
            q=q)
コード例 #24
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 = ['', 'puluh ', 'ratus ']
    seconds = [
        'ribu',
        'juta',
        'milyar',
        'triliun',
        'kuadriliun ',
        'kuintiliun',
        'sekstiliun',
        'septiliun',
        'oktilliun',
        'nonilliun',
        'desiliun',
    ]
    place_names = ['unit', 'ribuan', 'ratusan']
    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,
        'Berapa digit {place_name} dari {integer}?',
        place_name=place_name,
        integer=entity.expression_else_handle),
                           answer=answer)
コード例 #25
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(['pembagi persekutuan', 'faktor umum']) +
                 random.choice([' terbesar', ' tertinggi']))

    if is_question:
        template = random.choice([
            'Hitung {adjective} dari {p} dan {q}.',
            'Apa {adjective} dari {p} dan {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='Biarkan {self} menjadi {adjective} dari {p} dan {q}.',
            adjective=adjective,
            p=p,
            q=q)
コード例 #26
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([
        'Apa faktor prima dari {integer}?',
        'Sebutkan faktor prima dari {integer}.',
    ])
    return example.Problem(question=example.question(
        context, template, integer=entity.expression_else_handle),
                           answer=display.NumberList(prime_factors))
コード例 #27
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
コード例 #28
0
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
コード例 #29
0
 def gen(i, j):
     return number.integer(matrix_entropies[i, j], True)
コード例 #30
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