WICHTIG: Der Betrieb von goMatlab.de wird privat finanziert fortgesetzt. - Mehr Infos...

Mein MATLAB Forum - goMatlab.de

Mein MATLAB Forum

 
Gast > Registrieren       Autologin?   

Partner:




Forum
      Option
[Erweitert]
  • Diese Seite per Mail weiterempfehlen
     


Gehe zu:  
Neues Thema eröffnen Neue Antwort erstellen

Zufallsmatrix, Zeilen sollen einmalig sein

 

razmatazz.guest

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 20.06.2013, 14:31     Titel: Zufallsmatrix, Zeilen sollen einmalig sein
  Antworten mit Zitat      
Guten Tag,

es soll eine NxM Matrix erstellt werden, mit zufälligen Zahlen aus (1:1:p)
M ist erstmal unbeschränkt.
N=p.

Bsp:
Code:

p=4; M=3;

A=randi([1,p],p,M);
 

Bsp. Matrix:
Code:

A=
1 2 3
2 2 3
1 2 3
4 4 4
 


Jetzt soll zum einen jede Zeile nur einmal auftauchen, d.h. Zeile 3 (oder 1) müssten verändert werden.
Außerdem sollen in keiner Zeile nur identische Elemente stehen, also Zeile 4 ist unzulässig.

Gibt es da kompakte Ansätze für? Mir fallen nur ganz wirre while, if und for Ansätze ein, die wahrscheinlich auch klappen würden, aber das Problem ist, wenn ein Element verändert wird, müssen wieder die Bedingungen geprüft werden. Und die Prüfung ist das, was ich sehr schwierig finde und nur mit einer for Schleife realisieren könnte (eine Zeile jeweils mit allen anderen Zeilen vergleichen, und das für jede Zeile durchführen), aber selbst die krieg ich nicht hin.

Mein Ansatz wäre:
Code:

%Prüfung auf unterschiedliche Elemente in einer Zeile
for i=1:(p-1)
  if %gleiche Elemente
     A(i,:)=randi([1,p],1,M);
  end
end

%Prüfung auf einmalige Zeilen
A=unique(A,'rows');
while size(A,1)<p
   A( (size(A,1)+1):1:p ,:)=randi([1,p],p-size(A,1),M)
   A=unique(A,'rows');
end
 

Das Problem ist die Prüfung auf gleiche Elemente.
Und es müsste am Schluss beides nochmal geprüft werden, um eine übergeordnete while Schleife einzusetzen.

Aber selbst wenn das klappt, KÖNNTE es lange in der while Schleife hängen bleiben (unwahrscheinlich, aber möglich).

Ich hoffe, jemand hat eine Idee und kann mir einen FIngerzeig in die richtige Richtung geben.

Mit einem freundlichen Gruß,
Christoph


Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 20.06.2013, 14:44     Titel: Re: Zufallsmatrix, Zeilen sollen einmalig sein
  Antworten mit Zitat      
Hallo razmatazz.guest,

Einen vollkommen allgemeinen Ansatz für solche Probleme der Kombinatorik kann es nicht geben. "M ist erstmal unbeschränkt" erfordert mehrere verschiedene Ansätze, da sich M=4, M=40000 und M=4e12 nicht mit den gleichen Methoden sinnvoll behandeln lassen.
Kannst Du dies also irgendwie einschränken?

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
razmatazz.guest

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 20.06.2013, 15:03     Titel:
  Antworten mit Zitat      
Ja klar.

Verzeihung ich vergesse immer wieder, dass ganz andere Größenordnungen möglich sind..

M liegt hier im Bereich <10.
p maximal bei 4.
 
razmatazz.guest

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 21.06.2013, 13:14     Titel:
  Antworten mit Zitat      
Ok habe es mit while und for Schleifen gemacht, nicht schön, aber es macht was es soll, und ist noch recht allgemein, wie ich finde.

Für jemanden der vlt. eine Inspiration braucht hier der Code:
Code:

p=4; M=3; werte_ok=0;

A=randi([1,p],p,M);


while werte_ok==0

     %Prüfen ob Zeilenelemente ausschließlich identisch sind
     for i=1:p
        %Zeilenwerte in einen Spaltenvektor schreiben
        hilf_vek=A(i,1:1:size(A,2))' ;
        hilf_vek=unique(hilf_vek,'rows');
        while length(hilf_vek)==1
            A(i,:)=randi([1,p],1,M);
            hilf_vek=A(i,1:1:size(A,2)) ;
            hilf_vek=unique(hilf_vek,'rows');
        end          
     end

     %sowie jede Zeile einmalig ist
     A=unique(A,'rows') ;
     while size(A,1)<p
             A( (size(A,1)+1):1:p ,:)=randi([1,p],p-size(A,1),M)
             A=unique(A,'rows') ;
      end

     werte_ok=1;

     %Nochmals Zeilenelemente auf Gleichheit prüfen
     for i=1:p
        %Zeilenwerte in einen Spaltenvektor schreiben
        hilf_vek=A(i,1:1:size(A,2))' ;
        hilf_vek=unique(hilf_vek,'rows');
        if length(hilf_vek)==1
            werte_ok=0;
            %sobald eine Zeile mit identischen Zeilenelementen gefunden ist,
            %Abbruch dieser Schleife und zurück zum Anfang der äußersten while Schleife
            break
        end          
     end
     
