for i in [1,1] wird 2mal ausgeführt?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

Hi Leute,
ich studiere Mathematik und muss mich daher mit Python (genauer Sage) auseinandersetzen.
Wer nicht weiß, was Sage ist und daher denkt, ich sei hier falsch:
Sage ist Python mit ein paar mehr Befehlen, die man in Mathe öfter mal braucht und die Python standardmäßig nicht hat. So hat es zumindest unser Prof gesagt, in wie weit das stimmt, weiß ich nicht, denn ich kenne mich mit Python nicht wirklich aus.
Ich sehe das jetzt zwar nicht zum ersten Mal, aber viel Ahnung habe ich nicht.

Ich will hier auch keine Lösung für meine Aufgaben haben, ich habe lediglich ein spezifisches Problem (im Moment, evtl. hab ich später noch mehr...).
Ich habe eine for-Schleife der Form:

Code: Alles auswählen

for i in [k,n]:
    do something
n ist die Anzahl der Spalten einer Matrix, die ich "bearbeiten" soll (LU-Zerlegung, falls es wen interessiert), k ist der Parameter einen übergeordneten for-Schleife, mit der ich so zu sagen die Zeilen der Matrix durchgehe (nein, ich kann nicht einfach nur einzelne Elemente nehmen, ich brauche diese "Doppelschleife").
Mein Problem ist nun, dass es passieren kann, dass k=n ist und er die for-Schleife dann zweimal ausführt, was mir meine Zerlegung versaut.
Was kann ich da machen, dass er die nur einmal ausführt?
Muss ich was anderes als eine for-Schleife verwenden oder muss ich mein Intervall anders ausdrücken? Geht das ganz anders?

Vielen Dank schonmal für eure Hilfe!

MfG
Arachnid

P.S.:
Ich vermute, diese Frage taucht nicht zum ersten Mal auf, aber über die SuFu habe ich nichts gefunden, da ich nicht recht weiß, mit welchen Schlagwörten ich da suchen sollte, ich habs mit ein paar probiert, aber die haben mir wie gesagt keine Ergebnisse geliefert.

P.P.S.:
Ist nicht so wichtig, würde ich aber gerne wissen. Kann man if-Schleifen in Listen verwenden? Wenn ja wie?
Also irgendwie sowas:

Code: Alles auswählen

liste = [if i==2: 1 else: 0 for i in [1,5]]
So dass er halt eine Liste mit 5 Elementen erstellt, wobei überall 0 steht, außer an der zweiten Stelle?
Ja, ich weiß, mann kann das auch mit liste.append() in einer if-Schleife machen, aber es wäre halt kürzer und übersichtlicher, wenn das irgendwie so ginge.
BlackJack

@Arachnid: Der Körper der ``for``-Schleife, die Du da zeigst wird *grundsätzlich* zweimal ausgeführt, völlig unabhängig von den Werten von `k` und `n`. Vielleicht arbeitest Du mal ein Python-Tutorial für die Grundlagen durch, bevor Du anfängst die Syntax der Sprache zu *raten*. :roll: In der Python-Dokumentation ist zum Beispiel ein Tutorial enthalten. Ansonsten wird für Programmieranfänger auch gerne Learn Python The Hard Way empfohlen.

Bei der gezeigten „list comprehension” bekommst Du aus den selben Gründen immer *zwei* Elemente und nicht fünf. Was Du an Sprachmitteln dort suchst ist entweder der bedingte Ausdruck, oder ganz einfach die `int()`-Funktion, mit der man Wahrheitswerte (True/False) in die Zahlen 1 und 0 umwandeln kann.

Und: http://if-schleife.de/
lunar

@Arachnid "[k,n]" ist eine Liste mit zwei Elementen, nämlich den Werten der Variablen "k" und "n". Mithin wird "for i in [k, n]" immer zweimal ausgeführt, völlig unabhängig von den tatsächlich an "k" und "n" gebundenen Werte. "i" ist dabei im ersten Durchlauf gleich "k", und im zweiten gleich "n".

Das Intervall von "k" bis "n" einschließlich erhältst Du mit "range(k, n+1)", die Schleife lautet dann also "for i in range(k, n+1):".

Eine Liste von fünf Elementen, bei der an zweiter Stelle "1" statt "0" steht, erhältst Du folglich mit "[0, 1, 0, 0, 0]".

