MATLAB 程序的变量命名问题

题目已经告诉了读者老爷您这篇文章是和 MATLAB (以下昵称为M酱)有关的。我们先看一个程序:

clear;tic;
a=0;b=1;
for i=1:10000000
    a=a+b;
end
toc;

M 酱告诉我,她要用 0.061435 秒就干完了这件事。

我换了个活给她,尽管看起来差不多

clear;tic;
a=0;asin=1;
for i=1:10000000
    a=a+asin;
end
toc;

M酱跑过来说,她这次用了 5.069864 才干完了这件事。嗯?这是怎么回事?这次是什么事情这么花时间?我掀开了她的裙子看看她的胖次(profiler)上有没有什么线索,不过胖次上也什么都没写。

区别在哪呢?我调动了我高达⑨的智商,仔细推理后得出结论,卧槽原来这两个程序有一个变量名不同啊。再一看卧槽第二个程序居然某个变量名占用了函数名啊。M 酱这时露出了一脸虽然不大懂但是主人果然好厉害的表情。

嗯这篇文章有营养的部分到此就结束了,结论就是,变量占用函数名在 MATLAB 中是会降低执行效率的。如果你的程序没有我这样的上千万次循环自然关系不大,不过还是注意以下为好。

以下是一个小实验:

clear;tic;
a=0;
for i=1:10000000
    a=a+asin(1);
end
toc;

M酱表示这个程序只需要 0.141043 秒就能完成。看来每次执行的时候让她纠结这个到底是变量还是函数比让她算个 asin 函数还要让她苦恼呢。

还有一个:

clear;tic;
a=0;asin=1;
for i=1:10000000
    a=a+asin(1);
    a=a+1;
end
toc;

需要 11.022203 秒,比前面那个时间还要长一倍。也就是说循环间夹了其他不涉及到函数名变量的语句也是会进一步降低执行效率的。

在这里肏一下某位得了直肠癌的老不死他妈,刚才写了一个小时的文章忘了在发布的时候切到自动模式了,然后被 reset 搞没了(不知道到底是发布中的哪一部触发了,wordpress 的自动保存也只有最前面一段)。活该这为虎作伥的老不死肚子上开个口淌屎。

另外在大半夜把一个程序拟人化的我还真是有够可悲的啊……

Answer Set Programming 程序设计

不知道访问这个Blog的人里有多少写过程序,只要是写过的,想必一定知道,想要让计算机给你解题,首先你必须自己知道这题怎么解,这似乎是一件理所当然的事情。学校里的老师想必也一定也说过“程序=算法+数据结构”这个经典的等式。不过今天我们从以前的窠臼中跳出来,来质问一下那件理所当然的事情:凭什么我让计算机解题前我还非得要自己会才行?理想状况应该是我告诉电脑我需要解的问题,之后就让计算机去解好了。这种事情可不可能呢?事实上,虽然还有着各种各样的限制,但是逻辑程序设计已经为我们在一定程度上实现了这个理想,这次我会介绍逻辑程序设计里其中的一个分支Answer Set Programming(ASP)。这里我不准备涉及关于理论方面的知识,一切以实际应用为主,因为我觉得大部分时候应用时牵扯到的语法和语义都是很好理解的。当然如果你能够有一些关于命题逻辑一阶逻辑的知识的话那就再好不过了。

在正式的介绍ASP的各种规则之前,我们先来看一个简单的例子:现在有乌鲁木齐,北京,合肥,秦皇岛4个城市,我们现在要坐火车在这4个城市之间穿梭,已知除了秦皇岛以外,其他三个城市之间都有直达的火车,而秦皇岛只有到北京的直达火车,那么从合肥出发,我都能到达哪些城市呢?一个典型的ASP程序会像下面这样:

road(urumqi, beijing).
road(hefei, beijing).
road(urumqi, hefei).
road(beijing, qinhuangdao).

road(X, Y) :- road(Y, X).
route(X, Y) :- road(X, Y).
route(X, Y) :- route(X, Z), route(Z, Y).

arrive(X) :- route(hefei, X).

#hide.
#show arrive/1.

在这里,符号':-'代表如果,符号','代表并且。现在,如果我什么也不说,你能猜出这个程序里每一行的意思么?这并不困难,显然前4行代表了一些事实,它告诉我们哪些城市之间有道路相连,6-10行则是一些规则,其中第六行告诉我们,如果城市Y和X间有道路,则X和Y之间也有道路。第七行则告诉我们,如果X和Y之间有道路,那么X和Y就有一条通路,同理第八行告诉我们,如果X和Z有通路,Z和Y有通路,那么X和Y之间同样也有通路。第十行则告诉我们,如果合肥与X有通路,那么X就是从合肥可达的。最后两行我们可以先忽略,那是用于格式化输出结果的,和程序本身没有太大的关联了。

