Optimization 在Mathematica中,传递包含大量数据的变量会花费大量内存和时间吗?

Optimization 在Mathematica中,传递包含大量数据的变量会花费大量内存和时间吗?,optimization,wolfram-mathematica,mathematica-8,Optimization,Wolfram Mathematica,Mathematica 8,我正在编写一个基于Ukkonen算法的Mathematica后缀树构造算法 我的问题是,将我的整个树结构(我存储在一个列表中)传递给一个函数进行搜索,会花费我的程序大量的内存和时间,因为我必须在算法中多次使用一些函数吗 例如,我有一个搜索特定节点的子节点的函数,我使用Select函数搜索整个树 getChildren[parentID_] := Select[tree, #[[3]] == parentID &]; 但是我需要访问树,所以将整个树结构传递给函数合理吗?因为似乎没有一种方

我正在编写一个基于Ukkonen算法的Mathematica后缀树构造算法

我的问题是,将我的整个树结构(我存储在一个列表中)传递给一个函数进行搜索,会花费我的程序大量的内存和时间,因为我必须在算法中多次使用一些函数吗

例如,我有一个搜索特定节点的子节点的函数,我使用
Select
函数搜索整个树

getChildren[parentID_] := Select[tree, #[[3]] == parentID &];

但是我需要访问树,所以将整个树结构传递给函数合理吗?因为似乎没有一种方法可以使变量在整个笔记本中成为全局变量。或者有其他方法可以解决这个问题吗?

不,传递表达式不需要额外的内存。在函数式语言中,Mathematica对象通常是:不能修改它们,而是在使用某些函数对它们进行变换时创建一个新对象。这也意味着,如果不转换它们,它们就不会被复制,无论在函数之间传递了多少


从用户的角度来看,Mathematica表达式是树,但我认为它们在内部存储为,即同一子表达式在内存中只能存储一次,而不管它在完整表达式中出现多少次(例如,请参见的文档页)

下面是一个例子来说明:

首先,确保
输入
/
输出
不会占用额外内存:

In[1]:= $HistoryLength = 0;
检查内存使用情况:

In[2]:= MemoryInUse[]
Out[2]= 13421756
让我们创建一个占用大量内存的表达式:

In[3]:= s = f@Range[1000000];

In[4]:= MemoryInUse[]
Out[4]= 17430260
现在把这个表达式重复一百次

In[5]:= t = ConstantArray[s, 100];
。。。请注意,内存使用几乎没有增加:

In[6]:= MemoryInUse[]
Out[6]= 18264676
具有误导性,因为它不报告实际使用的物理内存,但报告如果不允许公共子表达式共享相同内存时将使用的内存:

In[7]:= ByteCount[t]
Out[7]= 400018040
值得注意的一点是:如果从
s
中删除
f[…]
,并将
s
t
都设置为普通的数字数组,那么这种内存共享将不会发生,内存使用量将跃升到~400 MB



无论您将
设置为全局变量还是
getChildren
的参数,都不会影响内存使用。

进一步了解Szabolcs的答案,如果您确实需要修改数据,您可能会发现关于“按引用传递”的问题很有用:


您的意思是“没有办法使变量在整个笔记本中成为全局变量”吗?如果定义
tree=5
,则
tree
Global
上下文中到处都是5(这是默认值)。默认情况下,它是全局的,除非你在追求其他行为。回答得很好!为了进一步确认您描述的图片,可以对
t
中的某个元素进行赋值,例如:
t[[1,1]]=2
,并注意到与单个
s
实例的大小相对应的内存消耗立即增加。您观察数字数组的原因很微妙:这只是因为
Range
生成压缩数组,并且您使用了
ConstantArray
(而不是例如
Table
)。关键是,
ConstantArray
将从压缩数组中生成压缩数组,并且您不能在大型压缩数组中共享内存,因为它是。。。。。。基于直接C的内存布局。您是否应该使用
ur=Developer`FromPackedArray[Range[1000000]];t=ConstantArray[ur,{100}]
r=Range[1000000];t=表[r,{100}],您会看到相同的内存共享,因为结果没有打包(这意味着有中间指针,共享是可能的-或者至少这是我目前对此的描述)。我会稍微将关于不变性的声明更改为:“除非存储在变量中,否则不能修改它们“-Mathematica不是一种纯粹的函数式语言,可变性是可能的。@LeonidShifrin@Szabolcs我的测试表明,在第一个示例中,
ConstantArray
也消耗了相同数量的内存。看看怎么解释?@user15964我看不出有什么问题。在第一种情况下,构建一个压缩数组,并将其包装到
f
中。在第二种情况下,您构建了一个对
f[first array]
的引用的常量数组。也许,指针和整数各占用8个字节,这就是为什么内存使用量增加的大小是相同的。我现在没有时间深入研究了。既然你提到了这个话题,让我提一下,虽然这个问题的公认答案确实有效,但从程序设计的角度来看,我通常建议不要以那种方式使用
未评估的
:应该设计自包含的函数,然而,只有当用户没有忘记在参数周围包装
Unevaluated
时,函数才会工作,而且,对于函数本身,没有办法捕捉到这种遗漏。依我看,在这种情况下,Hold属性比
未评估的属性更可取。@Leonid-我更改了链接以参考您的答案。(无论如何,这是我的第一个意图。)谢谢,但我的回答也不是一般性的建议——这个问题受到CDF的限制,其中明确的Hold属性不能附加到符号上。显然,这里还没有人问过一个简单的问题,比如“在数学中通过引用传递”(或者至少我知道),而对这样一个话题进行讨论似乎是非常可取的。@LeonidShifrin,我想问一下,你是否有一个更新版本的struct/object方法,显示在你的帖子末尾。我喜欢它,并想检查一下,如果你有一个更新的版本,在我写的演示使用。如果没有什么变化,我会的