三月十日杂感

zh

我还是说出了那句话。我们走到一起,已经有七天了。

起初并没有表白的想法。当晚看完电影后,两人都有微妙的感觉,但直到最后也没有表露心意。「就当做又一次平常的约电影好了」目送她进楼时我想。看电影时没有说出来,她回去了我就更说不出来了——我认为我们当时还是普通朋友关系,表白显得太唐突了。我兴奋又失落地回到宿舍。兴奋的是我们之间的关系貌似又近了一些,失落的是这样下去大概率是没有结果的。

但当晚,她接连发了几条动态,内容和语气都暗示了她对我的好感,只是和我一样,缺乏勇气。两个相互有好感却又没有恋爱经验的人(当然这是我后来知道的),就要这样还未开始便结束了彼此的关系,这怕是上天对胆小鬼的惩罚吧。

READ MORE

Visualizing Correlation

en

Say we have a matrix A of shape N x M , which can be viewed as a collection of N vectors of shape 1 x M . The code below gives us the correlation matrix of A :

A_corr = np.corrcoef(A)  # shape: (N, N)

To visualize it, just use plt.matshow(A_corr) .

If N is so large that the figure could not provide a clear insight, we might alternatively use histograms like this:

def corr_matrix_to_array(corr_mat):
N = corr_mat.shape[0]
return np.array([corr_mat[i][j] for i in range(1, N) for j in range(i + 1, N)])

plt.hist(corr_matrix_to_array(A_corr), bins=np.linspace(-1, 1, N_bins))
READ MORE

三月一日杂感

zh

我是怎么想的呢?我应该是喜欢她了。她看起来像是一个单纯的女孩,长得可爱,有些呆,总是一副样子很努力的样子。我们有共同的话题,应该可以谈得来,虽然谈话常因为关系不够深入而戛然而止。

她是怎么想的呢?她专心起来很少注意周围,我们有许多次出现在同一个场所,但她很少注意到我。看她朋友圈,大学时应该是有过被人纠缠的烦恼。她成绩不是很理想,为未来烦恼着。

我希求的是一段相互平等的关系,两人的能力和价值观不应该有太大的差距,两人的走近不应该妨碍各自的理想。我不希望我的另一半为了我而放弃自己一直追求的东西。伴侣就是伴侣,不是任何一方的附属品,也不应被任何一方「占有」。如果坚持这个理念,我们的关系想来是不会长久的,至少我走的路,我要去的地方,她不会想去。

那么,就让这段关系不要开始?这或许是一个好选择。我们的认识源于偶然,一年中保持着模糊的朋友关系。进一步发展,如果她不接受,那我就会陷入尴尬的境地;就算接受,毕业时也是要告别的。没有开始,就不会有结束。

但或许,我只是个胆小鬼罢了。

天性の弱虫さ

READ MORE

二月十一日杂感

zh
mybirth:bPNCBXyPaSNUzw/pnDHCvg==:XmV/Km36hgVGWzBaxi/vSA==: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
**THIS CONTENT IS ENCRYPTED**
 
DECRYPTING...
READ MORE

一月二十六日杂感

zh

小姑躺在床上,脸色苍白。一根管子从胸口伸出来,随着呼吸剧烈起伏着。长长的管子在床下绕了一圈,接上了一个白色塑料桶,里面尽是浑浊的黄色液体。病床对面坐着阿伯,一脸忧愁的样子。

我顿时感到有些难过——但也仅此而已。这感觉像是一种怜悯,却不是因为血缘,而是来自本性深处,对病危的同物种的怜悯。换句话说,如果躺在面前的是一个素未谋面的人,我的怜悯不会因此减少半分。这么说很残忍,但确实是我内心的真实写照。这种想法当然没有向任何人透露过,可在自己的博客我不想隐瞒这一点。

我身后有一个庞大的家族,但我时刻都想着和他们切断联系。这种想法来源已久了,或许是受到母亲的影响。母亲时常叨念家乡的事,这个人的小心眼,那个人的不作为。但由于外婆依旧健在,母亲还是保持着较高的探亲频率。说是探亲,不过也是周末偶尔回去住个两天,便匆匆回来了。四百公里的路,火车跑起来快得很。

我所不喜欢的,是老家那种到处是熟人的氛围。在那个小镇子上生活的人们从几代以前就互相认识了,出门走几步遇到的人大都能叫出你的名字。熟人社会有着他们自己认为的优点,办事方便,有困难时可以相互扶持。但在我看来这种关系状态是一种束缚。「熟人」们的指指点点会限制你的行为,即使你的行为并没有什么问题。如果将熟人社会看做一个整体,这个庞然大物的思想进步是非常缓慢的。社会中的人相互牵制,根深蒂固的观念不断同化着想要脱离的人。封闭而保守,也许有人喜欢那种状态,反正我是不喜欢的。