Ich weiß nicht, wie in Gottes Namen Du zu der völlig abwegigen Annahme gekommen bist, "[k, n]" wäre ein Interval, doch ganz offensichtlich hast Du Dir nicht einmal die Mühe gemacht, wenigstens die ersten drei Kapitel des Tutorials zu lesen. Stattdessen rätst Du offenbar munter vor Dich hin, wohl in der Hoffnung, dass es irgendwie klappen könnte, und man Dir ansonsten irgendwo im Internet schon weiterhelfen wird. Mit dieser Vorgehensweise und der daraus sprechenden Einstellung wirst Du nicht weit kommen…
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

lunar hat geschrieben:@Arachnid "[k,n]" ist eine Liste mit zwei Elementen, nämlich den Werten der Variablen "k" und "n". Mithin wird "for i in [k, n]" immer zweimal ausgeführt, völlig unabhängig von den tatsächlich an "k" und "n" gebundenen Werte. "i" ist dabei im ersten Durchlauf gleich "k", und im zweiten gleich "n".

Das Intervall von "k" bis "n" einschließlich erhältst Du mit "range(k, n+1)", die Schleife lautet dann also "for i in range(k, n+1):".

Eine Liste von fünf Elementen, bei der an zweiter Stelle "1" statt "0" steht, erhältst Du folglich mit "[0, 1, 0, 0, 0]".

Ich weiß nicht, wie in Gottes Namen Du zu der völlig abwegigen Annahme gekommen bist, "[k, n]" wäre ein Interval, doch ganz offensichtlich hast Du Dir nicht einmal die Mühe gemacht, wenigstens die ersten drei Kapitel des Tutorials zu lesen. Stattdessen rätst Du offenbar munter vor Dich hin, wohl in der Hoffnung, dass es irgendwie klappen könnte, und man Dir ansonsten irgendwo im Internet schon weiterhelfen wird. Mit dieser Vorgehensweise und der daraus sprechenden Einstellung wirst Du nicht weit kommen…
Ich studiere Mathe und nicht Informatik.
Wir hatten eine einwöchige Einführung in Sage, in der unser Prof. bspw. eine for-Schleife so gebaut hat:

Code: Alles auswählen

for i in [1...10]
Da ich als Mathematiker nun mal eher mit Intervallen vertraut bin als mit Programmier- bzw. Scriptsprachen, liegt da der Verdacht nicht so fern.
Ich weiß, dass es auch den range-Befehl gibt, der ist bloß in dem Kontext etwas unkomfortabel, weil der eben von 0 bis ausschließlich zum Argument zählt, das ist zwar kein Problem, aber man muss da eben verstärkt drauf achten, von daher hätte ich eben ein normales Intervall vorgezogen.

Und das man die Liste so erstellen kann, ist mir klar, ich habe nur ein vereinfachtes Beispiel gegeben. Bei mir hinge die Länge der Liste ja von einer Eingabe ab, daher kann ich sie nicht einfach so mauell eingeben, da sie je nach Eingabe anders aussehen muss, deswegen die Frage, ob es auf so eine Art ginge.

Wie einem hier gleich alles Mögliche vorgeworfen wird, weil man als nicht Programmierexperte das mal nicht weiß.
Ich habe sehr wohl einiges bzgl. Python etc. gelesen, da stand halt aber nie drin, "benutze immer range, wenn du ein Intervall willst".
Meine Güte.
Ich weiß, dass es nervig solche Anfängerfragen zu beantworten, die einem vlt. auch trivial oder dämlich vorkommen, aber für Leute, die Python nicht wirklich organisiert lernen, es aber plötzlich schnell beherrschen müssen, stellen sich solche fragen nunmal gelegentlich, da kann man auch etwas höflicher sein...
BlackJack

@Arachnid: Du kannst Dir ja auf Basis der `range()`-Funktion eine eigene Funktion schreiben bei der der Endwert inklusive ist, wenn Du das öfter brauchst.

Natürlich steht nirgends das man immer `range()` verwenden soll wenn man ein Intervall braucht. Es wird aber überall als die Funktion beschrieben mit der man die Zahlen eines Intervalls erzeugt. Also wird das wohl *die* Funktion sein mit der man die Zahlen eines Intervalls erstellt. Denn sonst würde man ja überall auch Alternativen dazu vorgestellt bekommen. Mal von Python 2.x abgesehen wo man die `xrange()`-Funktion bevorzugen sollte, wenn man nicht tatsächlich eine *Liste* von Zahlen benötigt.

