def __init__(self, numbers_to_use, **options): super().setup("minimal", **options) super().setup("numbers", nb=numbers_to_use, **options) super().setup("nb_variants", nb=numbers_to_use, **options) degrees1 = [0, 1] degrees2 = [0, 1] random.shuffle(degrees1) random.shuffle(degrees2) weighted_signs = [('+', 19), ('-', 1)] weighted_signs = [ val for val, cnt in weighted_signs for i in range(cnt) ] signs = ['+', '-'] self.expandable = Expandable( (Polynomial([ Monomial( (random.choice(weighted_signs), self.nb1, degrees1.pop())), Monomial((random.choice(signs), self.nb3, degrees1.pop())) ]), Polynomial([ Monomial((random.choice(weighted_signs), self.nb2, degrees2.pop())), Monomial((random.choice(signs), self.nb4, degrees2.pop())) ]))) self.expression = Expression(shared.number_of_the_question, self.expandable) self.expression_str = self.expression.printed shared.number_of_the_question += 1
def test_eq11_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('+', 5, 0)), Monomial( ('-', 1, 1))]), Polynomial([Monomial(('+', 5, 1))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[5-x=5x\]' '\[-x-5x=-5\]' '\[(-1-5)x=-5\]' '\[-6x=-5\]' '\[x=\\frac{-5}{-6}\]' '\[x=\\frac{5}{6}\]')
def test_eq8_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Polynomial([Monomial( ('+', 4, 1)), Monomial(('+', 2, 0))]), Polynomial([Monomial( ('-', 3, 0)), Monomial(('+', 2, 1))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[4x+2=-3+2x\]' '\[4x-2x=-3-2\]' '\[(4-2)x=-5\]' '\[2x=-5\]' '\[x=-\\frac{5}{2}\]')
def test_eq9_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Polynomial([Monomial( ('-', 2, 1)), Monomial(('+', 5, 0))]), Polynomial([Monomial( ('+', 3, 1)), Monomial(('-', 4, 0))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[-2x+5=3x-4\]' '\[-2x-3x=-4-5\]' '\[(-2-3)x=-9\]' '\[-5x=-9\]' '\[x=\\frac{-9}{-5}\]' '\[x=\\frac{9}{5}\]')
def test_eq13_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Polynomial([Monomial( ('+', 1, 1)), Monomial(('+', 5, 0))]), Polynomial([Monomial( ('+', 1, 1)), Monomial(('+', 2, 0))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[x+5=x+2\]' '\[x-x=2-5\]' '\[(1-1)x=-3\]' '\[0x=-3\]' '\[0=-3\]' 'This equation has no solution.' '\\newline ')
def expI(): t = Sum([Monomial(('+', 4, 1)), Expandable((Monomial(('+', 1, 0)), Polynomial([Monomial(('-', 15, 1)), Monomial(('+', 8, 0)), Monomial(('-', 5, 1))])))]) return Expression("I", t)
def test_eq10_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Polynomial([Monomial( ('+', 5, 0)), Monomial(('+', 4, 1))]), Polynomial([Monomial( ('-', 20, 1)), Monomial(('+', 3, 0))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[5+4x=-20x+3\]' '\[4x+20x=3-5\]' '\[(4+20)x=-2\]' '\[24x=-2\]' '\[x=-\\frac{2}{24}\]' '\[x=-\\frac{\\bcancel{2}}' '{\\bcancel{2}\\times 12}\]' '\[x=-\\frac{1}{12}\]')
def rubbish_polynomial(): return Polynomial([ Monomial(('+', 1, 2)), Monomial(('+', 7, 1)), Monomial(('-', 10, 2)), Monomial(('-', 9, 1)), Monomial(('+', 9, 2)) ])
def test_complicated_sum_02(): """Is this Sum correctly printed as (6+x)^{2}+12(2+11x)?""" assert Sum([ BinomialIdentity((Monomial(('+', 6, 0)), Monomial(('+', 1, 1)))), Expandable( (Monomial(('+', 12, 0)), Sum([Polynomial([Monomial(('+', 2, 0)), Monomial(('+', 11, 1))])]))) ]).printed == wrap_nb('(6+x)^{2}+12(2+11x)')
def test_eq0_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('+', 1, 1)), Monomial(('+', 7, 0))]), Item(3)), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[x+7=3\]' '\[x=3-7\]' '\[x=-4\]')
def test_eq1_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('-', 8, 0)), Monomial(('+', 1, 1))]), Item(-2)), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[-8+x=-2\]' '\[x=-2+8\]' '\[x=6\]')
def test_eq2_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Item(-5), Polynomial([Monomial( ('+', 1, 1)), Monomial(('+', 3, 0))])), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[-5=x+3\]' '\[x=-5-3\]' '\[x=-8\]')
def test_eq6_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('+', 2, 1)), Monomial(('+', 3, 0))]), Item(8)), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[2x+3=8\]' '\[2x=8-3\]' '\[2x=5\]' '\[x=\\frac{5}{2}\]')
def test_eq7_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('+', 19, 0)), Monomial(('+', 3, 1))]), Monomial(('+', 2, 1))), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[19+3x=2x\]' '\[3x-2x=-19\]' '\[(3-2)x=-19\]' '\[x=-19\]')
def test_eq12_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Polynomial([Monomial( ('+', 2, 1)), Monomial(('+', 1, 0))]), Item(1)), number=1) assert eq.auto_resolution() == wrap_nb('$(\\text{E}_{1}): $' '\[2x+1=1\]' '\[2x=1-1\]' '\[2x=0\]' '\[x=0\]')
def level_02(q_subkind, **options): max_coeff = 20 if 'max_coeff' in options and is_.an_integer(options['max_coeff']): max_coeff = options['max_coeff'] attribute_a_minus_sign = 'randomly' if 'minus_sign' in options and options['minus_sign']: attribute_a_minus_sign = 'yes' elif 'minus_sign' in options and not options['minus_sign']: attribute_a_minus_sign = 'no' # Creation of the objects # The three Monomials: ax², bx and c # Maybe we don't need to keep the integer values... a_val = randomly.integer(1, max_coeff) b_val = randomly.integer(1, max_coeff) c_val = randomly.integer(1, max_coeff) if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1', 'type_1_C1' ]: # __ c_val = randomly.integer(2, max_coeff) ax2 = Monomial((randomly.sign(), a_val, 2)) bx = Monomial((randomly.sign(), b_val, 1)) c = Monomial((randomly.sign(), c_val, 0)) # deg1: mx + p # and we need two of them deg1 = [] for i in range(2): deg1_mx = Monomial((randomly.sign(), randomly.integer(1, max_coeff), 1)) deg1_p = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_A1', 'type_1_B1', 'type_1_D1', 'type_1_E1', 'type_1_G1', 'type_1_H1', 'type_4_A0' ]: # __ deg1_p = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 0)) else: deg1_p = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) if not deg1_p.is_null(): lil_box = [deg1_mx, deg1_p] deg1.append( Polynomial([randomly.pop(lil_box), randomly.pop(lil_box)])) else: deg1.append(deg1_mx) # deg2: mx² + px + r # and we also need two of them deg2 = [] for i in range(2): deg2_mx2 = Monomial((randomly.sign(), randomly.integer(1, max_coeff), 2)) deg2_px = None deg2_r = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_A1', 'type_1_B1', 'type_1_D1', 'type_1_E1', 'type_1_G1', 'type_1_H1' ]: # __ if randomly.heads_or_tails(): deg2_px = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) else: deg2_px = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 0)) else: deg2_px = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) lil_box = [deg2_mx2] if not deg2_px.is_null(): lil_box.append(deg2_px) if not deg2_r.is_null(): lil_box.append(deg2_r) monomials_list_for_deg2 = [] for i in range(len(lil_box)): monomials_list_for_deg2.append(randomly.pop(lil_box)) deg2.append(Polynomial(monomials_list_for_deg2)) # Let's attribute the common factor C according to the required type # (NB: expression ± C×F1 ± C×F2) C = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1' ]: # __ C = c elif q_subkind in [ 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_D1', 'type_1_E1' ]: # __ C = bx elif q_subkind in [ 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_G1', 'type_1_H1' ]: # __ C = ax2 elif q_subkind in [ 'type_2_A0', 'type_2_B0', 'type_2_C0', 'type_2_A1', 'type_2_B1', 'type_4_A0' ]: # __ C = Polynomial([bx, c]) elif q_subkind in [ 'type_2_D0', 'type_2_E0', 'type_2_F0', 'type_2_D1', 'type_2_E1' ]: # __ C = Polynomial([ax2, c]) elif q_subkind in [ 'type_3_A0', 'type_3_B0', 'type_3_C0', 'type_3_A1', 'type_3_B1' ]: # __ C = Polynomial([ax2, bx, c]) # Let's attribute F1 and F2 according to the required type # (NB: expression ± C×F1 ± C×F2) F1 = None F2 = None if q_subkind in [ 'type_1_A0', 'type_1_A1', 'type_1_D0', 'type_1_D1', 'type_1_G0', 'type_1_G1', 'type_2_A0', 'type_2_A1', 'type_2_D0', 'type_2_D1', 'type_3_A0', 'type_3_A1' ]: # __ F1 = deg1[0] F2 = deg1[1] elif q_subkind in [ 'type_1_B0', 'type_1_B1', 'type_1_E0', 'type_1_E1', 'type_1_H0', 'type_1_H1', 'type_2_B0', 'type_2_B1', 'type_2_E0', 'type_2_E1', 'type_3_B0', 'type_3_B1' ]: # __ F1 = deg2[0] F2 = deg2[1] elif q_subkind in [ 'type_1_C0', 'type_1_F0', 'type_1_I0', 'type_2_C0', 'type_2_F0', 'type_3_C0' ]: # __ F1 = deg1[0] F2 = deg2[0] # The special case type_4_A0: (ax+b)² + (ax+b)×deg1' # aka C² + C×F1 elif q_subkind == 'type_4_A0': F1 = C.clone() F2 = deg1[0] # Let's put a "1" somewhere in the type_*_*1 if q_subkind in [ 'type_1_A1', 'type_1_D1', 'type_1_G1', 'type_2_A1', 'type_2_D1', 'type_3_A1', 'type_1_B1', 'type_1_E1' 'type_1_H1', 'type_2_B1', 'type_2_E1', 'type_3_B1' ]: # __ if randomly.heads_or_tails(): F1 = Item(1) else: F2 = Item(1) # Let's possibly attribute a minus_sign # (NB: expression ± C×F1 ± C×F2) minus_sign = None # this will contain the name of the factor having # a supplementary minus sign in such cases: # C×F1 - C×F2# - C×F1 + C×F2 # in all the following cases, it doesn't bring anything to attribute # a minus sign if ((q_subkind in ['type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1'] and c_val < 0) or ((q_subkind in ['type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_D1', 'type_1_E1']) and b_val < 0) or ((q_subkind in ['type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_G1', 'type_1_H1']) and a_val < 0)): # __ pass # here we let minus_sign equal to None # otherwise, let's attribute one randomly, # depending on attribute_a_minus_sign else: if attribute_a_minus_sign in ['yes', 'randomly']: # __ if (attribute_a_minus_sign == 'yes' or randomly.heads_or_tails()): # __ if randomly.heads_or_tails(): minus_sign = "F1" else: minus_sign = "F2" else: pass # here we let minus_sign equal to None # Now let's build the expression ! expression = None box_product1 = [C, F1] box_product2 = [C, F2] if q_subkind == 'type_4_A0': CF1 = Product([C]) CF1.set_exponent(Value(2)) else: CF1 = Product([randomly.pop(box_product1), randomly.pop(box_product1)]) CF2 = Product([randomly.pop(box_product2), randomly.pop(box_product2)]) if minus_sign == "F1": if len(F1) >= 2: CF1 = Expandable((Item(-1), CF1)) else: CF1 = Product([Item(-1), CF1]) elif minus_sign == "F2": if len(F2) >= 2: CF2 = Expandable((Item(-1), CF2)) else: CF2 = Product([Item(-1), CF2]) expression = Sum([CF1, CF2]) # Now let's build the factorization steps ! steps = [] steps.append(expression) F1F2_sum = None if minus_sign is None: F1F2_sum = Sum([F1, F2]) elif minus_sign == "F1": if len(F1) >= 2: F1F2_sum = Sum([Expandable((Item(-1), F1)), F2]) else: F1F2_sum = Sum([Product([Item(-1), F1]), F2]) elif minus_sign == "F2": if len(F2) >= 2: F1F2_sum = Sum([F1, Expandable((Item(-1), F2))]) else: F1F2_sum = Sum([F1, Product([Item(-1), F2])]) temp = Product([C, F1F2_sum]) temp.set_compact_display(False) steps.append(temp) F1F2_sum = F1F2_sum.expand_and_reduce_next_step() while F1F2_sum is not None: steps.append(Product([C, F1F2_sum])) F1F2_sum = F1F2_sum.expand_and_reduce_next_step() # This doesn't fit the need, because too much Products are # wrongly recognized as reducible ! if steps[len(steps) - 1].is_reducible(): steps.append(steps[len(steps) - 1].reduce_()) return steps
def level_03(q_subkind, **options): a = randomly.integer(1, 10) b = randomly.integer(1, 10) steps = [] if q_subkind in [ 'sum_square', 'sum_square_mixed', 'difference_square', 'difference_square_mixed' ]: # __ first_term = Monomial(('+', Item(('+', a, 2)).evaluate(), 2)) second_term = Monomial( ('+', Item(('+', Product([2, a, b]).evaluate(), 1)).evaluate(), 1)) third_term = Monomial(('+', Item(('+', b, 2)).evaluate(), 0)) if q_subkind in ['difference_square', 'difference_square_mixed']: second_term.set_sign('-') if q_subkind in ['sum_square_mixed', 'difference_square_mixed']: ordered_expression = Polynomial( [first_term, second_term, third_term]) [first_term, second_term, third_term] = randomly.mix([first_term, second_term, third_term]) steps.append(Polynomial([first_term, second_term, third_term])) if q_subkind in ['sum_square_mixed', 'difference_square_mixed']: steps.append(ordered_expression) sq_a_monom = Monomial(('+', a, 1)) sq_b_monom = Monomial(('+', b, 0)) let_a_eq = Equality([Item('a'), sq_a_monom]) let_b_eq = Equality([Item('b'), sq_b_monom]) steps.append( _("Let") + " " + let_a_eq.into_str(force_expression_markers=True) + " " + _("and") + " " + let_b_eq.into_str(force_expression_markers=True)) sq_a_monom.set_exponent(2) sq_b_monom.set_exponent(2) a_square_eq = Equality( [Item(('+', 'a', 2)), sq_a_monom, sq_a_monom.reduce_()]) b_square_eq = Equality( [Item(('+', 'b', 2)), sq_b_monom, sq_b_monom.reduce_()]) steps.append( _("then") + " " + a_square_eq.into_str(force_expression_markers=True)) steps.append( _("and") + " " + b_square_eq.into_str(force_expression_markers=True)) two_times_a_times_b_numeric = Product( [Item(2), Monomial(('+', a, 1)), Item(b)]) two_times_a_times_b_reduced = two_times_a_times_b_numeric.reduce_() two_times_a_times_b_eq = Equality([ Product([Item(2), Item('a'), Item('b')]), two_times_a_times_b_numeric, two_times_a_times_b_reduced ]) steps.append( _("and") + " " + two_times_a_times_b_eq.into_str(force_expression_markers=True)) steps.append(_("So it is possible to factorize:")) if q_subkind in ['difference_square', 'difference_square_mixed']: b = -b factorized_expression = Sum([Monomial(('+', a, 1)), Item(b)]) factorized_expression.set_exponent(2) steps.append(factorized_expression) elif q_subkind in ['squares_difference', 'squares_difference_mixed']: # To have some (ax)² - b² but also sometimes b² - (ax)²: degrees = [2, 0, 1, 0] if randomly.integer(1, 10) >= 8: degrees = [0, 2, 0, 1] first_term = Monomial(('+', Item(('+', a, 2)).evaluate(), degrees[0])) second_term = Monomial(('-', Item(('+', b, 2)).evaluate(), degrees[1])) sq_first_term = Monomial(('+', Item( ('+', a, 1)).evaluate(), degrees[2])) sq_second_term = Monomial(('-', Item( ('+', b, 1)).evaluate(), degrees[3])) # The 'mixed' cases are: -b² + (ax)² and -(ax)² + b² if q_subkind == 'squares_difference_mixed': [first_term, second_term] = randomly.mix([first_term, second_term]) [sq_first_term, sq_second_term] = randomly.mix([sq_first_term, sq_second_term]) positive_sq_first = sq_first_term.clone() positive_sq_first.set_sign('+') positive_sq_second = sq_second_term.clone() positive_sq_second.set_sign('+') steps.append(Polynomial([first_term, second_term])) first_inter = None second_inter = None if sq_second_term.is_negative(): first_inter = positive_sq_first.clone() first_inter.set_exponent(2) temp_second_inter = positive_sq_second.clone() temp_second_inter.set_exponent(2) second_inter = Product([-1, temp_second_inter]) else: temp_first_inter = positive_sq_first.clone() temp_first_inter.set_exponent(2) first_inter = Product([-1, temp_first_inter]) second_inter = positive_sq_second.clone() second_inter.set_exponent(2) steps.append(Sum([first_inter, second_inter])) if q_subkind == 'squares_difference_mixed': steps.append(Sum([second_inter, first_inter])) steps.append(_("So, this expression can be factorized:")) sum1 = None sum2 = None if sq_second_term.is_negative(): sum1 = Sum([sq_first_term, sq_second_term]) sq_second_term.set_sign('+') sum2 = Sum([sq_first_term, sq_second_term]) else: sum1 = Sum([sq_second_term, sq_first_term]) sq_first_term.set_sign('+') sum2 = Sum([sq_second_term, sq_first_term]) lil_box = [sum1, sum2] steps.append(Product([randomly.pop(lil_box), randomly.pop(lil_box)])) elif q_subkind in [ 'fake_01', 'fake_01_mixed', 'fake_02', 'fake_02_mixed', 'fake_03', 'fake_03_mixed', 'fake_04_A', 'fake_04_A_mixed', 'fake_04_B', 'fake_04_B_mixed', 'fake_04_C', 'fake_04_C_mixed', 'fake_04_D', 'fake_04_D_mixed' ]: # __ straight_cases = [ 'fake_01', 'fake_02', 'fake_03', 'fake_04_A', 'fake_04_B', 'fake_04_C', 'fake_04_D' ] match_pb_cases = [ 'fake_01', 'fake_02', 'fake_01_mixed', 'fake_02_mixed' ] sign_pb_cases = [ 'fake_03', 'fake_03_mixed', 'fake_04_A', 'fake_04_B', 'fake_04_C', 'fake_04_D', 'fake_04_A_mixed', 'fake_04_B_mixed', 'fake_04_C_mixed', 'fake_04_D_mixed' ] ax = Monomial(('+', a, 1)) b_ = Monomial(('+', b, 0)) ax_2 = ax.clone() ax_2.set_exponent(2) a2x2 = Monomial(('+', a * a, 2)) b_2 = Monomial(('+', b, 0)) b_2.set_exponent(2) b2 = Monomial(('+', b * b, 0)) two_ax_b = Product([Item(2), Monomial(('+', a, 1)), Item(b)]) twoabx = Monomial(('+', 2 * a * b, 1)) fake_twoabx = Monomial(('+', a * b, 1)) if randomly.integer(1, 10) >= 8: fake_twoabx = Monomial( ('+', 2 * a * b + randomly.pop([-1, 1]) * randomly.integer(1, 5), 1)) first_term = None second_term = None third_term = None ordered_expression = None mixed_expression = None if q_subkind == 'fake_03' or q_subkind == 'fake_03_mixed': first_term = a2x2.clone() second_term = b2.clone() ordered_expression = Polynomial([first_term, second_term]) mixed_expression = Polynomial([second_term, first_term]) else: first_term = a2x2.clone() third_term = b2.clone() if q_subkind in [ 'fake_01', 'fake_01_mixed', 'fake_02', 'fake_02_mixed' ]: # __ second_term = fake_twoabx.clone() else: second_term = twoabx.clone() if q_subkind == 'fake_02' or q_subkind == 'fake_02_mixed': second_term.set_sign('-') elif q_subkind == 'fake_04_A' or q_subkind == 'fake_04_A_mixed': third_term.set_sign('-') elif q_subkind == 'fake_04_B' or q_subkind == 'fake_04_B_mixed': first_term.set_sign('-') elif q_subkind == 'fake_04_C' or q_subkind == 'fake_04_C_mixed': second_term.set_sign('-') third_term.set_sign('-') elif q_subkind == 'fake_04_D' or q_subkind == 'fake_04_D_mixed': first_term.set_sign('-') second_term.set_sign('-') ordered_expression = Polynomial( [first_term, second_term, third_term]) mixed_expression = Polynomial( randomly.mix([first_term, second_term, third_term])) if q_subkind in straight_cases: steps.append(ordered_expression) elif q_subkind == 'fake_03_mixed': steps.append(mixed_expression) else: steps.append(mixed_expression) steps.append(ordered_expression) if q_subkind in match_pb_cases: let_a_eq = Equality([Item('a'), ax]) let_b_eq = Equality([Item('b'), b_]) steps.append( _("Let") + " " + let_a_eq.into_str(force_expression_markers=True) + " " + _("and") + " " + let_b_eq.into_str(force_expression_markers=True)) a_square_eq = Equality([Item(('+', 'a', 2)), ax_2, a2x2]) b_square_eq = Equality([Item(('+', 'b', 2)), b_2, b2]) steps.append( _("then") + " " + a_square_eq.into_str(force_expression_markers=True)) steps.append( _("and") + " " + b_square_eq.into_str(force_expression_markers=True)) two_times_a_times_b_eq = Equality([ Product([Item(2), Item('a'), Item('b')]), two_ax_b, twoabx, fake_twoabx ], equal_signs=['=', '=', 'neq']) steps.append( _("but") + " " + two_times_a_times_b_eq.into_str(force_expression_markers=True)) steps.append(_("So it does not match a binomial identity.")) steps.append(_("This expression cannot be factorized.")) elif q_subkind in sign_pb_cases: steps.append(_("Because of the signs,")) steps.append(_("it does not match a binomial identity.")) steps.append(_("This expression cannot be factorized.")) return steps
def test_complicated_sum_01(): """Is this Sum correctly printed as 2-10x^{2}+9?""" assert Sum([Item(2), Product([Polynomial([Monomial(('-', 10, 2)), Monomial(('+', 9, 0))])])]).printed == \ wrap_nb('2-10x^{2}+9')
def __init__(self, q_kind='default_nothing', **options): self.derived = True # The call to the mother class __init__() method will set the # fields matching optional arguments which are so far: # self.q_kind, self.q_subkind # plus self.options (modified) Q_Structure.__init__(self, q_kind, AVAILABLE_Q_KIND_VALUES, **options) # The purpose of this next line is to get the possibly modified # value of **options options = self.options MAX_COEFF = MAX_COEFF_TABLE[q_kind] MAX_EXPONENT = MAX_EXPONENT_TABLE[q_kind] DEFAULT_MINIMUM_LENGTH = DEFAULT_MINIMUM_LENGTH_TABLE[q_kind] DEFAULT_MAXIMUM_LENGTH = DEFAULT_MAXIMUM_LENGTH_TABLE[q_kind] # This field is to be used in the answer_to_strs() method # to determine a possibly different algorithm for particular cases self.kind_of_answer = "" # Max coefficient & degree values... max_coeff = MAX_COEFF max_expon = MAX_EXPONENT if 'max_coeff' in options and options['max_coeff'] >= 1: max_coeff = options['max_coeff'] if 'max_expon' in options and options['max_expon'] >= 1: max_expon = options['max_expon'] length = randomly.integer(DEFAULT_MINIMUM_LENGTH, DEFAULT_MAXIMUM_LENGTH, weighted_table=[0.15, 0.25, 0.6]) if ('length' in options and is_.an_integer(options['length']) and options['length'] >= 2): # __ length = options['length'] # 1st CASE: # PRODUCT REDUCTION if q_kind == 'product': # First let's determine a pack of letters where to draw # The default one will be [a, b, c, x, y, z] # but the reduced or entire alphabets can be used as well letters_package = alphabet.abc + alphabet.xyz if 'short_test' in options and options['short_test']: # __ self.objct = Product( [Monomial((RANDOMLY, 12, 1)), Monomial((RANDOMLY, 12, 1))]) self.objct.factor[0].set_degree(1) self.objct.factor[1].set_degree(1) else: # In the case of an exercise about reducing products # in a training sheet, the answers will be more detailed self.kind_of_answer = 'product_detailed' if 'use_reduced_alphabet' in options: letters_package = alphabet.reduced elif 'use_the_entire_alphabet' in options: letters_package = alphabet.lowercase elif 'use_these_letters' in options \ and is_.a_string_list(options['use_these_letters']): # __ letters_package = options['use_these_letters'] # Maximum Items number. (We make sure at the same time that # we won't # risk to draw a greater number of letters than the available # letters # in letters_package) max_literal_items_nb = min(PR_MAX_LITERAL_ITEMS_NB, len(letters_package)) if ('max_literal_items_nb' in options and 2 <= options['max_literal_items_nb'] <= 6): # __ max_literal_items_nb = min(options['max_literal_items_nb'], len(letters_package)) # Maximum number of occurences of the same letter in # the initial expression same_letter_max_occurences = PR_SAME_LETTER_MAX_OCCURENCES_NB if ('nb_occurences_of_the_same_letter' in options and options['nb_occurences_of_the_same_letter'] >= 1): # __ same_letter_max_occurences = options['nb_occurences_of' '_the_same_letter'] # CREATION OF THE EXPRESSION # We draw randomly the letters that will appear # in the expression current_letters_package = list(letters_package) nb_of_letters_to_draw = randomly.integer( 1, max_literal_items_nb) drawn_letters = list() for j in range(nb_of_letters_to_draw): drawn_letters.append(randomly.pop(current_letters_package)) # Let's determine how many times will appear each letter # and then create a list containing each of these letters # the number of times they will appear pre_items_list = list() items_list = list() for j in range(len(drawn_letters)): if j == 0: # We make sure that at least one letter occurs twice # so that the exercise remains interesting ! # But the number of cases this letter occurs 3 three # times should be limited to keep sufficient # simple cases for the pupils to begin with. # It is really easy to make it much more complicated # simply giving: # nb_occurences_of_the_same_letter=<enough_high_nb> # as an argument. if randomly.decimal_0_1() < 0.5: occurences_nb = 2 else: occurences_nb = randomly\ .integer(2, same_letter_max_occurences) else: occurences_nb = randomly\ .integer(1, same_letter_max_occurences) if occurences_nb >= 1: for k in range(occurences_nb): pre_items_list.append(drawn_letters[j]) # draw the number of numeric Items nb_item_num = randomly.integer(1, PR_NUMERIC_ITEMS_MAX_NB) # put them in the pre items' list for j in range(nb_item_num): pre_items_list.append(NUMERIC) # prepare the items' list that will be given to the Product's # constructor loop_nb = len(pre_items_list) for j in range(loop_nb): next_item_kind = randomly.pop(pre_items_list) # It's not really useful nor really possible to limit the # number # of occurences of the same letter being drawn twice in # a row because it belongs to the exercise and there # are many cases when # the same letter is in the list in 3 over 4 elements. # if j >= 1 and next_item_kind == items_list[j - 1] # .raw_value: # pre_items_list.append(next_item_kind) # next_item_kind = randomly.pop(pre_items_list) if next_item_kind == NUMERIC: temp_item = Item((randomly.sign(plus_signs_ratio=0.75), randomly.integer(1, max_coeff), 1)) items_list.append(temp_item) else: item_value = next_item_kind temp_item = Item( (randomly.sign(plus_signs_ratio=0.9), item_value, randomly.integer(1, max_expon))) items_list.append(temp_item) # so now that the items_list is complete, # let's build the Product ! self.objct = Product(items_list) self.objct.set_compact_display(False) # Let's take some × symbols off the Product to match a more # usual situation for i in range(len(self.objct) - 1): if ((self.objct.factor[i].is_numeric() and self.objct.factor[i + 1].is_literal()) or (self.objct.factor[i].is_literal() and self.objct.factor[i + 1].is_literal() and self.objct.factor[i].raw_value != self.objct.factor[i + 1].raw_value and randomly.decimal_0_1() > 0.5)): # __ self.objct.info[i] = False # 2d CASE: # SUM OF PRODUCTS REDUCTION if q_kind == 'sum_of_products': if (not ('length' in options and is_.an_integer(options['length']) and options['length'] >= 2)): # __ length = randomly.integer(DEFAULT_MINIMUM_LENGTH, DEFAULT_MAXIMUM_LENGTH, weighted_table=[0.15, 0.25, 0.6]) # Creation of the list to give later to the Sum constructor products_list = list() for i in range(length): monomial1 = Monomial((RANDOMLY, max_coeff, max_expon)) monomial2 = Monomial((RANDOMLY, max_coeff, max_expon)) products_list.append(Product([monomial1, monomial2])) # Creation of the Sum self.objct = Sum(products_list) # 3d CASE: # SUM REDUCTION if q_kind == 'sum': self.kind_of_answer = 'sum' # Let's determine the length of the Sum to create if not ('length' in options and is_.an_integer(options['length']) and options['length'] >= 1): # __ length = randomly\ .integer(DEFAULT_MINIMUM_LENGTH, DEFAULT_MAXIMUM_LENGTH, weighted_table=[0.1, 0.25, 0.5, 0.1, 0.05]) else: length = options['length'] # Creation of the Polynomial... if 'short_test' in options: self.objct = Polynomial((RANDOMLY, max_coeff, 2, length - 1)) temp_sum = self.objct.term degree_1_monomial_here = False for i in range(len(temp_sum)): if temp_sum[i].degree == 1: degree_1_monomial_here = True if degree_1_monomial_here == 1: temp_sum.append(Monomial((randomly.sign(), 1, 1))) else: # this should be 2d deg Polynomial w/out any 1st deg term temp_sum.append(Monomial((randomly.sign(), 1, 2))) self.objct.reset_element() for i in range(length): self.objct.term.append(randomly.pop(temp_sum)) self.objct.info.append(False) else: self.objct = Polynomial( (RANDOMLY, max_coeff, max_expon, length)) if q_kind == 'long_sum': m = [] for i in range(length): m.append(Monomial(RANDOMLY, max_coeff, max_expon)) self.objct = Polynomial(m) if q_kind == 'long_sum_including_a_coeff_1': m = [] for i in range(length - 1): m.append(Monomial(RANDOMLY, max_coeff, max_expon)) m.append(Monomial(RANDOMLY, 1, max_expon)) terms_list = [] for i in range(len(m)): terms_list.append(randomly.pop(m)) self.objct = Polynomial(terms_list) if q_kind == 'sum_not_reducible': self.kind_of_answer = 'sum_not_reducible' m1 = Monomial((RANDOMLY, max_coeff, 0)) m2 = Monomial((RANDOMLY, max_coeff, 1)) m3 = Monomial((RANDOMLY, max_coeff, 2)) lil_box = [m1, m2, m3] self.objct = Polynomial([randomly.pop(lil_box)]) for i in range(len(lil_box) - 1): self.objct.append(randomly.pop(lil_box)) if q_kind == 'sum_with_minus-brackets': minus_brackets = [] for i in range(3): minus_brackets.append( Expandable((Monomial(('-', 1, 0)), Polynomial( (RANDOMLY, 15, 2, randomly.integer(2, 3)))))) m1 = Monomial((RANDOMLY, max_coeff, 0)) m2 = Monomial((RANDOMLY, max_coeff, 1)) m3 = Monomial((RANDOMLY, max_coeff, 2)) m4 = Monomial((RANDOMLY, max_coeff, randomly.integer(0, 2))) lil_box = [m1, m2, m3, m4] plus_brackets = [] for i in range(3): plus_brackets.append( Expandable((Monomial(('+', 1, 0)), Polynomial( (RANDOMLY, 15, 2, randomly.integer(2, 3)))))) big_box = [] big_box.append(minus_brackets[0]) if ('minus_brackets_nb' in options and 2 <= options['minus_brackets_nb'] <= 3): # __ big_box.append(minus_brackets[1]) if options['minus_brackets_nb'] == 3: big_box.append(minus_brackets[2]) for i in range(randomly.integer(1, 4)): big_box.append(randomly.pop(lil_box)) if ('plus_brackets_nb' in options and 1 <= options['plus_brackets_nb'] <= 3): # __ for i in range(options['plus_brackets_nb']): big_box.append(plus_brackets[i]) final_terms = [] for i in range(len(big_box)): final_terms.append(randomly.pop(big_box)) self.objct = Sum(final_terms) # Creation of the expression: number = 0 if ('expression_number' in options and is_.a_natural_int(options['expression_number'])): # __ number = options['expression_number'] self.expression = Expression(number, self.objct)
def __init__(self, q_kind='default_nothing', **options): self.derived = True # The call to the mother class __init__() method will set the # fields matching optional arguments which are so far: # self.q_kind, self.q_subkind # plus self.options (modified) Q_Structure.__init__(self, q_kind, AVAILABLE_Q_KIND_VALUES, **options) # The purpose of this next line is to get the possibly modified # value of **options options = self.options init_caller = INIT_CALLER[q_kind] self.expandable_objct = None self.numeric_aux = None if q_kind == 'any_basic_expd': randomly_drawn = randomly.decimal_0_1() if randomly_drawn <= 0.25: self.expandable_objct = Expandable((RANDOMLY, 'monom0_polyn1'), randomly_reversed=0.5) elif randomly_drawn <= 0.50: self.expandable_objct = Expandable((RANDOMLY, 'monom1_polyn1'), randomly_reversed=0.5) else: self.expandable_objct = Expandable((RANDOMLY, 'polyn1_polyn1')) elif q_kind in ['monom0_polyn1', 'monom1_polyn1']: self.expandable_objct = Expandable((RANDOMLY, q_kind), randomly_reversed=0.5) elif q_kind == 'monom01_polyn1': self.expandable_objct = Expandable( (RANDOMLY, randomly.pop(['monom0_polyn1', 'monom1_polyn1'])), randomly_reversed=0.5) elif q_kind == 'polyn1_polyn1': self.expandable_objct = Expandable((RANDOMLY, 'polyn1_polyn1')) elif q_kind == 'sum_of_any_basic_expd': if self.q_subkind in ['harder', 'with_a_binomial']: # __ choices = ['monom0_polyn1', 'monom1_polyn1'] drawn_types = list() drawn_types.append(randomly.pop(choices)) if self.q_subkind == 'with_a_binomial': drawn_types.append('any_binomial') else: drawn_types.append('minus_polyn1_polyn1') aux_expd_list = list() for t in drawn_types: if t == 'any_binomial': aux_expd_list.append( BinomialIdentity((RANDOMLY, 'any'), **options)) else: aux_expd_list.append(Expandable((RANDOMLY, t))) final_list = list() for i in range(len(aux_expd_list)): final_list.append(randomly.pop(aux_expd_list)) self.expandable_objct = Sum(final_list) elif self.q_subkind == 'easy': choices = ['monom0_polyn1', 'monom1_polyn1'] aux_expd_list = list() aux_expd_list.append( Expandable((RANDOMLY, randomly.pop(choices)))) if randomly.heads_or_tails(): aux_expd_list.append(Expandable((RANDOMLY, 'sign_exp'))) else: aux_expd_list.append( Monomial((RANDOMLY, 15, randomly.integer(0, 2)))) final_list = list() for i in range(len(aux_expd_list)): final_list.append(randomly.pop(aux_expd_list)) self.expandable_objct = Sum(final_list) else: choices = [ 'monom0_polyn1', 'monom0_polyn1', 'monom1_polyn1', 'monom1_polyn1', 'polyn1_polyn1', 'minus_polyn1_polyn1' ] drawn_types = list() drawn_types.append(randomly.pop(choices)) drawn_types.append(randomly.pop(choices)) aux_expd_list = list() for element in drawn_types: aux_expd_list.append(Expandable((RANDOMLY, element))) aux_expd_list.append(Monomial((RANDOMLY, 15, 2))) final_list = list() for i in range(len(aux_expd_list)): final_list.append(randomly.pop(aux_expd_list)) self.expandable_objct = Sum(final_list) elif q_kind in ['sign_expansion', 'sign_expansion_short_test']: sign_exp_kind = options.get('sign_exp_kind', 0) if q_kind == 'sign_expansion_short_test': sign_exp_kind = 1 if sign_exp_kind == 0: sign_exp_kind = randomly.integer(1, 5) # Creation of the terms aux_terms_list = list() aux_expd_1 = Expandable((Monomial( (randomly.sign(), 1, 0)), Polynomial((RANDOMLY, 15, 2, 2)))) aux_expd_2 = Expandable((Monomial( (randomly.sign(), 1, 0)), Polynomial((RANDOMLY, 15, 2, 2)))) aux_expd_3 = Expandable((Monomial( (randomly.sign(), 1, 0)), Polynomial((RANDOMLY, 15, 2, 2)))) long_aux_expd = Expandable((Monomial( (randomly.sign(), 1, 0)), Polynomial((RANDOMLY, 15, 2, 3)))) if q_kind == 'sign_expansion_short_test': long_aux_expd = Expandable((Monomial( ('-', 1, 0)), Polynomial((RANDOMLY, 15, 2, 3)))) aux_monomial = Monomial((RANDOMLY, 15, 2)) # 1st kind: a Monomial and ± (long Polynomial) # (like in a short test) if sign_exp_kind == 1: aux_terms_list.append(long_aux_expd) aux_terms_list.append(aux_monomial) # 2d kind: ± (x+3) ± (4x - 7) elif sign_exp_kind == 2: aux_terms_list.append(aux_expd_1) aux_terms_list.append(aux_expd_2) # 3d kind: ± (x+3) ± (4x - 7) ± (x² - 5x) elif sign_exp_kind == 3: aux_terms_list.append(aux_expd_1) aux_terms_list.append(aux_expd_2) aux_terms_list.append(aux_expd_3) # 4th kind: ± (x+3) ± (4x - 7) ± Monomial elif sign_exp_kind == 4: aux_terms_list.append(aux_expd_1) aux_terms_list.append(aux_expd_2) aux_terms_list.append(aux_monomial) # 5th kind: ± (x+3) ± Monomial ± (long Polynomial) elif sign_exp_kind == 5: aux_terms_list.append(aux_expd_2) aux_terms_list.append(aux_monomial) aux_terms_list.append(long_aux_expd) # add as many possibilities as wanted, # don't forget to increase the last number here: # sign_exp_kind = randomly.integer(1, 5) (what's a bit above) # Now let's distribute the terms randomly final_terms_list = list() for i in range(len(aux_terms_list)): final_terms_list.append(randomly.pop(aux_terms_list)) self.expandable_objct = Sum(final_terms_list) elif q_kind in [ 'numeric_sum_square', 'numeric_difference_square', 'numeric_squares_difference' ]: # __ self.expandable_objct = init_caller( (options['couple'][0], options['couple'][1]), **options) if q_kind in ['numeric_sum_square', 'numeric_difference_square']: self.numeric_aux = Sum( [options['couple'][0], options['couple'][1]]).reduce_() self.numeric_aux.set_exponent(2) else: # squares_difference's case aux1 = Sum([options['couple'][0], options['couple'][1]]).reduce_() temp = options['couple'][1].clone() temp.set_sign('-') aux2 = Sum([options['couple'][0], temp]).reduce_() self.numeric_aux = Product([aux1, aux2]) else: if q_kind == 'any_binomial': q_kind = 'any' self.expandable_objct = init_caller((RANDOMLY, q_kind), **options) # Creation of the expression: number = 0 if 'expression_number' in options \ and is_.a_natural_int(options['expression_number']): # __ number = options['expression_number'] self.expression = Expression(number, self.expandable_objct) if self.numeric_aux is not None: self.numeric_aux = Expression(number, self.numeric_aux)
class Q_AlgebraExpressionReduction(Q_Structure): # -------------------------------------------------------------------------- ## # @brief Constructor. # @param q_kind= the kind of question desired # Available values are: 'product' # 'sum' # 'sum_of_products' # @param **options Options detailed below: # - short_test=bool # 'yes' # 'OK' # any other value will be understood as 'no' # - q_subkind=<string> # 'minus_brackets_nb' (values: 1, 2, 3) # 'plus_brackets_nb' (values: 1, 2, 3) # @todo describe the different available options in this comment # @return One instance of question.Q_AlgebraExpressionReduction def __init__(self, q_kind='default_nothing', **options): self.derived = True # The call to the mother class __init__() method will set the # fields matching optional arguments which are so far: # self.q_kind, self.q_subkind # plus self.options (modified) Q_Structure.__init__(self, q_kind, AVAILABLE_Q_KIND_VALUES, **options) # The purpose of this next line is to get the possibly modified # value of **options options = self.options MAX_COEFF = MAX_COEFF_TABLE[q_kind] MAX_EXPONENT = MAX_EXPONENT_TABLE[q_kind] MIN_LENGTH = DEFAULT_MINIMUM_LENGTH_TABLE[q_kind] MAX_LENGTH = DEFAULT_MAXIMUM_LENGTH_TABLE[q_kind] LENGTH_SPAN = MAX_LENGTH - MIN_LENGTH + 1 # This field is to be used in the answer_to_strs() method # to determine a possibly different algorithm for particular cases self.kind_of_answer = "" # Max coefficient & degree values... max_coeff = options.get('max_coeff', MAX_COEFF) max_expon = options.get('max_expon', MAX_EXPONENT) length = options.get('length', random.choice([n + MIN_LENGTH for n in range(LENGTH_SPAN)])) # 1st CASE: # PRODUCT REDUCTION if q_kind == 'product': # First let's determine a pack of letters where to draw # The default one will be [a, b, c, x, y, z] # but the reduced or entire alphabets can be used as well letters_package = ['a', 'b', 'c', 'x', 'y', 'z'] self.kind_of_answer = 'product_detailed' if 'use_reduced_alphabet' in options: letters_package = ['a', 'b', 'c', 'd', 'g', 'h', 'k', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] elif ('use_these_letters' in options and type(options['use_these_letters']) is list and all([type(elt) is str for elt in options['use_these_letters']])): # __ letters_package = options['use_these_letters'] # Maximum Items number. (We make sure at the same time that # we won't # risk to draw a greater number of letters than the available # letters # in letters_package) max_literal_items_nb = min(PR_MAX_LITERAL_ITEMS_NB, len(letters_package)) # Maximum number of occurences of the same letter in # the initial expression same_letter_max_occurences = PR_SAME_LETTER_MAX_OCCURENCES_NB if ('nb_occurences_of_the_same_letter' in options and options['nb_occurences_of_the_same_letter'] >= 1): # __ same_letter_max_occurences = options['nb_occurences_of' '_the_same_letter'] # CREATION OF THE EXPRESSION # We draw randomly the letters that will appear # in the expression current_letters_package = list(letters_package) nb_of_letters_to_draw = random.randint(1, max_literal_items_nb) drawn_letters = list() for j in range(nb_of_letters_to_draw): drawn_letters.append( random.choice(current_letters_package)) # Let's determine how many times will appear each letter # and then create a list containing each of these letters # the number of times they will appear pre_items_list = list() items_list = list() for j in range(len(drawn_letters)): if j == 0: # We make sure that at least one letter occurs twice # so that the exercise remains interesting ! # But the number of cases this letter occurs 3 three # times should be limited to keep sufficient # simple cases for the pupils to begin with. # It is really easy to make it much more complicated # simply giving: # nb_occurences_of_the_same_letter=<enough_high_nb> # as an argument. if random.random() < 0.5: occurences_nb = 2 else: occurences_nb = \ random.randint( min(2, same_letter_max_occurences), same_letter_max_occurences) else: occurences_nb = \ random.randint(1, same_letter_max_occurences) if occurences_nb >= 1: for k in range(occurences_nb): pre_items_list.append(drawn_letters[j]) # draw the number of numeric Items nb_item_num = random.randint(1, PR_NUMERIC_ITEMS_MAX_NB) # put them in the pre items' list for j in range(nb_item_num): pre_items_list.append(NUMERIC) # prepare the items' list that will be given to the Product's # constructor loop_nb = len(pre_items_list) for j in range(loop_nb): next_item_kind = random.choice(pre_items_list) # It's not really useful nor really possible to limit the # number # of occurences of the same letter being drawn twice in # a row because it belongs to the exercise and there # are many cases when # the same letter is in the list in 3 over 4 elements. # if j >= 1 and next_item_kind == items_list[j - 1] # .raw_value: # pre_items_list.append(next_item_kind) # next_item_kind = random.choice(pre_items_list) if next_item_kind == NUMERIC: temp_item = Item((random.choices(['+', '-'], cum_weights=[0.75, 1])[0], random.randint(1, max_coeff), 1)) items_list.append(temp_item) else: item_value = next_item_kind temp_item = Item((random.choices(['+', '-'], cum_weights=[0.9, 1])[0], item_value, random.randint(1, max_expon))) items_list.append(temp_item) # so now that the items_list is complete, # let's build the Product ! self.objct = Product(items_list) self.objct.set_compact_display(False) # Let's take some × symbols off the Product to match a more # usual situation for i in range(len(self.objct) - 1): if ((self.objct.factor[i].is_numeric() and self.objct.factor[i + 1].is_literal()) or (self.objct.factor[i].is_literal() and self.objct.factor[i + 1].is_literal() and self.objct.factor[i].raw_value != self.objct.factor[i + 1].raw_value and random.random() > 0.5)): # __ self.objct.info[i] = False # 2d CASE: # SUM OF PRODUCTS REDUCTION if q_kind == 'sum_of_products': if (not ('length' in options and is_integer(options['length']) and options['length'] >= 2)): # __ length = random.choices( [n + MIN_LENGTH for n in range(LENGTH_SPAN)], weights=[n for n in range(LENGTH_SPAN)])[0] # Creation of the list to give later to the Sum constructor products_list = list() for i in range(length): monomial1 = Monomial((RANDOMLY, max_coeff, max_expon)) monomial2 = Monomial((RANDOMLY, max_coeff, max_expon)) products_list.append(Product([monomial1, monomial2])) # Creation of the Sum self.objct = Sum(products_list) # 3d CASE: # SUM REDUCTION if q_kind == 'sum': self.kind_of_answer = 'sum' length = options.get('length', random.choice([n + MIN_LENGTH for n in range(LENGTH_SPAN)])) self.objct = Polynomial((RANDOMLY, max_coeff, max_expon, length)) # Creation of the expression: number = 0 if ('expression_number' in options and is_natural(options['expression_number'])): # __ number = options['expression_number'] self.expression = Expression(number, self.objct) # -------------------------------------------------------------------------- ## # @brief Returns the text of the question as a str def text_to_str(self): M = shared.machine result = M.write_math_style2(M.type_string(self.expression)) result += M.write_new_line() return result # -------------------------------------------------------------------------- ## # @brief Returns the answer of the question as a str def answer_to_str(self): M = shared.machine result = "" if self.kind_of_answer == 'product_detailed': result += M.write_math_style2(M.type_string(self.expression)) result += M.write_new_line() if not all(self.objct.factor[i] .alphabetical_order_cmp(self.objct.factor[i + 1]) > 0 for i in range(len(self.objct.factor) - 1)): ordered_product = self.objct.order() ordered_product.set_compact_display(False) ordered_expression = Expression(self.expression.name, ordered_product) result += M.write_math_style2( M.type_string(ordered_expression)) result += M.write_new_line() final_product = self.objct.reduce_() final_expression = Expression(self.expression.name, final_product) result += M.write_math_style2(M.type_string(final_expression)) result += M.write_new_line() elif ((self.kind_of_answer in ['sum', 'sum_not_reducible']) and self.expression. right_hand_side.expand_and_reduce_next_step() is None): # __ result += M.write_math_style2(M.type_string(self.expression)) result += M.write_new_line() result += M.write(_("This expression is not reducible.")) result += M.write_new_line() else: result += M.write(self.expression.auto_expansion_and_reduction()) return result