#set par(justify: true) = Version 1. La phrase "it is less computationally intensive... the compiler". est mal dite; tu peux dire que c'est la methode classique, par exemple, implementee pour simulink et aussi Zelus. Rmq: - Les methodes numeriques (centralisees) les premieres ont ete faites pour resoudre un probleme initial. dx/dt = f (x(t)) t et x(0) = x0 ou x est un vecteur. - La "simulation distribuee" (cad faisant intervenir plusieurs solveurs) existe aussi mais pose d'autres problemes: efficacite, convergence. Elle est plus difficile a implementer. - Sundials CVODE a une methode centralisee mais avec une implementation de manipulation des vecteurs qui peut etre parallele, cad que tous les calculs de vecteur/matrice peuvent se faire en parallele. On ne l'utilise pas dans Zelus. p2. "we cannot necessarily use "pre"...": a mon avis, le lecteur ne peut pas comprendre ce que tu ecris ici. A mon avis, tu peux dire ce qui marche (si je ne me trompe pas, pouvoir internaliser le solveur au modele et donc le composer avec un observateur qui contient son propre solveur) et ce qui est a faire (si je comprends, pouvoir ecrire directement assert dans le code et la compilation pour pouvoir co-simuler le modele et ses differents observateurs/assertions. Pour le "pre", c'est un point que tu peux mentionner plus loin dans le rapport lorsque le lecteur a plus de contexte et de matiere sur ce que tu as fait. Il n'y a pas de numero en bas des pages dans ton texte. Il en faut. Impossible de savoir ou on est sinon. section 2. Tu parles de streams (Nat -> V) alors que tu donnes une semantique avec des etats. C'est bizarre. Tu ecris pre(s) alors que l'on ne sait pas ce que c'est. le ```ocaml let rec (o, s) = M.f_step(i, M.s0 -> pre(s)) ``` n'est pas du caml valide. Que veux-tu dire ? Quel est le type de Simulate(M) ? Je pensais (cf. page d'apres) que tu voudrais ecrire: ```ocaml simulate(M): list(I) -> list(O) ``` Le listing 1 ne correspond pas a la page precedente (ou l'inverse). Pourquoi ? Page d'apres (5 ?). Je ne suis pas fan de l'exemple sincos_discrete() tel que tu l'as ecrit car il diverge. Il laisse soupconner que l'on ne peut pas ecrire de schemas numeriques avec des streams. C'est faux, en general. En somme, le code listing 2 est un mauvais programme. Il y a une raison mathematique liee a l'analyse des poles; je te montrerai a mon retour. Si tu veux garder cet exemple de sin/cos, il faut mettre deux integrateurs differents, un forward et un backward. Ou alors, il faut faire un discours (plus long) pour expliquer pourquoi c'est mieux d'ecrire la forme a temps continu, que justement, elle permet de ne pas se casser la tete pour savoir ou et quand mettre un pre. Mais c'est un peu orthogonal a ce que tu veux raconter. Discrete models -> Discrete-time models. Continuous models -> Continuous-time models. Tu pourras ensuite dire que tu confonds les deux. 2.2 la raison de la divergence n'est pas la. Si tu prends un schema backward + forward, ca ne diverge pas. Par contre, si tu prends Van der Pol en discret, pas fixe, avec un pas trop petit ou trop petit, tu tombes sur nan. Regarde. J'avais fait l'exemple (regarde sur le depot; ou refais le). Rmq: sin/cos n'est pas un super exemple pour justifier l'interet de Zelus (ou du temps continu en general) car ce systeme est lineaire. Un schema numerique pas fixe (donc programmable directement en synchrone) marche bien. C'est plutot quand la dynamique est compliquee, non lineaire, qu'il te faut un schema numerique plus elabore et que l'expression directe d'un modele a temps continu se justifie. La modelisation d'evenement en etat (zero-crossing) le justifie aussi. Le cas classique, c'est le modele bang-bang. Tu veux detecter les instants ou la temperature passe un seuil. Avec un modele de temps pas fixe, tu ne peux pas. avant de donner CNode(...), dit ce qu'est le probleme. Qu'est ce qu'un modele M ? ```ocaml model (i) = o where der s = f_der i s der o = f_out i s ``` 2.3. Tu n'as pas dit/defini ce qu'etait un "initial value problem". Le faire (sinon, on ne comprends pas). "the integr node from Listing 2 is another example of a numerical solver (albeit not a very good one)" A mon avis, inutile. Que veux-tu dire que tu n'as pas deja dit (on peut calculer une approximation de `(der(x)/dt)(t)` a des instants `n * h` (`n in Nat`) par `(x - pre(x))/h`? "Of particular interest is the fact that numerical ODE solvers compute approximations sequentially. " Ca depend. Les solveurs a memoire (dits "multi-pas"). Les solveurs sans memoire tels que RK, non. A mon avis, tu peux commencer par exempliquer ce que calcule un solveur: etant donne le IVP, l'objectif est de calculer une solution [0, tmax] -> V. En pratique, il ne calcule pas toute la solution. Il calcule une suite de solution pour [0, h0][h0, h1][h1, h2], etc. Relis l'article de Chapoutot et al., de memoire, c'est tres bien explique. Sinon, il y a les livres jaunes dans l'etagere de mon bureau. "This sequential process gives way to a synchronous interpretation of an ODE solver as a discrete node." Qu'est-ce qu'un "discrete node" ? IVP(Y, Y'). Aurait du arriver bien plus tot. dy /dt (t) = f t (y(t)) y(0) = y0 donner l'horizon de temps (par defaut, +infty ?). Je prendrais une autre lettre que "s". (on note s pour "state" en general). "o", pour "output" ? La notation pointee est un peu troublante (en math, on la confond avec la multiplication. Utiliser une police ad-hoc pour h et u de sorte que s_0.u ne soit pas ambigu. mets des numeros de ligne dans ton texte stp. Il y a un style latex pour ca. Ou au moins des no. de page. "The ODE solver does not itself introduce discontinuities; the only discontinuities in the system are those introduced by the input signal." Avant de dire cela, tu ne parles par d'entrees. Pour le moment, ton systeme n'est pas "hybride". C'est une ODE. Tu ne donnes pas d'hypotheses sur f. En faut-il ? Lesquelles ? "The simulation of a continuous-time system with an ODE solver is now itself a synchronous node:" c'est un point de vue. Puisque la simulation d'un modele a temps continu calcule une suite de solutions approchees, ne pourrait-on pas la voir elle meme comme une machine synchrone qui... page suivante. Plutot que Signal(V), j'utiliserais un autre nom. Tu as deja un langage qui manipule des signaux, non ? Superdense(V) ? En reference aux travaux de Pnueli et al. Puis Edward Lee et al. Puis Caspi et al. Superdence(V) = R+ -> Nat -> V avec, a cote, une fonction qui pour chaque t in R+, donne le nombre de sauts (relire les articles; j'ai oublie le nom de cette fonction). step(t) in Nat. est-ce tres different de Nat -> R+ -> V avec a cote, une fonction qui indique le temps qui s'ecoule pour chaque n in Nat ? Dans un des articles de Edward Lee, il explique le type des signaux pour le temps continu. Regarde son livre (vert) sur mon etagere. Le texte de cette page (8 ?) est un peu confus. est-ce que les bouts de fonctions sont collees les uns aux autres ? none a le sens de "not yet" ? Comment recolles-tu les morceaux ? (h0, u0) (h1, u1) ... (hn, un) est-ce equivalent a : (h0, u0) none (h1, u1) none none (hn, un) ? A ce stade, tu n'as pas dit ce qu'etait $italic("CNode")(I, O, S_M, S'_M)$. A quoi ca ressemble ? Les elements du listing 4 doivent etre donnes dans le texte en maths. Le code caml doit etre mis aussi dans le listing 4. Je comprends bien mieux le code que les explications ! Sois plus precis dans le texte, ca aidera a comprendre. utiliser hmax plutot que h pour ivp. Eviter les surcharges de noms autant que possible. Plutot que "discrete node", utiliser "synchronous machine" ? Le terme "machine" est un terme technique des annees 60/70. Cf. articles historiques sur les automates et les "sequential machines". Tu peux dire, qui se caraterise par un etat initial, une fonction step lisant une entree et produisant une sortie, (plus une fonction reset) si tu veux. "Since time is logical in discrete nodes". Un peu trop pedant (et obscur) a mon avis. On manipule des suites de valeurs; il n'y a donc pas de temps reel ou physique. Le temps est juste la succession des valeurs. Le paragraphe "The question of discrete events..." est un peu confus. Donne un exemple. E.g., un timer: un controleur ouvre un robinet pendant 4s; une lumiere doit clignoter en alternant allume/eteint 1s/2s. ce sont des cas ou il y a des evenements en temps, cad en reference a la variable t (der t = 1 init 0). D'autres evenements ne sont pas des evenements en temps. E.g., une roue qui tourne (e.g. volant moteur). Compter le nombre de tours de roue par seconde avec un capteur. Le schema general est dit de "Zero-crossing". Etc. La balle qui rebondit, etc. Tu en trouveras d'autres ! La suite est pas mal. Il faut expliquer (et possiblement donner le code, au moins en annexe) pour 2.5, 2.6, 2.7. Ca prend forme. Tu peux donner l'intuition de la compilation. Dans le source, on melange les der, present, up, etc. et le compilo., apres une analyse statique (qui va verifier des proprietes et donc rejeter certains programmes), va produire les differentes fonctions necessaires a la simulation qui alterne des phases d'integration (le temps ronronne) et des pas discrets (reactions instantanees). Super. Continue ! --Marc #pagebreak() = Version 2. *L.230 - 235*. Le discours peut donner l'impression de confondre simuation et modèle mathématique. Tu écris un modèle mathématique idéalisé, c.à.d. avec un choc élastique où la vitesse change instantanément de direction. Pour cela, la manière de simuler doit changer. La, tu peux garder le discours. "_Since time is logical in discrete nodes_". Tu veux dire plutôt que l'on choisit de décrire des réactions en temps zéro (ou instantanées), c'est bien ça ? "_Since time is logical in discrete nodes, nothing tells us when, in continuous time, we should perform discrete steps._" Je ne comprends pas cette phrase ! *L. 242-245*. Si tu veux définir le zéro-crossing, ne faudrait-il pas plutôt le faire avec une définition d'analyse d'abord et décrire ensuite, si besoin l'algorithme (mais informellement) ? L'intuition, c'est qu'il y a un zéro-crossing de $z$ en $t_0$, entre $t_"left"$ et $t_"right"$ lorsque il existe une boule d'épaisseur non nulle autour de $t_0$ (d'épaisseur $epsilon$) telle que pour tous les points a gauche de t0 (notons $t_0^- = { t | t <= t_0 and |t_0 - t| <= epsilon }$), $z(t_0^-) <= 0$ et tous les points a droite, $z(t_0^+) > 0$. Tim t'as donné l'article qui décrit l'algo. Illinois. Je ne l'ai pas sur moi. Le signal $z: [t_"left", t_"right"]$ a un zéro-crossing en t0 lorsque il existe un $epsilon > 0$ tq pour tout $alpha < epsilon$: ... . Qu'en penses-tu ? *Listing 5*. Tu n'expliques pas `last y'`. *P.10*. Tu devrais d'abord expliquer le modele mathématique, ce dont tu as besoin, puis l'exemple; ou bien l'inverse, expliquer d'abord intuitivement l'exemple, les ingrédients dont tu as besoin et que tu introduits, plus le modèle mathématique. Et ensuite, les choses dont tu as besoin pour simuler. E.g., connaitre $f_"der"$, $f_"zero"$, l'état initial continu, l'état discret, etc. *L.302*. Je trouve l'écriture $h in [0, v.h]$ un peu troublante. Est-ce qu'une notation $v\#h$ ou autre ne serait pas mieux ? Ou alors, utiliser plutôt un champ "horizon" que h, dans la notation en point. Ou "right" ? "_Multiple methods exist (Zélus uses the Illinois method [Sny53])_". La méthode Illinois est la plus connue et utilisée. C'est mal formulé. Multiple methods exist; one of the oldest and most-used method is the Illinois method. It is used, for example, in the Sundials CVODE suite (donner la référence; regarde le manuel). Simulink also used this method by default. Zelus also implements this method. *L.305-309*. C'est un peu confus. Dis simplement ce que fait une méthode de zéro-crossing et des ingrédients dont elle a besoin, avant d'expliquer, plus tard, comment on s'en sert dans la simulation. Tu as besoin de $g: T i m e -> X -> Z_o$; de $x_0: X$; de $t_"left"$, de $t_"right"$ et de $d e n s e: T i m e -> X$, défini sur cet intervalle. La fonction de zéro-crossing indique qui, sur le vecteur $Z_o$, traverse zéro. Tu peux signaler les difficultés éventuelles (on peut rater un événement, c'est sensible a la largeur de l'intervalle de détection, au fait que le nombre de traversées peut être paire et on rate l'événement, etc.). Et dire que on ne fait rien là dessus (pas plus que Simulink, Modelica, et les autres d'ailleurs). *L. 322-324*. Je ne comprends pas la définition entre la ligne 322 et 324 et pas bien le paragraphe précédent. *L. 418*. Tu veux plutôt dire que tu voudrais pouvoir agréger les solutions denses successives ($d k y$). Les solveurs classiques sont impératifs, c'est-à-dire qu'ils ont un état interne et que chaque appel à "step" le modifie physiquement. Pour pouvoir agréger plusieurs solutions successives, il faut qu'il fournisse un moyen de le faire. (Rmq: ce n'est pas forcément une "copie d'état" dont on a besoin. Pour RK, je l'ai fait en fournissant un moyen d'avoir une copie de $d k y$. Ça suffit.) *L. 459*. Si tu parles d'assertions dans les programmes, cite/lis les articles classiques car c'est une construction très ancienne des langages de programmation. Je ne suis pas spécialiste mais j'en ai lu deux vieux (de mémoire, un de Hoare; un de Dijsktra). Je suis sûr qu'il doit y avoir un article de survey que tout le monde cite la dessus. Je regarderai en rentrant. En somme, dis aussi pourquoi c'est intéressant/utile de pouvoir écrire des assertions et les difficultés que cela pose dans le cas présent. "_An important property of assertions is that they are transparent: their presence does not affect the result of the computation._" An expected feature of run-time assertions is that they should not affect the rest of the computation (except stopping execution when they are not fulfilled). We call them "transparent", in the sense that, running the program with or without, if no error is raised, should produce the same result. *Figure 9*. Je ne comprends pas la figure 9. Tu veux dire que, en Lustre, cela correspond à avoir un seul noeud qui calcule les deux en parallèle ? On n'écrira jamais le code de la partie droite. Relis l'article sur les assertions de Lustre (de memoire, AMAST 93). En Lustre, les assertions ont un role qui consiste à contraindre l'environnement, avant tout. C'est utile quand on veut vérifier des propriétes. En fait, une assertion se decompose en deux parties, une hypothèse (qui parle des entrées, incontrolâbles), et une conclusion (assume/guarantee). Dans notre cas, comme on veut s'en servir d'abord comme on le fait dans un langage généraliste et, pour le moment, pas pour faire de la vérification, on ne distingue pas les deux. Le programme de gauche est equivalent à ``` let node f (x) = let v = ... in let assertion = (let p = integr(0.0, v) in p >= 0.0) in (v, assertion) ``` c.à.d. que assertion est un flot comme les autres. Est-ce autre chose que cela que tu veux dire ? *L. 477*. Pas vraiment. Un noeud Lustre avec une assertion a vérifier dynamiquement, s'implémente en calculant un flot supplementaire et en vérifiant qu'il est vrai à chaque instant. On le calcule donc avec le reste du code, comme on le fait habituellement pour les assertions dans les langages classiques. Attention: je ne parle pas ici de vérification formelle. On traite de manière particulière les assertions quand on cherche a vérifier une propriété. En Lustre, on considère que les assertions sont vraies et on vérifie qu'elles ne dépendent pas des sorties; sinon, elle ne sont pas causales. C'est pour cela, qu'il faut distinguer les hypothèses (assume) des résultats attendus (guarantee). Il n'y a aucun exemple ?