git

使用案例

新建仓库

   git init .

下载远程仓库

   git clone --depth=1 https://...

--depth=1 表示只下载一部分历史

gitignore:忽略文件

gitignore

添加本地更改

   git add --all 
   git commit -m "sth"

从远端获取更新

   git pull

推送更新到远端

   git push origin master

使用代理

   git config --global http.proxy http://proxy.mycompany:80

记录里显示中文

   git config --global core.quotepath false

设置默认编辑器

   git config --global core.editor "vim"

git-lfs: 用 git 管理大文件

安装

从包管理器中安装 git-lfs ,windows版本已经包含了

使用

  1. 对账户启用 git lfs install
  2. 对仓库设置要追踪的文件类型 git lfs track "*.psd"
  3. 把配置文件加到追踪列表里 git add .gitattributes

常用大文件

gitattributes

   git lfs track "*.png"
   git lfs track "*.jpg"
   git lfs track "*.jpeg"
   git lfs track "*.gif"

   git lfs track "*.mp4"
   git lfs track "*.mpeg"
   git lfs track "*.mkv"

.gitattributes 文件内容为

*.pdf   filter=lfs diff=lfs merge=lfs -text
*.jpg   filter=lfs diff=lfs merge=lfs -text
*.jpeg  filter=lfs diff=lfs merge=lfs -text
*.png   filter=lfs diff=lfs merge=lfs -text
*.gif   filter=lfs diff=lfs merge=lfs -text
*.ico   filter=lfs diff=lfs merge=lfs -text
*.eps   filter=lfs diff=lfs merge=lfs -text
*.bmp   filter=lfs diff=lfs merge=lfs -text
*.psb   filter=lfs diff=lfs merge=lfs -text
*.tiff  filter=lfs diff=lfs merge=lfs -text
*.wbmp  filter=lfs diff=lfs merge=lfs -text
*.webp  filter=lfs diff=lfs merge=lfs -text

git-remote-dropbox: 用 Dropbox 做私人仓库

安装

  1. 安装 pip install git-remote-dropbox
  2. 在网站上生成 OAuth 2 密钥 app console
  3. 把密钥存在文件 /.config/git/git-remote-dropbox.json or ~/.git-remote-dropbox.json ~{"default":"token"}
  4. 配置别名 git config --global alias.dropbox '!git-dropbox-manage'

使用

clone 已有仓库

    git clone "dropbox:///path/to/repo"

创建远程仓库

    git remote add origin "dropbox:///path/to/repo"

pdftk: The PDF Toolkit

添加目录与修改元信息

从pdf中提取目录和元信息

   pdftk C:\Users\Sid\Desktop\doc.pdf dump_data output C:\Users\Sid\Desktop\doc_data.txt

给pdf添加或更新目录

   pdftk C:\Users\Sid\Desktop\doc.pdf update_info C:\Users\Sid\Desktop\doc_data.txt output C:\Users\Sid\Desktop\updated.pdf

目录文件格式:

   BookmarkBegin
   BookmarkTitle: PDF Reference (Version 1.5)
   BookmarkLevel: 1
   BookmarkPageNumber: 1
   BookmarkBegin
   BookmarkTitle: Contents
   BookmarkLevel: 2
   BookmarkPageNumber: 3

其中字符应编码成 html entitle 的样子。 可以用 https://tool.oschina.net/encode , https://www.online-toolz.com/tools/unicode-html-entities-convertor.php 这里的 Native/Unicode 转换工具。

或者python

   u"阿斯顿".encode('ascii', 'xmlcharrefreplace')

   def utf8_to_ascii_xml(filename):
       with open(filename,'r',encoding='utf-8') as fi:
           lines = fi.readlines()
           lines_ascii = [x.encode('ascii', 'xmlcharrefreplace') for x in lines]
       with open(f"{filename}.ascii", 'wb') as fi:
           fi.writelines(lines_ascii)

常用正则替换

s/\(.*\),\(.*\)/BookmarkBegin\nBookmarkTitle: \1\nBookmarkLevel: 2\nBookmarkPageNumber: \2/

