Computeralgebra

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.
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich definiere ein Monom, ein Polynom ist dann eine Summe von Monomen:

class Monom():
def __init__(self, c, e):
self.c = c
self.e = e

Dabei ist c der Koeffizient und e ein np.array, das den Exponentenvektor darstellt, z.B. wäre
2.5x^2y^5z
als
h1 = Monom(2,5, np.array([2,5,1]))
dargestellt.
Da man arrays nicht lexikorafisch verggleichen kann, bilde ich daraus eine Liste und definiere Funktionen
lt, gt, eq
die das gewünschte Ergebnis liefern.
Bei der Abfrage
if eq(m.e, b.e):
will ich zwei Exponentenvektoren verleichen, erhalte aber die Fehlermeldung

File "C:\Users\hubert grassmann\py\p.py", line 61, in addm
if lt(m.e, b[0]).e:
File "C:\Users\hubert grassmann\py\p.py", line 47, in lt
ba = [b[0],b[1],b[2]]
TypeError: 'Monom' object is not subscriptable

Dabei ist ba die aus einem Exponentenvektor eines Monoms gebildete Liste, nämlich von b[0].e, aber kein Monom.
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich habe die Listen (aus meiner Frage nach falschem Rechnen) durch np.array ersetzt, es tritt derselbe Effekt auf.
Sollten nicht verschiedene Bezeichner auf verschiedene Objekte verweisen?
Wenn ich a = np.array([1]) und b = a festlege und a ändere, ändert sich dann auch b?
Benutzeravatar
grubenfox
User
Beiträge: 447
Registriert: Freitag 2. Dezember 2022, 15:49

hubertgrassmann hat geschrieben: Montag 26. Dezember 2022, 19:08 Sollten nicht verschiedene Bezeichner auf verschiedene Objekte verweisen?
Wenn ich a = np.array([1]) und b = a festlege und a ändere, ändert sich dann auch b?
Also den Teil kann ich beantworten: "Nein" und "Ja"
Nach b = a verweisen beiden Namen (a und jetzt auch b) auf das Objekt das vorher nur über a zugreifbar war. Einfach mal

Code: Alles auswählen

a = np.array([1])
print(id(a))
b = a 
print(id(b))
Mangels NumPy kann ich es jetzt nicht selbst testen, aber eigentlich sollten dann beide eine identische id haben und damit eben auf das gleiche (oder dasselbe?) Objekt zeigen.
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich programmiere seit ca. 40 Jahren, dieses Verhalten ist unerwartet:

import numpy as np
a = np.array([1])
print("a",a)
b = a.copy()
a[0] = 15
print("b",b)

"""Ausgabe ohne das angehängte copy
a [1]
b [15]
"""
mit copy kommt die erwartete Ausgabe des Werts von b
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

So funktioniert Python eben. Ein Name zeigt auf ein Objekt. Wenn du das gleiche Objekt von diversen Namen aus ansprichst, ändert sich eben immer noch dasselbe Objekt.
narpfel
User
Beiträge: 646
Registriert: Freitag 20. Oktober 2017, 16:10

In Python ist dieses Verhalten seit ca. 30 Jahren erwartet. In vielen anderen Sprachen (den meisten anderen?) auch.

Ein `=` macht in Python keine Kopie, sondern bindet einen Wert an einen Namen. Mit `<name> = <expr>` wird der Wert der Expression auf der rechten Seite des `=` an den Namen auf der linken Seite gebunden. Also: Nach `a = 42` ist der Wert von `42` (also 42) an den Namen `a` gebunden. Nach `b = a` ist der Wert der Expression `a` (also immer noch die gleiche 42) zusätzlich (!) an den Namen `b` gebunden.

Auch wenn es nach 40 Jahren wahrscheinlich schwer fällt: Eine neue Sprache kann man nicht lernen, indem man das ganze Wissen aus einer anderen Sprache 1 zu 1 kopiert (und geschweifte Klammern durch Doppelpunkte und Einrückungen ersetzt). Man muss immer auch einen Schritt zurückgehen und sich klar machen, welches alte Wissen man nicht mitnehmen kann.

