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_expQ_auto_er(): """No redundant lines in expansion and reduction of 9-(0.4+0.4)×5?""" temp = Sum([9, Product([Expandable((Item(-1), Sum([Decimal('0.4'), Decimal('0.4')]))), Item(5)], compact_display=False)]) expQ = Expression("Q", temp) assert expQ.auto_expansion_and_reduction() == \ wrap_nb('$\\text{Q}=9-(0.4+0.4)\\times 5$\\newline \n' '$\\text{Q}=9-0.8\\times 5$\\newline \n' '$\\text{Q}=9-4$\\newline \n' '$\\text{Q}=5$\\newline \n')
def test_expR_auto_er(): """No extraneous parentheses or lines in exp. and red. of 2+(7.5-6.7)×6?""" temp = Sum([Item(2), Product([Expandable((Item(1), Sum([Decimal('7.5'), -Decimal('6.7')]))), Item(6)], compact_display=False)]) expR = Expression("R", temp) assert expR.auto_expansion_and_reduction() == \ wrap_nb('$\\text{R}=2+(7.5-6.7)\\times 6$\\newline \n' '$\\text{R}=2+0.8\\times 6$\\newline \n' '$\\text{R}=2+4.8$\\newline \n' '$\\text{R}=6.8$\\newline \n')
def __init__(self, build_data, **options): super().setup("minimal", **options) super().setup("numbers", nb=build_data, shuffle_nbs=False, **options) super().setup("nb_variants", nb=build_data, **options) degrees1 = [0, 1] degrees2 = [0, 1] random.shuffle(degrees1) random.shuffle(degrees2) weighted_signs = [('+', 16), ('-', 4)] weighted_signs = [val for val, cnt in weighted_signs for i in range(cnt)] signs = ['+', '-'] self.expandable = Expandable((Monomial((random.choice(signs), self.nb1, degrees1.pop())), Polynomial([Monomial((random.choice( weighted_signs), self.nb2, degrees2.pop())), Monomial((random.choice( signs), self.nb3, 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 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 expP(): t = Sum([Expandable((Monomial(('+', 7, 0)), Sum([Monomial(('-', 6, 1)), Monomial((6, 0))]))), BinomialIdentity((Monomial(('-', 10, 1)), Monomial(('-', 3, 0))), difference_square='OK')]) return Expression("P", t)
def expN(): t = Sum([Expandable((Monomial(('-', 1, 0)), Expandable((Sum([Monomial((2, 1)), Monomial((9, 0))]), Sum([Monomial((-3, 1)), Monomial((-7, 0))]))))), Expandable((Monomial((4, 0)), Sum([Monomial((-3, 1)), Monomial((9, 0))]))), Monomial((13, 0))]) return Expression("N", t)
def answer_to_str(self): M = shared.machine result = "" while self.objct is not None: result += M.write_math_style1(M.type_string(self.expression)) self.objct = self.objct.calculate_next_step() if self.objct is not None: self.expression = Expression(self.expression.name, self.objct) return result
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 is_.an_ordered_calculable_objects_list(self.objct.factor): 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
class sub_object(component.structure): def __init__(self, build_data, **options): super().setup("minimal", **options) super().setup("numbers", nb=build_data, **options) super().setup("nb_variants", nb=build_data, **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 q(self, **options): return shared.machine.write_math_style2(self.expression_str) def a(self, **options): return shared.machine.write( self.expression.auto_expansion_and_reduction(**options))
class sub_object(submodule.structure): 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 q(self, **options): return shared.machine.write_math_style2(self.expression_str) def a(self, **options): return shared.machine.write( self.expression.auto_expansion_and_reduction(**options))
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 q_subkind = self.q_subkind # That's the number of the question, not of the expressions it might # contain ! self.number = "" steps_method = None if q_kind == 'level_01': steps_method = level_01 if q_subkind == 'mixed': q_subkind = randomly.pop( ['default', 'three_terms', 'not_factorizable']) elif q_subkind == 'mixed_factorizable': q_subkind = randomly.pop(['default', 'three_terms']) # steps = level_01(subkind) elif q_kind == 'level_02': steps_method = level_02 if q_subkind == 'default': q_subkind = 'type_123' if q_subkind == 'type_123': q_subkind = randomly.pop(['type_1', 'type_2', 'type_3']) if q_subkind == 'type_1': q_subkind = randomly.pop( ['type_1_ABC', 'type_1_DEF', 'type_1_GHI']) if q_subkind == 'type_1_ABC': q_subkind = randomly.pop(['type_1_A', 'type_1_B', 'type_1_C']) if q_subkind == 'type_1_DEF': q_subkind = randomly.pop(['type_1_D', 'type_1_E', 'type_1_F']) if q_subkind == 'type_1_GHI': q_subkind = randomly.pop(['type_1_G', 'type_1_H', 'type_1_I']) if q_subkind == 'type_1_A': q_subkind = randomly.pop(['type_1_A0', 'type_1_A1']) if q_subkind == 'type_1_B': q_subkind = randomly.pop(['type_1_B0', 'type_1_B1']) if q_subkind == 'type_1_C': q_subkind = 'type_1_C0' if q_subkind == 'type_1_D': q_subkind = randomly.pop(['type_1_D0', 'type_1_D1']) if q_subkind == 'type_1_E': q_subkind = randomly.pop(['type_1_E0', 'type_1_E1']) if q_subkind == 'type_1_F': q_subkind = 'type_1_F0' if q_subkind == 'type_1_G': q_subkind = randomly.pop(['type_1_G0', 'type_1_G1']) if q_subkind == 'type_1_H': q_subkind = randomly.pop(['type_1_H0', 'type_1_H1']) if q_subkind == 'type_1_I': q_subkind = 'type_1_I0' if q_subkind == 'type_1_0': q_subkind = randomly.pop([ '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' ]) if q_subkind == 'type_1_1': q_subkind = randomly.pop([ 'type_1_A1', 'type_1_B1', 'type_1_D1', 'type_1_E1', 'type_1_G1', 'type_1_H1' ]) if q_subkind == 'type_2': q_subkind = randomly.pop(['type_2_ABC', 'type_2_DEF']) if q_subkind == 'type_2_ABC': q_subkind = randomly.pop(['type_2_A', 'type_2_B', 'type_2_C']) if q_subkind == 'type_2_DEF': q_subkind = randomly.pop(['type_2_D', 'type_2_E', 'type_2_F']) if q_subkind == 'type_2_A': q_subkind = randomly.pop(['type_2_A0', 'type_2_A1']) if q_subkind == 'type_2_B': q_subkind = randomly.pop(['type_2_B0', 'type_2_B1']) if q_subkind == 'type_2_C': q_subkind = 'type_2_C0' if q_subkind == 'type_2_D': q_subkind = randomly.pop(['type_2_D0', 'type_2_D1']) if q_subkind == 'type_2_E': q_subkind = randomly.pop(['type_2_E0', 'type_2_E1']) if q_subkind == 'type_2_F': q_subkind = 'type_2_F0' if q_subkind == 'type_2_0': q_subkind = randomly.pop([ 'type_2_A0', 'type_2_B0', 'type_2_C0', 'type_2_D0', 'type_2_E0', 'type_2_F0' ]) if q_subkind == 'type_2_1': q_subkind = randomly.pop( ['type_2_A1', 'type_2_B1', 'type_2_D1', 'type_2_E1']) if q_subkind == 'type_3': q_subkind = 'type_3_ABC' if q_subkind == 'type_3_ABC': q_subkind = randomly.pop(['type_3_A', 'type_3_B', 'type_3_C']) if q_subkind == 'type_3_A': q_subkind = randomly.pop(['type_3_A0', 'type_3_A1']) if q_subkind == 'type_3_B': q_subkind = randomly.pop(['type_3_B0', 'type_3_B1']) if q_subkind == 'type_3_C': q_subkind = 'type_3_C0' if q_subkind == 'type_3_0': q_subkind = randomly.pop( ['type_3_A0', 'type_3_B0', 'type_3_C0']) if q_subkind == 'type_3_1': q_subkind = randomly.pop(['type_3_A1', 'type_3_B1']) # steps = level_02(subkind, **options) elif q_kind == 'level_03': steps_method = level_03 options['markup'] = shared.machine.markup if q_subkind == 'any' or q_subkind == 'default': q_subkind = randomly.pop(['any_straight', 'any_mixed']) if q_subkind == 'any_straight': q_subkind = randomly.pop( ['any_true_straight', 'any_fake_straight']) if q_subkind == 'any_mixed': q_subkind = randomly.pop(['any_true_mixed', 'any_fake_mixed']) if q_subkind == 'any_true': q_subkind = randomly.pop( ['any_true_straight', 'any_true_mixed']) if q_subkind == 'any_fake': q_subkind = randomly.pop( ['any_fake_straight', 'any_fake_mixed']) if q_subkind == 'any_true_straight': q_subkind = randomly.pop( ['sum_square', 'difference_square', 'squares_difference']) if q_subkind == 'any_fake_straight': q_subkind = randomly.pop( ['fake_01', 'fake_02', 'fake_03', 'fake_04_any_straight']) if q_subkind == 'any_true_mixed': q_subkind = randomly.pop([ 'sum_square_mixed', 'difference_square_mixed', 'squares_difference_mixed' ]) if q_subkind == 'any_fake_mixed': q_subkind = randomly.pop([ 'fake_01_mixed', 'fake_02_mixed', 'fake_03_mixed', 'fake_04_any_mixed' ]) if q_subkind == 'fake_04_any': q_subkind = randomly.pop( ['fake_04_any_mixed', 'fake_04_any_straight']) if q_subkind == 'fake_04_any_mixed': q_subkind = randomly.pop([ 'fake_04_A_mixed', 'fake_04_B_mixed', 'fake_04_C_mixed', 'fake_04_D_mixed' ]) if q_subkind == 'fake_04_any_straight': q_subkind = randomly.pop( ['fake_04_A', 'fake_04_B', 'fake_04_C', 'fake_04_D']) steps = steps_method(q_subkind, **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, steps[0]) # Putting the steps and the solution together: self.steps = [] # for i in xrange(len(steps) - 1): # self.steps.append(Expression(number, # steps[i] # ) # ) # # solution = steps[len(steps) - 1] # # if isinstance(solution, Exponented): # self.steps.append(Expression(number, # solution # ) # ) # else: # self.steps.append(solution) for i in range(len(steps)): if isinstance(steps[i], Exponented): self.steps.append(Expression(number, steps[i])) else: self.steps.append(steps[i])
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 # That's the number of the question, not of the expressions it might # contain ! self.number = "" if 'number_of_questions' in options: self.number = options['number_of_questions'] self.objct = None # 1st OPTION if q_kind == 'fraction_simplification': root = randomly.integer(2, 19, weighted_table=[ 0.225, 0.225, 0, 0.2, 0, 0.2, 0, 0, 0, 0.07, 0, 0.0375, 0, 0, 0, 0.0375, 0, 0.005 ]) factors_list = [j + 1 for j in range(10)] ten_power_factor1 = 1 ten_power_factor2 = 1 if 'with_ten_powers' in options \ and is_.a_number(options['with_ten_powers']) \ and options['with_ten_powers'] <= 1 \ and options['with_ten_powers'] >= 0: # __ if randomly.decimal_0_1() < options['with_ten_powers']: ten_powers_list = [10, 10, 100, 100] ten_power_factor1 = randomly.pop(ten_powers_list) ten_power_factor2 = randomly.pop(ten_powers_list) self.objct = Fraction( ('+', root * randomly.pop(factors_list) * ten_power_factor1, root * randomly.pop(factors_list) * ten_power_factor2)) # 2d & 3d OPTIONS # Fractions Products | Quotients elif q_kind in ['fractions_product', 'fractions_quotient']: # In some cases, the fractions will be generated # totally randomly if randomly.decimal_0_1() < 0: lil_box = [n + 2 for n in range(18)] a = randomly.pop( lil_box, weighted_table=FRACTION_PRODUCT_AND_QUOTIENT_TABLE) b = randomly.pop( lil_box, weighted_table=FRACTION_PRODUCT_AND_QUOTIENT_TABLE) lil_box = [n + 2 for n in range(18)] c = randomly.pop( lil_box, weighted_table=FRACTION_PRODUCT_AND_QUOTIENT_TABLE) d = randomly.pop( lil_box, weighted_table=FRACTION_PRODUCT_AND_QUOTIENT_TABLE) f1 = Fraction((randomly.sign(plus_signs_ratio=0.75), Item((randomly.sign(plus_signs_ratio=0.80), a)), Item( (randomly.sign(plus_signs_ratio=0.80), b)))) f2 = Fraction((randomly.sign(plus_signs_ratio=0.75), Item((randomly.sign(plus_signs_ratio=0.80), c)), Item( (randomly.sign(plus_signs_ratio=0.80), d)))) # f1 = f1.simplified() # f2 = f2.simplified() # In all other cases (80%), we'll define a "seed" a plus two # randomly numbers i and j to form the Product | Quotient: # a×i / b × c / a × j # Where b is a randomly number coprime to a×i # and c is a randomly number coprime to a×j else: a = randomly.integer(2, 8) lil_box = [i + 2 for i in range(7)] i = randomly.pop(lil_box) j = randomly.pop(lil_box) b = randomly.coprime_to(a * i, [n + 2 for n in range(15)]) c = randomly.not_coprime_to(b, [n + 2 for n in range(30)], excepted=a * j) f1 = Fraction( (randomly.sign(plus_signs_ratio=0.75), Item((randomly.sign(plus_signs_ratio=0.80), a * i)), Item((randomly.sign(plus_signs_ratio=0.80), b)))) f2 = Fraction( (randomly.sign(plus_signs_ratio=0.75), Item((randomly.sign(plus_signs_ratio=0.80), c)), Item((randomly.sign(plus_signs_ratio=0.80), a * j)))) if randomly.heads_or_tails(): f3 = f1.clone() f1 = f2.clone() f2 = f3.clone() if q_kind == 'fractions_quotient': f2 = f2.invert() if q_kind == 'fractions_product': self.objct = Product([f1, f2]) elif q_kind == 'fractions_quotient': self.objct = Quotient(('+', f1, f2, 1, 'use_divide_symbol')) # 4th OPTION # Fractions Sums elif q_kind == 'fractions_sum': randomly_position = randomly\ .integer(0, 16, weighted_table=FRACTIONS_SUMS_SCALE_TABLE) chosen_seed_and_generator = FRACTIONS_SUMS_TABLE[randomly_position] seed = randomly.integer(2, chosen_seed_and_generator[1]) # The following test is only intended to avoid having "high" # results too often. We just check if the common denominator # will be higher than 75 (arbitrary) and if yes, we redetermine # it once. We don't do it twice since we don't want to totally # forbid high denominators. if seed * chosen_seed_and_generator[0][0] \ * chosen_seed_and_generator[0][1] >= 75: # __ seed = randomly.integer(2, chosen_seed_and_generator[1]) lil_box = [0, 1] gen1 = chosen_seed_and_generator[0][lil_box.pop()] gen2 = chosen_seed_and_generator[0][lil_box.pop()] den1 = Item(gen1 * seed) den2 = Item(gen2 * seed) temp1 = randomly.integer(1, 20) temp2 = randomly.integer(1, 20) num1 = Item(temp1 // gcd(temp1, gen1 * seed)) num2 = Item(temp2 // gcd(temp2, gen2 * seed)) f1 = Fraction((randomly.sign(plus_signs_ratio=0.7), num1, den1)) f2 = Fraction((randomly.sign(plus_signs_ratio=0.7), num2, den2)) self.objct = Sum([f1.simplified(), f2.simplified()]) # 5th # still to imagine:o) # 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 expH(): t = Sum([Item(-30), Item(80), Monomial(('+', 1, 2))]) return Expression("H", t)
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] 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) # -------------------------------------------------------------------------- ## # @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 is_.an_ordered_calculable_objects_list(self.objct.factor): 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
def expF(): t = Sum([Product([Item(-2), Item(-6)]), Item(-1), Product([Item(3), Item(('-', "x", 1))]), Product([Monomial(('-', 8, 1)), Item(-3)])]) return Expression("F", t)
def expG(): t = Sum([Monomial(('+', 5, 1)), Product([Monomial(('+', 7, 1)), Monomial(('+', 8, 1))]), Product([Monomial(('+', 5, 1)), Item(-1)]), Product([Item(7), Item(8)])]) return Expression("G", t)
def expD(): t = Expandable((Item(-1), Sum([Monomial((3, 1)), Item(-2)]))) return Expression("D", t)
def expE(): t = Sum([Product([Item(-3), Item(10)]), Product([Monomial(('-', 10, 1)), Monomial(('-', 9, 1))]), Product([Monomial(('+', 7, 1)), Monomial(('+', 8, 1))]), Product([Item(8), Item(10)])]) return Expression("E", t)
def expC(): t = Sum([Monomial((3, 1)), Expandable((Item(-1), Expandable((Sum([Item('x'), Item(3)]), Sum([Item(6), Monomial((2, 1))])))))]) return Expression("C", t)
def expJ(): t = BinomialIdentity((Item(3), Monomial(('+', 3, 1))), squares_difference=True) return Expression("J", t)
def expK(): t = BinomialIdentity((Item(1), Monomial(('+', 10, 1))), squares_difference=True) return Expression("K", t)
def expL(): t = Sum([Item(-2), Monomial(('-', 1, 1)), Monomial(('+', 8, 2)), Monomial(('+', 1, 1))]) return Expression("L", t)
def expM(): t = Sum([Monomial((-15, 0)), Expandable((Item(1), Sum([Item(10), Monomial((14, 1)), Monomial(('-', 10, 2))])))]) return Expression("M", t)
def expA(): t = Expandable((Item(2), Sum([Item(1), Monomial((5, 1))]))) return Expression("A", t)
def expB(): t = Expandable((Sum([Item(1), Monomial((-11, 1))]), Sum([Item(11), Monomial((7, 1))]))) return Expression("B", t)
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