Mathematica中的树数据结构

如何解决Mathematica中的树数据结构

| 我主要将mathematica用作数学工作台,并用于编写相对较小的即席程序。但是,我正在设计一个打算在Mathematica中编程的系统。我需要将数据存储在树中,然后搜索并遍历树。尽管我知道如何实现树,但是我更喜欢标准的,经过测试的代码。我在Mathematica用户Wiki上查看了用于基本数据结构的哪种软件包。尽管在Mathematica文档中有一个很小的例子,但我没有找到。 现在我的问题是: 是否有某个地方的(开源)数据结构包? 您对数据结构使用了哪种方法?逐渐开发自己的util包? (不是一个问题,只是一句话。也许……缺少(很多可用的)开源软件包是Mathematica缺乏应有的动力的原因。恐怕是鸡/蛋问题。)     

解决方法

在Mathematica中,您所做的大部分工作都是基于表达式。表达式自然具有树结构。对于深度优先遍历(可能是最常见的),您可以使用use0ѭ,
Map
Cases
等函数。与更传统的语言不同的是,没有简单的方法来保留表达式中各个节点的身份树,因为Mathematica中没有指针。同样,当您只需要在几个地方进行修改时,由于Mathematica中惯用的表达式的许多操作都会复制整个表达式,因为表达式是不可变的。 使用不可变的Mathematica表达式作为树仍然具有几个优点。一个是,由于它们是不可变的,因此仅查看它们就很容易理解它们存储的内容(状态和行为没有混合)。另一个是遍历它们的有效且通用的函数,例如
Map
MapIndexed
Scan
。例如,访客设计模式是不可见的-语言中仅内置了
Map[f,tree,Infinity]
。另外,还内置了诸如
Cases
Replace
ReplaceAll
等功能,这些功能使您可以编写非常简洁和声明性的代码来对树进行解构,找到具有某些语法或满足某些条件的树等。仅限于仅由列表构建并且由不同的头构建,因此可以有效地使用它来编写非常简洁的树处理代码。最后,本着探索性和自下而上编程的精神,可以非常轻松地构建所需的任何树结构,从而使执行实验和原型设计变得更加容易,这缩短了开发周期并最终导致更好的设计。 也就是说,您当然可以实现“有状态”(可变)树数据结构。我怀疑,通常还没有完成的真正原因是,与构建,修改和遍历这样的树相关的性能下降,因为它将在每个步骤上进行完整的符号评估过程(有关此内容的更多详细信息,请参阅此帖子)。 )。有关如何在Mathematica上下文中使用二进制搜索树以获取相当有效的代码的2个示例,请参见我的文章(通用符号设置)和此处(在编译代码的上下文中)。对于在Mathematica中惯用地构造数据结构的一般方法,我推荐Roman Maeder的书:“在Mathematica中编程”,“ Mathematica程序员I&II”,尤其是“在Mathematica中进行计算机科学”。在后者中,他详细讨论了如何在Mathematica中实现二进制搜索树。编辑正如@Simon所提到的,@ Daniel Lichtblau的演讲也是一个很好的资源,它显示了如何构建数据结构并使之高效。 关于在Mathematica中实现数据结构并包含某种状态的一般方法,这是从我在此Mathgroup线程中的帖子中提取的一个简单示例-它实现了“对”数据结构。
Unprotect[pair,setFirst,getFirst,setSecond,getSecond,new,delete];
ClearAll[pair,delete];
Module[{first,second},first[_] := {};
  second[_] := {};
  pair /: new[pair[]] := pair[Unique[]];
  pair /: pair[tag_].delete[] := (first[tag] =.; second[tag] =.);
  pair /: pair[tag_].setFirst[value_] := first[tag] = value;
  pair /: pair[tag_].getFirst[] := first[tag];
  pair /: pair[tag_].setSecond[value_] := second[tag] = value;
  pair /: pair[tag_].getSecond[] := second[tag];
  Format[pair[x_Symbol]] := \"pair[\" <> ToString[Hash[x]] <> \"]\";
];
Protect[pair,delete]; 
这是使用方法:
pr = new[pair[]];
pr.setFirst[10];
pr.setSecond[20];
{pr.getFirst[],pr.getSecond[]}

{10,20}
创建一个新的配对对象列表:
pairs = Table[new[pair[]],{10}]

