30

PpHd (./28) :
Pollux (./26) :
Est-ce que may_eval(may_foo_c(may_bar_c(x,y),z)) est équivalent à may_foo(may_bar(x,y),z) ? (modulo la rapidité si par exemple foo=mul et z=0)

Oui. Par contre,
may_eval(may_foo_c(bar = may_bar_c(x,y),z))
bar est incorrect (une évaluation invalide toute les références aux éléments non évalués qu'elle parcourt). Alors que :
may_foo(bar = may_bar(x,y),z)
bar est correct.

- Ah oui, mais selon la doc bar ne devient pas entièrement invalide dans le premier cas puisqu'on peut encore l'évaluer ?!?
- Ce serait possible de formaliser toutes les exigences des extensions pour qu'elles puissent maintenir ce genre d'invariants ? Là ça me paraît très très fragile, c'est à peu près certain que la première extension venue cassera tout si elle a une structure récursive...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

31

Pollux (./29) :
- Je viens de regarder may_subs_c, déjà il y a un gros problème c'est que le namespace des fonctions et des variables est le même : si je fais un subs sur l'expression digamma+1 ça va planter

Non. Il ne se passera rien. Car digamma est une expression et tu as fourni à subs une fonction de ce nom. Donc il ne fera pas le remplacement.
Pollux (./29) :
- Je pensais plutôt au cas où c'est non pas l'utilisateur final (= programme Basic) qui l'utilise, mais un programme écrit en C appelant MAY directement et définissant des fonctions comme digamma pour son usage interne. Peut-être que tu veux plutôt qu'on définisse une extension dans ce cas-là en fait ?

A mon avis, la meilleure facon d'implanter çà efficacement (une vrai fonction, avec une dérivée, et tout, et tout), est de faire une classe d'extension regroupant toutes tes fonctions.
L'enfant 1 est un entier indiquant le numéro de la fonction (0->digamma, 1 ->besselJ, ...)
L'enfant 2 est l'argument de la fonction.
Tu parses ton expression SANS l'évaluer. Puis tu fais un subs_c avec toutes ces nouvelles fonctions, pour les remplacer par les extensions.
Puis tu fais un éval de ton expression (avec tes extensions).
Avec cette méthode, même si un digamma interne apparait, ton digamma reste prioritaire smile
Pollux (./29) :
Non non je parle bien de la priorité des opérateurs, ça peut être utile d'avoir une priorité plus faible que + (genre pour un "=" ou un "or"), et aussi intermédiaire entre priorités prédéfinies ^^

Là tu me demande de pouvoir rajouter de nouveaux opérateurs. C'est dans le TODO, mais c'est pas encore supporté smile
Accordé.
Pollux (./29) :
Je crois que c'est important de faire le parallèle entre put_string() et la fonction qui put() un objet arbitraire ^^

Ok
Pollux (./29) :
L'enrobage c'est très bien, mais à moins que tu veuilles interdire de définir des extensions aux auteurs de programmes de moyen niveau (= l'équivalent des programmes C sous AMS, qui sont quand même assez étroitement couplés au CAS) ça ne te dispensera pas de la compatibilité binaire.

Oui je compte pas tout casser. Donc il y en aura. Mais ca ne sera pas la priorité absolue.
Pollux (./30) :
- Ah oui, mais selon la doc bar ne devient pas entièrement invalide dans le premier cas puisqu'on peut encore l'évaluer ?!?

Oui. C'est la seule chose possible restante.
Pollux (./30) :
- Ce serait possible de formaliser toutes les exigences des extensions pour qu'elles puissent maintenir ce genre d'invariants ? Là ça me paraît très très fragile, c'est à peu près certain que la première extension venue cassera tout si elle a une structure récursive...

Je ne pense pas que ca soit si fragile. En général, une forme _c ne vit pas très longtemps et tu l'évalues très rapidement (parce qu'autrement tu ne peux pas faire grand chose dessus).
De toute façon, si tu as les assertions activées, MAYLIB te lachera une robustesse très vite normalement dans ce cas.
Que verrais-tu dans la doc ?

32

Pollux (./26) :
l'alignement de toutes les structures est le même

C'est faux, du moins avec GCC. Par exemple, struct foo {char x;}; a une taille et un alignement de 1 dans TIGCC.
The fact of avoiding any name collision (between function and type) is let to the user.
Ca pose un problème d'évolutivité, qu'est-ce qui se passe si je définis une fonction digamma et qu'elle est implémentée dans une version future de maylib ?

Ton programme va boguer, exactement comme en TI-BASIC.
int non_commutative_product;
Ca me paraît pas très extensible comme façon de savoir si la classe vérifie un prédicat, ça veut dire que c'est impossible de linker ensemble deux modules qui ont été compilés avec des versions différentes de maylib (alors que si tu veux t'en servir comme CAS sur calculatrice la compatibilité binaire est super importante). Pourquoi pas utiliser à la place un champ avec des flags genre ASSERT_COMMUTATIVE_PRODUCT ? Comme ça tu pourras en rajouter d'autres quand t'en auras besoin...

On peut toujours rajouter des flags sans casser la compatibilité ascendante, il suffit de les rajouter à la fin de la structure. Et la compatibilité descendante, je ne connais pas un grand nombre de libs qui la gèrent. AMHA, c'est normal qu'il faille au moins la version de MAY de laquelle on a pris le header. Et puis vu que la lib est encore en développement, la compatibilité ascendante ne doit pas forcément être garantie non plus à l'heure actuelle, c'est à PpHd de voir.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

33

PpHd (./31) :
Pollux (./29) :
- Je viens de regarder may_subs_c, déjà il y a un gros problème c'est que le namespace des fonctions et des variables est le même : si je fais un subs sur l'expression digamma+1 ça va planter
Non. Il ne se passera rien. Car digamma est une expression et tu as fourni à subs une fonction de ce nom. Donc il ne fera pas le remplacement.

Alors j'ai pas dû comprendre comment on s'en sert, tu pourrais écrire un exemple d'utilisation ?
Pollux (./29) :
- Je pensais plutôt au cas où c'est non pas l'utilisateur final (= programme Basic) qui l'utilise, mais un programme écrit en C appelant MAY directement et définissant des fonctions comme digamma pour son usage interne. Peut-être que tu veux plutôt qu'on définisse une extension dans ce cas-là en fait ?

A mon avis, la meilleure facon d'implanter çà efficacement (une vrai fonction, avec une dérivée, et tout, et tout), est de faire une classe d'extension regroupant toutes tes fonctions.
L'enfant 1 est un entier indiquant le numéro de la fonction (0->digamma, 1 ->besselJ, ...)
L'enfant 2 est l'argument de la fonction.
Tu parses ton expression SANS l'évaluer. Puis tu fais un subs_c avec toutes ces nouvelles fonctions, pour les remplacer par les extensions.
Puis tu fais un éval de ton expression (avec tes extensions).
Avec cette méthode, même si un digamma interne apparait, ton digamma reste prioritaire smile