亲人又怎么样呢?如果不是经常见面,相互没有过印象深刻的经历,不过也是「熟人」罢了。血缘这种东西,粗暴地将一个人与另一个人捆绑在一起,物质上或许有一些牵连,但精神关系的认同仍然得看彼此的共同经历。自小我便和父母在另一个城市生活,除了曾经照顾过我的,家族中的许多人,同辈或是不同辈的,对于我都只是「熟人」。但遗憾的是,我常常需要回到这些「熟人」当中,有时甚至需要过多地流露一些感情,让我感到如坐针毡。而这一切,只因为我们有「血缘关系」。

有人说,计划生育和网络的崛起让我们这一代变得孤独而冷酷。但我觉得,如果孤独和冷酷不影响我们在现代社会生活的话,倒也无可厚非。熟人的相互关心也罢,沉迷于网络中的光怪陆离也罢,都是为了使精神不空虚,这是一个人活下去的必要条件。过去的人们没有过多的方式解决这个问题,但现在有了,我们应该有权利依自己的意志去选择。我们已经过了几千年的熟人/家族式社会,但不意味着这是常态。二三十年前的文学作品描绘了一个个乡土社会,它们透着幸福的气息,却不能使我产生憧憬。科技在瓦解旧的人际关系和社会结构,在此之前生活的人或许会感到痛惜,但在此之后的人只会无感甚至欣喜。我想,之前许多时代的接口处都会有这样的阵痛。

我盼望着,能尽早告别这一切。

READ MORE

SS Configuration

zh

SS Client

$ [sudo] pip3 install shadowsocks

/etc/ss.json :

{
"server": "<server ip>",
"server_port": "<server port>", // must be Number
"password": "<password>",
"local_address": "127.0.0.1",
"local_port": 1081,
"timeout": 300,
"method": "aes-256-cfb",
"fast_open": false
}
$ [sudo] sslocal -c /etc/ss.json -d start

proxychains

clone repository from https://github.com/rofl0r/proxychains-ng , make && sudo make install .

Append following lines to /etc/proxychains.conf :

