Matrix mit Zufallszahlen unter Nebenbedingung

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
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Ich möchte eine Matrix erzeugen, welche aus NxN Elementen besteht und jedem Element beliebig die Werte +1 oder -1 zuweist.
Das habe ich bereits ungesetzt:

Code: Alles auswählen

def spingitter(N):
    """Erzeugt Gitter der größe NxN, mit Spinzuständen +1, -1, welche beliebig 
    auf die Gitterplätze verteilt werden"""
    gitter = np.random.random_integers(0,1,(N,N))
    gitter[gitter==0] = -1
    return gitter
Allerdings möchte ich nun, dass diese Matrix unter einer Bedingung erzeugt wird. Und zwar möchte ich vorher Festlegen, wie groß die Summe aller Matrixelemente geteilt durch die Anzahl der Elemente in etwa sein soll. Wie implementiere ich diese Bedingung?
Ich möchte also vorher sagen 'm= 2,7' (mit m= Summe aller Elemente der Matrix / N) und dann soll er die Zustände entsprechend besetzen. Wie geht das?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

>>> import numpy as np
>>> a = np.array([1]*4 + [-1]*8)
>>> np.random.shuffle(a)
>>> a.reshape((3, 4))
array([[-1, -1,  1, -1],
       [ 1, -1, -1,  1],
       [-1,  1, -1, -1]])
Dein jetziger Code lässt sich übrigens leichter ausdrücken. Es ist nicht anderes als

Code: Alles auswählen

np.random.random_integers(0,1,(N,N))*2 - 1
Das Leben ist wie ein Tennisball.
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Habe selber etwas rumgebastelt und folgende Lösung gefunden:

Code: Alles auswählen

def spingitter(N, m, delta):
    """Erzeugt Gitter der größe NxN, mit Spinzuständen +1, -1, welche beliebig 
    auf die Gitterplätze verteilt werden"""
    for i in np.arange(10.0/delta):
        gitter = np.random.random_integers(0,1,(N,N))*2 -1
        if np.abs((np.sum(gitter)/N) - m) <= delta:
            break
        else:
            continue
    return gitter

tau = np.linspace(0.01, 5.0, 100)                   # dim.-lose Temperaturen
tau_c = 2.0 / np.arcsinh(1)                         # kritische Temperatur
N = 50.00                                           # Wurzel Spingitterelemente
delta = 0.005                                       
# maximale Abweichung zwischen gewähltem m und mittlerer Magn. des Spingitters
Wäre das vertretbar? Die Genauigkeit kann so natürlich nicht beliebig klein gewählt werden, aber so funktionierts erstmal.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Deine Lösung funktioniert nicht. Es ist nicht garantiert, dass du bei jedem Funktionsaufruf ein gültiges Gitter bekommst. Ein continue am Ende einer Schleife ist übrigens überflüssig.
Das Leben ist wie ein Tennisball.
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

EyDu hat geschrieben:Deine Lösung funktioniert nicht. Es ist nicht garantiert, dass du bei jedem Funktionsaufruf ein gültiges Gitter bekommst. Ein continue am Ende einer Schleife ist übrigens überflüssig.
Wie soll ich das ganze dann Umsetzen? Versteh nicht, wie ich deinen Algorithmus einbauen soll, wenn ich doch vorher garnicht weis, wieviel 1 und -1 ich brauche.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Doch, die kennst du. Du hast die Anzahl der Einträge in der Matrix und das gewünschte m. Daraus jetzt die Anzahlen der einzelnen Elemente zu berechnen ist nicht so schwer.
Das Leben ist wie ein Tennisball.
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Ja aber da fehlt doch eine Angabe.

Ich kann ja sagen: N*m = k*[1] + (N-k) *[-1]

Da fehlt mir aber trotzdem das k!

Ich steh hier irgendwie auf dem Schlauch

Gern auch jemand anderes, bin über jeden Hinweis dankbar.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@alex2007: wenn Du N und m gegeben hast, dann sind in Deiner Gleichung nur noch 1 und k variabel. Das müßte sich doch lösen lassen.
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Sirius3 hat geschrieben:@alex2007: wenn Du N und m gegeben hast, dann sind in Deiner Gleichung nur noch 1 und k variabel. Das müßte sich doch lösen lassen.
Sorry, aber ich hab echt keinen Plan, wie ich das in den Code von EyDu einbauen soll
BlackJack