最后,如果你有兴趣,可以去下载gringoclasp两样东西,将以上文件保存为road之后我们就可以在命令行下执行

gringo road | clasp 0

来得到如下的结果了:

Answer: 1
arrive(hefei) arrive(qinhuangdao)
arrive(beijing) arrive(urumqi)

那么现在让我们稍微扩展一下,假设北京和秦皇岛之间有列车发生了轻度追尾事故导致无法再通行(当然是没有人员伤亡了,至于你信不信,反正我是信了),那么我们有必要对上面那个程序做出一个修改,首先我们应该添加一个事实规则:

block(beijing,qinhuangdao).

同时也需要修改第7行的规则为:

route(X,Y) :- road(X,Y), not block(X,Y).

这个规则表示X和Y之间有一个通路如果X和Y之间有个道路并且这个道路没有被阻断[注]。之后再次执行这个修改过的程序,我们就会发现秦皇岛不再是可达的了。

从上面的例子我们可以看出,一个ASP程序包括两样重要的部分:事实,用于描述现实世界的状态。还有规则,用于进行推理,并且他们都由英文句号'.'结尾。而规则又分为在符号':-'左边的结论和右边的条件。结论成立,如果右边的条件被满足。另外事实也可以看做是省略了符号':-'和右边所有条件的规则。更细分一点,每一个ASP程序里还包括了一些常量(在这里就是城市名),谓词(这里的road,arrive什么的),每个谓词有若干个参数,并且为了简化起见,我们把带有n个参数的谓词p写作p/n。最后当然还有变量(在这里就是大写字母X和Y),需要注意的是本质上ASP程序是不支持变量的,这里的变量仅仅是为了方便书写,在实际的求解中这些变量会被替换为程序中出现的所有常量,这也是我们为什么需要先运行gringo程序的原因,它的作用就是将程序里所有变量挨个替换成程序里出现的所有常量,你可以用:

gringo --text road

来看看程序被替换后的样子。

现在让我们来定义一下ASP程序里各种规则的样子,有了这些,我们就可以用它来解决问题了。

1. 约束规则

所有在符号':-'左边什么都没有的规则就是约束规则,它表示右边的条件不能同时被全部满足。

2. 选择规则

所有在符号':-'左边形如 \(\{a_1,a_2,...,a_m\}\) 的规则就是选择规则,其含义是如果右边条件成立,那么左边的任意一个子集也成立。

下面我们来考虑一下对于选择规则的扩展,首先我们不限制\(\{a_1,a_2,...,a_m\}\)这样的元素只能出现在规则左边,而是也可以出现在规则右边。其次,任意子集的说法也未免太简单了,我们给它加上个数限制,像\(l \{a_1,a_2,...,a_m\} u\),这个元素表明花括号中的m个元素最少有l个最多有u个成立。所以形如

a :- 2 {b, c, d, e} 3.

这样的式子就表明如果b, c, d, e中最少有两个最多有三个元素成立,那么a也成立。当然,这里的l或者u并非必须同时出现,只写一个也是可以的,含义也很好理解。

3. 条件元素

数学里大家想必遇见过诸如 \(\{a\; |\; a\in A\}\) 这样的东西,它表示了所有满足 a 属于 A 的元素 a 的集合,这里我们也有类似的东西。比如说顶点着色问题,假设我们有诸如 vertex_color(X, Y) 这样的元素,我们想让它代表顶点X被染了颜色Y,并以此得到某一顶点v1所有的染色可能性。但是我们之前也说了,gringo会将程序里的所有变量拿所有常量替换一遍,这样Y不仅会被拿颜色替换,同时也会被拿顶点替换,这显然不是我们想要的,这时我们就需要条件元素了:

vertex_color(v1, Y):color(Y) :- vertex(v1).

看到了么?只需要用冒号':'就可以将变量Y限定在颜色的范围内,这样我们得到的就是顶点v1所有的着色可能了。需要说明的是条件并非只能加一个,如果你有多个变量需要做限制的话,可以将冒号一直连下去。

