亦欲以究天人之际,通古今之变,成一家之言。 ——司马迁

我叫杨春雨,来自江苏泗洪,中国科学技术大学化学物理系本科三年级在读,现在在侯中怀老师课题组做一点复杂体系的动力学理论研究以及分子动力学模拟。这是我的第一篇博客。

我将在这里分享自己的学习、探索的历程,以及对一些问题的思考。如果你想要联系我,我的邮箱是:chyyangustc@mail.ustc.edu.cn和larkyoung@foxmail.com。

应彭子骏同学邀请,在2023年4月1日和大一的同学们分享如何使用\(\LaTeX\),讲座所用的slide在此上传,除了slide上已经提及的清华大学讲座的slide,还可以参考ztx的slide,写的比我的要好不少,ztx也是国内\(\LaTeX\)推广的大佬级人物,可以期待一下他的关于LaTeX的书。林莲枝先生写过关于LaTeX规范的一个slide,大家可以看看,确实很多人学LaTeX完全是野路子,不规范的地方很多。

关于markdown部分的介绍,如果我以后有时间,可能会重写一个更加详细的版本发在个人主页上,如果没有时间,那就没有了()。

程序结构

我们先从一个最简单的Fortran程序看起

1
2
3
4
5
6
7
8
9
program HelloWorld
implicit none

! Hello World!

write(*,*) "Hello World!"
print *, "Hello Fortran!"

end program HelloWorld

当我们使用Fortran语言的时候,主程序要写在programend program之间,且program之后需要跟程序的名称,这个名称不必和文件名相同。

Fortran使用!标志注释行。implicit none的作用是要求程序不使用隐式变量声明(不然的话i,j,k,l这些会默认为整数类型)。

输入输出

在上述程序中,我们使用了write函数,这个函数接受两个参数。一个是输出的开始位置,默认为6(非默认情形我们稍后讨论),另外一个是格式化参数。Fortran中的输出函数还有print,它只接受一个参数,即格式化参数,换而言之,他只能输出到屏幕上。

read函数有两种写法read(*,*)read *,,分别类似于writeprint

输出的格式化按照如下的方式进行,输入同理。

  • Iw[.m]以w个字符的宽度来输出整数,至少输出m个数字。
  • Fw.d以w个字符文本框来输出浮点数,小数部分占d个字符宽,输出文本框的设置不足显示*号。输出不足补空格,小数不足补0。
  • Ew.d[Ee]用科学计数法,以w个字符宽来输出浮点数,小数部分占d个字符宽,指数部分最少输出e个数字。 !输出不足部分补空格,小数部分不足补0。
  • Aw 以w个字符宽来输出字符串。
  • nX 输出位置向右移动n位。

数据类型

Fortran中的数据类型有整型(integer)、实型(real)、复数型(complex)、逻辑型(logical)、字符型(character)等。

整数和实数类型的使用方式类似C语言,但是可以通过(kind=n)的形式来指定精度,当然括号中的是可选部分。

1
2
integer(kind=4) :: int_num
real(4) :: real_num

Fortran是少有的原生支持复数类型的语言,复数以类似向量的方式来表示,

1
2
3
complex :: a,b
a=(1.0,1.0)
b=(1.0,2.0)

此外还有字符串类型和逻辑类型,如果字符串类型没有初值,则必须指定长度,

1
2
character str_1='abcd'
character(len=10) str_2

如果接下来赋给str_2的值的长度大于10,则会自动截断到10。

逻辑判断类型无需多说,其使用方式为

1
2
3
logical a,b
a=.true.
b=.false.

Fortran中的数组定义有两种方式

1
2
3
integer :: student(5) 	!一维数组
integer :: a(3,3) !二维数组
integer,dimension(3,3) :: a !另一种方法

值得注意的是,Fortran中的数组索引从1开始,而且按列索引

以下是一些数组的操作的例子

1
2
3
4
5
6
integer :: a(3,3),b(3,3),c(3,3),d(5),e(5),f
a=b+c !实现矩阵相加
a=b-c !实现矩阵相减
a=matmul(b,c) !实现矩阵相乘
d(3:5)=5 !对数组部分操作 d(3)=d(4)=d(5)=5
f=dot_product(d, e) !对一维数组做向量的点乘

Fortran中可以声明可变大小的数组,只要在声明的时候加上allocatable的形容词,并注明是数组的维度,在后续需要确定大小的时候为数组配置内存空间即可。

