2010-06-29 9 views
2

est une opération très longue qui génère un jeu de données dans mon package. Je voudrais enregistrer cet ensemble de données et laisser le package le reconstruire uniquement lorsque je supprime manuellement le fichier mis en cache. Voici mon approche dans le cadre du paquet:La mise en cache de données dans Mathematica

myDataset = Module[{fname, data}, 
    fname = "cached-data.mx"; 
    If[FileExistsQ[fname], 
     Get[fname], 
     data = Evaluate[timeConsumingOperation[]]; 
     Put[data, fname]; 
     data] 
]; 

timeConsumingOperation[]:=Module[{}, 
    (* lot of work here *) 
    {"data"} 
]; 

Cependant, au lieu d'écrire les longues ensemble de données dans le fichier, la commande Put écrit une seule ligne: « timeConsumingOperation [] », même si je l'enveloppe avec Évaluer comme ci-dessus. (Pour être vrai, ce comportement n'est pas cohérent, parfois l'ensemble de données est écrit, parfois non.)

Comment mettez-vous en cache vos données?

Répondre

1

Dans le passé, chaque fois que j'avais des problèmes d'évaluation, c'était généralement lorsque je ne correspondais pas correctement au modèle requis par la fonction. Par exemple,

f[x_Integers]:= x 

qui ne correspondra à rien. Au lieu de cela, je voulais dire

f[x_Integer]:=x 

Dans votre cas, cependant, vous avez pas de modèle pour correspondre: timeConsumingOperation[].

Votre problème est plus probable lorsque timeConsumingOperation est défini par rapport à myDataset. Dans le code que vous avez posté ci-dessus, timeConsumingOperation est défini après myDataset. Ainsi, lors de la première exécution (ou immédiatement après avoir effacé les variables globales), vous obtenez exactement le résultat que vous décrivez car timeConsumingOperation n'est pas défini lorsque le code myDataset est exécuté.

Maintenant, SetDelayed (:=) provoque automatiquement le recalcul de la variable chaque fois qu'il est utilisé, et puisque vous n'avez besoin d'aucun paramètre à passer, les crochets ne sont pas nécessaires. Le point important ici est que timeConsumingOperation peut être déclaré, tel qu'écrit, avant myDataset parce que SetDelayed le fera ne pas être exécuté jusqu'à ce qu'il soit utilisé. Au total, votre méthodologie de mise en cache ressemble exactement à ce que je ferais à ce sujet.

+0

Cela semble résoudre mon problème. Merci! –

8

Une autre technique de mise en cache que j'utilise très souvent, en particulier lorsque vous ne souhaitez pas insérer la forme précalculée, par exemple. un paquet, est à memoize l'évaluation coûteuse (s), de sorte qu'il est calculé lors de la première utilisation, mais ensuite mis en cache pour les évaluations ultérieures. Ceci est facilement accompli avec SetDelayed et Set en concert:

f[arg1_, arg2_] := f[arg1, arg2] = someExpensiveThing[arg1, arg2] 

Notez que SetDelayed (:=) se fixe plus élevé que Set (=), de sorte que l'ordre implicite de l'évaluation est la suivante, mais vous n'avez pas besoin en fait la parens:

f[arg1_, arg2_] := (f[arg1, arg2] = someExpensiveThing[arg1, arg2]) 

Ainsi, la première fois que vous évaluez f[1,2], le retard évaluation-ERS est évaluée, ce qui provoque la valeur résultante est calculée et stockée sous forme de OwnValuef[1,2] avec Set.

@rcollyer est aussi juste que vous n'avez pas besoin d'utiliser des crochets vides si vous avez pas d'arguments, vous pouvez tout aussi facilement écrire:

g := g = someExpensiveThing[...] 

Il n'y a pas de mal à les utiliser, cependant.

+2

memoization est certainement utile, et pourrait facilement être couplé avec le type de mise en cache que l'OP recherche. En ce qui concerne le fait de ne pas avoir besoin des supports vides, je peux voir une bonne utilisation pour eux: faire savoir au programmeur de maintenance qu'il s'agit d'une valeur calculée. Sinon, vous pourriez faire un peu de chasse pour pouvoir dire qu'il recalcule chaque fois qu'il est appelé. – rcollyer