添加目录的示例流程

   # import
   import pytesseract
   from PIL import Image
   import numpy as np
   import pandas as pd
   import re

   # 利用 OCR 生成目录
   print(pytesseract.image_to_string(Image.open('a.png')))

   # 手动编辑目录,使用 orgmode 的表格
   data = pd.read_csv("a.txt", sep="|")
   darr = np.array(data)
   darr[:,1] = [i.strip() for i in darr[:,1]]
   darr[:,2] = [i.strip() for i in darr[:,2]]
   darr[2:,3] = darr[2:,3]+9
   data = pd.DataFrame(darr[:,1:-1])
   data

   # 生成目录格式并保存
   block = """BookmarkBegin
   BookmarkTitle: {title}
   BookmarkLevel: {level}
   BookmarkPageNumber: {page}
   """
   txt = ""
   for line in darr:
       index = line[1]
       title = line[2]
       page = line[3]
       if index == '' or index[-1] == '.':
           level = 1
       else:
           level = 2
           txt += block.format(title=f"{index} {title}", level=level, page=page)

   with open("b.txt",'w') as fi:
       fi.writelines(txt)

合并pdf文件

  pdftk in1.pdf in2.pdf cat output out1.pdf

djvu to pdf

  1. djvulibre
  ddjvu -format=pdf -quality=85 -verbose a.djvu a.pdf

分割文件

pdftk in.pdf burst output out_%04d.pdf

Early History of Bosonization

本文是 A. O. Gogolin, A. A. Nersesyan, A. M. Tsvelik 的 "Bosonization and Strongly Correlated Systems" 一书的序言,简短地回顾了强关联领域和1990年以前的玻色化方法的历史,对了解强关联领域很有帮助。

玻色化的早期历史

ssh

SSH 端口转发

本地转发: 本地访问远程

本地转发,顾名思义就是把本地主机端口通过待登录主机端口转发到远程主机端口上去。

本地转发通过参数 -L 指定,格式:-L [本地主机:]本地主机端口:远程网络主机:远程网络主机端口。加上ssh待登录主机,这里就有了三台主机。

举例:~ssh -L 0.0.0.0:50000:host2:80 user@host1~ 。这条命令将host2的80端口映射到本地的50000端口,前提是待登录主机host1上可以正常连接到host2的80端口。

畅想一下这个功能的作用:

  1. 因为本地的mysql更顺手,想用本地的mysql客户端命令连接受限网络环境的mysql服务端。
  2. 本地安装了开发工具,想用这个开发工具连接受限网络环境中某个服务的远程调试端口。

远程转发: 远程访问本地

远程转发是指把登录主机所在网络中某个端口通过本地主机端口转发到远程主机上。

远程转发通过参数 -R 指定,格式:-R [登录主机:]登录主机端口:本地网络主机:本地网络主机端口。

举例:~ssh -R 0.0.0.0:8080:host2:80 user@host1~ 。这条命令将host2的80端口映射到待登录主机host1的8080端口,前提是本地主机可以正常连接host2的80端口。

畅想一下这个功能的作用:

  1. 本地网络中有一个http代理,通过这个代理可以上外网,因此通过这条命令将这个http代理映射到待登录主机的某个端口,这样受限网络环境中所有其它服务器即可使用这个http代理上外网了。
  2. 在本机开发了一个web应用,想拿给别人测试,但现在你却处在内网,外网是无法直接访问内网的主机的,怎么办!?很多人可能会说,找台有公网IP的主机,重新部署一下就行了。这样可行,但太麻烦。然而自从你了解了ssh的远程转发之后,一切都变得简单了。只需在本地主机上执行一下上面例子的命令即可实现外网访问内网的web应用。

注意:

  1. sshdconfig里要打开AllowTcpForwarding选项,否则-R远程端口转发会失败。
  2. 默认转发到远程主机上的端口绑定的是127.0.0.1,如要绑定0.0.0.0需要打开sshdconfig里的GatewayPorts选项。这个选项如果由于权限没法打开也有办法,可配合ssh -L将端口绑定到0.0.0.0,聪明的你应该能想到办法,呵呵。

动态转发

相对于本地转发和远程转发的单一端口转发模式而言,动态转发有点更加强劲的端口转发功能,即是无需固定指定被访问目标主机的端口号。这个端口号需要在本地通过协议指定,该协议就是简单、安全、实用的 SOCKS 协议。

动态转发通过参数 -D 指定,格式:-D [本地主机:]本地主机端口。相对于前两个来说,动态转发无需再指定远程主机及其端口。它们由通过 SOCKS协议 连接到本地主机端口的那个主机。