{\"pair[430427975]\",\"pair[430428059]\",\"pair[430428060]\",\"pair[430428057]\",\"pair[430428058]\",\"pair[430428063]\",\"pair[430428064]\",\"pair[430428061]\",\"pair[430428062]\",\"pair[430428051]\"}
设置字段:
Module[{i},For[i = 1,i <= 10,i++,pairs[[i]].setFirst[10*i];
  pairs[[i]].setSecond[20*i];]]
检查字段:
#.getFirst[] & /@ pairs

{10,20,30,40,50,60,70,80,90,100}

#.getSecond[] & /@ pairs

{20,100,120,140,160,180,200} 
我提到的帖子中有更详细的讨论。以这种方式创建的“对象”的一个大问题是没有自动垃圾收集,这可能是在顶级Mathematica本身中实现的OOP扩展没有真正发挥作用的主要原因之一。 Mathematica有几种OOP扩展,例如Roman Maeder的ѭ15软件包(来源在他的“ Mathematica Programmer”书中),ѭ16商业软件包,以及其他几个软件包。但是,直到Mathematica本身提供用于构建可变数据结构的高效机制(也许基于某种指针或引用机制)(如果发生这种情况),与此类数据结构的顶级实现相关的性能可能会遭受重大打击在mma中同样,由于mma是基于不变性的核心思想之一,因此要使可变数据结构与Mathematica编程的其他惯用法很好地吻合并不是一件容易的事。 编辑 这是与上面的示例类似的准系统状态树实现:
Module[{parent,children,value},children[_] := {};
  value[_] := Null;
  node /: new[node[]] := node[Unique[]];
  node /: node[tag_].getChildren[] := children[tag];
  node /: node[tag_].addChild[child_node,index_] := 
        children[tag] = Insert[children[tag],child,index];
  node /: node[tag_].removeChild[index_] := 
        children[tag] = Delete[children[tag],index];
  node /: node[tag_].getChild[index_] := children[tag][[index]];
  node /: node[tag_].getValue[] := value[tag];
  node /: node[tag_].setValue[val_] := value[tag] = val;
];
一些使用示例:
In[68]:= root = new[node[]]

Out[68]= node[$7]

In[69]:= root.addChild[new[node[]],1]

Out[69]= {node[$8]}

In[70]:= root.addChild[new[node[]],2]

Out[70]= {node[$8],node[$9]}

In[71]:= root.getChild[1].addChild[new[node[]],1]

Out[71]= {node[$10]}

In[72]:= root.getChild[1].getChild[1].setValue[10]

Out[72]= 10

In[73]:= root.getChild[1].getChild[1].getValue[]

Out[73]= 10
有关使用此可变树数据结构的一个重要示例,请参阅我的这篇文章。它还通过大量重用Mathematica本机数据结构和函数来面对这种方法,并很好地说明了本文开头所讨论的要点。     ,我主要将mathematica用作数学工作台,并用于编写相对较小的即席程序。 Mathematica在这方面确实很出色。   您对数据结构使用了哪种方法?逐渐开发自己的util包? 我避免在Mathematica中创建自己的数据结构,因为它无法有效地处理它们。具体来说,Mathematica中的一般数据结构往往比其他地方慢10-1,000倍,这极大地限制了它们的实用性。例如,在计算红黑树中的深度范围时,Mathematica比F#慢100倍。 使用列表进行逻辑编程是一个示例,其中Mathematica通常比其他编译语言慢几个数量级。以下Mathematica程序使用链接列表来解决n皇后问题:
safe[{x0_,y0_}][{x1_,y1_}] := 
 x0 != x1 && y0 != y1 && x0 - y0 != x1 - y1 && x0 + y0 != x1 + y1

filter[_,{}] := {}
filter[p_,{h_,t_}] := If[p[h],{h,filter[p,t]},t]]

search[n_,nqs_,qs_,{},a_] := If[nqs == n,a + 1,a]
search[n_,{q_,ps_},a_] := 
 search[n,nqs,qs,ps,search[n,nqs + 1,{q,qs},filter[safe[q],ps],a]]

ps[n_] := 
 Fold[{#2,#1} &,Flatten[Table[{i,j},{i,n},{j,n}],1]]

solve[n_] := search[n,ps[n],0]
这是等效的F#:
let safe (x0,y0) (x1,y1) =
  x0<>x1 && y0<>y1 && x0-y0<>x1-y1 && x0+y0<>x1+y1

let rec filter f = function
  | [] -> []
  | x::xs -> if f x then x::filter f xs else filter f xs

let rec search n nqs qs ps a =
  match ps with
  | [] -> if nqs=n then a+1 else a
  | q::ps ->
      search n (nqs+1) (q::qs) (filter (safe q) ps) a
      |> search n nqs qs ps

let ps n =
  [ for i in 1..n do
      for j in 1..n do
        yield i,j ]

let solve n = search n 0 [] (ps n) 0

solve 8
使用Mathematica解决8皇后问题需要10.5s,而使用F#需要0.07s。因此,在这种情况下,F#比Mathematica快150倍。 Mathematica的“堆栈溢出”问题“链接列表”和性能给出了一个更极端的例子。将该Mathematica代码天真地转换为F#,可以得到一个等效的程序,其运行速度比Mathematica快4,000至200,000倍。
let rand = System.Random()
let xs = List.init 10000 (fun _ -> rand.Next 100)
Array.init 100 (fun _ ->
  let t = System.Diagnostics.Stopwatch.StartNew()
  ignore(List.length xs)
  t.Elapsed.TotalSeconds)
具体来说,Mathematica执行一次迭代需要0.156s至16s,而F#则需要42µs至86µs。 如果我真的想留在Mathematica中,那么我会尽一切努力将Mathematica的少数内置数据结构(例如
Dispatch
。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res