OK, mais du coup il faut faire ton propre affichage, et surtout il faut refaire un parseur from scratch non ?
Pollux (./29) :
Je crois que c'est important de faire le parallèle entre put_string() et la fonction qui put() un objet arbitraire ^^
Ok

Et tu devrais éviter de parler de buffer interne : après tout, si on affiche directement sur stdout, il n'y aura pas de buffer interne... Peut-être aussi que convert2str n'est pas un nom idéal, un truc genre display() ou stringify() serait plus générique et plus proche des autres noms de fonction ?
Pollux (./30) :
- Ah oui, mais selon la doc bar ne devient pas entièrement invalide dans le premier cas puisqu'on peut encore l'évaluer ?!?
Oui. C'est la seule chose possible restante.

Alors il faut aussi préciser que ça reste valide aussi si on avait construit une autre expression non évaluée qui dépend d'elle : même si on n'évalue pas bar il reste bien valide. Par contre si je comprends bien on n'a plus le droit d'appeler un constructeur non évalué avec cette expression en paramètre ?
(et c'est quoi le rationale de ce truc-là ?)
Pollux (./30) :
- Ce serait possible de formaliser toutes les exigences des extensions pour qu'elles puissent maintenir ce genre d'invariants ? Là ça me paraît très très fragile, c'est à peu près certain que la première extension venue cassera tout si elle a une structure récursive...

Je ne pense pas que ca soit si fragile. En général, une forme _c ne vit pas très longtemps et tu l'évalues très rapidement (parce qu'autrement tu ne peux pas faire grand chose dessus).
De toute façon, si tu as les assertions activées, MAYLIB te lachera une robustesse très vite normalement dans ce cas.
Que verrais-tu dans la doc ?

Ben je verrais une formalisation des garanties fournies par MAY et des exigences qu'elle pose sur les extensions, qui serait tout aussi complète que si tu voulais prouver avec un truc genre Coq la correction de tes transformations. Par exemple les axiomes de commutativité, de distributivité, d'élément neutre, absorbant, etc. Et tes assertions ne rattraperont pas le dixième des problèmes : par exemple j'écris une extension mais il y a un bug qui fait que si je multiplie par 0 je n'obtiens pas toujours 0 (*). Du coup 0 != eval(0*ext) = subs(e=ext, eval(0*e)) = subs(e=ext, 0) = 0. Et à moins que eval() soit purement bottom-up, le problème eval o foo_c o bar_c != foo o bar va aussi se poser...

(*) : ça peut au contraire être voulu, c'est par exemple ce que fait AMS avec les valeurs infinies : mais pour savoir à quoi s'attendre, c'est important de le définir dans un contrat


Est-ce que la commutativité pour la multiplication est adéquatement représentée par un flag statique ? Comment est-ce que tu décides si un arbre commute avec un autre ? Tu regardes si absolument toutes les feuilles des deux arbres commutent pour la multiplication ? Ca peut être trop prudent, par exemple si j'ai une fonction qui prend une matrice et qui me renvoie un nombre réel (genre le déterminant) le résultat sera commutatif même s'il utilise des matrices dans les feuilles.

Comment est-ce que tu évalues la commutativité multiplicative d'un identifiant ? S'il représente une matrice, ben ça commute pas...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

34

Kevin Kofler (./32) :
Pollux (./26) :
l'alignement de toutes les structures est le même

C'est faux, du moins avec GCC. Par exemple, struct foo {char x;}; a une taille et un alignement de 1 dans TIGCC.

C'est pas contraire à C99 ?
Norme C99 :
All pointers to structure types shall have the same representation and alignment requirements as each other.

Alors peut-être que j'interprète mal et que ça veut en fait dire "All pointers to a given structure type shall have...", mais ça m'étonnerait bcp ?!
The fact of avoiding any name collision (between function and type) is let to the user.
Ca pose un problème d'évolutivité, qu'est-ce qui se passe si je définis une fonction digamma et qu'elle est implémentée dans une version future de maylib ?
Ton programme va boguer, exactement comme en TI-BASIC.

Oui mais le TI-BASIC n'est pas fait pour être robuste à ce genre de choses : si j'écris un programme en C par contre c'est possible de faire en sorte que ça ne bugge pas (et de fait, je crois pas qu'il y ait de collision possible sous AMS, à moins de s'amuser à parser des chaînes bien sûr).
On peut toujours rajouter des flags sans casser la compatibilité ascendante, il suffit de les rajouter à la fin de la structure. Et la compatibilité descendante, je ne connais pas un grand nombre de libs qui la gèrent. AMHA, c'est normal qu'il faille au moins la version de MAY de laquelle on a pris le header. Et puis vu que la lib est encore en développement, la compatibilité ascendante ne doit pas forcément être garantie non plus à l'heure actuelle, c'est à PpHd de voir.

Ben ça voudrait dire que MAY 0.9 (ou PedroM 3.1) est incompatible avec les programmes compilés pour MAY 0.8 (ou PedroM 3.0), c'est dommage et c'est pas du tout le cas sous AMS par exemple.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

35

Pollux (./34) :
Norme C99 :
All pointers to structure types shall have the same representation and alignment requirements as each other.
Alors peut-être que j'interprète mal et que ça veut en fait dire "All pointers to a given structure type shall have...", mais ça m'étonnerait bcp ?!

Je pense qu'ils parlent de l'alignement du pointeur lui-même, pas de l'adresse contenue dedans. Si tu veux en savoir plus, il faudra envoyer un Defect Report. wink
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

36

Ah oui OK, c'est tout bête grin Mais du coup est-ce qu'on a un moyen portable de connaître l'alignement maximum de toutes les structures ? (par exemple pour réimplémenter malloc)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

37

ben, celui du plus gros truc que tu peux mettre dedans?

