mathmaker  0.6(alpha)
mamk_misc/doc/mathmaker4doxygen/sheet/exercise/question/Q_Factorization.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 Q_Structure import Q_Structure
00025 
00026 from core.base_calculus import *
00027 from core.calculus import *
00028 from lib.common.cst import *
00029 
00030 AVAILABLE_Q_KIND_VALUES = {'level_01':['default',
00031                                        'ax + b',
00032                                        'ax² + b',
00033                                        'ax² + bx',
00034                                        'three_terms',
00035                                        'not_factorizable',
00036                                        'mixed',
00037                                        'mixed_factorizable'],
00038 
00039                           # C : common factor
00040                           # F1 & F2 : the other factors
00041                           # deg1 and deg2 represent polynoms
00042                           # of 1st and 2d degree
00043                           # F1 and F2 will be randomly exchanged at creation
00044                           # of the expression, so a case like a×deg1 + a×deg2
00045                           # contains also a×deg2 + a×deg1
00046 
00047                           # C × F1  ±  C × F2
00048 
00049  'level_02':['default',   # synonym to type_123
00050              'type_123',  # any of type_1, type_2, type_3 (a polynom as
00051                           #                                   common factor)
00052              'type_1',    # any of type_1_*
00053              'type_1_ABC', # any of type 1 A, B and C cases
00054              'type_1_DEF', # any of type 1 D, E and F cases
00055              'type_1_GHI', # any of type 1 G, H and I cases
00056              'type_1_A',  # any of A1 or A0
00057              'type_1_B',  # any of B1 or B0
00058              'type_1_C',  # synonym to C0
00059              'type_1_D',  # any of D1 or D0
00060              'type_1_E',  # .
00061              'type_1_F',  # .
00062              'type_1_G',  # .
00063              'type_1_H',  # .
00064              'type_1_I',  # .
00065              'type_1_0',  # any of type_1_*0 cases
00066              'type_1_1',  # any of type_1_*1 cases
00067              'type_1_A0', # a×deg1 + a×deg1' (deg* : at least 2 terms & a!=1)
00068              'type_1_B0', # a×deg2 + a×deg2' (deg* : at least 2 terms & a!=1)
00069              'type_1_C0', # a×deg1 + a×deg2 (deg* : at least 2 terms & a!=1)
00070              'type_1_D0', # ax×deg1 + ax×deg1' (deg* : at least 2 terms)
00071              'type_1_E0', # ax×deg2 + ax×deg2' (deg* : at least 2 terms)
00072              'type_1_F0', # ax×deg1 + ax×deg2 (deg* : at least 2 terms)
00073              'type_1_G0', # ax²×deg1 + ax²×deg1' (deg* : at least 2 terms)
00074              'type_1_H0', # ax²×deg2 + ax²×deg2' (deg* : at least 2 terms)
00075              'type_1_I0', # ax²×deg1 + ax²×deg2 (deg* : at least 2 terms)
00076              'type_1_A1', # a×deg1 + a×1
00077              'type_1_B1', # a×deg2 + a×1
00078              #'type_1_C1', # C1 has no sense
00079              'type_1_D1', # ax×deg1 + ax×1
00080              'type_1_E1', # ax×deg2 + ax×1
00081              #'type_1_F1', # F1 has no sense
00082              'type_1_G1', # ax²×deg1 + ax²×1
00083              'type_1_H1', # ax²×deg2 + ax²×1
00084              #'type_1_I1', # I1 has no sense
00085 
00086              'type_2',    # any of type_2_*
00087              'type_2_ABC', # any of type 2 A, B and C cases
00088              'type_2_DEF', # any of type 2 D, E and F cases
00089              'type_2_A',  # any of A1 or A0
00090              'type_2_B',  # any of B1 or B0
00091              'type_2_C',  # synonym to C0
00092              'type_2_D',  # any of D1 or D0
00093              'type_2_E',  # .
00094              'type_2_F',  # .
00095              'type_2_0',  # any of type_2_*0 cases
00096              'type_2_1',  # any of type_2_*1 cases
00097              'type_2_A0', # (ax+b)×deg1 + (ax+b)×deg1'
00098              'type_2_B0', # (ax+b)×deg2 + (ax+b)×deg2'
00099              'type_2_C0', # (ax+b)×deg1 + (ax+b)×deg2
00100              'type_2_D0', # (ax²+b)×deg1 + (ax²+b)×deg1'
00101              'type_2_E0', # (ax²+b)×deg2 + (ax²+b)×deg2'
00102              'type_2_F0', # (ax²+b)×deg1 + (ax²+b)×deg2
00103              'type_2_A1', # (ax+b)×deg1 + (ax+b)×1
00104              'type_2_B1', # (ax+b)×deg2 + (ax+b)×1
00105              #'type_2_C1', # C1 has no sense
00106              'type_2_D1', # (ax²+b)×deg1 + (ax²+b)×1
00107              'type_2_E1', # (ax²+b)×deg2 + (ax²+b)×1
00108              #'type_2_F1', # F1 has no sense
00109 
00110              'type_3',    # any of type_3_*
00111              'type_3_ABC', # any of type 3 A, B and C cases
00112              'type_3_A',  # any of A1 or A0
00113              'type_3_B',  # any of B1 or B0
00114              'type_3_C',  # synonym to C0
00115              'type_3_0',   # any of type_3_*0 cases
00116              'type_3_1'   # any of type_3_*1 cases
00117              'type_3_A0', # (ax²+bx+c)×deg1 + (ax²+bx+c)×deg1'
00118              'type_3_B0', # (ax²+bx+c)×deg2 + (ax²+bx+c)×deg2'
00119              'type_3_C0', # (ax²+bx+c)×deg1 + (ax²+bx+c)×deg2
00120              'type_3_A1', # (ax²+bx+c)×deg1 + (ax²+bx+c)×1
00121              'type_3_B1', # (ax²+bx+c)×deg2 + (ax²+bx+c)×1
00122              #'type_3_C1' # C1 has no sense
00123 
00124              'type_4_A0'  # (ax+b)²×deg1 + (ax+b)×deg1'
00125 
00126              ],
00127 
00128 
00129            # Here are the binomial identities
00130 
00131 'level_03':['default',   # synonym to 'any'
00132             'any',
00133             'any_mixed',              # any but from the mixed types
00134                                       # (order of the terms is changed)
00135             'any_straight',           # any but not from a mixed type
00136             'any_true',               # any that can be factorized
00137             'any_fake',               # any that cannot be factorized
00138             'any_true_straight',      # any that can be factorized, not mixed
00139             'any_fake_straight',      # any that cannot be factorized, not mixed
00140             'any_true_mixed',         # any that can be factorized, mixed
00141             'any_fake_mixed',         # any that cannot be factorized, mixed
00142             'sum_square',               # (ax)² + 2abx + b²
00143             'sum_square_mixed',         # like above but terms' order is changed
00144             'difference_square',        # (ax)² - 2abx + b²
00145             'difference_square_mixed',  # like above but terms' order is changed
00146             'squares_difference',       # (ax)² - b²
00147             'squares_difference_mixed', # like above but terms' order is changed
00148             'fake_01',       # 2×a×b doesn't match a² and b² (sum)
00149             'fake_01_mixed', # 2×a×b doesn't match a² and b² (sum, mixed)
00150             'fake_02',       # 2×a×b doesn't match a² and b² (difference)
00151             'fake_02_mixed', # 2×a×b doesn't match a² and b² (difference, mixed)
00152             'fake_03',       # (ax)² + b²
00153             'fake_03_mixed', # b² + (ax)²
00154             'fake_04_any',   # any of fake_04 (signs don't match a binomial)
00155             'fake_04_any_straight',
00156             'fake_04_any_mixed',
00157             'fake_04_A',        #  (ax)² + 2abx - b²
00158             'fake_04_A_mixed',
00159             'fake_04_B',        # -(ax)² + 2abx + b²
00160             'fake_04_B_mixed',
00161             'fake_04_C',        #  (ax)² - 2abx - b²
00162             'fake_04_C_mixed',
00163             'fake_04_D',        # -(ax)² - 2abx + b²
00164             'fake_04_D_mixed'
00165            ]
00166 
00167 
00168 }
00169 
00170 
00171 
00172 # ------------------------------------------------------------------------------
00173 # --------------------------------------------------------------------------
00174 # ------------------------------------------------------------------------------
00175 ##
00176 # @class Q_Factorization
00177 # @brief Question related to the factorization of a literal expression
00178 class Q_Factorization(Q_Structure):
00179 
00180 
00181 
00182 
00183 
00184     # --------------------------------------------------------------------------
00185     ##
00186     #   @brief Constructor.
00187     #   @param embedded_machine The machine to be used
00188     #   @param **options Any options
00189     #   @return One instance of question.Q_Factorization
00190     def __init__(self, embedded_machine, q_kind='default_nothing', **options):
00191         self.derived = True
00192 
00193         # The call to the mother class __init__() method will set the
00194         # fields matching optional arguments which are so far :
00195         # self.q_kind, self.q_subkind
00196         # plus self.machine, self.options (modified)
00197         Q_Structure.__init__(self, embedded_machine,
00198                              q_kind, AVAILABLE_Q_KIND_VALUES,
00199                              **options)
00200         # The purpose of this next line is to get the possibly modified
00201         # value of **options
00202         options = self.options
00203         q_subkind = self.q_subkind
00204 
00205         # That's the number of the question, not of the expressions it might
00206         # contain !
00207         self.number = ""
00208 
00209         steps_method = None
00210 
00211         if q_kind == 'level_01':
00212             steps_method = level_01
00213 
00214             if q_subkind == 'mixed':
00215                 q_subkind = randomly.pop(['default',
00216                                         'three_terms',
00217                                         'not_factorizable'])
00218             elif q_subkind == 'mixed_factorizable':
00219                 q_subkind = randomly.pop(['default',
00220                                         'three_terms'])
00221 
00222             #steps = level_01(subkind)
00223 
00224         elif q_kind == 'level_02':
00225             steps_method = level_02
00226 
00227             if q_subkind == 'default':
00228                 q_subkind = 'type_123'
00229 
00230             if q_subkind == 'type_123':
00231                 q_subkind = randomly.pop(['type_1', 'type_2', 'type_3'])
00232 
00233             if q_subkind == 'type_1':
00234                 q_subkind = randomly.pop(['type_1_ABC',
00235                                         'type_1_DEF',
00236                                         'type_1_GHI'])
00237 
00238             if q_subkind == 'type_1_ABC':
00239                 q_subkind = randomly.pop(['type_1_A',
00240                                         'type_1_B',
00241                                         'type_1_C'])
00242 
00243             if q_subkind == 'type_1_DEF':
00244                 q_subkind = randomly.pop(['type_1_D',
00245                                         'type_1_E',
00246                                         'type_1_F'])
00247 
00248             if q_subkind == 'type_1_GHI':
00249                 q_subkind = randomly.pop(['type_1_G',
00250                                         'type_1_H',
00251                                         'type_1_I'])
00252 
00253             if q_subkind == 'type_1_A':
00254                 q_subkind = randomly.pop(['type_1_A0',
00255                                         'type_1_A1'])
00256             if q_subkind == 'type_1_B':
00257                 q_subkind = randomly.pop(['type_1_B0',
00258                                         'type_1_B1'])
00259             if q_subkind == 'type_1_C':
00260                 q_subkind = 'type_1_C0'
00261 
00262             if q_subkind == 'type_1_D':
00263                 q_subkind = randomly.pop(['type_1_D0',
00264                                         'type_1_D1'])
00265             if q_subkind == 'type_1_E':
00266                 q_subkind = randomly.pop(['type_1_E0',
00267                                         'type_1_E1'])
00268             if q_subkind == 'type_1_F':
00269                 q_subkind = 'type_1_F0'
00270 
00271             if q_subkind == 'type_1_G':
00272                 q_subkind = randomly.pop(['type_1_G0',
00273                                         'type_1_G1'])
00274             if q_subkind == 'type_1_H':
00275                 q_subkind = randomly.pop(['type_1_H0',
00276                                         'type_1_H1'])
00277             if q_subkind == 'type_1_I':
00278                 q_subkind = 'type_1_I0'
00279 
00280             if q_subkind == 'type_1_0':
00281                 q_subkind = randomly.pop(['type_1_A0',
00282                                         'type_1_B0',
00283                                         'type_1_C0',
00284                                         'type_1_D0',
00285                                         'type_1_E0',
00286                                         'type_1_F0',
00287                                         'type_1_G0',
00288                                         'type_1_H0',
00289                                         'type_1_I0'])
00290 
00291             if q_subkind == 'type_1_1':
00292                 q_subkind = randomly.pop(['type_1_A1',
00293                                         'type_1_B1',
00294                                         'type_1_D1',
00295                                         'type_1_E1',
00296                                         'type_1_G1',
00297                                         'type_1_H1'])
00298 
00299             if q_subkind == 'type_2':
00300                 q_subkind = randomly.pop(['type_2_ABC',
00301                                         'type_2_DEF'])
00302 
00303             if q_subkind == 'type_2_ABC':
00304                 q_subkind = randomly.pop(['type_2_A',
00305                                         'type_2_B',
00306                                         'type_2_C'])
00307 
00308             if q_subkind == 'type_2_DEF':
00309                 q_subkind = randomly.pop(['type_2_D',
00310                                         'type_2_E',
00311                                         'type_2_F'])
00312 
00313             if q_subkind == 'type_2_A':
00314                 q_subkind = randomly.pop(['type_2_A0',
00315                                         'type_2_A1'])
00316             if q_subkind == 'type_2_B':
00317                 q_subkind = randomly.pop(['type_2_B0',
00318                                         'type_2_B1'])
00319             if q_subkind == 'type_2_C':
00320                 q_subkind = 'type_2_C0'
00321 
00322             if q_subkind == 'type_2_D':
00323                 q_subkind = randomly.pop(['type_2_D0',
00324                                         'type_2_D1'])
00325             if q_subkind == 'type_2_E':
00326                 q_subkind = randomly.pop(['type_2_E0',
00327                                         'type_2_E1'])
00328             if q_subkind == 'type_2_F':
00329                 q_subkind = 'type_2_F0'
00330 
00331             if q_subkind == 'type_2_0':
00332                 q_subkind = randomly.pop(['type_2_A0',
00333                                         'type_2_B0',
00334                                         'type_2_C0',
00335                                         'type_2_D0',
00336                                         'type_2_E0',
00337                                         'type_2_F0'])
00338 
00339             if q_subkind == 'type_2_1':
00340                 q_subkind = randomly.pop(['type_2_A1',
00341                                         'type_2_B1',
00342                                         'type_2_D1',
00343                                         'type_2_E1'])
00344 
00345             if q_subkind == 'type_3':
00346                 q_subkind = 'type_3_ABC'
00347 
00348             if q_subkind == 'type_3_ABC':
00349                 q_subkind = randomly.pop(['type_3_A',
00350                                         'type_3_B',
00351                                         'type_3_C'])
00352 
00353             if q_subkind == 'type_3_A':
00354                 q_subkind = randomly.pop(['type_3_A0',
00355                                         'type_3_A1'])
00356             if q_subkind == 'type_3_B':
00357                 q_subkind = randomly.pop(['type_3_B0',
00358                                         'type_3_B1'])
00359             if q_subkind == 'type_3_C':
00360                 q_subkind = 'type_3_C0'
00361 
00362             if q_subkind == 'type_3_0':
00363                 q_subkind = randomly.pop(['type_3_A0',
00364                                         'type_3_B0',
00365                                         'type_3_C0'])
00366 
00367             if q_subkind == 'type_3_1':
00368                 q_subkind = randomly.pop(['type_3_A1',
00369                                         'type_3_B1'])
00370 
00371 
00372 
00373             #steps = level_02(subkind, **options)
00374 
00375         elif q_kind == 'level_03':
00376             steps_method = level_03
00377             options['markup'] = self.machine.markup
00378 
00379             if q_subkind == 'any' or q_subkind == 'default':
00380                 q_subkind = randomly.pop(['any_straight',
00381                                           'any_mixed'])
00382 
00383             if q_subkind == 'any_straight':
00384                 q_subkind = randomly.pop(['any_true_straight',
00385                                           'any_fake_straight'])
00386 
00387             if q_subkind == 'any_mixed':
00388                 q_subkind = randomly.pop(['any_true_mixed',
00389                                           'any_fake_mixed'])
00390 
00391             if q_subkind == 'any_true':
00392                 q_subkind = randomly.pop(['any_true_straight',
00393                                           'any_true_mixed'])
00394 
00395             if q_subkind == 'any_fake':
00396                 q_subkind = randomly.pop(['any_fake_straight',
00397                                           'any_fake_mixed'])
00398 
00399             if q_subkind == 'any_true_straight':
00400                 q_subkind = randomly.pop(['sum_square',
00401                                           'difference_square',
00402                                           'squares_difference'])
00403 
00404             if q_subkind == 'any_fake_straight':
00405                 q_subkind = randomly.pop(['fake_01',
00406                                           'fake_02',
00407                                           'fake_03',
00408                                           'fake_04_any_straight'])
00409 
00410             if q_subkind == 'any_true_mixed':
00411                 q_subkind = randomly.pop(['sum_square_mixed',
00412                                           'difference_square_mixed',
00413                                           'squares_difference_mixed'])
00414 
00415             if q_subkind == 'any_fake_mixed':
00416                 q_subkind = randomly.pop(['fake_01_mixed',
00417                                           'fake_02_mixed',
00418                                           'fake_03_mixed',
00419                                           'fake_04_any_mixed'])
00420 
00421             if q_subkind == 'fake_04_any':
00422                 q_subkind = randomly.pop(['fake_04_any_mixed',
00423                                           'fake_04_any_straight'])
00424 
00425             if q_subkind == 'fake_04_any_mixed':
00426                 q_subkind = randomly.pop(['fake_04_A_mixed',
00427                                           'fake_04_B_mixed',
00428                                           'fake_04_C_mixed',
00429                                           'fake_04_D_mixed'])
00430 
00431             if q_subkind == 'fake_04_any_straight':
00432                 q_subkind = randomly.pop(['fake_04_A',
00433                                           'fake_04_B',
00434                                           'fake_04_C',
00435                                           'fake_04_D'])
00436 
00437 
00438 
00439 
00440         steps = steps_method(q_subkind, **options)
00441 
00442 
00443 
00444 
00445         # Creation of the expression :
00446         number = 0
00447         if 'expression_number' in options                                 \
00448            and is_.a_natural_int(options['expression_number']):
00449         #___
00450             number = options['expression_number']
00451         self.expression = Expression(number, steps[0])
00452 
00453         # Putting the steps and the solution together :
00454         self.steps = []
00455 
00456         #for i in xrange(len(steps) - 1):
00457         #    self.steps.append(Expression(number,
00458         #                                          steps[i]
00459         #                                          )
00460         #                     )
00461         #
00462         #solution = steps[len(steps) - 1]
00463         #
00464         #if isinstance(solution, Exponented):
00465         #    self.steps.append(Expression(number,
00466         #                                          solution
00467         #                                          )
00468         #                     )
00469         #else:
00470         #    self.steps.append(solution)
00471 
00472         for i in range(len(steps)):
00473             if isinstance(steps[i], Exponented):
00474                 self.steps.append(Expression(number,
00475                                                       steps[i]
00476                                                       )
00477                                  )
00478             else:
00479                 self.steps.append(steps[i])
00480 
00481 
00482 
00483 
00484 
00485     # --------------------------------------------------------------------------
00486     ##
00487     #   @brief Returns the text of the question as a str
00488     def text_to_str(self):
00489         M = self.machine
00490 
00491         result = M.write_math_style2(M.type_string(self.expression))
00492         result += M.write_new_line()
00493 
00494         return result
00495 
00496 
00497 
00498 
00499 
00500 
00501     # --------------------------------------------------------------------------
00502     ##
00503     #   @brief Returns the answer of the question as a str
00504     def answer_to_str(self):
00505         M = self.machine
00506 
00507         result = ""
00508 
00509         for i in range(len(self.steps)):
00510             if type(self.steps[i]) == str:
00511                 result += M.write(self.steps[i])
00512             else:
00513                 result += M.write_math_style2(M.type_string(self.steps[i]))
00514             result += M.write_new_line()
00515 
00516         return result
00517 
00518 
00519 
00520 
00521 
00522 # --------------------------------------------------------------------------
00523 ##
00524 #   @brief Creates & returns the solution and the answer's steps.
00525 #   @return steps (list containing the steps)
00526 def level_01(q_subkind, **options):
00527     if q_subkind == 'default' \
00528        or q_subkind == 'three_terms' \
00529        or q_subkind == 'ax + b' \
00530        or q_subkind == 'ax² + b' \
00531        or q_subkind == 'ax² + bx' :
00532     #___
00533         # the idea is to build the final factorized result first and to
00534         # expand it to get the question (and the solution's steps
00535         # in the same time)
00536 
00537         if q_subkind == 'default':
00538             common_factor = Monomial((RANDOMLY, 6, 1))
00539             # In order to reduce the number of cases where x² appears,
00540             # let the common factor be of degree 0 most of the time.
00541             common_factor.set_degree(randomly.integer(0,
00542                                                       1,
00543                                                       weighted_table=[0.85,
00544                                                                       0.15])
00545                                     )
00546 
00547         elif q_subkind == 'three_terms' \
00548             or q_subkind == 'ax + b' \
00549             or q_subkind == 'ax² + b':
00550         #___
00551             common_factor = Monomial((RANDOMLY, 6, 0))
00552 
00553         elif q_subkind == 'ax² + bx':
00554             common_factor = Monomial((RANDOMLY, 6, 1))
00555             common_factor.set_degree(1)
00556 
00557         # to avoid having a situation like 1×(2x + 3) which isn't
00558         # factorizable :
00559         if common_factor.get_degree() == 0:
00560             common_factor.set_coeff(randomly.integer(2, 6))
00561 
00562 
00563         # signs are randomly chosen ; the only case that is to be avoided
00564         # is all signs are negative (then it wouldn't factorize well...
00565         # I mean then the '-' should be factorized and not left in the final
00566         # result)
00567         signs_box = [['+', '+'], ['+', '-']]
00568         signs = randomly.pop(signs_box)
00569 
00570         # this next test is to avoid -2x + 6 being factorized -2(x - 3)
00571         # which is not wrong but not "natural" to pupils
00572         # this test should be changed when a third term is being used.
00573         if signs == ['+', '-']:
00574             common_factor.set_sign('+')
00575 
00576         coeff_1 = randomly.integer(2, 10)
00577         coeff_2 = randomly.coprime_to(coeff_1, [i + 1 for i in range(10)])
00578         coeff_3 = None
00579 
00580         if q_subkind == 'three_terms':
00581             coeff_3 = randomly.coprime_to(coeff_1 * coeff_2,
00582                                           [i + 1 for i in range(9)])
00583             third_sign = randomly.sign()
00584             if third_sign == '-':
00585                 common_factor.set_sign('+')
00586 
00587             signs.append(third_sign)
00588 
00589         lil_box = []
00590         lil_box.append(Monomial(('+', 1, 0)))
00591 
00592         if q_subkind == 'ax² + b':
00593             lil_box.append(Monomial(('+', 1, 2)))
00594         else:
00595             lil_box.append(Monomial(('+', 1, 1)))
00596 
00597         if (common_factor.get_degree() == 0 \
00598            and randomly.integer(1, 20) > 17 \
00599            and q_subkind == 'default') \
00600            or q_subkind == 'three_terms':
00601         #___
00602             lil_box.append(Monomial(('+', 1, 2)))
00603 
00604         first_term = randomly.pop(lil_box)
00605         second_term = randomly.pop(lil_box)
00606         third_term = None
00607 
00608 
00609         first_term.set_coeff(coeff_1)
00610         first_term.set_sign(randomly.pop(signs))
00611         second_term.set_coeff(coeff_2)
00612         second_term.set_sign(randomly.pop(signs))
00613 
00614         if q_subkind == 'three_terms':
00615             third_term = randomly.pop(lil_box)
00616             third_term.set_coeff(coeff_3)
00617             third_term.set_sign(randomly.pop(signs))
00618             if first_term.is_positive() and second_term.is_positive()\
00619                and third_term.is_positive():
00620             #___
00621                 common_factor.set_sign(randomly.sign())
00622 
00623         if not (q_subkind == 'three_terms'):
00624             if common_factor.get_degree() == 0 \
00625                and first_term.get_degree() >= 1 \
00626                and second_term.get_degree() >= 1:
00627             #___
00628                 if randomly.heads_or_tails():
00629                     first_term.set_degree(0)
00630                 else:
00631                     second_term.set_degree(0)
00632 
00633         if q_subkind == 'three_terms':
00634             solution = Expandable((common_factor,
00635                                    Sum([first_term,
00636                                         second_term,
00637                                         third_term])))
00638 
00639         else:
00640             solution = Expandable((common_factor,
00641                                    Sum([first_term,
00642                                         second_term])))
00643 
00644         # now create the expanded step and the reduced step (which will
00645         # be given as a question)
00646         temp_steps = []
00647         current_step = solution.clone()
00648 
00649         while current_step != None:
00650             temp_steps.append(current_step)
00651             current_step = current_step.expand_and_reduce_next_step()
00652 
00653         # now we put the steps in the right order
00654         steps = []
00655         for i in range(len(temp_steps)):
00656             steps.append(temp_steps[len(temp_steps) - 1 - i])
00657 
00658         return steps
00659 
00660     elif q_subkind == 'not_factorizable':
00661         signs_box = [['+', '+'], ['+', '-']]
00662         signs = randomly.pop(signs_box)
00663 
00664         coeff_1 = randomly.integer(2, 10)
00665         coeff_2 = randomly.coprime_to(coeff_1, [i + 1 for i in range(10)])
00666 
00667         lil_box = []
00668         lil_box.append(Monomial(('+', 1, 0)))
00669         lil_box.append(Monomial(('+', 1, 1)))
00670         lil_box.append(Monomial(('+', 1, 2)))
00671 
00672         first_term = randomly.pop(lil_box)
00673         second_term = randomly.pop(lil_box)
00674 
00675         first_term.set_coeff(coeff_1)
00676         first_term.set_sign(randomly.pop(signs))
00677 
00678         second_term.set_coeff(coeff_2)
00679         second_term.set_sign(randomly.pop(signs))
00680 
00681         if first_term.get_degree() >= 1 \
00682            and second_term.get_degree() >= 1:
00683         #___
00684             if randomly.heads_or_tails():
00685                 first_term.set_degree(0)
00686             else:
00687                 second_term.set_degree(0)
00688 
00689         steps = []
00690         solution = \
00691         _("So far, we don't know if this expression can be factorized.")
00692         steps.append(Sum([first_term, second_term]))
00693         steps.append(solution)
00694 
00695         return steps
00696 
00697 
00698 
00699 
00700 
00701 # --------------------------------------------------------------------------
00702 ##
00703 #   @brief Creates & returns the solution and the answer's steps.
00704 #   @return steps (list containing the steps)
00705 def level_02(q_subkind, **options):
00706 
00707     max_coeff = 20
00708 
00709     if 'max_coeff' in options and is_.an_integer(options['max_coeff']):
00710         max_coeff = options['max_coeff']
00711 
00712     attribute_a_minus_sign = 'randomly'
00713 
00714     if 'minus_sign' in options \
00715        and (options['minus_sign'] == 'yes' \
00716             or options['minus_sign'] == 'OK'):
00717     #___
00718         attribute_a_minus_sign = 'yes'
00719 
00720     elif 'minus_sign' in options \
00721          and (options['minus_sign'] == 'no'):
00722     #___
00723         attribute_a_minus_sign = 'no'
00724 
00725     # Creation of the objects
00726 
00727     # The three Monomials : ax², bx and c
00728     # Maybe we don't need to keep the integer values...
00729     a_val = randomly.integer(1, max_coeff)
00730     b_val = randomly.integer(1, max_coeff)
00731     c_val = randomly.integer(1, max_coeff)
00732 
00733     if q_subkind == 'type_1_A0' \
00734        or q_subkind == 'type_1_B0' \
00735        or q_subkind == 'type_1_C0' \
00736        or q_subkind == 'type_1_A1' \
00737        or q_subkind == 'type_1_B1' \
00738        or q_subkind == 'type_1_C1':
00739     #___
00740         c_val = randomly.integer(2, max_coeff)
00741 
00742     ax2 = Monomial((randomly.sign(), a_val, 2))
00743     bx = Monomial((randomly.sign(), b_val, 1))
00744     c = Monomial((randomly.sign(), c_val, 0))
00745 
00746     # deg1 : mx + p
00747     # and we need two of them
00748     deg1 = []
00749     for i in range(2):
00750         deg1_mx = Monomial((randomly.sign(),
00751                             randomly.integer(1, max_coeff),
00752                             1))
00753         deg1_p = None
00754 
00755         if q_subkind == 'type_1_A0' \
00756            or q_subkind == 'type_1_B0' \
00757            or q_subkind == 'type_1_C0' \
00758            or q_subkind == 'type_1_D0' \
00759            or q_subkind == 'type_1_E0' \
00760            or q_subkind == 'type_1_F0' \
00761            or q_subkind == 'type_1_G0' \
00762            or q_subkind == 'type_1_H0' \
00763            or q_subkind == 'type_1_I0' \
00764            or q_subkind == 'type_1_A1' \
00765            or q_subkind == 'type_1_B1' \
00766            or q_subkind == 'type_1_D1' \
00767            or q_subkind == 'type_1_E1' \
00768            or q_subkind == 'type_1_G1' \
00769            or q_subkind == 'type_1_H1' \
00770            or q_subkind == 'type_4_A0' :
00771         #___
00772             deg1_p = Monomial((randomly.sign(),
00773                                randomly.integer(1, max_coeff),
00774                                0))
00775         else:
00776             deg1_p = Monomial((randomly.sign(),
00777                                randomly.integer(0, max_coeff),
00778                                0))
00779 
00780         if not deg1_p.is_null():
00781             lil_box = [deg1_mx, deg1_p]
00782             deg1.append(Polynomial([randomly.pop(lil_box),
00783                                     randomly.pop(lil_box)]))
00784 
00785         else:
00786             deg1.append(deg1_mx)
00787 
00788 
00789     # deg2 : mx² + px + r
00790     # and we also need two of them
00791     deg2 = []
00792     for i in range(2):
00793         deg2_mx2 = Monomial((randomly.sign(),
00794                             randomly.integer(1, max_coeff),
00795                             2))
00796 
00797         deg2_px = None
00798         deg2_r = None
00799 
00800         if q_subkind == 'type_1_A0' \
00801            or q_subkind == 'type_1_B0' \
00802            or q_subkind == 'type_1_C0' \
00803            or q_subkind == 'type_1_D0' \
00804            or q_subkind == 'type_1_E0' \
00805            or q_subkind == 'type_1_F0' \
00806            or q_subkind == 'type_1_G0' \
00807            or q_subkind == 'type_1_H0' \
00808            or q_subkind == 'type_1_I0' \
00809            or q_subkind == 'type_1_A1' \
00810            or q_subkind == 'type_1_B1' \
00811            or q_subkind == 'type_1_D1' \
00812            or q_subkind == 'type_1_E1' \
00813            or q_subkind == 'type_1_G1' \
00814            or q_subkind == 'type_1_H1':
00815         #___
00816             if randomly.heads_or_tails():
00817                 deg2_px = Monomial((randomly.sign(),
00818                                     randomly.integer(1, max_coeff),
00819                                     1))
00820                 deg2_r = Monomial((randomly.sign(),
00821                                     randomly.integer(0, max_coeff),
00822                                     0))
00823             else:
00824                 deg2_px = Monomial((randomly.sign(),
00825                                     randomly.integer(0, max_coeff),
00826                                     1))
00827                 deg2_r = Monomial((randomly.sign(),
00828                                     randomly.integer(1, max_coeff),
00829                                     0))
00830         else:
00831             deg2_px = Monomial((randomly.sign(),
00832                                 randomly.integer(0, max_coeff),
00833                                 1))
00834             deg2_r = Monomial((randomly.sign(),
00835                                 randomly.integer(0, max_coeff),
00836                                 0))
00837 
00838         lil_box = [deg2_mx2]
00839 
00840         if not deg2_px.is_null():
00841             lil_box.append(deg2_px)
00842         if not deg2_r.is_null():
00843             lil_box.append(deg2_r)
00844 
00845         monomials_list_for_deg2 = []
00846         for i in range(len(lil_box)):
00847             monomials_list_for_deg2.append(randomly.pop(lil_box))
00848 
00849         deg2.append(Polynomial(monomials_list_for_deg2))
00850 
00851 
00852     # Let's attribute the common factor C according to the required type
00853     # (NB : expression ± C×F1 ± C×F2)
00854     C = None
00855 
00856     if q_subkind == 'type_1_A0' \
00857        or q_subkind == 'type_1_B0' \
00858        or q_subkind == 'type_1_C0' \
00859        or q_subkind == 'type_1_A1' \
00860        or q_subkind == 'type_1_B1':
00861     #___
00862         C = c
00863 
00864     elif q_subkind == 'type_1_D0' \
00865          or q_subkind == 'type_1_E0' \
00866          or q_subkind == 'type_1_F0' \
00867          or q_subkind == 'type_1_D1' \
00868          or q_subkind == 'type_1_E1':
00869     #___
00870         C = bx
00871 
00872     elif q_subkind == 'type_1_G0' \
00873          or q_subkind == 'type_1_H0' \
00874          or q_subkind == 'type_1_I0' \
00875          or q_subkind == 'type_1_G1' \
00876          or q_subkind == 'type_1_H1':
00877     #___
00878         C = ax2
00879 
00880     elif q_subkind == 'type_2_A0' \
00881          or q_subkind == 'type_2_B0' \
00882          or q_subkind == 'type_2_C0' \
00883          or q_subkind == 'type_2_A1' \
00884          or q_subkind == 'type_2_B1' \
00885          or q_subkind == 'type_4_A0' :
00886     #___
00887         C = Polynomial([bx, c])
00888 
00889     elif q_subkind == 'type_2_D0' \
00890          or q_subkind == 'type_2_E0' \
00891          or q_subkind == 'type_2_F0' \
00892          or q_subkind == 'type_2_D1' \
00893          or q_subkind == 'type_2_E1':
00894     #___
00895         C = Polynomial([ax2, c])
00896 
00897     elif q_subkind == 'type_3_A0' \
00898          or q_subkind == 'type_3_B0' \
00899          or q_subkind == 'type_3_C0' \
00900          or q_subkind == 'type_3_A1' \
00901          or q_subkind == 'type_3_B1':
00902     #___
00903         C = Polynomial([ax2, bx, c])
00904 
00905     # Let's attribute F1 and F2 according to the required type
00906     # (NB : expression ± C×F1 ± C×F2)
00907     F1 = None
00908     F2 = None
00909 
00910     if q_subkind == 'type_1_A0' \
00911        or q_subkind == 'type_1_A1' \
00912        or q_subkind == 'type_1_D0' \
00913        or q_subkind == 'type_1_D1' \
00914        or q_subkind == 'type_1_G0' \
00915        or q_subkind == 'type_1_G1' \
00916        or q_subkind == 'type_2_A0' \
00917        or q_subkind == 'type_2_A1' \
00918        or q_subkind == 'type_2_D0' \
00919        or q_subkind == 'type_2_D1' \
00920        or q_subkind == 'type_3_A0' \
00921        or q_subkind == 'type_3_A1':
00922     #___
00923         F1 = deg1[0]
00924         F2 = deg1[1]
00925 
00926     elif q_subkind == 'type_1_B0' \
00927          or q_subkind == 'type_1_B1' \
00928          or q_subkind == 'type_1_E0' \
00929          or q_subkind == 'type_1_E1' \
00930          or q_subkind == 'type_1_H0' \
00931          or q_subkind == 'type_1_H1' \
00932          or q_subkind == 'type_2_B0' \
00933          or q_subkind == 'type_2_B1' \
00934          or q_subkind == 'type_2_E0' \
00935          or q_subkind == 'type_2_E1' \
00936          or q_subkind == 'type_3_B0' \
00937          or q_subkind == 'type_3_B1':
00938     #___
00939         F1 = deg2[0]
00940         F2 = deg2[1]
00941 
00942     elif q_subkind == 'type_1_C0' \
00943          or q_subkind == 'type_1_F0' \
00944          or q_subkind == 'type_1_I0' \
00945          or q_subkind == 'type_2_C0' \
00946          or q_subkind == 'type_2_F0'  \
00947          or q_subkind == 'type_3_C0':
00948     #___
00949         F1 = deg1[0]
00950         F2 = deg2[0]
00951 
00952     # The special case type_4_A0 : (ax+b)² + (ax+b)×deg1'
00953     #                       aka    C² + C×F1
00954     elif q_subkind == 'type_4_A0':
00955         F1 = C.clone()
00956         F2 = deg1[0]
00957 
00958     # Let's put a "1" somewhere in the type_*_*1
00959     if q_subkind == 'type_1_A1' \
00960        or q_subkind == 'type_1_D1' \
00961        or q_subkind == 'type_1_G1' \
00962        or q_subkind == 'type_2_A1' \
00963        or q_subkind == 'type_2_D1' \
00964        or q_subkind == 'type_3_A1' \
00965        or q_subkind == 'type_1_B1' \
00966        or q_subkind == 'type_1_E1' \
00967        or q_subkind == 'type_1_H1' \
00968        or q_subkind == 'type_2_B1' \
00969        or q_subkind == 'type_2_E1' \
00970        or q_subkind == 'type_3_B1':
00971     #___
00972         if randomly.heads_or_tails():
00973             F1 = Item(1)
00974         else:
00975             F2 = Item(1)
00976 
00977 
00978 
00979     # Let's possibly attribute a minus_sign
00980     # (NB : expression ± C×F1 ± C×F2)
00981     minus_sign = None # this will contain the name of the factor having
00982                       # a supplementary minus sign in such cases :
00983                       # C×F1 - C×F2
00984                       # - C×F1 + C×F2
00985 
00986     # in all the following cases, it doesn't bring anything to attribute
00987     # a minus sign
00988     if ((q_subkind == 'type_1_A0' \
00989          or q_subkind == 'type_1_B0' \
00990          or q_subkind == 'type_1_C0' \
00991          or q_subkind == 'type_1_A1' \
00992          or q_subkind == 'type_1_B1') \
00993         and c_val < 0) \
00994        or \
00995        ((q_subkind == 'type_1_D0' \
00996          or q_subkind == 'type_1_E0' \
00997          or q_subkind == 'type_1_F0' \
00998          or q_subkind == 'type_1_D1' \
00999          or q_subkind == 'type_1_E1') \
01000         and b_val < 0) \
01001        or \
01002        ((q_subkind == 'type_1_G0' \
01003          or q_subkind == 'type_1_H0' \
01004          or q_subkind == 'type_1_I0' \
01005          or q_subkind == 'type_1_G1' \
01006          or q_subkind == 'type_1_H1') \
01007         and a_val < 0) :
01008     #___
01009         pass # here we let minus_sign equal to None
01010 
01011     # otherwise, let's attribute one randomly,
01012     # depending on attribute_a_minus_sign
01013     else:
01014         if attribute_a_minus_sign == 'randomly' \
01015            or attribute_a_minus_sign == 'yes':
01016         #___
01017             if attribute_a_minus_sign == 'yes' \
01018                or randomly.heads_or_tails():
01019             #___
01020                 if randomly.heads_or_tails():
01021                     minus_sign = "F1"
01022                 else:
01023                     minus_sign = "F2"
01024             else:
01025                 pass # here we let minus_sign equal to None
01026 
01027 
01028     # Now let's build the expression !
01029     expression = None
01030 
01031     box_product1 = [C, F1]
01032     box_product2 = [C, F2]
01033 
01034     if q_subkind == 'type_4_A0':
01035         CF1 = Product([C])
01036         CF1.set_exponent(Value(2))
01037     else:
01038         CF1 = Product([randomly.pop(box_product1),
01039                        randomly.pop(box_product1)])
01040 
01041     CF2 = Product([randomly.pop(box_product2),
01042                    randomly.pop(box_product2)])
01043 
01044     if minus_sign == "F1":
01045         if len(F1) >= 2:
01046             CF1 = Expandable((Item(-1), CF1))
01047         else:
01048             CF1 = Product([Item(-1), CF1])
01049 
01050     elif minus_sign == "F2":
01051         if len(F2) >= 2:
01052             CF2 = Expandable((Item(-1), CF2))
01053         else:
01054             CF2 = Product([Item(-1), CF2])
01055 
01056     expression = Sum([CF1, CF2])
01057 
01058     # Now let's build the factorization steps !
01059     steps = []
01060     steps.append(expression)
01061 
01062     F1F2_sum = None
01063 
01064     if minus_sign is None:
01065         F1F2_sum = Sum([F1, F2])
01066 
01067     elif minus_sign == "F1":
01068         if len(F1) >= 2:
01069             F1F2_sum = Sum([Expandable((Item(-1), F1)), F2])
01070         else:
01071             F1F2_sum = Sum([Product([Item(-1), F1]), F2])
01072 
01073     elif minus_sign == "F2":
01074         if len(F2) >= 2:
01075             F1F2_sum = Sum([F1, Expandable((Item(-1), F2))])
01076         else:
01077             F1F2_sum = Sum([F1, Product([Item(-1), F2])])
01078 
01079     temp = Product([C, F1F2_sum])
01080     temp.set_compact_display(False)
01081     steps.append(temp)
01082 
01083     F1F2_sum = F1F2_sum.expand_and_reduce_next_step()
01084 
01085     while F1F2_sum != None:
01086         steps.append(Product([C, F1F2_sum]))
01087         F1F2_sum = F1F2_sum.expand_and_reduce_next_step()
01088 
01089     # This doesn't fit the need, because too much Products are
01090     # wrongly recognized as reducible !
01091     if steps[len(steps) - 1].is_reducible():
01092         steps.append(steps[len(steps) - 1].reduce_())
01093 
01094     return steps
01095 
01096 
01097 
01098 # --------------------------------------------------------------------------
01099 ##
01100 #   @brief Creates & returns the solution and the answer's steps.
01101 #   @return steps (list containing the steps)
01102 def level_03(q_subkind, **options):
01103 
01104     a = randomly.integer(1, 10)
01105     b = randomly.integer(1, 10)
01106 
01107     steps = []
01108 
01109     if q_subkind == 'sum_square' or q_subkind == 'sum_square_mixed' \
01110         or q_subkind == 'difference_square' \
01111         or q_subkind == 'difference_square_mixed':
01112     #___
01113         first_term = Monomial(('+',
01114                                Item(('+', a, 2)).evaluate(),
01115                                2))
01116 
01117         second_term = Monomial(('+',
01118                                 Item(('+', Product([2, a, b])\
01119                                            .evaluate(), 1))\
01120                                     .evaluate(),
01121                                 1))
01122 
01123         third_term = Monomial(('+', Item(('+', b, 2)).evaluate(), 0))
01124 
01125         if q_subkind == 'difference_square' \
01126             or q_subkind == 'difference_square_mixed':
01127         #___
01128             second_term.set_sign('-')
01129 
01130         if q_subkind == 'sum_square_mixed' \
01131             or q_subkind == 'difference_square_mixed':
01132         #___
01133             ordered_expression = Polynomial([first_term,
01134                                              second_term,
01135                                              third_term])
01136 
01137             [first_term, second_term, third_term] = randomly.mix([first_term,
01138                                                                   second_term,
01139                                                                   third_term])
01140 
01141 
01142         steps.append(Polynomial([first_term, second_term, third_term]))
01143 
01144         if q_subkind == 'sum_square_mixed' \
01145             or q_subkind == 'difference_square_mixed':
01146         #___
01147             steps.append(ordered_expression)
01148 
01149         sq_a_monom = Monomial(('+', a, 1))
01150         sq_b_monom = Monomial(('+', b, 0))
01151 
01152         let_a_eq = Equality([Item('a'),
01153                              sq_a_monom
01154                              ])
01155 
01156         let_b_eq = Equality([Item('b'),
01157                              sq_b_monom
01158                              ])
01159 
01160         steps.append(_("Let") + " " \
01161                      + let_a_eq.into_str(force_expression_markers='yes') \
01162                      + " " + _("and") + " " \
01163                      + let_b_eq.into_str(force_expression_markers='yes'))
01164 
01165         sq_a_monom.set_exponent(2)
01166         sq_b_monom.set_exponent(2)
01167 
01168         a_square_eq = Equality([Item(('+', 'a', 2)),
01169                                 sq_a_monom,
01170                                 sq_a_monom.reduce_()
01171                                 ])
01172 
01173         b_square_eq = Equality([Item(('+', 'b', 2)),
01174                                 sq_b_monom,
01175                                 sq_b_monom.reduce_()
01176                                 ])
01177 
01178         steps.append(_("then") + " " \
01179                      + a_square_eq.into_str(force_expression_markers='yes'))
01180 
01181         steps.append(_("and") + " " \
01182                      + b_square_eq.into_str(force_expression_markers='yes'))
01183 
01184         two_times_a_times_b_numeric = Product([Item(2),
01185                                                Monomial(('+', a, 1)),
01186                                                Item(b)])
01187 
01188         two_times_a_times_b_reduced = two_times_a_times_b_numeric.reduce_()
01189 
01190         two_times_a_times_b_eq = Equality([Product([Item(2),
01191                                                     Item('a'),
01192                                                     Item('b')]),
01193                                            two_times_a_times_b_numeric,
01194                                            two_times_a_times_b_reduced
01195                                            ])
01196 
01197         steps.append(_("and") + " " \
01198                      + two_times_a_times_b_eq.into_str(
01199                                                 force_expression_markers='yes')
01200                      )
01201 
01202         steps.append(_("So it is possible to factorize :"))
01203 
01204         if q_subkind == 'difference_square' \
01205             or q_subkind == 'difference_square_mixed':
01206         #___
01207             b = -b
01208 
01209         factorized_expression = Sum([Monomial(('+', a, 1)), Item(b)])
01210         factorized_expression.set_exponent(2)
01211 
01212         steps.append(factorized_expression)
01213 
01214 
01215 
01216     elif q_subkind == 'squares_difference' \
01217         or q_subkind == 'squares_difference_mixed':
01218     #___
01219         # To have some (ax)² - b² but also sometimes b² - (ax)² :
01220         degrees = [2, 0, 1, 0]
01221 
01222         if randomly.integer(1, 10) >= 8:
01223             degrees = [0, 2, 0, 1]
01224 
01225         first_term = Monomial(('+',
01226                                Item(('+', a, 2)).evaluate(),
01227                                degrees[0]))
01228 
01229         second_term = Monomial(('-',
01230                                 Item(('+', b, 2)).evaluate(),
01231                                 degrees[1]))
01232 
01233         sq_first_term = Monomial(('+',
01234                                   Item(('+', a, 1)).evaluate(),
01235                                   degrees[2]))
01236 
01237         sq_second_term = Monomial(('-',
01238                                    Item(('+', b, 1)).evaluate(),
01239                                    degrees[3]))
01240 
01241         # The 'mixed' cases are : -b² + (ax)² and -(ax)² + b²
01242         if q_subkind == 'squares_difference_mixed':
01243             [first_term, second_term] = randomly.mix([first_term,
01244                                                       second_term])
01245             [sq_first_term, sq_second_term] = randomly.mix([sq_first_term,
01246                                                             sq_second_term])
01247 
01248 
01249         positive_sq_first = sq_first_term.clone()
01250         positive_sq_first.set_sign('+')
01251         positive_sq_second = sq_second_term.clone()
01252         positive_sq_second.set_sign('+')
01253 
01254 
01255         steps.append(Polynomial([first_term, second_term]))
01256 
01257         first_inter = None
01258         second_inter = None
01259 
01260         if sq_second_term.is_negative():
01261             first_inter = positive_sq_first.clone()
01262             first_inter.set_exponent(2)
01263             temp_second_inter = positive_sq_second.clone()
01264             temp_second_inter.set_exponent(2)
01265             second_inter = Product([-1, temp_second_inter])
01266         else:
01267             temp_first_inter = positive_sq_first.clone()
01268             temp_first_inter.set_exponent(2)
01269             first_inter = Product([-1, temp_first_inter])
01270             second_inter = positive_sq_second.clone()
01271             second_inter.set_exponent(2)
01272 
01273 
01274         steps.append(Sum([first_inter, second_inter]))
01275 
01276         if q_subkind == 'squares_difference_mixed':
01277             steps.append(Sum([second_inter, first_inter]))
01278 
01279         steps.append(_("So, this expression can be factorized :"))
01280 
01281         sum1 = None
01282         sum2 = None
01283 
01284         if sq_second_term.is_negative():
01285             sum1 = Sum([sq_first_term, sq_second_term])
01286             sq_second_term.set_sign('+')
01287             sum2 = Sum([sq_first_term, sq_second_term])
01288 
01289         else:
01290             sum1 = Sum([sq_second_term, sq_first_term])
01291             sq_first_term.set_sign('+')
01292             sum2 = Sum([sq_second_term, sq_first_term])
01293 
01294         lil_box = [sum1, sum2]
01295 
01296         steps.append(Product([randomly.pop(lil_box),
01297                               randomly.pop(lil_box)
01298                             ])
01299                      )
01300 
01301     elif q_subkind == 'fake_01' or q_subkind == 'fake_01_mixed' \
01302         or q_subkind == 'fake_02' or q_subkind == 'fake_02_mixed' \
01303         or q_subkind == 'fake_03' or q_subkind == 'fake_03_mixed' \
01304         or q_subkind == 'fake_04_A' or q_subkind == 'fake_04_A_mixed' \
01305         or q_subkind == 'fake_04_B' or q_subkind == 'fake_04_B_mixed' \
01306         or q_subkind == 'fake_04_C' or q_subkind == 'fake_04_C_mixed' \
01307         or q_subkind == 'fake_04_D' or q_subkind == 'fake_04_D_mixed':
01308     #___
01309 
01310         straight_cases = ['fake_01', 'fake_02', 'fake_03',
01311                           'fake_04_A', 'fake_04_B', 'fake_04_C', 'fake_04_D']
01312         mixed_cases = ['fake_01_mixed', 'fake_02_mixed', 'fake_03_mixed',
01313                        'fake_04_A_mixed', 'fake_04_B_mixed',
01314                        'fake_04_C_mixed', 'fake_04_D_mixed']
01315 
01316         match_pb_cases = ['fake_01', 'fake_02',
01317                           'fake_01_mixed', 'fake_02_mixed']
01318 
01319         sign_pb_cases = ['fake_03', 'fake_03_mixed',
01320                          'fake_04_A', 'fake_04_B', 'fake_04_C', 'fake_04_D',
01321                          'fake_04_A_mixed', 'fake_04_B_mixed',
01322                          'fake_04_C_mixed', 'fake_04_D_mixed']
01323 
01324         ax = Monomial(('+', a, 1))
01325 
01326         b_ = Monomial(('+', b, 0))
01327 
01328         ax_2 = ax.clone()
01329         ax_2.set_exponent(2)
01330 
01331         a2x2 = Monomial(('+', a*a, 2))
01332 
01333         b_2 = Monomial(('+', b, 0))
01334         b_2.set_exponent(2)
01335 
01336         b2 = Monomial(('+', b*b, 0))
01337 
01338         two_ax_b = Product([Item(2),
01339                             Monomial(('+', a, 1)),
01340                             Item(b)])
01341 
01342         twoabx = Monomial(('+', 2*a*b, 1))
01343 
01344         fake_twoabx = Monomial(('+', a*b, 1))
01345 
01346         if randomly.integer(1, 10) >= 8:
01347             fake_twoabx = Monomial(('+',
01348                                     2*a*b \
01349                                     + randomly.pop([-1, 1])\
01350                                     *randomly.integer(1, 5),
01351                                     1))
01352 
01353         first_term = None
01354         second_term = None
01355         third_term = None
01356 
01357         ordered_expression = None
01358         mixed_expression = None
01359 
01360         if q_subkind == 'fake_03' or q_subkind == 'fake_03_mixed':
01361             first_term = a2x2.clone()
01362             second_term = b2.clone()
01363             ordered_expression = Polynomial([first_term, second_term])
01364             mixed_expression = Polynomial([second_term, first_term])
01365 
01366         else:
01367             first_term = a2x2.clone()
01368             third_term = b2.clone()
01369 
01370             if q_subkind == 'fake_01' or q_subkind == 'fake_01_mixed'\
01371                 or q_subkind == 'fake_02' or q_subkind == 'fake_02_mixed':
01372             #___
01373                 second_term = fake_twoabx.clone()
01374 
01375             else:
01376                 second_term = twoabx.clone()
01377 
01378             if q_subkind == 'fake_02' or q_subkind == 'fake_02_mixed':
01379                 second_term.set_sign('-')
01380 
01381             elif q_subkind == 'fake_04_A' or q_subkind == 'fake_04_A_mixed':
01382                 third_term.set_sign('-')
01383 
01384             elif q_subkind == 'fake_04_B' or q_subkind == 'fake_04_B_mixed':
01385                 first_term.set_sign('-')
01386 
01387             elif q_subkind == 'fake_04_C' or q_subkind == 'fake_04_C_mixed':
01388                 second_term.set_sign('-')
01389                 third_term.set_sign('-')
01390 
01391             elif q_subkind == 'fake_04_D' or q_subkind == 'fake_04_D_mixed':
01392                 first_term.set_sign('-')
01393                 second_term.set_sign('-')
01394 
01395             ordered_expression = Polynomial([first_term,
01396                                              second_term,
01397                                              third_term])
01398 
01399             mixed_expression = Polynomial(randomly.mix([first_term,
01400                                                         second_term,
01401                                                         third_term]))
01402 
01403 
01404         if q_subkind in straight_cases:
01405             steps.append(ordered_expression)
01406 
01407         elif q_subkind == 'fake_03_mixed':
01408             steps.append(mixed_expression)
01409 
01410         else:
01411             steps.append(mixed_expression)
01412             steps.append(ordered_expression)
01413 
01414 
01415 
01416         if q_subkind in match_pb_cases:
01417             let_a_eq = Equality([Item('a'),
01418                                  ax
01419                                  ])
01420 
01421             let_b_eq = Equality([Item('b'),
01422                                  b_
01423                                  ])
01424 
01425             steps.append(_("Let") + " " \
01426                          + let_a_eq.into_str(force_expression_markers='yes')\
01427                          + " " + _("and") + " " \
01428                          + let_b_eq.into_str(force_expression_markers='yes'))
01429 
01430 
01431             a_square_eq = Equality([Item(('+', 'a', 2)),
01432                                     ax_2,
01433                                     a2x2
01434                                     ])
01435 
01436             b_square_eq = Equality([Item(('+', 'b', 2)),
01437                                     b_2,
01438                                     b2
01439                                     ])
01440 
01441             steps.append(_("then") + " " \
01442                      + a_square_eq.into_str(force_expression_markers='yes'))
01443 
01444 
01445             steps.append(_("and") + " " \
01446                      + b_square_eq.into_str(force_expression_markers='yes'))
01447 
01448 
01449             two_times_a_times_b_eq = Equality([Product([Item(2),
01450                                                         Item('a'),
01451                                                         Item('b')]),
01452                                                two_ax_b,
01453                                                twoabx,
01454                                                fake_twoabx
01455                                                ],
01456                                                equal_signs=['=', '=', 'neq'])
01457 
01458             steps.append(_("but") + " " \
01459                      + two_times_a_times_b_eq.into_str(
01460                                                 force_expression_markers='yes')
01461                      )
01462 
01463             steps.append(_("So it does not match a binomial identity."))
01464             steps.append(_("This expression cannot be factorized."))
01465 
01466 
01467         elif q_subkind in sign_pb_cases:
01468             steps.append(_("Because of the signs,"))
01469             steps.append(_("it does not match a binomial identity."))
01470             steps.append(_("This expression cannot be factorized."))
01471 
01472 
01473 
01474     return steps
01475 
01476 
01477 
01478 
01479 
01480 
01481