mathmaker  0.6(alpha)
mamk_misc/doc/mathmaker4doxygen/sheet/exercise/question/Q_AlgebraExpressionExpansion.py
00001 # -*- coding: utf-8 -*-
00002 
00003 # Mathmaker creates automatically maths exercises sheets
00004 # with their answers
00005 # Copyright 2006-2014 Nicolas Hainaux <nico_h@users.sourceforge.net>
00006 
00007 # This file is part of Mathmaker.
00008 
00009 # Mathmaker is free software; you can redistribute it and/or modify
00010 # it under the terms of the GNU General Public License as published by
00011 # the Free Software Foundation; either version 3 of the License, or
00012 # any later version.
00013 
00014 # Mathmaker is distributed in the hope that it will be useful,
00015 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 # GNU General Public License for more details.
00018 
00019 # You should have received a copy of the GNU General Public License
00020 # along with Mathmaker; if not, write to the Free Software
00021 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023 from lib import *
00024 from lib.common.cst import *
00025 from Q_Structure import Q_Structure
00026 from core.base_calculus import *
00027 from core.calculus import *
00028 
00029 # DON'T FORGET FOR THIS QUESTION TO ALSO DEFINE
00030 # THE INIT CALLER (JUST AFTER AVAILABLE_Q_KIND_VALUES)
00031 AVAILABLE_Q_KIND_VALUES = \
00032     {'monom01_polyn1' : ['default'], # any of the 2 next
00033      'monom0_polyn1' : ['default'], # a×(bx + c)
00034      'monom1_polyn1' : ['default'], # ax×(bx + c)
00035      'polyn1_polyn1' : ['default'], # (ax + b)×(cx + d)
00036      'any_basic_expd' : ['default'], # any of the 3 prev.
00037      'sum_of_any_basic_expd' : ['default', 'easy', 'harder', 'with_a_binomial'],
00038      'sign_expansion' : ['default'],
00039      'sign_expansion_short_test' : ['default'],
00040      'numeric_sum_square' : ['default'],
00041      'numeric_difference_square' : ['default'],
00042      'numeric_squares_difference' : ['default'],
00043      'sum_square' : ['default'], # passed to an __init__()
00044      'difference_square' : ['default'], # idem
00045      'squares_difference' : ['default'],  # idem
00046      'any_binomial' : ['default']   # idem (not really good ?)
00047     }
00048 
00049 INIT_CALLER = \
00050     {'monom01_polyn1' : Expandable,
00051      'monom0_polyn1' : Expandable,
00052      'monom1_polyn1' : Expandable,
00053      'polyn1_polyn1' : Expandable,
00054      'any_basic_expd' : Expandable,
00055      'sum_of_any_basic_expd' : Expandable,
00056      'sign_expansion' : Expandable,
00057      'sign_expansion_short_test' : Expandable,
00058      'numeric_sum_square' : BinomialIdentity,
00059      'numeric_difference_square' : BinomialIdentity,
00060      'numeric_squares_difference' : BinomialIdentity,
00061      'sum_square' : BinomialIdentity,
00062      'difference_square' : BinomialIdentity,
00063      'squares_difference' : BinomialIdentity,
00064      'any_binomial' : BinomialIdentity
00065     }
00066 
00067 # ------------------------------------------------------------------------------
00068 # --------------------------------------------------------------------------
00069 # ------------------------------------------------------------------------------
00070 ##
00071 # @class Q_AlgebraExpressionExpansion
00072 # @brief An object to expand (like 2(x-3), 4x(2-9x), (3+x)(x-1) or (x+1)² etc.)
00073 class Q_AlgebraExpressionExpansion(Q_Structure):
00074 
00075 
00076 
00077 
00078 
00079     # --------------------------------------------------------------------------
00080     ##
00081     #   @brief Constructor
00082     #   @param embedded_machine The machine to be used
00083     #   @param **options Any options
00084     #   @return One instance of question.Q_AlgebraExpressionExpansion
00085     def __init__(self, embedded_machine, q_kind='default_nothing', **options):
00086         self.derived = True
00087 
00088         # The call to the mother class __init__() method will set the
00089         # fields matching optional arguments which are so far :
00090         # self.q_kind, self.q_subkind
00091         # plus self.machine, self.options (modified)
00092         Q_Structure.__init__(self, embedded_machine,
00093                              q_kind, AVAILABLE_Q_KIND_VALUES,
00094                              **options)
00095         # The purpose of this next line is to get the possibly modified
00096         # value of **options
00097         options = self.options
00098 
00099 
00100         init_caller = INIT_CALLER[q_kind]
00101 
00102         self.expandable_objct = None
00103 
00104         self.numeric_aux = None
00105 
00106         if q_kind=='any_basic_expd':
00107             randomly_drawn = randomly.decimal_0_1()
00108             if randomly_drawn <= 0.25:
00109                 self.expandable_objct = Expandable((RANDOMLY,
00110                                                     'monom0_polyn1'),
00111                                                     randomly_reversed=0.5)
00112             elif randomly_drawn <= 0.50:
00113                 self.expandable_objct = Expandable((RANDOMLY,
00114                                                     'monom1_polyn1'),
00115                                                     randomly_reversed=0.5)
00116             else:
00117                 self.expandable_objct = Expandable((RANDOMLY,
00118                                                     'polyn1_polyn1'))
00119 
00120         elif q_kind=='monom0_polyn1' or q_kind=='monom1_polyn1':
00121             self.expandable_objct = Expandable((RANDOMLY,
00122                                                 q_kind),
00123                                                  randomly_reversed=0.5)
00124         elif q_kind=='monom01_polyn1':
00125             self.expandable_objct = Expandable((RANDOMLY,
00126                                             randomly.pop(['monom0_polyn1',
00127                                                           'monom1_polyn1'])),
00128                                             randomly_reversed=0.5)
00129 
00130         elif q_kind=='polyn1_polyn1':
00131             self.expandable_objct = Expandable((RANDOMLY,
00132                                                 'polyn1_polyn1'))
00133 
00134         elif q_kind=='sum_of_any_basic_expd':
00135             if self.q_subkind == 'harder' \
00136                 or self.q_subkind == 'with_a_binomial':
00137             #___
00138                 choices = ['monom0_polyn1', 'monom1_polyn1']
00139 
00140                 drawn_types = list()
00141                 drawn_types.append(randomly.pop(choices))
00142 
00143                 if self.q_subkind == 'with_a_binomial':
00144                     drawn_types.append('any_binomial')
00145                 else:
00146                     drawn_types.append('minus_polyn1_polyn1')
00147 
00148                 aux_expd_list = list()
00149 
00150                 for t in drawn_types:
00151                     if t == 'any_binomial':
00152                         aux_expd_list.append(BinomialIdentity((RANDOMLY,
00153                                                                'any'),
00154                                                                **options))
00155                     else:
00156                         aux_expd_list.append(Expandable((RANDOMLY, t)))
00157 
00158                 final_list = list()
00159                 for i in range(len(aux_expd_list)):
00160                     final_list.append(randomly.pop(aux_expd_list))
00161 
00162                 self.expandable_objct = Sum(final_list)
00163 
00164             elif self.q_subkind == 'easy':
00165                 choices = ['monom0_polyn1', 'monom1_polyn1']
00166 
00167                 aux_expd_list = list()
00168                 aux_expd_list.append(Expandable((RANDOMLY,
00169                                                  randomly.pop(choices)
00170                                                 ))
00171                                     )
00172 
00173                 if randomly.heads_or_tails():
00174                     aux_expd_list.append(Expandable((RANDOMLY, 'sign_exp')))
00175                 else:
00176                     aux_expd_list.append(Monomial((RANDOMLY, 15,
00177                                                    randomly.integer(0,2)
00178                                                   ))
00179                                         )
00180 
00181                 final_list = list()
00182                 for i in range(len(aux_expd_list)):
00183                     final_list.append(randomly.pop(aux_expd_list))
00184 
00185                 self.expandable_objct = Sum(final_list)
00186 
00187             else:
00188                 choices = ['monom0_polyn1', 'monom0_polyn1',
00189                            'monom1_polyn1', 'monom1_polyn1',
00190                            'polyn1_polyn1',
00191                            'minus_polyn1_polyn1']
00192 
00193                 drawn_types = list()
00194                 drawn_types.append(randomly.pop(choices))
00195                 drawn_types.append(randomly.pop(choices))
00196 
00197                 aux_expd_list = list()
00198 
00199                 for element in drawn_types:
00200                     aux_expd_list.append(Expandable((RANDOMLY, element)))
00201 
00202                 aux_expd_list.append(Monomial((RANDOMLY, 15, 2)))
00203 
00204                 final_list = list()
00205                 for i in range(len(aux_expd_list)):
00206                     final_list.append(randomly.pop(aux_expd_list))
00207 
00208                 self.expandable_objct = Sum(final_list)
00209 
00210         elif q_kind=='sign_expansion' or q_kind=='sign_expansion_short_test':
00211         #___
00212             sign_exp_kind = 0
00213 
00214             if 'sign_exp_kind' in options:
00215                 sign_exp_kind = options['sign_exp_kind']
00216 
00217             if q_kind=='sign_expansion_short_test':
00218                 sign_exp_kind = 1
00219 
00220             if sign_exp_kind == 0:
00221                 sign_exp_kind = randomly.integer(1, 5)
00222 
00223             # Creation of the terms
00224             aux_terms_list = list()
00225 
00226             aux_expd_1 = Expandable((Monomial((randomly.sign(), 1, 0)),
00227                                      Polynomial((RANDOMLY, 15, 2, 2))
00228                                    ))
00229 
00230             aux_expd_2 = Expandable((Monomial((randomly.sign(), 1, 0)),
00231                                      Polynomial((RANDOMLY, 15, 2, 2))
00232                                    ))
00233 
00234             aux_expd_3 = Expandable((Monomial((randomly.sign(), 1, 0)),
00235                                      Polynomial((RANDOMLY, 15, 2, 2))
00236                                    ))
00237 
00238             long_aux_expd = Expandable((Monomial((randomly.sign(), 1, 0)),
00239                                         Polynomial((RANDOMLY, 15, 2, 3))
00240                                       ))
00241 
00242             if q_kind=='sign_expansion_short_test':
00243                 long_aux_expd = Expandable((Monomial(('-', 1, 0)),
00244                                             Polynomial((RANDOMLY, 15, 2, 3))
00245                                           ))
00246 
00247             aux_monomial = Monomial((RANDOMLY, 15, 2))
00248 
00249             # 1st kind : a Monomial and ± (long Polynomial)
00250             # (like in a short test)
00251             if sign_exp_kind == 1:
00252                 aux_terms_list.append(long_aux_expd)
00253                 aux_terms_list.append(aux_monomial)
00254 
00255             # 2d kind : ± (x+3) ± (4x - 7)
00256             elif sign_exp_kind == 2:
00257                 aux_terms_list.append(aux_expd_1)
00258                 aux_terms_list.append(aux_expd_2)
00259 
00260             # 3d kind : ± (x+3) ± (4x - 7) ± (x² - 5x)
00261             elif sign_exp_kind == 3:
00262                 aux_terms_list.append(aux_expd_1)
00263                 aux_terms_list.append(aux_expd_2)
00264                 aux_terms_list.append(aux_expd_3)
00265 
00266             # 4th kind : ± (x+3) ± (4x - 7) ± Monomial
00267             elif sign_exp_kind == 4:
00268                 aux_terms_list.append(aux_expd_1)
00269                 aux_terms_list.append(aux_expd_2)
00270                 aux_terms_list.append(aux_monomial)
00271 
00272             # 5th kind : ± (x+3) ± Monomial ± (long Polynomial)
00273             elif sign_exp_kind == 5:
00274                 aux_terms_list.append(aux_expd_2)
00275                 aux_terms_list.append(aux_monomial)
00276                 aux_terms_list.append(long_aux_expd)
00277 
00278             # add as many possibilities as wanted,
00279             # don't forget to increase the last number here :
00280             # sign_exp_kind = randomly.integer(1, 5) (what's a bit above)
00281 
00282             # Now let's distribute the terms randomly
00283             final_terms_list = list()
00284             for i in range(len(aux_terms_list)):
00285                 final_terms_list.append(randomly.pop(aux_terms_list))
00286 
00287             self.expandable_objct = Sum(final_terms_list)
00288 
00289         elif q_kind == 'numeric_sum_square' \
00290             or q_kind == 'numeric_difference_square' \
00291             or q_kind == 'numeric_squares_difference':
00292         #___
00293             self.expandable_objct = init_caller((options['couple'][0],
00294                                                  options['couple'][1]),
00295                                                  **options)
00296             if q_kind == 'numeric_sum_square' \
00297                 or q_kind == 'numeric_difference_square':
00298             #___
00299                 self.numeric_aux = Sum([options['couple'][0],
00300                                                  options['couple'][1]
00301                                                 ]).reduce_()
00302                 self.numeric_aux.set_exponent(2)
00303 
00304             else: # squares_difference's case
00305                 aux1 = Sum([options['couple'][0],
00306                                      options['couple'][1]
00307                                     ]).reduce_()
00308                 temp = options['couple'][1].clone()
00309                 temp.set_sign('-')
00310                 aux2 = Sum([options['couple'][0],
00311                                      temp
00312                                     ]).reduce_()
00313                 self.numeric_aux = Product([aux1, aux2])
00314 
00315         else:
00316             if q_kind == 'any_binomial':
00317                 q_kind = 'any'
00318 
00319             self.expandable_objct = init_caller((RANDOMLY, q_kind),
00320                                                  **options)
00321 
00322 
00323 
00324         # Creation of the expression :
00325         number = 0
00326         if 'expression_number' in options                                     \
00327            and is_.a_natural_int(options['expression_number']):
00328         #___
00329             number = options['expression_number']
00330         self.expression = Expression(number, self.expandable_objct)
00331         if self.numeric_aux != None:
00332             self.numeric_aux = Expression(number, self.numeric_aux)
00333 
00334 
00335 
00336 
00337 
00338 
00339     # --------------------------------------------------------------------------
00340     ##
00341     #   @brief Returns the text of the question as a str
00342     def text_to_str(self):
00343         M = self.machine
00344 
00345         result = ""
00346 
00347         if self.q_kind == 'numeric_sum_square' \
00348             or self.q_kind == 'numeric_difference_square' \
00349             or self.q_kind == 'numeric_squares_difference':
00350         #___
00351             result += M.write_math_style2(M.type_string(self.numeric_aux))
00352 
00353         else:
00354             result += M.write_math_style2(M.type_string(self.expression))
00355 
00356         result += M.write_new_line()
00357 
00358         return result
00359 
00360 
00361 
00362 
00363 
00364 
00365 
00366     # --------------------------------------------------------------------------
00367     ##
00368     #   @brief Returns the answer of the question as a str
00369     def answer_to_str(self):
00370         M = self.machine
00371 
00372         result = ""
00373 
00374         if self.q_kind == 'numeric_sum_square' \
00375             or self.q_kind == 'numeric_difference_square' \
00376             or self.q_kind == 'numeric_squares_difference':
00377         #___
00378             result += M.write_math_style2(M.type_string(self.numeric_aux))
00379             result += M.write_new_line()
00380 
00381         result += M.write(self.expression.auto_expansion_and_reduction())
00382 
00383         return result
00384 
00385 
00386 
00387 
00388 
00389