@alex2007: Musst Du die Formel nicht einfach nur nach `k` umstellen und kannst das dann ausrechnen? Und wenn Du `k` dann hast, dann kannst Du `k` und `N - k` an der Stelle von 4 und 8 einsetzen. Oder habe ich da etwas falsch verstanden?
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Also:

N*m = k * ([1]-[-1] + N*N *[-1]
=> k = (N*(m+N))/2

Code: Alles auswählen

import numpy as np
k = (N*(m+N))/2
a = np.array([1]*k + [-1]*(N-k))
np.random.shuffle(a)
a.reshape((N, N))
So richtig?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nein. Deine erste "Gleichung" sieht schon komisch aus. Die Rechnung ist doch ganz einfach: Du hast k Einsen, eine NxN-Matrix und damit (N^2 - k) minus Einsen. Als Summe der Einsen und minus Einsen erhältst du dann:

Code: Alles auswählen

k - (N*N - k)
Das musst du jetzt nur noch, wie gewünscht, ins Verhältnis zur Anzahl der Elemente der Matrix setzen:

Code: Alles auswählen

m = (k - (N^2 - k)) / N^2
Und anschließend noch nach k auflösen.
Das Leben ist wie ein Tennisball.
BlackJack

Wenn man die Formel schon in Code-Tags setzt, kann man sie auch ”richtig” setzen. ;-)

Code: Alles auswählen

       2      
    - N  + 2⋅k
m = ──────────
         2    
        N
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

push
Zuletzt geändert von alex2007 am Sonntag 6. Juli 2014, 20:55, insgesamt 1-mal geändert.
alex2007
User
Beiträge: 40
Registriert: Montag 14. April 2014, 10:08

Also:

Code: Alles auswählen

import numpy as np
k = (N**2*(m+1))/2
a = np.array([1]*np.int32(k) + [-1]*np.int32(N**2 - k))
np.random.shuffle(a)
a.reshape((N, N))
So?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

alex2007 hat geschrieben:So?
Ja, die Formel ist korrekt. Allerdings solltest du das k bereits in Zeile zwei runden, das kann in Zeile 3 sonst dazu führen, dass du nicht N^2 Element hast.
BlackJack hat geschrieben:Wenn man die Formel schon in Code-Tags setzt, kann man sie auch ”richtig” setzen. ;-)
Guter Hinweis, gleich viel leserlicher :D
Das Leben ist wie ein Tennisball.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Fülle Deine Matrix mit Float-Zufallszahlen von 0 bis 1. Mache eine Kopie der Matrix. An der Kopie machst Du einen reshape, sodass die Matrix zu einem 1D-Array wird. Sortiere das 1D-Array nach Größe. Iteriere durch das 1D-Array aufsteigend und zähle die Elemente bis Du die Anzahl Deiner -1 Spins hast. Merke Dir den Wert im 1D-Array, bei dem Du das Iterieren abbrichst. In der Original-Matrix kriegen alle Werte <= dem Abbruchwert den Spin -1 und alle anderen +1.
a fool with a tool is still a fool, www.magben.de, YouTube
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@MagBen: das Problem ist bereits mit einer geschlossenen Formel gelöst worden. Ich verstehe auch nicht, welches Problem Dein Algorithmus lösen soll. Wenn Du schon weißt, wieviele -1 Du willst, brauchst Du sie doch nicht erst umständlich zählen. Zum Mischen gibt es shuffle.

das ganze, ohne erst Pythonlisten erzeugen zu müssen:

Code: Alles auswählen

import numpy as np
spins = np.ones((N,N))
k = round((spins.size * (1-m)) / 2)
spins.flat[:k] = -1
np.random.shuffle(spins.flat)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Sirius3: Schöne Lösung, das flat-Attribut muss ich mir merken. Das macht die ganze Sache hier natürlich wesentlich eleganter.
Das Leben ist wie ein Tennisball.
Antworten