1
2
3
4
5
6
program allocatable_array
implicit none
integer n=10
integer, allocatable :: a(:) ! 声明一个可变大小的一维数组;
allocate a(n) ! 给数组分配内存空间
end program allocatable_array

条件判断

if语句

Fortran中的if语句和C语言是类似的(其实多数程序设计语言在这里都是类似的,而且说Fortran类似C本身并不合适,因为Fortran是最古老的程序设计语言,如果某个语言与之相似,则应该该语言借鉴了Fortran,不过按照现在的现在普遍规律,多数人都应该先学C语言再学的Fortran,为了便于大家理解Fortran所以说Fortran类似C)。

1
2
3
if (logical expression) then      
statement
end if

当然还有if... (else if..). else ...的结构

1
2
3
4
5
6
7
8
9
if (logical expression 1) then 
! block 1
else if (logical expression 2) then
! block 2
else if (logical expression 3) then
! block 3
else
! block 4
end if

我们可以给if语句一个名字

1
2
3
name if (logical expression 1) then 
...
end if name

当然不止if语句有这样的功能,Fortran中的所有块都可以给一个名字。

select case语句

select case 类似于C语言中的switch case,但是功能上更加灵活,支持简单的比较判断,支持整数,字符类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
program selectCaseProg
implicit none

! local variable declaration
integer :: marks = 78

select case (marks)
case (91:100)
print*, "Excellent!"
case (81:90)
print*, "Very good!"
case (71:80)
print*, "Well done!"
case (61:70)
print*, "Not bad!"
case (41:60)
print*, "You passed!"
case (:40)
print*, "Better try again!"
case default
print*, "Invalid marks"
end select
print*, "Your marks is ", marks

end program selectCaseProg

循环

do循环

Fortran中的do循环类似于C语言中的for循环,其基本格式为

1
2
3
4
do var = start, stop [,step]    
! statement(s)

end do

var需要是一个整数,step的默认值是1。

do while循环

do while循环类似于C语言中的while循环。

1
2
3
do while (logical expr) 
statements
end do

循环的控制语句

exit语句

exit语句终止循环或select case语句,并将执行立即循环或select 下面的语句。这个时候,给循环赋一个名字就很有用,当循环是嵌套的时候,可以直接指定退出某一层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
program nestedLoop 
implicit none

integer:: i, j, k
iloop: do i = 1, 3
jloop: do j = 1, 3
kloop: do k = 1, 3

print*, "(i, j, k): ", i, j, k

if (k==2) then
exit jloop
end if

end do kloop
end do jloop
end do iloop

end program nestedLoop

circle语句

这个类似于C语言中的continue,将会跳过循环的剩余部分,开始下一段循环。

stop语句

stop语句的作用是停止程序的执行,后面可以跟着字符串和数字,表示返回值。

函数

Fortran中自定义代码片段两种:子程序subroutine和自定义函数function,他们的不同之处在于返回值和传参方式

子程序

子程序的一般结构为

1
2
3
4
subroutine name(arg1, arg2, ....)    
[declarations, including those for the arguments]
[executable statements]
end subroutine name

它没有返回值,但是子程序可以修改传入的参数的值。

自定义函数

自定义函数的一般格式为

1
2
3
4
5
function add(a,b)
datatype :: a,b
datatype :: add !声明返回数值类型
……
end

自定义函数有返回值,且传入的只是变量值,自定义函数外的变量不会受到影响。

文件操作

Fortran的文件操作比C语言要简单很多,主要依赖于open,close,read,write四个函数。

在对某一个文件进行处理之前,需要打开该文件,最简单的方法是

1
open (unit = number, file = "name")

接下来对该文件进行读写只要使用writeread函数就可以

1
2
write(number,*) "string" , num
read(number,*) "string",num

当这个文件不再被使用的时候,应该使用close关闭

1
close(unit=number)

下载vscode和TeX Live

这部分显然不需要说太多,下载vscode应该是一件非常容易的事情,只需要进入vscode的官网,下载.exe(Windows),或者.zip(Mac OS)文件,点击安装即可

Windows下 TeX Live 安装

我本人推荐使用的TeX发行版是TeX Live,所以这里也就只介绍TeX Live的安装。推荐使用清华大学的镜像,点击进入,下载texlive.iso文件即可,这个不带日期的版本默认是最新的。

下载之后打开.iso文件,点击install-tl-windows.bat安装即可。

安装过程大约需要2个小时。耐心等待即可。

系统用户名为中文的解决方案

很多同学习惯于用中文作为用户名,但是这样会导致 TeX Live 安装失败。更改 系统的 TEMP 和 TMP 这两个环境变量可以避免这样的问题。在命令行中运行