Und bitte für Code Codeblöcke benutzen, dann bleibt die Einrückung erhalten, [ i ] wird nicht als „kursiv“ interpretiert und man kann den Code lesen.
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

narpfel hat geschrieben: Montag 26. Dezember 2022, 23:34 In Python ist dieses Verhalten seit ca. 30 Jahren erwartet. In vielen anderen Sprachen (den meisten anderen?) auch.

Ein `=` macht in Python keine Kopie, sondern bindet einen Wert an einen Namen. Mit `<name> = <expr>` wird der Wert der Expression auf der rechten Seite des `=` an den Namen auf der linken Seite gebunden. Also: Nach `a = 42` ist der Wert von `42` (also 42) an den Namen `a` gebunden. Nach `b = a` ist der Wert der Expression `a` (also immer noch die gleiche 42) zusätzlich (!) an den Namen `b` gebunden.
Aber Achtung: Zuweisung einerseits und Änderung eines (änderbaren) Objekts andererseits tun Verschiedenes, gerade auch im Hinblick auf zwei Namen für dasselbe Ding:

Code: Alles auswählen

a = 42
b = a
print(a, b)
42 42
a = 21
print(a, b)
21 42
a = [1, 3, 5]
b = a
print(a, b)
[1, 3, 5] [1, 3, 5]
a.append(7)
print(a, b)
[1, 3, 5, 7] [1, 3, 5, 7]
a = a[:3]
print(a, b)
[1, 3, 5] [1, 3, 5, 7]
Benutzeravatar
sparrow
User
Beiträge: 4237
Registriert: Freitag 17. April 2009, 10:28

@bb1898: Deine Erklärung und den Codeabschnitt finde ich eher verwirrend für den TE als hilfreich.

Code: Alles auswählen

>>> a = 42
>>> b = a
>>> id(a)
1766869528144
>>> id(b)
1766869528144
>>> b = 43
>>> id(b)
1766869528176
Wie man sieht, sind an an und b nach der Zuweisung "b=a" das selbe Objekt gebunden.
MIt b = 43 bindet man ein anderees Objekt (Integer mit dem Wert 43) an den Namen "b".

Ansonsten weiß ich nicht, worauf du hinaus willst, denn das vehält sich bei Listen ja gleich:

Code: Alles auswählen

>>> a = []
>>> b = a
>>> id(a)
1766910889344
>>> id(b)
1766910889344
>>> b = []
>>> id(b)
1766905651328
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich habe diese Erfahrung nun hinter mir: für den Exponentenvektor der Monome hatte ich eine Variable e vereibart und für jedes Monom neu belegt, was sich aber nur lokal auswirkte (korrekte Ausgabe), aber am Ende hatte der letzte gewonnen.
Viel Dank für die Hinweise.
Ich probiere doch, durch weglassen von { } ; aus einem Java-Programm eins für Python zu machen, ganz hoffnungslos bin ich nicht.
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich hatte einen gewissen Erfolg:
ca. 100 Zeilen Quelltext ermöglichen formales Rechnen mit "Variablen" z, y, z, also mit Polynonen.
ein Beispiel: Es wird für das Anfangspolynom die 2., 4., 8. Potzenz berechnet

+x-1z
a = +x^2-2xz+z^2
+x^4-4x^3z+6x^2z^2-4xz^3+z^4
+x^8-8x^7z+28x^6z^2-56x^5z^3+70x^4z^4-56x^3z^5+28x^2z^6-8xz^7+z^8

