Signori, il problema è risolto! (good)
Dopo un bel po' di delirio, ho cambiato il generatore dei numeri pseudocasuali.
Nel programma, inizialmente, usavo la famiglia di funzioni rand48 della stdlib (man drand48).
L'ho sostituita con il generatore (molto migliore) Mersenne Twister.
Oltre a non avere più malfunzionamenti, le simulazioni sono molto più veloci e l'estrazione (di un numero mooolto elevato di numeri) impiega circa un quarto del tempo che serve alle funzioni della famiglia rand48.
Fatto questo preambolo, visto che mi è comunque rimasto di capire come mai succedeva quel delirio, riprenderei con le cose rimaste da dire circa le simulazioni problematiche. E se qualcuno mi vuole venire appresso in questo delirio, perché magari sa capire meglio di me da cosa possa dipendere e vuole illuminarmi, è il benvenuto
Poi, nei prossimi messaggi, concluderei con la seconda questione, quella relativa alle mie perplessità circa il migliore metodo per la stampa degli elementi di un contenitore, da cui pensavo potesse dipendere questo problema.
Il codice delle simulazioni (ovviamente quello che dà problemi) lo riallego in questo messaggio.
(è lo stesso del precedente allegato, ma ho tolto i file .o compilati che per distrazione avevo messo in quello)
Purtroppo non ho un file make, ma una volta scaricato il "pacchetto", lo si compila con:
e poi, per creare l'eseguibile:
La spiegazione del problema è in
questo messaggio.
Per riprodurre il problema, si può procedere in due modi.
O si genera un set generico di simulazioni e poi con l'aiuto di uno script in python (script e spiegazione che accludo più sotto) si cerca tra i file di output quelli con le ripetizioni.
Oppure si lanciano le simulazioni singole con i parametri specifici che dovrebbero riprodurre il problema.
(dico "dovrebbero" perché io ho fatto delle prove e con gli stessi parametri le simulazioni si bloccano su computer differenti, ma mentre so che il mio processore è a 64 bit, non so se lo siano anche quelli degli altri computer o se siano a 32, anche se è più probabile che siano a 64 bit)
Le singole simulazioni problematiche si possono, quindi, lanciare con il comando:
Codice: Seleziona tutto
./MetastableRandWalk -set 100 -file NUMERO_FILE -part 316 -bound 100 -step 10 -visc 1.0 -length 200000 -print 200 -seed SEME
stando attenti a dare NUMERO_FILE sempre diverso (altrimenti, come spiegato sotto, i file di output coincidono e l'output di una simulazione viene appeso a quella precedente) e sostituendo al posto di SEME, per esempio, uno dei valori di questa lista di semi (che sono alcuni di quelli che ho constatato che danno problemi):
Codice: Seleziona tutto
Seme: 1331645036
Seme: 1331645075
Seme: 1331645098
Seme: 1331645122
Seme: 1331645145
Seme: 1331646552
Seme: 1331646592
Seme: 1331646615
Seme: 1331646638
Seme: 1331646662
Seme: 1331646733
Seme: 1331646756
Seme: 1331646780
Seme: 1331646883
Seme: 1331646906
Seme: 1331647618
Seme: 1331647641
Seme: 1331647665
Seme: 1331647688
Seme: 1331647711
Seme: 1331647765
Seme: 1331647788
Seme: 1331647811
Seme: 1331647834
Seme: 1331647889
Seme: 1331647912
Seme: 1331647936
Seme: 1331647959
Seme: 1331647982
Seme: 1331648005
Seme: 1331648027
Visto che i semi sono diversi, si potrebbe mettere tale valore come NUMERO_FILE.
Io ho inserito tale parametro, come si capisce più giù, per numerare le simulazioni di un set.
Alternativamente, potete generare un set di TOT simulazioni (che richiedono poche risorse e durano una manciata di minuti) con il comando:
Codice: Seleziona tutto
for i in `seq 1 1 TOT`; do ./MetastableRandWalk -set 100 -file $i -part 316 -bound 100 -step 10 -visc 1.0 -length 200000 -print 200; done
(ovviamente al posto di TOT ci va un numero
)
In entrambi i casi, nella stessa cartella in cui si lancia il programma, viene creata una cartella di nome:
in cui ci saranno delle sottocartelle:
(se non si varia NUMERO_FILE, come avvertito sopra, il problema è che si mette la simulazione dentro la stessa directory già presente).
All'interno di queste cartelle simulazione ci sono i tre file:
I file in cui si trovano le ripetizioni sono i primi due (se ci sono in crown_dens.txt ci saranno anche in frame_dens.txt "ovviamente").
Se i file sono stati creati con la prima procedura dovrebbero mostrare il problema delle ripetizioni nelle stampe ("dovrebbero", sempre perché non ho la certezza assoluta che anche su un processore a 32 bit diano problemi).
Se invece è stato generato un set di simulazioni con il secondo comando (il ciclo for), o anche se si vuole controllare che una delle simulazioni lanciate con uno dei semi elencati sia problematica anche sulle vostre macchine, si possono isolare le simulazioni problematiche (e anche quelle "tranquille") usando questo script in python, che vi illustro nel dettaglio.
Codice: Seleziona tutto
#! /usr/bin/env python
# -* coding: iso-8859-15 -*-
from sys import argv
import argparse, os
def singleDuplicateLinesSetCheck(inFilePath, untilMatch):
readPartialLines = []
partialRepetitions = []
singleSetFlag = False
if not untilMatch:
untilMatch = "'tempo'"
if not untilMatch.startswith("'"):
untilMatch = "'".join(['',untilMatch,''])
with open(inFilePath) as inFile:
for lineNumber, line in enumerate(inFile):
partialLine = line[:line.find(untilMatch) - 2]
if partialLine in readPartialLines:
if len(partialRepetitions) >= 2:
firstRep = partialRepetitions[0][1]
firstRep = firstRep[:firstRep.find(untilMatch) - 2]
if partialLine == firstRep:
singleSetFlag = True
break
partialRepetitions.append((lineNumber + 1, line))
else:
readPartialLines.append(partialLine)
if partialRepetitions:
firstRep = partialRepetitions[0][1]
firstRep = firstRep[:firstRep.find(untilMatch) - 2]
firstRowNumber = readPartialLines.index(firstRep) + 1
else:
firstRowNumber = 0
return firstRowNumber, singleSetFlag, partialRepetitions
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file', nargs='+', action="store", required=True)
parser.add_argument('--word', action="store")
parser.add_argument('--showSet', action="store_true")
parser.add_argument('--maxPrint', action="store", type=int)
arguments = parser.parse_args()
print arguments
word = arguments.word
for filePath in arguments.file:
try:
firstRowNum, singleSetFlag, repetita = singleDuplicateLinesSetCheck(filePath, word)
print "*"*8
eventsPath = os.path.dirname(filePath) + os.sep + 'events_count.txt'
events = open(eventsPath).readlines()
for event in events:
if event.startswith('Seme'):
seme = '-' + event.rstrip()
break
if repetita:
print "-Ripetizioni in: %s" % filePath
print seme
print "-Prima ripetizione della riga {0} alla riga numero: {1}\n{2}".format(firstRowNum, repetita[0][0], repetita[0][1].rstrip())
if not singleSetFlag:
print "-Numero di righe ripetute indeterminabile; potrebbe essere %i" % (repetita[0][0] - firstRowNum)
else:
rows = len(repetita)
print "-Numero di righe ripetute: %d" % rows
if arguments.showSet:
if arguments.maxPrint != None:
if rows > arguments.maxPrint:
print "-Numero di righe ripetute oltre il limite di %i previsto per la stampa" % arguments.maxPrint
continue
print "-Righe ripetute:"
for index, content in repetita:
print content.rstrip()
else:
print "-Righe ripetute:"
for index, content in repetita:
print content.rstrip()
else:
print "-Nessuna ripetizione in: %s" % filePath
print seme
except IOError as (errno, strerror):
print "{0}\nI/O error({1}): {2}".format(filePath, errno, strerror)
Perché questo script possa funzionare, si deve scaricare il codice del modulo argparse da
questo link (andate tranquilli, perché è un link ufficiale, fornito dal sito del progetto python.org) e metterlo nella stessa directory dello script in python per l'analisi delle simulazioni (oltre ad avere ovviamente l'interprete python installato).
Quindi, sia che si sia prodotto un insieme di simulazioni, sia che si siano lanciate direttamente quelle che a me danno problemi, per produrre un elenco con l'analisi delle simulazioni interne al set o per verificare se la simulazione singola si è bloccata o no, basta lanciare lo script python (ovviamente avendogli dato i permessi di esecuzione) con il comando:
Codice: Seleziona tutto
path_per_lo_script_python -f lista_path_file_da_controllare
Questo script, quindi, con il suo output (che illustro a breve) o dà la conferma che una delle specifiche simulazione lanciate con un seme si è bloccata anche a voi, oppure serve per fare un elenco di simulazioni bloccate tra quelle di un data set.
Il primo caso è abbastanza banale, si tratta di dare il comando qui sopra con il path del file da controllare (io di norma controllo solo i file crown_dens.txt) e vedere l'output singolo.
Nel caso si volesse analizzare un set di simulazioni, l'ideale, per non stare a guardare tutto l'output e per non scrivere ogni singolo path dei file da controllare, sarebbe (concentrandosi solo sui crown_dens.txt, perché tanto, come detto, se le ripetizioni sono in crown_dens sono anche in frame_dens) mettersi nella directory che contiene la cartella del set di simulazioni e dare il comando:
Codice: Seleziona tutto
path_per_lo_script_python -f `find set100-100-10-1.0-316-200000-200 -name "crown*" sort -V` | grep -i ripetizioni
Per fare un esempio, mentre scrivevo questo messaggio ho lanciato un set da 50 simulazioni (con il comando sopra) ottenendo:
Codice: Seleziona tutto
l3on4rdo@l3on4rdo-laptop:~/Documenti/tesi/tesi-03-05-2012/codiciSimulazioni/randomWalkDifettoso$ ls set100-100-10-1.0-316-200000-200/
totale 200K
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 14:20 simulazione01
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 14:23 simulazione02
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 14:23 simulazione03
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 14:24 simulazione04
...
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 15:12 simulazione47
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 15:13 simulazione48
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 15:13 simulazione49
drwxr-xr-x 2 l3on4rdo l3on4rdo 4,0K 2012-03-13 15:13 simulazione50
Di queste, produco un elenco con le informazioni utili (e mi metto l'output nel file ~/Scrivania/problematiche.txt) dando (da dentro la directory che contiene la directory set100-100-10-1.0-316-200000-200) il comando:
Codice: Seleziona tutto
l3on4rdo@l3on4rdo-laptop:~/Documenti/tesi/tesi-03-05-2012/codiciSimulazioni/randomWalkDifettoso$ ~/Documenti/tesi/tesi-03-05-2012/scriptAnalisiDati/repetitionSingleSetCheck.py -f `find set100-100-10-1.0-316-200000-200/ -name "crown*"` > ~/Scrivania/problematiche.txt
In questo modo, nel file, ho la descrizione esatta della situazione, con informazioni del tipo:
Codice: Seleziona tutto
********
-Nessuna ripetizione in: set100-100-10-1.0-316-200000-200/simulazione42/crown_dens.txt
-Seme: 1331647857
oppure:
Codice: Seleziona tutto
********
-Ripetizioni in: set100-100-10-1.0-316-200000-200/simulazione39/crown_dens.txt
-Prima ripetizione della riga 101 alla riga numero: 357
{1: 1.58228e-05, 2: 0.00401064, 3: 0.00750639, 4: 0.00869782, 5: 0.00649113, 6: 0.00645616, 7: 0.00504407, 8: 0.00483857, 9: 0.00756991, 10: 0.00842766, 11: 0.00506011, 'tempo': 71200, 'trapped': 61}
-Numero di righe ripetute: 256
-Seme: 1331647788
a seconda che la simulazione si blocchi o meno.
Da queste informazioni, posso estrarre le informazioni "veramente importanti" circa
il path dei soli file che presentano problemi con il comando:
Codice: Seleziona tutto
l3on4rdo@l3on4rdo-laptop:~/Documenti/tesi/tesi-03-05-2012/codiciSimulazioni/randomWalkDifettoso$ ~/Documenti/tesi/tesi-03-05-2012/scriptAnalisiDati/repetitionSingleSetCheck.py -f `find set100-100-10-1.0-316-200000-200/ -name "crown*" | sort -V` | grep Ripetizioni | cut -f 2 -d ':'
il cui ouput è:
Codice: Seleziona tutto
set100-100-10-1.0-316-200000-200/simulazione03/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione05/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione06/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione07/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione08/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione11/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione13/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione14/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione15/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione16/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione20/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione21/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione22/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione28/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione29/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione31/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione32/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione33/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione34/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione35/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione38/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione39/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione40/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione41/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione44/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione45/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione46/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione47/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione48/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione49/crown_dens.txt
set100-100-10-1.0-316-200000-200/simulazione50/crown_dens.txt
Codice: Seleziona tutto
for filePath in $(~/Documenti/tesi/tesi-03-05-2012/scriptAnalisiDati/repetitionSingleSetCheck.py -f `find set100-100-10-1.0-316-200000-200/ -name "crown*" | sort -V` | grep Ripetizioni | cut -f 2 -d ':'); do echo $filePath; done
oppure circa i semi delle simulazioni bloccate:
Codice: Seleziona tutto
l3on4rdo@l3on4rdo-laptop:~/Documenti/tesi/tesi-03-05-2012/codiciSimulazioni/randomWalkDifettoso$ for filePath in $(~/Documenti/tesi/tesi-03-05-2012/scriptAnalisiDati/repetitionSingleSetCheck.py -f `find set100-100-10-1.0-316-200000-200/ -name "crown*" | sort -V` | grep Ripetizioni | cut -f 2 -d ':'); do grep -i seme `dirname $filePath`/events_count.txt; done
con cui ho ottenuto proprio la lista di semi mostrata sopra.
A margine, faccio presente che lo script implementa anche altre due opzioni:
1°)
con cui si richiede la stampa di un singolo gruppo di righe che si ripetono, qualora questo sia determinabile.
O la stampa dell'avvertimento che il numero di righe non è determinabile
(senza che mi dilungo sui dettagli, può capitare che non si riesca a determinare con certezza il numero di righe ripetute, ma se ne può dare una stima... in pratica capita quando le ripetizioni iniziano "tardi" e non fanno in tempo a essere ristampate tutte le righe, prima che la simulazione termini)
2°)
da dare se viene data la precedente opzione.
Serve per limitare la stampa solo al caso in cui il numero di righe del set che si ripete sia minore o uguale al numero MAX passato come parametro
(esiste anche un ulteriore parametro --word, ma per il momento non serve usarlo).
Con questo, penso di aver detto tutto quello che serve.
Sperando di essere stato chiaro, concludo con una caratteristica "molto strana" che ho notato analizzando il problema.
Il numero di righe ripetute è sempre una potenza di 2 e la cosa mi "affascina" parecchio.
Inoltre il problema non dipende da altro che dal particolare seme di inizializzazione.
Quindi se volete fare altre prove, potete cambiare i parametri (considerando che le simulazioni possono diventare molto lunghe) e isolare, per ogni caso, i semi che danno problemi anche in altre condizioni, seguendo le istruzioni qui sopra.
Se qualcuno vuole venire appresso a questo delirio e dare un'occhiata al problema, lo ringrazio anticipatamente.
La cosa è alquanto assurda, perché la soluzione del problema è consistita nella semplice sostituizione dei generatori di numeri casuali con il generatore Mersenne Twister, di cui ho preso il codice (fornito con licenza GPL) in questo
sito.
Dopo tale sostituzione ho fatto circa 2000 simulazioni e non ci sono stati malfunzionamenti.
Dico che è una soluzione assurda, perché i generatori che usavo inizialmente sono usati solamente nei codici del file libEvolSmart.cpp (e dal main in cui si richiamano le funzioni in esso implementate).
Per esempio, nella funzione:
Codice: Seleziona tutto
list< pair <signed long, signed long> >
stateInit(unsigned long totalPart, unsigned long bound) {
list< pair <signed long, signed long> > sysState;
pair <signed long, signed long> coord;
for(unsigned long particle=1; particle<=totalPart; particle++) {
coord.first = (lrand48() % (2*bound + 1)) - bound;
coord.second = (lrand48() % (2*bound + 1)) - bound;
sysState.push_back(coord);
}
return sysState;
}
è diventata:
Codice: Seleziona tutto
list< pair <signed long, signed long> >
stateInit(unsigned long totalPart, unsigned long bound,
CRandomMersenne &RandGen) {
list< pair <signed long, signed long> > sysState;
pair <signed long, signed long> coord;
for(unsigned long particle=1; particle<=totalPart; particle++) {
coord.first = RandGen.IRandomX(0, 2*bound) - bound;
coord.second = RandGen.IRandomX(0, 2*bound) - bound;
sysState.push_back(coord);
}
return sysState;
}
e tutte le altre modifiche sono dello stesso tipo.
Quindi non capisco proprio come un
ipotetico bug nei generatori della famiglia rand48 (o una correlazione tra i numeri generati) possa aver causato un malfunzionamento di questo tipo.
Perché questi, ora, sono i due unici possibili scenari che vedo come causa di tali malfunzionamenti.
Aspetto un vostro feedback in merito al problema (o un eventuale "a Leona'... ma che te si mpazzito!?"
) per parlare della mia perplessità in merito ai metodi di stampa (e poi mettere [Risolto] a questa discussione
)
Ciao e grazie davvero per l'attenzione.