Deine Frage hat offenbart, dass Du kein Grundlagentutorial durchgearbeitet hast. Eine ``for``-Schleife über fortlaufende Zahlen ist *so* grundlegend, dass das wirklich in jedem Tutorial vorkommen sollte. Hier hat kaum jemand Lust anderen die Dokumentation von Python vorzulesen oder zu raten was mit „geratener” Syntax tatsächlich gemeint ist. Die meisten hier erwarten, dass Quelltext der gezeigt wird auch tatsächlich funktioniert, also zumindest bis zu dem Fehler den der Fragende darin nicht gelöst bekommt. Und bei Deiner Schleife hätte Dir eigentlich auffallen müssen, dass das kein Intervall von `k` bis `n` ist. Und die `range()`-Funktion kanntest Du ja anscheinend schon.

Auch wenn Du die Sprache „plötzlich” beherrschen musst, führt kein Weg daran vorbei sich die Grundlagen selbst zu erarbeiten. Von jetzt auf gleich kann man keine Programmierprache lernen. Insbesondere nicht, wenn es die Erste ist. Und wie man das unorganisiert machen möchte ist mir nicht so ganz klar.

Quelltextbeispiele von Profs aus Vorlesungen muss man bei einigen leider mit Vorsicht geniessen. Es gibt welche bei denen man am besten gleich davon ausgeht, dass die komplett falsch sind, oder aus verschiedenen Programmiersprachen zusammen gemischt sind. Das Intervall wäre zum Beispiel in der Programmiersprache CoffeeScript syntaktisch richtig — allerdings mit den drei Punkten exklusive dem Endpunkt wie bei `range()`. :-)

Vielleicht noch mal ein Beispiel zur zweiten Frage:

Code: Alles auswählen

In [7]: [int(i == 2) for i in xrange(1, 6)]
Out[7]: [0, 1, 0, 0, 0]
lunar

@Arachnid Ich glaube nicht, dass ich Dir besondere Höflichkeit schulde.

Dir mangelt es an absolut notwendigen, essentiellen und überaus trivialen Grundlagen der Sprache Python. Um diese zu verstehen, musst Du nichts studieren, nicht Informatik, nicht Mathematik, nein, gar nichts. Du musst nur lesen können… und wollen. Nun lesen kannst Du offensichtlich. Die Grundlagen fehlen Dir trotzdem.

Ich kann also nicht anders als anzunehmen, dass Du nicht willens bist, das Tutorial und die Dokumentation selbst zu lesen, sondern vielmehr lieber auf „Verdacht“ programmierst, und Dir die Dokumentation dann lieber vorlesen lässt. Nun, diesen Dienst habe ich Dir erwiesen, Dir sogar die korrekte Lösung für Dein Problem genannt, was mich - wie ich finde – der Pflicht zur besonderen Höflichkeit überhebt, und mir darüber hinaus das Recht gibt, meiner Verärgerung Ausdruck zu verleihen.

Zurück zum Thema:

"range()" zählt nicht zwingend von 0, sondern erlaubt Dir, den Startwert explizit anzugeben. Darauf aufbauend ist es trivial, eine Funktion zu implementieren, die Intervalle angibt:

Code: Alles auswählen

def interval(k, n):
    return range(l, n+1)
Deine Schleife wäre dann wie folgt zu schreiben:

Code: Alles auswählen

for i in interval(n, k):
Wenn Du die Liste dynamisch erzeugen musst, dann nutze den von Blackjack erwähnten bedingten Ausdruck:

Code: Alles auswählen

l = [0 if i != 2 else 1 for i in …]
Achte dabei darauf, dass das zweite Element einer Liste den Index 1 trägt, da die Zählung bei Listen mit 0 beginnt.
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

Dass ich mir so eine Funktion erstellen kann, weiß ich sehr wohl, nur wenn du auf Grund deiner Einführung zu diesem Thema einmal der Überzeugung bist, dass es so ginge, gehst du ja davon aus, dass du so eine Funktion nicht brauchst.
Jetzt weiß ich, wo der Fehler liegt, und werde sowas in Zukunft auch machen.