end


Viele Grüße,
Christoph
 
Winkow
Moderator

Moderator



Beiträge: 3.842
Anmeldedatum: 04.11.11
Wohnort: Dresden
Version: R2014a 2015a
     Beitrag Verfasst am: 22.06.2013, 02:26     Titel:
  Antworten mit Zitat      
habs mal ein wenig kürzer gemacht. sollte auch gehen
Code:
p=4;
m=3;
Matrix=zeros(p,m);
for k=1:p
    a=1;
    Matrix(k,:)=0;
    while a==1;
    while length(unique(Matrix(k,:)))==1
    Matrix(k,:)=randi(p,1,m);
    end
    if isempty(intersect(Matrix(1:k-1,:),Matrix(k,:),'rows'))
        a=0;
    end
    end
end

ist aber nicht schneller als deine lösung.
Private Nachricht senden Benutzer-Profile anzeigen
 
razmatazz.guest

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 22.06.2013, 10:53     Titel:
  Antworten mit Zitat      
Danke für dein Interesse und Engagement,

die Lösung gefällt mir gut, kann mir gar nicht vorstellen, warum die nicht schneller ist.
Aber allein im Zuge der Übersichtlichkeit werde ich meine durch deine ersetzen.
Meine Überlegungen waren irgendwie verknotet, und so ist es auch der Code, vorallem habe ich unique unnötig verkompliziert.
Und wieder einen neuen Befehl kennen gelernt (intersect).

Dankeschön =)

Viele Grüße,
Christoph
 
Winkow
Moderator

Moderator



Beiträge: 3.842
Anmeldedatum: 04.11.11
Wohnort: Dresden
Version: R2014a 2015a
     Beitrag Verfasst am: 22.06.2013, 11:20     Titel:
  Antworten mit Zitat      
ich denke es liegt am intersect warums langsamer ist. aber das weis jan oder so bestimmt besser Smile
Private Nachricht senden Benutzer-Profile anzeigen
 
razmatazz.guest

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 22.06.2013, 11:23     Titel:
  Antworten mit Zitat      
Fällt mir gerade erst auf:

"Matrix(k,Smile=0; " ist durch Initialisierung mit "Matrix=zeros(p,m);" überflüssig.

Außerdem hängt sich das ganze in der while a==1 Schleife auf, wenn die Spalten zwar unterschiedliche Elemente beinhalten, Zeilen aber gleich sind, weil es nicht mehr geändert wird.

Code:

p=4;
m=3;
Matrix=zeros(p,m);
for k=1:p
    a=1;
    while a==1;
      while length(unique(Matrix(k,:)))==1
               Matrix(k,:)=randi(p,1,m);
      end
      if isempty(intersect(Matrix(1:k-1,:),Matrix(k,:),'rows'))
               a=0;
      else  Matrix(k,:)=randi(p,1,m);
      end
    end
end

So wird eine identische Zeile nochmal verändert und dann die Schleife nochmal von vorne durchlaufen. So passt es.
 
Winkow
Moderator

Moderator



Beiträge: 3.842
Anmeldedatum: 04.11.11
Wohnort: Dresden
Version: R2014a 2015a
     Beitrag Verfasst am: 22.06.2013, 11:53     Titel:
  Antworten mit Zitat      
das =0 war wichtig. da sonst kein neuer vektor generiert wird. in
Code:
while length(unique(Matrix(k,:)))==1
               Matrix(k,:)=randi(p,1,m);
      end
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 22.06.2013, 12:51     Titel:
  Antworten mit Zitat      
Hallo razmatazz.guest,

Zitat:
NxM Matrix mit zufälligen Zahlen aus 1:p
M liegt hier im Bereich <10.
p maximal bei 4.

Dies erlaubt noch einen brute-force Ansatz, bei dem man zuerst alle möglichen Kombinationen erzeugt und dann zufällig welche aussucht, "N=p" lasse ich weg, da dies von der allgemeinen Lösung abgedeckt wird. Zur effizienten Erstellung aller möglichen Kombinationen wird dies benötigt: http://www.mathworks.com/matlabcent.....exchange/26242-vchoosekro
Code:
p = 4;
M = 10;
N = 15;

pool = VChooseKRO(uint8(1):uint8(p), M);  % Unique combinations

% Delete rows with all equal elements:
index = all(bsxfun(@eq, pool, pool(:, 1)), 2);
pool(index, :) = [];

% Take N rows:
select = randperm(size(pool, 1), N);
% Older: select = randperm(size(pool, 1)); select = select(1:N);
result = pool(select, :);

Damit komme ich auf 0.10 Sekunden (R2011b/64, Win7, Core2Duo). Für M=8, N=15, p=4 werden 0.0067 sec benötigt.
Private Nachricht senden Benutzer-Profile anzeigen
 
razzmatazz
Forum-Newbie

