source: pyromaths/trunk/fuentes/src/pyromaths/classes/SquareRoot.py @ 423

Last change on this file since 423 was 423, checked in by mabarracus, 4 years ago

add sources from pyromaths 15.10

File size: 14.7 KB
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#
4# Pyromaths
5# Un programme en Python qui permet de créer des fiches d'exercices types de
6# mathématiques niveau collège ainsi que leur corrigé en LaTeX.
7# Copyright (C) 2006 -- Jérôme Ortais (jerome.ortais@pyromaths.org)
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22#
23
24'''
25Created on 19 déc. 2014
26
27@author: jerome
28'''
29from pyromaths.outils.Arithmetique import carrerise
30from pyromaths.outils.decimaux import decimaux
31from pyromaths.outils import Priorites3
32# from pyromaths.classes.Fractions import Fraction
33
34from math import sqrt
35class SquareRoot():
36    '''
37    Définit la classe SquareRoot permettant de manipuler des racines carrées.
38   
39    SquareRoot([a,b], [c, d], e) ou SquareRoot([a,b], [c, d], [e, None]) permet de définir a*sqrt(b)+c*sqrt(d)+e
40   
41    Cette définition permet d'utiliser pyromaths.outils.Priorites3
42   
43    >>> from pyromaths.classes.SquareRoot import SquareRoot
44    >>> SquareRoot(-4,[-2,1],[3,45],[-1,7],8)
45    SquareRoot([[-4, None], [-2, 1], [3, 45], [-1, 7], [8, None]])
46    '''
47
48
49    def __init__(self, *radicandes):
50        '''
51        Constructor
52        '''
53        #  print radicandes, len(radicandes), radicandes[0], len(radicandes[0])
54        if len(radicandes) == 1 and len(radicandes[0]) == 2 and not isinstance(radicandes[0][0], list) and not isinstance(radicandes[0][1], list):
55            # SquareRoot([3, 4]),
56            self.racines = [radicandes[0]]
57        else:
58            if len(radicandes) == 1 and (len(radicandes[0]) != 2 or isinstance(radicandes[0][0], list) or isinstance(radicandes[0][1], list)):
59                # SquareRoot([1, [3, 4]])
60                radicandes = radicandes[0]
61            self.racines = []
62            for arg in radicandes:
63                if isinstance(arg, list) and len(arg) == 2:
64                    # On gère a*sqrt(b)
65                    if isinstance(arg[1], (float, int))and arg[1] < 0:
66                        raise ValueError(u'Le radicande doit être un nombre positif.')
67                    else:
68                        self.racines.append(arg)
69                elif isinstance(arg, (float, int)):
70                    self.racines.append([arg, None])
71                else:
72                    raise ValueError(u'Not Implemented : SquareRoot(%s)' % arg)
73
74    def __str__(self):
75        r"""Renvoie une version LaTeX d'un objet SquareRoot.
76
77        >>> from pyromaths.classes.SquareRoot import SquareRoot
78        >>> str(SquareRoot([[-4, None], [-2, 1], [3, 45], [-1, 7], [8, None]]))
79        '-4-2\\,\\sqrt{1}+3\\,\\sqrt{45}-\\sqrt{7}+8'
80
81        :rtype: String
82        """
83        def print_coef(coef):
84            """Gère le format du coef
85            """
86            if isinstance(coef, (float, int)):
87                if coef > 0: return "+" + decimaux(coef)
88                else: return decimaux(coef)
89            if isinstance(coef, Fraction):
90                if isinstance(coef.n, int) and isinstance(coef.d, int) and coef.n < 0 and coef.d > 0:
91                    return "-" + str(Fraction(-coef.n, coef.d, coef.code))
92                return "+" + str(coef)
93            if isinstance(coef, str):
94                texte = "(" + "".join(Priorites3.texify([Priorites3.splitting(coef)])) + ")"
95                if texte[0] != "-": return "+" + texte
96                else: return texte
97        s = ""
98        for m in self.racines:
99            if m[1] == None:
100                # pas de racine ici
101                s = s + print_coef(m[0])
102            else:
103                # Racine carrée
104                if m[0] == 1:
105                    s += r'+\sqrt{%s}' % m[1]
106                elif m[0] == -1:
107                    s += r'-\sqrt{%s}' % m[1]
108                else:
109                    s += print_coef(m[0]) + r'\,\sqrt{%s}' % m[1]
110        # supprime le + en début de séquence
111        s = s.lstrip("+")
112        if not s: s = "0"
113        return s
114
115    def __repr__(self):
116        """Renvoie une chaîne de caractère représentant un :mod:`SquareRoot`
117        évaluable pour créer un :mod:`SquareRoot`.
118       
119        >>> from pyromaths.classes.SquareRoot import SquareRoot
120        >>> repr(SquareRoot(-4, [-2, 1], [3, 45], [-1, 7], 8))
121        'SquareRoot([[-4, None], [-2, 1], [3, 45], [-1, 7], [8, None]])'
122       
123        :rtype: String
124        """
125        return "SquareRoot(%s)" % self.racines
126
127    def __len__(self):
128        """*object*\ .\ **__len__**\ ()
129
130        Renvoie le nombre d'éléments de l'objet SquareRoot.
131
132        >>> from pyromaths.classes.SquareRoot import SquareRoot
133        >>> len(SquareRoot(3, [2, 2], [4, 5]))
134        3
135
136        :rtype: integer
137        """
138        return len(self.racines)
139
140    def __getitem__(self, i):
141        """*object*\ .\ **__getitem__**\ (*integer*)
142
143        Renvoie le i ème élément de l'objet SquareRoot.
144
145        >>> from pyromaths.classes.SquareRoot import SquareRoot
146        >>> SquareRoot(3, [2, 2], [4, 5])[2]
147        [4, 5]
148
149        :rtype: list
150        """
151        return self.racines[i]
152
153
154    def __add__(self, other):
155        """Renvoie la somme d'un objet SquareRoot et d'un nombre.
156       
157        >>> from pyromaths.classes.SquareRoot import SquareRoot
158        >>> SquareRoot([3,45],3)+SquareRoot([2,45])
159        SquareRoot([[3, None], [5, 45]])
160       
161        :rtype: SquareRoot
162        """
163
164        if not isinstance(other, SquareRoot):
165            other = SquareRoot([other, None])
166        self.racines.extend(other.racines)
167        return SquareRoot(self.racines).simplifie()
168
169    def __radd__(self, other):
170        """
171        >>> from pyromaths.classes.SquareRoot import SquareRoot
172        >>> 2+SquareRoot([3,45],3)
173        SquareRoot([[5, None], [3, 45]])
174
175        :rtype: SquareRoot
176        """
177        other = SquareRoot([other, None])
178        other.racines.extend(self.racines)
179        return SquareRoot(other.racines).simplifie()
180
181    def __neg__(self):
182        """*object*\ .\ **__neg__**\ ()
183
184        ``p.__neg__()`` est équivalent à ``-p`` est équivalent à ``p = -p``
185
186        Renvoie l'opposé d'un objet SquareRoot.
187
188        :rtype: SquareRoot
189        """
190        if self.EstDecomposable() or self.EstReductible(): return '-%r' % self.simplifie()
191        r = list(self.racines)
192        for i in range(len(r)):
193            r[i][0] = -r[i][0]
194        return SquareRoot(r)
195
196    def __abs__(self):
197        """ Renvoie la valeur absolue d'un objet SquareRoot
198       
199        >>> from pyromaths.classes.SquareRoot import SquareRoot
200        >>> abs(SquareRoot([5, 5], [-2, 7]))
201        SquareRoot([[5, 5], [-2, 7]])
202        >>> abs(SquareRoot([-5, 5], [2, 7]))
203        SquareRoot([[5, 5], [-2, 7]])
204       
205        :rtype: SquareRoot
206        """
207        t = 0
208        for e in self.racines:
209            if e[1] == None: t += e[0]
210            else: t += e[0] * sqrt(e[1])
211        if t > 0: return self
212        else: return -self
213
214
215    def __mul__(self, other):
216        """Multiplie un objet SquareRoot par un nombre.
217       
218        >>> from pyromaths.classes.SquareRoot import SquareRoot
219        >>> SquareRoot([3,45],3)*SquareRoot([2,45],-1)
220        SquareRoot([['6*45', None], [-3, 45], [6, 45], [-3, None]])
221        """
222        if not isinstance(other, SquareRoot):
223            other = SquareRoot([other, None])
224        reduction = False
225        if self.EstReductible():
226            self = self.simplifie()
227            reduction = True
228        if other.EstReductible():
229            other = other.simplifie()
230            reduction = True
231        if reduction: return '%r*%r' % (self, other)
232        lprod = []
233        for e in self.racines:
234            for f in other.racines:
235                if e[1] == None or f[1] == None:
236                    lprod.append([e[0] * f[0], max(e[1], f[1])])
237                elif e[1] == f[1]:
238                    lprod.append(['%r*%r' % (e[0] * f[0], e[1]), None])
239                elif carrerise(e[1]) == 1 or carrerise(f[1]) == 1:
240                    if carrerise(e[1]) == 1: e[0], e[1] = e[0] * int(sqrt(e[1])), 1
241                    if carrerise(f[1]) == 1: f[0], f[1] = f[0] * int(sqrt(f[1])), 1
242                    lprod.append([e[0] * f[0], e[1] * f[1]])
243                else:
244                    lprod.append([e[0] * f[0], e[1] * f[1]])
245        return SquareRoot(lprod)
246
247    def __rmul__(self, other):
248        """
249        >>> from pyromaths.classes.SquareRoot import SquareRoot
250        >>> 5*SquareRoot([3,45],3)
251        SquareRoot([[15, 45], [15, None]])
252
253        :rtype: SquareRoot
254        """
255        return SquareRoot([other, None]) * self
256
257    def  __floordiv__(self, other):
258        """
259        Division entière par un entier
260       
261        >>> from pyromaths.classes.SquareRoot import SquareRoot
262        >>> SquareRoot([10, 8], [15, 5])//5
263        SquareRoot([[2, 8], [3, 5]])
264
265        :rtype: SquareRoot
266        """
267        if isinstance(other, int):
268            r = list(self.racines)
269            for i in range(len(r)):
270                r[i][0] = r[i][0] // other
271            return SquareRoot(r)
272        else:
273            raise NotImplemented
274    def EstDecomposable(self):
275        """
276        Renvoie True si une des racines est de la forme sqrt{a**2*b} avec a != 1
277       
278        >>> from pyromaths.classes.SquareRoot import SquareRoot
279        >>> SquareRoot([5, 8], [1, 7]).EstDecomposable()
280        True
281        >>> SquareRoot([5, 7], [1, 7]).EstDecomposable()
282        False
283     
284        :rtype: Boolean
285        """
286        for e in self.racines:
287            if e[1] != None and (carrerise(e[1]) != e[1] or e[1] == 1):
288                return True
289        return False
290
291    def EstReductible(self):
292        """
293        Renvoie True si la somme de racines est réductible
294
295        >>> from pyromaths.classes.SquareRoot import SquareRoot
296        >>> SquareRoot([5, 8], [1, 45]).EstReductible()
297        False
298        >>> SquareRoot([5, 8], [1, 8]).EstReductible()
299        True
300
301        :rtype: Boolean
302        """
303        lradicandes = []
304        rationnel = False
305        for e in self.racines:
306            if e[1] != None:
307                if e[1] in lradicandes:
308                    return True
309                else:
310                    lradicandes.append(e[1])
311            elif e[1] == None:
312                if rationnel: return True
313                else: rationnel = True
314        return False
315
316    def Decompose(self):
317        """
318        Décompose une unique racine carrée de la forme a*sqrt(b^2*c) en a*sqrt(b^2)*sqrt(c)
319       
320        >>> from pyromaths.classes.SquareRoot import SquareRoot
321        >>> SquareRoot([5, 8]).Decompose()
322        'SquareRoot([[5, 4]])*SquareRoot([[1, 2]])'
323
324        :rtype: string
325        """
326        racine = self.racines[0]
327        if racine[1] == None: return repr(racine[0])
328        if isinstance(racine[1], int):
329            complement = carrerise(racine[1])
330            if complement == 1:
331                if racine[0] == 1:
332                    return int(sqrt(racine[1]))
333                if racine[0] == -1:
334                    return -int(sqrt(racine[1]))
335                if racine[1] == 1:
336                    return str(racine[0])
337                return '%r*%r' % (racine[0], int(sqrt(racine[1])))
338            if complement == racine[1]:
339                return repr(self)
340            return '%r*%r' % (SquareRoot([racine[0], racine[1] / complement]), SquareRoot([1, complement]))
341        raise ValueError(u'Not Implemented : SquareRoot(%s)' % racine)
342
343    def simplifie(self):
344        """
345        Additionne les nombres rationnels et décompose les racines carrées.
346         
347        >>> from pyromaths.classes.SquareRoot import SquareRoot
348        >>> SquareRoot([[3, 9]]).simplifie()
349        '3*3'
350        >>> SquareRoot(-2, [-2, 1], [3, 1], [-1, 7], 8).simplifie()
351        SquareRoot([[6, None], [1, 1], [-1, 7]])
352        >>> SquareRoot(-2, [-2, 1], [3, 45], [-1, 7], 8).simplifie()
353        SquareRoot([[6, None], [-2, 1], [3, 45], [-1, 7]])
354        >>> SquareRoot([-2,1],[3,45]).simplifie()
355        '-2+SquareRoot([[3, 9]])*SquareRoot([[1, 5]])'
356       
357        :rtype: SquareRoot ou String
358        """
359        decomposable = self.EstDecomposable()
360        reductible = self.EstReductible()
361        if not decomposable and not reductible:
362            return self
363        if reductible:
364            racines = []
365            # racines = [[sum([x[0] for i, x in enumerate(self.racines) if x[1] == None]), None]]
366            # TODO: cas de fractions
367            lsomme = [x[0] for i, x in enumerate(self.racines) if x[1] == None]
368            s = ''
369            for ls in lsomme:
370                if isinstance(ls, str): s += '+%s' % ls
371                else: s += '+%r' % ls
372            s.lstrip('+')
373            racines.append([eval(s), None])
374            for pos in reversed([i for i, x in enumerate(self.racines) if x[1] == None]):
375                    self.racines.__delitem__(pos)
376            if racines[0][0] == 0: racines = []
377            while len(self.racines) > 0:
378                # racines.append([sum([x[0] for i, x in enumerate(self.racines) if x[1] == self.racines[0][1]]), self.racines[0][1]])
379                # TODO: cas de fractions
380                lsomme = [x[0] for i, x in enumerate(self.racines) if x[1] == self.racines[0][1]]
381                s = ''
382                for ls in lsomme:
383                    if isinstance(ls, str): s += '+%s' % ls
384                    else: s += '+%r' % ls
385                s.lstrip('+')
386                racines.append([eval(s), self.racines[0][1]])
387                if racines[-1][0] == 0: racines.pop(-1)
388                for pos in reversed([i for i, x in enumerate(self.racines) if x[1] == self.racines[0][1]]):
389                    self.racines.__delitem__(pos)
390            if racines:
391                if len(racines) == 1 and racines[0][1] == None:
392                    return racines[0][0]
393                else:
394                    return SquareRoot(racines)
395            else: return 0
396        # Décomposable
397        s = ''
398        if len(self.racines) == 1 and isinstance(SquareRoot(self.racines).Decompose(), int):
399            return SquareRoot(self.racines).Decompose()
400        for e in self.racines:
401            decomposee = SquareRoot(e).Decompose()
402            if isinstance(decomposee, int): decomposee = str(decomposee)
403            if decomposee[0]in'+-':
404                s += decomposee
405            else:
406                s += '+' + decomposee
407        s = s.lstrip('+')
408        return s
Note: See TracBrowser for help on using the repository browser.