1
2
3
mkdir C:\temp
set TEMP=C:\temp
set TMP=C:\temp

然后再点击安装即可。这样修改环境变量是暂时的,等到cmd窗口关闭,环境变量会自动恢复原样。

Mac OS 下 MacTeX安装

MaxTeXTeX Live 的一个为 Mac OS 所定制的发行版,所以对于使用 Mac OS的推荐使用 MacTeX。同样我们也可以到清华镜像站下载。对于 Mac OS 用户,Homebrew 是一个非常方便的包管理程序,如果你安装了 homebrew,可以通过下面的方法安装 MacTeX

1
brew install MacTeX

vscode的配置

在已经完成了上述工作的基础之上,接下来就可以进行vscode的配置,不过和配置C语言环境相比,配置vscode要简单得多,安装插件LaTeX Workshop。然后进入设置,在文本模式中编辑设置,把以下代码复制进去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
"latex-workshop.latex.tools": [
{
"name": "xelatex",
"command": "xelatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"%DOC%"
]
},
{
"name": "xelatex-with-shell-escape",
"command": "xelatex",
"args": [
"--shell-escape",
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"%DOC%"
]
},
{
"name": "xelatex-latexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-xelatex",
"-outdir=%OUTDIR%",
"%DOC%"
]
},
{
"name": "xelatex-latexmk-with-shell-escape",
"command": "latexmk",
"args": [
"--shell-escape",
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-xelatex",
"-outdir=%OUTDIR%",
"%DOC%"
]
},
{
"name": "pdflatex",
"command": "pdflatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"%DOC%"
]
},
{
"name": "pdflatex-with-shell-escape",
"command": "pdflatex",
"args": [
"--shell-escape",
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"%DOC%"
]
},
{
"name": "pdflatex-latexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
]
},
{
"name": "pdflatex-latexmk-with-shell-escape",
"command": "latexmk",
"args": [
"--shell-escape",
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
]
},
{
"name": "latexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-pdf",
"%DOC%"
]
},
{
"name": "bibtex",
"command": "bibtex",
"args": [
"%DOCFILE%"
]
},
{
"name": "lualatex",
"command": "lualatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-shell-escape",//这个命令行在网上的Latex Workshop设置里一般没有,所以直接recipe会报错
"%DOCFILE%"
]
}
],

"latex-workshop.latex.recipes": [
{
"name": "XeLaTeX",
"tools": [
"xelatex"
]
},
{
"name": "LuaLaTeX",
"tools": [
"lualatex"
]
},
{
"name": "XeLaTeX with Shell Escape",
"tools": [
"xelatex-with-shell-escape"
]
},
{
"name": "XeLaTeX Auto",
"tools": [
"xelatex-latexmk"
]
},
{
"name": "XeLaTeX Auto with Shell Escape",
"tools": [
"xelatex-latexmk-with-shell-escape"
]
},
{
"name": "PDFLaTeX",
"tools": [
"pdflatex"
]
},
{
"name": "PDFLaTeX with Shell Escape",
"tools": [
"pdflatex-with-shell-escape"
]
},
{
"name": "PDFLaTeX Auto",
"tools": [
"pdflatex-latexmk"
]
},
{
"name": "PDFLaTeX Auto with Shell Escape",
"tools": [
"pdflatex-latexmk-with-shell-escape"
]
},
{
"name": "PDFLaTeX -> BibTeX -> PDFLaTeX*2",
"tools": [
"pdflatex",
"bibtex",
"pdflatex",
"pdflatex"
]
},
{
"name": "XeLaTeX -> BibTeX -> XeLaTeX*2",
"tools": [
"xelatex",
"bibtex",
"xelatex",
"xelatex"
]
},
{
"name": "latexmk",
"tools": [
"latexmk"
]
},
{
"name": "BibTeX",
"tools": [
"bibtex"
]
},
{
"name":"MakeIndex",
"tools":[
"makeindex"
]
},

],

//tex文件浏览器,可选项为"none" "browser" "tab" "external"
"latex-workshop.view.pdf.viewer": "tab",
//自动编译tex文件
"latex-workshop.latex.autoBuild.run": "onSave",
//显示内容菜单:(1)编译文件;(2)定位游标
"latex-workshop.showContextMenu": true,
//显示错误
"latex-workshop.message.error.show": false,
//显示警告
"latex-workshop.message.warning.show": false,
//从使用的包中自动补全命令和环境
"latex-workshop.intellisense.package.enabled": true,
//设置为never,为不清除辅助文件
"latex-workshop.latex.autoClean.run": "onFailed",
//设置vscode编译tex文档时的默认编译链
"latex-workshop.latex.recipe.default": "lastUsed",
// 用于反向同步的内部查看器的键绑定。ctrl/cmd +点击(默认)或双击
"latex-workshop.view.pdf.internal.synctex.keybinding": "double-click",
"workbench.editorAssociations": {
"*.pdf": "latex-workshop-pdf-hook"
},

