MAY TODO : In French, since it is only for me :)
----------

++++++++++++++++++++++++++++++++++
++++ Fonctionnalites primaires ***
++++++++++++++++++++++++++++++++++

+ Algebre lineaire sur les matrices (operations elementaires, augment, resize, extract, transpose, trace, reduction de gauss, resolution des systemes (bareiss, divfree, gauss), determinant (gauss, bareiss, divfree, laplace?), polynome caracteristique, rang, noyau, valeurs/vecteurs propres, ...) 
+ limites (Gruntz)
+ Factorisation sur Z (Distinc Degree Factorisation + Cantor-Zassenhaus) / Factorisation modulaire (?)
  ==> Factorisation sur R ou C (Utilisation de formule classiques pour casser les degrees 2, 3 et 4).
     ==> Solveur de polynome en une variable et/ou de systeme lineaire et/ou de f(x)=alpha avec f dans une table
  	==> Primitives (algo poor man)
+ sum(x^k, k=1..N)= ?


++++++++++++++++++++++++++++++++++++++++
++++ Fonctions Internes / Extensions +++
++++++++++++++++++++++++++++++++++++++++

+ mod(P,A) [EXTENSION FACULTATIVE]
  A ne peut etre que :
         un entier.
  	 un polynome
  Corps de Galois devient donc : x % UPOLY % INTEGER
  Operation de liftage dans les entiers naturels ?
  != remainder
  Problem: Si on fait RootOf, l'interet de mod diminue (et inversement).
  Exemple:	mod(x,2)+mod(y,2)*3 -> mod(x+y,2)
 
 Forme	MOD(value, modulus[, vars])

 Eval:	si nops != 2 et nops != 3 throw error ?
 	modulus = eval (modulus)
	si modulus = 0 return value
 	si modulus = INTEGER
 	   oldint = kernel_intmod (modulus)
	   v = reeval (value)
	   kernel_intmod (oldint)
	   si v is a MODULO and v.modulus = INTEGER
	      si v.modulus != modulus
	      	      modulus = gcd (v.modulus, modulus)
	      	      v = reeval (v.value)
	      sinon   v = v.value
	   return hold (mod (v, modulus)
	sinon modulus non entier
	   var = nops() > 2 ? eval(vars) : may_indets (modulus)
	   FIXME: si flags only poly
	   	     si pas poly
		     	v = may_rationalize (v)
			si pas poly
			   On fait rien
			sinon
	   v = may_expand_mod (eval (value), modulus, var)
	   si v est un modulo
	      si v.modulus est un entier
	      	 intmod = v.modulus
	      	 oldint = kernel_intmod (intmod)
	      	 si v.value est aussi un modulo
		    modulus = gcd (modulus, v.value.modulus)
		    divqr (0, &v, v.value.value, modulus, var)
		 sinon
		    v = v.value
		 kernel_intmod (oldint)
		 return hold (mod (mod (v, modulus, var), intmod)
	      sinon
		 modulus = gcd (modulus, v.modulus)
		 divqr (0, &v, v.value, modulus, var)
	    return hold (mod (v, modulus, var) 
 Add/Mul/Pow: eval (add/mul/pow)
 avec modulus = gcd (modulus) s'il y en a plusieurs
 Attention on peut avoir mod(x,2) + mod(x+1,x^2+1) qui doit donner mod(mod(1,x^2+1),2)
 Surcharger: divqr / degree / expand / gcd / diff / ... pour qu'il les gere ? Faire un flag global ?
 Probleme: mod((x^42-1)/(x-1),x-1,x) ?????
 	   Faire avec ? Utiliser un flag pour demander de rationalizer avant et de ne rien faire si value n'est pas un polynome ? (ie. interdire de calculer l'inverse modulo).

+ RootOf(p(x),x,i)
  Represente une des racines du polynome p(x).
  Si i=0, une racine quelconque. Sinon i=1..deg(p), et represente l'index de la racine.
  
  Eval:
	Si p est independant de x, return NAN
	Si i n'est pas un entier >= 0 return NAN
	p = expand (sqrfree (p, x)) sans les multiciplicites.
	Si i > deg(p), renvoit NAN
	Si deg(p) <= 1, renvoit la valeur.
	p = primpart (p)
	Si x n'est pas une variable locale,
	   local_x = get_loval_var (x)
	   p = replace (p, x, local_x)
	   x = local_x 
	Return Hold (p, x, i)
   Gestion pow (Rootof, N) ? Si N > 0 ? Si N < 0 ?
   Remarque:	   (1+RootOf(X^2-5))^100 = (1*X+1)^100 % (X^2-5)
   Gestion diff / series / evalf (!) ?
   Simplification de la somme/produit/... des racines ?
   Pouvoir extraire les racines des polynomes de degre 2, 3 et 4 ?

 + MATRIX

++++++++++++++++++++++++++++++++++++
++++ Operations basiques         +++
++++++++++++++++++++++++++++++++++++

may_t   may_normal        (may_t x);
     	Forme normale d'une expression - dans la mesure du possible, deux
	expressions egales ont leur forme normal structurellement egales
   	ou bien la difference des deux est nulle.
	(sqrtsimp, rectform, normalsign, reduce, rationalize)
	Penser a remplacer les valeurs non-rationalles temporairement (sqrt(2) --> a --> Utiliser RootOf ? Mod ?)
	pour gerer (sqrt(2)-x)/(2-x^2) ?

int     may_equal_p (may_t a, may_tb)
  	Retourne may_zero_p (may_normal (a-b))

may_t   may_expsimp      (may_t x);
	Simplification des expressions mettant en oeuvre des exp / log
	==> Difference avec may_reduce ?

may_t   may_trigsimp      (may_t x);
	Simplification des expressions mettant en oeuvres des cos/sin/tan
	==> comdenom + Mod ( , s^2+c^2-1) ?

int	may_upoly_p       (may_t x, may_domain_e domain, may_t var)
	Teste si x est un polynome univarie de la variable x avec les coefficients dans le domaine 'domain'. Retourne 0 si x n'est pas, 1 si x l'est, 2 si x l'est ET tous ces coefficients sont des 'pure numbers'. Ajouter MAY_PURE_D ?

may_t   may_upoly_coeff (may_t x, may_t var, mpz_srcptr deg)
	Retourne le coeff de degree 'deg' de la variable 'var' dans 'x'.
	Ou NULL si ce n'est pas possible.
	(Reutilise une partie de may_degree).

may_t   may_append (size_t n, const may_t *list, MAY_APPEND_NORMAL|MAY_APPEND_UNIQUE)
	Retourne la liste concatenee de tous les arguments passees en parametre. Si list[i] est une liste, on concatene chacun de ses elements.
	Si MAY_APPEND_UNIQUE, fait en sorte que les membres de la liste resultante soit unique dans la liste (ordre indetermine dans ce cas la).

may_t   may_mid (may_t list, size_t begin, size_t end)
        Retourne la liste de begin a end (inclus) depuis list.  si end est negatif, on s'arret e a nops(list)-end (ie left(list,1) <=> mid(0,-2,list) ).Si begin negatif, on demarre depuis nops(list)-begin. si begin > end, on renvoit la liste vide. si begin ou end sont hors de la taille de la liste, on renvoit la liste vide.

int     may_member_p (may_t list, may_t x)
 	Retourne TRUE si x est membre de 'list'.
	Voir si on fait que si x est une liste, retourne TRUE si un des membres de x est contenue dans list ?

may_t   may_optimize_indets (may_t list_var).
  	Optimize la liste des indetermines. (Interne)
	en recherchant des dependances algebriques entre les indetermines.
	==> Comment faire ?
	Utiliser les proprietes des fonctions exp / sin / cos ?
	Comment faire un algorithme un minimum robuste

may_t   may_reduce (may_t x)
  	Recherche les dependances entre les indeterminees de x et retourne x
	apres simplification par cette nouvelle base (Utilisation de may_optimize_indets).

may_t   may_mod (may_t p1, may_t p2, may_t vars)
  	return Mod(p1, p2,vars)
	p1 / p2 polynome (ou p2 entier)
	vars peut etre null (may_indents)

may_t   may_invmod (may_t p1, may_t p2, may_t vars)
  	return 1 / (p1 % p2)
	p1 / p2 polynome (ou p2 entier)
	Necessite may_gcdex

may_t	may_unmod (a)
	Enleve toute reference au modulo de a (Repasse a dans Z).
	
may_t	may_expand_mod (may_t a, may_t modulus, may_t vars)
	Retourne a developpe  modulo modulus (Polynome de vars)

may_t 	may_resultant (may_t a, may_t b, may_t x)
	Retourne le resultant de A et de B. Voir comment on peut recuperer le code du sous-resulatant (PGCD).

void    may_q2z (may_t *num, may_t *denom, may_t x)
	Transforme x vue comme polynome multivariee sur les rationnels en un
	polynome sur les entiers telle que x = *num / *denom avec
	*denom un entier et *num le polynome sur les entiers.

++++++++++++++++++++++++++++++
++++    Amelioration       +++
++++++++++++++++++++++++++++++

 + Les RANGE devraient .betre une extension et non pas int.Aegre comme lment de base.

 + Ajouter le support de MAY_OUT_UNIT_CIRCLE et MAY_IN_UNIT_CIRCLE dans les predicate.

 + may_ratfactor --> may_unifactor ? --> may_ufactor ?
 + may_ratfactor devrait supporter de travailler % INTEGER <== Probleme en multivari.be...

 + Ameliorer "evalr" pour qu'il gere plus de fonctions (trigonometrie entre autre).
   Utiliser mpfi ?

 + may_rewrite:
    Construire une methode pour faire plusieurs rewrite d'un coup de parsing.
    Construire un arbre de decision ? Voir ce qui a .Aete fait pour l'antidiff.

 + tests:
    Utiliser un fichier a part pour stocker les donn.bees.

 + may_match x et $1*x+$2 marche-t-il ? J'ai des doutes.
   Est-ce necessaire ?

 + "sign(x)^2" devrait .Atre simplifi en 1 sauf si x vaut 0.
   "sign(x)^3" devrait tre simplifi en sign(x).

+ extension + rationalize/expand/..

++++++++++++++++++++++++++++++
++++    Corriger bugs      +++
++++++++++++++++++++++++++++++

+ Finir may_sqrtsimp pour que sqrt(30)*sqrt(105) == 15*sqrt(14)
  Et (7+5*sqrt(2))^(1/3) --> (1+sqrt(2))
  Et 1/(2^(1/2)+3^(1/2)+6^(1/2)) --> 5/23*sqrt(3)-1/23*sqrt(2)*sqrt(3)+7/23*sqrt(2)-12/23 ??
  Et 2^(1/4)*(2^(1/2)+2)/(8+6*2^(1/2))^(1/2) --> 1 (Ca a l'air compliqu.be!!!!)
  Et (5-2*3^(1/2)*x-2*2^(1/2)*3^(1/2)+2*2^(1/2)*x+x^2)/(1-2*3^(1/2)*x+x^2)
     --> (-sqrt(3)+sqrt(2)+x)/(-sqrt(3)-sqrt(2)+x)
  Et (19+15*2^(1/3)+12*2^(2/3))^(1/3) --> 1+2^(1/3)+2^(2/3)

+ may_get_domain devrait etre debuggue.

+ f({1,2}) ne devrait pas donner f(1,2)

+ r  "1/sin(a*x)" -oantidiff x -odiff x -otcollect
 ==> [MAYLIB]: assertion failed in polvar.c.134: n >= 1

+  (real(x)+abs(real(x)))/(real(x)+abs(real(x))) = 1
   alors que ce n'est pas vrai presque partout...

+ 4^(1/2) % 3 vaut-il 1 (maple) ou 2 (mupad/xcas) ?
  Faut-il simplifier 4 en 3 si N n'est pas entier ?
  Et 4^n % 3 faut-il le simplifier en 1 ? ou pas ?
  Probleme general du choix de la racine : 4^(1/2) peut donner 1 ou 2 suivant le choix du signe. 1 peut paraitre comme racine plus simple (et plus privisible car on fait tout le temps les operations de modulo).

+ Definir proprement degree(x^-1) et voir le conflit avec degree(0)
  
 + ./t-pika "(x+2)*INFINITY"
==> INFINITY+INFINITY*x
 Reponse pas vraiment fausse pour x<0 mais franchement pas tr.As intelligente...

+ ./t-pika "-7/2*sign(2-x)/abs(2-x)+4/5/(5-x^2)-31/25/(1-1/5*x^2)+87/25*sign(5-x^2)*x/abs(5-x^2)-1/50*sign(x)/abs(x)+8/5*x^2/(5-x^2)^2+17/5*x/(5-x^2)^2" -ocomdenom
[MAYLIB]: assertion failed in lcm1.c.102: tmp != NULL
==> Pb dans may_divqr & friends qui ne gerent pas 
 le fait d'avoir plusieurs variables qui sont dependantes de la meme:
   degree(x+abs(x),x) ==> failed.
  Creer degree2 moins strict ? Attention que faire pour x^(1/2) !!!!
  		  degree (x^(1/2)+x,x^(1/2) ???

+ ./t-pika "tan(5*PI/18)*tan(7*PI/18)*sqrt(3)" -otcollect
==> (cosh(1/2*log(3)-2/3*I*PI)+sinh(1/2*log(3)-2/3*I*PI)-sinh(1/2*log(3)-1/9*I*PI)-cosh(1/2*log(3)-1/9*I*PI)+cosh(1/2*log(3)+2/3*I*PI)+sinh(1/2*log(3)+2/3*I*PI)-sinh(1/2*log(3)+1/9*I*PI)-cosh(1/2*log(3)+1/9*I*PI))/(1-2*cos(1/9*PI))
  ./t-pika "tan(5*PI/18)*tan(7*PI/18)" -otcollect
==> -(1+2*cos(1/9*PI))/(1-2*cos(1/9*PI))
 Le sqrt(3) empeche MAY de recoller les morceaux ==> A corriger !

+ expand ne fournit pas une entre compltement dveloppe et  cause du flag 'expand' ne renvoit pas l'entre.
 ./t-pika "(-3/2*x*(1-x)^(4/3)-9/20*(1-x)^(7/3)+9/20*(1+7/3*x)*(1-x)^(4/3)+x^2*(1-x)^(1/3))/(1-x)^(1/3)" -oexpand -oexpand
9/20-9/20*(1-x)^2+x^2-9/20*x*(1-x)-9/20*x
[pphd@localhost may]$ ./t-pika "9/20-9/20*(1-x)^2+x^2-9/20*x*(1-x)-9/20*x" -oexpand
x^2

++++++++++++++++++++++++++++++
++++    Optimisations      +++
++++++++++++++++++++++++++++++

+ Partout :)

+ may_expand peut etre pas tres performant sur certains entrees.
  	Exemple: (1+3*x+2*x^2)^1000
	=> Convertir si polynome univari.be en entier + gmp ? Borne d'erreur ?
	Ameliorer les threshold
  Determiner si le polynome est sparse ou pas ( Sparse <=> Product (Degree Max of var[i]) > (# elems)^2)

+ may_eval_sum / may_eval_product: les sommes dans les sommes doivent etre fusionnees et non pas retriees si possibles.

+ may_add:
  Tester si les entrees sont des sommes evaluees, et dans ce cas faire une fusion des sommes
  sans passer par eval.
+ may_mul:
  De meme.

+ may_replace (P(x), x, NUM)
  Si P est un polynome univarie et NUM aussi, 
  alors on peut optimiser en cachant NUM^d pour d <= degree de P
  	may_replace_upol (may_t P, may_t x, may_t num)
		MAY_ASSERT (MAY_TYPE (x) == MAY_STRING_T && MAY_PURENUM_P(num));
		Appel recursif avec une table de la taille de deg P+1
		Remplissage de cette table par les valeurs calculees : faire une evaluation binaire et remplir par le haut.
  Plus general que cela : par exemple, si on a plusieurs occurences de sqrt(x), et qu'on remplace x par un flottant (ou cos...)
  on va calculer plusieurs fois sqrt(2.3) (x->2.3). Detecter cela et l'optimiser ? Comment ?
	Cr.Aeer x = may_compress (x)
		Parcourt x recursivement et s'il trouve une sous-expression deja utilise autre part dans l'expression, il retourne cette derniere.
		==> Reduire la taille d'une expression / Ameliorer les performances des comparaisons.
		==> Permet de n'avoir qu'une sous-expression 'sqrt(x)' dans mon expression.
	may_replace devrait faire un cache specifique (avec gestion des exponentiations deja calcule pour calculer la nouvelle).
	Cela n'est utile que si on remplace par quelque chose de numerique (autrement ca ne sert pas vraiment).
+ may_sub:
  De m.beme.

+ may_div_qr univarie:
  Voir comment on peut faire via evaluation entiere puis remontee heuristique
  Voir aussi comment on peut faire via une evaluation par Newton et une division par les puissances croissantes.

+ may_expand_var/may_collect ne devrait pas developper si possible.
     Si pas dependant de x, retourner x
     Si c'est une somme, collect chacun des elements de la somme, puis regroupement des degrees identiques.
     Si c'est un produit, collect chacun des elements et extraire les elements independants de x des autres. 
     	Developper les elements de x si plus de 2.
	mul_expand par les elements independants.
     Si pow et entier, expand (c'est forcement dependant de x).

+ may_gcd:
  Hack pour gerer les cas gcd(P^N,Q) sans developper P^N
     gcd (P^n, Q^m) =
     	 . g = 1
	 . g' = gcd(P,Q)
	 . tant que g' != 1
	   	si n < m :
		   g = g * g' ^n
		   P = P/g'
		   Q = g'
		   m = m - n
		sinon si n > m
		   g = g * g' ^ m
		   Q = Q/g'
		   P = g'
		   n = n - m
		sinon
		   g = g * g' ^ n
		   break loop
		g' = gcd (P, Q)
	 . return g
  Hack: Substituer variable locale s'il existe N entier tel que y n'existe que sous la forme y^N dans les expressions.
  Hack: reordonner les hacks de telle facon que l'on fasse la decomposition en produit / puissance avant le developpement
  des variables (et don la detection des variables non utilisees par une expression).
  Subresultant PRS :
    - Trier la liste du plus petit degree au plus grand / taille coefficient de facon a mimiser le GCD pour le PSR.
    - Inliner la division pour ne plus avoir a faire des convertions inutiles.
  Heuristic GCD:
    - Mettre un point d'arret a partir duquel on ne calcule plus le GD heuristique.
    - Prendre en compte tous les arguments pour ne pas avoir a convertir / deconvertir sans arret.
    - Permet de prendre en compte le minimum des maximum de toutes les entrees.
    - Une passe pour convertir / deconvertir toutes les variables ?
    - La deconvertion ne doit pas faire la double division entiere pour recuperer le mod et le quotient.  
    - Voir si on ne peut pas evaluer plus faible quitte a echouer plus souvent, et a continuer en cas de succes (qui aura l'avantage
      de reduire les degrees).
  GCDMOD: A implanter.
  Algorithme pour detecter quel algo utilise en fonction des entrees (degree total, nombre de variable, degrees partiels, spartivite, ...),

+ matrix: implanter l'algo div_free et frac_free

+ Ajout d'un nouveau type SMALL_INT (=0) :
	.type  = SMALL_INT
	.flags = EVAL|NUM|EXPAND
	.hash  = La valeur petite stock.Aee
  Permet de passer pour les entiers 16 bits (sur une plateforme 32) de 4+(4+4+4+4+4)=24 octets a 4+4=8 octets.
  Ne gagne pas autant que de coder directement dans le pointeur meme ((long)x&1) == 1 (=4 octets)
  Mais evite de faire des tests pour verifier si may_t est bien un pointeur et respecte mieux la norme.
  Impact suiote a integration d'un nouveau type atomique :
	may_enum_t:	Ajout du nouveau type en premier.
	compact_recur1: Ajout du nouveau type.
	may_get_name:	Retourne may_integer_name pour ce nouveau type.
	may_eval:	Gestion du nouveau type.
	may_recompute_hash: Gestion du nouveau type.
	may_dump_rec:	Gestion du nouveau type.
	may_length:	Ajout du nouveau type.
	may_copy_c:	Ajout du nouveau type.
	may_identical:	Ajout du nouveau type (Si les hash et les types sont egaux, les nombres sont egaux).
	may_cmp:	Identique may_identical.
  Impact suite a integration d'un nouveau type entier:
	init_num:	Reprendre : les entiers initialises au demarrage sont des SMALL_INT.
	may_zero_fastp:	Il n'est plus necessaire de tester si c'est INT_T: SMALL_INT_T suffit.
	may_* predicate: Integration du nouveau type.
	may_get_*:	Ajout du nouveau type entier.
	may_set_*:	Ajout du nouveau type entier (FIXME: Non necessaire vraiment, mais dommage de ne pas court-circuite le circuit d'evaluation dans ce cas la).
	may_get_domain: Ajout du nouveau type entier.
	may_num_*:	Ajout du nouveau type entier.
	may_mpz_simplify: Simplification du mpz en SMALL_INT s'il rentre dans le hash.
	evalf:		Ajout du nouveau type entier.
	may_eval_pow:	Ajout du nouveau type entier.
	Reprendre toutes les references a MAY_INT_T (#185).
	Remplacer 	MAY_TYPE (MAY_AT (x, 0)) == MAY_INT_T par MAY_TYPE (MAY_AT (x, 0)) <= MAY_INT_T
	Est-ce que le constructeur MAY_INT doit fonctionner avec un SMALL_INT ?

+++++++++++++++++++++++
++++    Errors      +++
+++++++++++++++++++++++

+ Classe: may_catch_c: constructeur may_error_catch (error_throw_handler, NULL);
  	  	       destructeur  may_error_uncatch ();
==>
 try {
  may_catch_c catch;
   /* Do some computing */
 } catch (may_error_e error_code) {
  std::cerr << "ERROR reported: " << may_error_what (error_code) << std::endl;
 }

+ Exporter les defaults thrower

+++++++++++++++++++++++
++++    Autres      +++
+++++++++++++++++++++++

+ Ajout le support partiel (et optionnel) des matrices et de l'algebre linaire.
  Extension: EMAT
+ Ajouter Index d'une matrice: a[i,j]  Ou utiliser MAY_FUNC_T ?
  Est-ce necessaire de permettre de faire des expressions avec ? <== Oui, je pense.
+ Ajouter le cache (Hash-Table) : regler problemes de coherence.
+ Pouvoir ajouter de nouveaux operateurs.
+ Support de l'attribut visibility pour les fonctions internes (http://gcc.gnu.org/wiki/Visibility)
+ Support des thread.

++++++++++++++++++++
++++    Doc      +++
++++++++++++++++++++

Revoir les requirements de l'alignement.
Aligner en struct ?

L'alignement d'un "long" peut etre plus petit que celui d'une structure, je pense que tu veux plut.bt "suitably aligned for a struct" (l'alignement de toutes les structures est le meme, donc comme une structure peut contenir un long l'alignement est plus grand).

Preciser les conditions d'utilisation de may_hold plus finement.
