# -*- coding: utf-8 -*-
# Mathmaker creates automatically maths exercises sheets
# with their answers
# Copyright 2006-2017 Nicolas Hainaux <nh.techn@gmail.com>
# This file is part of Mathmaker.
# Mathmaker is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
# Mathmaker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with Mathmaker; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import random
from mathmakerlib.calculus import is_number
from mathmaker.lib.core.base_calculus import Monomial
from .X_Structure import X_Structure
from . import question
AVAILABLE_X_KIND_VALUES = \
{'short_test': ['sign_expansion', 'medium_level',
'three_binomials', 'three_numeric_binomials',
'default'],
'mini_test': ['two_expansions_hard', 'two_randomly'],
'preformatted': ['mixed_monom_polyn1'],
'bypass': ['sign_expansion', 'any_basic_expd', 'sum_of_any_basic_expd',
'sum_square', 'difference_square', 'squares_difference',
'any_binomial', 'polyn1_polyn1', 'two_expansions_hard']}
DEFAULT_RATIO_MIXED_MONOM_POLYN1 = 0.5
X_LAYOUT_UNIT = "cm"
# ---------------------- lines_nb col_widths questions
# In each list, the first number is the number of lines (or the value '?'),
# then follow the columns widths. The tuple contains the questions per cell.
# For instance, [2, 6, 6, 6], (1, 1, 1, 1, 1, 1) means 2 lines, 3 cols (widths
# 6 cm each), then 1 question per cell.
X_LAYOUTS = {'default':
{'exc': [None, 'all'],
'ans': [None, 'all']},
('short_test', 'three_numeric_binomials'):
{'exc': [None, 'all'],
'ans': [[1, 5.5, 5.5], (2, 1)], }}
# ------------------------------------------------------------------------------
# --------------------------------------------------------------------------
# ------------------------------------------------------------------------------
##
# @class X_AlgebraExpressionExpansion
# @brief Expressions to expand (like 2(x-3) or 4x(2-9x) or (3+x)(x-1))
[docs]class X_AlgebraExpressionExpansion(X_Structure):
# --------------------------------------------------------------------------
##
# @brief Constructor.
# @param **options Options detailed below:
# - start_number=<integer>
# (should be >= 1)
# - number_of_questions=<integer>
# /!\ only useful if you use x_kind and not preformatted
# (should be >= 1)
# - x_kind=<string>
# ...
# ...
# - preformatted=<string>
# /!\ preformatted is useless with short_test
# /!\ number_of_questions is useless with preformatted
# /!\ if you use it with the x_kind option, ensure there's a
# preformatted possibility with this option
# 'yes'
# 'OK'
# any other value will be understood as 'no'
# - short_test=bool
# /!\ the x_kind option above can't be used along this option
# use subtype if you need to make different short_test exercises
# 'yes'
# 'OK'
# any other value will be understood as 'no'
# - subtype=<string>
# ...
# ...
# @return One instance of exercise.AlgebraExpressionExpansion
def __init__(self, x_kind='default_nothing', **options):
self.derived = True
X_Structure.__init__(self,
x_kind, AVAILABLE_X_KIND_VALUES, X_LAYOUTS,
X_LAYOUT_UNIT, **options)
# The purpose of this next line is to get the possibly modified
# value of **options
options = self.options
default_question = question.Q_AlgebraExpressionExpansion
# TEXTS OF THE EXERCISE
self.text = {'exc': _("Expand and reduce") + ": ",
'ans': ""}
# alternate texts section
if self.x_subkind == 'three_numeric_binomials':
self.text = {'exc': _("Calculate thanks to a binomial "
"identity:"),
'ans': ""}
# PREFORMATTED EXERCISES
if self.x_kind == 'short_test':
if self.x_subkind == 'sign_expansion':
q = default_question(q_kind='sign_expansion_short_test',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
elif self.x_subkind == 'medium_level':
q = default_question(q_kind='monom01_polyn1',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
q = default_question(q_kind='polyn1_polyn1',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
q = default_question(q_kind='sum_of_any_basic_expd',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
elif self.x_subkind == 'three_binomials':
kinds_list = ['sum_square',
'difference_square',
'squares_difference']
random.shuffle(kinds_list)
for i in range(3):
q = default_question(q_kind=kinds_list.pop(),
expression_number=i,
**options)
self.questions_list.append(q)
elif self.x_subkind == 'three_numeric_binomials':
a_list1 = [20, 30, 40, 50, 60, 70, 80, 90, 100]
a_list2 = [200, 300, 400, 500, 600, 700, 800, 1000]
b_list = [1, 2, 3]
random.shuffle(b_list)
random.shuffle(a_list1)
a1_choice = random.choice(a_list2)
b1_choice = b_list.pop()
a2_choice = a_list1.pop()
b2_choice = b_list.pop()
a3_choice = a_list1.pop()
b3_choice = b_list.pop()
a1 = Monomial(('+', a1_choice, 0))
b1 = Monomial(('+', b1_choice, 0))
a2 = Monomial(('+', a2_choice, 0))
b2 = Monomial(('+', b2_choice, 0))
a3 = Monomial(('+', a3_choice, 0))
b3 = Monomial(('+', b3_choice, 0))
kinds_list = ['numeric_sum_square',
'numeric_difference_square',
'numeric_squares_difference']
random.shuffle(kinds_list)
monomials_to_use = [(a1, b1), (a2, b2), (a3, b3)]
ordered_kinds_list = []
squares_differences_option = [0, 0, 0]
for i in range(3):
ordered_kinds_list.append(kinds_list.pop())
if ordered_kinds_list[i] == 'numeric_difference_square':
monomials_to_use[i][1].set_sign('-')
elif ordered_kinds_list[i] == 'numeric_squares_difference':
squares_differences_option[i] = 1
for i in range(3):
if squares_differences_option[i] == 1:
q = default_question(q_kind=ordered_kinds_list[i],
couple=monomials_to_use[i],
squares_difference=True,
expression_number=i,
**options)
else:
q = default_question(q_kind=ordered_kinds_list[i],
couple=monomials_to_use[i],
expression_number=i,
**options)
self.questions_list.append(q)
else: # default short_test option
if random.choice([True, False]):
q1 = default_question(
q_kind='monom0_polyn1',
expression_number=0 + self.start_number)
q2 = default_question(
q_kind='monom1_polyn1',
expression_number=1 + self.start_number,
reversed='OK')
else:
q1 = default_question(
q_kind='monom0_polyn1',
reversed='OK',
expression_number=0 + self.start_number)
q2 = default_question(
q_kind='monom1_polyn1',
expression_number=1 + self.start_number)
q3 = default_question(q_kind='polyn1_polyn1',
expression_number=2 + self.start_number)
self.questions_list.append(q1)
self.questions_list.append(q2)
self.questions_list.append(q3)
elif self.x_kind == 'mini_test':
if self.x_subkind == 'two_expansions_hard':
if random.choice([True, False]):
q1 = default_question(
q_kind='sum_of_any_basic_expd',
q_subkind='harder',
expression_number=0 + self.start_number)
q2 = default_question(
q_kind='sum_of_any_basic_expd',
q_subkind='with_a_binomial',
expression_number=1 + self.start_number)
else:
q1 = default_question(
q_kind='sum_of_any_basic_expd',
q_subkind='with_a_binomial',
expression_number=0 + self.start_number)
q2 = default_question(
q_kind='sum_of_any_basic_expd',
q_subkind='harder',
expression_number=1 + self.start_number)
self.questions_list.append(q1)
self.questions_list.append(q2)
elif self.x_subkind == 'two_randomly':
if random.choice([True, False]):
q = default_question(q_kind='sign_expansion_short_test',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
q = default_question(
q_kind='polyn1_polyn1',
expression_number=self.start_number + 1,
**options)
self.questions_list.append(q)
else:
q = default_question(q_kind='monom01_polyn1',
expression_number=self.start_number,
**options)
self.questions_list.append(q)
q = default_question(
q_kind='sum_of_any_basic_expd',
q_subkind='easy',
expression_number=self.start_number + 1,
**options)
self.questions_list.append(q)
elif self.x_kind == 'preformatted':
# Mixed expandable expressions from the following types:
# 0-degree Monomial × (1st-degree Polynomial)
# 1-degree Monomial × (1st-degree Polynomial)
# The Monomial & the polynomial may be swapped: it depends
# if the option 'reversed' has been given in
# argument in this method
if self.x_subkind == 'mixed_monom_polyn1':
ratio = DEFAULT_RATIO_MIXED_MONOM_POLYN1
if 'ratio_mmp' in options \
and is_number(options['ratio_mmp']) \
and options['ratio_mmp'] > 0 \
and options['ratio_mmp'] < 1:
# __
ratio = options['ratio_mmp']
choices_list = []
for i in range(int(self.q_nb * ratio) + 1):
choices_list.append('monom0_polyn1')
for i in range(int(self.q_nb - self.q_nb * ratio)):
choices_list.append('monom1_polyn1')
random.shuffle(choices_list)
for i in range(len(choices_list)):
q = default_question(
q_kind=choices_list.pop(),
expression_number=i + self.start_number,
**options)
self.questions_list.append(q)
# OTHER EXERCISES
else:
for i in range(self.q_nb):
q = default_question(
q_kind=self.x_subkind,
expression_number=i + self.start_number,
**options)
self.questions_list.append(q)