部分命令已经带有了注释,可以自行修改。如果有同学想要进一步了解这些命令,可以自行查看LaTeX Workshop的文档,这里不赘述。此外还可以设置使用外部阅读器查看PDF,可以自行使用搜索引擎完成。

完成上述设置之后,就可以使用vscode编辑LaTeX了。

使用snippet和newcommad提高编辑效率

snippet就是自定义的代码补全,在vscodectrl+shift+p,搜索snippet,选择配置用户代码片段,在弹出的文本中输入即可。同时还需要再刚才的setting.json中输入"editor.snippetSuggestions": "top",

有一个网站可以自动将命令转化为snippet。读者可以自行去了解,使用snippet确实是一种非常好的提供效率的方式

Lisp

As we have noted before, Mathematica is similar to Lisp. So let us talk about some characters of Lisp before we discuss the Mathematica.

Actually, Lisp is the abbreviation for list processing. List is an object take the form of:

1
(item1,item2,item3)

The list is also named as symbolic expression. The target of the interpreter of Lisp is to get the value of each symbol expression passed to it. The compiler takes item1 as the name of the function and item2 and item3 as variables. The method was invented by Jan Łukasiewicz from Poland, so it is named as Polish notation. Despite its difficulties for human to understand, it is convenient for the computer to cope with. When we compile a program, we need to convert the source code to abstract syntax tree. So the way we write Lisp is just writing a syntax tree.

In Mathematica, the function Treeform can get a expression's syntax tree.

1
TreeForm[(a + b^n)/z == x]

Have a try, and some surprises are waiting for you. If we want to write the expression above in Lisp, then it would take the form of

1
(==,(*,(+,a,(expt,b,n)),(expt,z,-1)),x)

Actually, the kernel of Mathematica understand the expression in the same way.

1
2
In:FullForm[(a + b^n)/z == x]
Out:Equal[Times[Plus[a,Power[b,n]],Power[z,-1]],x]

The the similarity is very conspicuous.

Everything is An Expression

==Everything is An Expression== is a philosophy that both Mathematica and Lisp follow (actually, it is more proper to say Mathematica get the idea from Lisp). Now let's review the definition of expression:

  1. An atom is an expression;
  2. If are expressions, is a expression.

Then we go on to illustrate why we say everything is an expression.

1
2
In: Map[FullForm,{a+b,a-b,a*b,a/b,a^b,a==b,a!=b,a<b,a<=b,a>b,a>=b,a&&b,a||b} ]
Out: {Plus[a,b],Plus[a,Times[-1,b]],Times[a,b],Times[a,Power[b,-1]],Power[a,b],Equal[a,b],Unequal[a,b],Less[a,b],LessEqual[a,b],Greater[a,b],GreaterEqual[a,b],And[a,b],Or[a,b]}

Though, expressions like a+b,a-b and a!=b is not take the form of , but Mathematica understands them in a different way. It's also noteworthy that the expression above could be write in a more convenient way, i.e. Map[f,expr] is equivalent to f\@ expr.

Computation is Rewriting

We could find that the first principle only care about the method we use to denote the object to be computed. It doesn't take the computation itself into consideration. ==Lisp is not good at computation==, and that's why Wolfram unsatisfied with Lisp. Mathematica got its way of computation from other functional programming languages like Haskell and OCaml.

In order to understand that, let's recall how we human perform computation. Just take a integrate as an example, Firstly, we rewrite as , then we computer and , and when we computer ,we rewrite it as . To conclude, when we perform computation, we always try to simplify the formulations until they could be computed directly. And Mathematica follow the same philosophy to compute, i.e. ==pattern matching== and ==rule substitution==. As a result, in Mathematica, to compute is to rewrite. (The computational model based on patterns and rules is called a rewriting system in mathematical logic or computer science.)

Function Matters

There is no rewriting system in Lisp, and Haskell and OCaml don't take everything as list, but we still classify them into one category which is so-called functional language. Why we do that?

In Lisp, we could add a ' to prevent a list get its' value, and the we take the list as some kind of data which is manipulative. When we combine some data to a List, we could use (eval L) to force the list get its value. Then the data L be converted to executable code again. We call Code-as-Data as the philosophy of Lisp.