举例:~ssh -D 50000 user@host1~ 。这条命令创建了一个SOCKS代理,所以通过该SOCKS代理发出的数据包将经过host1转发出去。

怎么使用?

  1. 用firefox浏览器,在浏览器里设置使用socks5代理127.0.0.1:50000,然后浏览器就可以访问host1所在网络内的任何IP了。
  2. 如果是普通命令行应用,使用proxychains-ng,参考命令如下:

          brew install proxychains-ng
          vim /usr/local/etc/proxychains.conf # 在ProxyList配置段下添加配置 "socks5 	127.0.0.1 50000"
          proxychains-ng wget http://host2 # 在其它命令行前添加proxychains-ng即可
    
  3. 如果是ssh,则用以下命令使用socks5代理:

          ssh -o ProxyCommand='/usr/bin/nc -X 5 -x 127.0.0.1:5000 %h %p' user@host2
    

畅想一下这个功能的作用:

  1. 想访问受限网络环境中的多种服务
  2. FQ
  3. ……

免密码登录

在本地机器生成密钥对

   ssh-keygen -t rsa

根据提示设置文件名和密码

授权登录

将公钥追加到目标服务器的 $HOME/.ssh/authorized_keys 文件中,该文件的权限应为 600.ssh 目录权限应为 700

   touch ~/.ssh/authorized_keys
   chmod 600 ~/.ssh/authorized_keys
   cat ~/.ssh/a_rsa.pub >> ~/.ssh/authorized_keys

测试一下

   ssh username@localhost

配置别名

~/.ssh/config 中配置别名,就不用记 ip 了。

  # 指定使用 bash 登录
  Host thbash
      HostName 10.0.0.101
      User username
      RequestTTY yes
      RemoteCommand bash

  # 指定使用 zsh 登录
  Host th
      HostName 10.0.0.101
      User username
      RequestTTY yes
      RemoteCommand zsh

  # 最基本的设置
  Host group1
      Hostname 10.0.5.90
      User username

systemd

systemctl: 管理服务

  • systemd 中的服务后缀名 .service 可以不写,会自动补全。
  • systemd 中把服务称作 unit , unit 有多种类型包括 .service, .target

列出服务

   # 查看系统所有安装的服务项
   systemctl list-unit-files --type=service

   # 查看系统所有运行的服务项
   systemctl list-units --type=service

   # 查看系统所有开机自启动的服务项
   systemctl list-unit-files --type=service | grep enabled

查看特定服务

   # 查看指定服务项状态
   systemctl status <服务项名称>

   # 查看服务项的依赖关系
   systemctl list-dependencies <服务项名称>

查看系统状态

   # 查看系统启动耗时
   systemd-analyze

   # 查看各项服务启动耗时
   systemd-analyze blame | grep .service

管理服务

   # 启动服务
   systemctl start <服务项名称>

   # 停止服务
   systemctl stop <服务项名称>

   # 重启服务
   systemctl restart <服务项名称>

   # 重新读取配置文件
   # 如果该服务不能重启,但又必须使用新的配置,这条命令会很有用
   systemctl reload <服务项名称>

   # 使服务开机自启动
   systemctl enable <服务项名称>

   # 使服务不要开机自启动
   systemctl disable <服务项名称>

   # 禁用服务
   # 这可以防止服务被其他服务间接启动,也无法通过 start 或 restart 命令来启动服务。
   systemctl mask <服务项名称>

   # 不再禁用服务
   systemctl unmask <服务项名称>

   # 重新读取所有服务项
   # 修改、添加、删除服务项之后需要执行以下命令。
   systemctl daemon-reload

编写简单的服务

服务文件都存放在 /etc/systemd/system/ 中,后缀名为 .service

简单的自启动脚本

  • Type=simple 表示启动并一直运行
  • ExecStart=/... 表示要执行的命令,路径要写全
  • WantedBy=multi-user.target 表示当用户能登录的时候就该启动这个服务了
  • User=name 表示运行程序时使用的用户,默认为 root
   [Unit]
   Description=My Startup

   [Service]
   Type=simple
   ExecStart=/path/to/server --server

   [Install]
   WantedBy=multi-user.target

配置自启动 jupyterlab