[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 127.0.0.1 1081

Usage: proxychains [command] .

Chrome Addons

SwitchyOmega .

READ MORE

一月七日杂感

zh

前几天和阿三聚了一餐,这大概是一年到头来我们为数不多能好好聊天的时间。

我们谈了很多,从考试到动漫到未来。令人惊讶的是,他表现出了一种忧虑,对未来的忧虑。在我看来这是很少见的。忧虑的一方面是关于短期的未来,有 CSST 面试的压力,以及成堆的考试;另一方面是更遥远的未来,暑研或是升学或是就业。再往前两天的团队聚餐上大家的讨论,关于资本寒冬的,关于机器学习的逐渐饱和,都给我们留下了深刻的印象。

我问他不做金融吗。他说经过暑假的实习他也对这个行业失去了兴趣,量化交易不过也是机械性的脑力劳动(如有冒犯请见谅,这是我凭回忆归纳的,然而我对这个行业一窍不通)。现在他也开始迷茫将来要做什么。

他说有点羡慕我的状态,对周围的环境不 care,沉浸在自己的小世界当中。这个学校没能让他满意,没有地缘优势,身边足够优秀的人还是少了些。但这些在我看来都不重要,甚至还是优点。

吃完饭后已经是九点半了。雾霾洇开了路灯的光晕,整个城市笼上了一种眩目的橘黄色。

在那之后,我又断断续续想了很多。机器学习真的是我喜欢的吗?钻研理论时我是开心的,但我没有记笔记的习惯;做实验有时会让我很头疼,冗长而累人,很多时候结果还并不好。让我快乐的其实是在概念间的思维游走,但真正深入细节却是有些乏味的。许多创意到了底层,无非也是各种指标的相互比较——除非你是一个子领域的开山鼻祖。但这需要热情和灵感,我认为我没有。我之所以处在这其中,是因为它热门——至少当时是的,而且不让我讨厌,无论是数学或是 CS。

我想我最纯粹的快乐就是写代码了,次之就是钻研各种新东西,数学上或程序上的。但这两者都不能让我活下去。逐利的代码是需要迎合市场的,但这很累,而且会包含许多我讨厌的东西。我从来不是一个好的产品经理,也不想成为。我只希望能依自由意志写代码,折腾各种东西,这些产出多是无用的或是无法迎合市场的,但又确实能让我感到快乐。这个愿望其实是奢侈的。如果把「写代码」替成「追番」、「玩手机」、「打机」,那就能契合到很多人身上。我还是需要一门手艺,支撑我活下去,而让我的纯粹爱好成为我的业余游戏。

既然如此,为什么不尝试将手艺的价值最大化呢?比如出国。在另一个环境凭这门手艺或许能活得更好。我觉得这其中有太多令我望而却步的东西,包括和很多人打交道,包括环境的切换。很多人觉得没什么,但我却十分在意。或许是刻在基因里的一种病吧。不想和人说话;一旦浸入了一个环境,出来时会痛苦万分。升学时也是,回家时也是。想改也改不了。

所以呢,依然没有结论,未来依旧是迷茫的。这两年多我错过了很多机会,实不相瞒是故意的。但也意外收获了一些好处,或许可以成为新的契机。很多问题要随着时间的流动才能找到答案,我也祈祷如此吧。

READ MORE

四月·病

zh
mybirth:FADO+tjeoO88yaFhw0deZQ==:/kAejdHo/9YWWwOJNib3AQ==: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
**THIS CONTENT IS ENCRYPTED**
 
DECRYPTING...
READ MORE

Haskell 笔记:State Monad

zh

一个依赖于外部状态 s 的伪函数 f' :: a -> b,我们可以将其改写为 f :: a -> s -> (b, s) 使其良定。即,在输入输出中显式传递状态 s。现在,我们需要利用 Monad 将状态传递过程隐藏起来。

注意到,输出值 (b, s) 中的末状态 s 不仅依赖于输入状态,更依赖于之前更改过状态的一系列函数及其逻辑。因此我们不能简单地将 Monad 定义为 (a, s) 类似的形式,否则两个函数用 >=> 结合的结果将与函数逻辑无关,这与我们的期望不符。

考虑如下定义:

newtype State s a = { runState :: s -> (a, s) }

由于 -> 的右结合性,f :: a -> s -> (b, s)f :: a -> State s b 等价。固定 s,则 State s 可以成为一个 Monad。一个类型为 State s a 的值通常也被称为一个 state processor。

现在尝试定义 (>>=) :: State s a -> (a -> State s b) -> State s b。若 p >>= f,则 p 蕴含了在此之前所有的状态处理逻辑,我们希望将 pf 的逻辑融合在一起,成为一个新的 state processor,并作为返回值。

p >>= f = 
(
State $ \s -> (b, s'')
where
(a, s') = (runState p) s
p2 = f a -- :: State s b
(b, s'') = (runState p2) s'
)

return 是平凡的:

return a = State $ (\s -> (a, s))

fmap 可以作如下定义:

fmap :: (a -> b) -> (State s a) -> (State s b)
fmap f =
(
\pIn -> (
\s -> (b, s')
where
(a, s') = (runState pIn) s
b = f a
)

如此一来,我们可以将一系列的依赖外部状态的函数串成一个依赖外部状态的函数,传以初始状态,便可得到结果。

READ MORE

Haskell 笔记:Monad 引论

zh

动机

pure functions 看似完美,但却不能模拟现实世界中的诸多任务。这是由于 pure functions 是良定的映射,对于特定的输入值会返回唯一的输出。这种模式在面对如下任务时会显得苍白无力:

  • 有可能失败的任务。如大多数的 IO。
  • 依赖外部状态的任务。如(伪)随机数生成器。
  • 非确定性任务,即对于确定的输入可能有多个输出。这种在 IP 中较为少见。
  • 对外界会造成影响的任务。如大多数的写入过程。

这些问题可以用数学中的域扩充技巧来解决。

域扩充

在数学中,当定义问题的范畴不足以容纳问题的解时,我们通常会对相关的范畴进行扩充。类似的技巧同样也可以应用在这里。

假设一个不良定的函数 f: A -> B

  • 如果 f 有可能失败,我们可以将 B 扩充为 Err(B) ∪ { reasons of failures },其中 reasons of failures 可能是对异常的描述,也可以是空值一类的东西。则 f': A -> Err(B) 是良定的映射,且与 f 行为一致。事实上,这就是 Maybe Monad 和 Either Monad。
  • 如果 f 依赖于外部状态,我们定义 Pref(B)从外部状态空间到 B 的映射的全体,则 f': A -> Pref(B) 为良定的映射,且行为和 f 一致。换言之,对于特定的输入 af'(a) 返回一个函数,其中蕴含了已知 a 时如何从各种不同状态得到结果的逻辑。事实上,这就是 State Monad。
  • 如果 f 具有非确定性,我们将 B 扩充为 Power(B),即 B 的幂集。则 f': A -> Power(B) 为良定的映射,且行为与 f 一致。事实上,这就是 List Monad。
  • 如果 f 依赖于真实世界,我们将 B 扩充为 IO(B),其中的元素为一些值域为 B伪函数,可能对真实世界有影响。这些伪函数已经脱离了 pure functions 的范畴,但将它们看成元素是没有问题的。如此一来 f': A -> IO(B) 为良定的映射,且行为与 f 一致。事实上,这就是 IO Monad。

以上操作都有一个共同点,即对一个不良定函数的值域做了扩充,使之变成良定函数。如果用 Haskell 语言描述,它们都有相似的型:f :: a -> m b,其中 m 为扩充规则。

一个问题随之而来:这样的新函数该怎么结合?为此我们要对相关逻辑进行抽象。这就是 Monad。

Monad

这里我们尝试从实际需求出发,导出一个 Type Constructor 成为 Monad 的必要条件。

约定两个名称:

  • a -> m b 型函数为 monadic function
  • a -> b 型函数为 non-monadic function

首先需要解决的是 monadic functions 如何结合的问题。这个问题具有重要的现实意义。monadic function 常常代表某种计算任务,它们之间的结合相当于把若干计算任务串行化,而后者是非常常见的需求。

我们希望有一种运算符有如下的类型 (b -> m c) -> (a -> m b) -> (a -> m c),在此记为 >=> (因其形状,常被叫做 fish operator)。一个自然的想法是,Monad m 需要某种平凡的拆箱操作 extract' :: m a -> a。所谓“平凡”,即 extract' 不应该丢失参数的任何信息。但这往往不能实现,因为 m a 通常会比 a 包含更多的信息,导致 extract' 无法构成良定的映射。例如 Maybe a 中的值 Nothing 就无法在 a 中找到对应的值。

而事实上,我们不需要条件这么强的拆箱操作。在 m 已是 Functor 的情况下,拆箱操作可以弱化为 join :: m (m a) -> m a。我们尝试用 fmapjoin 合成 >=>

f :: b -> m c
g :: a -> m b

fmap f :: m b -> m (m c)
(fmap f) . g :: a -> m (m c)
join . (fmap f) . g :: a -> m c

-- i.e.

f >=> g = join . (fmap f) . g

Functor 的假设是容易成立的。当然我们可以定义多个不同的 fmap,如此产生的 Monad 会有不同的语义。join 的假设也是容易成立的,m (m a) 通常和 m a 包含相同多的信息。故此做法是实际可行的。

我们再考虑 monadic function 和 non-monadic function 结合的问题。期望有如此一个运算:>.> :: (b -> c) -> (a -> m b) -> (a -> m c)。注意,此处返回值是 a -> m c 而不是 a -> c,因为我们不希望 a -> m b 产生的额外信息有所丢失。自然地,我们希望有一个平凡的装箱操作,return :: a -> m a。如此一来便可结合 >=> 完成上面的运算:

f :: b -> c
g :: a -> m b

return . f :: b -> m c
(return . f) >=> g :: a -> m c

-- i.e.

f >.> g :: (return . f) >=> g

non-monadic function 和 monadic function 另一个方向的结合是平凡的。

综上我们可以得到成为 Monad 的基本条件:

  • 是 Functor,存在 fmap :: (a -> b) -> m a -> m b
  • 有一个平凡的拆箱操作 join :: m (m a) -> m a
  • 有一个平凡的装箱操作 return :: a -> m a

为了描述平凡,我们要求三个函数必须满足如下公理(下面的 f 为 non-monadic function):

  1. return . f == (fmap f) . returnreturn 的平凡性)
  2. join . fmap (fmap f) == (fmap f) . joinjoin 的平凡性)

事实上在 Category Theory 中,还有另外两条公理:

  • join . (fmap join) == join . join
  • join . fmap return == join . return == id

以上四条公理描述了 Id(恒等 Functor)、mm^2m^3 之间的泛性质,并使图交换。

Monad Typeclass

以下为 Prelude 中的定义:

class Functor m => m a where

return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b

此处没有出现 join,也没有 fish operator,而是使用了一个更常用的算符 >>= (通常称为 bind operator)。这是因为在实际中我们不直接将函数结合,而是使用 non-pointfree 的写法。

此外,还有 >> :: m a -> m b -> m b 运算符。return>>=>> 三者是构成 do-notation 的基础。此处不再赘述。

References

READ MORE