Und ich glaube ihr versteht hier einiges grundsätzlich falsch.
Ich habe sehr wohl einiges bzgl. Python und speziell for-Schleifen gelesen, bevor ich hier gefragt habe. Aber, wenn du einmal die Idee im Kopf hast, dass es so funktionieren müsste, fällt es dir nicht unbedingt auf, wo der Fehler liegt.
Wie gesagt ich kenne den range()-Befehl sehr wohl und ich weiß auch, dass ich den auch bei 1, 5 oder sonstwo starten lassen kann, ich kann ja auch die Schrittweite ändern usw.
Alles kein Problem.
So eine Einführung nutzt halt nichts, wenn man sie nicht wirklich als Einführung benutzt. Hätte ich von Anfang an mit der Einführung bearbeitet, wäre mir das sicher auch nicht passiert. Ich ging halt auf Grund meines Vorkurses davon aus, dass es gehen müsste, und die Einführung erklärt halt leider nicht, wieso es nicht geht. Da steht halt was anderes.

Ich verstehe jetzt ja auch, wo der Fehler lag, bin halt nur nicht drauf gekommen.

Ihr müsst mich jetzt auch nicht als Vollidioten behandeln.
und ja, dass die Elemente einer Liste nach dem Muster 0, 1, 2 etc. gezählt werden, wusste ich.

BlackJack hat geschrieben:Und: http://if-schleife.de/
Und sry dafür, aber wenn selbst dein Prof. die Dinger "if-Schleifen" nennt...
BlackJack

@Arachnid: Wenn man die Grundlagen kennt, dann weiss man doch aber das ``[2, 7]`` eine Liste mit zwei Elementen ist, und dass man mit einer ``for``-Schleife über die Elemente einer Liste iteriert. Wie kann man denn dann erwarten das bei einer Liste mit zwei Zahlen als Elementen plötzlich etwas *völlig anderes* passiert als in allen anderen Fällen? Mal als Illustration (kein echtes Python-Verhalten):

Code: Alles auswählen

>>> for i in [2]: print i
2
>>> for i in [2, 7]: print i
2
3
4
5
6
7
>>> for i in [2, 7, 10]: print i
2
7
10
Das wäre doch ein total schräges Verhalten, was sehr überraschend wäre und wo sicher viele Leute drüber stolpern würden. Insbesondere wenn die Liste nicht als literal nach dem ``in`` stehen würde, sondern an einen Namen gebunden wird. Dann müsste man ja vor *jeder* Schleife über eine Liste mit ganzen Zahlen sicherstellen, dass die nicht nur aus zwei Elementen besteht und diesen Fall dann besonders behandeln.
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

BlackJack hat geschrieben:@Arachnid: Wenn man die Grundlagen kennt, dann weiss man doch aber das ``[2, 7]`` eine Liste mit zwei Elementen ist, und dass man mit einer ``for``-Schleife über die Elemente einer Liste iteriert. Wie kann man denn dann erwarten das bei einer Liste mit zwei Zahlen als Elementen plötzlich etwas *völlig anderes* passiert als in allen anderen Fällen?
Ich weiß, dass auch Listen so aussehen, es ist mir in dem Moment einfach nicht in den Sinn gekommen, dass er das ja als Liste interpretieren könnte. Ich war mir halt sicher, dass es ein Intervall wäre.
In der Sekunde, wo ihr beide mir das gesagt habt, war es mir auch sofort klar, und ich hab mit die Hand vor die Stirn geschlagen, aber ich kam halt nicht alleine drauf.
lunar

@Arachnid Nun, bedenke, dass wir Dich nur nach dem Inhalt Deiner Beiträge beurteilen können. In diesem Fall ließ sich aus dem Inhalt der Beiträge kaum ein anderes Urteil treffen…

Dennoch habe ich Dir unrecht getan. Das tut mir aufrichtig leid, und ich entschuldige mich dafür.
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

So, mein Programm funktioniert nun, auch dank eurer Hilfe, so wie es soll.
Da ich doch ganz gerne Python wenigstens einigermaßen anständig lernen will, dachte ich mir, ich zeug euch einmal den fertigen Quellcode und frage, ob jemandem daran Dinge auffallen, die ungünstig geschrieben sind.
Sprich, die das Programmfehleranfällig machen oder die man auch einfach eleganter hätte lösen können, denn das sind Sachen, wo ich mich immer schwer tue.

