Beispiel #1
0
  def testAdd(self):
    add = ops.Add()
    self.assertEqual(str(add), '0')
    self.assertEqual(add.sympy(), 0)

    add = ops.Add(2, 3)
    self.assertEqual(str(add), '2 + 3')
    self.assertEqual(add.sympy(), 5)

    add = ops.Add(ops.Add(1, 2), 3)
    self.assertEqual(str(add), '1 + 2 + 3')
    self.assertEqual(add.sympy(), 6)
Beispiel #2
0
def _make_equals_zero_split(monomials):
    """Returns an `ops.Eq` containing sum of monomials split on left and right."""
    left = []
    right = []
    for monomial in monomials:
        if random.choice([False, True]):
            left.append(monomial)
        else:
            right.append(ops.Neg(monomial))
    if not left:
        left = [0]
    if not right:
        right = [0]
    left = ops.Add(*left)
    right = ops.Add(*right)
    return ops.Eq(left, right)
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)
Beispiel #4
0
  def testDescendants(self):
    constants = [ops.Constant(i) for i in range(6)]

    # (1 + 2*3**4) / 5 - 6
    expression = ops.Sub(
        ops.Div(
            ops.Add(
                constants[0],
                ops.Mul(
                    constants[1],
                    ops.Pow(
                        constants[2],
                        constants[3]))),
            constants[4]),
        constants[5])
    descendants = expression.descendants()
    descendants = ops._flatten(descendants)

    for constant in constants:
      self.assertIn(constant, descendants)
      self.assertEqual(descendants.count(constant), 1)

    # Also test top-level.
    self.assertEqual(constants[0].descendants(), [constants[0]])

    # Also general structure.
    constant = ops.Constant(3)
    expression = ops.Neg(constant)
    self.assertEqual(set(expression.descendants()), set([constant, expression]))
def _sample_with_brackets(depth, variables, degrees, entropy, length,
                          force_brackets=True):
  """Internal recursive function for: constructs a polynomial with brackets."""
  # To generate arbitrary polynomial recursively, can do one of:
  # *   add two polynomials, with at least one having brackets.
  # *   multiply two polynomials.
  # *   call `sample` (i.e., polynomial without brackets).

  if force_brackets:
    length = max(2, length)

  if not force_brackets and (random.choice([False, True]) or length < 2):
    return sample(variables, degrees, entropy, length)

  length_left = random.randint(1, length - 1)
  length_right = length - length_left
  entropy_left, entropy_right = entropy * np.random.dirichlet(
      [length_left, length_right])

  if random.choice([False, True]):
    # Add two. Force brackets on at least one of the polynomials, and sample
    # repeatedly until we don't get cancellation.
    while True:
      left = _sample_with_brackets(
          depth + 1, variables, degrees, entropy_left, length_left, True)
      right = _sample_with_brackets(
          depth + 1, variables, degrees, entropy_right, length_right, False)
      if random.choice([False, True]):
        left, right = right, left
      result = ops.Add(left, right)
      all_ok = True
      for variable, degree in zip(variables, degrees):
        if _degree_of_variable(result, variable) != degree:
          all_ok = False
          break
      if all_ok:
        return result
  else:
    # Multiply two.
    def sample_with_zero_check(degrees_, entropy_, length_):
      while True:
        result = _sample_with_brackets(
            depth + 1, variables, degrees_, entropy_, length_, False)
        if degrees_.sum() > 0 or not result.sympy().is_zero:
          return result
    degrees = np.asarray(degrees)

    def sample_degree(max_degree):
      """Select in range [0, max_degree], biased away from ends."""
      if max_degree <= 1 or random.choice([False, True]):
        return random.randint(0, max_degree)
      return random.randint(1, max_degree - 1)

    degrees_left = np.array([sample_degree(degree) for degree in degrees])
    degrees_right = degrees - degrees_left
    left = sample_with_zero_check(degrees_left, entropy_left, length_left)
    right = sample_with_zero_check(degrees_right, entropy_right, length_right)
    return ops.Mul(left, right)
 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)
