def compose(value, sample_args, context=None): """E.g., "Let f(x)=2x+1, let g(x)=3x+10. What is f(g(x))?".""" del value # unused if context is None: context = composition.Context() entropy, sample_args = sample_args.peel() entropy_f, entropy_g = entropy * np.random.dirichlet([1, 1]) coeffs_f = polynomials.sample_coefficients([random.randint(1, 2)], entropy_f) coeffs_g = polynomials.sample_coefficients([random.randint(1, 2)], entropy_g) entity_f, entity_g = context.sample( sample_args, [composition.Polynomial(coeffs_f), composition.Polynomial(coeffs_g)]) variable = sympy.var(context.pop()) poly_f = polynomials.coefficients_to_polynomial(coeffs_f, variable) poly_g = polynomials.coefficients_to_polynomial(coeffs_g, variable) poly_f_g = poly_f.sympy().subs(variable, poly_g.sympy()).expand() expression = composition.FunctionHandle(entity_f, entity_g).apply(variable) template = random.choice(_TEMPLATES) return example.Problem(question=example.question(context, template, composed=expression), answer=poly_f_g)
def coefficient_named(value, sample_args, context=None): """E.g., "Express x^2 + 2x in the form h * x^2 + k * x + t and give h.".""" del value # not used if context is None: context = composition.Context() variable = sympy.Symbol(context.pop()) entropy, sample_args = sample_args.peel() degree = random.randint(1, 4) if random.choice([False, True]): coefficients = polynomials.sample_coefficients( degree, entropy / 2, min_non_zero=random.randint(degree - 1, degree)) expanded = polynomials.expand_coefficients(coefficients, entropy / 2) expression = polynomials.coefficients_to_polynomial(expanded, variable) else: expression = polynomials.sample_with_brackets(variable, degree, entropy) coefficients = list(reversed(sympy.Poly(expression).all_coeffs())) named_coeffs = [sympy.Symbol(context.pop()) for _ in range(degree + 1)] canonical = polynomials.coefficients_to_polynomial(named_coeffs, variable) if random.random() < 0.2: # only small probability of non-zero power power = random.randint(0, degree) else: non_zero_powers = [ i for i in range(degree + 1) if coefficients[i] != 0 ] power = random.choice(non_zero_powers) value = coefficients[power] named_coeff = named_coeffs[power] template = random.choice([ 'Ekspresikan {expression} sebagai {canonical} dan berikan {target}. ' 'Atur ulang {expression} menjadi {canonical} dan berikan {target}.', 'Ekspresikan {expression} dalam bentuk {canonical} dan berikan {target}.', 'Atur ulang {expression} ke bentuk {canonical} dan berikan {target}.', ]) return example.Problem(question=example.question(context, template, expression=expression, canonical=canonical, target=named_coeff), answer=value)
def testPolynomialRoots(self): variable = sympy.Symbol('x') for _ in range(10): roots = random.sample(list(range(-9, 10)), 3) coeffs = algebra._polynomial_coeffs_with_roots(roots, scale_entropy=10.0) polynomial = polynomials.coefficients_to_polynomial(coeffs, variable) calc_roots = sympy.polys.polytools.real_roots(polynomial) self.assertEqual(calc_roots, sorted(roots))
def testUnivariate(self): # Test generation for: x**2 + 2*x + 1 x = sympy.Symbol('x') coeffs = [1, 2, 3] for _ in range(10): expanded = polynomials.expand_coefficients(coeffs, 5.0) polynomial = polynomials.coefficients_to_polynomial(expanded, [x]) sympified = sympy.sympify(polynomial) self.assertEqual(sympified, 1 + 2 * x + 3 * x * x)
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 testMultivariate(self): # Test generation for: x**2 + 2*x*y + 3*y**2 - x + 5 x, y = sympy.symbols('x y') coeffs = [[5, 0, 3], [-1, 2, 0], [1, 0, 0]] for _ in range(10): expanded = polynomials.expand_coefficients(coeffs, 5.0, length=10) polynomial = polynomials.coefficients_to_polynomial( expanded, [x, y]) sympified = sympy.sympify(polynomial) self.assertEqual(sympified, x * x + 2 * x * y + 3 * y * y - x + 5)
def _differentiate_polynomial(value, sample_args, context, num_variables): """Generates a question for differentiating a polynomial.""" is_question = context is None if context is None: context = composition.Context() if value is not None: num_variables = value.coefficients.ndim entropy, sample_args = sample_args.peel() max_derivative_order = 3 derivative_order = random.randint(1, max_derivative_order) entropy = max(0, entropy - math.log10(max_derivative_order)) derivative_axis = random.randint(0, num_variables - 1) if value is None: coefficients = _generate_polynomial( num_variables, entropy, derivative_order, derivative_axis) else: coefficients = _sample_integrand( value.coefficients, derivative_order, derivative_axis, entropy) (entity,) = context.sample( sample_args, [composition.Polynomial(coefficients)]) value = coefficients for _ in range(derivative_order): value = polynomials.differentiate(value, axis=derivative_axis) nth = display.StringOrdinal(derivative_order) if entity.has_expression(): polynomial = entity.expression variables = entity.polynomial_variables else: variables = [sympy.Symbol(context.pop()) for _ in range(num_variables)] polynomial = entity.handle.apply(*variables) variable = variables[derivative_axis] if is_question: template = _template(context.module_count, derivative_order, len(variables)) answer = polynomials.coefficients_to_polynomial(value, variables).sympy() return example.Problem( question=example.question( context, template, eq=polynomial, var=variable, nth=nth), answer=answer) else: fn_symbol = context.pop() variables_string = ', '.join(str(variable) for variable in variables) assert len(variables) == 1 # since below we don't specify var we diff wrt return composition.Entity( context=context, value=composition.Polynomial(value), description='Misalkan {fn} ({variables}) menjadi turunan ke-{nth} dari {eq}.', handle=composition.FunctionHandle(fn_symbol), fn=fn_symbol, variables=variables_string, nth=nth, eq=polynomial)
def add(value, sample_args, context=None): """E.g., "Let f(x)=2x+1, g(x)=3x+2. What is 5*f(x) - 7*g(x)?".""" is_question = context is None if context is None: context = composition.Context() entropy, sample_args = sample_args.peel() if value is None: max_degree = 3 degree = random.randint(1, max_degree) entropy -= math.log10(max_degree) entropy_value = entropy / 2 entropy -= entropy_value value = polynomials.sample_coefficients(degree, entropy=entropy_value, min_non_zero=random.randint( 1, 3)) value = composition.Polynomial(value) c1, c2, coeffs1, coeffs2 = polynomials.coefficients_linear_split( value.coefficients, entropy) coeffs1 = polynomials.trim(coeffs1) coeffs2 = polynomials.trim(coeffs2) c1, c2, fn1, fn2 = context.sample(sample_args, [ c1, c2, composition.Polynomial(coeffs1), composition.Polynomial(coeffs2) ]) var = sympy.var(context.pop()) expression = (c1.handle * fn1.handle.apply(var) + c2.handle * fn2.handle.apply(var)) if is_question: answer = polynomials.coefficients_to_polynomial( value.coefficients, var) answer = answer.sympy() template = random.choice(_TEMPLATES) return example.Problem(question=example.question(context, template, composed=expression), answer=answer) else: intermediate_symbol = context.pop() intermediate = sympy.Function(intermediate_symbol)(var) return composition.Entity( context=context, value=value, description='Misalkan {intermediate} = {composed}.', handle=composition.FunctionHandle(intermediate_symbol), intermediate=intermediate, composed=expression)
def _polynomial_entity(value, context): """Create a generic `Entity` describing a polynomial.""" assert isinstance(value, Polynomial) coefficients = np.asarray(value.coefficients) num_variables = coefficients.ndim variables = [sympy.Symbol(context.pop()) for _ in range(num_variables)] function_symbol = context.pop() handle = FunctionHandle(function_symbol) handle_description = sympy.Function(function_symbol)(*variables) polynomial = polynomials.coefficients_to_polynomial(coefficients, variables) polynomial = polynomial.sympy() return Entity( context=context, value=value, expression=polynomial, polynomial_variables=variables, description='Let {function} = {polynomial}.', handle=handle, function=handle_description, polynomial=polynomial)
def polynomial_roots(value, sample_args, context=None): """E.g., "Solve 2*x**2 - 18 = 0.".""" del value # not currently used # is_question = context is None if context is None: context = composition.Context() entropy, sample_args = sample_args.peel() scale_entropy = min(entropy / 2, 1) roots = _sample_roots(entropy - scale_entropy) solutions = sorted(list(sympy.FiniteSet(*roots))) coeffs = _polynomial_coeffs_with_roots(roots, scale_entropy) (polynomial_entity, ) = context.sample(sample_args, [composition.Polynomial(coeffs)]) if random.choice([False, True]): # Ask for explicit roots. if len(solutions) == 1: answer = solutions[0] else: answer = display.NumberList(solutions) if polynomial_entity.has_expression(): equality = ops.Eq(polynomial_entity.expression, 0) variable = polynomial_entity.polynomial_variables[0] else: variable = sympy.Symbol(context.pop()) equality = ops.Eq(polynomial_entity.handle.apply(variable), 0) template = random.choice([ 'Misalkan {equality}. Berapakah {variable}?', 'Misalkan {equality}. Hitung {variable}.', 'Misalkan {equality}. Berapakah {variable}?', 'Misalkan {equality}. Hitung {variable}.', 'Berapakah {variable} dalam {equality}?', 'Selesaikan {equality} untuk {variable}.', 'Temukan {variable} sehingga {equality}.', 'Temukan {variable}, mengingat {equality}.', 'Tentukan {variable} sehingga {equality}.', 'Tentukan {variable}, mengingat bahwa {equality}.', 'Selesaikan {equality}.' ]) return example.Problem(question=example.question(context, template, equality=equality, variable=variable), answer=answer) else: if polynomial_entity.has_expression(): expression = polynomial_entity.expression variable = polynomial_entity.polynomial_variables[0] else: variable = sympy.Symbol(context.pop()) expression = polynomial_entity.handle.apply(variable) factored = sympy.factor( polynomials.coefficients_to_polynomial(coeffs, variable)) template = random.choice([ 'Faktor dari {expression}.', ]) return example.Problem(question=example.question( context, template, expression=expression), answer=factored)
def testCoefficientsToPolynomial(self): coeffs = [3, 2, 1] x = sympy.Symbol('x') polynomial = polynomials.coefficients_to_polynomial(coeffs, [x]) polynomial = sympy.sympify(polynomial) self.assertEqual(polynomial, x * x + 2 * x + 3)