Eine Anmerkung noch:
Da ich Mathestudent bin, wird bei uns kein besonderer Wert auf "Schönheit" oder "Effizienz" der Programme gelegt. D.h. ich bekomme nicht mehr Punkte, nur weil mein Programm einen ausgefeilten Quellcode hat oder so. Nicht, dass jemand auf die Idee kommt, ich versuche mir hier so Punkte von euch verschaffen zu lassen.

So, also zum Quellcode:

Code: Alles auswählen

def listensumme(l):
    ergebnis = 0
    for i in l:
        ergebnis = ergebnis + i
    return ergebnis

def LUZerlegung(M):
    A = M
    n = A.nrows()
    m = A.ncols()
    determinanten = [det(A.submatrix(0,0,k,k)) for k in range(1,n)]
    if n != m:
        sys.exit("Keine LU-Zerlegung moeglich, Matrix ist nicht quadratisch")
    for k in determinanten:
        if k == 0:
            sys.exit("Keine LU-Zerlegung moeglich, Hauptabschittsdeterminanten verschwinden")
    I = identity_matrix(n)
    listelkek = []
    for k in range(1, n):
        lk = []
        ek = matrix([0 if i!=k else 1 for i in range(1,n+1)])
        for i in range(1, k+1):
            lk.append(0)
        for i in range(k+1, n+1):
            lk.append((1/A[k-1,k-1])*A[i-1,k-1])
        print lk
        lk = matrix(lk)
        Mk = I - lk.transpose()*ek
        A = Mk*A
        listelkek.append(lk.transpose()*ek)
    U = A
    L = I + listensumme(listelkek)
    print L*U
    return L, U

M = matrix([[1,2,3],[6,3,1],[9,3,2]])
LUZerlegung(M)
Eine Sache dazu noch, weil ich es vorausahne.
Meine Variablen sind teilweise sehr unpräzise und ich benutze immer wieder die gleichen Buchstaben als "Zählparameter" usw.
Dazu muss ich sagen, dass cih den Algorhitmus ja aus einem Vorlesungsskript in ein Programm übersetzt hab, dementsprechend hab ich meine Variablen so gewählt, wie es am dichtesten an der theoretischen Vorlage ist, d.h. "ek", "lk" etc. sind für mich absolut eindeutig.
Bei den Zählparametern ist das bei mir so ne Marotte, dass ich immer irgendwie nur i und k benutze, hab mich irgendwie dran gewöhnt und sah noch nie einen Grund es anders zu machen. Kommt vlt. noch, wenn die Programme etwas länger werden...

MfG
Arachnid
Zuletzt geändert von Anonymous am Montag 15. April 2013, 16:19, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
lunar

@Arachnid "sys.exit()" ist an dieser Stelle – innerhalb einer Funktion – ein absolutes No-Go. Nutze Ausnahmen, um Fehler innerhalb von Funktionen anzuzeigen.

Die Funktion "listensumme()" ist identisch zur eingebauten Funktion sum() und daher überflüssig.

In der ersten Schleife "for k in determinanten:" würde ich "k" eher "determinante" nennen, da "k" kein Zähler ist, sondern eben eine konkrete Determinante. Die Schleife selbst lässt sich mithilfe der eingebauten Funktion any() abkürzen zu:

Code: Alles auswählen

if any(d == 0 for d in determinanten):
    raise ValueError("Keine LU-Zerlegung moeglich, Hauptabschittsdeterminanten verschwinden")
Statt "sys.exit()" verwende ich hier eine Ausnahme, um den Fehler anzuzeigen.

Die zwei inneren "for"-Schleifen lassen sich ebenfalls abkürzen:

Code: Alles auswählen

lk.extend(0 for i in range(k))
lk.extend((1/A[k-1,k-1])*A[i-1,k-1] for i in range(k + 1, n + 1))
Um Operatoren wie "+" oder "!=", sowie nach Kommata in den Argumente für Funktion werden in Python üblicherweise Leerzeichen platziert, um die Lesbarkeit zu erhöhen.

Die Variablen würde ich englisch benennen, da sich ein Gemisch aus deutschen Namen und englischen Schlüsselwörtern einfach komisch liest. YMMV.

Kürzel wir "lk" sind akzeptable Namen in Quelltext, der sich an mathematisch beschriebenen Algorithmen orientiert. Ebenso sind "i" und "k" übliche Bezeichnungen für Zählvariablen in Programmen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Arachnid: was mir in Ergänzung zu lunar noch aufgefallen ist - warum hast Du die Anweisungen A=M und U=A im Programm? Ausser um nah bei möglichen Bezeichnern Deiner Kursvorlage zu sein, sind sie überflüssig. Der Parameter muß auf Funktionsseite nicht die gleiche Bezeichnung haben, wie beim Aufruf.

