Mathe-Operation in Python

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
zunder
User
Beiträge: 4
Registriert: Samstag 2. Mai 2015, 14:14

Hallo,

Ich will in Python ein inneres Produkt von Vektoren programmieren.
Ich will das Ganze mit Listen machen, also die Vektoren x ([x1, x2,..., xn]) und y ([y1, y2,..., yn]) sind Listen.
Ich will, dass eine Matrix mit n Zeilen (also eine Liste mit n "Unterlisten") erstellt wird.
Die Zeilen der Matrix sind der Vektor x multipliziert mit dem "n-ten" Eintrag von y.

Also beispielsweise: [[x1*y1, x2*y1, x3*y1], [x1*y2, x2*y2, x3*y2], [x1*y3, x2*y3, x3*y3]]

Danach will ich die Matrix transponieren. Für das Transponieren habe ich schon ein Programm, also muss
ich da nichts schreiben. Außerdem habe ich das Matrixvektorprodukt und das Skalarprodukt zur Verfügung.

Für Hilfe wäre ich sehr dankbar.

Code: Alles auswählen

def skalprod(a,b):
   r=0
   for i in range(len(a)):
      r=r+a[i]*b[i]
   return r

def matvekprod(A,v):
   r=[]
   for i in range(len(A)):
       r=r+ [skalprod(A[i],v)]
   return r

def transcomp(A):
    return [[zeile[sp] for zeile in A] for sp in range(len(A[0]))]

def matprod(I,B):
    if len(I) != len(transcomp(B)):
        print "Falsch"
        return
    C=transcomp(I)
    r=[]
    for i in range(len(I)):
        r=r+ [matvekprod(C,B[i])]
    return r
BlackJack

@zunder: Die drei Setze die da mit „Ich will” anfangen, sollten wohl eher mit „Ich muss” anfangen, denn das riecht verdammt nach Hausaufgaben. Denn wenn man mit Matrizen und Vekoren rechnen will, nimmt man normalerweise einfach die Numpy-Bibliothek.

Anmerkungen zum Quelltext: Da sind ein paar sehr schlechte Namen vergeben worden. Einbuchstabige Namen und einzelne Grossbuchstaben kann man ja noch nachsehen wenn die in der Problemdomäne vorkommen, aber die Funktionsnamen sollten nicht aus kryptischen Abkürzungen bestehen.

Laufindizes sollte man nur verwenden wenn sie wirklich braucht, also wenn `zip()` und `itertools.izip()` zum Beispiel nicht mehr ausreichen. Beispiel:

Code: Alles auswählen

def skalar_produkt(a, b):
    if len(a) != len(b):
        raise ValueError('Die Laengen der Vektoren sind unterschiedlich.')
    return sum(x * y for x, y in izip(a, b))
Hier sieht man auch wie man mit Fehlern in den Eingabewerten einer Funktion umgehen sollte statt eine Ausgabe zu machen und einen speziellen Fehlerwert zurück zu geben.

`matvekprod()` verwendet eine sehr ineffizienze Art um Elemente an eine Liste anzuhängen, denn das passiert dort nur vom Endeffekt her, tatsächlich wird für jede Element eine neue Liste erstellt in die alle Elemente der vorherigen Liste kopiert werden, plus das eine neue Element, was auch noch mal unnötigerweise in eine Liste gesteckt wurde. Es gibt die `append()`-Methode für so etwas. Oder man schreibt das gleich als „list comprehension” (LC).
zunder
User
Beiträge: 4
Registriert: Samstag 2. Mai 2015, 14:14

Interessant, dass du das schreibst, denn diese Funktion stand so auf der Vorlesungsfolie.

Die Funktionsnamen waren bereits vorgegeben.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@zunder: das zeigt nur wieder einmal, dass auch Vorlesungen nicht immer perfekt sind. Einstiegsvorlesungen wechseln die Programmiersprache so oft, wie andere ihre Unterhosen. Da kann man den Dozenten kaum den Vorwurf machen, dass sie die Sprache wenig beherrschen. Aber sinnvolle Variablennamen sollten in jeder Sprache gleich wichtig sein.
Transponieren kann man übrigens so:

