wolfram-mathematica – 使用内存构建函数的最佳方式

美好的一天,

我有一些非常slooooow和复杂的功能,说f [x,y]。我需要构建它的详细轮廓图。此外,函数f [x,y]有时由于缺少物理内存而失败。在这种情况下,我必须停止评估并自己调查{x,y}点的问题。然后我应该将元素{x,y,f [x,y]}添加到f [x,y](例如“缓存”)的计算值列表中,然后重新开始轮询ContourPlot。 ContourPlot必须从缓存中获取所有已经计算出的f值。我希望将这样的列表存储在某些文件中,以便稍后再次使用它。手动添加问题点可能更简单。

如果f的计算值的列表可能包含10000-50000点,那么实现最快的方法是什么?

我们假设我们的慢函数具有签名f [x,y]。

纯内存方法

如果您对内存中的缓存感到满意,最简单的事情就是使用memoization:

Clear@fmem
fmem[x_, y_] := fmem[x, y] = f[x, y]

每次调用时,它都会自动添加一个定义。

文件支持的内存中方法

但是,如果您在长时间的计算过程中内存不足或遇到内核崩溃,您将需要使用某种持久性来备份该缓存。最简单的事情是保持运行的日志文件:

$runningLogFile = "/some/directory/runningLog.txt";

Clear@flog
flog[x_, y_] := flog[x, y] = f[x, y] /.
  v_ :> (PutAppend[Unevaluated[flog[x, y] = v;], $runningLogFile]; v)

If[FileExistsQ[$runningLogFile]
, Get[$runningLogFile]
, Export[$runningLogFile, "", "Text"];
]

flog与fmem是一样的,除了它还将一个条目写入正在运行的日志中,该条目可以在稍后的会话中恢复缓存的定义。最后一个表达式在找到现有日志文件时重新加载这些定义(或者如果文件不存在则创建该文件)。

当需要手动干预时,日志文件的文本性质很方便。请注意,浮点数的文本表示引入了不可避免的四舍五入错误,因此在从日志文件中重新加载值后,可能会产生稍微不同的结果。如果这是非常值得关注的话,您可以考虑使用二进制DumpSave功能,尽管我将把这种方法的细节留给读者,因为它不太方便保存增量日志。

SQL方法

如果内存真的很紧张,并且您想要避免使用大量的内存中缓存来为其他计算腾出空间,那么以前的策略可能不合适。在这种情况下,您可能会考虑使用Mathematica的内置SQL数据库来完全从外部存储缓存:

fsql[x_, y_] :=
  loadCachedValue[x, y] /. $Failed :> saveCachedValue[x, y, f[x, y]]

我在下面定义了loadCachedValue和saveCachedValue。基本思想是创建一个SQL表,其中每行包含x,y,f三元组。每次需要一个值时都会查询SQL表。请注意,这种方法比内存缓存慢得多,所以当f的计算时间比SQL访问时间长得多的时候,这是最有意义的。 SQL方法不会受到影响文本日志文件方法的四舍五入的错误的影响。

loadCachedValue和saveCachedValue的定义现在跟随着一些其他有用的帮助函数:

Needs["DatabaseLink`"]

$cacheFile = "/some/directory/cache.hsqldb";

openCacheConnection[] :=
  $cache = OpenSQLConnection[JDBC["HSQL(Standalone)", $cacheFile]]

closeCacheConnection[] :=
  CloseSQLConnection[$cache]

createCache[] :=
  SQLExecute[$cache,
    "CREATE TABLE cached_values (x float, y float, f float)
     ALTER TABLE cached_values ADD CONSTRAINT pk_cached_values PRIMARY KEY (x, y)"
  ]

saveCachedValue[x_, y_, value_] :=
  ( SQLExecute[$cache,
      "INSERT INTO cached_values (x, y, f) VALUES (?, ?, ?)", {x, y, value}
    ]
  ; value
  )

loadCachedValue[x_, y_] :=
  SQLExecute[$cache,
    "SELECT f FROM cached_values WHERE x = ? AND y = ?", {x, y}
  ] /. {{{v_}} :> v, {} :> $Failed}

replaceCachedValue[x_, y_, value_] :=
  SQLExecute[$cache,
    "UPDATE cached_values SET f = ? WHERE x = ? AND y = ?", {value, x, y}
  ]

clearCache[] :=
  SQLExecute[$cache,
    "DELETE FROM cached_values"
  ]

showCache[minX_, maxX_, minY_, maxY_] :=
  SQLExecute[$cache,
    "SELECT *
     FROM cached_values
     WHERE x BETWEEN ? AND ?
     AND y BETWEEN ? AND ?
     ORDER BY x, y"
  , {minX, maxX, minY, maxY}
  , "ShowColumnHeadings" -> True
  ] // TableForm

此SQL代码使用浮点值作为主键。这在SQL中通常是一个有问题的实践,但在当前上下文中工作正常。

在尝试使用任何这些功能之前,您必须调用openCacheConnection []。完成之后,你应该调用closeCacheConnection []。一次只能调用createCache []来初始化SQL数据库。 replaceCachedValue,clearCache和showCache用于手动干预。

翻译自:https://stackoverflow.com/questions/5287817/the-best-way-to-construct-a-function-with-memory

转载注明原文:wolfram-mathematica – 使用内存构建函数的最佳方式