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)
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 level_01(q_subkind, **options): if q_subkind == 'default' \ or q_subkind == 'three_terms' \ or q_subkind == 'ax + b' \ or q_subkind == 'ax² + b' \ or q_subkind == 'ax² + bx': # __ # the idea is to build the final factorized result first and to # expand it to get the question (and the solution's steps # in the same time) if q_subkind == 'default': common_factor = Monomial((RANDOMLY, 6, 1)) # In order to reduce the number of cases where x² appears, # let the common factor be of degree 0 most of the time. common_factor.set_degree( randomly.integer(0, 1, weighted_table=[0.85, 0.15])) elif q_subkind in ['three_terms', 'ax + b', 'ax² + b']: common_factor = Monomial((RANDOMLY, 6, 0)) elif q_subkind == 'ax² + bx': common_factor = Monomial((RANDOMLY, 6, 1)) common_factor.set_degree(1) # to avoid having a situation like 1×(2x + 3) which isn't # factorizable: if common_factor.get_degree() == 0: common_factor.set_coeff(randomly.integer(2, 6)) # signs are randomly chosen ; the only case that is to be avoided # is all signs are negative (then it wouldn't factorize well... # I mean then the '-' should be factorized and not left in the final # result) signs_box = [['+', '+'], ['+', '-']] signs = randomly.pop(signs_box) # this next test is to avoid -2x + 6 being factorized -2(x - 3) # which is not wrong but not "natural" to pupils # this test should be changed when a third term is being used. if signs == ['+', '-']: common_factor.set_sign('+') coeff_1 = randomly.integer(2, 10) coeff_2 = randomly.coprime_to(coeff_1, [i + 1 for i in range(10)]) coeff_3 = None if q_subkind == 'three_terms': coeff_3 = randomly.coprime_to(coeff_1 * coeff_2, [i + 1 for i in range(9)]) third_sign = randomly.sign() if third_sign == '-': common_factor.set_sign('+') signs.append(third_sign) lil_box = [] lil_box.append(Monomial(('+', 1, 0))) if q_subkind == 'ax² + b': lil_box.append(Monomial(('+', 1, 2))) else: lil_box.append(Monomial(('+', 1, 1))) if ((common_factor.get_degree() == 0 and randomly.integer(1, 20) > 17 and q_subkind == 'default') or q_subkind == 'three_terms'): # __ lil_box.append(Monomial(('+', 1, 2))) first_term = randomly.pop(lil_box) second_term = randomly.pop(lil_box) third_term = None first_term.set_coeff(coeff_1) first_term.set_sign(randomly.pop(signs)) second_term.set_coeff(coeff_2) second_term.set_sign(randomly.pop(signs)) if q_subkind == 'three_terms': third_term = randomly.pop(lil_box) third_term.set_coeff(coeff_3) third_term.set_sign(randomly.pop(signs)) if first_term.is_positive() and second_term.is_positive()\ and third_term.is_positive(): # __ common_factor.set_sign(randomly.sign()) if not (q_subkind == 'three_terms'): if common_factor.get_degree() == 0 \ and first_term.get_degree() >= 1 \ and second_term.get_degree() >= 1: # __ if randomly.heads_or_tails(): first_term.set_degree(0) else: second_term.set_degree(0) if q_subkind == 'three_terms': solution = Expandable( (common_factor, Sum([first_term, second_term, third_term]))) else: solution = Expandable( (common_factor, Sum([first_term, second_term]))) # now create the expanded step and the reduced step (which will # be given as a question) temp_steps = [] current_step = solution.clone() while current_step is not None: temp_steps.append(current_step) current_step = current_step.expand_and_reduce_next_step() # now we put the steps in the right order steps = [] for i in range(len(temp_steps)): steps.append(temp_steps[len(temp_steps) - 1 - i]) return steps elif q_subkind == 'not_factorizable': signs_box = [['+', '+'], ['+', '-']] signs = randomly.pop(signs_box) coeff_1 = randomly.integer(2, 10) coeff_2 = randomly.coprime_to(coeff_1, [i + 1 for i in range(10)]) lil_box = [] lil_box.append(Monomial(('+', 1, 0))) lil_box.append(Monomial(('+', 1, 1))) lil_box.append(Monomial(('+', 1, 2))) first_term = randomly.pop(lil_box) second_term = randomly.pop(lil_box) first_term.set_coeff(coeff_1) first_term.set_sign(randomly.pop(signs)) second_term.set_coeff(coeff_2) second_term.set_sign(randomly.pop(signs)) if first_term.get_degree() >= 1 \ and second_term.get_degree() >= 1: # __ if randomly.heads_or_tails(): first_term.set_degree(0) else: second_term.set_degree(0) steps = [] solution = _("So far, we don't know if this expression can be " "factorized.") steps.append(Sum([first_term, second_term])) steps.append(solution) return steps
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 __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)