/etc/systemd/system/jupyterlab.service

   # start jupyter lab
   [Unit]
   Description=jupyter lab
   After=nginx.target

   [Service]
   Type=simple
   Environment="PATH='/home/username/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games'" "PYTHONPATH='/home/username/.local/bin:/usr/lib/python39.zip:/usr/lib/python3.9:/usr/lib/python3.9/lib-dynload:/home/username/.local/lib/python3.9/site-packages:/usr/local/lib/python3.9/dist-packages:/usr/lib/python3/dist-packages:/home/username/.local/lib/python3.9/site-packages/IPython/extensions:/home/username/.ipython'"
   ExecStart=/home/username/.local/bin/jupyter lab --LabApp.app_dir=/home/username/.local/share/jupyter/lab --notebook-dir=/home/username/Projects --allow-root --config=/home/username/.jupyter/jupyter_lab_config.py

   [Install]
   WantedBy=multi-user.target

配置自动挂载

配置文件路径: /etc/systemd/system/path-to-dir.mount

注意:文件名必须是挂载路径名,例如要把 /dev/sdb1 挂载到 /mnt/sds ,配置文件应该叫做 mnt-sds.mount

   [Unit]
   Description=mount 

   [Mount]
   What=/dev/sdb1
   Where=/mnt/sds
   Options=defaults

   [Install]
   WantedBy=local-fs.target

问题

用户定义服务

  • 命令使用 systemctl --user 剩下一样。
  • 配置文件放在 $HOME/.config/systemd/user
  • 然后执行一次 loginctl enable-linger username 让开机时自启动用户

samba 文件共享

Samba 基本配置

安装 Samba

   apt install samba

添加组和用户

假定已经有一个本地用户 mylocaluser

   # 创建 smb 的组
   /usr/sbin/addgroup smbgroup
   # 把用户加到组里
   /usr/sbin/usermod -aG smbgroup mylocaluser
   # 设置用户的远程密码,可以与本地登录密码不同
   smbpasswd -a mylocaluser

配置文件

首先一定要备份一份

   cp /etc/samba/smb.conf /etc/samba/smb.conf.backup

配置文件修改如下,没有的项目就加进去,已有的就修改一下

   [global]

   # 允许用户登录
   security = user

   [homes]

   read only = no

如果要加入其它登录地址,例如 smb://ip/newport 就如下配置

   [newport]
   path = /path/to/files
   valid users = @smbgroup
   guest ok = no
   writable = yes
   browsable = yes

软链接权限

从别处软链接过来的文件夹打不开,因为没有配置软链接的权限,只要在 [global] 里加入下面的内容就行了。

参考:这个博客

  [global]
  wide links = yes
  symlinks = yes
  unix extensions = no

Gram-Schmidt Orthogonalization

Gram-Schmidt 正交化方法

把一组向量正交化的常用方法就是 Gram-Schmidt 正交化过程。 这个过程基于投影 $$ \mathrm{proj}_u(v) = \frac{\langle u,v \rangle}{\langle u , u \rangle} u $$ 每一次迭代得到一个与之前所有矢量都正交的新矢量 $$ \begin{array}{lll} b_1 &=& a_1 \\ b_2 &=& a_2 - \mathrm{proj}_{b_1}(a_2) \\ b_3 &=& a_3 - \mathrm{proj}_{b_1}(a_3) - \mathrm{proj}_{b_2}(a_3) \\ b_k &=& a_k - \sum_{i=1}^{k-1}\mathrm{proj}_{b_i}(a_k) \end{array} $$

In [1]:
import numpy as np
In [2]:
def proj(u, v, do_norm=False):
    if do_norm:
        result = np.vdot(u,v) / np.linalg.norm(u,u) * u
    else:
        result = np.vdot(u,v) * u
    return result.flatten()
In [3]:
def gram_schmidt(A):
    b = A.copy()
    b[:,0] = b[:,0] / np.linalg.norm(b[:,0])
    for i in range(1, A.shape[1]):
        b[:,i] = (b[:,i] 
                  - np.sum(np.apply_along_axis(
                      lambda u: proj(u, b[:,i]), 
                      0, 
                      b[:,:i]),
                           axis=1).flatten())
        b[:,i] = b[:,i] / np.linalg.norm(b[:,i])
    return b