def collect(value, sample_args, context=None):
    """Collect terms in an unsimplified polynomial."""
    is_question = context is None
    if context is None:
        context = composition.Context()

    entropy, sample_args = sample_args.peel()
    if value is None:
        entropy_value, entropy = entropy * np.random.dirichlet([2, 3])
        degrees = [random.randint(1, 3)]
        value = composition.Polynomial(
            polynomials.sample_coefficients(degrees, entropy_value))

    assert isinstance(value, composition.Polynomial)
    coefficients = value.coefficients

    all_coefficients_are_integer = True
    for coeff in coefficients.flat:
        if not number.is_integer(coeff):
            all_coefficients_are_integer = False
            break

    if all_coefficients_are_integer:
        coefficients = polynomials.expand_coefficients(coefficients, entropy)
    else:
        # put back the unused entropy
        sample_args = composition.SampleArgs(sample_args.num_modules,
                                             sample_args.entropy + entropy)

    num_variables = coefficients.ndim
    variables = [sympy.Symbol(context.pop()) for _ in range(num_variables)]
    unsimplified = polynomials.coefficients_to_polynomial(
        coefficients, variables)
    simplified = unsimplified.sympy().expand()

    # Bit of a hack: handle the very rare case where no number constants appearing
    if not ops.number_constants(unsimplified):
        unsimplified = ops.Add(unsimplified, ops.Constant(0))
    context.sample_by_replacing_constants(sample_args, unsimplified)

    if is_question:
        template = 'Sederhanakan {unsimplified}.'
        return example.Problem(question=example.question(
            context, template, unsimplified=unsimplified),
                               answer=simplified)
    else:
        function_symbol = context.pop()
        function = sympy.Function(function_symbol)(*variables)
        return composition.Entity(
            context=context,
            value=value,
            handle=composition.FunctionHandle(function_symbol),
            expression=unsimplified,
            polynomial_variables=variables,
            description='Misalkan {function} = {unsimplified}.',
            function=function,
            unsimplified=unsimplified)
def coefficients_to_polynomial(coefficients, variables):
  """Converts array of lists of coefficients to a polynomial."""
  coefficients = np.asarray(coefficients)
  shape = coefficients.shape

  indices = list(zip(*np.indices(shape).reshape([len(shape), -1])))
  monomials = []
  for power in indices:
    coeffs = coefficients.item(power)
    if (number.is_integer_or_rational(coeffs)
        or isinstance(coeffs, sympy.Symbol)):
      coeffs = [coeffs]
    elif not isinstance(coeffs, list):
      raise ValueError('Unrecognized coeffs={} type={}'
                       .format(coeffs, type(coeffs)))
    for coeff in coeffs:
      monomials.append(monomial(coeff, variables, power))
  random.shuffle(monomials)
  return ops.Add(*monomials)
Beispiel #9
0
  def testMul(self):
    mul = ops.Mul()
    self.assertEqual(str(mul), '1')
    self.assertEqual(mul.sympy(), 1)

    mul = ops.Mul(2, 3)
    self.assertEqual(str(mul), '2*3')
    self.assertEqual(mul.sympy(), 6)

    mul = ops.Mul(ops.Identity(ops.Constant(-2)), 3)
    self.assertEqual(str(mul), '-2*3')
    self.assertEqual(mul.sympy(), -6)

    mul = ops.Mul(ops.Add(1, 2), 3)
    self.assertEqual(str(mul), '(1 + 2)*3')
    self.assertEqual(mul.sympy(), 9)

    mul = ops.Mul(ops.Mul(2, 3), 5)
    self.assertEqual(str(mul), '2*3*5')
    self.assertEqual(mul.sympy(), 30)
Beispiel #10
0
  def testNeg(self):
    op = ops.Neg(2)
    self.assertEqual(str(op), '-2')
    self.assertEqual(op.sympy(), -2)

    op = ops.Add(ops.Neg(2), 3)
    self.assertEqual(str(op), '-2 + 3')
    self.assertEqual(op.sympy(), 1)

    op = ops.Add(3, ops.Neg(2))
    self.assertEqual(str(op), '3 - 2')
    self.assertEqual(op.sympy(), 1)

    op = ops.Add(ops.Add(ops.Neg(2), 5), 3)
    self.assertEqual(str(op), '-2 + 5 + 3')
    self.assertEqual(op.sympy(), 6)

    op = ops.Add(3, ops.Add(ops.Identity(ops.Neg(2)), 5))
    self.assertEqual(str(op), '3 - 2 + 5')
    self.assertEqual(op.sympy(), 6)

    op = ops.Add(3, ops.Add(2, ops.Neg(5)))
    self.assertEqual(str(op), '3 + 2 - 5')
    self.assertEqual(op.sympy(), 0)
Beispiel #11
0
 def testEq(self):
   op = ops.Eq(ops.Add(2, 3), 4)
   self.assertEqual(str(op), '2 + 3 = 4')
   self.assertEqual(op.sympy(), False)