DMUG-Archiv 1999

Frühere

 

Chronologischer Index

 

Spätere

Vorherige

 

Thematischer Index

 

Nächste

Re: probleme mit Liste

  • From: "Wolf, Hartmut" <hwolf@XXXXXXX.com>
  • Organization: debis Systemhaus
  • Subject: Re: probleme mit Liste
  • Date: Fri, 23 Apr 1999 13:05:22 +0200
  • To: Clemens Frey <btml01@XXXXXXX.de>
  • Cc: dmug@XXXXXXX.ch
  • Old-from: Hartmut Wolf <hw@gsmail01.darmstadt.dsh.de>
Lieber Clements,

recht haben Sie -- in ihrem Beispiel, oder doch nicht? Schauen wir's uns
an!

Grundsätzlich sind alle Eingaben in Mathematica von der Form
expr0[expr1,expr2,...] (wie Sie sich mit FullForm[], gegebenenfalls mit
FullForm[Hold[]] überzeugen können). Diese werden nach dem von S.Wolfram
in Kapitel 2.5 und im Anhang A.4 beschriebenen Verfahren evaluiert,
sprich rekursiv umgeformt, solange bis nichts ändert. Umgeformt werden
dabei alle Ausdrücke, für die in der Session mit Set, oder SetDelayed
ausgeführte Definitionen als OwnValues, DownValues oder UpValues
vorliegen, oder für die im Kern spezielle Behandlungen vorgesehen sind.
Liegen aber solche Definitionen nicht vor, passiert gar nichts.

Die Gestalt der Terme und der Evaluierungsmechanismus sagen nicht aus,
wozu sie verwendet werden. (In der Tat werden sie für _alles_ verwendet,
siehe 2.2.1 bei S.Wolfram)

Vielfach stellt man mit Definitionen mathematische Funktionen dar. Man
sollte sich aber sehr im klaren sein, daß ein Ausdruck

    f[x]   in Mathematica

als programmiersprachliches Objekt etwas völlig anderes ist als

    f(x)

in C, Fortran u.a. Programmiersprachen. Letzteres bezeichnet einen Call
zu einer Prozedur, pragmatisch den Ansprung eines Stückes Codes, der in
der gebundenen Anwendung vorhanden sein muß, einschließlich der
dynamischen Übergabe der Rücksprungadresse und der Parameter in einem
festgelegten Format (in Fortran ist das eine Code-Adresse).

Völlig anders in Mathematica. Hier wird nachgeschaut, ob
Termersetzungsregeln anwendbar sind, wenn ja wird die Substitution
ausgeführt, anderfalls passiert eben nichts.

Betrachten wir ein Beispiel:

In[1]:= a=c[1] /. c[1]->"eins"
Out[1]= "eins"

In[2]:= a
Out[2]= "eins"

In[3]:= ?c
"Global`c"

Wie wir sehen, hat a einen Wert bekommen, c aber nicht! c[1] war nur
eine Form, die uns "eins" zur Zuweisung nach a getragen hat. Die
Funktion von c[1] in diesem Zusammenhang ist nur: sie (1.) bezeichnet
(links in Rule) das zu substituierende Objekt (rechts in Rule) und (2.)
markiert (links in ReplaceAll) die Position an der das Substitut
eingefügt werden soll. Nichts mehr!

In[4]:= c[1]/. c[1]->"eins"
Out[4]= "eins"

In[5]:= c[1]
Out[5]= c[1]

hier ist der Wert nur nach

In[6]:= %4
Out[6]= "eins"

Out[4] getragen worden.

Das ist nun genau die intendierte Funktion im Zusammenhang mit Solve,
DSolve usw.