那么冗长无聊的语法介绍就先到此为止吧,我们来用一个例子来介绍如何来撰写一个ASP程序。我们所用的例子就是著名的八皇后问题,如何在8*8的国际象棋棋盘上摆放8个皇后而使他们无法相互攻击。

首先是事实,我们的棋盘有8行8列:

row(1..8).
col(1..8).

这里我们用1..8来代表从1到8的简写,这样的式子会被展开为row(1). row(2).等等直到row(8).

之后就是各个规则了,首先我们需要在 I 行 J 列上放置皇后:

queen(I, J) : row(I) : col(J).

这还不够,因为我们放且只能放8个皇后,所以我们把这个规则改写一下:

8 {queen(I, J) : row(I) : col(J) } 8

好了,到此为止如果你好奇的话可以像上面的例子那样先执行一下看看结果是什么,不过千万要记得把clasp后面的0换成5来表示只计算5种满足条件的结果,毕竟我们现在可以说什么限制都没有加,所有结果的数量多的可怕。另外,因为我们只关心queen的情况,而你会发现程序把row和col的结果都打印出来了,所以我们可以用

#hide.
#show queen/2.

来将结果显示限定在谓词queen上而隐藏其他的谓词。好了,到现在你会发现得到的结果只是随便把8个皇后放到棋盘上,根本没有考虑他们之间有没有攻击的问题,那么之后我们就来添加这些限制,首先是每行每列上不能同时有两个皇后:

:- queen(I, J1), queen(I, J2), J1 != J2.
:- queen(I1, J), queen(I2, J), I1 != I2.

最后,对角线上也不能同时有两个皇后:

:- queen(I1, J1), queen(I2, J2), I1 != I2,
J1 != J2, I1 - J1 == I2 - J2.
:- queen(I1, J1), queen(I2, J2), I1 != I2,
J1 != J2, I1 + J1 == I2 + J2.

到现在为止我们的程序就完成了,运行来看看结果吧。很有趣不是么,我们没有教计算机如何计算,只是描述了整个问题,计算机就把结果告诉了我们。当然这里介绍的只是冰山一角,限于篇幅和我的水平也没法更加详细的介绍了,如果你有兴趣的话,这里有不少文档可以供参考,如果能把你拉下水,那么我的目的也达到了。

注:也许很多人在这里的第一反应是用否定的 \(\neg block(X,Y).\) 而不是什么奇怪的not,这其实牵扯到非单调推理的问题,不过限于篇幅这个就不扯了,大家可以自己去找找资料。

Google 拼音中数学符号的输入(LaTeX)

晚上我在做翻译的时候突然感叹,要是 Google 输入法能用LaTeX(确切的说是AMS LaTeX)格式输入各种数字符号以及希腊字母该多好啊(刚才输xi就立刻有Ξ和ξ出现在备选项里了,这就是今晚的工作成果吧),然后我就突然想起来了 Google 输入法好像有个自定义短语的功能。然后我就想,以 Google 公司的 geek 传统肯定是有导入导出功能的。然后一看果然有,就在属性设置→词典→编辑自定义短语→导入那里。

然后我就研究了一下导入导出的 dis 格式。嗯其实很简单,首先是 ANSI 编码的文本,里面每行一个短语,前面是你要输入的代码,中间隔一个制表符,后面就是自定义的短语。

如果你不会 LaTeX,下面这段你基本就不用看了,当然愿意点进来说明你还是对用 Google 输入法输入数学符号有兴趣的,那么就把一开始的那个 dis 文件 down 下来

嗯于是我就把 Google 拼音输入法软键盘里数学符号的符号的 LaTeX 代码弄了出来,弄出来的dis文件在这里(因为 blog 不支持制表符,所以也就不能贴出来大家复制粘贴了),大多数没什么好说的,要说的首先是平行 parallel ∥。这个符号在 LaTeX 里实际上不叫 parallel ,叫 \shortparallel,比一般的 \parallel 稍微短一些,不过既然 ANSI 里这符号只有一个我也就不蛋疼了。然后这个符号在 LaTeX 里还有一个用途是一种特殊的括号,代码是\lVert 和\rVert,所以我也就把这两个加入了。当然了由于 dis 文件里左边的代码是不能有大写的,而LaTeX里显然是区分大小写的,而\lvert 和\rvert 指的是单竖线|,所以这里比较蛋疼。另外是弧 arc ⌒,这个 LaTeX 里是没有的,因为 LaTeX 里的上下标系统非常发达,根本就不需要这蛋玩意,例如 \widearc{abc} 这种,所以我就把它叫 arc 了,不过为了显示对 LaTeX 的敬意(?)widearc 也可以弄出来⌒。至于开方 sqrt √,LaTeX里的\sqrt 语句自然比这个漂亮多了,另外还有两个软键盘里没有的 fallingdotseq    ≒和oplus    ⊕,这是在word的符号库里找到的。如果还有什么ANSI数学符号我这里面没有而LaTeX符号里是有的(比如这里),请务必在下面留言,我会及时更新文件的。