In [4]:
a = np.random.rand(4,4)
b = gram_schmidt(a)
In [5]:
from itertools import combinations
for i,j in combinations(range(4),2):
    print(np.isclose(b[:,i] @ b[:,j], 0))
True
True
True
True
True
True
In [ ]:
 

Power Method for Eigenvalues

幂法:矩阵本征值迭代求解的基本方法

基本的幂法:求矩阵的最大本征值

$$ Ax^{(k)} = x^{(k+1)} $$

只要把任何一个初始随机向量反复地被一个矩阵作用,同时除以一个足够大的数保证不超过数值精度,那么最终的收敛结果就是矩阵的最大本征矢。

这种方法可行的原因是,矩阵可以看做是一个线性变换,对任何一个向量连续地作用同一个变换的结果,总是会让这个向量趋近于变换的主向量,也就是矩阵的最大本征值对应的本征矢。

In [1]:
import numpy as np
In [2]:
def power_iteration(A, num_simulations: int, v0=None):
    if v0 is None:
        v = np.random.rand(A.shape[1])
    else: 
        v = v0
        
    for _ in range(num_simulations):     
        v = A @ v / np.max(v)
    return v
In [3]:
a = np.random.rand(4,4)
e2,v2=np.linalg.eig(a)
ei2 = e2.argmax()
e2[ei2], v2[:,ei2] / np.linalg.norm(v2[:,ei2])
Out[3]:
((2.1973691032607885+0j),
 array([0.54317076+0.j, 0.56821252+0.j, 0.28769568+0.j, 0.54711174+0.j]))
In [4]:
v1 = power_iteration(a, 1000)
(a @ v1 / v1)[0], v1/ np.linalg.norm(v1)
Out[4]:
(2.197369103260788, array([0.54317076, 0.56821252, 0.28769568, 0.54711174]))

反幂法:求矩阵的最小本征矢

与幂法完全相同,只不过迭代的是矩阵的逆,显然矩阵的逆的最大本征值就是原矩阵的模最小的本征值。 $$ A^{-1}x^{(k)} = x^{(k+1)} $$ 不过由于矩阵求逆计算复杂度很大,可以把它转化成求线性方程组: $$ A x^{(k+1)} = x^{(k)} $$

In [5]:
def inverse_power_iteration(A, num_simulations: int, v0=None):
    if v0 is None:
        v = np.random.rand(A.shape[1])
    else: 
        v = v0
        
    for _ in range(num_simulations):  
        v = np.linalg.solve(A, v) 
        # v = np.linalg.inv(A) @ v
        v = v / np.max(v)
    return v
    
In [6]:
a = np.random.rand(4,4)
e2,v2=np.linalg.eig(a)
ei2 = np.abs(e2).argmin()
e2[ei2], v2[:,ei2] / np.linalg.norm(v2[:,ei2])
Out[6]:
(0.0934634074161824,
 array([ 0.06236468, -0.34577788,  0.87179586, -0.34135067]))
In [7]:
v1 = inverse_power_iteration(a, 1000)
1/ (np.linalg.inv(a) @ v1 / v1)[0], v1/ np.linalg.norm(v1)
Out[7]:
(0.09346340741618211,
 array([ 0.06236468, -0.34577788,  0.87179586, -0.34135067]))
In [ ]:
 

nikola: static site generator

Nikola: 基本用法

Nikola 是一个 python 写的静态博客生成器。参见官网getnikola 。主要的特色是原生支持 orgmode 和 ipynb 格式作为博客,看起来很方便。

备查资料

时间的格式

date +"%F %T UTC%:z"

博客模板

tags 用逗号分隔, category 被看做一个词。

orgmode

#+BEGIN_COMMENT
.. title: nikola: static site generator
.. slug: nikola-static-site-generator
.. date: 2020-12-19 15:19:12 UTC+08:00
.. tags: python, blog
.. category: tools
.. link: 
.. description: 
.. type: text
.. has_math: true

#+END_COMMENT

blog here.

ipynb

   "metadata": {
     "nikola": {
      "title": "Power Method for Eigenvalues",
      "slug": "power-method-for-eigenvalues",
      "date": "2020-12-19 15:20:52 UTC+08:00",
      "tags": "Numerical Algorithm,Linear Algebra",
      "category": "Algorithm",
      "link": "",
      "description": "",
      "type": "text"
     }
   }