xzcyr xzcyr
关注数: 3 粉丝数: 748 发帖数: 13,947 关注贴吧数: 17
关于NRoots函数的(可能)提速,以及某matlab函数roots的测试请 为了避免一会儿答昏了头又忘了先把这帖发出来。会折腾起这个问题是因为前两天在知乎上看到了一个问题(那个问题现在貌似被删了……)。该问题问的是如何提升NRoots的效率,并声称NRoots函数比某matlab的roots()函数(定义在这里http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fradio.feld.cvut.cz%2Fmatlab%2Ftoolbox%2Fmathlib%2Fcppmathug%2Fmatlab11.html&urlrefer=c718dc5954add794b75faa368c11b46c)效率低一个数量级。 虽然我的电脑上没有装matlab,但我认为这一“声称”还是可信的,因为NRoots是使用多项式(而非列表)作为输入的,那么几乎可以肯定,对符号的分析是会占用时间的。类似的情况我们可以在LinearSolve上看到:在解一次方程组时它的速度大致比Solve快一个数量级。 然后我就在想,NRoots会不会像Solve之于LinearSolve一样,拥有一个抽象的(我的意思是,直接以列表为输入的)对应函数呢?在帮助里找了一下,找不到,想了想就把问题扔SE去了,然后,被踩了……路过的Daniel Lichtblau猜是不是因为我没给出具体的测试结果,我也觉得有可能,于是……有人能帮忙测一下然后截个图什么的吗? 问题在这里:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fq%2F73312%2F1871&urlrefer=2e2bc58f5501205c6d2be4a3e2a39fba 要是能帮我直接编辑进问题里那就更感谢了! 要是能顺便再Upvote一下那就更更感谢了! 直接在这帖下面讨论这个问题也是欢迎的,不过要是能帮忙到那边把问题给答了那就更更更感谢了! 好了,先这样。我继续屠版去了。
我是怎样学起Mathematica来 本文系自此帖(http://tieba.baidu.com/p/2736346260)5楼的回复修订增补而来。吧里的老人们阅读本文时可能会觉得各种眼熟:毕竟重要的经验我都是不断强调的。 我最初会得知Mathematica的存在,是因为《数学建模》老师在课堂上的推荐。我第一眼就被它那极度接近传统数学式书写的使用方法给吸引了——相信这个吧里的许多人也是一样。《数学建模》结课后不久校内就搞了数学建模大赛(目的是为了选拔参加全国大赛的选手),我就参加了,用的当然是Mathematica。 注意这时的时间点是快三年前,也就是2012年的上半年,那个时候具有全中文帮助文档的Mathematica 8已经出世,但是,版本8的体积比之前的版本要大,于是我这个吝啬鬼想了半天最后 错误地选择了版本7,并从图书馆借了一本《Mathematica7实用教程》,觉得这样应该也够用了。 比赛时间是三天,我所属的组在最后一天算是弄出了模型,然后,解不出来。 站在现在看来,这一局面是理所当然的,因为我那时对Mathematica的使用,几乎是胡来,因为Mathematica的代码接近传统数学式,我便 想当然的在Mathematica里写起了传统数学式。我还能记得的在这一时期犯过的错误——实际犯的肯定不止这些——有: 为了获得纯正的传统数学表达,大量依赖TraditionalForm和自由格式输入。 以为在代码的开头写上 a ∈ Integers 就可以使 a 被全局声明为整数。 不会清变量,对语法着色也毫无概念,只好通过反复重开软件来使软件“恢复正常”。 ………… 总而言之,那时的我对 Mathematica其实是一种严谨的编程语言这点可以说是完全没有认识,而那本 万恶的《Mathematica7实用教程》也基本上只是把Mathematica当成一个计算器在介绍,这便进一步封死了我认知自己错误的路。参赛的结果,也就不消我多说了吧。这次失败让我陷入了强烈的沮丧之中,从此一厥不振,Mathematica成为了我心中又一段不堪回首的记忆——要真是这样我现在就不会在这儿了,故事当然还有后续。 这次经历固然让我受到了打击,但也让我感到了不甘心,结果,Mathematica还是留在了我的电脑里没有删掉。不久,我所在的教研室迎来了一个组会日,我那时还没进实验室,手上没什么东西可讲,搜肠刮肚,我忽地想起自己本科毕设时的一个问题可以用Mathematica来解决,就拿这个当材料做PPT了。 注意,这个问题是连当时的我也能自力解决的问题,不消说,它是十分简单的。(实际上就是用Reduce求解整数不定方程。)但是我却忘记了自己当初是怎么被形如Solve[x^3 + 2 x^2 + 3 x + 4 == 0, x]的代码迷得神魂颠倒,不知道这一切在旁人眼里是多么的神奇,没想到自己已经被选为了目标……暑假临近时,导师忽然找到了我,让我帮忙解一个数学模型。我在这个时候才得知,教研室内部不知何时起已经流传起了一个奇怪的传闻,说是我参加建模大赛获奖了囧。 “既然导师信任我,那我就不能辜负人家的期望”——这种假话我当然说不出口,但是我拼命想要快点解完这个模型那是千真万确的,因为,我想回家。毕竟这是我大学以来第一次暑假没家回,虽然理性上清楚这对研究生来说是正常的,但是感性上这就好像一直拥有的权利突然被剥夺了一样浑身难受。我所要求解的模型实际上是一个偏微分方程组,我一看到这个问题自然想起了NDSolve(《实用教程》介绍了这个函数)。“那就赶快把方程塞进这个指令里解出来然后回家!”我第一时间 把电脑里的Mathematica换成了版本8——我在这个时候已经意识到了纸质教程的内容恐怕会不足,而且在回家的诱惑面前硬盘空间当然是浮云——输入方程,Shift+Enter,我得到的是——一大片的警告。 但是此刻我已经不是几个月前的我了!几个月前的失败也就是浪费几天时间,这次可是关乎回不回得了家的大事!……而且,或许是不断的失败使我在潜移默化中有了反省,最终我竟基本冷静了下来。我开始意识到我面临的其实是复数个问题的集合, 贪婪地想要一口气把问题彻底解决是不现实的。于是我开始读着自带帮助和网上看到的各色杂七杂八的资料开始了跌跌撞撞的探索。基本掌握Mathematica的最基础语法并没花掉我很多时间,可是,还是不够……我最终开始在百度知道上提问(这算是Mathematica学习再开后的第一问:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F447269535.html&urlrefer=4efec66f5a57e52c755730b0ed6bf5fd)。 读到这里,或许会有读者对我此时的选择嗤之以鼻或是感觉不理解:一个学术问题,怎么想到跑百度知道上来问了?为什么不问问你的同学和老师呢?比如你的《数学建模》老师?关于这点,一个原因是我的身边没有什么人会Mathematica,而《数学建模》与我甚至不同院,当时还是暑假,我怎么好意思去麻烦别人——好吧,这其实是借口,说白了我就是从小怕老师怕惯了,所以对找老师这事有抵触——不过,现在看来,即使我当时选择这条路,等在我前方的恐怕依旧是死胡同,说句听起来有些不知天高地厚的话:我丝毫不认为在课堂上教我们破解版本4(还是版本3?记不起来了)Mathematica的老师能够给我帮什么忙——当然了,也可能他会因此为我介绍一位新的老师,最终闯出一条新路……遐想就到此为止,历史不容假设,而且我丝毫不后悔我当时的选择。 虽然困难,但我开始将我要求解的问题一点一点的分解开,放到知道上提问,虽然得到的答案并不总是如意,但是还是有收获的,至少我开始对我所面临的问题的难度以及其中重大的难点看得越来越清楚了—— 百度知道并不像某些人想的那么糟糕,还是有人在认真的回答问题的。这里要特别感谢 @tryytr ,尽管他对我所要解的问题并不熟悉,却依旧在这段我最为艰难的时期积极地与我进行了多次探讨。(比如这里:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F452380013.html&urlrefer=e9800c58323aab1db01a1b2ee478212d 和这里:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F455225843.html&urlrefer=b7e6b068687046b7a06b2bd2662a9303 )但是,依旧不够……有的问题不解决我还是回不了家……就在我再度陷入僵局,甚至在漫天飞的“Matlab更擅长数值计算”的 流言影响下装上了Matlab的时候,神( @yang_bigarm )出现了!:(这个提问因为最终含了外链被百度和谐了,所以这里只贴个图。) 得知 Stackexchange的存在(由stackoverflow找到mathematica的分站去并没花掉我多少时间),可以说是我学习Mathematica过程中最重要的 转折点——今天看来,我所要求解的模型中所蕴含的问题,其实是超乎想象的,其中的许多内容至今没有彻底解决。(鉴于其复杂度以及吧里关心偏微分方程问题的人员稀少度,此处按下不表。)但是,mathematica.stackexchange的成员们的实力,同样超乎想象。通过在Stackexchange的提问,我所面临的主要问题均得到了解决。(这是其中最重要的一个:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fq%2F9277%2F1871&urlrefer=cb49ff4e68e2a11a79b0a665418d1039 ,我至今认为这是我在Stackexchange的最有价值的提问。)——而这,依旧是次要的,更重要的是,在我在Stackexchange阅读帖子的过程中, 我对Mathematica的热情再度迸发了出来。 诚然,我在首次接触Mathematica时也曾为之着迷,但那更多的是被它的光鲜一面给吸引,没法长久,而这一次,我是在幻想破灭之后, 被Mathematica真正的强大吸引的。同时,对于一些基本原则的掌握也使我有了进一步学习的资本。(比如 勤查自带帮助这一点——这也是stackexchange的各位强人们在不断强调的。)我再次迎来了一个学习Mathematica的高潮。 我一面 在Stackexchange大量阅读帖子,一面开始在百度知道疯狂答题(之所以那个时候没在Stackexchange答,一来是因为本身实力不济,二来是因为那时候Stackexchange开站不久,原始会员们答题远比现在积极,我根本抓不到机会),那时我的答题近乎饥不择食(话说那段日子里抢了 @yang_bigarm 不少“生意”真是不好意思……) ,甚至连要注册码的问题我也来者不拒(http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F492396412.html&urlrefer=82fc9008bf83e97dae09e607ce261125),现在看来,这种做法无疑造成了一定的 负面影响,那就是这种无差别答题给我造成了巨大的精神压力,以致我在某个时期回答他人问题时的态度很不好(啥,现在也不咋的?……总之比那时候好多了吧。这都是靠着我如今对答题时间的限制),但是,不可否认的是尝试 回答他人的问题确实是一个让自己快速进步的方法。 我在这一时期的进步是非常快的,毫不夸张地说,我每阅读一个Stackexchange的帖子,每回答一个百度知道的问题,我都能切实地感觉到自己比上一刻更懂Mathematica。到了大约十月的时候,我已经打遍百度知道无敌手了(我不否认这和百度知道上的提问总体容易有关,其实在我在知道上开始答题后的很长一段时间里,甚至连Table都不能熟练使用:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F475944231.html&urlrefer=4fedc0aa0e4f13347436644fe195e9b3)。同时百度知道有的时候还是会冒出一些困难得光靠自查帮助解决不了的问题的,这种时候我就会把问题搬到Stackexchange去——我就是靠着这个到手了我在stackexchange的第一个nice question:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F499080092.html&urlrefer=6d164ecb644233c5e9392c8661637db7 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fq%2F15021%2F1871&urlrefer=62029c8278b3e49483380533c9c7a4af 。顺便这一时期我最重要的回答是:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F505315229.html&urlrefer=270afee2707bc9201f907f56ceef926c 。 再往后的事,就波澜不惊了。先是把答题的战场扩张到了贴吧。(我曾因为一些历史原因,犹豫了很长时间是否要进驻贴吧,但是知道上的问题已日益无法满足我的需求,最后,“管他呢!”顺便这大概是吧内第一帖:http://tieba.baidu.com/p/1950670750)然后又开始 阅读Leonid Shifrin写的那本书。(我已经记不起来最初是因为什么才开始读这本书的了,不过,长时间在Stackexchange摸爬滚打,接触到这本书绝对是时间问题。)大概到了年底,也就是正式开始学习Mathematica约半年的时候,我发觉自己的进步速度似乎慢了下来——其实可学的东西还有非常非常多(http://tieba.baidu.com/p/2025917205),但是对软件的学习毕竟受限于自己的知识和兴趣——再往后,我的Mathematica技能的进步进入了一个比较平缓的时期,经常很长时间都没有什么显著的进步,当然,绝不是没有进步,实际上,包括编译、模式匹配在内的许多重要内容我都是在这一时期学会的。(关于模式匹配,必须要感谢 @33珊珊2013 于2013年3月前后在知道的一系列问题的促进作用。) 以上,就是我学习Mathematica的主要过程的一个啰啰嗦嗦的回顾。如今的我虽然不再是个新手,但是和Stackexchange的众神相比还是有着光年级的差距,即使是在吧里,我也绝不是最强的。(不知道全吧打排位赛的话能不能进前十啊……)我在学习过程中走了不少弯路,某些做法也不见得对,不过,若是各位能从这个帖子里吸取到些许经验或教训,我会非常高兴。 凡是在本帖下面仅回复“太长不看”或类似词句者,删。 最后的最后,依旧用从前在 @青衣瓦屋 的帖子下面胡诌的小诗做结吧: 假如StandardForm欺骗了你, 不要悲伤,不要心急! 出错的日子里需要镇静, 相信吧,习惯InputForm的日子将会来临。
【吧务】关于精品帖门槛的放低 嗯……细心的同学可能发现最近一个月吧里精品帖的数量多了起来,很多的老帖突然被加了精。 会产生这个想法的直接的原因是,过去的一个月里的某几天,突然又出现了数位求问诸如“你们的Mathematica是怎么学的的”同学……为什么又有人问?这个我们不是说过很多次么?教程的地址也贴了很多次,为什么没有人看?难道……于是我试着新建了个“教程”的精品分类,然后把@mm_酱 那个翻译Leonid的书的帖子给加了精,结果……这个沉了不知多少年的帖子果然被立刻挖出来了!明明过去我们不管怎么自顶,都会迅速沉掉的! 看样子过去吧里加精的门槛设的太高了,没能活用这个制度,发挥出它的力量。 大家应该也有感觉,那就是百度贴吧的搜索功能越来越渣了,有时候,有的内容,明明过去讨论过,却怎么搜也搜不到。如果是在我自己发的主题里那还好,如果是别人的帖,甚至只是在我自己过去的回复里,那找起来简直就是大海捞针,类似的事我已经做了多次,不想再做了。我相信我绝不是唯一一个这么想的人。 而且连我们自己也搜不到的东西,别人怎么能搜到呢? 如果别人搜不到、答完了就废,那我坚持不加Mathematica相关的QQ和QQ群、一直在公开场合答题的意义又在哪呢? 为什么不把这种需要多次引用的帖子放到精品里呢? 就因为它们中有价值的往往只有某一层楼? 就因为帖子本身没有整理的四平八稳和个论文似的? 就因为问题本身其实很简单,答题者没有很麻烦很累就把问题解决了? 没必要弄这种形式主义。 今后,只要是感觉值得一看的帖子都会考虑加精,不论帖子中实际蕴含的工作量是高还是低,也不论帖子内容是否“整齐”,更不论帖子的可看之处是在主楼还是在回复或是在楼中楼。 我自己能记忆起来的(以及能找到的)帖子毕竟有限,大家看到或想到有意思的帖子时大可以挖上来,我会加精的。 对于这个“政策”有什么意见或建议的话,欢迎回帖讨论。
【讨论】并行到底有多难 嗯……这个问题的复杂度我心里还是有个数的,所以这帖不指望得出答案之类,重在交流讨论。 先说一下我大致的了解吧。因为最近有机会接触到了多核的计算机,所以我也稍微关心了一下。总的感觉是并行似乎真不那么容易,在Stackexchange的未解答率(无人回答或有人答却未被采纳或没有Upvote的问题数比上总问题数)只有35/175.==0.2,这算是相当高了,要知道全站总体未解答率是1325/14474.==0.0915435,一些流行的Tag,比如plot,未解答率只有63./2069==0.0304495。compile在我印象里应该是比较麻烦的,可是一查却发现未解答率才16/149.==0.107383,正好是平均水准。 这175个问题里面得分比较高的问题我也算读了一下,要总结的话,那就是,只有一件事是可以并行的那它才是可以并行的,也就是说,只有当你要做的事是可以互无瓜葛地进行的的时候,Mathematica的并行指令才可以被使用…… 说到这里,有件事大家或许会觉得奇怪,那就是,照这个说法,很多的列表操作似乎都应该是可以并行的,为什么实际上并非如此?对于这一点,我也不是很清楚(那你拿出来说干嘛!),但我怀疑这可能和PackedArray(某个和Mathematica的快速计算有着重要关系的数据结构,Mathematica在版本5.2之后快起来很大程度上就是因为它)本身结构的特殊性有关……具体的……我也不是很清楚。但是看看SE上某些高手对SparseArray内部结构的解析帖,我就强烈地感觉,PackedArray一定没那么容易并行。 此外,就我所做的简单的测试而言,并行提速的效果很有限,并且,很多时候都不能和Compile并用,而单用Compile获得的提速往往大幅高于单用并行所获得的。 在这过程中我甚至考虑了要不要转战别的软件。Julia不知道有没有人知道?一个还在零点几版的以高性能计算为目标的语言,研究了半天之后提了这个问题: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fstackoverflow.com%2Fq%2F23290917%2F1551513&urlrefer=1030516fea4a9ac13de0e6e30f804976 结果至今未见回应……我想我的问题问的应该不那么糟,那么,没人给出具体解答的原因,应该还是因为它不那么容易吧…… 于是我就试着在更一般的层面上探索了一下这个问题,于是看到了这么一篇文章: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fwww.ltesting.net%2Fceshi%2Fceshijishu%2Frjcsgcsrm%2F2013%2F1024%2F206739.html&urlrefer=e24c91b3ea23348c70c35306ca357cd9 七零八落地写了这么多(答了一天题着实有点疲劳),以上就是我所查到的和并行有关的一些信息,欢迎大家交流探讨。
关于Compile内语句的简化 这个讨论某种意义上是这个讨论的后续: http://tieba.baidu.com/p/2574814340?pid=38451621323&cid=#38451621323 啊~上面这个帖子不看也没关系,这帖会给出简化代码。总之,我们来看这么一个含了Compile的函数: ie = 200; ez = ConstantArray[0., {ie + 1}]; hy = ConstantArray[0., {ie}]; (* Notice the following function hasn't been fixed yet *) fdtd1d = Compile[{{steps}}, Module[{ez = ez, hy = hy}, Do[ ez[[2 ;; -2]] += (hy[[2 ;; -1]] - hy[[1 ;; -2]]); ez[[1]] = Sin[n/10]; hy[[1 ;; -1]] += hy[[1 ;; -1]] + (ez[[2 ;; -1]] - ez[[1 ;; -2]]), {n, steps}]; ez]]; fdtd1d[1000] 显然,Compile的内部出现了两条结构很相似的语句,即ez[[2;;ie]]+=…和hy[[1;;ie]]+=…,这里需要指出的是,希望简化的两条语句,虽然在这个示例代码里显得还比较简单,但在实际情况中这两条语句可能会因为系数变得很冗长,此外,同样的语句,在实际情况中会出现多次。(这里是一维情况,所以只有2次,三维会有6次……如果再加上些其他东西会更长……)我们自然会想到,如果我们可以使用一个函数之类的来表示这个结构的话,那是再好不过了。 比如,如果没有编译存在的话,我们可以这么做: ie = 200; ez = ConstantArray[0., {ie + 1}]; hy = ConstantArray[0., {ie}]; Clear[f]; SetAttributes[f, HoldFirst] f[list1_, list2_, end_] := list1[[end ;; -end]] += (list2[[2 ;; -1]] - list2[[1 ;; -2]]); fdtd1d = Function[{steps}, Module[{ez = ez, hy = hy}, Do[f[ez, hy, 2]; ez[[1]] = Sin[n/10.]; f[hy, ez, 1], {n, steps}]; ez]]; sol=fdtd1d[120];//AbsoluteTiming ListPlot@sol (*{0.009, Null}*)但是这招在Compile里面用不了,不,确切地说是,能用,但是比不Compile的版本慢的多,因为它多次调用了外部函数,也就是说多次使用了MainEvaluate,导致代码变慢了……: ie = 200; ez = ConstantArray[0., {ie + 1}]; hy = ConstantArray[0., {ie}]; Clear[f]; SetAttributes[f, HoldFirst] f[list1_, list2_, end_] := list1[[end ;; -end]] += (list2[[2 ;; -1]] - list2[[1 ;; -2]]); fdtd1d = Compile[{{steps}}, Module[{ez = ez, hy = hy}, Do[f[ez, hy, 2]; ez[[1]] = Sin[n/10.]; f[hy, ez, 1], {n, steps}]; ez]]; sol = fdtd1d[120]; // AbsoluteTiming (* {0.0710000, Null} *) 然后大家当然会想到Stackexchange上有没有解法。能直接找到的是这帖: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fq%2F24595%2F1871&urlrefer=d5f5cdae824cc58710b9ecacf13c890f 目前有4个答案,两个比较短的要不没有用要不用不了(我指的是Szabolcs的解法,只支持纯函数),两个长的今晚读不完了,只稍微试了下被采纳的那个,没成功,恐怕至少是不能简单地运用。不过要是我只看到了这个帖子,大概早就被打击的放弃了, 真正激励我开这帖的其实是Ruebenko的这个答案: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fa%2F23885%2F1871&urlrefer=18977257660d798b2e5e876baea17a73 他在里面展示了这样的一个技巧: tmp = Join[ {{1, 1, 1}}, Transpose[Quiet[Array[Part[var, ##] &, {3, 2}]]]];me = {{0, 0}, {1, 0}, {0, 1}};p = Inverse[tmp].me;help = Transpose[ (p.Transpose[p])*Abs[Det[tmp]]/2];diffusion2D = With[{code = help}, Compile[{{coords, _Real, 2}, {incidents, _Integer, 1}}, Block[{var}, var = coords[[incidents]]; code ] , RuntimeAttributes -> Listable (*,CompilationTarget->"C"*)]]; 简单地说就是利用With把外部的代码给引到Compile里面了,并且这是可以通过编译的!那么,我就在想,是不是可以把这个方法推广出去呢?推广到我上面所说的情况里去? 或者还有其他什么精妙的方法? 总之,有人有主意吗?
【征集】学习Mathematica时最常见的问题暨Mathematica吧“十戒” 贴吧新弄了个贴条,贴条只能同时存在10个并且只能实际只能显示26字,于是我就在想着是不是该总结些Mathematica新手最常见的问题贴到那上面滚动播出(虽然很多人或许不会看,但有总比没有好嘛……)。试着弄了个草稿(二十戒),大家可以看看,哪些需要修改,哪些需要删节或补充: 二十戒 1 不要为了节约硬盘选择过老的版本。至少要用版本7 2  自带帮助是最好的教材,提问前先打开软件按下F1仔细查查 3 将光标停在不认识的函数前/中/后再按F1即可调出相应帮助 4 看不懂英文的就老老实实装个中文版 5 Mathematica区分大小写,内置函数均以大写字母开头 6 Mathematica用的全是英文标点,别错成了中文标点 7 按下F2可以补全函数名,包括你自定义的函数 8 要避免使用内置函数做变量名 9 没赋值的变量是蓝色的,注意这点能有效避免低级错误 10 赋过值的变量会变黑,注意这点能有效避免低级错误 11 内置函数全是黑色的,注意这点能有效避免低级错误 12 Mathematica中有四种括号,分工明确,功能全不同 13 含有类似“求一段代码”的内容的帖子,通删 14 如果希望问题被尽快解决,帖子中就别出现“大神”字样 15 求助时不要光截张图,把你的代码文本也复制上来 16 “代码文本”指的是你用键盘敲进软件里的那些东西 17 复制代码前先按Ctrl+Shift+I再复制,可以避免代码变乱 18 赋过值的变量如果不清除或用别的值覆盖,它就一直在那儿 19 要分清“ = ”和“ == ”的区别 20 用Show可以将多幅图合而为一 哦,顶部的贴条大家当然是可以随便去贴的,贴条这东西说到底也还没定形,说不定将来还会取消,这个说到底算是我的个人行为——当然要是有人能来一起贴“十戒”的话我会很开心。
【讨论】像Mathematica一般给人以“惊艳”感觉的软件 犹豫了有一阵要不要开这么个主题不明确而且有跑题嫌疑的帖。学Mathematica也一年半了,我差不多——不对,是已经进入瓶颈期(即技能无明确进步)很长时间了。嗯……怎么说呢,虽然我喜欢喊“Mathematica是万能的”,但是这个世上自然是没什么万能的东西。Mathematica可以画图,但是,至少是不适合,画图纸;可以解相当多的偏微分方程,但是(至少目前)不能很好地求解复杂区域上的偏微分方程;大规模低级运算的速度虽然可以用编译提速,但是却会大幅限制编程的思路…… 总之,我在考虑着是不是该把“深度”放一放,试着扩展一下“广度”,也就是,我在琢磨着是不是该学点别的软件了。 可是,曾经沧海难为水…… 在Mathematica之前也接触过一些软件(科学软件?工程软件?科研软件?……唉,总之会出没在这个贴吧里的人应该明白我在指啥),最后都没学会。Origin用过,用着很痛苦,扔了——当然如今它的功能也完全被Mathematica取代了;听说ProE有用,三天打鱼两天晒网地对着本教材学过一段时间,很痛苦,终于没学下去,扔了;学习有限元时接触过Ansys,很痛苦,没学会,扔了……当然如今想起来,这些软件会没学会,“学的时候缺乏目的性”也算原因之一,但是另一个重要的理由是,这些软件……全都散发着一种让人不爽的感觉啊! ——我知道这个理由太模糊了,我也没法很具体地表达。或许是因为它们没有中文的界面?或许是因为它们没有详细而易懂的参考资料?或许是它们没有那种立竿见影的强大?或许只是因为它们体积太大?或许是没有那种优雅的感觉?总之,它们都没有让我产生那种“啊~真的好神奇啊我要学会它”的感觉。 所以最终还是决定开这么个帖子,讨论一下,确切地说,是普查一下,看看各位有没有遇到过这样的软件……或许可以这么问,诸位有没有遇到过堪称××界的Mathematica的软件?
【交流】从粗略的经验规则无法预知的编译的某些具体限制及非限制 编译是个麻烦的东西。但是有时候为了速度就必须得用。虽然我想之前关注过吧里的编译帖的人都对编译的限制有了一些粗略的知识,比如写的越像低级语言越方便编译(虽然也不总是如此),比如SE上的某个可编译函数单啊:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fquestions%2F1096%2Flist-of-compilable-functions&urlrefer=715ac47a4b4ecbebf6aa3f4c38de3a3a (虽然可以用在Compile里的函数其实并不限于此,比如Sow),还有SE上的另外一个关于编译的指导帖啊(http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fmathematica.stackexchange.com%2Fquestions%2F1096%2Flist-of-compilable-functions&urlrefer=715ac47a4b4ecbebf6aa3f4c38de3a3a),可是其实使用Compile时要注意的并不止这些,比如这两天我发现的一个。 我们知道Part结合Span(;;)可以对列表的某一部分进行取出。而当Span取出的片段的尾巴是原列表的该行(列?)的最后一个元素时,存在几种不同的表达方法: a = Range[5]; a[[2;;5]](*最规矩的写法,直接写最后一个元素的序号*) a[[2;;-1]](*使用倒序号,对于某些列表操作还是有利于减轻思维负担的*) a[[2;;]](*省略最后一个参数,这个最省字数*) a[[2;;All]](*最后一个参数用All表示,帮助里没有直接给出,但是只要按下Ctrl+Shift+I检查a[[2;;]]的InputForm,就会发现a[[2;;]]的本质就是这个*) 这四种写法,只有头两种是可以通过编译的。 顺便一提,省略Span的第一个参数(也就是a[[;;3]]之类的)不会对编译造成影响,如果把All单用(a[[All]])也就是取下一整行(列?)也不会造成影响(这点也是个亮点,因为All,虽然只是个选项,但是,也是没有出现在上面的那个单子里的),只有Span和All凑一起的时候编译才会失败。 好了,其实标题说要交流编译什么的那都是幌子,我只是发现了这个问题所以想拿出来说说而已(拖),不过如果大家有相似的发现不妨也拿出来谈谈。
怎样才是最“优”的为列表分段赋值的方法? 已知两个长为n的一维列表a和b。如果我们要生成一个列表c,而这个列表c的每个元素的值都为列表a和b的对应位置元素的乘积的话,显然,最“优”的方法应该是: c = a b; 但是,如果这个c列表是个分段的表的话,情况会是怎样呢?举例而言,如果这个c的中间的1/2元素都是0(其他的元素依旧满足前面的规律)的话…… 首先这两个,我想大家凭感觉就能知道它们速度不行: n = 10000000; a = RandomReal[{0, 1}, {n}]; b = RandomReal[{0, 1}, {n}]; c1 = Table[If[n/4 <= i <= 3 n/4, 0., a[[i]] b[[i]]], {i, n}]; c2 = Table[a[[i]] b[[i]], {i, n}]; c2[[n/4 + 1 ;; 3 n/4]] = ConstantArray[0., {n/2}]; 然后是这两个,它们的速度是不相上下的(c4的初始化没有计入时间,理由下面会说明): AbsoluteTiming[c3 = a b; c3[[n/4 + 1 ;; 3 n/4]] = ConstantArray[0., {n/2}];] c4 = ConstantArray[0., {n}]; AbsoluteTiming[c4[[1 ;; n/4]] = a[[;; n/4]] b[[;; n/4]]; c4[[3 n/4 + 1 ;; All]] = a[[3 n/4 + 1 ;;]] b[[3 n/4 + 1 ;;]];] 单就这里举的例子来说,c3应该是最优解(速度基本上是最快的,代码也比较简洁),但是,实际情况并没有这么简单。这个问题其实又是从有限差分的讨论中抽象而来的(相关帖:http://tieba.baidu.com/p/2574814340)——所以上面c4的初始化没有计入时间,因为被计时的部分其实会重算多次,所以这部分时间是微不足道的——那一帖的7楼,给出了一段小孔衍射的代码,因为求解区域是不规则的,所以最终赋值分成了三块,显然,用我们前面所说的c3思路,代码能简化一些(需要分块赋值的区域将减至两块): iter = Compile[{{tf, _Real}}, Module[{n = 64, Courant = 1./Sqrt[2], c = 1., dx, dt, z1 = ConstantArray[0., {64, 64}], z2 = ConstantArray[0., {64, 64}], lst = {{31, 33, 2, 28}, {31, 33, 36, 63}}, i1, i2, j1, j2}, dx = 1.0/(n - 1.); dt = (Courant dx)/c; Do[ (*先不管有没有墙,把整个区域算了 *) z2[[2 ;; -2, 2 ;; -2]] = Courant^2 (z1[[1 ;; -3, 2 ;; -2]] + z1[[3 ;; -1, 2 ;; -2]] + z1[[2 ;; -2, 1 ;; -3]] + z1[[2 ;; -2, 3 ;; -1]] - 4 z1[[2 ;; -2, 2 ;; -2]]) + 2 z1[[2 ;; -2, 2 ;; -2]] - z2[[2 ;; -2, 2 ;; -2]]; (* 再把有墙的部分(算是比较狭小了)给归0 *) Do[{j1, j2, i1, i2} = i; z2[[i1 ;; i2, j1 ;; j2]] = 0., {i, lst}]; {z1, z2} = {z2, z1}; z1[[32, 16]] = Sin[16. \[Pi] (t + dt)], {t, 0., tf - dt, dt}]; z1]]; 但是,这里可以遗憾地告诉各位,这个代码,没有分三块的版本快……理由可能是每个点上的计算比较复杂,所以那些最终会被“墙”掉的部分的计算,消耗了大量的时间。 并且,在列表的维度增加时,最“优”解甚至有可能会是c1或者c2,因为这两个思路,虽然慢,但是书写非常简单…… 写到这里我终于明确意识到我想陈述的问题有点复杂,想要用比较少的字数陈述清楚比较困难,实际上我也已经被上面的c1, c2, c3, c4折磨得够呛,不想再对它们哪个最优这点讨论下去了。其实我想知道的,只有一件事: 存不存在一种思路c5,使它同时具备c1的语法简洁性和c4的速度?
时域有限差分(FDTD)的Matlab代码(唉呀其实就是个循环)的优化 事情的起因是看到了这个帖子: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fforums.wolfram.com%2Fstudent-support%2Ftopics%2F23872&urlrefer=91316415bc512a6d5568ba0bb10de4b8 这段Matlab代码要移植进Mathematica还是很容易的。以下是我做的移植(做了极简单的优化): Clear["`*"] c = 2.99792458 10^8;(*% speed of light*) mu = 4.0*Pi*1.0 10^-7;(*% free space def*) eps = 1.0/(c*c*mu); freq = 10^8;(*% frequency*) ie = 100;(*% grids*) je = 100; steps = 200;(*% number of time steps to simulate*) lambda = 1/freq; dx = lambda/20; dy = lambda/20; dt = 1/(c*Sqrt[1/dx^2 + 1/dy^2]); (*% updating coefficients*) c1 = dt/(eps*dx); c2 = dt/(mu*dx); (*% setup arrays*) ez = hx = hy = ConstantArray[0., {ie + 1, je + 1}]; (*% fdtd algorithm*) (*Compile[{{steps,_Integer}},*)Do[ ez[[2 ;; ie, 2 ;; je]] = ez[[2 ;; ie, 2 ;; je]] + c1*(hx[[2 ;; ie, 1 ;; je - 1]] - hx[[2 ;; ie, 2 ;; je]] + hy[[2 ;; ie, 2 ;; je]] - hy[[1 ;; ie - 1, 2 ;; je]]); (*% source*) ez[[ie/2, je/2]] = -E^(-0.01` (-40.` + n)^2) + E^(-0.01` (-20.` + n)^2); hx[[2 ;; ie, 1 ;; je]] = hx[[2 ;; ie, 1 ;; je]] + c2*(ez[[2 ;; ie, 1 ;; je]] - ez[[2 ;; ie, 2 ;; je + 1]]); hy[[1 ;; ie, 2 ;; je]] = hy[[1 ;; ie, 2 ;; je]] + c2*(ez[[2 ;; ie + 1, 2 ;; je]] - ez[[1 ;; ie, 2 ;; je]]); , {n, steps}](*,CompilationTarget->"C",RuntimeOptions->"Speed"][steps]*)// AbsoluteTiming; (*% plot ez at last step*) ListPlot3D[ez, PlotRange -> All] ListPlot3D[hx, PlotRange -> All] ListPlot3D[hy, PlotRange -> All] 现在的问题是,这个代码比原始代码——因为是借别人的机子测试的,所以不算准确的比较,但是——慢 约5倍。 编译,至少是直接的编译,对速度没什么提高——咬咬牙装了个C编译器速度居然还变慢了……不知诸位有什么高招没?
把一个函数拆开Compile几次生成的函数会比一次性生成的函数快? 这是答这个问题的时候发觉的: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F557717614.html%3Ffr%3Duc_push%26push%3Dkeyword%26oldq%3D1%23answer-1401951926&urlrefer=5e49dd3cb0ebea35de9534c3fcbb0c13 以下是修正那帖楼主的问题代码后得到的代码: m = 0.8; w = \[Pi]; i = 5.6; vma1 = Compile[{{t, _Real}}, m Sin[w t]]; vmb1 = Compile[{{t, _Real}}, m Sin[w t - (2 \[Pi])/3]]; vmc1 = Compile[{{t, _Real}}, m Sin[w t + (2 \[Pi])/3]]; ia = Compile[{{t, _Real}, {\[Theta], _Real}}, i Sin[w t - \[Theta]]]; ib = Compile[{{t, _Real}, {\[Theta], _Real}}, i Sin[w t - (2 \[Pi])/3 - \[Theta]]]; ic = Compile[{{t, _Real}, {\[Theta], _Real}}, i Sin[w t + (2 \[Pi])/3 - \[Theta]]]; inavg = Compile[{{v0, _Real}, {t, _Real}, {q, _Real}}, -(Sign[ vma1[t] + v0] (vma1[t] + v0) ia[t, q] + Sign[vmb1[t] + v0] (vmb1[t] + v0) ib[t, q] + Sign[vmc1[t] + v0] (vmc1[t] + v0) ic[t, q])]; newinavg[v0_?NumericQ, t_?NumericQ, q_?NumericQ] := inavg[v0, t, q]; vc10 = 280;vc1[v0_?NumericQ, q_?NumericQ] := vc10 + (1/(2/4700.^6)) NIntegrate[newinavg[v0, t, q], {t, 0, 0.3}, Method -> {Automatic, "SymbolicProcessing" -> False}]; Plot3D[vc1[v0, \[Theta]], {v0, -0.2, 0.2}, {\[Theta], -Pi, Pi}] // AbsoluteTiming 这段代码重复Compile了很多次。直觉上这似乎不利于提速,于是我弄了个精简版: m = 0.8; w = Pi; i = 5.6; inavg = Compile[{v0, t, \[Theta]}, -(Sign[ m*Sin[w*t] + v0]*( m*Sin[w*t] + v0)*i* Sin[w*t - \[Theta]] + Sign[m*Sin[w*t - (2*Pi)/3] + v0]*(m*Sin[w*t - (2*Pi)/3] + v0)*i* Sin[w*t - (2*Pi)/3 - \[Theta]] + Sign[m*Sin[w*t + (2*Pi)/3] + v0]*(m*Sin[w*t + (2*Pi)/3] + v0)*i* Sin[w*t + (2*Pi)/3 - \[Theta]])]; newinavg[v0_?NumericQ, t_?NumericQ, \[Theta]_?NumericQ] := inavg[v0, t, \[Theta]]; vc10 = 280; vc1[(v0_)?NumericQ, (\[Theta]_)?NumericQ] := vc10 + (1/(2/4700.^6))* NIntegrate[newinavg[v0, t, \[Theta]], {t, 0, 0.3}, Method -> {Automatic, "SymbolicProcessing" -> False}]; AbsoluteTiming[ Plot3D[vc1[v0, \[Theta]], {v0, -0.2, 0.2}, {\[Theta], -Pi, Pi}]] 可是,反复执行对比的结果是,下面的精简版始终会比上面的慢5s左右,这是怎么回事?难不成是拆得越碎速度越快?
【交流】怎么让贴到吧里的代码不是一团乱麻 这里针对Mathematica代码直接贴入贴吧时经常变乱这一问题做了一点点总结和探索,还很不完备,欢迎大家补充。 现在已知的有 1 代码中不要出现,凡是出现了的,全部使用[a]之类的东西代替,总之不能在两个中括号之间用b。 可能的 原因: 百度贴吧的字体加粗的后台语法(这词我生造的,因为不知道该怎么叫……)似乎遵循的是UBB代码的语法,也就是说,当一段文字的头部出现 英文左中括号+b+英文右中括号 时,其后的文字将被加粗,后面没字时这三个字符则会被直接吞掉。(不信的可以现在就试试。) 未解明部分: (1) 没有加粗权限时系统会如何处理? (2) 红字按理来说也有相应的代码,它的代码是什么?(不过,考虑到至今没人碰到,一定比较复杂……) 2 复制代码时,要选择右键菜单中的“复制”,或是直接使用快捷键Ctrl+C。不要使用“复制为”下面的选项。 绝对不要选择“复制为 -> 单元表达式 / 笔记本表达式”。 顺便不听话的下场就是这样:3 在代码中所有换行的地方,预先多回车一次,也就是预留一个空行。(一个 简便方法是,如果手上有 EmEditor 之类的文本编辑器的话,可以先把代码贴进去,然后Ctrl+H,勾选“使用转义符,然后将 \n 替换为 \n\n 。) 理由:贴吧在贴入文本时会自动吃掉一个换行符,但是它疑似只吃一个…… 未解明部分:我尝试找到一个Mathematica原生的方法来解决这个问题。(StringReplace之类),但是问题比我想的要复杂得多,我没能成功…… 目前发现的就这些,请大家补充。
这个例子里的赋值过程就这么慢? 一点偶然的机会,我对Monitor产生了兴趣,于是开始翻看帮助。 我看到了这么个例子: Monitor[NDSolve[{D[u[t, x], t, t] == D[u[t, x], x, x] + Sin[u[t, x]], u[0, x] == E^(-x^2), Derivative[1, 0][u][0, x] == 0, u[t, -10] == u[t, 10]}, u, {t, 0, 10}, {x, -10, 10}, StepMonitor :> (sol = u[t, x]; time = t)], Plot[sol, {x, -10, 10}, PlotRange -> {0, 8}, PlotLabel -> time]] 虽然帮助对Monitor里面的变量局部化的关系说的不是很清楚,但是对照上下文(具体来说,就是紧接着的下面一个例子),我产生了一个疑问:上面这个例子的StepMonitor里的赋值过程不是多余的吗?改成这样不就行了吗? Monitor[NDSolve[{D[u[t, x], t, t] == D[u[t, x], x, x] + Sin[u[t, x]], u[0, x] == E^(-x^2), Derivative[1, 0][u][0, x] == 0, u[t, -10] == u[t, 10]}, u, {t, 0, 10}, {x, -10, 10}], Plot[u[t, x], {x, -10, 10}, PlotRange -> {0, 8}, PlotLabel -> t]] 但是实际运行,不行…… 又仔细研究了一下帮助,发现下面一个例子,是在StepMonitor里加了个Pause,于是我模仿着也加了一个: Monitor[NDSolve[{D[u[t, x], t, t] == D[u[t, x], x, x] + Sin[u[t, x]], u[0, x] == E^(-x^2), Derivative[1, 0][u][0, x] == 0, u[t, -10] == u[t, 10]}, u, t, 0, 10}, {x, -10, 10}, StepMonitor :> Pause[0.5]], Plot[u[t, x], {x, -10, 10}, PlotRange -> {0, 8}, PlotLabel -> t]] 这下可以了——等一下,第一段代码和第二段代码的区别,也就是有没有重新赋值而已,这个过程就这么慢?!事实上,我拿紧接着的下一个例子也试了试,重新赋值就没能弄出这么夸张的延迟: data = {{0.18, -0.13}, {0.84, -0.06}, {0.05, 0.88}, {0.24, -0.63}, {0.67, 0.93}, {0.05, 0.88}, {0.65, 0.92}, {0.01, 0.99}, {0.17, -0.04}, {0.23, -0.55}};lp = ListPlot[data, PlotRange -> All]; model[{a_, k_, w_, p_}][x_] = a Exp[-k x] Sin[w x + p]; Module[{vars = {a, k, w, p}}, Monitor[FindFit[data, model[vars][x], vars, x, StepMonitor :> (mm = model[vars][x])], Show[Plot[mm, {x, 0, 1}, PlotRange -> {-2, 2}], lp]]] 这算啥?总不会是在StepMonitor里玩赋值会拖慢整个计算的速度吧?有人知道是怎么回事吗?
Mma专攻团百度知道邀请赛 Mathematica贴吧如今有了秩序,很好很好——百度知道那边的“生意”也因此比以前淡了不少。于是,为了增加我的团队的生意,满足我那可悲的虚荣心,早日赚取到足以换取鼠标垫的角的财富值……好吧,其实主要是突然来了劲,觉得一大堆未处理问题挂在那里看着难受,所以决定把我过去曾在百度知道上问过但没人答的mathematica问题列出,欢迎诸位加入了和没加入Mma专攻团的同志们回答。 以下问题,有许多如今我都心里有谱了,但是,百度知道是没有自答系统的……: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F416377318.html%3Fquesup2&urlrefer=b46f54a9bbca052d53181cc96f97724e http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F455225843.html%3Fquesup2&urlrefer=03159e37ea5d8e720727fb1c7bb166fb http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F455608202.html%3Fquesup2&urlrefer=4c3c1f59cb2e39e10a89330e25579f03 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F455615000.html%3Fquesup2&urlrefer=e012dcfa1a2cea861b80179b85713566 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F455642304.html%3Fquesup2&urlrefer=5479d88d4e6585fda0ad7fd2ce724981 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F456451260.html%3Fquesup2&urlrefer=6812bc1646d607c6e784ac5b84967512 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F456955649.html%3Fquesup2&urlrefer=253a523c971283d519de4acae03c6306 http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fzhidao.baidu.com%2Fquestion%2F475336933.html%3Fquesup2&urlrefer=177d720a09689fab71de8742e5d8e07c
首页 1 2 3 4 下一页