我另外还做了希腊字母的两个导入文件。由于LaTeX的希腊字母输入就是\alpha \Beta这种所以这些也可以认为是LaTeX语句了XD。大写字母在这里,小写字母在这里

需要注意的是,由于导入的短语会自动占据第一位,所以希腊字母的导入请谨慎,比如正如我之前所说的我现在xi的第一个是Ξ,第二个是ξ。

以上,由于这玩意匆忙做出来,有不小的可能会有问题,如果使用中碰到了什么问题请不吝在下面留言告知。

p.s 在文件的最后我加了个latex LaTeX,结果打成了LeTeX,这太黑历史了

抛弃文件夹!用Plex来管理你MAC下的视频!

Update(2012/5/9): 有鉴于字幕的支持问题,我现在切换到XBMC上了,这篇文章不少地方还适用,不过要补充几点:

1. XBMC支持自定义字体,但是需要将字体文件放入~/.xbmc/temp/fonts文件夹下。另外不知为何,我这里需要将这个文件夹设为只读才可以,否则每次播放文件这个文件夹会被清空。

2. 最新稳定版的XBMC(11.0 eden)不支持10bit视频,但是Nightly版支持,另外预定在下一个稳定版时会支持。
12.0已支持(2013/02/12)

3. 对于电视剧即使其本身只有只有一季,在文件名里也必须写上S01而不能省略。详细的命名规则在这里

Update(2012/5/26): 对于iOS版的XBMC,可以将ASS字幕所用字体放入/private/var/mobile/Library/Preferences/XBMC/temp/fonts下(没有就自己新建一个)。不过需要注意的是,对于大码率的视频,带特效的字幕会导致拖慢,这个恐怕除非以后硬件升级,是没有把法解决了。另外使用共享功能观看计算机上的视频我推荐使用这个软件可以使用系统自带的AFP(Apple)或SMB(Microsoft)共享方式,比较方便。其他的使用指南网上有很多,我就不再复述了。

Update(2012/5/29): Nightly版的XBMC现在已经支持BD原盘的HDMV menu功能,只要打开BDMV文件夹下的index.bdmv文件即可,但是仍旧有不少Bug,也不支持BD-J和BD-Live,Windows用户 还是使用TMT或者PowerDVD作为外挂播放程序比较完美,至于MAC用户嘛...去装个Windows吧... 12.0正式版对HDMV Menu的支持有所改善,但仍旧不完美,另外仍旧不支持BD-J和BD-Live(2013/02/12)

Update(2012/7/18): 在iOS上播放如果连普通的字幕都会拖慢,可以考虑安装nightly版本,对于字幕的处理效率比起正式版有了本质的提高。 12.0已解决(2013/02/12)

============================

不知道有多少人和我一样已经习惯了用库来管理自己的文件,iTunes,Papers,iPhoto。之前还嫌他们巨大而又笨拙,但是当习惯之后却再也不想回到用文件夹来管理文档的低级工作中去。那么上面的3个软件分别对应于音乐,论文,照片。但是显然的,我们还有一个重要的类别没有被包含在内,那就是视频。Plex是Mac下一个出名的视频管理软件,不过大部分人应该只把其当作了视频播放器来用。如果只是把它当作视频播放器的话这个软件未免显得太巨大了一点,并且它大部分的功能都没有利用到。那么经过两天的初步摸索,就让我来介绍一下使用Plex管理视频文件的心得体会吧~以下内容适用于Plex的0.9及以上版本,以OS X10.6.6作为运行平台,不过Plex之前放出了Windows版,所以以下内容应该也是部分适用于Windows。

首先要说明的是Plex的管理功能相较于iTunes之类还是稍显麻烦,上面的3个软件你并不需要关心文件夹是否整齐,文件名是否合适。但是显然Plex现在还不是那么的智能,所以我们还是要先从最基本的文件夹和文件名开始整理起,以备Plex的Media Server使用。

