DSPython  00.03.03 — 25 juin 2012
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
polynomial.py
Aller à la documentation de ce fichier.
1 #!/usr/bin/env python
2 # -*- coding: latin-1 -*-
3 ##\package DSPython.polynomial Polynômes
4 
5 ##\file
6 # Polynômes
7 
8 # (c) Olivier Pirson --- DragonSoft
9 # http://www.opimedia.be/DS/
10 # Débuté le 11 mars 2007
11 ####################################
12 from __future__ import division
13 from __future__ import print_function
14 
15 ## Date du dernier changement pour ce module
16 VERSION = 'polynomial --- 2010 March 16'
17 
18 import numbers, string
19 
20 import DSPython
21 import DSPython.numbernone as numbernone
22 
23 
24 
25 # ############
26 # Constantes #
27 ##############
28 ## String contenant les caractères alphabétiques majuscules puis minuscules
29 ALPHA = string.ascii_uppercase + string.ascii_lowercase
30 
31 ## String contenant les caractères alphabétiques minuscules puis majuscules
32 ALPHA_DOWN = string.ascii_lowercase + string.ascii_uppercase
33 
34 
35 
36 # #########
37 # Classes #
38 ###########
39 ## Terme (tuple de Number ou de None représentant les exposants pour chaque variable)
40 class Term(tuple):
41  """Terme(tuple de Number ou de None
42  représentant les exposants pour chaque variable)"""
43 
44  ## Renvoie le terme sous forme de string "'Term(tuple des exposants)'"
45  def __repr__(self):
46  """Renvoie le terme sous forme de string "'Term(tuple des exposants)'"
47 
48  Result: string
49 
50  O() = ..."""
51  return "'Term({0})'".format(tuple.__repr__(self))
52 
53 
54  ## Renvoie le terme sous forme de string
55  def __str__(self, varsstr=ALPHA, nonestr='?',
56  mulstr='*', expstr='^', exprstr='', simplify=True):
57  """Renvoie le terme sous forme de string.
58  varsstr spécifie le caractère des variables utilisées
59  nonestr spécifie la chaîne de caractères
60  représentant les valeurs indéterminées None
61  Les facteurs sont séparés par multstr.
62  expstr est placé à gauche de chaque exposant et exprstr à droite.
63  Si simplify alors chaque élément sera présent dans le résultat,
64  sinon passe les variables d'exposant 0
65  et passe les exposants 1.
66  Si le résultat ne contient aucun élément
67  alors finalement renvoie '1'.
68 
69  Pre: varsstr: string assez grand
70  pour que chaque variable ait un caractère
71  nonestr: string
72  multstr: string
73  expstr: string
74  exprstr: string
75  simplify: boolean
76 
77  Result: string
78 
79  O() = ..."""
80  assert isinstance(varsstr, str), type(varsstr)
81  assert len(varsstr) >= len(self), (len(varsstr), len(self))
82  assert isinstance(nonestr, str), type(nonestr)
83  assert isinstance(mulstr, str), type(mulstr)
84  assert isinstance(expstr, str), type(expstr)
85  assert isinstance(exprstr, str), type(exprstr)
86 
87  l = [] # liste des facteurs sous forme de string
88  for i in range(len(self)):
89  e = self[i]
90 
91  assert isinstance(e, numbers.Number) or (e == None), (i, e)
92 
93  if simplify and (e == 1):
94  l.append(varsstr[i])
95  elif (not simplify) or (e != 0):
96  l.append('{0}{1}{2}{3}'.format(varsstr[i], expstr, (e if e != None
97  else nonestr), exprstr))
98  return (mulstr.join(l) if l != []
99  else '1')
100 
101 
102  ## ??? Compare les exposants (d'après l'ordre déterminé par order) des 2 Term
103  def cmp_order(self, other, order=None):
104  """Compare les exposants (d'après l'ordre déterminé par order)
105  des 2 Term et renvoie -1 si self < other
106  0 ==
107  1 >
108  Si order == None alors utilise l'ordre normal
109 
110  Pre: other: Term
111  order: None
112  ou tuple de naturels assez grand
113  pour que chaque variable ait un indice
114 
115  Result: -1, 0 ou 1
116 
117  O() = ..."""
118  assert isinstance(other, Term), type(other)
119  assert len(self) == len(other), (len(self), len(other))
120  assert order == None or isinstance(order, tuple), type(order)
121  assert order == None or len(order) >= len(self), (len(order), len(self))
122 
123  if order == None:
124  for i in range(len(self)):
125  c = cmp(self[i], other[i])
126  if c != 0:
127  return c
128  i += 1
129  return 0
130  else:
131  for i in range(len(self)):
132  c = order[i]
133  c = cmp(self[c], other[c])
134  if c != 0:
135  return c
136  i += 1
137  return 0
138 
139 
140  ## Renvoie la k<sup>e</sup> dérivée partielle pour la variable d'indice i
141  def deriv(self, i=0, k=1):
142  """Renvoie la kème dérivée partielle pour la variable d'indice i
143  Si k > 0 alors pour le terme (..., n, ...)
144  renvoie (n(n - 1)...(n - k + 1), Term((..., n - k, ...)))
145  En particulier si k == 1
146  alors renvoie (n, Term((..., n - 1, ...)))
147  Si k == 0 alors renvoie (1, Term(self))
148  Si k < 0 alors pour le terme (..., n, ...)
149  renvoie (1/((n + 1)...(n - k)), Term((..., n - k, ...)))
150  (Si k <= n < 0 alors renvoie (None, Term((..., n - k, ...))))
151  Si n == None alors renvoie (None, Term((..., n, ...)))
152  Donc pour (..., n, ...) renvoie toujours
153  (numbernone.falling_factorial_pow(n, k), Term((..., n - k, ...)))
154 
155  Pre: i: natural < len(self)
156  k: Integral
157 
158  Result: (Number ou None, Term)
159 
160  O() = ..."""
161  assert DSPython.natural_is(i), i
162  assert i < len(self), (i, len(self))
163  assert isinstance(k, numbers.Integral), k
164 
165  return ((numbernone.falling_factorial_pow(self[i], k),
166  Term(self[:i] + (self[i] - k, ) + self[i + 1:])) if self[i] != None
167  else (None, Term(self)))
168 
169 
170  ## Renvoie le terme évalué en fonction des valeurs de values
171  def eval(self, values=1):
172  """Renvoie le terme évalué en fonction des valeurs de values
173  Pour le terme (a, b, c, ...)
174  si values est un Number
175  alors renvoie values^a * values^b * values^c * ...
176  si values est une séquence
177  alors renvoie values[0]^a * values[1]^b * values[2]^c * ...
178  Si un des ces Number est None alors renvoie None
179 
180  Pre: value: Number ou None
181  ou tuple (de Number ou de None) assez grand
182  pour que chaque variable ait une valeur
183  ou list (de Number ou de None) assez grand
184  pour que chaque variable ait une valeur
185 
186  Result: Number ou None
187 
188  O() = ..."""
189  assert isinstance(values, numbers.Number) or (values == None) \
190  or isinstance(values, tuple) or isinstance(values, list), type(values)
191  assert isinstance(values, numbers.Number) or (values == None) \
192  or (len(values) >= len(self)), (len(values), len(self))
193 
194  if isinstance(values, numbers.Number):
195  if values == 1:
196  return 1
197  else:
198  nb = 0
199  for e in self:
200  if e == None:
201  return None
202  if e != 0:
203  nb += e
204  return values**nb
205  elif values != None:
206  assert len(values) >= len(self), (len(values), len(self))
207 
208  r = 1
209  for i in range(len(self)):
210  e = self[i]
211  if (e == None) or (values[i] == None):
212  return None
213  if (e != 0) and (values[i] != 1):
214  r *= values[i]**e
215  return r
216  else:
217  return None
218 
219 
220  ##\brief Renvoie une "évaluation partielle" du terme sous forme de (coef, Term)
221  # en fonction des valeurs de values
222  def partialeval(self, values):
223  """Renvoie une "évaluation partielle" du terme
224  sous forme de (coef, Term) en fonction des valeurs de values.
225  Pour chaque Number de values,
226  la variable correspondante est évaluée,
227  le résultat multiplie coef et l'exposant est réinitialisé à 0,
228  alors que pour chaque None de values,
229  la variable correspondante est ignorée
230  et son exposant conservé.
231  Si le terme est vide alors renvoie (1, Term())
232  Si le terme contient un exposant None qui doit être évalué
233  alors renvoie (None, Term) où les exposants None sont conservés
234 
235  Pre: value: tuple de Number ou de None assez grand
236  pour que chaque variable ait une valeur
237  ou list de Number ou de None assez grand
238  pour que chaque variable ait une valeur
239 
240  Result: (Number ou None, Term)
241 
242  O() = ..."""
243  assert isinstance(values, tuple) or isinstance(values, list), type(values)
244  assert len(values) >= len(self), (len(values), len(self))
245 
246  notnone = True
247  coef = 1
248  l = list(self)
249  for i in range(len(self)):
250  n = values[i]
251  if n != None:
252  if self[i] != None:
253  coef *= n**self[i]
254  l[i] = 0
255  else:
256  coef = 0
257  notnone = False
258  return (coef if notnone
259  else None, Term(l))
260 
261 
262 ##\brief Polynôme (dictionnaire[Term] = coefficient,
263 # avec varsstr, une chaîne de caractères pour les variables)
264 class Polynomial(dict):
265  """Polynôme (dictionnaire[Term] = coefficient,
266  avec varsstr, une chaîne de caractères pour les variables)"""
267 
268  ## Initialise le polynôme à value * coef
269  def __init__(self, value=(), coef=1, varsstr=ALPHA):
270  """Initialise le polynôme à value * coef et
271  et spécifie le caractère des variables par varsstr.
272  Si value est un Polynomial
273  alors varsstr est ignoré et value.varsstr est utilisé
274 
275  Pre: value: Polynomial
276  ou dict de Term de même taille pour les clés
277  et de Number pour les valeurs
278  ou Term
279  ou tuple de Term de même taille
280  ou liste de Term de même taille
281  coef: Number
282  varsstr: string assez grand
283  pour que chaque variable ait un caractère
284 
285  Result: None
286 
287  O() = ..."""
288  assert isinstance(value, Polynomial) or isinstance(value, Term) or isinstance(value, dict) \
289  or isinstance(value, tuple) or isinstance(value, list), type(value)
290  assert isinstance(coef, numbers.Number), coef
291  assert isinstance(varsstr, str), type(varsstr)
292 
293  ## String contenant les caractères pour chaque variable
294  self.varsstr = (value.varsstr if isinstance(value, Polynomial)
295  else varsstr)
296  if coef != 0:
297  if isinstance(value, Polynomial) or isinstance(value, dict):
298  if (coef == 1) and isinstance(value, Polynomial):
299  dict.__init__(self, value)
300  else:
301  dict.__init__(self)
302  for t in value:
303  assert isinstance(t, Term), t
304  assert len(t) == len(list(value.keys())[0]), (len(t), len(value.keys()[0]))
305 
306  if value[t]*coef != 0:
307  self[t] = value[t] * coef
308  elif isinstance(value, Term):
309  assert len(varsstr) >= len(value), (len(varsstr), len(value))
310 
311  dict.__init__(self, {value: coef})
312  else: # value est un tuple de Term ou une liste de Term
313  dict.__init__(self)
314  for t in value:
315  assert isinstance(t, Term), type(t)
316  assert len(t) == len(value[0]), (len(t), len(value[0]))
317 
318  if t not in self:
319  self[t] = coef
320  else:
321  self[t] += coef
322  if self[t] == 0:
323  del self[t]
324  else:
325  dict.__init__(self)
326 
327 
328  ## ??? Renvoie le polynôme auquel est ajouté value * coef
329  def __iadd__(self, value, coef=1):
330  """Renvoie le polynôme auquel est ajouté value * coef
331 
332  Pre: value: Polynomial de même taille des termes
333  ou Term (de taille quelconque si le polynôme est vide,
334  de taille lenterms() sinon)
335  ou Number (si le polynôme n'est pas vide)
336  coef: Number
337 
338  Result: Polynomial
339 
340  O() = ..."""
341  if coef != 0:
342  if isinstance(value, Term):
343  if (not self) or (self.lenterms() == len(value)):
344  if value not in self:
345  self[value] = coef
346  else:
347  self[value] += coef
348  if self[value] == 0:
349  del self[value]
350  return self
351  elif isinstance(value, numbers.Number):
352  if self:
353  t = Term((0, ) * self.lenterms())
354  coef *= value
355  if coef != 0:
356  if t in self:
357  self[t] += coef
358  if self[t] == 0:
359  del self[t]
360  else:
361  self[t] = coef
362  return self
363  elif isinstance(value, Polynomial) and (value.lenterms() == self.lenterms()):
364  for t in value:
365  if t not in self:
366  self[t] = value[t] * coef
367  else:
368  self[t] += value[t] * coef
369  if self[t] == 0:
370  del self[t]
371  return self
372  raise NotImplementedError
373  else:
374  return self
375 
376 
377  ## Renvoie le polynôme sous forme de string "'Polynomial(tuple des exposants, varsstr="...")'"
378  def __repr__(self):
379  """Renvoie le polynôme sous forme
380  de string "'Polynomial(tuple des exposants, varsstr="...")'"
381 
382  Result: string
383 
384  O() = ..."""
385  return "'Polynomial({0}, varsstr=\"{1}\")'".format(dict.__repr__(self), self.varsstr)
386 
387 
388  ## ??? Renvoie le polynôme sous forme de string
389  def __str__(self, varsstr=None, nonestr='?', addstr=' + ', substr=' - ', mulstr='*',
390  expstr='^', exprstr='', simplify=True, order=None):
391  """Renvoie le polynôme sous forme de string.
392  varsstr spécifie le caractère des variables utilisées
393  (si varsstr == None alors utilise self.varsstr).
394  nonestr spécifie la chaîne de caractères
395  représentant les valeurs indéterminées None
396  Les termes de coefficients >= 0 sont séparés par addstr,
397  < 0 substr.
398  Les facteurs sont séparés par mulstr.
399  expstr est placé à gauche de chaque exposant et exprstr à droite.
400  Si simplify alors chaque élément sera présent dans le résultat,
401  sinon passe le coefficient si == 1,
402  passe les variables d'exposant 0
403  et passe les exposants 1.
404  order ???
405  Si le résultat ne contient aucun élément alors renvoie ''.
406 
407  Pre: varsstr: None
408  ou string assez grand
409  pour que chaque variable ait un caractère
410  nonestr: string
411  addstr: string
412  substr: string
413  multstr: string
414  expstr: string
415  exprstr: string
416  simplify: boolean
417  order: None
418  ou tuple de naturels ou liste de tuple de naturels
419  assez grand pour que chaque variable ait un indice
420 
421  Result: string
422 
423  O() = ..."""
424  if varsstr == None:
425  varsstr = self.varsstr
426 
427  assert isinstance(varsstr, str), type(varsstr)
428  assert (self.lenterms() == None) or (len(varsstr) >= self.lenterms()), \
429  (len(varsstr), self.lenterms())#???
430  assert isinstance(nonestr, str), type(nonestr)
431  assert isinstance(addstr, str), type(addstr)
432  assert isinstance(substr, str), type(substr)
433  assert isinstance(mulstr, str), type(mulstr)
434  assert isinstance(expstr, str), type(expstr)
435  assert isinstance(exprstr, str), type(exprstr)
436  assert order == None or isinstance(order, tuple) or isinstance(order, list), type(order)
437  assert order == None or len(order) >= len(self), (len(order), len(self))
438 
439  if order != None:
440  raise NotImplementedError
441 
442  l = [] # liste des termes sous forme de string
443  terms = sorted(self)
444  if simplify:
445  for t in terms:
446  assert isinstance(t, Term), type(t)
447 
448  if self[t] >= 0:
449  l.append(addstr)
450  if self[t] != 1:
451  l.append(str(self[t]))
452  t_str = t.__str__(varsstr=varsstr, nonestr=nonestr,
453  mulstr=mulstr, expstr=expstr, exprstr=exprstr)
454  if (self[t] != 1) and (t_str != '1'):
455  l.append(mulstr)
456  if (t_str != '1') or (self[t] == 1):
457  l.append(t_str)
458  else:
459  if l == []:
460  l.append(substr)
461  l.append(substr)
462  if self[t] != -1:
463  l.append(str(-self[t]))
464  t_str = t.__str__(varsstr=varsstr, nonestr=nonestr,
465  mulstr=mulstr, expstr=expstr, exprstr=exprstr)
466  if (self[t] != -1) and (t_str != '1'):
467  l.append(mulstr)
468  if (t_str != '1') or (self[t] == -1):
469  l.append(t_str)
470  else:
471  for t in terms:
472  assert isinstance(t, Term), type(t)
473 
474  if self[t] >= 0:
475  l.append(addstr)
476  l.append(str(self[t]))
477  t_str = t.__str__(varsstr=varsstr, nonestr=nonestr,
478  mulstr=mulstr, expstr=expstr, exprstr=exprstr, simplify=False)
479  else:
480  if l == []:
481  l.append(substr)
482  l.append(substr)
483  l.append(str(-self[t]))
484  t_str = t.__str__(varsstr=varsstr, nonestr=nonestr,
485  mulstr=mulstr, expstr=expstr, exprstr=exprstr, simplify=False)
486  l.append(mulstr)
487  l.append(t_str)
488  return ''.join(l[1:]) # ignore le premier addstr ajouté dans l
489 
490 
491  ## Renvoie la k<sup>e</sup> dérivée partielle pour la variable d'indice i
492  def deriv(self, i=0, k=1):
493  """Renvoie la kème dérivée partielle pour la variable d'indice i
494  (c.-à-d. la somme des dérivées de ses termes)
495 
496  Pre: i: natural < self.lenterms()
497  k: Integral
498 
499  Result: (Number ou None, Term)
500 
501  O() = ..."""
502  assert DSPython.natural_is(i), i
503  assert i < self.lenterms(), (i, self.lenterms())
504  assert isinstance(k, numbers.Integral), k
505 
506  d = {}
507  for t in self:
508  (c, dt) = t.deriv(i=i, k=k)
509  d[dt] = (self[t] * c if c != None
510  else None)
511  return Polynomial(d, varsstr=self.varsstr)
512 
513 
514  ## Renvoie le polynôme évalué en fonction des valeurs de values
515  def eval(self, values=1):
516  """Renvoie le polynôme évalué en fonction des valeurs de values
517 
518  Pre: value: Number
519  ou tuple de Number assez grand
520  pour que chaque variable ait une valeur
521  ou list de Number assez grand
522  pour que chaque variable ait une valeur
523 
524  Result: Number ou None ???
525 
526  O() = ..."""
527  assert isinstance(values, numbers.Number) or isinstance(values, tuple) \
528  or isinstance(values, list), type(values)
529  assert isinstance(values, numbers.Number) or (len(values) >= self.lenterms()), \
530  (len(values), self.lenlenterms())
531 
532  r = 0
533  for t in self:
534  p = t.eval(values) * self[t]
535  if p != 0:
536  r += p
537  return r
538 
539 
540  ## Renvoie la taille des termes
541  def lenterms(self):
542  """Renvoie la taille des termes ou None si le polynôme est vide
543 
544  Result: int ou None
545 
546  O() = ..."""
547  return (len(list(self.keys())[0]) if len(self) > 0
548  else None)
549 
550 
551  ## Renvoie une "évaluation partielle" du polynôme en fonction des valeurs de values.
552  def partialeval(self, values):
553  """Renvoie une "évaluation partielle" du polynôme
554  en fonction des valeurs de values.
555  Pour chaque Number de values,
556  la variable correspondante est évaluée,
557  le résultat multiplie le coefficient du terme
558  et l'exposant est réinitialisé à 0,
559  alors que pour chaque None de values,
560  la variable correspondante est ignorée et son exposant conservé.
561  Si le polynôme est vide alors renvoie Polynomial()
562 
563  Pre: value: tuple de Number ou de None assez grand
564  pour que chaque variable ait une valeur
565  ou list de Number ou de None assez grand
566  pour que chaque variable ait une valeur
567 
568  Result: Polynomial
569 
570  O() = ..."""
571  assert isinstance(values, tuple) or isinstance(values, list), type(values)
572  assert (self.lenterms() == None) or (len(values) >= self.lenterms()), \
573  (len(values), self.lenterms())#???
574 
575  p = Polynomial()
576  for t in self:
577  (c, new_t) = t.partialeval(values)
578  c *= self[t]
579  if c != 0:
580  if new_t not in p:
581  p[new_t] = c
582  else:
583  p[new_t] += c
584  if p[new_t] == 0:
585  del p[new_t]
586  return p
587 
588 
589 
590 # ######\cond MAINTEST
591 # Main #
592 ########
593 if __name__ == '__main__':
594  def main_test():
595  """Test du module"""
596  import decimal, sys
597 
598  import DSPython.debug as debug
599 
600  debug.test_begin(VERSION, __debug__)
601 
602  print("ALPHA == '{0}'".format(ALPHA)); sys.stdout.flush()
603  print("ALPHA_DOWN == '{0}'".format(ALPHA_DOWN)); sys.stdout.flush()
604 
605 
606 
607  print()
608  print('Term()...', end=''); sys.stdout.flush()
609  assert Term() == (), Term()
610  assert Term(()) == (), Term(())
611  assert Term((1, 2)) == (1, 2), Term((1, 2))
612  assert Term([1, 2]) == (1, 2), Term([1, 2])
613  assert Term((1, None, 2)) == (1, None, 2), Term((1, None, 2))
614  assert Term((3, -5, 7)) == (3, -5, 7), Term((3, -5, 7))
615  assert Term((3, 5.0, decimal.Decimal('7'))) == (3, 5.0, decimal.Decimal('7')), \
616  Term((3, 5.0, decimal.Decimal('7')))
617  assert Term(Term((3, 5, 7))) == (3, 5, 7), Term(Term((3, 5, 7)))
618  assert isinstance(Term((3, 5, 7)), Term), Term((3, 5, 7))
619  assert isinstance(Term((3, 5, 7)), tuple), Term((3, 5, 7))
620  assert not isinstance(Term((3, 5, 7)), list), Term((3, 5, 7))
621  print('ok'); sys.stdout.flush()
622 
623 
624  print('Term.__repr__()...', end=''); sys.stdout.flush()
625  assert repr(Term()) == "'Term(())'", repr(Term())
626  assert repr(Term((0, 0))) == "'Term((0, 0))'", repr(Term((0, 0)))
627  assert repr(Term((1, 2))) == "'Term((1, 2))'", repr(Term((1, 2)))
628  assert repr(Term([1, 2])) == "'Term((1, 2))'", repr(Term([1, 2]))
629  assert repr(Term((1, None, 2))) == "'Term((1, None, 2))'", repr(Term((1, None, 2)))
630  assert repr(Term((3, -5, 7))) == "'Term((3, -5, 7))'", repr(Term((3, -5, 7)))
631  assert repr(Term((3, 5.0, decimal.Decimal('7')))) == "'Term((3, 5.0, Decimal('7')))'",\
632  repr(Term((3, 5.0, decimal.Decimal('7'))))
633  assert repr(Term((3, 1, 7))) == "'Term((3, 1, 7))'", repr(Term((3, 1, 7)))
634  assert repr(Term((3, 0, 7))) == "'Term((3, 0, 7))'", repr(Term((3, 0, 7)))
635  print('ok'); sys.stdout.flush()
636 
637 
638  print('Term.__str__()...', end=''); sys.stdout.flush()
639  assert str(Term()) == '1', str(Term())
640  assert str(Term((0, 0))) == '1', str(Term((0, 0)))
641  assert str(Term((1, 2))) == 'A*B^2', str(Term((1, 2)))
642  assert str(Term([1, 2])) == 'A*B^2', str(Term([1, 2]))
643  assert str(Term((3, -5, 7))) == 'A^3*B^-5*C^7', str(Term((3, -5, 7)))
644  assert str(Term((3, 5.0, decimal.Decimal('7')))) == 'A^3*B^5.0*C^7', \
645  str(Term((3, 5.0, decimal.Decimal('7'))))
646  assert str(Term((3, 1, 7))) == 'A^3*B*C^7', str(Term((3, 1, 7)))
647  assert str(Term((3, 0, 7))) == 'A^3*C^7', str(Term((3, 0, 7)))
648  assert str(Term((1, None, 0, 2))) == 'A*B^?*D^2', str(Term((1, None, 0, 2)))
649  t = Term((3, 0, 7, None, 1))
650  assert str(t) == 'A^3*C^7*D^?*E', str(t)
651  assert Term.__str__(t, mulstr='') == 'A^3C^7D^?E', (t, Term.__str__(t, mulstr=''))
652  assert Term.__str__(t, mulstr=' . ') == 'A^3 . C^7 . D^? . E', \
653  (t, Term.__str__(t, mulstr=' . '))
654  assert Term.__str__(t, simplify=True) == 'A^3*C^7*D^?*E', \
655  (t, Term.__str__(t, simplify=True))
656  assert Term.__str__(t, simplify=False) == 'A^3*B^0*C^7*D^?*E^1', \
657  (t, Term.__str__(t, simplify=False))
658  assert Term.__str__(t, varsstr='tuXYZ') == 't^3*X^7*Y^?*Z', \
659  (t, Term.__str__(t, varsstr='tuXY'))
660  assert Term.__str__(t, varsstr='tuXYZ', nonestr='None') == 't^3*X^7*Y^None*Z', \
661  (t, Term.__str__(t, varsstr='tuXY', nonestr='None'))
662  assert Term.__str__(t, varsstr='tuXYZ', mulstr=' . ', simplify=False) \
663  == 't^3 . u^0 . X^7 . Y^? . Z^1', \
664  (t, Term.__str__(t, varsstr='tuXYZ', mulstr=' . ', simplify=False))
665  assert Term.__str__(t, varsstr='tuXYZ', expstr='^(', exprstr=')') == 't^(3)*X^(7)*Y^(?)*Z',\
666  (t, Term.__str__(t, varsstr='tuXYZ', expstr='^(', exprstr=')'))
667  print('ok'); sys.stdout.flush()
668 
669 
670  print('Term.cmp_order()...', end=''); sys.stdout.flush()
671  print('???', end='')
672  print('ok'); sys.stdout.flush()
673 
674 
675  print('Term.deriv()...', end=''); sys.stdout.flush()
676  for n in range(-100, 100):
677  assert Term.deriv(Term((n, ))) == (n, Term((n - 1, ))), (n, Term.deriv(Term((n, ))))
678  assert Term.deriv(Term((n, 33))) == (n, Term((n - 1, 33))), \
679  (n, Term.deriv(Term((n, 33))))
680  assert Term.deriv(Term((0, 1, 2, n, 4, 5)), i=3) == (n, Term((0, 1, 2, n - 1, 4, 5))), \
681  (n, Term.deriv(Term((0, 1, 2, n, 4, 5)), i=3))
682  assert Term.deriv(Term((n, 33)), k=0) == (1, Term((n, 33))), \
683  (n, Term.deriv(Term((n, 33)), k=0))
684  assert Term.deriv(Term((n, 33)), k=2) == (n*(n - 1), Term((n - 2, 33))), \
685  (n, Term.deriv(Term((n, 33)), k=2))
686  assert Term.deriv(Term((n, 33)), k=3) == (n*(n - 1)*(n - 2), Term((n - 3, 33))), \
687  (n, Term.deriv(Term((n, 33)), k=3))
688  if -1 <= n < 0:
689  assert Term.deriv(Term((n, 33)), k=-1) == (None, Term((n + 1, 33))), \
690  (n, Term.deriv(Term((n, 33)), k=-1))
691  else:
692  assert Term.deriv(Term((n, 33)), k=-1) == (1/(n + 1), Term((n + 1, 33))), \
693  (n, Term.deriv(Term((n, 33)), k=-1))
694  if -2 <= n < 0:
695  assert Term.deriv(Term((n, 33)), k=-2) == (None, Term((n + 2, 33))), \
696  (n, Term.deriv(Term((n, 33)), k=-2))
697  else:
698  assert Term.deriv(Term((n, 33)), k=-2) \
699  == (1/((n + 1)*(n + 2)), Term((n + 2, 33))), \
700  (n, Term.deriv(Term((n, 33)), k=-2))
701  if -3 <= n < 0:
702  assert Term.deriv(Term((n, 33)), k=-3) == (None, Term((n + 3, 33))), \
703  (n, Term.deriv(Term((n, 33)), k=-3))
704  else:
705  assert Term.deriv(Term((n, 33)), k=-3) \
706  == (1/((n + 1)*(n + 2)*(n + 3)), Term((n + 3, 33))), \
707  (n, Term.deriv(Term((n, 33)), k=-3))
708  assert Term.deriv(Term((None, 33)), k=n) == (None, Term((None, 33))), \
709  (None, Term.deriv(Term((None, 33)), k=n))
710  print('ok'); sys.stdout.flush()
711 
712 
713  print('Term.eval()...', end=''); sys.stdout.flush()
714  t = Term()
715  assert t.eval() == 1, (t, t.eval())
716  assert t.eval(0) == 1, (t, t.eval(0))
717  assert t.eval(1) == 1, (t, t.eval(1))
718  assert t.eval(2) == 1, (t, t.eval(2))
719  assert t.eval(3) == 1, (t, t.eval(3))
720  assert t.eval(None) == None, (t, t.eval(None))
721  t = Term((2, ))
722  assert t.eval() == 1, (t, t.eval())
723  assert t.eval(0) == 0, (t, t.eval(0))
724  assert t.eval(1) == 1, (t, t.eval(1))
725  assert t.eval(2) == 4, (t, t.eval(2))
726  assert t.eval(3) == 9, (t, t.eval(3))
727  assert t.eval(None) == None, (t, t.eval(None))
728  t = Term((2, 3))
729  assert t.eval() == 1, (t, t.eval())
730  assert t.eval(0) == 0, (t, t.eval(0))
731  assert t.eval(1) == 1, (t, t.eval(1))
732  assert t.eval(2) == 4*8, (t, t.eval(2))
733  assert t.eval(3) == 9*27, (t, t.eval(3))
734  assert t.eval(None) == None, (t, t.eval(None))
735  t = Term((0, 3))
736  assert t.eval() == 1, (t, t.eval())
737  assert t.eval(0) == 0, (t, t.eval(0))
738  assert t.eval(1) == 1, (t, t.eval(1))
739  assert t.eval(2) == 8, (t, t.eval(2))
740  assert t.eval(3) == 27, (t, t.eval(3))
741  assert t.eval(None) == None, (t, t.eval(None))
742 
743  t = Term()
744  assert t.eval((0, 0)) == 1, (t, t.eval((0, 0)))
745  assert t.eval((4, 0)) == 1, (t, t.eval((4, 0)))
746  assert t.eval((4, 5)) == 1, (t, t.eval((4, 5)))
747  assert t.eval(None) == None, (t, t.eval(None))
748  t = Term((2, ))
749  assert t.eval((0, 0)) == 0, (t, t.eval((0, 0)))
750  assert t.eval((4, 0)) == 16, (t, t.eval((4, 0)))
751  assert t.eval((4, 5)) == 16, (t, t.eval((4, 5)))
752  assert t.eval((4, None)) == 16, (t, t.eval((4, None)))
753  t = Term((2, 3))
754  assert t.eval((0, 0)) == 0, (t, t.eval((0, 0)))
755  assert t.eval((4, 0)) == 0, (t, t.eval((4, 0)))
756  assert t.eval((4, 5)) == 16*125, (t, t.eval((4, 5)))
757  assert t.eval([4, 5]) == 16*125, (t, t.eval([4, 5]))
758  assert t.eval((4, None)) == None, (t, t.eval((4, None)))
759  t = Term((0, 3))
760  assert t.eval((0, 0)) == 0, (t, t.eval((0, 0)))
761  assert t.eval((4, 0)) == 0, (t, t.eval((4, 0)))
762  assert t.eval((0, 5)) == 125, (t, t.eval((4, 0)))
763  assert t.eval((4, 5)) == 125, (t, t.eval((4, 5)))
764  assert t.eval((4, 5, 6)) == 125, (t, t.eval((4, 5, 6)))
765  assert t.eval((4, None)) == None, (t, t.eval((4, None)))
766  t = Term((-2, 3))
767  assert t.eval((4, 0)) == 0, (t, t.eval((4, 0)))
768  assert t.eval((4, 5)) == 125/16, (t, t.eval((4, 5)))
769  assert t.eval((4, None)) == None, (t, t.eval((4, None)))
770  t = Term((2, None))
771  assert t.eval((4, 0)) == None, (t, t.eval((4, 0)))
772  assert t.eval((4, 5)) == None, (t, t.eval((4, 5)))
773  assert t.eval((4, None)) == None, (t, t.eval((4, None)))
774  print('ok'); sys.stdout.flush()
775 
776 
777  print('Term.partialeval()...', end=''); sys.stdout.flush()
778  t = Term()
779  assert t.partialeval(()) == (1, t), (t, t.partialeval(()))
780  assert t.partialeval((0, 5)) == (1, t), (t, t.partialeval((0, 5)))
781  assert t.partialeval((4, 5)) == (1, t), (t, t.partialeval((4, 5)))
782  assert t.partialeval((None, 5)) == (1, t), (t, t.partialeval((None, 5)))
783  assert t.partialeval((4, None)) == (1, t), (t, t.partialeval((4, None)))
784  assert t.partialeval((4, None, 6)) == (1, t), (t, t.partialeval((4, None, 6)))
785  t = Term((2, 3))
786  assert t.partialeval((0, 5)) == (0, (0, 0)), (t, t.partialeval((0, 5)))
787  assert t.partialeval((4, 5)) == (16*125, (0, 0)), (t, t.partialeval((4, 5)))
788  assert t.partialeval((None, 5)) == (125, (2, 0)), (t, t.partialeval((None, 5)))
789  assert t.partialeval((4, None)) == (16, (0, 3)), (t, t.partialeval((4, None)))
790  assert t.partialeval((4, None, 6)) == (16, (0, 3)), (t, t.partialeval((4, None, 6)))
791  t = Term((-2, 3))
792  assert t.partialeval((4, 5)) == (125/16, (0, 0)), (t, t.partialeval((4, 5)))
793  assert t.partialeval((None, 5)) == (125, (-2, 0)), (t, t.partialeval((None, 5)))
794  assert t.partialeval((4, None)) == (1/16, (0, 3)), (t, t.partialeval((4, None)))
795  assert t.partialeval((4, None, 6)) == (1/16, (0, 3)), (t, t.partialeval((4, None, 6)))
796  t = Term((2, None))
797  assert t.partialeval((0, 5)) == (None, (0, None)), (t, t.partialeval((0, 5)))
798  assert t.partialeval((4, 5)) == (None, (0, None)), (t, t.partialeval((4, 5)))
799  assert t.partialeval((None, 5)) == (None, (2, None)), (t, t.partialeval((None, 5)))
800  assert t.partialeval((4, None)) == (16, (0, None)), (t, t.partialeval((4, None)))
801  assert t.partialeval((4, None, 6)) == (16, (0, None)), (t, t.partialeval((4, None, 6)))
802  print('ok'); sys.stdout.flush()
803 
804 
805 
806  print()
807  print('Polynomial()...', end=''); sys.stdout.flush()
808  assert Polynomial() == {}, Polynomial()
809  assert Polynomial(()) == {}, Polynomial(())
810  assert Polynomial(Term()) == {Term(): 1}, Polynomial(Term())
811  assert Polynomial(Term((0, 0))) == {Term((0, 0)): 1}, Polynomial(Term((0, 0)))
812  t = Term((2, 3))
813  assert Polynomial(t) == {t: 1}, (t, Polynomial(t))
814  u = Term((5, 4))
815  assert Polynomial((t, u)) == {t: 1, u: 1}, (t, u, Polynomial((t, u)))
816  assert Polynomial([t, u]) == {t: 1, u: 1}, (t, u, Polynomial([t, u]))
817  assert Polynomial((t, t)) == {t: 2}, (t, u, Polynomial((t, t)))
818  assert Polynomial({t:8, t:5}) == {t: 5}, (t, u, Polynomial({t:8, t:5}))
819 
820  assert Polynomial(coef=3) == {}, Polynomial(coef=3)
821  assert Polynomial((t, u), coef=-7) == {t: -7, u: -7}, (t, u, Polynomial((t, u), coef=-7))
822  assert Polynomial([t, u], coef=-7) == {t: -7, u: -7}, (t, u, Polynomial([t, u], coef=-7))
823  assert Polynomial((t, t), coef=-7) == {t: -14}, (t, u, Polynomial((t, t), coef=-7))
824  assert Polynomial([t, u, t], coef=-7) == {t: -14, u: -7}, \
825  (t, u, Polynomial([t, u, t], coef=-7))
826  assert Polynomial({t:8, t:5}, coef=-7) == {t: -35}, (t, u, Polynomial({t:8, t:5}, coef=-7))
827  print('???', end='')
828  print('ok'); sys.stdout.flush()
829 
830 
831  print('Polynomial.__iadd__()...', end=''); sys.stdout.flush()
832  print('???', end='')
833  print('ok'); sys.stdout.flush()
834 
835 
836  print('Polynomial.__repr__()...', end=''); sys.stdout.flush()
837  assert repr(Polynomial()) == "'Polynomial({{}}, varsstr=\"{0}\")'".format(ALPHA), \
838  repr(Polynomial())
839  print('???', end='')
840  print('ok'); sys.stdout.flush()
841 
842 
843  print('Polynomial.__str__()...', end=''); sys.stdout.flush()
844  assert str(Polynomial()) == '', str(Polynomial())
845  assert str(Polynomial(Term())) == '1', str(Polynomial(Term()))
846  assert str(Polynomial(Term((0, 0)))) == '1', str(Polynomial(Term((0, 0))))
847  print('???', end='')
848  print('ok'); sys.stdout.flush()
849 
850 
851  print('Polynomial.deriv()...', end=''); sys.stdout.flush()
852  p = Polynomial({Term((3, 0, 7, 1)):5, Term((-4, 2, 3, 1)):-3})
853  assert p.deriv() == Polynomial({Term((2, 0, 7, 1)):15, Term((-5, 2, 3, 1)):12}), p.deriv()
854  assert p.deriv(k=2) == Polynomial({Term((1, 0, 7, 1)):30, Term((-6, 2, 3, 1)):-60}), \
855  p.deriv(k=2)
856  assert p.deriv(k=-1) == Polynomial({Term((4, 0, 7, 1)):1.25, Term((-3, 2, 3, 1)):1}), \
857  p.deriv(k=-1)
858  assert p.deriv(i=1) == Polynomial({Term((3, -1, 7, 1)):0, Term((-4, 1, 3, 1)):-6}), \
859  p.deriv(i=1)
860  assert p.deriv(i=2) == Polynomial({Term((3, 0, 6, 1)):35, Term((-4, 2, 2, 1)):-9}), \
861  p.deriv(i=2)
862  print('???', end='')
863  print('ok'); sys.stdout.flush()
864 
865 
866  print('Polynomial.eval()...', end=''); sys.stdout.flush()
867  assert Polynomial().eval() == 0, Polynomial().eval()
868  assert Polynomial(Term()).eval() == 1, Polynomial(Term()).eval()
869  assert Polynomial(Term((0, 0))).eval() == 1, Polynomial().eval(Term((0, 0)))
870  p = Polynomial(Term((3, 0, 7, 1)))
871  assert p.eval() == 1, (p, p.eval())
872  assert p.eval(1) == 1, (p, p.eval(1))
873  assert p.eval(2) == 8*128*2, (p, p.eval(2))
874  assert p.eval((5, 6, 2, 13)) == 125*128*13, (p, p.eval((5, 6, 2, 13)))
875  assert p.eval([5, 6, 2, 13]) == 125*128*13, (p, p.eval([5, 6, 2, 13]))
876  assert p.eval((5, 0, 2, 13)) == 125*128*13, (p, p.eval((5, 0, 2, 13)))
877  assert p.eval((5, 6, 2, 0)) == 0, (p, p.eval((5, 6, 2, 0)))
878  p = Polynomial(Term((3, 0, 7, 1)), coef=-3)
879  assert p.eval() == -3, (p, p.eval())
880  assert p.eval(1) == -3, (p, p.eval(1))
881  assert p.eval(2) == -3*8*128*2, (p, p.eval(2))
882  assert p.eval((5, 6, 2, 13)) == -3*125*128*13, (p, p.eval((5, 6, 2, 13)))
883  assert p.eval([5, 6, 2, 13]) == -3*125*128*13, (p, p.eval([5, 6, 2, 13]))
884  assert p.eval((5, 0, 2, 13)) == -3*125*128*13, (p, p.eval((5, 0, 2, 13)))
885  assert p.eval((5, 6, 2, 0)) == 0, (p, p.eval((5, 6, 2, 0)))
886  p = Polynomial((Term((3, 0, 7, 1)), Term((-2, 2, 3, 1))), coef=-3)
887  assert p.eval() == -6, (p, p.eval())
888  assert p.eval(1) == -6, (p, p.eval(1))
889  assert p.eval(2) == -3*8*128*2 - 3/4*4*8*2, (p, p.eval(2))
890  assert p.eval((5, 6, 2, 13)) == -3*125*128*13 - 3/25*36*8*13, (p, p.eval((5, 6, 2, 13)))
891  assert p.eval((5, 0, 2, 13)) == -3*125*128*13, (p, p.eval((5, 0, 2, 13)))
892  assert p.eval((5, 6, 2, 0)) == 0, (p, p.eval((5, 6, 2, 0)))
893  print('???', end='')
894  print('ok'); sys.stdout.flush()
895 
896 
897  print('Polynomial.lenterms()...', end=''); sys.stdout.flush()
898  assert Polynomial().lenterms() == None, Polynomial().lenterms()
899  assert Polynomial(Term()).lenterms() == 0, Polynomial(Term()).lenterms()
900  assert Polynomial(Term((0, 0))).lenterms() == 2, Polynomial(Term((0, 0))).lenterms()
901  assert Polynomial(Term((2, 3))).lenterms() == 2, Polynomial(Term((2, 3))).lenterms()
902  assert Polynomial((Term((2, 3)), Term((4, 5)), Term((6, 7)))).lenterms() == 2, \
903  Polynomial((Term((2, 3)), Term((4, 5)), Term((6, 7)))).lenterms()
904  assert Polynomial(Term((7, 8, 9))).lenterms() == 3, Polynomial(Term((7, 8, 9))).lenterms()
905  print('???', end='')
906  print('ok'); sys.stdout.flush()
907 
908 
909  print('Polynomial.partialeval()...', end=''); sys.stdout.flush()
910  assert Polynomial().partialeval(()) == {}, Polynomial().partialeval(())
911  p = Polynomial()
912  assert p.partialeval(()) == {}, (p, p.partialeval(()))
913  assert p.partialeval((0, 5)) == {}, (p, p.partialeval((0, 5)))
914  assert p.partialeval((None, 5)) == {}, (p, p.partialeval((None, 5)))
915  p = Polynomial(Term((2, 3)))
916  assert p.partialeval((0, 5)) == Polynomial(Term((0, 0)), coef=0), \
917  (p, p.partialeval((0, 5)))
918  assert p.partialeval((4, 5)) == Polynomial(Term((0, 0)), coef=16*125), \
919  (p, p.partialeval((4, 5)))
920  assert p.partialeval([4, 5]) == Polynomial(Term((0, 0)), coef=16*125), \
921  (p, p.partialeval([4, 5]))
922  assert p.partialeval((None, 5)) == Polynomial(Term((2, 0)), coef=125), \
923  (p, p.partialeval((None, 5)))
924  assert p.partialeval((4, None)) == Polynomial(Term((0, 3)), coef=16), \
925  (p, p.partialeval((4, None)))
926  assert p.partialeval((4, None, 6)) == Polynomial(Term((0, 3)), coef=16), \
927  (p, p.partialeval((4, None, 6)))
928  p = Polynomial((Term((3, 0, 7, 1)), Term((-2, 2, 3, 1))), coef=-3)
929  assert p.partialeval((5, 0, 2, 13)) == Polynomial(Term((0, 0, 0, 0)), coef=-3*125*128*13), \
930  (p, p.partialeval((5, 0, 2, 13)))
931  assert p.partialeval((5, 6, 2, 13)) \
932  == Polynomial(Term((0, 0, 0, 0)), coef= -3*125*128*13 - 3/25*36*8*13), \
933  (p, p.partialeval((5, 6, 2, 13)))
934  assert p.partialeval((5, None, 2, 13)) \
935  == Polynomial({Term((0, 0, 0, 0)): -3*125*128*13,
936  Term((0, 2, 0, 0)): -3/25*8*13}), \
937  (p, p.partialeval((5, None, 2, 13)))
938  print('???', end='')
939  print('ok'); sys.stdout.flush()
940  debug.test_end()
941 
942  main_test()
943 ##\endcond MAINTEST