(ça m'arrangerait que ce soit 4 trigni)

38

Pollux (./33) :
Alors j'ai pas dû comprendre comment on s'en sert, tu pourrais écrire un exemple d'utilisation ?

Si le pointeur que l'on donne pour remplacer l'expression est contenu dans la pile de MAY, c'est une expression => Donc on ne peut remplacer que des expressions avec.
Si le pointeur que l'on donne pour remplacer l'expression n'est pas contenu dans la pile de MAY, c'est une fonction => Donc on ne peut remplacer que des fonctions avec.
Pollux (./33) :
OK, mais du coup il faut faire ton propre affichage, et surtout il faut refaire un parseur from scratch non ?

Oui, mais comme on peut réutiliser le parseur précédent en grande partie, ce n'est pas si génant.
Pollux (./33) :
Et tu devrais éviter de parler de buffer interne : après tout, si on affiche directement sur stdout, il n'y aura pas de buffer interne... Peut-être aussi que convert2str n'est pas un nom idéal, un truc genre display() ou stringify() serait plus générique et plus proche des autres noms de fonction ?

Ok
Pollux (./33) :
Alors il faut aussi préciser que ça reste valide aussi si on avait construit une autre expression non évaluée qui dépend d'elle : même si on n'évalue pas bar il reste bien valide. Par contre si je comprends bien on n'a plus le droit d'appeler un constructeur non évalué avec cette expression en paramètre ? (et c'est quoi le rationale de ce truc-là ?)

C'est bien à cause de toutes ces complications que je sens que je vais simplifier la doc en disant que bar devient invalide.
Pollux (./33) :
Ben je verrais une formalisation des garanties fournies par MAY et des exigences qu'elle pose sur les extensions, qui serait tout aussi complète que si tu voulais prouver avec un truc genre Coq la correction de tes transformations. Par exemple les axiomes de commutativité, de distributivité, d'élément neutre, absorbant, etc. Et tes assertions ne rattraperont pas le dixième des problèmes : par exemple j'écris une extension mais il y a un bug qui fait que si je multiplie par 0 je n'obtiens pas toujours 0 (*). Du coup 0 != eval(0*ext) = subs(e=ext, eval(0*e)) = subs(e=ext, 0) = 0. Et à moins que eval() soit purement bottom-up, le problème eval o foo_c o bar_c != foo o bar va aussi se poser...

Oui les assertions ne sont pas une solution. Oui un vrai contrat serait mieux. Mais tant que je n'aurais pas des utilisateurs pour un retour pratique, je ne serais pas quel sera le meilleur compromis complexité / efficiacité / evolutivité.

Pour 0 != eval(0*ext) = subs(e=ext, eval(0*e)) = subs(e=ext, 0) = 0, je cite tout d'abord la doc:
algebraically correct, possibly except for a set of measure zero: y / y is simplified into 1.

ensuite si si e est un identifiant, il ne peut être qu'au maximum dans le domaine des complexes, donc 0*e se simplifiant en 0 est tout à fait correct. C'est le subs qui est incorrect.

Sinon rien n'empêche de faire une extesion des qui gère les identifiants non complexes, mais dans ce cas, c'est à elle de gérer 0*x qui devient [ 0].
Pollux (./33) :
Est-ce que la commutativité pour la multiplication est adéquatement représentée par un flag statique ? Comment est-ce que tu décides si un arbre commute avec un autre ? Tu regardes si absolument toutes les feuilles des deux arbres commutent pour la multiplication ? Ca peut être trop prudent, par exemple si j'ai une fonction qui prend une matrice et qui me renvoie un nombre réel (genre le déterminant) le résultat sera commutatif même s'il utilise des matrices dans les feuilles.

Qu'appelles-tu arbre / feuille ?
Par défaut, la commutativité entre classes différentes est obbligatoire (deux classes différentes sont supposées être tout le temps commutative).
C'est un choix pour simplifier l'algorithme utilisé, pour qu'il reste efficace, et qui je pense, ne limite pas vraiment en pratique.
Pollux (./33) :
Comment est-ce que tu évalues la commutativité multiplicative d'un identifiant ? S'il représente une matrice, ben ça commute pas...

Un identifiant est au dans le domaine des complexe (Voir may_kernel_domain). Si après tu t'amuses à le remplacer par une matrice, tu changes les règles. tongue
squalyl (./37) :

(ça m'arrangerait que ce soit 4 trigni.gif )

Sur 32 bits ca peut être 8 (long long / sse)
Sur 64 bits, ca peut être encore plus smile

39

PpHd (./38) :
Si le pointeur que l'on donne pour remplacer l'expression est contenu dans la pile de MAY, c'est une expression => Donc on ne peut remplacer que des expressions avec.Si le pointeur que l'on donne pour remplacer l'expression n'est pas contenu dans la pile de MAY, c'est une fonction => Donc on ne peut remplacer que des fonctions avec.

WTF?! Tu traîtes les pointeurs différement selon leur adresse?! C'est quoi cette API?
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

40

PpHd (./38) :
Pollux (./33) :
Alors j'ai pas dû comprendre comment on s'en sert, tu pourrais écrire un exemple d'utilisation ?

Si le pointeur que l'on donne pour remplacer l'expression est contenu dans la pile de MAY, c'est une expression => Donc on ne peut remplacer que des expressions avec. Si le pointeur que l'on donne pour remplacer l'expression n'est pas contenu dans la pile de MAY, c'est une fonction => Donc on ne peut remplacer que des fonctions avec.

OK, enfin c'est un tout petit peu crade quand même grin Faut pas avoir envie d'allouer une zone de Data avec MAY pour mettre le code d'une fonction dedans cheeky
Et aussi c'est super crade de pas pouvoir faire la différence entre f(1,2) et f({1,2}) sad
Pollux (./33) :
OK, mais du coup il faut faire ton propre affichage, et surtout il faut refaire un parseur from scratch non ?
Oui, mais comme on peut réutiliser le parseur précédent en grande partie, ce n'est pas si génant.

Comment ça ? Tu peux le réutiliser pour parser un flottant, oui, mais la structure arborescente tu es obligé de la recréer entièrement toi-même par exemple. Ou y a une API pour ça ?
Pollux (./33) :
Alors il faut aussi préciser que ça reste valide aussi si on avait construit une autre expression non évaluée qui dépend d'elle : même si on n'évalue pas bar il reste bien valide. Par contre si je comprends bien on n'a plus le droit d'appeler un constructeur non évalué avec cette expression en paramètre ? (et c'est quoi le rationale de ce truc-là ?)
C'est bien à cause de toutes ces complications que je sens que je vais simplifier la doc en disant que bar devient invalide.

Si bar devient complètement invalide ça veut dire qu'on peut juste créer une chaîne (linéaire) de constructeurs plutôt qu'un arbre quelconque, c'est peut être gênant au niveau performance ?
Sinon actuellement en quoi appeler plusieurs constructeurs avant d'évaluer est plus rapide que de faire l'évaluation au fur et à mesure ? Ca évite juste de faire plusieurs parcours de l'arbre (gain d'un facteur O(nb_de_constructeurs)) ou ça permet aussi de faire des optimisations top-down ? (gain d'un facteur arbitrairement grand)
Pour 0 != eval(0*ext) = subs(e=ext, eval(0*e)) = subs(e=ext, 0) = 0, je cite tout d'abord la doc:
algebraically correct, possibly except for a set of measure zero: y / y is simplified into 1.
ensuite si si e est un identifiant, il ne peut être qu'au maximum dans le domaine des complexes, donc 0*e se simplifiant en 0 est tout à fait correct. C'est le subs qui est incorrect.

Ok ; à propos de ce que tu cites, comment est-ce que tu gères e / e où e est très compliquée et pourrait en particulier être nulle sur une surface de mesure non nulle ?
Est-ce que ce serait pas une bonne idée de pouvoir rajouter un flag au domaine qui empêcherait ce genre d'optimisation, pour éviter les problèmes de solutions ratées comme sur TI ?
Sinon rien n'empêche de faire une extesion des qui gère les identifiants non complexes, mais dans ce cas, c'est à elle de gérer 0*x qui devient [ 0].

Comment est-ce que ton extension fait pour intercepter ça ?
Pollux (./33) :
Est-ce que la commutativité pour la multiplication est adéquatement représentée par un flag statique ? Comment est-ce que tu décides si un arbre commute avec un autre ? Tu regardes si absolument toutes les feuilles des deux arbres commutent pour la multiplication ? Ca peut être trop prudent, par exemple si j'ai une fonction qui prend une matrice et qui me renvoie un nombre réel (genre le déterminant) le résultat sera commutatif même s'il utilise des matrices dans les feuilles.

Qu'appelles-tu arbre / feuille ?
Par défaut, la commutativité entre classes différentes est obbligatoire (deux classes différentes sont supposées être tout le temps commutative). C'est un choix pour simplifier l'algorithme utilisé, pour qu'il reste efficace, et qui je pense, ne limite pas vraiment en pratique.

Si je veux regarder si (1+[matrice1])*(1+det([matrice2])) commute, les deux arbres sont les arbres des deux expressions (avec pour feuilles les entiers/matrices).
Comment la commutativité est décidée dans mon exemple ?
squalyl (./37) :

(ça m'arrangerait que ce soit 4 trigni.gif )

Sur 32 bits ca peut être 8 (long long / sse)
Sur 64 bits, ca peut être encore plus smile

En pratique je crois que même en 32 bits on a besoin d'alignements sur 16 octets pour que les SSE soient efficaces (inversement si on parle d'alignement pour la correction plutôt que pour la performance, c'est possible que 1 octet suffise sur x86 non ?)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

41

Kevin Kofler (./39) :
WTF?! Tu traîtes les pointeurs différement selon leur adresse?! C'est quoi cette API?

Si p est un pointeur sur char, la norme m'autorise à savoir si p pointe dans char Tab[ 10];
C'est tout ce que je fais (même s'il y a un cast de void (*)(void) vers void* non autorisé mais je fais avec sauf si on me trouve une marchine sur laquelle il y a un compilateur C99 et où ca ne marche pas).
Pollux (./40) :
OK, enfin c'est un tout petit peu crade quand même biggrin.gif Faut pas avoir envie d'allouer une zone de Data avec MAY pour mettre le code d'une fonction dedans mod.gif

Je crois que sous linux, MAY alloue une zone non executable tongue
Pollux (./40) :
Et aussi c'est super crade de pas pouvoir faire la différence entre f(1,2) et f({1,2}) frown.gif

Bug du parseur.
Pollux (./40) :
Comment ça ? Tu peux le réutiliser pour parser un flottant, oui, mais la structure arborescente tu es obligé de la recréer entièrement toi-même par exemple. Ou y a une API pour ça ?

Dans ce que j'ai cité, tu parses (sans évaluer) en utilisant may_parse_c, tu fais un may_subs_c pour faire les changements en extension, puis tu évalues.
Pollux (./40) :
Si bar devient complètement invalide ça veut dire qu'on peut juste créer une chaîne (linéaire) de constructeurs plutôt qu'un arbre quelconque, c'est peut être gênant au niveau performance ?

D'après mon expérience, pas tellement.
Pollux (./40) :
Sinon actuellement en quoi appeler plusieurs constructeurs avant d'évaluer est plus rapide que de faire l'évaluation au fur et à mesure ? Ca évite juste de faire plusieurs parcours de l'arbre (gain d'un facteur O(nb_de_constructeurs)) ou ça permet aussi de faire des optimisations top-down ? (gain d'un facteur arbitrairement grand)

Réponse 1: parcours de l'abre, et des GC en moins.
Pollux (./40) :
Ok ; à propos de ce que tu cites, comment est-ce que tu gères e / e où e est très compliquée et pourrait en particulier être nulle sur une surface de mesure non nulle ?

Exemple ?
Pollux (./40) :
Est-ce que ce serait pas une bonne idée de pouvoir rajouter un flag au domaine qui empêcherait ce genre d'optimisation, pour éviter les problèmes de solutions ratées comme sur TI ?

Sinon e / e est parsé en e * e^ -1. Et l'extension peut décider de ne pas retourner e ^ -1 lors d'évaluation si elle sait que e * e ^ -1 peut poser des problèmes.
Si e est complexe, alors e/e est toujours simplifiée en 1.
Pollux (./40) :
Comment est-ce que ton extension fait pour intercepter ça ?

Pour l'expression 0*24*2^(sqrt(2))*E où E est l'extension. sa fonction de multiplication recoit 0*E et c'est à elle de décider ce qu'elle en veut.
Pollux (./40) :
Si je veux regarder si (1+[matrice1])*(1+det([matrice2])) commute, les deux arbres sont les arbres des deux expressions (avec pour feuilles les entiers/matrices).

Si une extension renvoie 1+E, toutes les simplifications faites sur les complexes s'appliqueront (donc la commutativité s'appliquera). Il faut qu'elle encapsule çà dans un EX(1+E) pour qu'elle gère elle-même sa sauce (et la commutativité s'appliquera quand même car 1+det est complexe).
Pollux (./40) :
En pratique je crois que même en 32 bits on a besoin d'alignements sur 16 octets pour que les SSE soient efficaces (inversement si on parle d'alignement pour la correction plutôt que pour la performance, c'est possible que 1 octet suffise sur x86 non ?)

Surement.

42

PpHd (./41) :
Pollux (./40) :
OK, enfin c'est un tout petit peu crade quand même biggrin.gif Faut pas avoir envie d'allouer une zone de Data avec MAY pour mettre le code d'une fonction dedans mod.gif

Je crois que sous linux, MAY alloue une zone non executable tongue

Mais sur TI non happy
Pollux (./40) :
Et aussi c'est super crade de pas pouvoir faire la différence entre f(1,2) et f({1,2}) frown.gif
Bug du parseur.

? Bug de la spec de may_subs_c surtout...
Pollux (./40) :
Comment ça ? Tu peux le réutiliser pour parser un flottant, oui, mais la structure arborescente tu es obligé de la recréer entièrement toi-même par exemple. Ou y a une API pour ça ?
Dans ce que j'ai cité, tu parses (sans évaluer) en utilisant may_parse_c, tu fais un may_subs_c pour faire les changements en extension, puis tu évalues.

Ok mais ça c'est pour les changements simples (assez simples pour qu'il y ait une regexp transformant par exemple les crochets de mes matrices custom en parenthèses d'appel de fonction), dès que ça devient un tout petit peu plus compliqué il faut tout réimplémenter. Enfin c'est pas très grave hein ^^
Pollux (./40) :
Sinon actuellement en quoi appeler plusieurs constructeurs avant d'évaluer est plus rapide que de faire l'évaluation au fur et à mesure ? Ca évite juste de faire plusieurs parcours de l'arbre (gain d'un facteur O(nb_de_constructeurs)) ou ça permet aussi de faire des optimisations top-down ? (gain d'un facteur arbitrairement grand)
Réponse 1: parcours de l'abre, et des GC en moins.

Ben l'arbre t'es pas obligé de le reparcourir si tu mets des flags pour dire que t'es déjà passé ; le GC en moins ok, mais c'est peut-être que c'est juste pas le bon modèle mémoire ? (i.e. peut-être que ça pourrait être intéressant de laisser volontairement des saletés sur la pile pour éviter de faire des memmove() 50 fois)
Pollux (./40) :
Ok ; à propos de ce que tu cites, comment est-ce que tu gères e / e où e est très compliquée et pourrait en particulier être nulle sur une surface de mesure non nulle ?
Exemple ?

(real(x)+abs(real(x)))/(real(x)+abs(real(x))) ?
Pollux (./40) :
Est-ce que ce serait pas une bonne idée de pouvoir rajouter un flag au domaine qui empêcherait ce genre d'optimisation, pour éviter les problèmes de solutions ratées comme sur TI ?

Sinon e / e est parsé en e * e^ -1. Et l'extension peut décider de ne pas retourner e ^ -1 lors d'évaluation si elle sait que e * e ^ -1 peut poser des problèmes. Si e est complexe, alors e/e est toujours simplifiée en 1.

Oui justement, je parle pas des extensions mais des nombres complexes : AMS peut rater des solutions à cause d'optimisations style e/e = 1. En fait c'est sûrement possible de faire ça avec des extensions, e/e serait représenté par l'extension when(e=0,UNDEF,1) -- il suffit d'avoir un flag pour dire à May de toujours le représenter par ça plutôt que par 1 smile
Pollux (./40) :
Si je veux regarder si (1+[matrice1])*(1+det([matrice2])) commute, les deux arbres sont les arbres des deux expressions (avec pour feuilles les entiers/matrices).
Si une extension renvoie 1+E, toutes les simplifications faites sur les complexes s'appliqueront (donc la commutativité s'appliquera). Il faut qu'elle encapsule çà dans un EX(1+E) pour qu'elle gère elle-même sa sauce (et la commutativité s'appliquera quand même car 1+det est complexe).

Ah, ok... Donc en fait le type d'une expression évaluée est entièrement déterminé par le premier noeud, et c'est exactement comme si les types étaient explicites. Si je veux faire des calculs sur des matrices je dois donc définir une extension matrix qui évaluerait ça en un truc comme :
matrix(1+matrix([matrice1]))*(1+det(matrix([matrice2])))


(hmm tout ça ça me fait un peu penser à "Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp." hehe)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

43

Pollux (./42) :
PpHd (./41) :
Pollux (./40) :
OK, enfin c'est un tout petit peu crade quand même biggrin.gif Faut pas avoir envie d'allouer une zone de Data avec MAY pour mettre le code d'une fonction dedans mod.gif

Je crois que sous linux, MAY alloue une zone non executable tongue

Mais sur TI non happy

Ça peut se corriger, hein. 0x700000-0x700007... wink
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

44

Pollux (./42) :
? Bug de la spec de may_subs_c surtout...

A oué. Bon à reprendre.
Pollux (./42) :
Ben l'arbre t'es pas obligé de le reparcourir si tu mets des flags pour dire que t'es déjà passé ; le GC en moins ok, mais c'est peut-être que c'est juste pas le bon modèle mémoire ? (i.e. peut-être que ça pourrait être intéressant de laisser volontairement des saletés sur la pile pour éviter de faire des memmove() 50 fois)

C'est déjà fait.
Et le GC en situation réelle consomme 5-10% du CPU.
Pollux (./42) :
(real(x)+abs(real(x)))/(real(x)+abs(real(x))) ?

A oué.
Bon tous les CAS que je connaissent font cette simplification, mais il va falloir que je réexamine çà.
Pollux (./42) :
Oui justement, je parle pas des extensions mais des nombres complexes : AMS peut rater des solutions à cause d'optimisations style e/e = 1. En fait c'est sûrement possible de faire ça avec des extensions, e/e serait représenté par l'extension when(e=0,UNDEF,1) -- il suffit d'avoir un flag pour dire à May de toujours le représenter par ça plutôt que par 1

Oui, cependant dans ce cas, je risque de partir dans une combinatoire exponentielle des décisions avec des WHEN partout.
Ce qui n'est pas forcément plus utile.
Pollux (./42) :
Ah, ok... Donc en fait le type d'une expression évaluée est entièrement déterminé par le premier noeud, et c'est exactement comme si les types étaient explicites. Si je veux faire des calculs sur des matrices je dois donc définir une extension matrix qui évaluerait ça en un truc comme : matrix(1+matrix([matrice1]))*(1+det(matrix([matrice2])))

Oui

45

PpHd (./44) :
C'est déjà fait. Et le GC en situation réelle consomme 5-10% du CPU.

Donc appeler n fois foo_c() en chaîne puis faire un eval() ne gagne que 5-10% (mettons 10-15% pour se laisser un peu de marge) par rapport à n foo() ? confus
Pollux (./42) :
Oui justement, je parle pas des extensions mais des nombres complexes : AMS peut rater des solutions à cause d'optimisations style e/e = 1. En fait c'est sûrement possible de faire ça avec des extensions, e/e serait représenté par l'extension when(e=0,UNDEF,1) -- il suffit d'avoir un flag pour dire à May de toujours le représenter par ça plutôt que par 1

Oui, cependant dans ce cas, je risque de partir dans une combinatoire exponentielle des décisions avec des WHEN partout. Ce qui n'est pas forcément plus utile.

- Il n'y a pas d'explosion exponentielle, les UNDEF sont absorbants ; après évidemment décider la satisfiabilité d'une branche du when est NP-dure si t'as des formules compliquées, mais 1) t'es pas obligé de la décider dans tous les cas, tu peux te contenter de dire que deux conditions de la même forme sont équivalentes et 2) en pratique les conditions seront pas forcément grosses
- Tu ne rajoutes une condition que quand tu fais une division, ce qui ne doit pas être très fréquent ?

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

46

Pollux (./45) :
Donc appeler n fois foo_c() en chaîne puis faire un eval() ne gagne que 5-10% (mettons 10-15% pour se laisser un peu de marge) par rapport à n foo() ? confus.gif

Même pas, en "général".

Par contre si foo=add ou si foo=mul, alors eval(add_c (add_c (add_c (....))))) sera grosso modo en N*log (N), alors que add(add(add(add()))) sera (dans le pire cas!) en sum(i*log(i),i=1..N)
Et là ca peut faire mal dans les performances.
Pollux (./45) :
- Il n'y a pas d'explosion exponentielle, les UNDEF sont absorbants

Pas dans MAY.
NAN +x reste NAN + x
Pollux (./45) :
- Tu ne rajoutes une condition que quand tu fais une division, ce qui ne doit pas être très fréquent ?

Tout dépend de l'algorithme utilisé.

47

PpHd (./46) :
Pollux (./45) :
Donc appeler n fois foo_c() en chaîne puis faire un eval() ne gagne que 5-10% (mettons 10-15% pour se laisser un peu de marge) par rapport à n foo() ? confus.gif

Même pas, en "général".

Par contre si foo=add ou si foo=mul, alors eval(add_c (add_c (add_c (....))))) sera grosso modo en N*log (N), alors que add(add(add(add()))) sera (dans le pire cas!) en sum(i*log(i),i=1..N) Et là ca peut faire mal dans les performances.

Pourquoi il faudrait du n^2*log n ? T'as un exemple en tête ?
Pollux (./45) :
- Il n'y a pas d'explosion exponentielle, les UNDEF sont absorbants

Pas dans MAY. NAN +x reste NAN + x

Mais on peut aussi faire une extension qui serait absorbante, et là il n'y a pas d'explosion ^^
Pollux (./45) :
- Tu ne rajoutes une condition que quand tu fais une division, ce qui ne doit pas être très fréquent ?

Tout dépend de l'algorithme utilisé.

Oui, tu penses à quoi en particulier ?

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

48

49

Pollux (./47) :
Pourquoi il faudrait du n^2*log n ? T'as un exemple en tête ?

Ben j'optimise pas du tout l'insertion d'un nouvel élément dans une somme.
Pollux (./47) :
Mais on peut aussi faire une extension qui serait absorbante, et là il n'y a pas d'explosion ^^

Oui
Pollux (./47) :
Oui, tu penses à quoi en particulier ?

Rien de particulier. Je réfléchis.

50

PpHd (./49) :
Ben j'optimise pas du tout l'insertion d'un nouvel élément dans une somme.

A moins que ça soit trop compliqué ce serait pas rentable d'optimiser pour simplifier l'API ? (et accélérer par la même occasion les programmes qui n'ont pas été écrits de la façon la plus optimisée)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

51

Pollux (./50) :
PpHd (./49) :
Ben j'optimise pas du tout l'insertion d'un nouvel élément dans une somme.

A moins que ça soit trop compliqué ce serait pas rentable d'optimiser pour simplifier l'API ? (et accélérer par la même occasion les programmes qui n'ont pas été écrits de la façon la plus optimisée)

Ce n'est pas si simple. Je pourrais enlever le facteur log(n) mais pas le facteur n^2 (donc intérêt très limité) dans le pire cas.
Car dans add(add(add(add()))) à chaque étape il faut réallouer un nouvel espace de taille + 1 pour stocker la nouvelle chaine et recalculer son hash.
Par exemple, dans le cas où on ajoute un identifieur unique à chaque étape, on obtient N^2 de complexité.

add_c(add_c(add_c... est en N*ln(N) car chaque construction ne réalloue pas toute la chaine (pas besoin de calculer les hash intermédiares des sommes).

Mais c'est vraiment le seul cas pratique, où il y a une réelle différence de performance à utiliser add_c.

52

OK, je suis convaincu qu'on peut le descendre à n*log(n) (tu prends un hash commutatif, et tu utilises une structure de donnée moins "impérative" qu'un tableau), mais la constante sera probablement moins bonne qu'avec add_c donc il vaut peut être mieux le garder.
Est-ce que le fait de vérifier si l'argument a bien été évalué est si prohibitif que ça ? Parce que sinon il suffit de supprimer add et d'utiliser add_c à la place, et puis d'appeler eval de façon paresseuse quand on en aura besoin, du coup on peut se débarrasser de tous les _c.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

53

Pollux (./52) :
Est-ce que le fait de vérifier si l'argument a bien été évalué est si prohibitif que ça ? Parce que sinon il suffit de supprimer add et d'utiliser add_c à la place, et puis d'appeler eval de façon paresseuse quand on en aura besoin, du coup on peut se débarrasser de tous les _c.


Sauf que une forme non-évaluée ne peut pas franchir la barrière d'une marque déposée (Ex: x =may_cos_c (may_set_ui (2)); may_mark (); x = may_cos (x); est invalide).
Sauf que ca peut nécessiter d'évaluer plusieurs fois la même expression dans 2 branches de codes différentes sauf si je taggue l'expression comme réévalué en tel endroit.

Un autre problème de eval est le intmod. Si intmod vaut 2,
may_eval (may_pow_c (may_set_ui_c (17), may_set_ui_c (5))));
ne sera pas pareil que:
may_pow (may_set_ui (17), may_set_ui (5));

car 5 sera évalué lui aussi dans Z/2Z avant l'appel à may_pow.
(Donc oui, tu avais raison).

54

PpHd (./53) :
Pollux (./52) :
Est-ce que le fait de vérifier si l'argument a bien été évalué est si prohibitif que ça ? Parce que sinon il suffit de supprimer add et d'utiliser add_c à la place, et puis d'appeler eval de façon paresseuse quand on en aura besoin, du coup on peut se débarrasser de tous les _c.

Sauf que une forme non-évaluée ne peut pas franchir la barrière d'une marque déposée (Ex: x =may_cos_c (may_set_ui (2)); may_mark (); x = may_cos (x); est invalide).

Il y a une bonne raison pour ça ? Je vois pas en quoi add_c(x,y) serait fondamentalement différent de la liste {x,y} du point de vue du GC...
Sauf que ca peut nécessiter d'évaluer plusieurs fois la même expression dans 2 branches de codes différentes sauf si je taggue l'expression comme réévalué en tel endroit.

?
Un autre problème de eval est le intmod. Si intmod vaut 2,
may_eval (may_pow_c (may_set_ui_c (17), may_set_ui_c (5))));
ne sera pas pareil que:
may_pow (may_set_ui (17), may_set_ui (5));

car 5 sera évalué lui aussi dans Z/2Z avant l'appel à may_pow.
(Donc oui, tu avais raison).

Ah oui c'est super crade de faire ça... Ca veut dire que finalement tu casses la notion de types explicites dont j'avais parlé. Pourquoi tu ferais pas plutôt une extension pour gérer les types modulo ? (en plus ça serait une bonne occasion de "eat your own dogfood" pour voir si ton système d'extension tient la route, ou si au contraire le fait de rajouter un noeud pour préciser le type est 50x plus lourd que d'avoir une vraie annotation de type sur chaque noeud ; personnellement je penche pour la 2è solution ^^)

may_pow(may_classmod(may_set_ui(17), may_set_ui(2)), may_set_ui(5))


(et euh ton exemple est mal choisi, 17^5 = 17^1 mod 2 hehe mod 3 ça marche par contre)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

55

Pollux (./54) :
Il y a une bonne raison pour ça ? Je vois pas en quoi add_c(x,y) serait fondamentalement différent de la liste {x,y} du point de vue du GC...

La raison est que les fils de x qui appartient à un espace N ne peuvent jamais appartenir à un espace N+1. Seulement <= N.
Pollux (./54) :
Ah oui c'est super crade de faire ça...

Tu n'as que ce mot à la bouche tongue
Pollux (./54) :
Ca veut dire que finalement tu casses la notion de types explicites dont j'avais parlé. Pourquoi tu ferais pas plutôt une extension pour gérer les types modulo ? (en plus ça serait une bonne occasion de "eat your own dogfood" pour voir si ton système d'extension tient la route, ou si au contraire le fait de rajouter un noeud pour préciser le type est 50x plus lourd que d'avoir une vraie annotation de type sur chaque noeud ; personnellement je penche pour la 2è solution ^^)

C'est prévu (Et j'en ai déjà fait des extensions - les lists par exemple).
En fait, je sais pas trop comment gérer la notion de RootOf, et je me demande si mod ne serait pas une solution convenable pour gérer les extensions algébriques.
En gros, on aura les transformations suivantes:
mod(x,2)+3*mod(y,2) -> mod(x+y,2)
mod(f12),2) -> mod(f(12),2)
mod(x^3+x,x^2+1,x) -> mod(-x+,x^2+1,x)
mod(mod(x^3+x,x^2+1,x),3) -> mod(mod(2*x+1,x^2+1,x),3)
Et faudra surcharger les appels à degree, expand, gcd, ...
Pollux (./54) :
(et euh ton exemple est mal choisi, 17^5 = 17^1 mod 2 hehe.gif mod 3 ça marche par contre)