gibt es Interesse?
Benutzeravatar
__blackjack__
User
Beiträge: 13241
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@hubertgrassmann: Also wenn der Ausgangspunkt Java ist, verstehe ich nicht so ganz die ursprüngliche Überraschung bei der Zuweisung/Übergabe und dem ändern von Objekten, weil sich Java da ja bei Objekten wie Python verhält. Das Beispiel aus Deinem anderen Thema liefert in Java exakt das gleiche Verhalten:

Code: Alles auswählen

import java.util.Arrays;

public final class Test {
    private Test() {}

    private static void print(int[] a) {
        System.out.println(Arrays.toString(a));
    }

    private static void print(Object[] a) {
        System.out.println(Arrays.deepToString(a));
    }

    private static int[][] ma(int[] m, int[][] a) {
        for (var p: a) p[0] = p[0] + m[0];
        return a;
    }

    public static void main(String... args) {
        var h1 = new int[] {1};
        var h2 = new int[] {2};
        var h3 = new int[] {3};
        var b = new int[][]{h1, h2, h3};

        print(h2);
        print(b);
        var c = ma(h2, b);
        print(c);
    }
}
Ausgabe:

Code: Alles auswählen

[2]
[[1], [2], [3]]
[[3], [4], [7]]
Aber auch wenn sich Java und Python in dem Aspekt sehr ähnlich sind, ist es keine gute Idee einfach nur geschweifte Klammern und Semikolons weg zu lassen (das auch Java-Quelltext ordentlich eingerückt ist, setze ich hier mal voraus). Die Sprachen unterscheiden sich in der idiomatischen Verwendung an einigen Punkten, hier und da in technischen Details, und auch die Richtlinien an die sich fast alle Programmierer halten, weisen Unterschiede auf.

Zum Beispiel gilt zwar auch bei Java das man gute, aussagekräftige Namen wählen sollte, durch die statische Typisierung ist es aber in der Regel okay für lokale Namen Abkürzungen zu verwenden wenn da gleich in der Nähe die ordentlich benannte Typdeklaration steht. Also in Python wäre ``b = do_something()`` nicht okay, während das bei Java in ``Butterfly b = doSomething();`` in kurzen Funktionen akzeptabel ist, weil die Bedeutung von `b` durch die Typdeklaration klar ist. Während ``var b = doSomething();`` auch in Java nicht gut ist. Und das gilt natürlich nur wenn `b` tatsächlich nur für das generische `Butterfly` steht. Sollte das die Abkürzung für den Oberschmetterling sein, dann sollte das auch mit Typdeklaration ``Butterfly boss = doSomething();`` heissen.

Wenn ich mir Deine maximal zwei Buchstaben pro Namen Beispiele so anschaue, möchte ich den Code wahrscheinlich eher nicht sehen. 😱
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

an blackjack
Danke für die Belehrung, ich habe natürlich beim Weglassen nachgedacht. Die probeweise eingeführten Funktionen lt, gt, eq werden Fortran-Kennern bekannt vorkommen.
Die von mir implementierten Punktionen heißen add, mult und write, deren Wirkung ist wohl gut verständlich; die Eingabemöglichkeiten sind noch nicht optimal.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

hubertgrassmann hat geschrieben: Mittwoch 28. Dezember 2022, 18:39 an blackjack
Danke für die Belehrung, ich habe natürlich beim Weglassen nachgedacht. Die probeweise eingeführten Funktionen lt, gt, eq werden Fortran-Kennern bekannt vorkommen.
Die von mir implementierten Punktionen heißen add, mult und write, deren Wirkung ist wohl gut verständlich; die Eingabemöglichkeiten sind noch nicht optimal.
Das hört sich an, als ob man die Monom- bzw. Polynom-Klassen mit den entsprechenden special methods sinnvoll aufrüsten könnte (Vergleiche, Multiplikation, Addition, ...).
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Gibt es das nicht alles schon mit https://docs.sympy.org/latest/modules/p ... rence.html ?
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

