def test_eq37_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Monomial((Fraction( (Item(2), Item(3))), 1)), Fraction((Item(4), Item(5))))) assert eq.auto_resolution(dont_display_equations_name=True) == \ wrap_nb('\[\\frac{2}{3}x=\\frac{4}{5}\]' '\[x=\\frac{4}{5}\div \\frac{2}{3}\]' '\[x=\\frac{4}{5}\\times \\frac{3}{2}\]' '\[x=\\frac{4\\times 3}{5\\times 2}\]' '\[x=\\frac{\\bcancel{2}\\times 2\\times 3}' '{5\\times \\bcancel{2}}\]' '\[x=\\frac{6}{5}\]')
def test_fractions_by_items_01_next_step(): """Is this Product's calculation's next step correct?""" p = Product([ Fraction((Item(3), Item(5))), Item(8), Fraction((Item(7), Item(11))), Item(4), Fraction((Item(13), Item(17))) ]) assert p.calculate_next_step().printed == \ wrap_nb('\\frac{3\\times 8\\times 7\\times 4\\times 13}{5\\times 11' '\\times 17}')
def test_eq39_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Sum([ Monomial((Fraction((Item(2), Item(1))).simplified(), 1)), Fraction((Item(1), Item(5))) ]), Fraction(('-', Item(4), Item(5))))) assert eq.auto_resolution(dont_display_equations_name=True) == \ wrap_nb('\[2x+\\frac{1}{5}=-\\frac{4}{5}\]' '\[2x=-\\frac{4}{5}-\\frac{1}{5}\]' '\[2x=\\frac{-4-1}{5}\]' '\[2x=-\\frac{5}{5}\]' '\[2x=-\\frac{\\bcancel{5}}{\\bcancel{5}}\]' '\[2x=-1\]' '\[x=-\\frac{1}{2}\]')
def test_f6_simplification_line(): """Is this Fraction's simplification line correct?""" assert Fraction(('+', Product([Item(10), Item(5)]), Product([Item(5), Item(9)])))\ .simplification_line().printed == \ wrap_nb('\\frac{10\\times \\bcancel{5}}{\\bcancel{5}\\times 9}')
def test_eq29_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation( (Monomial(('+', 1, 1)), Sum([Fraction((Item(1), Item(4))), Fraction((Item(1), Item(8)))])), number=1) assert eq.auto_resolution(decimal_result=2) == \ wrap_nb('$(\\text{E}_{1}): $' '\[x=\\frac{1}{4}+\\frac{1}{8}\]' '\[x=\\frac{1\\times 2}{4\\times 2}' '+\\frac{1}{8}\]' '\[x=\\frac{2}{8}+\\frac{1}{8}\]' '\[x=\\frac{2+1}{8}\]' '\[x=\\frac{3}{8}\]' '\[x\\simeq0.38\]')
def test_f3_simplification_line(): """Is this Fraction's simplification line correct?""" assert Fraction(('+', Product([Item(7), Item(6)]), Product([Item(3), Item(3)])))\ .simplification_line().printed == \ wrap_nb('\\frac{7\\times \\bcancel{3}\\times 2}' '{\\bcancel{3}\\times 3}')
def fig0b(): fig0b = InterceptTheoremConfiguration(sketch=False, rotate_around_isobarycenter=40) fig0b.set_lengths([6, 12, 9], Fraction((Item(4), Item(3)))) fig0b.setup_labels(['?', True, False, True, True, True, False, False], segments_list=[fig0b.u, fig0b.side[1], fig0b.v] + fig0b.small + fig0b.chunk) return fig0b
def test_f5_simplification_line(): """Is this Fraction's simplification line correct?""" assert Fraction(('+', Product([Item(8), Item(3)]), Product([Item(5), Item(6)])))\ .simplification_line().printed == \ wrap_nb('\\frac{\\bcancel{2}\\times 4\\times \\bcancel{3}}{5\\times' ' \\bcancel{2}\\times \\bcancel{3}}')
def test_eq38_autoresolution(): """Is this Equation correctly auto-resolved?""" eq = Equation((Sum([ Monomial((Fraction((Item(1), Item(4))), 1)), Fraction((Item(1), Item(7))) ]), Fraction(('-', Item(3), Item(14))))) assert eq.auto_resolution(dont_display_equations_name=True) == \ wrap_nb('\[\\frac{1}{4}x+\\frac{1}{7}=-\\frac{3}{14}\]' '\[\\frac{1}{4}x=-\\frac{3}{14}-\\frac{1}{7}\]' '\[\\frac{1}{4}x=-\\frac{3}{14}-\\frac{1\\times 2}' '{7\\times 2}\]' '\[\\frac{1}{4}x=-\\frac{3}{14}-\\frac{2}{14}\]' '\[\\frac{1}{4}x=\\frac{-3-2}{14}\]' '\[\\frac{1}{4}x=-\\frac{5}{14}\]' '\[x=-\\frac{5}{14}\div \\frac{1}{4}\]' '\[x=-\\frac{5}{14}\\times \\frac{4}{1}\]' '\[x=-\\frac{5\\times 4}{14\\times 1}\]' '\[x=-\\frac{5\\times \\bcancel{2}\\times 2}' '{\\bcancel{2}\\times 7}\]' '\[x=-\\frac{10}{7}\]')
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 q1(): return Quotient(('+', Fraction(('+', 8, 9)), Fraction( ('+', 7, 2)), 1, 'use_divide_symbol'))
def q2(): return Quotient(('-', Fraction(('+', 1, 2)), Fraction( ('+', 1, 3)), 1, 'use_divide_symbol'))
def fs1(): return Sum([Fraction(('+', 1, 4)), Fraction(('+', 1, 8))])
def fs2(): return Sum([Fraction(('+', 1, 9)), Fraction(('+', 1, -12))])
def fs7(): return Sum([Item(4), Fraction((25, 10)), Item(-7), Fraction((1, 10))])
def fs0(): return Sum([Fraction(('+', 2, 3)), Fraction(('+', 3, 4))])
def fs5(): return Sum([Fraction(('+', 25, 10)), Fraction(('+', 1, 10))])
def fs6(): return Sum([Fraction(('-', 18, 5)), Fraction(('-', 2, 5))])
def fp1(): return Product([Fraction((14, 7)), Fraction((12, 12))]) @pytest.fixture
def test_f12_eval(): """Is this Fraction correctly evaluated?""" assert Fraction((Item(3), Item(7))).evaluate() == \ decimal.Decimal('0.4285714285714285714285714286')
def test_f12_eval2(): """Is this Fraction correctly evaluated?""" assert Fraction((Item(3), Item(7)))\ .evaluate(keep_not_decimal_nb_as_fractions=True).printed == \ wrap_nb('\\frac{3}{7}')
def f1(): return Fraction(('+', 92, 76))
def fig1(): fig1 = InterceptTheoremConfiguration(sketch=False, butterfly=True, rotate_around_isobarycenter=40) fig1.set_lengths([6, 12, 9], Fraction((Item(4), Item(3)))) return fig1
def f2(): return Fraction(('+', Product([Item(10), Item(6)]), Product([Item(7), Item(2)])))
def test_f4_next_step(): """Is this Fraction's calculation's next step correct?""" assert Fraction(('+', Product([Item(3), Item(7)]), Product([Item(10), Item(4)])))\ .calculate_next_step().printed == wrap_nb('\\frac{21}{40}')
def generate_values(source_id): if source_id == 'int_irreducible_frac': return [(k, Fraction((n, k))) for k in [i + 2 for i in range(18)] for n in coprime_generator(k)] elif source_id == 'rank_words': return [(elt,) for elt in RANKS] elif source_id == 'decimal_and_10_100_1000_for_multi': box_10_100_1000 = [10, 100, 1000] result = set() for n in range(20): if not box_10_100_1000: box_10_100_1000 = [10, 100, 1000] chosen_10_100_1000 = box_10_100_1000.pop() ranks_scale = list(RANKS[2:]) width = randomly.pop([1, 2, 3], weighted_table=[0.14, 0.63, 0.33]) start_rank = randomly.pop([n for n in range(len(ranks_scale))]) result |= {(chosen_10_100_1000, generate_decimal(width, ranks_scale, start_rank))} return list(result) elif source_id == 'decimal_and_10_100_1000_for_divi': box_10_100_1000 = [10, 100, 1000] result = set() for n in range(20): if not box_10_100_1000: box_10_100_1000 = [10, 100, 1000] chosen_10_100_1000 = box_10_100_1000.pop() ranks_scale = list(RANKS[2:]) width = randomly.pop([1, 2, 3], weighted_table=[0.14, 0.63, 0.33]) wt = {10: [0.2, 0.2, 0.2, 0.2, 0.2], 100: [0.25, 0.25, 0.25, 0.25, 0], 1000: [0.34, 0.33, 0.33, 0, 0]} start_rank = randomly.pop([n for n in range(len(ranks_scale))], weighted_table=wt[chosen_10_100_1000]) result |= {(chosen_10_100_1000, generate_decimal(width, ranks_scale, start_rank))} return list(result) elif source_id == 'decimal_and_one_digit_for_multi': box = [Decimal('0.1'), Decimal('0.01'), Decimal('0.001')] result = set() for n in range(20): if not box: box = [Decimal('0.1'), Decimal('0.01'), Decimal('0.001')] chosen = box.pop() ranks_scale = list() if chosen == Decimal('0.1'): ranks_scale = list(RANKS[:-1]) elif chosen == Decimal('0.01'): ranks_scale = list(RANKS[:-2]) elif chosen == Decimal('0.001'): ranks_scale = list(RANKS[:-3]) width = randomly.pop([1, 2, 3, 4], weighted_table=[0.14, 0.43, 0.33, 0.2]) start_rank = randomly.pop([n for n in range(len(ranks_scale))]) result |= {(chosen, generate_decimal(width, ranks_scale, start_rank))} return list(result) elif source_id == 'decimal_and_one_digit_for_divi': box = [Decimal('0.1'), Decimal('0.01'), Decimal('0.001')] result = set() for n in range(20): if not box: box = [Decimal('0.1'), Decimal('0.01'), Decimal('0.001')] chosen = box.pop() ranks_scale = list() if chosen == Decimal('0.1') or chosen == Decimal('0.01'): ranks_scale = list(RANKS) elif chosen == Decimal('0.001'): ranks_scale = list(RANKS[1:]) width = randomly.pop([1, 2, 3, 4], weighted_table=[0.14, 0.43, 0.33, 0.2]) start_rank = randomly.pop([n for n in range(len(ranks_scale))]) result |= {(chosen, generate_decimal(width, ranks_scale, start_rank))} return list(result) elif source_id in ['nothing', 'bypass']: return []
def fs3(): return Sum([Fraction(('+', -7, 10)), Fraction(('-', 11, -15))])
def fp0(): return Product([Fraction((5, 4)), Fraction((5, 5))]) @pytest.fixture
def fs4(): return Sum([Fraction(('+', 3, 4)), Item(-5)])
def fp2(): return Product([Fraction((9, -2)), Fraction((-8, 10))]) @pytest.fixture
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 = random.choices([n + 2 for n in range(19 - 2 + 1)], weights=[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])[0] ten_power_factor1 = 1 ten_power_factor2 = 1 if 'with_ten_powers' in options \ and is_number(options['with_ten_powers']) \ and options['with_ten_powers'] <= 1 \ and options['with_ten_powers'] >= 0: # __ if random.random() < options['with_ten_powers']: ten_powers_list = [10, 10, 100, 100] random.shuffle(ten_powers_list) ten_power_factor1 = ten_powers_list.pop() ten_power_factor2 = ten_powers_list.pop() factors_list = [j + 1 for j in range(10)] random.shuffle(factors_list) self.objct = Fraction(('+', root * factors_list.pop() * ten_power_factor1, root * factors_list.pop() * 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 random.random() < 0: lil_box = [n + 2 for n in range(18)] a = random.choices( lil_box, weights=FRACTION_PRODUCT_AND_QUOTIENT_TABLE)[0] b = random.choices( lil_box, weights=FRACTION_PRODUCT_AND_QUOTIENT_TABLE)[0] lil_box = [n + 2 for n in range(18)] c = random.choices( lil_box, weights=FRACTION_PRODUCT_AND_QUOTIENT_TABLE)[0] d = random.choices( lil_box, weights=FRACTION_PRODUCT_AND_QUOTIENT_TABLE)[0] f1 = Fraction((random.choices(['+', '-'], cum_weights=[0.75, 1])[0], Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], a)), Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], b)))) f2 = Fraction((random.choices(['+', '-'], cum_weights=[0.75, 1])[0], Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], c)), Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], 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 = random.randint(2, 8) lil_box = [i + 2 for i in range(7)] random.shuffle(lil_box) i = lil_box.pop() j = lil_box.pop() b = random.choice(coprimes_to(a * i, [n + 2 for n in range(15)])) c = random.choice(not_coprimes_to(b, [n + 2 for n in range(30)], exclude=[a * j])) f1 = Fraction((random.choices(['+', '-'], cum_weights=[0.75, 1])[0], Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], a * i)), Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], b)))) f2 = Fraction((random.choices(['+', '-'], cum_weights=[0.75, 1])[0], Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], c)), Item((random.choices(['+', '-'], cum_weights=[0.80, 1])[0], a * j)))) if random.choice([True, False]): 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 = random\ .choices([n for n in range(17)], weights=FRACTIONS_SUMS_SCALE_TABLE)[0] chosen_seed_and_generator = FRACTIONS_SUMS_TABLE[randomly_position] seed = random.randint(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 = random.randint(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 = random.randint(1, 20) temp2 = random.randint(1, 20) num1 = Item(temp1 // gcd(temp1, gen1 * seed)) num2 = Item(temp2 // gcd(temp2, gen2 * seed)) f1 = Fraction((random.choices(['+', '-'], cum_weights=[0.7, 1])[0], num1, den1)) f2 = Fraction((random.choices(['+', '-'], cum_weights=[0.7, 1])[0], 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_natural(options['expression_number']): # __ number = options['expression_number'] self.expression = Expression(number, self.objct)