Oups... gni

56

PpHd (./55) :
Pollux (./54) :
Il y a une bonne raison pour ça ? Je vois pas en quoi add_c(x,y) serait fondamentalement différent de la liste {x,y} du point de vue du GC...
La raison est que les fils de x qui appartient à un espace N ne peuvent jamais appartenir à un espace N+1. Seulement <= N.

Je vois pas... (t'as zappé mon "?" du post précédent aussi happy)
Pollux (./54) :
Ah oui c'est super crade de faire ça...

Tu n'as que ce mot à la bouche tongue

Bah j'y peux rien si c'est le meilleur descriptif de certaines caractéristiques des CAS cheeky Dans le genre crade, AMS est pas mal aussi ^^
Pollux (./54) :
Ca veut dire que finalement tu casses la notion de types explicites dont j'avais parlé. Pourquoi tu ferais pas plutôt une extension pour gérer les types modulo ? (en plus ça serait une bonne occasion de "eat your own dogfood" pour voir si ton système d'extension tient la route, ou si au contraire le fait de rajouter un noeud pour préciser le type est 50x plus lourd que d'avoir une vraie annotation de type sur chaque noeud ; personnellement je penche pour la 2è solution ^^)

C'est prévu (Et j'en ai déjà fait des extensions - les lists par exemple).
En fait, je sais pas trop comment gérer la notion de RootOf, et je me demande si mod ne serait pas une solution convenable pour gérer les extensions algébriques.
En gros, on aura les transformations suivantes:
mod(x,2)+3*mod(y,2) -> mod(x+y,2)
mod(f12),2) -> mod(f(12),2)
mod(x^3+x,x^2+1,x) -> mod(-x+,x^2+1,x)
mod(mod(x^3+x,x^2+1,x),3) -> mod(mod(2*x+1,x^2+1,x),3) Et faudra surcharger les appels à degree, expand, gcd, ...