In[1]:= DSolve[y''[x]==-w^2 y[x],y,x]
Out[1]= {{y->(C[2] Cos[w #1]+C[1] Sin[w #1]&)}}

In[2]:= f[1]=y /. %[[1]] /. {C[1]->0., C[2]->1.} 
Out[2]= 1. Cos[w #1]+0. Sin[w #1]&

In[3]:= f[2]=y /.%%[[1]] /. {C[1]->1., C[2]->0.}
Out[3]= 0. Cos[w #1]+1. Sin[w #1]&

In[4]:= ?y
"Global`y"

In[5]:= Information[C]
"C[i] is the default form for the ith constant of integration produced
in \
solving a differential equation with DSolve."
Attributes[C] = {Protected}

Wir haben uns also zwei Lösungen besorgt, die Funktionen f[1] und f[2]
mit denen wir jetzt beliebige Berechnungen z.B.

    Block[{w=Pi}, Plot[f[2][t],{t,-1,1}]] 

durchführen können. Weder y noch C[1] oder C[2] haben Werte bekommen,
letzteren hätten wir auch überhaupt keine geben können! f selbst ist
weder eine Funktion noch ein Array, sondern ein Symbol. Mit 1 und 2
'indizieren'  wir im Ausdruck f[i] (ursprünglicher Wortsinn "zeigen
auf") die eine oder die andere Lösungsfunktion.

Mit dem Begriff "Array" muß man vorsichtig sein. In Mathematica ist dies
ein (offizieller) technischer Term, der geschachtelte Strukturen mit
Kopf List beschreibt, gilt dann noch die Restriktionen für gleiche Länge
der Subtrukturen auf gleicher Ebene, heißt das Ding auch Matrix, ist der
Wertetyp überall gleich, dann auch Tensor. Außer dem Kopf List, ist
nichts besonderes daran.

Jeder Ausdruck wird in Mathematica intern im Speicher als (jetzt
allgemeine, inoffizielle Sprechweise) "Array" (d.h. als
Wiederholungsstruktur im Speicher) abgelegt. expr0, d.h. der Kopf
(genauer ein Pointer auf den Kopf) auf Position  0, die expr1, expr2,
... (resp. Pointer) auf den folgenden Plätzen 1, 2, ... 
Wird am Ausdruck strukturell etwas verändert, z.B. durch Append, muß
dieses gesamte "Array" kopiert werden, um noch Platz für das
hinzukommende Element zu schaffen. Deswegen sollte man mit Append, Drop
etc. bei _sehr_ großen Strukturen (bei tausenden von Elementen)
vorsichtig sein. Andererseits aber arbeiten die Funktionen Map, Thread,
Transpose, Part, Inner, Outer, etc. direkt auf diesen Strukturen (bzw.
manipulieren sie direkt) und sind deswegen phantastisch schnell.

Jedes Element eines Ausdruckes und jeder Unterausdruck läßt sich mit der
Funktion Part der Struktur entnehmen ("indizieren"), d.h. Part ist die
Manövrierfunktion auf den gestuften (eindimensionalen) Pointer-Arrays
der Implementierung. So gibt

In[10]:= f[2][[1,2,2,0]]
Out[10]= Sin

Nur wenn die Struktur flach ist, bzw. auf einer Ebene, kann man das mit
der Indizierung eines Arrays in C oder in Fortran vergleichen,
keinesfalls aber bei gestuften Indizierungen! Das ist genauso
syntaktischer Zucker wie bei den Funktionen oben! Die Semantik freilich
ist oft -- aber nicht immer -- dieselbe.
__________

Ich wiederhole hier meine Warnung vor reeller "Indizierung" in
Ausdrücken der Form c[i]. Das abgegebene Beispiel sollte eigentlich
schlagend sein. Ich danke aber Roman E. Mäder für seinen angefügten
Hinweis, der mir erst klarmachte, daß c[1.] _unbeabsichtigt_ entstanden
sein könnte. Dann heißt es natürlich dort zu feilen, wo die Reals
reinkamen.

Was jetzt Ihr Beispiel betrifft, lieber Clemens 

Clemens Frey schrieb:
> 
> Hallo!
> 
> Nur ein kleiner Kommentar zur Holzweg-Bemerkung (s.u.), ganz unabhaengig
> vom urspuenglichen Problem. Es ist doch ueberhaupt nicht abwegig, in MMA
> etwa Spezialfaelle einer Funktion so zu definieren :
> 
> c[x_]/; x<0 = -1.;
> c[x_]/; x>0 = 1.;
> c[0.] = c[0] = 0.;
> 
Betrachten wir erstmal:

In[1]:= c[x_]:=-1./; x<0;
        c[x_]:= 1./;x>0;
        c[0]=0.;

In[2]:= epsi=0.+10^-15
Out[2]= \!\(1.`*^-15\)

In[3]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]}
Out[3]= {1.,-1.,0.,1.,-1.,c[0.]}

In[4]:= c[N[Sin[10.^-50000],50000]]
Out[4]= 1.

also der kleinstmögliche positive relle Wort gibt eins (wie es sich
gehört), aber für die reelle 0. (¿was ist das genau?) gibt es keinen
Wert, denn 0. ist nicht größer als 0, nicht kleiner als 0 und c[0.]
matched nicht auf das Muster c[0] -- alles sonnenklar, also, die
"Funktion" hat ein Loch. Wie stopfen?

Versuchen wir's nach Ihrem Vorschlag:

In[1]:= c[x_]:=-1./; x<0;
        c[x_]:= 1./;x>0;
        c[0]=0.;
        c[0.]="hoppla";

In[2]:= epsi=0.+10^-15
Out[2]= \!\(1.`*^-15\)

In[3]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]}
Out[3]= {1.,-1.,0.,1.,-1.,"hoppla"}

In[4]:= c[N[Sin[10.^-50000],50000]]
Out[4]= "hoppla"

In[5]:= N[Sin[10.^-20000],50000]>0
Out[5]= True

Was ist da passiert? c[0.] bekommt den Wert, den wir vorgesehen hatten,
aber der kleinste positve Wert ist zwar nicht gleich Null, bekommt aber
den Wert für reell Null?? (im Gegensatz zum alten Programm oben, wo
dieser richtig berechnet wurde)

Jetzt kommen wir zu einer etwas trüberen Seite von Mathematica. Das
Rätsel löst sich, wenn wir uns die Definition für c anschauen:

In[6]:= ?c
"Global`c"
c[0] = 0.
 
c[0.] = "hoppla"
 
c[x_] := -1. /; x < 0
 
c[x_] := 1. /; x > 0

Aha, es kommt gar nicht zur Abfrage x>0, sondern
c[N[Sin[10.^-20000],50000]] matched c[0.] (Warum das so ist, muß man
wohl bei Wolfram Research nachfragen!)

Deswegen, meine ich, die korrekte Variante deiner Funktion ist

In[9]:= Clear[c]

In[10]:= c[x_]:=-1. /; x<0;
         c[x_]:= 1. /;x>0;
         c[x_]:= 0. /;x==0

In[11]:= ?c
"Global`c"
c[x_] := -1. /; x < 0
 
c[x_] := 1. /; x > 0
 
c[x_] := 0. /; x == 0

In[12]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]}
Out[12]= {1.,-1.,0.,1.,-1.,0.}

In[13]:= c[N[Sin[10.^-50000],50000]]
Out[13]= 1.

Ceterum Censeo!

> Das hat doch nichts mit "Indizierung" irgendeines Arrays zu tun (wir sind
> hier nicht in C!!), auch wenn man das auch damit machen koennte; eine
> solche Methode bietet sich meiner Meinung z.B. an,  falls
> man heufig einzelne Elemente eines grossen Arrays aendern muss und
> verhindern will, das jedesmal das ganze Array wieder ausgewertet
> wird. Weiteres Stichwort: Assoziative Arrays etc.
> 
Der Vorsatz ist geklärt, der Nachsatz ist ein Trick zur Verbesserung der
Performance wie er z.B. bei 

   David B. Wagner: Power Programming with Mathematica: The Kernel

beschrieben ist.

[Anmerkung: Ich wollte natürlich niemanden mit "Holzweg" beleidigen,
aber ich will jeden von einem offensichtlichen Irrweg abhalten!]

Beste Grüße
        Hartmut Wolf


Verweise:
Re: probleme mit Liste
Clemens Frey, 23.04.1999

Frühere

 

Chronologischer Index

 

Spätere

Vorherige

 

Thematischer Index

 

Nächste

DMUG-Archiv, http://www.mathematica.ch/dmug-liste.html; Letzte Änderung: 08.09.2003 20:45