对于文件夹的设置,我们需要将电影和电视剧放置在不同的文件夹下,并且,不同的电影和不同的电视剧放在不同的文件夹下。也就是说一个片子一个文件夹,并且电影放到电影的文件夹里,电视剧放到电视剧的文件夹里。接下来就是文件的重命名了,如果说文件夹的问题还好说,那么文件的重命名就绝对就是一大讨厌的事的,特别是对于电视剧而言,动辄十几到几十集,难道我们还要一集一集的更改文件名么?复杂重复的工作自然就要交给机器来做!这时后我们就要请出Apple系统中自带的Automator了(*注:从 Yosemite 起系统菜单中集成了批量重命名的功能,可选项比起这个少一点,不过也够用)。在应用程序中打开Automator,选取服务作为工作流程的模版,在右侧上方将服务接受选定的...改为文件和文件夹,从左侧添加一个“给Finder项重新命名”到右边,它会提示你是否要创建副本,我们选择不添加(当然你要是觉得不保险也可以选择添加,不过仅仅是重命名,问题应该不大)。之后按照图上的样式设置一下就可以了。

Photobucket

接下来只要保存这个工作流程,给它取个名字就可以了,我这里叫做批量重命名。

之后就是批量选择你想要重新命名的文件之后点击鼠标右键,在菜单的下方应该就可以看见刚才保存的那个服务了吧:

Photobucket

点击之后会弹出一个对话框,此时我们就可以按照“剧集名称 - S季数E集数”的格式来修改文件名了,左下角会出现名称的预览,确定前先看看中不中意吧:

Photobucket

好了,点击继续,你就会发现所有文件名都已经更改成功了!(耶~~)

如果是电影的命名,则相对而言容易一些,只需要更改为“电影名 (年代)”就可以了,比如说
The Dark Knight (2008).mkv

如果你的电影文件分为多个部分(这个在几年前很常见)就需要先将保存这个电影的文件夹按照上面的模式重命名,之后再将每个文件命名成形如
The Dark Knight Pt1.avi
The Dark Knight Pt2.avi
的样子就可以了。

折腾了这么半天,我们终于做好了准备工作。的确,就这而言Plex还大有需要改进的地方,我们就期盼制作小组们可以在下一个版本里做出改进吧。

那么之后就是安装Plex了,从http://wiki.plexapp.com/index.php/Downloads 下载最新的0.9版,安装好之后打开就会出现配置界面,这里我就直接盗用官网的图片了:

Photobucket Pictures, Images and Photos

第一个是让你设置电影的文件夹,第二个则是电视剧,最后一个就是音乐,因为我还是倾向于用iTunes来管理音乐,最后这一步我就Skip过了。

安装好了之后在菜单栏就能看见如图所示的图标,那就是Plex Media Server,并且它会自动开始扫描文件。

Photobucket Pictures, Images and Photos

等它扫描完成之后我们就可以察看结果啦~
Photobucket

怎么样,看上去还不错吧。对于每部片子,还可以察看全片的简介和每集的简介(如果有的话):

Photobucket

Photobucket

封面图,背景图会自动下载,现在看来这个数据库还是挺全的。

之后我们就可以打开Plex了,从Plex里进入剧集浏览界面后会自动播放片头音乐(部分,原理未知),并且会显示媒体分辨率,编码等信息:

Photobucket

至于软件本身的设置大家可以自己摸索,如果需要显示外挂字幕的话需要在Preferences--视频--字幕里将字体调为Arial Unicode MS,字符集可以默认,之后将字幕用文本编辑打开后另存成UTF-8编码的格式才行。

Photobucket Pictures, Images and Photos

不要问我为啥只能用该死的Arial,我也想知道。MKV的内封字幕不用管,软件会自己加载。另外播放的时候也可以按M键调出菜单,有兴趣的就请去看看吧~

说了这么多好处,现在来说说缺点吧。首先需要手动改名绝对是一大坑爹的事啊,虽说对于0Day的命名格式这个软件可以自己识别,但是如果是按照国内字幕组的命名格式的话这软件就直接呈天然呆状了,字幕也是个问题,普通的srt字幕倒是没啥大事,但是对于有着各种特效的ass字幕显示效果就不那么尽如人意了。所以虽然我标题写的野心很大的样子,不过实际上现阶段这个软件还有不少的路要走,恐怕我也还没办法在这一个软件里实现全部我所希望的视频功能吧。

最后,如果想要看看详细的软件使用指导,可以去Plex的Wiki页面察看,当然是英文的。