Code: Alles auswählen

def LUZerlegung(A):
    ...
    print L*A
    return L, A
Das ist jetzt zwar vergleichsweise banal, aber je mehr Du entschlackst und je genauer die Bezeichner, desto klarer wird Dein Code. Was das wert ist, weisst Du in 14 Tagen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Noch ein paar kleine Sachen:

Code: Alles auswählen

[0 if i!=k else 1 for i in range(1,n+1)]
kannst du etwas umformulieren:

Code: Alles auswählen

[i==k for i in rage(1, n+1)]
was nichts anderes ist als:

Code: Alles auswählen

[i==k]*n
Als Mathematiker hast du natürlich das "Bedrüfnis" die Indizes von 1 bis n laufen zu lassen, wenn du allerdings ``range(1, n+1)`` benutzt und den Index nie verwendest, dann würde ich auf ``range(n)`` umsteigen. Es ist auch üblich, dass nicht-verwendete Zähler den Unterstrich als Namen bekommen:

Code: Alles auswählen

for _ in range(n):
    ....
Das gleiche gilt für

Code: Alles auswählen

lk = []
for i in range(1, k+1):
    lk.append(0)
Das wird dann zu:

Code: Alles auswählen

lk = [0]*k
Ab und zu eine Leerzeile könnte deinem Code auch gut tun.
Das Leben ist wie ein Tennisball.
BlackJack

@Arachnid: Es gibt bereits eine `sum()`-Funktion in Python. Die muss man nicht noch mal selber erfinden. :-)

Die Zeilen ``A = M`` und ``U = A`` bewirken nicht wirklich etwas ausser einen zusätzlichen aber unnötigen Namen einzuführen.

Wenn die Matrix nicht quadratisch ist, kann das ermitteln von `determinanten` schon zu einer Ausnahme führen. Also sollte man das *vorher* testen.

Wenn man nicht tatsächlich eine Liste mit Zahlen benötigt, verwendet man in Python 2.x besser `xrange()` statt `range()`.

`sys.exit()` ist nichts was man in beliebigen Funktionen benutzen sollte. Damit nimmt man dem Aufrufer jede Möglichkeit auf Ausnahmesituationen oder Fehler zu reagieren. Das macht man mit Ausnahmen.

Um zu testen ob eine 0 in `determinanten` ist verwendet man am einfachsten den ``in``-Operator.

Wenn bei ``for i in xrange(1, k + 1):`` das `i` überhaupt nicht verwendet wird, dann kann man den `xrange()`-Aufruf einfacher haben: ``xrange(k)``. Eine Liste mit `k` Nullen kann man aber *noch* einfacher haben, dafür braucht man keine Schleife sondern ``*`` auf Listen.

Namen sollte man möglichst nah an der Stelle einführen an der man sie auch verwendet. An der Stelle wo `ek` verwendet wird, muss man erst mal suchen wo das definiert wurde, weil dazwischen eine ganze Menge Code steht.

Das die `k`-Schleife bei 1 anfängt, macht den soweit ich das sehe komplizierter. Insbesondere auch für Programmierer, bei denen die Zählung halt üblicherweise bei 0 startet. Ich hoffe ich habe mich beim Anpassen nicht vertan (ungetestet):

Code: Alles auswählen

def lu_zerlegung(A):
    n, m = A.nrows(), A.ncols()
    if n != m:
        raise ValueError(
            'Keine LU-Zerlegung moeglich, Matrix ist nicht quadratisch'
        )
    if 0 in (det(A.submatrix(0, 0, k, k)) for k in xrange(1, n)):
        raise ValueError(
            'Keine LU-Zerlegung moeglich,'
            ' Hauptabschittsdeterminanten verschwinden'
        )
    I = identity_matrix(n)
    lkek = list()
    for k in xrange(n):
        lk = [0] * k
        lk.extend((1 / A[k, k]) * A[i, k] for i in xrange(k + 1, n))
        print lk
        lk = matrix(lk)
        ek = matrix([int(i == k) for i in xrange(n)])
        Mk = I - lk.transpose() * ek
        A = Mk * A
        lkek.append(lk.transpose() * ek)
    L = I + sum(lkek)
    print L * A
    return L, A