Forum-Newbie


Beiträge: 1
Anmeldedatum: 22.06.13
Wohnort: Aachen
Version: R2011a
     Beitrag Verfasst am: 22.06.2013, 13:34     Titel:
  Antworten mit Zitat      
Hey,

das ist eine super Idee mit dem erzeugen aller Kombination und dann auswählen.
Und die Geschwindigkeit ist heftig.

Ich bin nur nicht zu 100% sicher, ob ich es tatsächlich überehme, da ich von der Zugänglichkeit die bisherigen Lösungen schöner finde. Aber Rechenzeit (allerdings nicht so wichtig bei meinem Problem), Schlankheit, und das Umgehen des möglichen langen Verweilens in den while Schleifen sprechen aber für deine Lösung.

Meine Unentschlossenheit zu deiner Lösung bitte nicht falsch verstehen.
Deine Antwort hat mich wahrlich verblüfft und ich danke dir für deine Leistung.

Ein schönes Wochenende
und mit freundlichen Grüßen,
Christoph
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 22.06.2013, 13:40     Titel:
  Antworten mit Zitat      
Hallo razmatazz.guest,

Zitat:
NxM Matrix mit zufälligen Zahlen aus 1:p
M liegt hier im Bereich <10.
p maximal bei 4.

Dies erlaubt noch einen brute-force Ansatz, bei dem man zuerst alle möglichen Kombinationen erzeugt und dann zufällig welche aussucht, "N=p" lasse ich weg, da dies von der allgemeinen Lösung abgedeckt wird. Zur effizienten Erstellung aller möglichen Kombinationen wird dies benötigt: http://www.mathworks.com/matlabcent.....exchange/26242-vchoosekro
Code:
p = 4;
M = 10;
N = 15;

pool = VChooseKRO(uint8(1):uint8(p), M);  % Unique combinations

% Delete rows with all equal elements:
index = all(bsxfun(@eq, pool, pool(:, 1)), 2);
pool(index, :) = [];

% Take N rows:
select = randperm(size(pool, 1), N);
% Older: select = randperm(size(pool, 1)); select = select(1:N);
result = pool(select, :);

Damit komme ich auf 0.10 Sekunden (R2011b/64, Win7, Core2Duo). Für M=8, N=15, p=4 werden 0.0067 sec benötigt.

Für großes M wird die Erstellung aller möglichen Kombinationen also der Flaschenhals, da es p^M Möglichkleiten gibt. Gleichzeitig sinkt aber auch die Chance, dass man zufällig zwei gleiche Vektoren erhält. Ausserdem sind von den 4^10=1'048'576 Lösungen nur 4, bei denen alle Elemente gleich sind. Die Rejection-Methode ist dann also viel effizienter, also zufällige Kombinantionen erzeugen und bei Bedarf verwerfen.

Dann gibt es noch einen goldenen Weg, der beide Vorteile kombiniert: Erzeugung garantiert unterschiedlicher Kombinationen ohne gleich alle zu erzeugen:
Code:
p = 4;
M = 10;
N = 15;

% select = randperm(p ^ M, N);
select = double(Shuffle(p ^ M, 'index', N));
index  = (select(:) - 0.5) * p .^ (1-M:0);
index  = rem(floor(index), p) + 1;
V      = uint8(1):uint8(p);
result = V(index);

Siehe auch http://www.mathworks.com/matlabcent.....ub-1-0/content/combnsub.m .

Nun müssten nur noch die Ergebnisse ausgefiltert werden, bei denen alle Elemente gleich sind:
Code:
ready = false;
while ~ready
  result = <call the function here>;
  equalRow = all(bsxfun(@eq, result, result(:, 1)), 2);
  ready = ~any(equalRow);
end

Wenn N in der Nähe von p^M liegt, kann diese Zurückweisungsmethode sehr zeitraubend werden. Dann würde ich einen Zähler einbauen, der es erstmal 10 mal so versucht und beim 11.ten mal auf die obige Methode zurückgreift.
Natürlich könnte man auch eine statistische Abschätzung machen, ab welchem Verhältnis N zu p^M sich die eine oder andere Methode besser eignet.

Noch ein allgemeiner Ratschlag: Es scheint bei diesem Problem um zehntel bis 1000stel Sekunden zu gehen. Wenn dies Milliardenfach durchgeführt wird, könnte es sich lohnen eine Stunde aufzuwenden, um Millisekunden weniger Laufzeit zu erreichen. Aber eine Woche mit der Optimierung zu verbringen, damit das Program insgesamt 20 Sekunden kürzer läuft, wäre natürlich Zeitverschwendung.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Neues Thema eröffnen Neue Antwort erstellen



Einstellungen und Berechtigungen
Beiträge der letzten Zeit anzeigen:

Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum posten
Du kannst Dateien in diesem Forum herunterladen
.





 Impressum  | Nutzungsbedingungen  | Datenschutz | FAQ | goMatlab RSS Button RSS

Hosted by:


Copyright © 2007 - 2025 goMatlab.de | Dies ist keine offizielle Website der Firma The Mathworks

MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.