ZipWith, Inner Product, Einstein

ZipWith って内積だよね

今朝方だらだらと Mathematica のテンソルのページ を読んでいて,唐突に ZipWith が (一般化) 内積 (の一歩手前) ということに気付いたり.今更って感じですが.

Inner[f,list1,list2,g]

Dotを一般化したもので,f が掛け算,そしてg が足し算の役割を担う.

タイミング良く id:kkamegawa さんが似たような話を書いてたり.

External Iteratorいいですね。しばしばこんな感じでかけないかと思う局面に出会うことがあって、C#でなんかいい方法ないかと思ってます。

Google TechTalkのビデオから引用

e1 = [1,2,3,4].each
e2 = [10,11,4].each
loop  {
  p e1.next + e2.next
}

結果は 11,13,7

これを Mathematica の Inner で書くとこんな感じ.(ただし数学のお約束のために次元は合わせてます)

In[0] = Inner[Plus, {1, 2, 3}, {10, 11, 4}, List]
Out[0] = {11, 13, 7}

C# ならこんな感じ.って ZipWith なんてありませんが.

var v1 = new[] { 1, 2, 3, 4 };
var v2 = new[] { 10, 11, 4 };
var q = v1.ZipWith(v2, (a, b) => a + b);

あとはこれの Sum を取るなり,加法を用いた Aggregate を行うことで,よくみる意味での内積のできあがり.
というわけで,ZipWith って名前が気に入らない人は,拡張して Inner ってメソッド名にしても良いのかも.
関係ないけど,内積っぽいものの記法と言えば,アインシュタインの縮約記法 は Nice Hack ですな.

SelectMany で外積

ついでに (一般化) 外積も.

In[1] = Outer[List, {1, 2, 3}, {10, 11, 4}]
Out[1] = {{{1, 10}, {1, 11}, {1, 4}}, {{2, 10}, {2, 11}, {2, 4}},
          {{3, 10}, {3, 11}, {3, 4}}, {{4, 10}, {4, 11}, {4, 4}}}

C# 版.SelectMany で……と言いたいところだけど SelectMany だと結果をフラット化してしまうので困ることに気付く.微妙に日和ってみたり.

var v1 = new[] { 1, 2, 3, 4 };
var v2 = new[] { 10, 11, 4 };
var q = from x in v1
        select v2.Select(y => new List<int> { x, y });

あるいはこう書いた方が分かりやすいかも.

var v1 = new[] { 1, 2, 3, 4 };
var v2 = new[] { 10, 11, 4 };
var q = from x in v1
        select v2.Select(y => new []{ x, y }).ToArray();