def main():
    M = matrix([[1, 2, 3], [6, 3, 1], [9, 3, 2]])
    L, U = lu_zerlegung(M)
    print L
    print U


if __name__ == '__main__':
    main()
Edit: Oh, man ich bin heute zuuuu laaaangsam. :-)
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

lunar hat geschrieben:@Arachnid "sys.exit()" ist an dieser Stelle – innerhalb einer Funktion – ein absolutes No-Go. Nutze Ausnahmen, um Fehler innerhalb von Funktionen anzuzeigen.
Danke, hab ich korrigiert.
Ich nehme an, sys.exit() sollte man vermeiden, weil es das ganze Programm abbricht, obwohl nur an einer isolierten Stelle, die nicht unbedingt das komplette Program betrifft ein Fehler vorliegt?
So dass mir nicht eine Funktion, in einem Programm, dass aus vielen besteht, das ganze Programm abbricht?
Ist das dann eher für die Programmstabilität oder für das Finden von Fehlern nützlich? Oder für beides?
lunar hat geschrieben:Die Funktion "listensumme()" ist identisch zur eingebauten Funktion sum() und daher überflüssig.
Mhm, das hat bei mir jetzt nicht wirklich funktioniert. sum() nimmt ja immer 4 Argumente, klar ich könnte mit liste dann über alle Listenelemente iterieren, das hat bei mir aber nicht wirklich geklappt, er hat dann immer eine Fehlermeldung angezeigt, dass ihm eine Summationsvariable fehlt. Beim Suchen nach einer Lösung, habe ich aber den Befehl add() gefunden, der mir sehr nützlich erschien. Ich hab den neuen Quellcode ganz unten, ist das so okay? Könnte es sein, dass hier ein Unterschied zwischen Python und Sage besteht? Das Sage sich sum() für mathematische Summen reserviert?
lunar hat geschrieben:In der ersten Schleife "for k in determinanten:" würde ich "k" eher "determinante" nennen, da "k" kein Zähler ist, sondern eben eine konkrete Determinante. Die Schleife selbst lässt sich mithilfe der eingebauten Funktion any() abkürzen zu:

Code: Alles auswählen

if any(d == 0 for d in determinanten):
    raise ValueError("Keine LU-Zerlegung moeglich, Hauptabschittsdeterminanten verschwinden")
Statt "sys.exit()" verwende ich hier eine Ausnahme, um den Fehler anzuzeigen.
Danke, das mit "determinante" statt "k" ist tatsächlich einleuchtend und sinnvoller. Diese any()-Funktion kannte ich noch gar nicht, danke.
Kleine Frage noch zu dem raise-Befehl. Das "ValueError" gibt eine Klasse an, der der Fehler zugeordnet werden kann, habe ich das richtig verstanden? Also so, dass ich halt dann schnell erkennen kann, ob mein Eingabewert nicht stimmt oder vlt. ein Syntaxfehler vorliegt etc.?
lunar hat geschrieben:Die zwei inneren "for"-Schleifen lassen sich ebenfalls abkürzen:

Code: Alles auswählen

lk.extend(0 for i in range(k))
lk.extend((1/A[k-1,k-1])*A[i-1,k-1] for i in range(k + 1, n + 1))
Danke, liste.extend() war mir nicht so geläufig, hab das zwar gelesen, aber wenn man ständig nur mit liste.append() arbeitet, vergisst man sowas schnell. Wenn ich das richtig sehe, ist .extend() praktisch genauso wie .append(), nur dass ich mit .extend() gleich mehrere Werte hinzufügen kann, sehe ich das richtig?
lunar hat geschrieben:Um Operatoren wie "+" oder "!=", sowie nach Kommata in den Argumente für Funktion werden in Python üblicherweise Leerzeichen platziert, um die Lesbarkeit zu erhöhen.
Okay, ist sinnvoll. Habe ich gemacht, hoffe ich habe nichts übersehen.
lunar hat geschrieben:Die Variablen würde ich englisch benennen, da sich ein Gemisch aus deutschen Namen und englischen Schlüsselwörtern einfach komisch liest. YMMV.
[/quote][/quote]
Okay, auch verständlich. Werde ich mich wohl zukünftig dran halten, sofern mir die nötigen englischen Begriffe vertraut sind.
Die Fehlerausgabe habe ich dennoch auf deutsch gelassen, erschien mir hier eher angemessen.


