2009-02-23 12 views
2

Je suis en train d'écrire une simulation et j'ai besoin de quelques conseils sur la conception. L'idée de base est que les données pour les processus stochastiques donnés sont générées et consommées plus tard pour divers calculs. Par exemple, pour une itération:Conception de simulation - flux de données, couplage

  • Process 1 -> génère des données pour la source 1: x1
  • Procédé 2 -> génère des données pour la source 1: x2
  • et ainsi de suite

plus tard Je veux appliquer quelques transformations par exemple sur la sortie de la source 2, ce qui se traduit par x2a, x2b, x2c. Donc, à la fin, avec le vecteur suivant: [x1, x2a, x2b, x2c].

I ont un problème, en ce qui concerne les processus stochastiques N-multivariées (représentant par exemple plusieurs phénomènes corrélés) Je suis pour générer échantillon N dimensions à la fois:

  • Process 1 -> génère des données pour la source 1. ..N: x1 ... xN

Je pense à l'architecture simple qui permettrait de structurer le code de simulation et fournir une flexibilité sans entraver les performances.

Je pensais à quelque chose le long de ces lignes (pseudocode):

class random_process 
{ 
    // concrete processes would generate and store last data 
    virtual data_ptr operator()() const = 0; 
}; 

class source_proxy 
{ 
    container_type<process> processes; 
    container_type<data_ptr> data; // pointers to the process data storage 
    data operator[](size_type number) const { return *(data[number]);} 
    void next() const {/* update the processes */} 
}; 

D'une certaine façon, je ne suis pas convaincu de cette conception. Par exemple, si je voudrais travailler avec des vecteurs d'échantillons au lieu d'une seule itération, alors la conception ci-dessus devrait être modifiée (je pourrais par exemple avoir les processus pour remplir les sous-matrices de la matrice proxy Je ne sais pas si c'est une bonne idée - si oui, cela correspondrait aussi bien au cas de l'itération unique). Tous les commentaires, suggestions et critiques sont les bienvenus.

EDIT:

Bref résumé du texte ci-dessus pour résumer les points clés et de clarifier la situation:

  • random_processes contiennent la logique pour générer des données. Par exemple, il peut dessiner des échantillons à partir d'un gaussien aléatoire multivarié avec les moyennes données et la matrice de corrélation. Je peux utiliser par exemple la décomposition de Cholesky - et par conséquent je vais obtenir un ensemble d'échantillons [x1 x2 ... xN]
  • Je peux avoir plusieurs random_processes, avec des dimensions et des paramètres différents
  • Je veux faire quelques transformations sur les éléments individuels générés par random_processes

Voici le diagramme de flux de données

 
random_processes     output 
    x1 --------------------------> x1 
           ----> x2a 
p1 x2 ------------transform|----> x2b 
           ----> x2c 
    x3 --------------------------> x3 

p2 y1 ------------transform|----> y1a 
           ----> y1b 

la sortie est utilisée pour faire des calculs.

Répondre

1

Quand je lis ce « la réponse » ne se matérialisent pas dans mon esprit, mais plutôt une question:

(Ce problème fait partie d'une classe de problèmes que divers fournisseurs d'outils sur le marché ont créé des solutions configurables pour.

Avez-vous «besoin» d'écrire ceci ou pouvez-vous investir dans une technologie éprouvée pour vous faciliter la vie?

Dans mon travail chez Microsoft, je travaille avec des fournisseurs d'informatique haute performance - dont plusieurs ont des bibliothèques de mathématiques. Les gens de ces entreprises se rapprocheraient beaucoup plus de la compréhension de la question que moi. :)

Cheers, Greg Oliver [MSFT]

0

Je pense que la deuxième option (celle mentionnée dans le dernier paragraphe) est plus logique. Dans celui que vous avez présenté, vous jouez avec des pointeurs et un accès indirect aux données de processus aléatoires. L'autre stockerait toutes les données (vecteur ou matrice) en un seul endroit - l'objet source_proxy. Les objets de processus aléatoires sont ensuite appelés avec une sous-matrice à remplir en tant que paramètre, et eux-mêmes ne stockent aucune donnée. Le proxy gère tout, de la fourniture des données source (pour toute source distincte) à la demande de nouvelles données à partir des générateurs.

Donc changer un peu votre extrait, nous pourrions nous retrouver avec quelque chose comme ceci:

class random_process 
{ 
    // concrete processes would generate and store last data 
    virtual void operator()(submatrix &) = 0; 
}; 

class source_proxy 
{ 
    container_type<random_process> processes; 
    matrix data; 
    data operator[](size_type source_number) const { return a column of data} 
    void next() {/* get new data from the random processes */} 
}; 

Mais je suis d'accord avec l'autre commentaire (Greg) qu'il est un problème difficile, et en fonction de l'application finale peut exiger une réflexion lourde. Il est facile d'aller dans l'impasse avec pour résultat de réécrire beaucoup de code ...

+0

C'est ce que j'avais à l'esprit, mais comme je le disais - je ne sais pas s'il n'y a pas de pièges cachés dans ce ... –

1

Je vais essayer de le faire, peut-être qu'il me manque quelque chose mais on dirait que nous avons une liste de processus 1 .. .N qui ne prend aucun argument et retourne un data_ptr. Alors pourquoi ne pas les stocker dans un vecteur (ou un tableau) si le nombre est connu au moment de la compilation ... et les structurer de quelque façon que ce soit a du sens. Vous pouvez aller vraiment loin avec les objets fonction stl et container construits (std :: vector) (std :: tr1 :: function) et les algorithmes (std :: transform) ... vous n'avez pas beaucoup parlé de la plus haute structure de niveau donc je suppose un naïf vraiment stupide, mais clairement vous construiriez le flux de données de manière appropriée. Cela devient encore plus facile si vous avez un compilateur avec un support pour C++ 0x lambdas car vous pouvez imbriquer les transformations plus facilement.

//compiled in the SO textbox... 
#include <vector> 
#include <functional> 
#include <numerics> 
typedef int data_ptr; 

class Generator{ 
public: 
    data_ptr operator()(){ 
     //randomly generate input 
     return 42 * 4; 
    } 
}; 
class StochasticTransformation{ 
public: 
    data_ptr operator()(data_ptr in){ 
     //apply a randomly seeded function 
     return in * 4; 
    } 
}; 
public: 
    data_ptr operator()(){ 
     return 42; 
    } 
}; 
int main(){ 

    //array of processes, wrap this in a class if you like but it sounds 
    //like there is a distinction between generators that create data 
    //and transformations 

    std::vector<std::tr1::function<data_ptr(void)> generators; 

    //TODO: fill up the process vector with functors... 
    generators.push_back(Generator()); 

    //transformations look like this (right?) 
    std::vector<std::tr1::function<data_ptr(data_ptr)> transformations; 

    //so let's add one 
    transformations.push_back(StochasticTransformation); 

    //and we have an array of results... 
    std::vector<data_ptr> results; 

    //and we need some inputs 
    for (int i = 0; i < NUMBER; ++i) 
     results.push_back(generators[0]()); 

    //and now start transforming them using transform... 
    //pick a random one or do them all... 
    std::transform(results.begin(),results.end(), 
        results.begin(),results.end(),transformation[0]); 
}; 
+0

Merci pour l'idée très agréable. Cependant, il y a encore un problème qui me dérange. Je n'ai pas été assez clair dans la question, alors je vais essayer de le reformuler. –

+0

merci pour clarifier. Cela fait un moment que j'ai regardé les décompositions/factorisations de Cholesky, mais je vais réviser ma réponse tard ce soir ou demain quand j'aurai l'opportunité d'être plus pertinent. – Rick

Questions connexes