Code: Alles auswählen

def transpose(A):
   return zip(*A)
zunder
User
Beiträge: 4
Registriert: Samstag 2. Mai 2015, 14:14

Ich habe es so gelöst:

Code: Alles auswählen

#Hilfsfunktion (es wird eine Diagonalmatrix mit den Werten von g auf der Diagonale erzeugt, aus Vorlesung)
def l(g):
    i=len(g)
    U=[[0]*i for _ in range(len(g))]
    for i in range(len(U)):
        for j in range(len(U[i])):
            if i==j:
                U[i][j] = g[i]
    return U
print l(g)
 
def tensprod(f,g):
    if len(f)!=len(g):
        print 'Die Vektoren sind nicht gleich lang'
        return    
    A=len(f)*[f]
    B=matprod(A,l(g))
    C=transcomp(B)
    return C


print tensprod(f,g)
print tensprod(g,f)
Verlangt war nur das Tensorprodukt von gleich langen Vektoren.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@zunder: jetzt schau Dir mal die Funktionen genau an, und versuche zu verstehen, was Du da machst, und warum das unglaublich umständlich ist.
Zuerst einmal ist l der wohl schlechteste Name für eine Variable den es gibt. Sagt nichts aus, ist zu kurz und sieht auch noch 1 oder I zum verwechseln ähnlich. Du hast in der Funktion 4 len-Aufrufe, die alle zum selben Ergebnis kommen, das Du ganz am Anfang an den nichtssagenden Namen i bindest. Leerzeichen an der ein oder anderen Stelle würden die Lesbarkeit auch erhöhen. Es ist unüblich, in Python Listen vorzuinitialisieren und danach mit Daten zu füllen. for ... in range(len(...)) ist ein Antipattern und sollte so weit es geht vermieden werden. Würde man das alles berücksichtigen, käme ungefähr das raus:

Code: Alles auswählen

def create_diagonal_matrix_from_vector(vector):
    size = len(vector)
    return [
        [0] * index + [value] + [0] * (size - index - 1)
        for index, value in enumerate(vector)
    ]
Die Zeile nach der Funktion wirft einen Nameerror, weil g nicht definiert ist. Welche um welche 10 sprods geht es in der nächsten Funktion?
Ich mußte auch dreimal überlegen, warum die Funktion das macht, was sie macht. Zuerst einmal ist die Fehlerbehandlung fehlerhaft. Bei unterschiedlich langen Vektoren wird als Ergebnis None zurückgeliefert, statt eine Exception zu werfen. Prinzipiell könnte man das Tensorprodukt für unterschiedlich dimensionale Vektoren berechnen. Viel intuitiver ist es doch, das Produkt direkt in einer doppelten Schleife hinzuschreiben:

Code: Alles auswählen

def tensor_produkt(f, g):
    return [
        [x * y for x in g]
        for y in f
    ]
zunder
User
Beiträge: 4
Registriert: Samstag 2. Mai 2015, 14:14

Du hast Recht, l war ungeschickt gewählt, ich habe da einfach irgendeinen Buchstaben genommen.
Die Hilfsfunktion habe ich nicht selber geschrieben, da habe ich die aus der Vorlesung verwendet. Für Vektoren, die nicht gleich lang sind, wäre es wohl zu schwierig, man muss berücksichtigen, dass wir erst drei Vorlesungen zu Python hatten.
BlackJack

@zunder: Es geht ja nicht darum irgend etwas für Vektoren unterschiedlicher Länge zu implementieren sondern da vernünftig mit umzugehen statt einfach `None` zurück zu geben. Wenn eine Funktion nichts mit den Eingabewerten anfangen kann, wäre es sinnvoller einen `ValueError` auszulösen.
Antworten