示例#1
0
    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')
示例#4
0
    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
示例#5
0
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)
示例#6
0
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)
示例#7
0
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)
示例#8
0
    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
示例#10
0
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))
示例#11
0
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))
示例#12
0
    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])
示例#13
0
    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)
示例#14
0
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
示例#16
0
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)
示例#17
0
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)
示例#18
0
def expD():
    t = Expandable((Item(-1), Sum([Monomial((3, 1)), Item(-2)])))
    return Expression("D", t)
示例#19
0
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)
示例#20
0
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)
示例#21
0
def expJ():
    t = BinomialIdentity((Item(3), Monomial(('+', 3, 1))),
                         squares_difference=True)
    return Expression("J", t)
示例#22
0
def expK():
    t = BinomialIdentity((Item(1), Monomial(('+', 10, 1))),
                         squares_difference=True)
    return Expression("K", t)
示例#23
0
def expL():
    t = Sum([Item(-2), Monomial(('-', 1, 1)),
             Monomial(('+', 8, 2)), Monomial(('+', 1, 1))])
    return Expression("L", t)
示例#24
0
def expM():
    t = Sum([Monomial((-15, 0)), Expandable((Item(1),
                                             Sum([Item(10),
                                                  Monomial((14, 1)),
                                                  Monomial(('-', 10, 2))])))])
    return Expression("M", t)
示例#25
0
def expA():
    t = Expandable((Item(2), Sum([Item(1), Monomial((5, 1))])))
    return Expression("A", t)
示例#26
0
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