durch eine Liste von 4*4 Matrizen iterieren

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
huebi
User
Beiträge: 5
Registriert: Dienstag 20. Mai 2025, 10:50

Moin,

ich have folgenden Code:

Code: Alles auswählen

positions = [ 
  [[ 1.0, 0.0, 0.0, 0.0],  #x
   [ 0.0, 1.0, 0.0, 0.0],  #y
   [ 0.0, 0.0, 1.0, 0.0],  #z
   [ 0.0, 0.0, 0.0, 1.0]]
]

for p in positions:
    p[0][0] = 4711
    
print(positions)
für mich unerwartet hat sich nun positiions verändert

Code: Alles auswählen

>>> %Run test.py
[[[4711, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]]
>>> 
Nun gut, also halt eine Kopie erzeugt:

Code: Alles auswählen

positions = [ 
  [[ 1.0, 0.0, 0.0, 0.0],  #x
   [ 0.0, 1.0, 0.0, 0.0],  #y
   [ 0.0, 0.0, 1.0, 0.0],  #z
   [ 0.0, 0.0, 0.0, 1.0]]
]

for p in positions:
    x = p.copy()
    x[0][0] = 4711
    
print(positions)
Ausgabe:

Code: Alles auswählen

>>> %Run test.py
[[[4711, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]]
>>> 
Dass sich jetzt positions immer noch verändert verstehe ich nicht. Warum ist das so und wie verhindere ich das?

Hintergrund, ich habe eine Liste von Matrizen für homogene Koordinaten, insgesamt 12 an der Zahl. Diese 12 sollen nun dupliziert werden und eine Translation hinzugefügt werden.

Also aus

Code: Alles auswählen

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
soll

Code: Alles auswählen

1 0 0 dx
0 1 0 dy
0 0 1 dz
0 0 0  1
werden und der Liste hinzugefügt werden. Das Problem ist hier allerdings auf eine zu duplizierende Matrix reduziert.

//Huebi
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

huebi hat geschrieben: Dienstag 20. Mai 2025, 11:00 für mich unerwartet hat sich nun positiions verändert
Das würden aber die meisten Programmierer genau so erwarten, dass man beim Iterieren über eine Liste die Objekte der Liste erhält. Und wenn man die in einer Schleife verändert, dann verändert man eben auch die zugrunde liegende Struktur. Wie hätte es deiner Meinung nach denn funktionieren sollen?

copy() dupliziert übrigens nur die oberste Ebene (sog. flache Kopie). Somit legst du mit copy() zwar eine neue Liste für die zweidimensionale Matrix an, aber die zweite Dimension besteht dabei aus Referenzen zu den Original-Listen aus ``positions`` und somit keinen Kopien. Eine Veränderung daran ist auch hier eine Veränderung am Original.
huebi
User
Beiträge: 5
Registriert: Dienstag 20. Mai 2025, 10:50

Ich glaube nicht dass die meisten nach copy noch erwartet haben dass sich das durchiterierte Objekt doch noch ändert. Hab die Lösung und Erklärung aber mittlerweile anderweitig gefunden.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@huebi: Naja die Dokumentation zu `copy()` sagt, dass es eine flache Kopie erstellt, da würden die meisten halt doch erwarten, dass sich da was ändert.

Die übliche Lösung ist nichts zu verändern, sondern neue Objekte erstellen, mit den gewünschten Werten. Alternativ einen anderen Datentyp als Listen verwenden, beispielsweise Numpy-Arrays, aber auch hier explizit `copy()` aufrufen und sich nicht darauf verlassen, dass Kopien erstellt werden wenn man die nicht explizit anfordert. Denn Numpy versucht das von sich aus zu vermeiden, solange das nicht auf die Performance geht.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

huebi hat geschrieben: Dienstag 20. Mai 2025, 11:00 Also aus

Code: Alles auswählen

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
soll

Code: Alles auswählen

1 0 0 dx
0 1 0 dy
0 0 1 dz
0 0 0  1
werden
Dieser Teil aus Spaß an der Freude mal mit Python Boardmitteln umgesetzt. Wobei ich die Anforderung auf beliebig viele Felder mit einer beliebigen Länge verallgemeinert habe. Man muss nur ausreichend viele Namen mitgeben.

Code: Alles auswählen

def set_names(matrix, names):
    return [
        [*field[:-1], name]
        for field, name in zip(matrix, names)
    ] + matrix[len(names):]

def print_matrix(matrix, bottom_line=None):
    for field in matrix:
        print(*field)
    if bottom_line is not None:
        print(bottom_line)

def main():
    positions = [
        [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ]
    ]
    names = ["dx", "dy", "dz"]
    for matrix in positions:
        print_matrix(matrix, "-" * 8)
        print_matrix(set_names(matrix, names))


if __name__ == "__main__":
    main()
huebi
User
Beiträge: 5
Registriert: Dienstag 20. Mai 2025, 10:50

Ich habe in der Tat mit numpy arrays angefangen, diese aber wieder verworfen weil bei homogenen Koordinaten an bestimmten Stellen klar ist was rauskommt und man das nicht ausrechnen muss. Numpy weiss natürlich nicht dass ich mit homogenen Matrizen rechne und rechnet alles brav durch. Wenn man dann noch loop unrolling macht ist es in der Tat schneller die Multiplikation selbst zu kodieren. Die copy Methode eines numpy array Arrays macht aber deepcopy. Daher war ich überrascht dass die copy Methode des Listobjektes nur eine flache Kopie erzeugt. Dass es extra ein copy package mit einer deepcopy Funktion gibt war mir bisher nicht bekannt.

Ach ja, danke für den Code. Dx dy dz sind allerdings Zahlen, nämlich die Werte des Translationsvektors 8)
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

@huebi: ich bezweifle stark, dass Du irgendetwas schnelleres selbst programmieren kannst, als das, was numpy intern macht.
Wenn man deepcopy glaubt zu brauchen, dann macht man etwas falsch.
In Dein Problem läuft man gar nicht, wenn man sauber mit Funktionen und Listen arbeitet:

Code: Alles auswählen

def translate(matrix, dx, dy, dz):
    return [
        [*row[:3], row[-1] + q]
        for q, row in zip((dx, dy, dz, 0), matrix)
    ]
...
new_positions = [
    translate(matrix, 1, 2, 3)
    for matrix in positions
]
huebi
User
Beiträge: 5
Registriert: Dienstag 20. Mai 2025, 10:50

Ich muss mich hier nicht beweisen. Ich habe geschrieben dass es bei homogenen Koordinaten Abkürzungen gibt die numpy nicht kennt und deepcopy nimmt mir eine Menge Arbeit ab. Du siehst ausserdem nur einen klitzekleinen Auschnitt. Von daher ist die Diskussion für mich beendet wenn es in "bezweifeln" und "falschmachen" geht.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@huebi: Numpy's `copy()` macht kein ”deepcopy” denn da gibt es gar keine verschachtelte Objektstruktur. Die Array-Objekte haben direkt Zugriff auf die Daten und ein `copy()` kopiert diese Daten halt.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
noisefloor
User
Beiträge: 4167
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Ich habe geschrieben dass es bei homogenen Koordinaten Abkürzungen gibt die numpy nicht kennt
Du kannst mit Numpy alles machen, was du auch mit Python Listen machen kannst.Wenn du also eine "Abkürzung" kennst, dann ginge das auch mit Numpy.

Ob du's verwendest oder nicht liegt am Ende an dir. Du wirst halt i.d.R. in allen Python Forum darauf hingewiesen, dass man besser Numpy nimmt, statt sich mit verschachtelten Listen selber was zu basteln. Selbst wenn die Performance keine Rolle spielt: Numpy hat den größeren Werkzeugkasten.

Gruß, noisefloor
huebi
User
Beiträge: 5
Registriert: Dienstag 20. Mai 2025, 10:50

Es sind Spezialfälle bzgl homogener Koordinaten und von mir benötigter Symmetrieoperationen im Raum. Ich glaube nicht dass nimpy vorher die Matrizen analysiert und dann Optimierungen vornimmt. Numpy rechnet alles brav durch, ich brauche manchmal nur Elemente vertauschen oder nur zwei oder drei Multiplikatilnen wo numpy immer schön alle Multiplikationen , 16 an der Zahl, durchrechnen. Ich hab mir einen Sack sehr spezieller Funktionen gebaut die Symmetrieeigenschaften ausnutzen und Egebnisse die bekannt sind nicht ausrechnen.

Aber natürlich bin ich doof und habe nicht nachgemessen.
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@huebi: AFAIK reiht NumPy die Werte einfach hintereinander auf als ein Array. Die Strukturierung in Dimensionen erfolgt sozusagen auf Abruf. Man möge mich korrigieren, wenn ich das falsch verstanden habe. Auf jeden Fall ist dann ja eine Kopie etwas anderes als in Python, wo die Daten intern tatsächlich in einzelnen PyList()-Objekten stecken (oder allen möglichen anderen Strukturen).
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und zu dem anderen Thema: Was fortgeschrittene Algorithmen angeht, hat SciPy noch jede Menge zu bieten, falls du das noch nicht kennst. Das arbeitet auf NumPy-Basis, ist auf spezifischen Gebieten aber eben "smarter".
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

@huebi: Du darfst stolz auf Dich sein, dass Du alle Spezialfälle einzeln durchprogrammiert hast und dann auch noch so tolle Dinge wie loop-unrolling draufhast.
Wenn Du aber vor hast, ernsthaft zu programmieren, dann gilt Messen statt Behaupten.
Neben dem Argument, dass numpy schneller ist, gibt es auch noch die Argumente, dass eine einfache Matrixmultiplikation einfacher zu verstehen ist, weniger fehleranfällig ist.
Du kannst natürlich jeden Satz als Vorwurf lesen, oder einfach als das, was es ist, gut gemeinte Tipps.
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Loop Unrolling in Python klingt ein bisschen so, als hat da jemand ein Buzzword aufgeschnappt und glaubt, dass dies in jeder Programmiersprache einen spürbaren Vorteil bringen würde. Bevor man mit so etwas anfängt bzw. sofern es wirklich erforderlich ist, sollte man IMHO lieber etwas wie Cython, PyPy oder Numba einsetzen und auf vermeintlich optimierte Eigenkreationen verzichten.
Benutzeravatar
noisefloor
User
Beiträge: 4167
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Ich glaube nicht dass nimpy vorher die Matrizen analysiert und dann Optimierungen vornimmt. Numpy rechnet alles brav durch, ich brauche manchmal nur Elemente vertauschen oder nur zwei oder drei Multiplikatilnen wo numpy immer schön alle Multiplikationen , 16 an der Zahl, durchrechnen.
Das klingt stark nach einem Äpfel-Birnen-Vergleich... Grundsätzlich macht der Code genau da, was _du_ programmierst. Numpy beherrscht genau so den Zugriff auf einzelne Elemente wie eine Python-Liste. D.h. alle deine Optimierungen kannst du genau so auf Numpy Arrays anwenden, ebenso wie auf verschachtelte Python Listen. Wenn du Numpy alles stumpf durchrechnen lässt, und das mit meinem optimierten, gezielten Zugriff auf einzelne Elemente vergleichst, ist das halt weder das selbe noch das gleiche vom Vorgehen her.

@snafu: wie Numpy intern Daten organisiert: https://numpy.org/doc/stable/dev/internals.html Da ist auch beschrieben / verlinkt, wie man beeinflussen kann, ob die Daten reihenweise oder spaltenweise gespeichert werden,
Antworten