<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
            <title type="text">陈哔哔的BLOG</title>
            <subtitle type="text">资深的小虫养殖家</subtitle>
    <updated>2022-10-16T21:14:35+08:00</updated>
        <id>https://vitalight.me</id>
        <link rel="alternate" type="text/html" href="https://vitalight.me" />
        <link rel="self" type="application/atom+xml" href="https://vitalight.me/atom.xml" />
    <rights>Copyright © 2026, 陈哔哔的BLOG</rights>
    <generator uri="https://halo.run/" version="1.6.0">Halo</generator>
            <entry>
                <title><![CDATA[C++内存管理的轶闻]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/cpp-anecdote" />
                <id>tag:https://vitalight.me,2022-02-14:cpp-anecdote</id>
                <published>2022-02-14T19:51:31+08:00</published>
                <updated>2022-02-14T22:08:18+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>C++中内存管理是一件比较麻烦的事情，因为需要手动进行内存的分配和释放，很容易出现内存泄漏的问题。</p><p>在C++ 11的标准制定过程中，Bjarne Stroustrup（C++之父）觉得Java的内存管理比较好，想要参考Java的方法改进C++。</p><p>当他给C++标准委员会提起这件事的时候，来自Microsoft和IBM等公司的代表马上不乐意了。代表们说，如果C++采用Java的内存模型，Java的运行速度至少会慢上一倍，你可不能这么对Java。</p><h2 id="英文原文">英文原文</h2><p>Bjarne Stroustrup: We thought, at least I thought that Java had a pretty good memory model, so why don't we adopt that, and it'll save us a lot of work. So i mentioned this, and the representatives from various important groups such as Microsoft and IBM says, you can't do that, because if you adopt the Java memory model for C++, our Java implementations will slow down by at least a factor of two, and you just can't do that to Java.</p><h2 id="视频链接">视频链接</h2><p><a href="https://youtu.be/Q7HcwDE3lsU?t=3958">Core C++ 2021 :: Bjarne Stroustrup :: Thriving in a crowded and changing world: C++ 2006-2020</a></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[提瓦特游记]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/genshin-impact-screenshots" />
                <id>tag:https://vitalight.me,2021-08-08:genshin-impact-screenshots</id>
                <published>2021-08-08T19:26:46+08:00</published>
                <updated>2021-10-31T12:45:08+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>天高散孤云，<br />落日澄空故乡影，<br />飘摇游子心。</p><p><img src="https://i.loli.net/2021/08/08/kQf5K8cru4FO7En.png" alt="璃月城" /></p><p><img src="https://i.loli.net/2021/08/08/wUB2T9jy3iStdPY.png" alt="柴犬茶屋" /></p><p><img src="https://i.loli.net/2021/08/08/Fj8GJkU2nPNWomV.png" alt="稻妻落日" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[🎓一个图形学研究牲的论文投稿心得]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/notes-on-cg-paper-submission" />
                <id>tag:https://vitalight.me,2021-03-13:notes-on-cg-paper-submission</id>
                <published>2021-03-13T10:21:29+08:00</published>
                <updated>2021-03-13T12:21:04+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>封面图来自<a href="https://www.behance.net/gallery/97916559/WIRES">WIRES on Behance</a></p></blockquote><p>最近在忙着投稿毕业小论文，在这里简单记录一下计算机图形学领域的一些投稿心得。本文主要内容如下：</p><ul><li><a href="#-投稿期刊和会议的区别">👨‍🔬 投稿期刊和会议的区别？</a></li><li><a href="#-如何查询期刊会议是否是sciccf">🔍 如何查询期刊/会议是否是SCI/CCF？</a></li><li><a href="#-2021年-计算机图形学-sci期刊列表">🧾 2021年 计算机图形学 SCI期刊列表</a></li><li><a href="#-2021年-计算机图形学-ccf会议-截稿时间列表">📆 2021年 计算机图形学 CCF会议 截稿时间列表</a></li><li><a href="#-如何写出一篇好的图形学论文">👨‍🎓 如何写出一篇好的图形学论文？</a></li><li><a href="#-结语">✍ 结语</a></li></ul><h2 id="-投稿期刊和会议的区别">👨‍🔬 投稿期刊和会议的区别？</h2><hr /><p>一般而言，会议（Conference）有明确的截稿时间、结果通知时间，审稿周期相对更短，通常在1~2个月就会给出初步的审稿结果。而期刊（Journal）虽然全年随时都可以投，但审稿周期则相对较长，运气不好的时候半年、一年都有可能。</p><p>另外，有的会议（如IEEE VR，ISMAR）会有多个track，一个track会将收录的论文推荐到其他的期刊（如TVCG）进行发表，另一个track则留在自己的会议论文集发表。SIGGRAPH ASIA则是将所有论文都推荐到TOG上进行发表，所以虽然SIGGRAPH ASIA本身并不在CCF名单中，但是TOG则属于SCI顶刊，因而可以放心的拿来毕业。</p><p>这种推荐机制使投稿者既可以享受会议的短期审稿周期，也可以让自己的论文在高水平的期刊上发表。所以综合而言，研究生投稿会议论文更加合适。</p><h2 id="-如何查询期刊会议是否是sciccf">🔍 如何查询期刊/会议是否是SCI/CCF？</h2><hr /><p>CCF的列表在<a href="https://www.ccf.org.cn/Academic_Evaluation/CGAndMT/">中国计算机学会推荐国际学术会议和期刊目录</a>可以看到。每年CCF列表中的评级可能会变化，学校的要求一般是“按照申请人入学后的列表并集处理”，也就是只要某个期刊/会议在你就读研究生期间曾出现在CCF上，就可以算作CCF。</p><p>SCI只针对期刊，进入<a href="https://mjl.clarivate.com/home">官方查询界面</a>，在搜索框里输入期刊名，Web of Science Core Collection栏目中显示Science Citation Index Expanded (SCIE) 就对啦。SCIE和SCI本质是稍有区别的，但是现在各个学校基本上已不再区分。</p><h2 id="-2021年-计算机图形学-sci期刊列表">🧾 2021年 计算机图形学 SCI期刊列表</h2><hr /><p>SCI并没有像CCF那样提供一个官方的每个学科的列表，所以自己要统计起来会比较头疼。以下更改自<a href="http://www.cad.zju.edu.cn/home/liugengdai/Journal%20&amp;%20Conference.htm">刘更代老师整理的SCI-Indexed Journals</a>，在原有基础上删去了一个不再收稿的期刊，并更新了部分期刊的网址：</p><p><strong>Graphics:</strong> (Computer Graphics, Visualization, Animation and Applications)</p><ul><li><a href="http://www.acm.org/pubs/tog/">ACM Transactions on Graphics</a></li><li><a href="http://www.computer.org/tvcg">IEEE Transactions on Visualization and Computer Graphics</a></li><li><a href="https://ieeexplore.ieee.org/xpl/RecentIssue.jsp?punumber=38">IEEE Computer Graphics and Applications</a></li><li><a href="https://www.journals.elsevier.com/graphical-models">Graphical Models</a></li><li><a href="https://onlinelibrary.wiley.com/journal/1546427x">Computer Animation and Virtual Worlds</a></li><li><a href="https://www.springer.com/journal/371">The Visual Computer</a></li><li><a href="https://onlinelibrary.wiley.com/journal/14678659">Computer Graphics Forum</a></li><li><a href="http://www.elsevier.com/locate/cag">Computers &amp; Graphics</a></li></ul><p><strong>Virtual Reality:</strong> (including VR, Multimedia and Simulation)</p><ul><li><a href="https://dl.acm.org/journal/pres">Presence: Teleoperators &amp; Virtual Environments</a></li><li><a href="https://dl.acm.org/journal/tap">ACM Transactions on Applied Perception</a></li><li><a href="http://www.elsevier.com/wps/find/journaldescription.cws_home/622907/description#description">Journal of Visual Languages and Computing</a></li><li><a href="http://www.springer.com/computer/information+systems/journal/11042">Multimedia Tools and Applications</a></li><li><a href="http://www.elsevier.com/wps/find/journaldescription.cws_home/505615/description">Mathematics and Computers in Simulation</a></li></ul><p><strong>Human-Computer Interaction:</strong></p><ul><li><a href="http://tochi.acm.org/">ACM Transactions on Computer-Human Interaction</a></li><li><a href="https://www.journals.elsevier.com/international-journal-of-human-computer-studies">International Journal of Human-Computer Interaction</a></li><li><a href="http://www.elsevier.com/wps/find/journaldescription.cws_home/622846/description#description">International Journal of Human-Computer Studies</a></li><li><a href="http://www.springer.com/computer/hci/journal/779">Personal and Ubiquitous Computing</a></li></ul><p><strong>General:</strong> (Computer Engineering and Application)</p><ul><li><a href="http://search.ieice.org/bin/index.php?category=D&amp;lang=E&amp;curr=1">IEICE Transactions on Information and Systems</a></li><li><a href="https://www.springer.com/journal/11390">Journal of Computer Science and Technology</a></li><li><a href="http://www.elsevier.com/wps/find/journaldescription.cws_home/399/description#description">Computers and Industrial Engineering</a></li><li><a href="http://www.elsevier.com/wps/find/journaldescription.cws_home/347/description#description">Computers &amp; Education</a></li><li><a href="https://www.springer.com/journal/366">Engineering with Computers</a></li><li><a href="http://www.ijicic.org/aims.htm">International Journal of Innovative Computing, Information and Control</a></li><li><a href="https://ieeexplore.ieee.org/xpl/RecentIssue.jsp?punumber=5992">Computing in Science &amp; Engineering</a></li><li><a href="https://onlinelibrary.wiley.com/journal/10990542">Computer Applications in Engineering Education</a></li></ul><h2 id="-2021年-计算机图形学-ccf会议-截稿时间列表">📆 2021年 计算机图形学 CCF会议 截稿时间列表</h2><hr /><p>以下按Full Paper截稿时间排序。部分会议会要求提前一周左右提交论文Abstract。</p><table><thead><tr><th>会议</th><th>CCF评级</th><th>截稿时间</th><th>结果通知</th></tr></thead><tbody><tr><td><a href="http://cadcg2021.icrp.xjtu.edu.cn/">CADCG</a></td><td>C</td><td>2021-02-07</td><td>2021-03-13</td></tr><tr><td><a href="http://casa2021.ca/page_callforpapers.php">CASA</a></td><td>C</td><td>2021-03-06</td><td>2021-04-06</td></tr><tr><td><a href="http://www.cgs-network.org/cgi21/#features">CGI</a> for Visual Computer</td><td>C</td><td>2021-03-10</td><td>2021-04-15</td></tr><tr><td><a href="https://ismar21.org/call-for-papers/">ISMAR</a> for TVCG</td><td>A</td><td>2021-03-15</td><td>2021-05-21</td></tr><tr><td><a href="https://computeranimation.org/">SCA</a></td><td>B</td><td>2021-04-月初</td><td>Unknown</td></tr><tr><td><a href="https://sa2020.siggraph.org/en/submissions/technical-papers">SIGGRAPH Asia</a> for TOG</td><td>\</td><td>2020-05-21</td><td>2020-07-07</td></tr><tr><td><a href="https://ismar21.org/call-for-papers/">ISMAR</a> Conference</td><td>B</td><td>2021-05-28</td><td>2021-07-23</td></tr><tr><td><a href="http://www.cgs-network.org/cgi21/#features">CGI</a> Conference</td><td>C</td><td>2021-06-01</td><td>2021-06-30</td></tr><tr><td><a href="https://pg2020.org/">Pacific Graphics</a></td><td>B</td><td>2020-06-30</td><td>2020-08-05</td></tr><tr><td><a href="https://vrst.acm.org/vrst2021/">VRST</a></td><td>C</td><td>2021-07-15</td><td>2020-08-31</td></tr><tr><td><a href="http://ieeevr.org/2021/contribute/">IEEE VR</a> for TVCG</td><td>A</td><td>2020-09-09</td><td>2020-10-31</td></tr><tr><td><a href="https://conferences.eg.org/eg2021/for-submitters/important-dates/">Eurographic</a></td><td>B</td><td>2020-10-05</td><td>2020-11-23</td></tr><tr><td><a href="http://ieeevr.org/2021/contribute/conference-papers/">IEEE VR</a> Conference</td><td>A</td><td>2020-11-13</td><td>2021-01-13</td></tr><tr><td><a href="http://i3dsymposium.github.io/2021/index.html">I3D</a></td><td>B</td><td>2020-12-22</td><td>2021-02-16</td></tr><tr><td><a href="https://s2021.siggraph.org/program/technical-papers/">SIGGRAPH</a></td><td>A</td><td>2021-01-29</td><td>2021-03-08</td></tr></tbody></table><p><strong>备注：</strong></p><ul><li>部分会议/期刊没有公布2021年的截稿时间，所以表格写的是2020年的截稿时间，以供参考。</li><li>大部分的图形学顶级会议论文可以在<a href="https://kesen.realtimerendering.com/">Resources for Computer Graphics</a>中找到。</li><li>部分会议提供Rebuttal机制，也就是在获得论文reviewer的评价之后，可以针对评价进行一次辩解。Reviwer们会再根据你提供的辩解内容，决定最终是录用还是拒稿。</li></ul><h2 id="-如何写出一篇好的图形学论文">👨‍🎓 如何写出一篇好的图形学论文？</h2><hr /><p>在这里给大家推荐一些大佬们的资料：</p><ul><li><a href="https://vitalight.me/upload/2021/03/RE00-How-to-Write-a-SIGGRAPH-Paper-7e2a071d1fa64145bdba16fee093aca7.pdf">📋 How to write a SIGGRAPH paper</a>：SIGGRAPH Course教你怎么写SIGGRAPH论文</li><li><a href="https://vitalight.me/upload/2021/03/RE01-How-to-do-research-178c813aa0954e6195d1f53d64bcf408.pdf">📋 How to do research</a>：MIT教授Bill Freeman告诉你如何做研究</li><li><a href="https://vitalight.me/upload/2021/03/RE02-Elements-of-a-successful-graduate-career-851570cb601b40398361d2000687a61f.pdf">📋 Elements of a successful graduate career</a>：MIT教授Bill Freeman找众多教授收集的成功秘诀</li><li><a href="https://vitalight.me/upload/2021/03/RE03-Notes-on-writing-5432a354f1824f62910a89951d9ffc10.pdf">📋 Notes on writing</a>：MIT教授Fredo Durand的写论文秘诀</li><li><a href="https://vitalight.me/upload/2021/03/RE04-Graduate-student-survival-guide-ad74ea6a55d341f09aac4057c8eab55d.pdf">📋 Graduate student survival guide</a>：Waterloo大学教授撰写的研究生生存指南</li></ul><h2 id="-结语">✍ 结语</h2><hr /><p>投论文的过程中遇到失败总是难免的。希望大家保持积极心态，早日上岸🚀！</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Cyber Travel 2077]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/cyber-travel" />
                <id>tag:https://vitalight.me,2021-02-25:cyber-travel</id>
                <published>2021-02-25T10:03:21+08:00</published>
                <updated>2021-08-18T23:14:20+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>赛博朋克世界的旅行🌴（图片截自游戏<a href="https://store.steampowered.com/app/1091500/_2077/">Cyberpunk 2077</a>）。</p><p><img src="https://i.loli.net/2021/02/25/OJ2jnSiV5WYUhem.jpg" alt="夜之城的高楼" /></p><p><img src="https://i.loli.net/2021/02/25/mB6DgRaAYdsoQTr.jpg" alt="从无辜路人手中抢到的豪车" /></p><p><img src="https://i.loli.net/2021/02/25/EDRYXyFPjpdQ7W2.png" alt="日式街景" /></p><p><img src="https://i.loli.net/2021/02/25/uq7IcomjFP5wHBN.jpg" alt="AI德拉曼的核心" /></p><p><img src="https://i.loli.net/2021/02/25/oTKzJUO5fDnVqMr.jpg" alt="摇滚演奏" /></p><p><img src="https://i.loli.net/2021/02/25/2rOiEaom5X7VUxH.png" alt="反派的落幕" /></p><p><img src="https://i.loli.net/2021/02/25/q1MdRVtSOyEHmaT.png" alt="废土游乐场" /></p><p><img src="https://i.loli.net/2021/02/25/piz3mjlEB1vTnAM.png" alt="体检" /></p><p><img src="https://i.loli.net/2021/02/25/pEJHjcAheLkOKgm.jpg" alt="离别的背影" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[论文分享：Detailed Rigid Body Simulation with Extended Position Based Dynamics]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/detailed-rigid-body-sim" />
                <id>tag:https://vitalight.me,2021-01-04:detailed-rigid-body-sim</id>
                <published>2021-01-04T11:03:34+08:00</published>
                <updated>2021-02-25T23:25:55+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>📄 论文：<a href="https://onlinelibrary.wiley.com/doi/abs/10.1111/cgf.14105">Detailed Rigid Body Simulation with Extended Position Based Dynamics</a></p></blockquote><h1 id="引言">引言</h1><p>刚体物理仿真是游戏引擎以及CG特效中一个极为重要的功能。然而为了实现刚体运动的模拟，我们通常需要求解一些极为复杂的数学公式：</p><p><img src="https://i.loli.net/2021/01/04/CHFksv3PmdyIXqR.png" alt="复杂的刚体动力学公式" /></p><p>难道只有数学巫师才配研究刚体物理仿真吗？😿</p><p>基于位置的动力学（Position Based Dynamics, PBD）<sup>[2]</sup>是Müller等人于2006年发表的一种物理仿真方法。此前的方法都是基于<strong>力</strong>进行解算的，而PBD方法的独特点则在于它选择基于<strong>位置</strong>进行解算。</p><p>这样做有很多好处，一个是避免加速度到速度，速度到位置的多次积分，因而提升性能；另一方面则是具有更好的可控性，比如下图中，为了将两个碰撞的物体分离，基于力的方法需要很精妙的设计，才能找到一个合适的力将两个物体分离开。而基于位置的方法，直接将物体挪走就完成了。除此之外，PBD方法还具有易于实现、稳定的优点，这使其十分契合实时应用的需求。</p><p><img src="https://i.loli.net/2021/01/04/hLPjz8vOntNbDH2.png" alt="基于力的更新以及基于位置的更新" /></p><p>PBD方法是基于粒子的。仿真场景中的所有物体都由粒子组成，再加上各类约束（Constraint），保证物体满足特定的性质。因此，PBD方法可以在一套统一的框架下同时模拟刚体、布料、软体、流体等不同物理性质的物体极及其交互<sup>[3]</sup>。</p><p><img src="https://i.loli.net/2021/01/04/fLSbtOpn5mT6N42.png" alt="统一粒子框架模拟各种物体" /></p><p>PBD使用粒子表示各种物体，这使得其实现相比传统物理引擎会简单很多。因为所有的计算操作，都只需要针对没有旋转自由度的球体进行。然而，这也是PBD方法的一个缺点。使用粒子表示物体，意味着物体的体积越大，需要的粒子越多，这使其Scalability较差。并且，基于粒子的方法难以实现稳定的冲量传导和关节效果。</p><p>本论文名为Detailed Rigid Body Simulation with Extended Position Based Dynamics<sup>[1]</sup>，目标就是在继承PBD方法的简单性的同时，加入对任意形状刚体以及关节效果的支持。</p><p><img src="https://i.loli.net/2021/01/04/gdakm7hGNLsZDqY.png" alt="PBD通用物理引擎" /></p><h1 id="思考">思考</h1><p>刚体和粒子的区别其实不大。粒子因为是完全对称的，所以不需要考虑角度和角速度。而刚体则因为可能具有任意的形状，在受力时需要加入对角度和角速度的计算。</p><p>传统物理引擎的复杂性，主要是因为使用了Global Solver，也就是企图使用一个矩阵连立所有已知方程，一下子把所有物体的物理更新计算出来。求解矩阵对于计算机来说很简单，但是对于人类的理解而言则带来了很多困难。所以本文想要继续采取PBD方法的Local Solver，以每个物体为单位，单独的进行迭代求解。</p><p>关于Global Solver和Local Solver的区别可见下图。左边是Global Solver，在一次迭代中会考虑所有的Constraint一并进行更新，即$\nabla C_1+\nabla C_2$。右边是Local Solver，每次迭代会依次遍历所有Constraint，分别进行更新，也就是交替的修正$\nabla C_1$和$\nabla C_2$。</p><p><img src="https://i.loli.net/2021/01/04/Ri3qs78Zy1cTQlN.png" alt="Global Solver和Local Solver" /></p><p>Local Solver可能存在一会南辕，一会北辙的情况，所以以往Local Solver的缺陷在于收敛速度相对较慢。而PBD方法就在前几年引入了sub-stepping<sup>[4]</sup>的机制，可以在很大程度上缓解收敛速度慢的问题。</p><h1 id="改进">改进</h1><p>这篇文章的主要增量工作，就是在原来只考虑位置和速度更新的PBD方法中，加入了角度和角速度的更新。下图左侧是PBD方法中的步骤，右边是本文的增量工作。可以看出角速度和速度其实是很类似的，只是需要涉及到转动惯量等角度专用的物理属性。</p><p><img src="https://i.loli.net/2021/01/04/a8EM4bprWFy2RiG.png" alt="计算步骤" /></p><p>同理，约束相关的公式也需要加入对角度相关属性的计算，就可以实现支持通用刚体形状的各类约束，把这些约束像API一样使用，就可以实现包括Attachment, Contact, Static Friction, Hinge Joint等效果。</p><p><img src="https://i.loli.net/2021/01/04/3WAU21uVnsYt6if.png" alt="演示视频截图" /></p><p>本文中的方法在Core-i7 CPU @ 3.6GHz的CPU上就可以达到实时的性能。</p><p><img src="https://i.loli.net/2021/01/04/J5f8UXVtL7mZePi.png" alt="性能" /></p><p>并且因为PBD本身是一种类似于隐式的方法，所以可以很好的保留空间及时间维度上的细节。比如下图中，本文的方法可以稳定模拟一堆玻璃珠在高度复杂的轨道形状上滚动的效果。而传统的方法要么性能太差，要么会遭受穿透。</p><p><img src="https://i.loli.net/2021/01/04/9TX3lN72ZoRda6G.png" alt="玻璃珠在轨道上滚动" /></p><h1 id="总结">总结</h1><p>本文提出了一种基于PBD的通用物理引擎框架，相比传统物理引擎更加容易实现，并且能更好的保留时空细节。继承了XPBD方法的简单性和能够处理无限刚硬（Infinitely stiff）关节的优点。通过substepping，能够在一个时间步内处理大质量比的物体交互以及快速的转动变化。</p><p>目前的缺陷在于substepping会使得一些过高频率的扰动也被保留下来，在特定情况下会让人看到物体在颤动。另外一方面是在模拟大量层层相叠的物体时会有不稳定的情况，这也是本文的未来研究方向。</p><h1 id="引用">引用</h1><ol><li>Müller, Matthias, et al. &quot;Detailed rigid body simulation with extended position based dynamics.&quot; Computer Graphics Forum. Vol. 39. No. 8. 2020.</li><li>Müller, Matthias, et al. &quot;Position based dynamics.&quot; Journal of Visual Communication and Image Representation 18.2 (2007): 109-118.</li><li>Macklin, Miles, et al. &quot;Unified particle physics for real-time applications.&quot; ACM Transactions on Graphics (TOG) 33.4 (2014): 1-12.</li><li>Macklin, Miles, et al. &quot;Small steps in physics simulation.&quot; Proceedings of the 18th annual ACM SIGGRAPH/Eurographics Symposium on Computer Animation. 2019.</li></ol>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[PageRank: The algorithm behind Google search engine]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/pagerank" />
                <id>tag:https://vitalight.me,2020-09-26:pagerank</id>
                <published>2020-09-26T14:37:47+08:00</published>
                <updated>2022-10-16T21:14:35+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>📄 You can download <a href="https://vitalight.me/upload/2020/10/pagerank_note-40709e93352f480d8f032b6a39e7a2a7.pdf" target="_blank">PDF version</a> for better readability</p></blockquote><h2 id="contents" tabindex="-1">Contents</h2><p><div class="table-of-contents"><ul><li><a href="#contents">Contents</a></li><li><a href="#1-introduction">1 Introduction</a></li><li><a href="#2-pagerank">2 PageRank</a><ul><li><a href="#2.1-definition">2.1 Definition</a></li><li><a href="#2.2-matrix-forms">2.2 Matrix Forms</a></li><li><a href="#2.3-random-surfer-model">2.3 Random Surfer Model</a></li><li><a href="#2.4-calculation-method">2.4 Calculation Method</a><ul><li><a href="#2.4.1-power-method">2.4.1 Power Method</a></li><li><a href="#2.4.2-algebraic-method">2.4.2 Algebraic Method</a></li></ul></li></ul></li><li><a href="#3-key-properties">3 Key Properties</a><ul><li><a href="#3.1-proof-of-convergence">3.1 Proof of Convergence</a></li><li><a href="#3.2-time-complexity">3.2 Time Complexity</a></li></ul></li><li><a href="#4-conclusion">4 Conclusion</a><ul><li><a href="#4.1-summary">4.1 Summary</a></li><li><a href="#4.2-extensions">4.2 Extensions</a></li></ul></li><li><a href="#references">References</a></li></ul></div></p><h2 id="1-introduction" tabindex="-1">1 Introduction</h2><p>The World Wide Web is a great invention that benefits all of us today. Anyone can share information online with nearly zero cost. However, the convenience of publishing websites also leads to trouble. Since web pages proliferate free of quality control or publishing cost, the Internet is flooded with useless or even harmful information.</p><p>Luckily, search engines come to our rescue. Just by typing in the keyword, the search engine will find the most relevant pages for us automatically and instantly. Highest mountain, tallest man on earth, favorite food of a celebrity. Google is capable of answering a large variety of questions.</p><p>But have you ever considered how do the search engines work? How is it possible that search engines can figure out what web pages are most likely useful to you among billions of web pages? Suppose you are searching for “SJTU” on Google, what logic and algorithm make Google decide to put the home page of SJTU on top of everything else?</p><p>PageRank<sup>[1]</sup> is one of the algorithm that is responsible for these decisions. It is developed by Larry Page and Sergey Brin (founders of Google) at Stanford University in 1996 and became one of the most famous and fundamental algorithms behind the Google search engine.</p><p>In a nutshell, PageRank is a link analysis algorithm that assigns numerical weights to each element of a hyperlinked set of documents, with the purpose of measuring its relative importance within the set <sup>[2]</sup>.</p><p>In the following sections, we will describe PageRank in more detail.</p><h2 id="2-pagerank" tabindex="-1">2 PageRank</h2><h3 id="2.1-definition" tabindex="-1">2.1 Definition</h3><p>The basic idea of PageRank is that the importance of a web page depends on the pages that link to it.</p><p>Given page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span>, if there are a lot of pages link to this page, then it is considered important on the web. On the other hand, if page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> has only one backlink, but this link is from an authoritative web page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> (such as <a href="http://www.bbc.com" target="_blank">www.bbc.com</a> or <a href="http://www.yahoo.com" target="_blank">www.yahoo.com</a>), we also think <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> is important because page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> can transfer its popularity or authority to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span>.</p><p>In the PageRank algorithm, the connections between web pages are represented by a graph. Each web page is considered as a vertex, and each hyperlink is considered as a directed edge. Forward links correspond to out-edges, and backlinks correspond to in-edges. Links from a page to itself are ignored. Multiple outbound links from one page to another page are treated as a single link.</p><p>With these intuitions, we begin by defining a simple ranking <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>S</mi><mi>P</mi><mi>R</mi></mrow><annotation encoding="application/x-tex">SPR</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span>, which is a slightly simplified version of PageRank.</p><p><strong>Definition 1</strong> (Simple PageRank). <em>Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span> be a web page. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>F</mi><mi>u</mi></msub></mrow><annotation encoding="application/x-tex">F_u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is the set of pages <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span> points to, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>B</mi><mi>u</mi></msub></mrow><annotation encoding="application/x-tex">B_u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.05017em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is the set of pages that points to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span>. Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>N</mi><mi>u</mi></msub><mo>=</mo><mi mathvariant="normal">∣</mi><msub><mi>F</mi><mi>u</mi></msub><mi mathvariant="normal">∣</mi></mrow><annotation encoding="application/x-tex">N_u = |F_u|</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord">∣</span></span></span></span> be the number of links from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span>. Then, the Simple PageRank of a set of Web pages is an assignment SPR to the Web pages which satisfies</em></p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  \begin {spli…'>\begin{equation}  \begin {split}    SPR(u) &amp;= \sum_{v \in B_u} \frac{SPR(v)}{N_v} \\    \sum_{u\in V}SPR(u) &amp;= 1  \end {split}\end{equation}</p><p>Note that the rank of a page is divided among its forward links evenly to contribute to the ranks of the pages they point to.</p><p>Now let’s look at an example to see how this works. Suppose there are three web pages <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span>. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> has two edges to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span>. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> has one edge to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span> has one edge to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span>.</p><p>Since <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> has two out-edges, it contributes half of its rank to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span>. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span> on the other hand, have only one out-edge, thus they give all of their ranks to the target. Therefore, we can easily calculate the PageRank for each page.</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}…'>\begin{equation}\begin{split}    SPR(A) &amp;= SPR(C) = 0.4\\    SPR(B) &amp;= \frac{SPR(A)}{2} = 0.2 \\    SPR(C) &amp;= \frac{SPR(A)}{2} + SPR(B) = 0.4 \\  \end{split}\end{equation}</p><p>Figure 1 demonstrate the graph representation for this example.</p><p><img src="https://i.loli.net/2020/10/02/O8cfu2h3qIzTEn4.png" alt="Figure 1: Simplified PageRank Calculation Example" /></p><p>However, there are some problems with this simplified ranking function <sup>[3]</sup>.</p><p><strong>Disconnected Components</strong>. If our web graph has two or more disconnected components, the rank from one component has no way to get into the other component. This means the initial assignment of rank will influence the final ranking assignment in the stable state.</p><p><strong>Dangling Nodes</strong>. There are some pages that do not have any out-links (referred to as dangling nodes), and the importance received by these pages cannot be propagated. They affect the model because it is not clear where their weight should be distributed, and there are a large number of them. Often these dangling nodes are simply pages that have not been downloaded yet since it is hard to sample the entire web.</p><p><strong>Rank Sinks</strong>. Consider two web pages that point to each other but to no other page. And suppose there are some web pages which point to one of them. Then, during iteration, the loop will accumulate rank but never distribute any rank (since there are no out-edges). The loop forms a sort of trap that we call a rank sink.</p><p><img src="https://i.loli.net/2020/10/02/VkOejyuHfaYN6bn.png" alt="Figure 2: Problem with simplified PageRank" /></p><p>To solve the dangling nodes problem, dangling nodes are assumed to link out to all other pages in the collection. Their PageRank scores are therefore divided evenly among all other pages. In other words, to be fair with pages that are not dangling, these random transitions are added to all nodes in the Web.</p><p>In order to deal with the problem with rank sinks and disconnected components, a positive constant <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> between 0 and 1 (typically set to 0.85 <sup>[4]</sup>) is introduced, which we call the damping factor.</p><p>Finally, the definition of PageRank is modified as follows:</p><p><strong>Definition 2</strong> (PageRank). <em>Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span> be a web page. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>F</mi><mi>u</mi></msub></mrow><annotation encoding="application/x-tex">F_u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is the set of pages <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span> points to, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>B</mi><mi>u</mi></msub></mrow><annotation encoding="application/x-tex">B_u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.05017em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is the set of pages that points to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span>. Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>N</mi><mi>u</mi></msub><mo>=</mo><mi mathvariant="normal">∣</mi><msub><mi>F</mi><mi>u</mi></msub><mi mathvariant="normal">∣</mi></mrow><annotation encoding="application/x-tex">N_u = |F_u|</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">u</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord">∣</span></span></span></span> be the number of links from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi></mrow><annotation encoding="application/x-tex">u</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">u</span></span></span></span>. Then, the PageRank of a set of Web pages is an assignment PR to the Web pages which satisfies</em></p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}…'>\begin{equation}\begin{split}    PR(u) &amp;= \frac{1-d}{N} + d\big(\sum_{v \in B_u} \frac{PR(v)}{N_v}\big) \\    \sum_{u\in V}PR(u) &amp;= 1  \end{split}\end{equation}</p><h3 id="2.2-matrix-forms" tabindex="-1">2.2 Matrix Forms</h3><p>Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> be a square matrix with the rows and columns corresponding to web pages. We define the entries of matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> by</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲A_{u,v} = \lef…'>\begin{equation}A_{u,v} = \left\{\begin{array}{rcl}\frac{1}{N_u} &amp; &amp; {\text{if there is an edge from v to u,}}\\\frac{1}{N-1} &amp; &amp; {\text{if node v is a dangling node and } u \ne v}\\0 &amp; &amp; {\text{otherwise,}}\end{array}\right.\end{equation}</p><p>We treat <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi></mrow><annotation encoding="application/x-tex">R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span> as a vector over web pages, that is</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲R = \left[   …'>\begin{equation}R = \left[   \begin{matrix}    PR(u_1) \\ PR(u_2) \\ \vdots \\ PR(u_n)  \end{matrix}   \right]\end{equation}</p><p>Finally, we have the following matrix equation to calculate PageRank for all web pages.</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R = \frac{1-…'>\begin{equation}  R = \frac{1-d}{N} \mathbf{1}+ dAR\end{equation}</p><p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn mathvariant="bold">1</mn></mrow><annotation encoding="application/x-tex">\mathbf 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord mathbf">1</span></span></span></span> is the vector consisting of all ones.</p><h3 id="2.3-random-surfer-model" tabindex="-1">2.3 Random Surfer Model</h3><p>The definition of PageRank above has another intuitive basis in random walks on graphs. The random surfer simply keeps clicking on successive links at random. The simplified version corresponds to the standing probability distribution of a random walk on the graph of the Web.</p><p>However, if a real Web surfer ever gets into a small loop of web pages, it is unlikely that the surfer will continue in the loop forever. Instead, the surfer will jump to some other page. The additional parameter <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> can be viewed as a way of modeling this behavior: the surfer periodically “gets bored” and jumps to a random page.</p><h3 id="2.4-calculation-method" tabindex="-1">2.4 Calculation Method</h3><p>PageRank can be computed either iteratively or algebraically <sup>[2]</sup>. The iterative method can be viewed as the power iteration or the power method. The basic mathematical operations performed by these two methods are similar.</p><h4 id="2.4.1-power-method" tabindex="-1">2.4.1 Power Method</h4><p>At <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">t=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>, an initial probability distribution is assumed, usually</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  PR(u_i;0) = …'>\begin{equation}  PR(u_i;0) = \frac{1}{N}\end{equation}</p><p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span> is the total number of pages, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mi>R</mi><mo stretchy="false">(</mo><msub><mi>u</mi><mi>i</mi></msub><mo separator="true">;</mo><mn>0</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">PR(u_i;0)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">0</span><span class="mclose">)</span></span></span></span> denotes rank for page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>u</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">u_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> at time 0.</p><p>At each time step, the computation, as detailed above, yields</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  PR(u_i;t+1) …'>\begin{equation}  PR(u_i;t+1) = \frac{1-d}{N} + d\left(\sum_{v \in B_{u_i}} \frac{PR(v;t)}{N_v}\right)\end{equation}</p><p>or in matrix notation</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R(t+1) = \fr…'>\begin{equation}  R(t+1) = \frac{1-d}{N} + dAR(t)  \label{eq:matrix}\end{equation}</p><p>Since <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi></mrow><annotation encoding="application/x-tex">R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span> is a probability distribution (i.e.<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">∣</mi><mi>R</mi><mi mathvariant="normal">∣</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">|R|=1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord">∣</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span>), we have</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  \begin{split…'>\begin{equation}  \begin{split}  ER &amp;=     \mathbf 1 \times (PR(u_1) + PR(u_2) + ... + PR(u_n)) \\    &amp;= \mathbf 1  \end{split} \end{equation}</p><p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn mathvariant="bold">1</mn></mrow><annotation encoding="application/x-tex">\mathbf 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord mathbf">1</span></span></span></span> is a vector of all ones, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi></mrow><annotation encoding="application/x-tex">E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span> is a matrix of all ones.</p><p>Therefore, Equation 9 can be rewrite as</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R(t+1) = (\f…'>\begin{equation}  R(t+1) = (\frac{1-d}{N}E + dA)R(t)  \label{eq:complex_matrix}\end{equation}</p><p>Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>\hat A = \frac{1-d}{N}E + dA<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>, and Equation 11 can be further simplified as</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R(t+1) = \ha…'>\begin{equation}  R(t+1) = \hat A R(t)\end{equation}</p><p>Now we can see that the PageRank <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi></mrow><annotation encoding="application/x-tex">R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span> we want to calculate is actually the principal eigenvector of matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>A</mi><mo>^</mo></mover></mrow><annotation encoding="application/x-tex">\hat A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9467699999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.9467699999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal">A</span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.11110999999999999em;"><span class="mord">^</span></span></span></span></span></span></span></span></span></span> with eigenvalue <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span>.</p><p>The probability calculation is repeated for several iterations until convergence is achieved, that is</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  |R(t+1)-R(t)…'>\begin{equation}  |R(t+1)-R(t)|&lt;\epsilon\end{equation}</p><h4 id="2.4.2-algebraic-method" tabindex="-1">2.4.2 Algebraic Method</h4><p>For <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mo>→</mo><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">t\rightarrow\infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord">∞</span></span></span></span> (i.e., in the steady state), Equation 9 can be rewrite as</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R = \frac{1-…'>\begin{equation}  R = \frac{1-d}{N} \mathbf 1 + dAR\end{equation}</p><p>Hence,</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: align at position 7: \begin{̲a̲l̲i̲g̲n̲}̲(I-dA) R &amp;= \f…'>\begin{align}(I-dA) R &amp;= \frac{1-d}{N} \mathbf 1 \\R &amp;= (I-dA)^{-1} \frac{1-d}{N} \mathbf 1\end{align}</p><p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi></mrow><annotation encoding="application/x-tex">I</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span></span></span></span> is the identity matrix.</p><p>The solution exists and is unique for <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>&lt;</mo><mi>d</mi><mo>&lt;</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0 &lt; d &lt; 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68354em;vertical-align:-0.0391em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73354em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span>. This can be seen by noting that <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> is by construction a stochastic matrix (i.e. the elements of each column sum up to 1) and hence has an eigenvalue equal to one as a consequence of the Perron-Frobenius theorem.</p><p>However, since the time complexity of matrix inversion is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>3</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n^3)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>, this method is impractical for industrial usage where billions of webpages are involved.</p><h2 id="3-key-properties" tabindex="-1">3 Key Properties</h2><h3 id="3.1-proof-of-convergence" tabindex="-1">3.1 Proof of Convergence</h3><p><strong>Claim 3.</strong> <em>The power method for calculating PageRank always converge to true solution for any given <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">ϵ</span></span></span></span> (error tolerance parameter) <sup>[5]</sup>.</em></p><p><em>Proof.</em> First, we define <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>R^\star<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span> as the true PageRank assignments, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><msup><mi>R</mi><mo>⋆</mo></msup><mo stretchy="false">(</mo><mi>v</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">PR^\star(v)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.688696em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">⋆</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mclose">)</span></span></span></span> as the true PageRank for page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span>. We have</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  R^\star = \l…'>\begin{equation}  R^\star = \left[   \begin{matrix}    PR^\star(u_1) \\ PR^\star(u_2) \\ \vdots \\ PR^\star(u_n)  \end{matrix}   \right]\end{equation}</p><p>Then we can define the total error at step <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span> to be:</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  Err(t) = \su…'>\begin{equation}  Err(t) = \sum_{v \in V} |PR(v;t)-PR^\star(v)|\end{equation}</p><p>Since <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><msup><mi>R</mi><mo>⋆</mo></msup></mrow><annotation encoding="application/x-tex">PR^\star</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.688696em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.688696em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">⋆</span></span></span></span></span></span></span></span></span></span></span> is the true solution, we know that it must satisfy the PageRank equations exactly:</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  PR^\star (u)…'>\begin{equation}  PR^\star (u) = \frac{1-d}{N} + d\left(\sum_{v \in B_u}\frac{PR^\star (u)}{N_v}\right)\end{equation}</p><p>To find the error between true solution and current time step, we subtract this from the iterative method equation, and obtain:</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  PR(u;t) - PR…'>\begin{equation}  PR(u;t) - PR^\star (u) = d\left(\sum_{v \in B_u}\frac{PR(u;t-1) - PR^\star (u)}{N_v}\right)\end{equation}</p><p>Using the Triangle Inequality, we can get this expression for the error in PageRank <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span> at step <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span>:</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  |PR(u;t) - P…'>\begin{equation}  |PR(u;t) - PR^\star (u)| \le d\left(\sum_{v \in B_u}\frac{|PR(u;t-1) - PR^\star (u)|}{N_v}\right)\end{equation}</p><p>Now we can sum over all v to get the total error <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi><mi>r</mi><mi>r</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">Err(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span>. Notice that the page <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span> will occur <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>N</mi><mi>v</mi></msub></mrow><annotation encoding="application/x-tex">N_v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> times on the right-hand side, and since there is also a <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>N</mi><mi>v</mi></msub></mrow><annotation encoding="application/x-tex">N_v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> on the denominator, they will cancel each other.</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  \begin{split…'>\begin{equation}  \begin{split}  Err(t) &amp;= \sum_{u \in V} |PR(u;t) - PR^\star (u)| \\         &amp;\le d \left( \sum_{v\in B_u} |PR(u;t-1) - PR^\star (u)| \right)  \end{split}\end{equation}</p><p>We are left with <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> times the total error at time <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">t-1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69841em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span> on the right-hand side.</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲  Err(t) \le d…'>\begin{equation}  Err(t) \le d Error(t-1)\end{equation}</p><p>This shows fast convergence of power method, because the decrease in total error is compounding. From this inequality, we can also see that the damping parameter <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> is essential for convergence.</p><h3 id="3.2-time-complexity" tabindex="-1">3.2 Time Complexity</h3><p>PageRank is computed for several iterations until termination condition <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi><mi>r</mi><mi>r</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>≤</mo><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">Err(t) \le \epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">ϵ</span></span></span></span> is met. In each iteration, every vertex will compute a new PageRank by accumulating all of its neighbors’ contributions. Thus the time complexity of one iteration is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>m</mi><mo>+</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(m+n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>, where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> is the number of vertices, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi></mrow><annotation encoding="application/x-tex">m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">m</span></span></span></span> is the number of edges.</p><p>In the following, we prove that there exists an upper bound for the number of iterations.</p><p><strong>Claim 4.</strong> <em>The number of iteration is bounded by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>log_d(\frac{\epsilon}{n})<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>, where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> is the number of vertices, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">ϵ</span></span></span></span> is the tolerance parameter, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> is the damping factor.</em></p><p><em>Proof.</em> According to our previous analysis on convergence, we have</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: align at position 9:   \begin{̲a̲l̲i̲g̲n̲}̲    Err(t) &amp;= …'>  \begin{align}    Err(t) &amp;= \sum_{v \in V} |PR(v;t)-PR^\star(v)| \label{eq:err} \\    Err(t) &amp;\le d Error(t-1) \label{eq:reduction}  \end{align}</p><p>Since <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mi>R</mi><mo stretchy="false">(</mo><mi>v</mi><mo separator="true">;</mo><mi>t</mi><mo stretchy="false">)</mo><mo>∈</mo><mo stretchy="false">[</mo><mn>0</mn><mo separator="true">,</mo><mn>1</mn><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">PR(v;t)\in [0,1]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">[</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">1</span><span class="mclose">]</span></span></span></span>, From equation 24 we can obtain</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 9:   \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲    Err(0) = \…'>  \begin{equation}    Err(0) = \sum_{v \in V} |PR(v;0)-PR^\star(v)|     \le \sum_{v \in V} 1 \le n   \end{equation}</p><p>Combinated with Equation 25, and we get</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 9:   \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲    Err(t) \le…'>  \begin{equation}    Err(t) \le d Error(t-1) \le d^t Error(0) \le d^t n    \label{eq:dtn}  \end{equation}</p><p>The condition for iteration to terminate is</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲    Err(t) \le…'>\begin{equation}    Err(t) \le \epsilon    \label{eq:eps}\end{equation}</p><p>Putting Equation 27 and 28 together and we obtain an upper bound for iteration number <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span>.</p><p class='katex-block katex-error' title='ParseError: KaTeX parse error: No such environment: align at position 7: \begin{̲a̲l̲i̲g̲n̲}̲    d^tn &amp;\le …'>\begin{align}    d^tn &amp;\le \epsilon \\    t &amp;\le log_d(\frac{\epsilon}{n})  \end{align}</p><p>Finally, since the number of iteration is bounded by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>log_d(\frac{\epsilon}{n})<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>, and the time complexity of one iteration is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>m</mi><mo>+</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(m+n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>, the total time complexity of PageRank is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>O((m+n)log_d(\frac{\epsilon}{n}))<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">‘</span></span></span></span>.</p><p>According to the original paper <sup>[1]</sup>, PageRank on a large 322 million link database converges to a reasonable tolerance in roughly 52 iterations. The convergence on half the data takes roughly 45 iterations. This suggests that PageRank will scale very well even for an extremely large collection.</p><p>The actual time complexity for industrial use can get quite more complex. Due to the large scale of webpages, the graph can hardly be stored in memory on a single machine. Distributed algorithms such as <sup>[6]</sup> are developed to solve this problem.</p><h2 id="4-conclusion" tabindex="-1">4 Conclusion</h2><h3 id="4.1-summary" tabindex="-1">4.1 Summary</h3><p>In this note, we described PageRank, a ranking algorithm for webpages based on their importance. The intuition behind PageRank is that it uses information that is external to the Web pages themselves - their backlinks, which provide a kind of peer review <sup>[1]</sup>. PageRank works by counting the number and quality of links to a page to determine a rough estimate of how important the website is. The underlying assumption is that more important websites are likely to receive more links from other websites.</p><p>First, we show a simplified version of PageRank, which works well in some cases, but can’t handle problems like dangling nodes, rank sinks, and disconnected components. Therefore, the damping factor and some other modifications are introduced to solve these problems.</p><p>The behavior of PageRank can be thought of as modeling the behavior of a random surfer. The random surfer simply keeps clicking on successive links at random, and the PageRank corresponds to the standing probability distribution.</p><p>PageRank can be calculated iteratively or algebraically. However, the algebraical method is time-consuming since it involves matrix inversion, making it impractical for industrial usage. Iterative methods such as Power Method are preferred, and gives an approximate result for PageRank with much better performance. The proof of convergence and time complexity analysis for the iterative method is described in detail in Section 3.</p><p>PageRank method was developed to evaluate the importance of web-pages via their link structure. The mathematics of PageRank, however, is entirely general and applies to any graph or network in any domain <sup>[7]</sup>. Thus, PageRank is now regularly used in other fields, such as bibliometrics, social and information network analysis, link prediction, and recommendation.</p><h3 id="4.2-extensions" tabindex="-1">4.2 Extensions</h3><p>Following the discovery of PageRank, there has been a huge amount of work to improve or extend PageRank. Here are a few:</p><ul><li>Intelligent Surfing<sup>[8]</sup>. This paper proposes a method to improve PageRank by using a more intelligent surfer, one that is guided by a probabilistic model of the relevance of a page to a query.</li><li>TrustRank<sup>[9]</sup>. Web spam pages use various techniques to achieve higher-than-deserved rankings in a search engine’s results. This paper proposes techniques to semi-automatically separate reputable, good pages from spam.</li><li>PigeonRank<sup>[10]</sup>. PigeonRank is developed by Google to provide preference to local search results. This is quite useful for the user and local businesses.</li><li>Fast Distributed PageRank Computation<sup>[6]</sup>. Due to the large scale of webpages, PageRank can benefit a lot from distributed computation. This paper presents fast random walk-based distributed algorithms for computing PageRanks in general graphs and prove strong bounds on the round complexity.</li></ul><h2 id="references" tabindex="-1">References</h2><ol><li>Lawrence Page, Sergey Brin, Rajeev Motwani, and Terry Winograd. The pagerank citation ranking: Bringing order to the web. Technical report, Stanford InfoLab, 1999.</li><li>Wikipedia contributors. Pagerank — Wikipedia, the free encyclopedia. <a href="https://en.wikipedia.org/w/index.php?title=PageRank&amp;oldid=961815901" target="_blank">https://en.wikipedia.org/w/index.php?title=PageRank&amp;oldid=961815901</a>, 2020. [Online; accessed 14-June-2020].</li><li>Ryan Tibshirani. Pagerank. <a href="https://www.stat.cmu.edu/~ryantibs/datamining/lectures/03-pr.pdf" target="_blank">https://www.stat.cmu.edu/~ryantibs/datamining/lectures/03-pr.pdf</a>, 2013.</li><li>Sergey Brin and Lawrence Page. The anatomy of a large-scale hypertextual web search engine. 1998.</li><li>Rio Goodman. Lecture 10: Pagerank. <a href="https://web.stanford.edu/~ashishg/msande235/spr08_09/Lecture10.pdf" target="_blank">https://web.stanford.edu/~ashishg/msande235/spr08_09/Lecture10.pdf</a>, 2009.</li><li>Atish Das Sarma, Anisur Rahaman Molla, Gopal Pandurangan, and Eli Upfal. Fast distributed pagerank computation. In International Conference on Distributed Computing and Networking, pages 11–26. Springer, 2013.</li><li>David F Gleich. Pagerank beyond the web. SIAM Review, 57(3):321–363, 2015.</li><li>Matthew Richardson and Pedro Domingos. The intelligent surfer: Probabilistic combination of link and content information in pagerank. In Advances in neural information processing systems, pages 1441–1448, 2002.</li><li>Zoltan Gyongyi, Hector Garcia-Molina, and Jan Pedersen. Combating web spam with trustrank. In Proceedings of the 30th international conference on very large data bases (VLDB), 2004.</li><li>Wikipedia contributors. Google pigeon — Wikipedia, the free encyclopedia. <a href="https://en.wikipedia.org/w/index.php?title=Google_Pigeon&amp;oldid=945252161" target="_blank">https://en.wikipedia.org/w/index.php?title=Google_Pigeon&amp;oldid=945252161</a>, 2020. [Online; accessed<br />15-June-2020].</li></ol>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[一次失败的优化经历：Lookup Tables]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/lookup-tables-optimization" />
                <id>tag:https://vitalight.me,2020-09-21:lookup-tables-optimization</id>
                <published>2020-09-21T15:57:49+08:00</published>
                <updated>2021-02-25T23:40:06+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>最近看<a href="https://ieeexplore.ieee.org/abstract/document/7487018/">Divergence-Free SPH</a> (DFSPH) 的论文时看到了一个有趣的性能优化方法——Lookup tables。</p><p>Smoothed Particle Hydrodynamics (SPH)方法会频繁的涉及Kernel的计算。Kernel可以理解为一种加权平均的函数，越相近的部分会获得更高的权值，以此就可以使用附近粒子的平均属性估算空间中某一点的属性（例如密度）。</p><p>Kernel有很多种计算公式，在不同场景下会选择不同的Kernel。DFSPH论文中使用的是Cubic Spline Kernel，计算公式如下：</p><p><img src="https://i.loli.net/2020/09/21/iWSga8cy6EBzNMd.png" alt="Cubic Spline Kernel" /></p><p>虽然这个式子本身没有特别复杂，但是因为是分段函数，需要执行if语句（if语句在GPU上是开销比较高的)，又因为Kernel在每次迭代中都需要执行非常多的次数，所以整体而言消耗了比较多的性能。因而，论文就提出，可以使用Lookup tables的方法对Kernel计算进行优化。</p><h2 id="lookup-tables">Lookup Tables</h2><p>Lookup tables方法首先会对函数进行预计算，每隔一定间隔进行采样，并将结果以table形式存储在内存。在之后的运行中，就可以直接从table中查到近似的函数值。</p><p>以下面这个线性函数为例：<br />$$<br />w(q)=q, q \in [0,  1]<br />$$<br />假设采样频率为0.01，那么我们会创建一个表格<code>table[101]</code>，并根据如下公式进行初始化<br />$$<br />table[i*0.01]=w(i*0.01), i\in[0,100]<br />$$<br />在运行时，假设我们需要取 $w(0.054)$ 的值，我们会首先我们会从table中读取，而不再使用原公式进行计算。读取的下标为$i=0.054/0.01=5$，因而最终获取到的值为$table[i*0.01]=0.05$。</p><p>在这个例子中，我们可以看到最终获取的结果和精确值之间存在 $(0.054-0.05)/0.05=8$% 的误差。但通过设置足够高的采样频率，我们可以使得计算误差任意的小。在这个示例中我们使用的函数计算很简单，可能体现不出来lookup tables的优势。而其实对于任意复杂的函数，我们都可以使用类似的优化方法，相当于是将原本的任意次加减乘除以及if判断指令，替换为单次内存读取操作。理论上而言，可以取得非常多的性能提升。</p><h2 id="实现">实现</h2><p>于是乎，我就把lookup tables的方法实现在了我GPU加速的流体项目中。不幸的是，性能不仅没有提高，反而有一定幅度的下降。原本的帧率在91~92FPS左右，开启lookup tables优化后，下降到了77~78FPS。</p><p>这是为什么呢？经过一番搜寻后，我找到了大致的原因。使用lookup tables后，执行的指令数量确实是大幅下降了，但是内存读取操作却带来了新的问题。内存读取的性能，很大程度上依赖Cache的命中率，如果进行连续读取，Cache命中率可以很高；而在实际应用中，lookup tables通常都是被随机访问的，这引入了大量的Cache Miss。Cache Miss的开销通常远高于省去的加减乘除的开销，最终使得性能反而下降。</p><p>在<a href="https://yarchive.net/comp/linux/lookup_tables.html">操作系统Linux的讨论邮件</a>中也有涉及这个问题。Linus Torvalds指出：</p><blockquote><p>Lookup tables are only faster in benchmarks, they are almost always slower in real life. You only need to miss in the cache <em>once</em> on the lookup to lose all the time you won on the previous one hundred calls.</p></blockquote><p>为证实这一猜想，我将lookup table的Resolution（也就是table的size）由10000降至了32，此时性能提升到了95~96FPS，略高于原来的性能。但是这么低的Resolution，计算误差是比较大的，再鉴于如此轻微的性能提升，还不如不进行优化。</p><h2 id="总结">总结</h2><p>优化不总是一件好事，理论也不一定能与实践相符。以Linus Torvalds的话收尾：</p><blockquote><p>&quot;Small and simple&quot; is almost always better than the alternatives.</p></blockquote>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[蜘蛛侠主机游戏：高度定制化的技术方案]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/spider-man-console-game" />
                <id>tag:https://vitalight.me,2020-04-28:spider-man-console-game</id>
                <published>2020-04-28T10:31:27+08:00</published>
                <updated>2021-02-25T23:40:21+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>本篇文章是根据2019 GDC Talk的“Marvel's Spider-Man: A Technical Postmortem”[1]基础上总结和翻译而成的，对原视频中部分过于细节的内容进行了删减，感兴趣的同学可以在文末找到视频原链接进行观看。本文将介绍Insomniac Games的开发者们在游戏《蜘蛛侠》中，面临特定游戏需求带来的特定问题时，采取的各类高度定制化的技术解决方案。</p><p>《蜘蛛侠》（Marvel's Spider Man）是由Insomniac Games开发并由索尼互动娱乐发行于PlayStation 4平台的动作冒险游戏，同时也是Insomniac获得授权后基于漫威漫画超级英雄蜘蛛侠制作的作品。游戏包含着全新的蜘蛛侠故事，且与现有的漫画、电子游戏和电影没有任何关联，同时也会展现一个年龄更大且更有经验的蜘蛛侠。作品已于2018年9月7日在全球发售。</p><p>本作以纽约为原型，实现了一个拥有庞大地图的开放世界游戏。庞大的地图给开发者们带来了渲染、存储等多方面的挑战；蜘蛛侠在城市中飞檐走壁的高速移动，也给开放世界的动态加载带来了前所未有的难题。</p><h1 id="目录">目录</h1><ul><li><a href="#目录">目录</a></li><li><a href="#串流streamming">串流（Streamming）</a></li><li><a href="#文件空间占用">文件空间占用</a></li><li><a href="#大规模渲染">大规模渲染</a></li><li><a href="#lighting光照">Lighting（光照）</a></li><li><a href="#pedestrian行人">Pedestrian（行人）</a></li><li><a href="#photo-mode拍照模式">Photo Mode（拍照模式）</a></li><li><a href="#总结">总结</a></li><li><a href="#参考">参考</a></li></ul><h1 id="串流streamming">串流（Streamming）</h1><p>大型开放世界游戏，通常都采用串流的方式，将地图数据进行动态地异步加载。整个游戏地图会被分为一个一个小块，当角色靠近新的小块时，就只需要读取这个小块即可。常用的几种划分方法如下图，这些划分方式可以保证整个地图能够无线的拼凑和延申。</p><p><img src="https://i.loli.net/2020/04/27/IiyMZGgBH4DCQ8A.png" alt="对城市进行网格化划分的方法" /></p><p>本作采取的方法是第一种，矩形划分，整个城市被分为一个一个矩形块进行单独的存储及加载。并出于简化计算量的考虑，在实际进行相交判断时，实际上是使用的圆形的范围，如下图所示。</p><p><img src="https://i.loli.net/2020/04/27/ZmOsot5eJgzaXVr.png" alt="蜘蛛侠中采取的范围判定方法" /></p><p>在玩家进行移动时，每移动一个区块，就会需要相应地读入附近的5个新区块。</p><p><img src="https://i.loli.net/2020/04/27/pfgKwWNVX5vjliZ.png" alt="地图区块加载策略" /></p><p>然而，本作和其他开放世界游戏的一个差别，在于主角蜘蛛侠，可以通过吐丝的方式在城市中以极快的速度进行移动。如此快的移动速度，意味着需要在更短的时间内加载更多的区块，IO带宽的压力成倍增加。</p><p>所以首先的一个优化思路，就是减少读取区块的数量。考虑到玩家大部分时间都是进行近似的直线运动，所以只需要加载正前方的三块区块就行了，这样大大减少了带宽消耗。</p><p><img src="https://i.loli.net/2020/04/27/tMVXONczgrIuQC5.png" alt="优化后的地图区块加载策略" /></p><p>有人可能会想了，那玩家转弯怎么办？幸运的是，在本游戏中，蜘蛛侠转弯大概需要花将近1s的时间，这完全足够异步加载系统重新进行规划和读取了。</p><p>除此之外，另外一个优化策略是Delayed Loading，对区块中部分内容进行延迟加载。考虑到蜘蛛侠在进行快速移动时，镜头模糊会使周围的视线都很模糊，这个时候附近的模型可以直接使用Texture中Mipmap的最模糊层级即可，其他层级的贴图则可以暂时延后。除此之外，当蜘蛛侠在空中快速移动时，街边小店中的各种模型也都是看不见的，所以也可以一并进行Delayed Loading。这样的方法省下了相当大的带宽。</p><p><img src="https://i.loli.net/2020/04/27/6dGrl5unLKiv7eg.png" alt="运动模糊效果" /></p><h1 id="文件空间占用">文件空间占用</h1><p>对于很多PS平台游戏来说，Duplication是一种比较常用的一个IO性能优化方法。因为Play Station使用的是机械硬盘，机械硬盘在进行连续读取的时候有很好的性能，但当需要进行seek（寻址）的时候就会浪费很多时间。所以，游戏开发者通常会将同一份数据在磁盘中进行冗余存储，如果A地图区块和B地图区块都需要用到模型X，则他们会在自己的区块上各存储一份，这样一个区块的内容可以在一次连续读取中完成。</p><p>然而，因为纽约地图实在是太过巨大，在游戏还未完成的阶段，游戏的预估占用空间就已经超过了一张蓝光碟的存储容量。这一方面会增加发行成本，另外一方面对于游戏玩家来说，在多张光碟间切换也是十分糟糕的体验。</p><p><img src="https://i.loli.net/2020/04/27/5Iovwu1sEbJpFmk.png" alt="优化前的游戏空间占用" /></p><p>所以，我们需要重新审视Duplication。Duplication的初衷是什么？空间换时间。这也是程序开发中一个常见的优化思路。然而对于本游戏而言，因为使用了高度定制化的自研引擎，本身CPU性能是十分充裕的，而空间方面却是十分吃紧。所以，我们需要避免之前那种Naive的Duplication（即无论任何情况都Duplicate），而改为更加聪明的Duplication策略。</p><p>具体而言，就是不再Duplicate特定类型的文件。首先是可以进行Delayed Loading的文件类型，因为这类文件本身没有很高的及时性要求，例如Texture mipmap的精细层级和音效等。除此之外，文件体积大于4MB的，冗余次数大于400次的都不再进行冗余。</p><p><img src="https://i.loli.net/2020/04/27/5j92pqeFNTvQD7C.png" alt="更聪明的Duplication策略" /></p><p>文件空间占用的另外一个优化方法，更加是“走火入魔”：本作在传统的模型存储格式上进行了修改。传统的模型存储格式中有很大一部分空间，存储的是每个三角面片对应的顶点index。而在本作中，这些顶点index被修改为与上一位置之间的差值。例如原本存储的是74,75,76，在修改后就成为了74,+1,+1。这样做的一方面原因，是因为三角面片中的顶点通常都是相连的，这使得如果我们存储差值的话，其中会有更多的重复数值；另一方面原因，就是本作使用了LZ4格式对文件进行压缩，而文件中的数据重复越多，就能取得更高的压缩率。最后经过计算，通过这样的压缩，模型文件的空间占用减少了多达20%。</p><p><img src="https://i.loli.net/2020/04/27/C36bHWegVivsI9X.png" alt="魔改模型文件格式" /></p><h1 id="大规模渲染">大规模渲染</h1><p>在纽约的帝国大厦天台，玩家可以纵览整个纽约城。如此庞大的城市，也带来了前所未有的渲染压力。</p><p><img src="https://i.loli.net/2020/04/27/oX9V4HMIjZuwR3B.png" alt="帝国大厦的风景" /></p><p>为了渲染如此宏大的场景，使用的第一个优化技巧，称为Imposter（假冒者）。Imposter是一些“轻量级”的场景物体，应用于视线远端的各类低精度建筑。他们的轻量，一方面在于对数据结构进行了简化，只存储必要的一些数据（Transform，模型等），另一方面则是使用更加简化的渲染管线（没有uv，没有法线，主要都靠离线烘培）。</p><p>另外一类物体称为Hibernates，主要用于建筑顶端的各类装饰品，例如太阳能板、烟囱等，这些小东西看上去并不起眼，但是对于提升城市的真实感而言却至关重要。</p><p><img src="https://i.loli.net/2020/04/27/xorksijWDgT7Ob9.png" alt="隐藏屋顶装饰物效果图" /></p><p><img src="https://i.loli.net/2020/04/27/MOQy931s4oTtqNk.png" alt="显示屋顶装饰物效果图" /></p><p>这些装饰性物品长期性的处于玩家视线之中。然而糟糕的是，整个城市中有60万个这类物体，每个物体的原始空间占用为384bytes，这意味着光是存储这些物体的信息就会占用600k*384bytes=230.4MB的内存。</p><p>这也是使用Hibernates的原因，和Imposter类似，Hibernates也对数据结构进行了精简，只存储极少的必要信息。例如位置信息，通过存储到地区区块中心的偏移量，可以使用一个16位的变量即可进行存储。在优化后，每个Hibernate只占用40 bytes，全体hibernates的内存占用也从230.4MB优化到了24MB。在角色足够靠近这些hibernates的时候，他们又会动态切换为正常的Game Object，以实现动画、玩家交互等功能。</p><p><img src="https://i.loli.net/2020/04/27/wKDLhtzCYijlp2Z.png" alt="Hibernates模型" /></p><h1 id="lighting光照">Lighting（光照）</h1><p>对于真实感渲染的游戏而言，一个必不可少的元素是环境探测球（Environment Probe），例如水面、金属等材质的镜面反射效果就离不开它。</p><p><img src="https://i.loli.net/2020/04/27/ae3nZrqFO9vJxbR.png" alt="环境探测球" /></p><p>环境探测球的生成并不复杂，只需要在探测球位置对上下左右前后六个方向进行快照即可获得。出于实时性能的考量，通常的做法是进行离线烘培并存储在磁盘中。但是，对于纽约如此庞大的城市来说，光是环境探测球就会占据8GB的空间，这是很难承受的。出于和之前Duplication部分的同样想法（CPU算力充足，而空间占用紧缺），本作采用了实时渲染的方法。当玩家进入新的区域后，如果当前有充裕的计算资源，则会异步的生成附近的环境探测球，并且为了减少重复计算量，会对生成的环境探测球进行适当的缓存。这样的做法完全是0磁盘占用。</p><p><img src="https://i.loli.net/2020/04/27/vn1NKMFXA6GQdtw.png" alt="环境探测球的生成方法" /></p><h1 id="pedestrian行人">Pedestrian（行人）</h1><blockquote><p>只要是游戏中会动的东西，总会有玩家想去和它进行交互。</p></blockquote><p>为了增加游戏的真实感及沉浸感，开发者们决定给行人们加上更加交互性的AI逻辑。然而，纽约城市中，来来往往的行人数量繁多，如果所有行人都使用同样复杂的AI逻辑，则会给游戏带来巨大的性能压力。</p><p>因此，AI逻辑部分也使用了LOD（Level of Detail）的优化思路。在游戏中，行人默认使用十分轻量级的AI逻辑。每隔30秒，玩家附近的一个行人会被切换为完全体AI（Full AI Bot），从默认的几类交互事件中随机选取一类并执行。默认的交互事件包括和玩家进行动作交互（如合照、签名等），向玩家报案（在本作中，玩家需要像警察一样到处去逞凶除恶），指引玩家前往附近的重要区域等等。当行人离玩家很远（例如只占据几个像素左右时），或者被遮挡的情况下，行人的动画、AI全都会暂停，只在原地进行左右的随机平移，给玩家带来他们仍然在移动的错觉。</p><p><img src="https://i.loli.net/2020/04/28/DKEwIBxF41a3jAP.png" alt="行人AI动态调整策略" /></p><h1 id="photo-mode拍照模式">Photo Mode（拍照模式）</h1><p>起初整个项目组只是打算将拍照模式做一个很简单的版本，这样就足以他们对外宣传“我们有拍照模式！”了。但随着用户反馈的收集，开发者们发现拍照模式的意义远比他们想象中的更大。玩家很享受在纽约城中的各个角落自拍、拍景色、甚至是拍遇到的BUG，并在各大社交平台上分享，这给游戏带来了相当多的曝光度。因此，开发者对拍照模式投入了额外的精力，加入了滤镜、贴花等功能，更好的满足玩家的拍照需求。</p><p><img src="https://i.loli.net/2020/04/28/Cxi6Z3JcwTMfrLu.png" alt="Photo Mode - 蜘蛛侠的自拍" /></p><p><img src="https://i.loli.net/2020/04/28/BOj4Dado36eCANU.png" alt="Photo Mode - 玩家的分享" /></p><h1 id="总结">总结</h1><p>在本次演讲中，演讲者Elan Ruskin总结出了四个技术实现的信条（Moral）：</p><p><strong>简单的实现就是好的实现（Simple is Good）</strong>。简单的实现有更低的开发成本和很高的可扩展度，在进行技术实现时，如果简单的实现方法可行，就不要一味去追求各类天花乱坠的高端方法。</p><p><strong>因地制宜的采取技术方案（Fit Tech To Context）</strong>。本作中相当多的优化方法，都是根据游戏的具体情况，所采取的极度定制化的优化思路。并且从这些优化思路中也可以看出来，为什么极具创新性和开创性的游戏通常都会采用自研引擎。例如模型格式的修改、多级别的Game Object、以及Mipmap的分级分离存储，这些修改在没有游戏引擎源码并高度熟悉游戏引擎架构的情况下都是很难实现的。自研引擎的核心优势，就是在于可以根据自己游戏的需求，无限制的对引擎中的各个功能进行魔改。</p><p><strong>重新进行空间和速度间的权衡（Revisit Speed-Space Tradeoffs）</strong>。传统游戏引擎中，有相当多的功能是以空间换时间的，例如各类预渲染和预计算。但随着游戏规模的不断扩大以及软硬件优化技术的提升，很多时候需要重新进行权衡，根据自身需求做出修改。</p><p><strong>做游戏的首要目标是开心（If There's No Fun Then What is Even The Point）</strong>。做游戏其实就是做玩具，而玩具的首要任务就是让用户感受到快乐。一个无法带来快乐的游戏，还有什么意义呢？</p><h1 id="参考">参考</h1><p>[1] Marvel's Spider-Man: A Technical Postmortem - Youtube. <a href="https://www.youtube.com/watch?v=KDhKyIZd3O8Hi">https://www.youtube.com/watch?v=KDhKyIZd3O8Hi</a></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[不务正业的寒假]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/2020-winter-break" />
                <id>tag:https://vitalight.me,2020-02-08:2020-winter-break</id>
                <published>2020-02-08T15:08:19+08:00</published>
                <updated>2021-02-25T23:25:25+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>最近又被同学拉回剑网三的坑，在这种垃圾优化游戏里充分发挥了我电脑RTX2060的性能，并截了一波图🤣。</p><p><img src="https://i.loli.net/2020/02/09/MKD1LsftPhNo7Ud.jpg" alt="" /></p><p><img src="https://i.loli.net/2020/02/08/Tyj4asuLt8zX9SJ.jpg" alt="" /></p><p><img src="https://i.loli.net/2020/02/08/toB7fEYZkOsnbpu.jpg" alt="" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[震惊！不知名博主租用新服务器竟为此事…]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/new-server-vray" />
                <id>tag:https://vitalight.me,2020-02-04:new-server-vray</id>
                <published>2020-02-04T14:18:18+08:00</published>
                <updated>2020-06-17T10:45:35+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="起因">起因</h2><p>自从COVID-19爆发以来，我之前服务器的网络状况就不断恶化（不知道两者之间是否存在联系），最近更是已经完全无法支撑流畅观看Youtube视频的需求了。</p><p>之前用的VPS供应商是一个很小众的公司<a href="https://virmach.com/">VirMach</a>。相同配置的价格比别家都要低一些，但是稳定性就比较差了，所以打算购置新的VPS。</p><h2 id="hostwinds">Hostwinds</h2><p>昨天在知乎上看到一个疯狂安利<a href="https://hostwinds.com">Hostwinds</a>的博主，整个Google搜索记录上几乎只有他在安利。一番权衡后决定先买三个月试一下。</p><p>价格方面，Hostwinds最便宜的VPS是5美元一个月，首次付费九折，配置很一般，但是对于我这种小打小闹的人还是基本足够。</p><h2 id="评测">评测</h2><p>实际拿到手之后大概对比了一下我的俩服务器。</p><p>首先是明面上的数据，VirMach虽然价格便宜（现在新服务器的价格也贵了，这是一年前活动的价格），但是各种配置却要好一些。</p><table><thead><tr><th>服务器</th><th>价格</th><th>位置</th><th>CPU</th><th>RAM</th><th>Storage</th><th>Bandwidth</th></tr></thead><tbody><tr><td>VirMach</td><td>$3.5/月</td><td>US. Buffalo</td><td>1CPU</td><td>2GB</td><td>30GB</td><td>2TB</td></tr><tr><td>Hostwinds</td><td>$5/月</td><td>US. Seattle</td><td>1CPU</td><td>1GB</td><td>30GB</td><td>1TB</td></tr></tbody></table><p>再用网上的脚本测试一下实际的数据。</p><pre><code class="language-bash"># I/O and Network$ wget -qO- bench.sh | bash# Performance$ wget --no-check-certificate https://github.com/teddysun/across/raw/master/unixbench.sh$ chmod +x unixbench.sh$ ./unixbench.sh</code></pre><p><img src="https://vitalight.me/upload/2020/2/benchmark-397a3c6bbead40be81d231f081e09b85.png" alt="网速及I/O测试" /></p><p><img src="https://vitalight.me/upload/2020/2/benchmark-2-d8c8105e1479477abff557f6aebb165c.png" alt="性能评分" /></p><table><thead><tr><th>服务器</th><th>网络延迟</th><th>I/O速度</th><th>网络速度</th><th>性能评分</th></tr></thead><tbody><tr><td>VirMach</td><td>284ms</td><td>84.0MB/s</td><td>30MB/s</td><td>455.2</td></tr><tr><td>Hostwinds</td><td>286ms</td><td>482.3MB/s</td><td>28MB/s</td><td>563.3</td></tr></tbody></table><p>网络速度和延迟都差不太多，但是I/O的速度差别很大，猜测VirMach并没有用SSD（虽然我记得它宣称用的是SSD）。性能评分部分，Hostwinds也要高不少。目前两天的使用情况看来，Hostwinds的整体稳定性也是比VirMach好的。</p><h2 id="结语">结语</h2><p>作为一个死宅程序猿，每台服务器都会有自己的名字。之前的那一台叫做VTai，<code>VT</code>取自我的英文名Vital，<code>ai</code>取自人工智能的英语AI。新的这一台叫做VRay，<code>V</code>取自Vital，而<code>Ray</code>取自在上面安装的第一个软件，<del>用于翻墙的V2Ray</del>（手工打码）。之后有空的话可能还可以写一下服务器的迁移过程。最后祝愿VRay能够平安长寿，肺炎的风波也早一点结束。</p><h2 id="后记">后记</h2><p>买了服务器没过几天找到了一个综合型介绍科学上网相关知识的文章[3]，介绍了常用的VPS供应商以及网络线路相关的知识，可以之后再参考一下。</p><h2 id="参考">参考</h2><ol><li><a href="https://teddysun.com/245.html">秋水逸冰 » Linux性能测试UnixBench一键脚本</a></li><li><a href="https://teddysun.com/444.html">秋水逸冰 » 一键测试脚本bench.sh</a></li><li><a href="https://haoel.github.io/">科学上网 | 左耳朵</a></li></ol>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Bullet物理引擎调研]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/bullet-physics-engine" />
                <id>tag:https://vitalight.me,2020-02-03:bullet-physics-engine</id>
                <published>2020-02-03T11:20:10+08:00</published>
                <updated>2021-02-25T23:18:13+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<ul><li><a href="#1-总览">1 总览</a></li><li><a href="#2-架构">2 架构</a><ul><li><a href="#21-rigid-body-dynamics">2.1 Rigid Body Dynamics</a></li><li><a href="#22-collision-detection">2.2 Collision Detection</a></li><li><a href="#23-constraints">2.3 Constraints</a><ul><li><a href="#231-point-to-point-constrain">2.3.1 Point to Point Constrain</a></li><li><a href="#232-hinge-constrain">2.3.2 Hinge Constrain</a></li><li><a href="#233-slider-constrain">2.3.3 Slider Constrain</a></li><li><a href="#234-cone-twist-constrain">2.3.4 Cone Twist Constrain</a></li><li><a href="#235-generic-6-dof-constrain">2.3.5 Generic 6 Dof Constrain</a></li></ul></li><li><a href="#24-soft-body-dynamics">2.4 Soft Body Dynamics</a></li></ul></li><li><a href="#3-hello-world-源码分析">3 Hello World 源码分析</a><ul><li><a href="#31-创建dynamics-world">3.1 创建Dynamics world</a></li><li><a href="#32-添加仿真物体">3.2 添加仿真物体</a></li><li><a href="#33-循环更新">3.3 循环更新</a></li></ul></li><li><a href="#4-功能演示">4 功能演示</a><ul><li><a href="#41-api">4.1 API</a></li><li><a href="#42-multibody">4.2 Multibody</a></li><li><a href="#43-physics-client-server">4.3 Physics Client-Server</a></li><li><a href="#44-inverse-dynamics">4.4 Inverse Dynamics</a></li><li><a href="#45-inverse-kinematics">4.5 Inverse Kinematics</a></li><li><a href="#46-deformable-body">4.6 Deformable Body</a></li><li><a href="#47-soft-body">4.7 Soft Body</a></li><li><a href="#48-benchmarks">4.8 Benchmarks</a></li><li><a href="#49-importers">4.9 Importers</a></li><li><a href="#410-raycast">4.10 Raycast</a></li><li><a href="#411-experiments">4.11 Experiments</a></li><li><a href="#412-rendering">4.12 Rendering</a></li><li><a href="#413-evolution">4.13 Evolution</a></li></ul></li><li><a href="#5-前车之鉴">5 “前车之鉴”</a></li><li><a href="#6-references">6 References</a></li></ul><h2 id="1-总览">1 总览</h2><p>Bullet，是一个实时物理仿真引擎，在VR、游戏、视觉特效、机器人、机器学习等领域都有应用。Bullet的著名客户包括侠盗飞车5、荒野大镖客、闪电狗、Blender、Cinema 4D等等。</p><p><img src="https://i.loli.net/2020/02/12/RokqKC79BvWypxJ.png" alt="侠盗飞车5" /></p><p>评价物理引擎主要有四方面的指标，性能、仿真精度、功能广度、易用性。鱼和熊掌不可兼得，各个物理引擎主要的差别就在于对这些方面进行了不同的取舍。Bullet文档中写道“Bullet is physics simulation software, in particular for rigid body dynamics and collision detection”，其主要的侧重点在于刚体模拟、碰撞检测和易用性，从官网的动态来看近来比较受科研工作者的喜爱（如机器人仿真方向的研究团队Google Brain, Stanford AI Lab, Open AI）。</p><p>但因为Bullet是一个没有商业机构运作的引擎，仅仅依靠开源社区支持，所以相比其他引擎，它的功能较少、代码及文档质量不佳，这使得其在商用方面逐渐式微[1]。并且其在OpenCL并行加速方面的工作还处于Experimental的状态，可能整体性能不如PhysX、Havok等引擎。</p><p>下面列举一下官方的“王婆卖瓜，自卖自夸”（译自官方源码中提供的文档Bullet_User_Manual），可以比较直观的了解Bullet引擎的特性：</p><ul><li>同时支持离散(Discrete)及连续(Continuous)碰撞检测以及射线及凸扫描测试(convex sweep test)。引擎支持的碰撞体形状包括凸状网格、凹状网格以及所有基本形状(basic primitives)。</li><li>支持最高6自由度的刚体模拟及约束连接，以及基于关节体算法（Articulated body algorithm）使用移动器（mobilizers）实现的多刚体(Multibody)系统。</li><li>实现了快速、稳定的刚体动力学约束解算器，车辆动力学(Vehicle Dynamics)，角色控制器(Character Controller)，滑块(Slider)，铰链(Hinge)，通用的6自由度Constrain以及用于实现布娃娃(Ragdoll)模拟的Cone Twist Constraint。</li><li>使用柔体动力学实现布料、绳、可变形物的模拟，支持柔体与刚体的双向交互(Two-way Interaction)，并提供了对约束(Constraint)的支持。</li><li>Bullet是Zlib许可下的开源项目，可以免费用于商业项目，并提供了广泛的平台支持(PS3, XBox 360, Wii, PC, Linux, Mac OSX, Android, iPhone)。</li><li>提供了Maya Dynamica插件，Blender集成，原生二进制.bullet序列化等文件及辅助功能。引擎支持URDP，.obj，.bsp等格式资源的导入。</li><li>提供了Example Browser示例程序展示Bullet SDK的功能。示例程序可以使用OpenGL3渲染模拟结果，也可以直接在控制台进行输出。</li><li>提供了上手指南、源码文档、Wiki和论坛，能够帮助开发者更轻松地了解引擎功能。</li></ul><h2 id="2-架构">2 架构</h2><p>物理引擎的主要任务是进行碰撞检测，并根据碰撞及其他约束进行修正，最后提供一个实时更新的Transform（包括位置及旋转信息）。</p><p>Bullet的主要功能模块如下图：</p><p><img src="https://i.loli.net/2020/02/12/PLjGM2f49xOhzFs.png" alt="Bullet功能模块图" /></p><h3 id="21-rigid-body-dynamics">2.1 Rigid Body Dynamics</h3><p>在下图中，上半部分是流程中用到的主要数据结构，下半部分是刚体物理解算流程。蓝色箭头代表读取数据，红色箭头代表读写数据。</p><p><img src="https://i.loli.net/2020/02/12/XAdQgDUvz5lPKcL.png" alt="刚体物理数据结构及解算流程图" /></p><p>在Bullet引擎中，整个上述流程都被封装在dynamics world中。当对dynamics world调用 <code>stepSimulation</code> 方法时，就会执行一次上述解算流程。并且开发者可以根据自身需求，替换甚至是重写其中的每个部分，如broadphase collision detection，narrowphase collision detection以及constraint solver。</p><h3 id="22-collision-detection">2.2 Collision Detection</h3><p>首先是broadphase碰撞检测，会根据Axis aligned bounding box (AABB)进行重叠检测，粗略的筛选出有较大可能性碰撞的物体对(pair)。Bullet会对重叠物体对进行缓存，这样之后重复碰撞时可以使用上一次缓存的信息加速约束解析的收敛速度。</p><p>Collision dispatcher会对所有物体对进行遍历，根据它们的形状类型找到合适的碰撞算法，并执行找到的碰撞算法求出接触点（Contact Point）。</p><p>Bullet支持许多种类的形状，并给出了一个图让开发者能够直观的选择适合自身需求的类型。</p><p><img src="https://i.loli.net/2020/02/12/I5yPSWYGTdHJaqe.png" alt="形状选择指引图" /></p><p>Collision Dispatcher会根据物体对中双方的形状，在下表中映射到对应的解析算法，且开发者可以根据需要修改这个映射表。其中GJK全称是Gilbert, Johnson和Keerthi，他们是Convex distance calculation algorithm的发明者。GJK通常会和EPA一起使用，EPA是用于穿透深度计算的方法，全称为Expanding Polythope Algorithm，由Gina van den Bergen发明。</p><p><img src="https://i.loli.net/2020/02/12/qylNHIYF3ixbgzS.png" alt="碰撞算法映射表" /></p><p>另外，Bullet还提供了Collision Filtering的机制，允许开发者去除掉指定物体之间的碰撞。</p><h3 id="23-constraints">2.3 Constraints</h3><p>Bullet提供了许多种Constrain的实现，以下分别列举。</p><h4 id="231-point-to-point-constrain">2.3.1 Point to Point Constrain</h4><p>Point to Point Constrain可以使两个刚体的给定轴点(pivot point)保持重合，可以用于将刚体像锁链一样连接。示例代码如下：</p><pre><code class="language-cpp">btPoint2PointConstraint(btRigidBody&amp; rbA,const btVector3&amp; pivotInA);btPoint2PointConstraint(btRigidBody&amp; rbA,btRigidBody&amp; rbB, const btVector3&amp; pivotInA,const btVector3&amp; pivotInB);</code></pre><p><img src="https://i.loli.net/2020/02/12/NrVqdZwQI2S9Tio.png" alt="Point to Point Constrain" /></p><h4 id="232-hinge-constrain">2.3.2 Hinge Constrain</h4><p>Hinge Constrain又叫Revolute joint，限制两个方向的旋转角度，保证刚体只能绕单个方向(即hinge axis)进行旋转，可以用来模拟门或轮胎。示例代码如下：</p><pre><code class="language-cpp">btHingeConstraint(btRigidBody&amp; rbA,const btTransform&amp; rbAFrame, bool useReferenceFrameA = false);btHingeConstraint(btRigidBody&amp; rbA,const btVector3&amp; pivotInA,btVector3&amp; axisInA, bool useReferenceFrameA = false);btHingeConstraint(btRigidBody&amp; rbA,btRigidBody&amp; rbB, const btVector3&amp; pivotInA,const btVector3&amp; pivotInB, btVector3&amp; axisInA, btVector3&amp; axisInB, bool useReferenceFrameA = false);btHingeConstraint(btRigidBody&amp; rbA,btRigidBody&amp; rbB, const btTransform&amp; rbAFrame, const btTransform&amp; rbBFrame, bool useReferenceFrameA = false);</code></pre><p><img src="https://i.loli.net/2020/02/12/xeXS1IUu2o8wnrM.png" alt="Hinge Constrain" /></p><h4 id="233-slider-constrain">2.3.3 Slider Constrain</h4><p>Slider Constrain限制物体只能绕单个轴进行旋转，只能沿单个轴进行平移。</p><pre><code class="language-cpp">btSliderConstraint(btRigidBody&amp; rbA, btRigidBody&amp; rbB, const btTransform&amp; frameInA, const btTransform&amp; frameInB, bool useLinearReferenceFrameA);</code></pre><p><img src="https://i.loli.net/2020/02/12/uEn9KXreyLxHF7Z.png" alt="Slider Constrain" /></p><h4 id="234-cone-twist-constrain">2.3.4 Cone Twist Constrain</h4><p>Cone twist constrain常被用于模拟Ragdoll的四肢。It is a special point to point constraint that adds cone and twist axis limits.</p><pre><code class="language-cpp">btConeTwistConstraint(btRigidBody&amp; rbA,const btTransform&amp; rbAFrame);btConeTwistConstraint(btRigidBody&amp; rbA,btRigidBody&amp; rbB, const btTransform&amp; rbAFrame, const btTransform&amp; rbBFrame);</code></pre><h4 id="235-generic-6-dof-constrain">2.3.5 Generic 6 Dof Constrain</h4><p>开发者可以针对6个自由度（3个位置自由度，3个旋转自由度）单独设定constrain。每个自由度可以处于锁定(locked)、自由(free)和受限(limited)三种状态。</p><pre><code class="language-cpp">btGeneric6DofConstraint(btRigidBody&amp; rbA, btRigidBody&amp; rbB, const btTransform&amp; frameInA, const btTransform&amp; frameInB, bool useLinearReferenceFrameA);</code></pre><h3 id="24-soft-body-dynamics">2.4 Soft Body Dynamics</h3><p>本模块在刚体动力学基础上增加了对绳、布料、体积软体(volumetric soft bodies)的支持。并且软体可以和刚体之间进行双向交互(Two-way interaction)。</p><p>使用函数 <code>btSoftBodyHelpers::CreateFromTriMesh</code> 可以从面片模型生成软体。默认的情况下，软体的碰撞检测是在顶点和面片之间进行的，因而需要很稠密的细分（dense tessellation）才能进行正确的碰撞检测。Bullet另外还实现了一种基于Automatic decomposition convex deformable clusters的改进方法，通过如下代码启用：</p><pre><code class="language-cpp">psb-&gt;generateClusters(numSubdivisions);//enable cluster collision between soft body and rigid bodypsb-&gt;m_cfg.collisions += btSoftBody::fCollision::CL_RS;//enable cluster collision between soft body and soft bodypsb-&gt;m_cfg.collisions += btSoftBody::fCollision::CL_SS;</code></pre><p>Bullet支持对软体或软体的单个顶点施加力：</p><pre><code class="language-cpp">softbody -&gt;addForce(const btVector3&amp; forceVector);softbody -&gt;addForce(const btVector3&amp; forceVector,int node);</code></pre><p>Bullet支持对单个顶点添加约束，以实现各种效果。如固定软体中单个顶点的位置：</p><pre><code class="language-cpp">softbody-&gt;setMass(node,0.f);</code></pre><p>或者将软体中某个顶点附着在刚体上：</p><pre><code class="language-cpp">softbody-&gt;appendAnchor(int node,btRigidBody* rigidbody, bool disableCollisionBetweenLinkedBodies=false);</code></pre><h2 id="3-hello-world-源码分析">3 Hello World 源码分析</h2><p>Bullet引擎中在 ·examples/HelloWorld/HelloWorld.cpp· 文件中提供了一个Hello World版本，也就是一个简易的Demo，能够让我们初步了解Bullet引擎的基本使用方法。</p><p>主要分为四个部分：</p><ul><li>创建dynamics world进行参数配置。</li><li>添加仿真物体，并设置物体信息。</li><li>循环更新逻辑，逐帧输出物体位置数据。</li><li>释放分配的资源及指针。</li></ul><h3 id="31-创建dynamics-world">3.1 创建Dynamics world</h3><p>首先是include头文件 ·btBulletDynamicsCommon.h· 。这个文件内部包含了常用的API。</p><pre><code class="language-cpp">#include &quot;btBulletDynamicsCommon.h&quot;#include &lt;stdio.h&gt;</code></pre><p>然后创建dynamics world，并设置重力大小、使用的Solver类型以及配置等参数。</p><pre><code class="language-cpp">///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);dynamicsWorld-&gt;setGravity(btVector3(0, -10, 0));</code></pre><h3 id="32-添加仿真物体">3.2 添加仿真物体</h3><p>接着就是添加需要仿真的物体，这里以Sphere为例。需要设置物体的形状、Transform、质量、运动状态(Motion State)等信息，最后添加到dynamics world中。</p><pre><code class="language-cpp">//btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));btCollisionShape* colShape = new btSphereShape(btScalar(1.));collisionShapes.push_back(colShape);/// Create Dynamic ObjectsbtTransform startTransform;startTransform.setIdentity();btScalar mass(1.f);//rigidbody is dynamic if and only if mass is non zero, otherwise staticbool isDynamic = (mass != 0.f);btVector3 localInertia(0, 0, 0);if (isDynamic)colShape-&gt;calculateLocalInertia(mass, localInertia);startTransform.setOrigin(btVector3(2, 10, 0));//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objectsbtDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia);btRigidBody* body = new btRigidBody(rbInfo);dynamicsWorld-&gt;addRigidBody(body);</code></pre><h3 id="33-循环更新">3.3 循环更新</h3><p>准备工作就此完成，现在就可以正式进入程序的循环更新逻辑了。主要就是遍历dynamics world中的所有物体，并输出其位置信息。具体的物理仿真逻辑都隐藏在Bullet SDK中了，开发者无需涉足。</p><pre><code class="language-cpp">for (i = 0; i &lt; 150; i++){dynamicsWorld-&gt;stepSimulation(1.f / 60.f, 10);//print positions of all objectsfor (int j = dynamicsWorld-&gt;getNumCollisionObjects() - 1; j &gt;= 0; j--){btCollisionObject* obj = dynamicsWorld-&gt;getCollisionObjectArray()[j];btRigidBody* body = btRigidBody::upcast(obj);btTransform trans;if (body &amp;&amp; body-&gt;getMotionState()){body-&gt;getMotionState()-&gt;getWorldTransform(trans);}else{trans = obj-&gt;getWorldTransform();}printf(&quot;world pos object %d = %f,%f,%f\n&quot;, j, float(trans.getOrigin().getX()),float(trans.getOrigin().getY()),float(trans.getOrigin().getZ()));}}</code></pre><p>最后一步是释放掉各种分配的资源和指针，具体代码就不列出了。</p><h2 id="4-功能演示">4 功能演示</h2><p>Bullet源码[2]中提供了一个Example Browser，用于浏览Bullet引擎中提供的各种实例场景，可以很直观的看到Bullet引擎提供的各类功能，并且用户可以使用鼠标拖拽移动场景中的物体进行交互。下面按照该Browser的划分来简单介绍功能。</p><h3 id="41-api">4.1 API</h3><p>展示Bullet引擎提供的基础API，如碰撞响应、摩擦力、Constrain以及各种物体类型刚体、Hinge、弹簧、陀螺仪、柔体。</p><p><img src="https://i.loli.net/2020/02/12/JIsu7C3igt16RoW.png" alt="Basic Example Demo" /></p><h3 id="42-multibody">4.2 Multibody</h3><p>展示多个刚体之间的交互，主要是使用关节进行连接。</p><p><img src="https://i.loli.net/2020/02/12/fVTdOvngeLDt684.png" alt="Multi DOF Demo" /></p><h3 id="43-physics-client-server">4.3 Physics Client-Server</h3><p>Bullet支持使用CS架构调用其他进程进行物理仿真计算。其他进程可以在本地运行，也可以在其他机器上运行（通过TCP/UDP网络进行通信）。</p><p><img src="https://i.loli.net/2020/02/12/iVzrvwmJtqRZ6uj.png" alt="Client Server Demo" /></p><h3 id="44-inverse-dynamics">4.4 Inverse Dynamics</h3><p>反向动力学。拖拽其中一个位置之后，其他关节也会被带动进行旋转。</p><p><img src="https://i.loli.net/2020/02/12/C1BJGS6l32NAtfq.png" alt="Inverse Dynamics URDF Demo" /></p><h3 id="45-inverse-kinematics">4.5 Inverse Kinematics</h3><p>反向运动学。示例程序中的物体由多个关节相连，动作像随风摇摆的树一样。Inverse Kinematics和Inverse Dynamics有一定相似之处，但是两个算法具有不同的目标和初始假设[3]。</p><p>Inverse Dynamics是给定指定点在一段时间内的位置及速度，求各关节的转矩(torques)。</p><p>Inverse Kinematics (IK)要计算的则是保证指定点处于指定位置的情况下，各关节的旋转度数。IK经常被用于进行骨骼动画和物理的融合，常用于游戏及Robotics。</p><p><img src="https://i.loli.net/2020/02/12/zPfh2ukX8NytG6I.png" alt="Inverse Kinematics SDLS Demo" /></p><h3 id="46-deformable-body">4.6 Deformable Body</h3><p>主要是可变形物体的展示，如布料（自碰撞、摩擦力）、可变形物体以及可变形物体与刚体的交互。</p><p><img src="https://i.loli.net/2020/02/12/aSnhHGgP1fuoUTk.png" alt="Deformable Self Collision Demo" /></p><h3 id="47-soft-body">4.7 Soft Body</h3><p>柔体的模拟，好像和Deformable Body就是一样的东西，不知道为什么会单独列出。包括布料、柔体、体积/压强约束、绳子的模拟，同时也有一个空气动力学的Demo。</p><p><img src="https://i.loli.net/2020/02/12/bTrBkQJUYPiaGM2.png" alt="Cloth Demo" /></p><h3 id="48-benchmarks">4.8 Benchmarks</h3><p>小方块碰撞性能测试。3000个小方块从空中落下、碰撞并散开。支持多线程和SIMD加速。</p><p><img src="https://i.loli.net/2020/02/12/1ZkR2UwcABqXSar.png" alt="3000 Boxes Demo" /></p><h3 id="49-importers">4.9 Importers</h3><p>展示Bullet引擎为各类文件格式提供的导入器，包括自己的.bullet格式以及其他常用格式如URDF（Unified Robot Description Format），MJCF（Multi-Joint Dynamics with Contact Format），SDF（Spatial Data File）等文件。这些文件主要是储存场景物体模型及状态信息。</p><p><img src="https://i.loli.net/2020/02/12/thryQC3w8mjsSY5.png" alt="Import .bullet Demo" /></p><h3 id="410-raycast">4.10 Raycast</h3><p>射线功能被广泛应用于游戏等应用，实现鼠标选中三维物体等功能。在示例场景中，一条水平方向的射线在垂直方向上下移动，并显示该射线在场景物体上的交点及交点位置处的法线。</p><p><img src="https://i.loli.net/2020/02/12/qS8gX2nI69FMrNA.png" alt="Raytest Demo" /></p><h3 id="411-experiments">4.11 Experiments</h3><p>夹子模拟。类似于抓娃娃机一样的行为，使用一个夹子抓取地面上的方块。</p><p><img src="https://i.loli.net/2020/02/12/YPMV2SCBH3WtObs.png" alt="Gripper Grasp Demo" /></p><h3 id="412-rendering">4.12 Rendering</h3><p>Bullet SDK同时支持CPU渲染及GPU渲染。</p><p><img src="https://i.loli.net/2020/02/12/eD5iFsCPh2wGr9U.png" alt="Tiny Renderer Demo" /></p><h3 id="413-evolution">4.13 Evolution</h3><p>神经网络驱动的自动行走的小蜘蛛。</p><p><img src="https://i.loli.net/2020/02/12/HmwULbCMnvDVcPJ.png" alt="Neural Network 3D Walkers Demo" /></p><h2 id="5-前车之鉴">5 “前车之鉴”</h2><p>最后大致总结一下Bullet引擎中值得参考和学习的地方：</p><ul><li>开发语言。Bullet引擎本体使用C++进行开发，目前正在开发PyBullet，将接口暴露在Python语言中，通过pip install命令即可安装，让开发者能够更轻松的上手。</li><li>编译工具。Bullet同时支持Premake[4]和CMake[5]两种方式。</li><li>源码文档。Bullet使用了Doxygen[6]实现源码文档的自动生成。</li><li>接口设计。基础方面Bullet将整个物理引擎分割为了许多的模块如Configuration，Broadphase，Narrowphase等，每个模块都提供了几种默认类型供选择，开发者也可以自己继承基类实现自己的计算方法。并且Bullet加入了许多callback支持开发者的自定义行为。</li><li>物理引擎实现原理。Bullet官网列出了与其实现相关的三个SIGGRAPH 2015 course的slides[7][8][9]，讲解了物理引擎的基本实现原理、优化算法和并行加速。</li></ul><h2 id="6-references">6 References</h2><ol><li>为什么Physx会成为目前大部分主流游戏引擎的选择，相比较bullet优势在哪里？. <a href="https://www.zhihu.com/question/309154499/answer/578649506">https://www.zhihu.com/question/309154499/answer/578649506</a></li><li>bulletphysics/bullet3 源码. <a href="https://github.com/bulletphysics/bullet3">https://github.com/bulletphysics/bullet3</a></li><li>Inverse Dynamics – Wikipedia. <a href="https://en.wikipedia.org/wiki/Inverse_dynamics">https://en.wikipedia.org/wiki/Inverse_dynamics</a></li><li>Premake: Powerfully simple build configuration. <a href="https://premake.github.io/">https://premake.github.io/</a></li><li>CMake: An open-source, cross-platform family of tools designed to build, test and package software. <a href="https://cmake.org/">https://cmake.org/</a></li><li>Doxygen: Generate documentation from source code. <a href="http://www.doxygen.nl/">http://www.doxygen.nl/</a></li><li>Introduction to rigid body pipeline, collision detection. <a href="https://docs.google.com/presentation/d/1-UqEzGEHdskq8blwNWqdgnmUDwZDPjlZUvg437z7XCM/edit#slide=id.ga4b37291a_0_0">https://docs.google.com/presentation/d/1-UqEzGEHdskq8blwNWqdgnmUDwZDPjlZUvg437z7XCM/edit#slide=id.ga4b37291a_0_0</a></li><li>Advances in constraint solving, Featherstone Articulated Body Algorithm. <a href="https://docs.google.com/presentation/d/1wGUJ4neOhw5i4pQRfSGtZPE3CIm7MfmqfTp5aJKuFYM/edit#slide=id.ga4b37291a_0_0">https://docs.google.com/presentation/d/1wGUJ4neOhw5i4pQRfSGtZPE3CIm7MfmqfTp5aJKuFYM/edit#slide=id.ga4b37291a_0_0</a></li><li>Acceleration of the full collision detection and constraint solver on GPU. <a href="https://docs.google.com/presentation/d/1BW5-2ADy88-Eo_v_bknTNDOoBNYjRL4XCF_tYLYUL3g/edit#slide=id.ga4b37291a_0_0">https://docs.google.com/presentation/d/1BW5-2ADy88-Eo_v_bknTNDOoBNYjRL4XCF_tYLYUL3g/edit#slide=id.ga4b37291a_0_0</a></li></ol>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[ChemiX - 化学仿真引擎]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/chemix" />
                <id>tag:https://vitalight.me,2019-07-09:chemix</id>
                <published>2019-07-09T16:30:08+08:00</published>
                <updated>2021-05-11T16:26:24+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>ChemiX is a <strong>chemistry experiment simulation engine</strong>, aiming to support realtime simulation of chemical reactions and display various kinds of visual effects based on the reaction.</p><h2 id="abstract">Abstract</h2><p>In chemistry, and natural sciences in general, experimental and laboratory work is one of the most effective methods for acquiring knowledge. Students can have a more intuitive and thorough understanding of subject knowledge through various well-designed experiments. However, traditional physical laboratories have several limitations, such as high maintenance costs, limited resources, and potential safety issues. Therefore, we try to take advantage of computer simulation technology to enable users to engage in chemistry experiments in a more convenient and efficient way in the virtual world.</p><p>First, we present the design and implementation of ChemiX, a general and efficient chemistry experiment simulation engine. A highly scalable database is implemented for inputting and storing information about chemical substances and chemical reactions. We also proposed a general and efficient method to calculate the reaction rate based on the principle of chemical kinetics, which supports the unified simulation of common chemical reactions in our system.</p><p>Second, we developed ChemiX Lab, a virtual chemistry lab based on our simulation engine. We implemented a user-friendly interface and powerful simulation features such as event-based process guidance and automated demonstration. Our system has great simulation capabilities while preserving high performance and scalability, and can be applied in many fields such as chemistry experiment simulation and teaching tool.</p><p>Finally, our system provides well-designed interfaces and powerful simulation features, making it effortless to extend. Other developer can easily build their own virtual chemistry lab based on our system by adding scenes, experiments, or focusing on improving certain feature such as interaction and rendering.</p><h2 id="screenshots">ScreenShots</h2><ul><li>Demonstration</li></ul><p><img src="https://vitalight.me/upload/2021/05/chemix-auto-demo-29d4a2624b8640879753b6187c61f1cb.gif" alt="实验自动演示" /></p><ul><li>Overall architecture</li></ul><p><img src="https://vitalight.me/upload/2020/2/archi-6ee5ed07e03d4f19982006b44ce2ac05.png" alt="系统架构" /></p><ul><li>Basic user interface</li></ul><p><img src="https://vitalight.me/upload/2020/2/chemix-ui-21435da71bad48bf9d6bfd631892766b.png" alt="UI界面" /></p><ul><li>Database Configuration</li></ul><p><img src="https://vitalight.me/upload/2020/2/chemix%20database-1161d0b4edc34c6187a9da56232f447a.png" alt="数据库配置" /></p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Vincents' Dream - 解谜游戏]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/vincents-dream" />
                <id>tag:https://vitalight.me,2019-01-30:vincents-dream</id>
                <published>2019-01-30T18:18:45+08:00</published>
                <updated>2020-02-11T02:54:47+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<blockquote><p>我们提供了<a href="#download">Windows 64位可执行版本</a>，欢迎试玩~</p></blockquote><p>Vincent's Dream is a <strong>puzzle game</strong> about dream and redemption. In this game, you are going to help Vincent Van Gogh to accomplish his dreams about travling to Japan.</p><p>This game is made using <strong>Unreal Engine 4</strong>, one of the most powerful game engine ever on earch. You can know more about the stories behind Vincent's magnificent painting and solve mistery along the way.</p><h2 id="screenshots">Screenshots</h2><ul><li>Stories to be told</li></ul><p><img src="https://vitalight.me/upload/2020/2/ill-a0164795f66c49eab1b5bb4860eb2af6.png" alt="诊断记录" /></p><ul><li>Lost to be found</li></ul><p><img src="https://vitalight.me/upload/2020/2/drawer-c6b0a029c9614395b7dbe6ef642fd587.png" alt="探索与发现" /></p><ul><li>Mistery to be solved</li></ul><p><img src="https://vitalight.me/upload/2020/2/clock-e9e956d80f7c4810aa932e8cfa59811e.png" alt="时钟的谜题" /></p><h2 id="download">Download</h2><ul><li><a href="https://github.com/vitalight/Vincent-s-Dream">Source Code</a></li><li><a href="https://github.com/vitalight/Vincent-s-Dream/releases/download/v1.0/Vincents-Dream-Win64.rar">Win64 Build</a></li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Nova - 星际遨游]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/nova" />
                <id>tag:https://vitalight.me,2018-01-10:nova</id>
                <published>2018-01-10T15:20:46+08:00</published>
                <updated>2020-02-11T02:51:25+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p><strong>Nova</strong> is a solar system simulator build with <strong>C++</strong> and <strong>OpenGL</strong>. Various types of objects are simulated in this program, such as Skybox, Sun(Lightsource), Planets, Asteroids(Particle Effects), and spaceship.</p><p>Several techniques and libraries are used in this program:</p><ul><li><strong>Core-profile Mode</strong> and <strong>Instanced Rendering</strong> are used to achieve better performance</li><li><code>Assimp</code> library for loading model</li><li><code>Stb_image</code> library for loading texture</li><li><code>Freetype</code> for font rendering</li></ul><h2 id="screenshots">Screenshots</h2><ul><li>Custom shader</li></ul><p><img src="https://vitalight.me/upload/2020/2/shader-02a2c3a150ad447488ee66d70c25a796.png" alt="高级星球Shader" /></p><ul><li>Self-made model: Evil robot</li></ul><p><img src="https://vitalight.me/upload/2020/2/robot-6f053700562e4906a296f84d82a3a2c2.jpg" alt="星际机器人" /></p><h2 id="download">Download</h2><ul><li>Release Date: March 2018</li><li>Source: <a href="https://github.com/vitalight/OpenGL-Solar-System">https://github.com/vitalight/OpenGL-Solar-System</a></li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Visionary - 图像处理软件]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/visionary" />
                <id>tag:https://vitalight.me,2018-01-05:visionary</id>
                <published>2018-01-05T18:10:22+08:00</published>
                <updated>2020-02-11T02:54:00+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p><strong>Visionary</strong> is a software for image processing build with <strong>C++</strong> and <strong>Qt Framework</strong>.</p><h3 id="features">Features</h3><ul><li>Real-time preview</li><li>Contrast Adjustment</li><li>Edge detection</li><li>Hough transform</li><li>Mathematical Morphology</li></ul><h2 id="download">Download</h2><ul><li>Release Date: Jan 2018</li><li>Source: <a href="https://github.com/vitalight/Visionary">https://github.com/vitalight/Visionary</a></li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Linkode - 艺术交流网站]]></title>
                <link rel="alternate" type="text/html" href="https://vitalight.me/archives/linkode" />
                <id>tag:https://vitalight.me,2017-09-13:linkode</id>
                <published>2017-09-13T18:13:12+08:00</published>
                <updated>2020-02-11T02:50:55+08:00</updated>
                <author>
                    <name>陈哔哔</name>
                    <uri>https://vitalight.me</uri>
                </author>
                <content type="html">
                        <![CDATA[<p>A website build for artist to share their works and find a job.</p><ul><li>MySQL as database</li><li>Java for backend with SSH framework</li><li>JSP and jQuery for frontend</li></ul><h2 id="screenshots">Screenshots</h2><ul><li>Portfolio page</li></ul><p><img src="https://vitalight.me/upload/2020/2/works-356f38607d134371830b92d6a2e94087.png" alt="作品界面" /></p><ul><li>Tutorial page</li></ul><p><img src="https://vitalight.me/upload/2020/2/tutorial-2f77c881eb464c38a5ba07ad5c7274fa.png" alt="教程界面" /></p><ul><li>Chat page</li></ul><p><img src="https://vitalight.me/upload/2020/2/comment-714d9c57a35646c19f17b4bc8a3e43c2.png" alt="讨论区" /></p><ul><li>Project page</li></ul><p><img src="https://vitalight.me/upload/2020/2/project-8785e4d508a14cc4bcc9fd9c84ef7873.png" alt="作品界面" /></p><ul><li>User page</li></ul><p><img src="https://vitalight.me/upload/2020/2/user-9015d8b057c7446e8bfc87bc1619ba9b.png" alt="用户信息" /></p>]]>
                </content>
            </entry>
</feed>
