假设我们的缓慢函数具有签名f[x, y]
。
纯内存方法
如果您满意使用内存缓存,则最简单的方法是使用记忆化:
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
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
]
这段 SQL 代码使用浮点值作为主键。在 SQL 中,这通常是一个有问题的做法,但在当前情况下运行良好。
在尝试使用任何这些函数之前,您必须调用 openCacheConnection[]
。完成后应该调用closeCacheConnection[]
。仅需一次,您必须调用createCache[]
来初始化SQL数据库。提供了 replaceCachedValue
、clearCache
和 showCache
以进行手动干预。
{x,y,f[x,y]}
的列表,使用ListContourPlot[pts]
可能比ContourPlot
更值得。 - Brett ChampionListContourPlot
不会继续计算其他值以使绘图更好。我的需求是能够从某个问题点继续计算f[x,y]
失败的ContourPlot
。 - Alexey Popkov