Okay, hier also mein überarbeiter Quellcode:

Code: Alles auswählen

def LUDecomposition(M):
    A = M
    n = A.nrows()
    m = A.ncols()
    subdeterminants = [det(A.submatrix(0, 0, k, k)) for k in range(1, n)]
    if n != m:
        raise ValueError ("Keine LU-Zerlegung moeglich, Matrix ist nicht quadratisch")
    if any(subdeterminant == 0 for subdeterminant in subdeterminants):
        raise ValueError ("Keine LU-Zerlegung moeglich, Hauptabschnittsdeterminanten verschwinden")
    I = identity_matrix(n)
    listlkek = []
    for k in range(1, n):
        lk = []
        ek = matrix([0 if i != k else 1 for i in range(1, n+1)])
        lk.extend(0 for i in range(1, k+1))
        lk.extend((1 / A[k-1, k-1]) * A[i-1, k-1] for i in range(k+1, n+1))
        lk = matrix(lk)
        Mk = I - lk.transpose()*ek
        A = Mk*A
        listlkek.append(lk.transpose()*ek)
    U = A
    L = I + add(listlkek)
    return L, U
    
M = matrix([ [1, 2, 3], [6, 3, 1], [9, 3, 2] ])
result = LUDecomposition(M)
print "L ist: \n{0}\n\nUnd U ist: \n{1}".format(result[0], result[1])
Ich habe noch einige kleine Änderungen daran vorgenommen, von denen ich meinte sie verbessern die Ausgabe, so dass man halt auch richtig sieht, was das Endergebnis ist.

Auf jeden Fall nochmal vielen Dank für die ganze Hilfe :)
Zuletzt geändert von Arachnid am Montag 15. April 2013, 18:57, insgesamt 1-mal geändert.
BlackJack

@Arachnid: `sum()` nimmt maximal zwei Argumente entgegen, wobei das zweite auch noch optional ist und mit 0 vorbelegt.

Code: Alles auswählen

In [85]: sum?
Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in function sum>
Namespace:  Python builtin
Docstring:
sum(sequence[, start]) -> value

Returns the sum of a sequence of numbers (NOT strings) plus the value
of parameter 'start' (which defaults to 0).  When the sequence is
empty, returns start.
Arachnid
User
Beiträge: 16
Registriert: Dienstag 27. Juli 2010, 18:32

BlackJack hat geschrieben:@Arachnid: `sum()` nimmt maximal zwei Argumente entgegen, wobei das zweite auch noch optional ist und mit 0 vorbelegt.

Code: Alles auswählen

In [85]: sum?
Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in function sum>
Namespace:  Python builtin
Docstring:
sum(sequence[, start]) -> value

Returns the sum of a sequence of numbers (NOT strings) plus the value
of parameter 'start' (which defaults to 0).  When the sequence is
empty, returns start.
Okay, dann ist da definitiv ein Unetrschied zwischen Sage und Python. Denn wenn ich eine Syntaxabfrage für sum() in meiner Sageumgebung starte kriege ich folgendes:
File: /usr/local/sage-5.5/local/lib/python2.7/site-packages/sage/misc/functional.py

Type: <type ‘function’>

Definition: sum(expression, *args, **kwds)

Docstring:

Returns the symbolic sum ∑bv=aexpression with respect to the variable v with endpoints a and b.

INPUT:

expression - a symbolic expression
v - a variable or variable name
a - lower endpoint of the sum
b - upper endpoint of the sum
algorithm - (default: ‘maxima’) one of - ‘maxima’ - use Maxima (the default) - ‘maple’ - (optional) use Maple - ‘mathematica’ - (optional) use Mathematica
Bzw. wenn ich z.B. sum(5, 0, 3) eingebe folgende Fehlermeldung:
TypeError: symbolic_sum() takes at least 4 arguments (3 given)
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Arachnid hat geschrieben:Okay, dann ist da definitiv ein Unetrschied zwischen Sage und Python. Denn wenn ich eine Syntaxabfrage für sum() in meiner Sageumgebung starte kriege ich folgendes
...
File: /usr/local/sage-5.5/local/lib/python2.7/site-packages/sage/misc/functional.py
Ohne Sage zu kennen, vermute ich, das da in Deinem Code etwas in der Art

Code: Alles auswählen

from sage import *
auftaucht und Dir die build-in sum-Funktion von Python verdeckt.
Antworten