an deets
Ich habe es mir angesehen, es geht sicher etwas weniger aufwendig
an bord0
ich weiß nicht, wie man Polynome vergleichen will.
Sinnvolle Erweiterungen wäre ggT-Berechnung, Nullstellenmenge von F(x,y,z) (das ist eine algebraische Fläche) grafisch darstellen
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Verzeiung: ggt bei Polynomen in einer Variablen
Benutzeravatar
__blackjack__
User
Beiträge: 13241
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@hubertgrassmann: Wenn Du jetzt gesagt hättest, dass man die Funktionsnamen von den entsprechenden ”magischen” Methoden von Python kennt, okay, aber FORTRAN ist doch schon ziemlich weit weg von Python und Sprach- und Entwurfsentscheidungen die aus *den* Zeiten stammen, sollten heute keine Massstäbe für gute Namen sein. Man kennt die vielleicht auch aus Shell-Programmierung als Argumentnamen für ``test`` oder in der PowerShell wo ``<`` und ``>`` ja schon für Umleitungen von Ein- und Ausgaben verwendet werden, oder aus Perl wo man eine Unterscheidung zwischen Zahlenvergleich und Zeichenkettenvergleich braucht. Ebenso als Operatoren von alten Microsoft-BASIC-Compilern, als Rückfalloption für Rechner wo es so exotische Sachen wie ``<`` oder ``>`` nicht auf der Tastatur gibt, oder wo solche Sonderzeichen schwierig(er) einzugeben sind.

Nur sollte man halt keinen Code schreiben den nur Leute verstehen die schon so lange dabei sind, dass die ersten Erfahrungen mit BASIC-Dialekten gesammelt wurden, die nur 1 bis 2 Buchstaben lange Namen erlaubt haben (mein Erstkontakt: CBM BASIC V2 auf einem C64). Teilweise sogar nur 1 Buchstabe (Beispiel: ZX Spektrum für alles ausser skalare Zahlen). Best practice heute ist es nicht kryptisch abzukürzen, und in der Regel gibt es auch eine Konvention für Funktionen und Methoden die einen Wahrheitswert zurück geben. Also hier `is_less_than()`, `is_greater_than()`, und `is_equal()`. Wobei, wie von bords0 schon angemerkt, das prima Kandidaten für Operatorüberladung zu sein scheinen, so das man dann einfach ``<``, ``>``, und ``==`` mit den Objekten verwenden kann. Das ist etwas was in Java nicht geht, in Python aber schon.
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

hubertgrassmann hat geschrieben: Mittwoch 28. Dezember 2022, 19:18 an bord0
ich weiß nicht, wie man Polynome vergleichen will.
Ich hatte die Vergleiche erwähnt, weil du von lt, gt, eq geschrieben hattest. Das hatte ich so verstanden, dass du Vergleichsfunktionen schreiben willst. (Ich hatte deinem Post entnommen, dass es darum geht, die Koeffizientenfolgen miteinander zu vergleichen, aber vielleicht ist etwas anderes gemeint.)
hubertgrassmann
User
Beiträge: 61
Registriert: Montag 26. Dezember 2022, 14:53

Ich habe einen Modul Rxy fertigestellt (formales Rechnen mit Unbestimmten x, y) und kann die Lösungen von
+0.3x^2+0.2xy^2+0.1y^3+0.5y^2-1=0
plotten (eine komische Kurve, ich würde sie gern zeigen): in einer Liste w stehen alle Punktkoorinaten und ich starte

for p in w:
plt.plot(p[0],p[1],'.r')

Das klappt nicht ohne '.r', auch nicht mit '-r', es ergibt sich also ein recht grobes Bild.
In allen Beispielen, die ich gesehn habe, wird einfach
plt.plot(x,y)
aufgerufen. Was mache ich falsch?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt jedes Mal für jeden Punkt ein Plot Kommando aufzurufen, Bilde zwei Listen x und y. Und rufe damit einmal Plot auf.

Der kanonische Weg das zu tun ist

Code: Alles auswählen

x, y = zip(*w)
Antworten