Scripting mit Rekursion

abakus shared this question 5 years ago
Answered

Hallo,

ich habe in den Zellen A1 und A2 folgendes stehen:


SetValue[A,A+(0.01,0)]

Execute[A1:A2]


Das starte ich über die Eingabezeile mit Execute[A1:A2].

Diese Befehlsfolge wird schlagartig 184 mal ausgeführt. (A wandert um 1,84 Einheiten nach rechts.)

Warum gerade 184 mal?

Wer Interesse hat, bitte verifizieren.

(Ich habe nicht die Absicht, für einen konkreten Zweck A zu animieren, das geht anders einfacher. Ich experimentiere einfach mit Scripten.)


Gruß Abakus

Comments (9)

photo
1

Hi Abakus,


similar here.

Just that I get a 934 times repetition and then the error message: Invalid Input SetValue[A,A+...


With

    L = {"SetValue[A,A+(1,0)]", "Execute[L]"}

and then in the Input Bar

    Execute[L]

I get the same result and error message.


Interesting.


Gerhard

photo
1

Sorry:


Hi Abakus,


bei mir ist es ähnlich.

Allerdings sind es bei mir 934 Wiederholungen gefolgt von der Fehlermeldung: Invalid Input SetValue[A,A+...


Mit

    L = {"SetValue[A,A+(1,0)]", "Execute[L]"}

und Eingabe von

    Execute[L]

erhalte ich das gleiche Resultat inkl. Fehlermeldung


Interessant.


Gerhard

photo
1

Hi Abakus,


langsamer, dafür ohne Fehlermeldung:8eee8b3c40d35235c720334128b9255dAber ob das so gewollt ist ....


Gerhard

photo
1

Hallo abakus


Grundlagenforschung an der Blackbox GGB könnte man das schon fast nennen.


Wer Interesse hat, bitte verifizieren.

Ich komme auf meinem System auf einen vergleichbaren Wert:177

Wenn ich das Applet neu starte ist der Wert höher (249), der sinkt dann mit jedem Execute[], bis er sich bei 177 einpendelt.


Warum gerade 184 mal?

Irgend wer (ich nehme an Java) muss sich den Rückweg merken um dort weiter zu fahren wo mit Execute[] die nächst tiefere Rekursions-Stufe aufgerufen wurde. Das ist in deinem Beispiel "nichts". Es bleibt dort jedoch die Aufgabe in die nächst höhere Rekursions-Stufe zurückzukehren usw bis zur höchsten Rekursionsstufe.

Diese Rücksprung-Merker benötigen Speicher und haben irgend wann das Maximum erreicht. Dann bricht Java (?) mit einer Fehlermeldung ab.Diese Fehlermeldung erscheint, wenn man den ersten Execute[] in einer Schaltfläche ausführt (also nicht wenn per Eingabezeile gestartet).

Java ist bemüht jene Speicher-bereiche zu erkennen, die nicht mehr benötigt werden und gibt sie wieder frei.

Das gelingt nicht zu 100%, deshalb (?) wird der anfängliche Wert (249) mit jedem erneuten Aufruf kleiner.


Um obige Behauptungen zu unterlegen öffne TestR01.ggb


https://ggbm.at/568733


Anstelle des Verschiebens eines Punktes wird vor dem rekursiven Execute[] der Zähler a um 1 erhöht und nach dem rekursiven Exekute[] der Zähler b.

Du wirst feststellen, dass nur a erhöht wird. b bleibt 0. Dies weil der Weg zurück von Java (?) nicht ausgeführt wurde.


Um diese Behauptung zu unterlegen öffne TestR02.ggb


https://ggbm.at/568735


Hier wird in Abhängigkeit von max die Rekursion abgebrochen. Stell den Schieberegler max auf 100.

Du wirst feststellen, dass nun (anfänglich) auch b erhöht wird. Java (?) hat den Weg zurück ausgeführt. Es erscheint auch keine Fehlermeldung.

Ohne das Programm neu zu laden: wiederhol das einige mal (Zähler auf 0, Ausführen)

Du wirst feststellen, dass nach ca 5 mal die Fehlermeldung wieder erscheint und b im Fehlerfall nicht erhöht wurde.

Ich schliesse daraus (kann es aber nicht unterlegen), dass nun Java (?) pro Rekursions-Stufe mehr Speicher benötigt.


Noch ein Wort zum Execute[] mit Abbruch-Bedingung für die Rekursion:


Angezeigt mit F3 in Eingabezeile:

A2= "Execute[If[a>=max,{},{" + (UnicodeToLetter[34]) + "Execute[A1:A3]" + (UnicodeToLetter[34]) + "}]]"


Angezeigt mit F4 in Eingabezeile

A2="Execute[If[a>=max,{},{"Execute[A1:A3]"}]]"


Der Befehl Execute ist selbst ein Element innerhalb einer Script-Liste (A1:A3) und steht innerhalb von "".

Darin hat es eine Kondition und in Abhängigkeit davon wird entweder die leere Liste oder eine Liste mit dem Rekursiven Execute[] ausgeführt. Dieses Element in dieser Skriptliste muss ebenfalls in "" gesetzt sein. Innerhalb von GGB-Script geht das nur über den Trick mit Unicode, da GGB keine Sprachelemente für verschachtelte Literal-Strings hat. Uebrigens: Ich vermute, dass dieses If-Konstrukt den zusätzlichen Speicher (gegenüber TestR01) benötigt.


Weiterhin viel Spass und lass uns an Deinen Entdeckungen teilhaben.


Raymond

photo
1

Hallo Gerhard


Einen tollen Computer scheinst Du zu haben.

Kannst du zu diesen Fragen Angaben machen. In Klammern die Werte meines Computers)

-Wieviel Memory steht zur Verfügung (3.5G)

-Welches Betriebssystem (windows 8.1)

-Welche CPU (Kerne, Cash-Memory) (2 Kerne, 512K L2-Cash, 3MB L3-Cash)

-Welches Java (Build 1.7.0_67-b01)

-Hast du irgendwo an den Parametern geschraubt, sodass bei Dir eine höhere Rekursions-Auflösung möglich ist (Betriebssystem, Java oder sonst was) (Ich: nein)


Raymond

photo
1

Hallo abakus


Grundlagenforschung an der Blackbox GGB könnte man das schon fast nennen.


Wer Interesse hat, bitte verifizieren.

Ich komme auf meinem System auf einen vergleichbaren Wert:177

Wenn ich das Applet neu starte ist der Wert höher (249), der sinkt dann mit jedem Execute[], bis er sich bei 177 einpendelt.


Warum gerade 184 mal?

Irgend wer (ich nehme an Java) muss sich den Rückweg merken um dort weiter zu fahren wo mit Execute[] die nächst tiefere Rekursions-Stufe aufgerufen wurde. Das ist in deinem Beispiel "nichts". Es bleibt dort jedoch die Aufgabe in die nächst höhere Rekursions-Stufe zurückzukehren usw bis zur höchsten Rekursionsstufe.

Diese Rücksprung-Merker benötigen Speicher und haben irgend wann das Maximum erreicht. Dann bricht Java (?) mit einer Fehlermeldung ab.Diese Fehlermeldung erscheint, wenn man den ersten Execute[] in einer Schaltfläche ausführt (also nicht wenn per Eingabezeile gestartet).

Java ist bemüht jene Speicher-bereiche zu erkennen, die nicht mehr benötigt werden und gibt sie wieder frei.

Das gelingt nicht zu 100%, deshalb (?) wird der anfängliche Wert (249) mit jedem erneuten Aufruf kleiner.


Um obige Behauptungen zu unterlegen öffne TestR01.ggb

[attachment=1]TestR01.ggb[/attachment]

Anstelle des Verschiebens eines Punktes wird vor dem rekursiven Execute[] der Zähler a um 1 erhöht und nach dem rekursiven Exekute[] der Zähler b.

Du wirst feststellen, dass nur a erhöht wird. b bleibt 0. Dies weil der Weg zurück von Java (?) nicht ausgeführt wurde.


Um diese Behauptung zu unterlegen öffne TestR02.ggb

[attachment=0]TestR02.ggb[/attachment]

Hier wird in Abhängigkeit von max die Rekursion abgebrochen. Stell den Schieberegler max auf 100.

Du wirst feststellen, dass nun (anfänglich) auch b erhöht wird. Java (?) hat den Weg zurück ausgeführt. Es erscheint auch keine Fehlermeldung.

Ohne das Programm neu zu laden: wiederhol das einige mal (Zähler auf 0, Ausführen)

Du wirst feststellen, dass nach ca 5 mal die Fehlermeldung wieder erscheint und b im Fehlerfall nicht erhöht wurde.

Ich schliesse daraus (kann es aber nicht unterlegen), dass nun Java (?) pro Rekursions-Stufe mehr Speicher benötigt.


Noch ein Wort zum Execute[] mit Abbruch-Bedingung für die Rekursion:


Angezeigt mit F3 in Eingabezeile:

A2= "Execute[If[a>=max,{},{" + (UnicodeToLetter[34]) + "Execute[A1:A3]" + (UnicodeToLetter[34]) + "}]]"


Angezeigt mit F4 in Eingabezeile

A2="Execute[If[a>=max,{},{"Execute[A1:A3]"}]]"


Der Befehl Execute ist selbst ein Element innerhalb einer Script-Liste (A1:A3) und steht innerhalb von "".

Darin hat es eine Kondition und in Abhängigkeit davon wird entweder die leere Liste oder eine Liste mit dem Rekursiven Execute[] ausgeführt. Dieses Element in dieser Skriptliste muss ebenfalls in "" gesetzt sein. Innerhalb von GGB-Script geht das nur über den Trick mit Unicode, da GGB keine Sprachelemente für verschachtelte Literal-Strings hat. Uebrigens: Ich vermute, dass dieses If-Konstrukt den zusätzlichen Speicher (gegenüber TestR01) benötigt.


Weiterhin viel Spass und lass uns an Deinen Entdeckungen teilhaben.


Raymond

Hallo Raymond,

ich hatte mir die Frage gestellt, ob man Geogebra als Programmierumgebung (ähnlich wie BASIC) verwenden kann.

Das sollte rein prinzipiell funktionieren, denn den Quelltext kann man statt in Programmzeilen in Tabellenspalten schreiben. Schleifen sind offensichtlich möglich mit Execute[If[...,Zellbereich]].

Variablen, denen man Werte zuweisen kann, müssen nicht wie in Pascal vordefiniert werden.

Pausen kann man mit dem einmaligen Ablauf einer Animation erzeugen.

Textfelder für Eingaben gibt es ja auch, die müssten sich bei Bedarf ein- und dann ausblenden lassen.

Das alles ist sicher nicht komfortabel, und die Systemressourcen könnten bei zu häufigen Wiederholungen zum Problem werden.

Gruß Abakus

photo
1

Hallo abakus,


Ich denke auch, dass das gehen müsste. Wäre auch spannend es an einem Beispiel beobachten zu können.


Allerdings muss man sich dann selbst um die (mehrstufigen) Abhängigkeiten zwischen den Objekten kümmern. Das kann recht komplex und performance-intensiv werden. Dies ist einer der Hauptgründe warum ich dafür plädiere Skripts so sparsam wie möglich einzusetzen.


Viele Freunde würde diese Programmierumgebung wohl kaum finden, da alles (und noch viel mehr) bereits in Java-Script abgedeckt ist. Allerdings ist dort der "Eintrittspreis" (Einarbeitungs-Aufwand) erheblich höher.

Sofern man sich aber auf die von Dir aufgeführten Sprachelemente beschänkt käme man mit einer der JS-Schleifen, dem If-Befehl und der ggbApplet - Schnittstelle durch. Das wäre dann wiederum keine all zu grosse Hürde.


Raymond


PS:

In diesem Zusammenhang ist vielleicht auch von Interess, dass man Skript-Listen per Folge oder Zip generieren kann. Wenn man zB die Eigenschaften von (benannten) Punkten ändern will, deren Namen in einer Liste aufgezählt sind (oder, wie in der Tabelle, standardisierte Namen haben), so könnte man das über eine generierte Skript-Liste erledigen.

photo
1

Hallo,


Kannst du zu diesen Fragen Angaben machen.
Intel Core i7, 2,6 GHz

4 (Doppel-)Kerne

L2: 256 kB, L3: 6 MB

16 GB max, GGB: ca. 5,4 GB (ca. 300 MB resident, permanent steigend)

GGB 5.0.18 (Java 1.8.0 64 bit, 910 MB)

OSX 10.8.5


Ich habe es noch mal getestet:

    L = {"SetValue[A,A+(1,0)]", "SetValue[k,k+1]", "Execute[L]"}

    Execute[{"SetValue[k,0]","Execute[L]"}]

Nach dem Start von GGB liegt die Anzahl der Schritte (k) zwischen 340 und 408.

Dann erhöht sich die Anzahl langsam beim 2. und 3. mal, nach 5 mal komme ich auf ca. 1700.


Getestet habe ich auch:

    Fibonacci = {"SetValue[c, a+b]", "SetValue[a, b]", "SetValue[b, c]", "SetValue[n, n+1]", "Execute[If[n<30, Fibonacci, {}]]"}

    Execute[{"SetValue[a,0]","SetValue[b,1]","Execute[Fibonacci]"}]

    Heron = {"SetValue[w,(w+r/w)/2]", "SetValue[q,w w]", "SetValue[wn,wn+1]", "Execute[If[q!= r, Heron, {}]]"}

    Execute[{"SetValue[w,1]","SetValue[r,105]","SetValue[wn,0]","Execute[Heron]"}]

    Ulam = {"SetValue[u,If[u ≟ 1, 1, If[Mod[u, 2] ≟ 0, u / 2, 3u + 1]]]", "SetValue[v, v+1]", "Execute[If[u!=1, Ulam, {}]]"}

    Execute[{"SetValue[u,201]", "SetValue[v,0]", "Execute[Ulam]"}]

Fibonacci ergibt 1346269

Heron ergibt w = 10.24695076622689, wn = 6, (q = 105.00000000547784 leider nur auf 8 Stellen wegen der internen Rundung von GGB beim Test auf Gleichheit)

Ulam ergibt u = 1 nach v = 17


Um die Ausgabe der Folgenwerte habe ich mich bisher noch nicht gekümmert, das scheint nicht ganz so einfach zu sein.

die Systemressourcen könnten bei zu häufigen Wiederholungen zum Problem werden.
Stimmt, ist zwar hierbei noch nicht aufgetreten, aber in anderen Fällen (Listen oder Texte über Scripts erstellt) habe ich GGB und auch das System komplett eingefroren.


Gerhard

photo
1

Hallo,


ich habe noch etwas umprobiert.


Heron mit Ausgabe der Zwischenwerte:

    cmdH = "H" + (wn) + "=" + w + ""

    Heron2 = {cmdH, "SetValue[w,(w+r/w)/2]", "SetValue[q,abs((r-w w)*1.0E14)]", "SetValue[wn,wn+1]", "Execute[If[q>1, Heron2, {}]]"}

    Execute[{"SetValue[w,1]", "SetValue[wn,1]", "SetValue[r,%1]", "Execute[Heron2]", "Execute[{cmdH}]"},2]

Fibonacci mit Ausgabe der Folgenglieder

    cmdF = "F" + (n) + "=" + c + ""

    Fibonacci = {"SetValue[c, a+b]", "SetValue[a, b]", "SetValue[b, c]", "SetValue[n, n+1]", cmdF, "Execute[If[n<30, Fibonacci, {}]]"}

    Execute[{"SetValue[a,0]","SetValue[b,1]","SetValue[n,0]","Execute[Fibonacci]","Execute[{cmdF}]"}]

Ulam mit Ausgabe der Schritte bis u_n = 1

    cmdU = {"E" u_0 "=(" u_0 "," v ")"}

    Ulam = {"SetValue[u,If[u ≟ 1, 1, If[Mod[u, 2] ≟ 0, u / 2, 3u + 1]]]", "SetValue[v, v+1]", "Execute[If[u!=1, Ulam, {}]]"}

Das geht:

    Execute[{"SetValue[u_0,%1]", "SetValue[u,u_0]", "SetValue[v,0]", "Execute[Ulam]","Execute[cmdU]"},3]

    ...

    Execute[{"SetValue[u_0,%1]", "SetValue[u,u_0]", "SetValue[v,0]", "Execute[Ulam]","Execute[cmdU]"},10]

Ist aber mühselig.


Was ich nicht hinbekommen habe, ist das über eine Folge zu erledigen:

    list = Sequence[{"SetValue[u_0,"i"]", "SetValue[u,u_0]", "SetValue[v,0]", "Execute[Ulam]"},i,3,10]

geht zwar, kann aber nicht an Execute übergeben werden.

Zitat aus der GGB Hilfe zu Scripting:

These commands don't return any object, therefore cannot be nested in other commands.

Also dürfte es auch schwierig sein, das zu realisieren

Das geht alles nicht:

    Zip["Execute["cmd"]", cmd, list]

    Zip["Execute["cmd"]\n", cmd, list]

    Sequence[Execute[{"SetValue[u_0,%1]", "SetValue[u,u_0]", "SetValue[v,0]", "Execute[Ulam]","Execute[cmdU]"},i],i,3,10]

    Execute[Sequence[{"SetValue[u_0,%1]", "SetValue[u,u_0]", "SetValue[v,0]", "Execute[Ulam]","Execute[cmdU]"},i],i,3,10]

Gerhard

© 2019 International GeoGebra Institute