Je crois que ça ne peut pas marcher vraiment proprement comme ça. Je vais distinguer deux types de mod(), le mod() d'AMS qui calcule dans Q/R/C puis au dernier moment réduit la valeur et ton mod() qui représente une classe d'équivalence et suppose que toutes les feuilles sont modulo p.
Le problème c'est que tu ne peux pas transformer amsmod(2*x,2) en 0 si tu ne supposes pas x entier ; inversement pphdmod((x+1)/2,2) provoque une division par 0. Je vois deux solutions :
- empêcher que le type top-down de pphdmod() descende à *toutes* les feuilles : on pourrait écrire pphdmod(integer((x+1)/2),2) pour protéger (x+1)/2 de l'évaluation mod 2
- annoter x dans amsmod() pour signifier qu'il sera bien entier
Moi je pencherais pour des annotations systématiques à chaque noeud ^^


Autre question : est-ce que tu autorises des trucs genre mod(x,2*pi) ? (ou mod(pi,2))

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

57

Pollux (./54) :
?

Si x est non évaluée et que tu le pases en argument à f puis à g.
Rien n'indique que si f à évaluer x, il n'a pas du le déplacer ailleurs car il ne rentrait pas dans l'espace mémoire initial.
D'où g doit à nouveau évaluer x lorsqu'il calcule.
Sauf si la place originelle de x est marqué comme un lien vers la nouvelle place.
Pollux (./56) :
Je vois pas... (


<------------------------------[1111111111111111111[2222222222222222[333333333------->

Mettons que [ indique les moments où j'ai appelé may_mark
Mettons que x appartienne à 2
Tous les fils de x ne peuvent être que dans 1 ou 2, et pas dans 3.
Parce que sinon, lorsque le GC voudra compacter x, il verra que x appartient à 2, et rendra la main directement en vidant la mémoire :

<------------------------------[1111111111111111111[2222222222222222[------->

Dans ce cas, on aurait des fils de x qui pointent vers une zone mémoire détruite, et qui n'ont pas été compactés.
Pollux (./56) :
- empêcher que le type top-down de pphdmod() descende à *toutes* les feuilles : on pourrait écrire pphdmod(integer((x+1)/2),2) pour protéger (x+1)/2 de l'évaluation mod 2

Perso, c'est la réponse que j'attend:
mod((x+1)/2,2) ->NAN+NAN*x
Pollux (./56) :
et suppose que toutes les feuilles sont modulo p.

Ca ne se propage qu'on sein de K[X,..]
mod(x^2,2) reste mod(x^2,2) et mod(f(2),2) reste mod(f(2),2) évidemment.
Donc je ne vois pas trop ton problème.
Pollux (./56) :
Autre question : est-ce que tu autorises des trucs genre mod(x,2*pi) ? (ou mod(pi,2))

Oui, mais je ne suis pas sûr que ca fasse ce que tu veux gni

58

PpHd (./57) :
Si x est non évaluée et que tu le pases en argument à f puis à g.
Rien n'indique que si f à évaluer x, il n'a pas du le déplacer ailleurs car il ne rentrait pas dans l'espace mémoire initial.
D'où g doit à nouveau évaluer x lorsqu'il calcule.
Sauf si la place originelle de x est marqué comme un lien vers la nouvelle place.
Pollux (./56) :
Je vois pas... (


<------------------------------[1111111111111111111[2222222222222222[333333333------->

Mettons que [ indique les moments où j'ai appelé may_mark
Mettons que x appartienne à 2
Tous les fils de x ne peuvent être que dans 1 ou 2, et pas dans 3.
Parce que sinon, lorsque le GC voudra compacter x, il verra que x appartient à 2, et rendra la main directement en vidant la mémoire :

<------------------------------[1111111111111111111[2222222222222222[------->
Dans ce cas, on aurait des fils de x qui pointent vers une zone mémoire détruite, et qui n'ont pas été compactés.

Oui ok. La fonction d'eval() est de fournir un endroit où stocker le résultat.
Pollux (./56) :
- empêcher que le type top-down de pphdmod() descende à *toutes* les feuilles : on pourrait écrire pphdmod(integer((x+1)/2),2) pour protéger (x+1)/2 de l'évaluation mod 2

Perso, c'est la réponse que j'attend:mod((x+1)/2,2) ->NAN+NAN*x

Ben pour prendre l'exemple d'une interface haut-niveau vers may tu ne peux pas nier qu'on peut avoir envie de stocker l'entier (x+1)/2 dans une variable, puis après d'utiliser cette variable dans un calcul modulo p... Ca veut dire que si x avait une valeure concrète on aurait eu la vraie réponse, mais que s'il reste symbolique pouf ça dégénère en NAN, c'est pas le comportement qu'on veut (une TI qui est incapable d'intégrer une fonction la laisse intacte, elle ne remplace pas par NAN). C'est très courant en arithmétique de devoir faire ce genre de divisions, par exemple l'exposant du symbole de Legendre est (p-1)/2 ; tu peux me répondre que les exposants tu les calcules dans N, mais je te réponds que l'utilisateur peut vouloir les calculer dans phi(p) = p-1, et 2 n'est pas inversible modulo p-1 donc ça te ferait aussi un NAN*p + NAN.
En gros ta méthode consiste à peu de choses près à avoir un gros switch global "tout faire mod p" ou "ne rien faire mod p", mais c'est pas assez fin pour représenter tout ce qu'on veut faire, même si tu traites les exposants comme un cas spécial.
Pollux (./56) :
et suppose que toutes les feuilles sont modulo p.

Ca ne se propage qu'on sein de K[X,..]
mod(x^2,2) reste mod(x^2,2) et mod(f(2),2) reste mod(f(2),2) évidemment.Donc je ne vois pas trop ton problème.

mod(4^(1/2),3) est transformé en mod(1^(1/2),3) = 1, je suppose ? Or évidemment si tu calcules la puissance avant de "simplifier" tu obtiens mod(2,3) = 2.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

59

Pollux (./58) :
Ben pour prendre l'exemple d'une interface haut-niveau vers may tu ne peux pas nier qu'on peut avoir envie de stocker l'entier (x+1)/2 dans une variable, puis après d'utiliser cette variable dans un calcul modulo p... Ca veut dire que si x avait une valeure concrète on aurait eu la vraie réponse, mais que s'il reste symbolique pouf ça dégénère en NAN, c'est pas le comportement qu'on veut (une TI qui est incapable d'intégrer une fonction la laisse intacte, elle ne remplace pas par NAN). C'est très courant en arithmétique de devoir faire ce genre de divisions, par exemple l'exposant du symbole de Legendre est (p-1)/2 ; tu peux me répondre que les exposants tu les calcules dans N, mais je te réponds que l'utilisateur peut vouloir les calculer dans phi(p) = p-1, et 2 n'est pas inversible modulo p-1 donc ça te ferait aussi un NAN*p + NAN.
En gros ta méthode consiste à peu de choses près à avoir un gros switch global "tout faire mod p" ou "ne rien faire mod p", mais c'est pas assez fin pour représenter tout ce qu'on veut faire, même si tu traites les exposants comme un cas spécial.

Oui.
Et ce que tu décris (et besoin) correspond plus à une fonction fonction 'rem' qui renvoie un reste qu'à une fonction modulo.
Ton interface de haut niveau aura je pense créé cette fonction rem la calculant.
Et je suis désolé, mais (x+1)/2 mod 2 doit donner NAN*x+NAN (qui est surement la réponse la plus compréhensible des CAS que je connaisse).
Et franchement, c'est à l'utilisateur de savoir ce qu'il fait. S'il calcule dans Z/pZ, faut pas s'étonner à avoir des NAN si on divise par p. S'il calcule dans les exposants, il ne calcule pas avec modulo. Avant de remplacer sa variable, il vérifie que c'est un entier. C'est évident. S'il veut quelque chose de plus souple, il écrit du code correct (et il a plein de moyens d'en faire). C'est pas comme si la future extension 'mod' ou si kernel_intmod étaient les seules façons de calculer un reste.
Je ne supporterai jamais le neu-neu proof. smile

une TI qui est incapable d'intégrer une fonction la laisse intacte, elle ne remplace pas par NAN)

Mais là, on sait parfaitement calculer. Au pire, l'utilisateur dans son programme détecte que le résultat est indéfini, et revient à l'expression initiale.
Pollux (./58) :
mod(4^(1/2),3) est transformé en mod(1^(1/2),3) = 1, je suppose ? Or évidemment si tu calcules la puissance avant de "simplifier" tu obtiens mod(2,3) = 2.

Sémantiquement non, car x^y avec y non entier est considéré comme une fonction classique (comme exp(y*ln(x)))

60

PpHd (./59) :
Pollux (./58) :
Ben pour prendre l'exemple d'une interface haut-niveau vers may tu ne peux pas nier qu'on peut avoir envie de stocker l'entier (x+1)/2 dans une variable, puis après d'utiliser cette variable dans un calcul modulo p... Ca veut dire que si x avait une valeure concrète on aurait eu la vraie réponse, mais que s'il reste symbolique pouf ça dégénère en NAN, c'est pas le comportement qu'on veut (une TI qui est incapable d'intégrer une fonction la laisse intacte, elle ne remplace pas par NAN). C'est très courant en arithmétique de devoir faire ce genre de divisions, par exemple l'exposant du symbole de Legendre est (p-1)/2 ; tu peux me répondre que les exposants tu les calcules dans N, mais je te réponds que l'utilisateur peut vouloir les calculer dans phi(p) = p-1, et 2 n'est pas inversible modulo p-1 donc ça te ferait aussi un NAN*p + NAN.
En gros ta méthode consiste à peu de choses près à avoir un gros switch global "tout faire mod p" ou "ne rien faire mod p", mais c'est pas assez fin pour représenter tout ce qu'on veut faire, même si tu traites les exposants comme un cas spécial.

Oui.
Et ce que tu décris (et besoin) correspond plus à une fonction fonction 'rem' qui renvoie un reste qu'à une fonction modulo.
Ton interface de haut niveau aura je pense créé cette fonction rem la calculant.
Et je suis désolé, mais (x+1)/2 mod 2 doit donner NAN*x+NAN (qui est surement la réponse la plus compréhensible des CAS que je connaisse).
Et franchement, c'est à l'utilisateur de savoir ce qu'il fait. S'il calcule dans Z/pZ, faut pas s'étonner à avoir des NAN si on divise par p. S'il calcule dans les exposants, il ne calcule pas avec modulo. Avant de remplacer sa variable, il vérifie que c'est un entier. C'est évident. S'il veut quelque chose de plus souple, il écrit du code correct (et il a plein de moyens d'en faire). C'est pas comme si la future extension 'mod' ou si kernel_intmod étaient les seules façons de calculer un reste.
Je ne supporterai jamais le neu-neu proof. smile

C'est même pas une question de neuneu proof, c'est juste que ton truc est un gros switch global donc on ne peut pas faire tout ce qu'on veut. Pourquoi pas, hein, mais c'est quand même une limitation.
Pollux (./58) :
mod(4^(1/2),3) est transformé en mod(1^(1/2),3) = 1, je suppose ? Or évidemment si tu calcules la puissance avant de "simplifier" tu obtiens mod(2,3) = 2.

Sémantiquement non, car x^y avec y non entier est considéré comme une fonction classique (comme exp(y*ln(x)))

Donc 4^n n'est jamais simplifié en 1 ? :/

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)