In Haskell, we take every category as a set. Functions between categories are just the map between sets. It's easy to combine with by the operator .. What's more, all the map from to is also a set. Notice that all the maps from to is also a set which is called . The set is defined as a set automatically. As a result, all the bivariable functions from can be viewed as a one variable function from to . This operation is called currying. Both Code-as-Data and currying can be achieved in Mathematica and that's why people group it with languages like Lisp and Haskell.

The character is so important that we call it Mathematica's zeroth principle: Function Matters, not variables.

Expression and List

Brief Structure of An Expression or List

A expression is defined as an atom or a function like . Actually, we could also take atom as a special case of when there is no independent variables. So when we discuss expression in the future, it would take the form of .

Given a expression , is named a head.

1
2
In:Head /@ {1,1/2,True,"Number",a+b,a-b,a*b,a/b,(f+g)[x1,x2,x3]}
Out: {Integer, Rational, Symbol, String, Plus, Plus, Times, Times, f + g}

Note:f\@expr is Map[f,expr]

We could find that for atom, a symbol's head is always Symbol , a number's head depends on its type and could be Integer, Rational, Real, Complex, a string's head is always String, etc. We could decide whether a expression is an atom in this manner.

1
2
3
4
myAtomQ = 
Function[ex,
MemberQ[{Symbol, Integer, Rational, Reals, Complex, String, Image},
Head[ex]]];

However, sometimes we need to deal with the parameters of a expression. Then we take them out, but what we get turns out to be only a sequence compose of several expressions, and there is no head with them. But all of expressions of Mathematica must have a head. In order to deal with a expression without head, Mathematica introduce list and all of expressions don't have a head have a head of List. The case bellow shows that when we apply List to a expression, it become a list.

1
2
3
In: ex = f[x1, x2, x3];
List @@ ex
Out:{x1,x2,x3}

List itself is also an inner function of Mathematica, and it could turn a sequence of expressions into as list. eg

1
2
In:List[1,2,3]
Out: {1,2,3}

@@, whose full name Apply, is also a functional operation and it change a expression's head. eg

1
2
3
4
In:Apply[g,h[x1,x2,x3]]
In:g@@h[x1,x2,x3]
Out:g[x1, x2, x3]
Out:g[x1, x2, x3]

There is also another type of list which is so-called Sequence. We could take sequence as a list without {} in both sides. Or we could say, list is turn a sequence into an object while sequence is something more basic.

1
2
3
4
5
6
In: ex = h[1, 2, 3]
seq = Sequence @@ ex
lst = List @@ ex
Out:h[1,2,3]
Sequence[1,2,3]
{1,2,3}

And when we want to convey the parameters of one expression to another expression, we can't get what we want because of the {}. Therefore we need to change the head of that expression to Sequence.

1
2
3
4
5
6
7
8
In: f[seq]
f[lst]
f @@ lst
f[seq, lst, 4, 5, 6]
Out:f[1, 2, 3]
f[{1, 2, 3}]
f[1, 2, 3]
f[1, 2, 3, {1, 2, 3}, 4, 5, 6]

Operations on Lists

Apart from Head and Apply , we could use the built-in function Part to visit expression inside compound expressions. It takes the form of Part[expr,number] or expr[[number]] and 0 is the head.

1
2
3
In: ex = f[x1, x2, x3];
{ex[[0]], ex[[1]], ex[[2]], ex[[3]], ex[[4]]}
Out:{f, x1, x2, x3, f[x1, x2, x3][[4]]}

As we have discussed before, the type checking of Mathematica is not so strict and as a result of there is no ex[[4]], Mathematica return us a result of f[x1, x2, x3][[4]]. It's often the case that when Mathematica doesn't know what to do with our command, it would return what it get to us.

And for nested expressions, we can take Part more than one time.

1
2
3
In: ex = f[a, g[b, c], h[d, k[e, i], j]];
ex[[3]][[2]][[2]]
Out:i

The operation could also write as ex[[3, 2, 2]]. There are many other ways to use Part, and we show this by four examples

1
2
3
4
5
6
7
8
In: ex[[-1, -2, -1]]
ex[[{2, 3}]]
ex[[1 ;; 2]]
ex[[1 ;; 3 ;; 2]]
Out:i
f[g[b, c], h[d, k[e, i], j]]
f[a,g[b, c]]
f[a, h[d, k[e, i], j]]

There are also some built-in functions for some Parts which are often used.

1
2
3
4
5
6
In: Function[op, op[f[x1, x2, x3, x4]]] /@ {First, Last, Rest, Most}
Take[f[x1, x2, x3, x4], {2, 3}]
Drop[f[x1, x2, x3, x4], {2, 3}]
Out:{x1, x4, f[x2, x3, x4], f[x1, x2, x3]}
f[x2,x3]
f[x1,x4]

For a given expression, there are two values matter. i.e. depth and length.

1
2
3
4
In: Length[f[g[x1, h[x2, x3]], x4]]
Depth[f[g[x1, h[x2, x3]], x4]]
Out:2
4

Construct a List

Like many other language, Range could be used to build a simple list.

1
Range[begin,end,step]

Only end is a must to this function. And Table, Array, Turples and Outer can be used to build a list too.

1
2
3
4
5
6
7
8
9
10
In: Table[i^2 + i + 1, {i, 10}]
Table[KroneckerDelta[i, j - 1] + t KroneckerDelta[i, j + 4], {i, 5}, {j, 5}]//MatrixForm
Out:{3, 7, 13, 21, 31, 43, 57, 73, 91, 111}
{{0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 0, 1}, {t, 0, 0, 0, 0}}
In: Array[#^2 + # + 1 &, 10]
#^2 + # + 1 & /@ Range[10]
Out:{3, 7, 13, 21, 31, 43, 57, 73, 91, 111}
{3, 7, 13, 21, 31, 43, 57, 73, 91, 111}
In: Array[f, 5, 2, h]
Out:h[f[2],f[3],f[4],f[5],f[6]]

Tuples[List,n] means use members of the list to construct lists of n numbers and combine all possible answer to one list.

1
2
3
4
5
6
In: Tuples[Range[3], 3]
Out:{{1, 1, 1}, {1, 1, 2}, {1, 1, 3}, {1, 2, 1}, {1, 2, 2}, {1, 2, 3}, {1,
3, 1}, {1, 3, 2}, {1, 3, 3}, {2, 1, 1}, {2, 1, 2}, {2, 1, 3}, {2,
2, 1}, {2, 2, 2}, {2, 2, 3}, {2, 3, 1}, {2, 3, 2}, {2, 3, 3}, {3, 1,
1}, {3, 1, 2}, {3, 1, 3}, {3, 2, 1}, {3, 2, 2}, {3, 2, 3}, {3, 3,
1}, {3, 3, 2}, {3, 3, 3}}

Outer[f,list1,list2] group all the possible combinations of members of list1 and list2 and use them as the independent variables of f.

1
2
In: Outer[f, Range[3], Range[2]]
Out: {{f[1, 1], f[1, 2]}, {f[2, 1], f[2, 2]}, {f[3, 1], f[3, 2]}}

Search and Sort

MemberQ[expr,i] is used to judge whether i is a member of expr, while FreeQ[expr,i] is used to judge whether expr has a sub-expression which matches i. Both of them will return False, when i is the head of the expr.

1
2
3
4
5
In: ex = f[x1, x2, x3, x4];
Function[i, MemberQ[ex, i]] /@ {f, x1, x2, x3, x4, x5, x6}
Function[i, FreeQ[ex, i]] /@ {f, x1, x2, x3, x4, x5, x6}
Out:{False, True, True, True, True, False, False}
{False, False, False, False, False, True, True}

And we could appoint the depth of searching for them.

Count[expr,i] is used to calculate how many times i appear in expr, appoint depth is also powered.

1
2
3
In: euler = (a + b^n)/n == x;
{Count[euler, n], Count[euler, n, Infinity]}
Out:{0,2}

Use n means searching from 0th layer to nth layer, while use {n} means only search nth layer.

1
2
3
4
5
6
In: Position[euler, n]
Function[level, Position[euler, n, level]] /@ {0, 1, 2, 3, 4}
Function[level, Position[euler, n, level]] /@ {{3}, {4}}
Out:{{1, 1, 2, 2}, {1, 2, 1}}
{{}, {}, {}, {{1, 2, 1}}, {{1, 1, 2, 2}, {1, 2, 1}}}
{{{1, 2, 1}}, {{1, 1, 2, 2}}}

And we could use Select to choose members by self-defined rules.

1
2
In: Select[Prime /@ Range[10], OddQ]
Select[Prime /@ Range[10], Mod[#, 4] == 1 &]

This is a note to the course "Core Language of Mathematica" given by Siqi Liu in Bilibili. There is also a PDF version in Chinese.

Introduction

Why Mathematica?

Firstly, we talk about why we use Mathmatica. The question is quite open and people in different areas will give different answers. So we begin with the way of a scientific worker workes:

  1. Find a question which seems solvable;
  2. Try to use some examples to understand the question;
  3. Come up with a scheme which seems to be able to solve the question;
  4. If the scheme succeeds, then the problem is solved;
  5. If the scheme fails, return to 2;
  6. If all the schemes fail, return to 1.

So, scientific workers would use plenty of simulation and experiments. In order to enhance the efficiency of work, we get the machine to share some of our work. Specifically, for people who need computation, we should get the computer to help us. So we need programming.

And then we need to choose the most efficient way of programming. The efficiency of programming is decided by the time we spend writing and using it. In most cases, the time of running a program for once is far shorter than the time we need to write it. And usually, we scientists would run the program only once. As a result, the most efficient way is just the fastest way to write a program.

The language of Mathematica is close to natural language and it has many built-in functions and well developed documents, which makes it very suitable and easy to write a program, thus shortening the time we need to develop a program.

The History of Mathematica

We could learn about the history of Mathematica in the web site Mathematica—Three Decades of Contributions, Invention, Discovery, and Education (wolfram.com), and as Mathematica is developed by C, it is similar to C in some respects. When Wolfram developed the Mathematica, he got many inspirations from Lisp which lead to the similarity between them.

The Mathematica function as calculator

The calculation in Mathematica will always be performed in high precision and it could function as a calculator itself. Like:

1
2
3
4
In: 1+1
Out: 2
In: Sin[Pi/2]
Out: 1

But its capacity is far more than the arithmetic operation and call simple functions. We could use Expand to perform expansion, Factor to perform factorization, Solve to solve equations. Some functions of advanced mathematics are also equipped, like Dsolve to solve differential equations, D to perform derivation, Limit to get the limit of a function, Sum to calculate the series.

When you are performing a series of computations, if you worry about the contamination of variables, you could reopen the kernel.

Apart from the simple functions we have noted above, Mathematica has a lot of advanced built-in functions. For example, we could use Import to get data from the internet. And we could also deal with pictures and music with Mathematica, capture stock data from the Internet to achieve quantitative trading.

Notations

In Mathematica both the functions and constants use the Upper Camel Case. As a result, to avoid using the reserved words, we could use the Lower Camel Case. The comments are written in the form of (* comments *). If an element has got an value, it would be black and if not it would be blue.

Some Other Information about This notes

The notes is from the course "Core Language of Mathematica" taught by Siqi Liu, Tsinghua University. And as the document of Mathematica is so strong, we don't talk about the details of many functions unless we need to do that. We mention the usage of the function and readers could just read the details of the function in the document of Mathematica.

We highly recommend our readers to use genuine software. The price is not so unaffordable. If you think it is quiet costive, there are still a way to use the Mathematica legally. In May 2019, Wolfram put forward Wolfram Engine, and it is free of charge. And there many ways to add a notebook to the kernel. I recommend this passage 在 VS Code 中使用 Wolfram 笔记本 - 知乎 (zhihu.com).

The Principle of Mathematica

In Mathematica, there are two fundamental principles. Firstly, everything is a expression. Secondly, computation is just rewriting.

In Mathematica, numbers, strings and symbols are called atom. An atom is a expression and if are expressions, is a expression.

And when we perform computation in Mathematica, what we do is just get a repeatable regime in what we need to compute and interpret it to Mathematica. Thus, rather than variables, what we actually care about is the functions. i.e. Mathematica's zeroth principle: functions matter, not variables.

Basic Grammar

In this section, we will talk about the basic grammar of writing a Mathematica programm.

Type Checking

The type checking for Mathematica is not strict, for example:

1
2
In: Sin["I'm a String!"]
Out: Sin[I'm a String!]

The less stricter the type checking, the more flexible the programming. Of course, it may incur errors. But usually a Mathematica program is short, so developers could check the error by themselves.

We will see some skills base on the loose type checking of Mathematica in later sections.

Condition

The If of Mathematica take the form of If[conditional judgement,True's opertaions, Else's operations, Unevaluated' operations].

For example:

1
2
If[a==b,Print["Then"],Print["Else"],Print["Unevaluated"]]
If[a === b, Print["Then"], Print["Else"], Print["Unevaluated"]]

In Mathematica, == means equal while === means sames.

Circle

Subroutine

关于陶瓷时间

比较合适的时间是每年的一月份,刚好考完期末,时间比较充裕,而且这个时候教授们也都处理完了或者快处理完了去年的招生事宜。最好在一到二月份解决,再往后签证的时间可能比较紧迫,也可能你想找的教授以及招到了不少学生了。

也不推荐太早,如果你头年10月就找到了暑研,你会发现接下来的八九个月如何和教授保持联系还是一件蛮头疼的事情。

关于择校

暑研申请没有什么成本,而且是自费(USTC Fellowship)所以大胆申请就好,突出一个人有多大胆,地有多大产。

直接去六大、Yale、JHU等学校主页扒它们的老师就好,我自己看的时候会习惯了解一下这个老师组里面是否有亚裔。不过绝大多数教授组里面都是有的。

除此以外,可以问一问组里面的博士师兄,或者直接问自己的老板,如果老板有一个不错的connection能够直接把你扔出去那就再好不过了。就算不能,他们对做的比较好的组和他们是否喜欢中国学生也是有一些了解的。也可以问一问学长学姐(我也可以,欢迎联系chyyangustc@mail.ustc.edu.cn)。和学长学姐交流能够少走不少弯路,出国如果是自己diy,一定不要闭门造车。

关于邮件陶瓷

遇到感兴趣的直接发邮件,可以认真了解他的研究之后再好好写一份邮件、也可以大概了解之后按照模板发(半海套)。

不过大多数时候可能你花了好长时间读懂了他的几篇文章,然后结合自己的经历写了很长的文章,然后在人家的spam里面,或者人家看到了,但是不回复,这种情况还是蛮打击人的。而且多数情况下,想招的自然会招,不想招的也不会因为你很优秀就招你,所以我觉得最好的方式还是半海套。

当然,暑研的回复率低实在是太正常了,因此如果连发三四封邮件没人回复先别气馁。

在看教授课题组主页的时候(如果有的话),可以关注一下有没有USTC的学长、学姐,可能会有USTC的学长学姐在他们那边读博、做博后。这种情况可以联系一下,万一能说上一句话呢。一定要善用校友资源,我们年级有两位同学通过科大老学长申请到了Harvard的暑研。

除此以外,如果教授给你回复了,但是拒绝了你,给出了理由是要去旅游之类的。当然不排除完全是礼貌性的拒绝理由,但是最好还是给一个礼貌的回复。比如:I am really interested in your research and hope to get admitted into your group when I apply for the PhD. 万一明年真的申请他了,有个脸缘总是好事情。

学校&教授推荐以及避雷

推荐

我自己想要申请的方向主要是分子模拟,当然电子结构计算也可以接受。最后申请的是芝加哥大学的Greg Voth,不过芝大的暑研确实蛮麻烦的,一方面要收学费($1400),另外一方面流程上比较繁琐要推荐信、要托福。而且如果你不是按照他们的学期取得,你的学费就double了,夏季学期从6.12到9.25,秋季是9.26到12.6,总的来说时间的契合度有点低。可以优先考虑其他学校(如果能够套到的话)。

此外,如果想做电子结构计算的话,UWM的Yang Yang是一个很好的选择,人非常的nice。我原本以为Voth不会回复我了,就联系了他,他非常热情。但是就在发邮件给他的第二天,Voth回复了我,考虑到Voth的工作和我的方向和兴趣都更加契合一些,我最后还是选择了Voth,感觉很对不起他的热情。发邮件给他解释了之后,他给我回复了:“No worries at all. Good luck with your summer intern”。人确实非常nice,非常推荐做电子结构计算的同学考虑一下。

避雷

再说说避雷,主要避雷西北大学的Todd,他已经鸽掉了我们组的两位同学了。邮件联系之后要面试,面试先拖一个月,面试结束过了二十天告诉你他不想要你。从各种意义上说都有点不太合适。

所以陶瓷的过程中一定注意这样的老师养鱼(我猜是在养🐟,也可能只是拖沓),毕竟陶瓷最好的窗口期就一两个月,在一个老师身上花了两个月就结束了。因此尽可能选做事比较干脆的老师。

其他

托福最好早点考,最好在大二下学期和大三上的时候能够有一份90+的成绩单,因为暑研申请的时候可能有一些学校会需要。

科大的量子化学课程主要讲授群论在结构化学领域的应用。从较为基本的分子对称性判断、分子点群的划归到分子点群的特征标表以及其在分子结构上的应用。

这门课程本身可能略有抽象,但是并不困难。不过科大化院很多课程最大的问题似乎都是,没有一个合适的教材或者参考书。因此,我在这里将我在2022年春学期的笔记上传,希望稍微能有一点用处。

0%