先日の記事「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」で、上付き・下付き添字の説明をしたのですが、説明の対象である上付き・下付き添字以外に、上付き・下付き添字の記法を大量に使っている事実に気が付きました。随分とひどいオーバーロード〈多義的使用〉だわ。「過度のオーバーロードはやめよう」と主張している僕としては、ちょっと愕然としました。
僕自身が上付き・下付き添字をどんな目的で使っているかを解説することにより、反省の材料にしたいと思います。また、「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」の分かりにくい記法への補足説明でもあります。
「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」と強く関係している節(第5節です)を読み流してもらえれば、上付き・下付き添字記法がどのように使用されているかの調査報告(ただし、サンプル数は1)としても読めるでしょう。
内容:
上付き・下付き添字の使用状況
gがニ変数〈ニ引数〉の関数〈写像〉のとき、g(a, b)を短く書くために単なる併置〈juxtaposition〉を使います。
- g(a, b) = ab
と書くわけです。掛け算が併置で書かれることはお馴染みですね。併置以外で短く書く記法というと、aとbの配置を斜め上下にすることにして:
- g(a, b) = ab
- g(a, b) = ab
- g(a, b) = ba
- g(a, b) = ba
となります。左上下はあまり使わないので*1、よく使うのは ab と ab です。これが上付き添字〈superscript | スーパースクリプト〉と下付き添字〈subscript | サブスクリプト〉です。添字をインデックス〈index〉ともいいます。
一変数関数fに対しても、f(a) を上付き・下付き添字で表すことがあります。
- f(a) = fa
- f(a) = fa
- f(a) = af
- f(a) = af
f(a) は、fのaによる評価〈evaluation〉または(同じことだが)aへのfの適用〈application〉なので、f(a) = eval(f, a) = app(a, f) とすれば:
- eval(f, a) = fa
- eval(f, a) = fa
- app(a, f) = af
- app(a, f) = af
と書けるので、ニ変数関数の添字記法だと解釈できます。
上付き添字の形で、たいていの人が思い出すのはニ変数の指数関数でしょう。
- exp(a, b) = ab
この用法が多いので、上付き添字を見ると指数だと解釈してしまう人が多いみたいです。上付き添字と指数の結びつきは一旦チャラにして、「この上付き添字はどんな意味だろう?」と毎回考えるようにしてください。
マヤカシのRn
ここから先は、僕の記事「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」に出現する上付き・下付き添字を、ほぼ出現順に解説していきます。
最初に出た添字表現は「Rn」です。ユークリッド空間と呼ばれる集合です。とりあえずこれは、数の指数と同じく“n個の累乗”という意味です。
- Rn = R× ... ×R (n個)
こういう説明や定義をするたびに、僕は少し後ろめたくなります。これはマヤカシです。
2つの集合A, Bに対して、その指数〈ベキ〉を、
- BA = (AからBへのすべての写像からなる集合) = Map(A, B)
とします。BA = Map(A, B) は標準的記法として認めましょう。この指数(上付き添字)記法が腑に落ちない方は次の記事をどうぞ。腑に落ちてる方は参照不要。
[0] = {}, [1] = [1], [2] = {1, 2}, ... などと定義します。一般的には、
- [n] := {k∈N | 1 ≦ k ≦ n}
通常Rnと書かれているものは、R[n] = Map([n], R) = Map({1, ..., n}, R) と解釈したほうがいいです。何故かと言うと、もし、R3 := R×R×R としてしまうと、x∈R3 の下付き添字表示が x = (x1, x2, x3) とは書けずに、x = (x1, x2), x1 = ((x1)1, (x1)2) と書くハメになるからです。
'×'が二項直積の演算子記号として、R×R = R[2] は言えます*2が、R×R×R = (R×R)×R = R[3] は言えないのです。R[3]の要素 t = (a, b, c) (t(1) = a, t(2), t(3) = c)に対応する (R×R)×R の要素は、{1:{1:a, 2:b}, 2:c} とでも書くべきものです。 R×(R×R) の要素なら {1:a, 2:{1:b, 2:c}} です。もとの3-タプルは、(a, b, c) = {1:a, 2:b, 3:c} です。
{1:{1:a, 2:b}, 2:c}, {1:a, 2:{1:b, 2:c}}, {1:a, 2:b, 3:c} はイコールではなく、次の同型があるだけです。
- (R×R)×R R×(R×R) R[3]
これは、つまらない話でも簡単な話でもなく、難しくて重用な話題です。直接の発展としては、モノイド圏に関するマックレーンの一貫性定理〈Mac Lane's coherence theorem for monoidal categories〉があります。
「二項直積演算が厳密には結合的ではない」という困難を避けるためには、R3 = (R×R)×R ではなくて、R3 = R[3] = Map({1, 2, 3}, R) と解釈したほうがいいでしょう。
引数としての添字
「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」で二番目に登場する添字記法は、「(ξi | i = 1, ..., n)」です。これは、ξ∈Rn を成分表示したものです。前節で述べたように、Rn = R[n] と考えると ξ∈Map([n], R) です。ξは関数ですから、型付きラムダ記法で書けば:
- ξ = λi∈[n].ξ(i)
ξ(i) を ξi と書けば、λi∈[n].ξi 、これを (ξi | i∈[n]) のようにも書くのです。一般的に、関数 λi∈I.f(i) の別表記として (fi | i∈I) とか (fi)i∈I とか書かれます。これは単に関数〈写像〉の別表記に過ぎないのですが、こう書くとインデックス族〈indexed family〉と呼ばれたりします。「インデックス族」あるいは単に「族」は、「関数」と同義であり、使い分けは気分だけです*3。
「(ξi | i = 1, ..., n)」における下付き添字の用法は、関数への引数渡し〈評価〉です。次のように書いてもまったく同じ意味です。違いは気分だけ。
- ξ(i)
- ξi
- ξ[i]
- eval(ξ, i)
- app(i, ξ)
作用素としての添字
次に「f~」という上付き添字が登場します。この例では、上付きの'~'が作用素〈operator | オペレータ〉で、fがその引数〈オペランド | operand | 被作用項 | 被演算項〉です。「作用素」という言葉も、結局は関数・写像と同義語ですが、気分としては、“集合や関数を引数にとる関数”を作用素とか汎関数〈functional〉とか呼ぶ傾向があります。operatorの訳語が「作用素」または「演算子」なので、演算子でも作用素と同じニュアンスがあります。
上付き'~'が表す作用素をextとすれば、次の表現は同じ意味です。
- f~
- ext(f)
- eval(ext, f)
- app(f, ext)
extは、実はモナドのクライスリ拡張〈Kleisli extension〉オペレータです。モナドに関する解説は、興味があれば、次の記事からの参照をたどればいいと思います。
f~ において、f∈Map(A, X) だった(元の記事参照)ので、(-)~ = ext は次のようなオペレータ〈作用素 | 演算子〉です。
- ext:Map(A, X)→Lin(RA, X)
ここで、Lin(-, -) は線形写像全体からなる集合を表します*4。extは、ベクトル空間Xとその基底Aに依存して決まるので、正確には extA,X のように書きます。あっ、またしても添字がぁー …
extA,X のように、集合や構造に依存して写像が決まることは多いのです*5。これも、(集合や写像)|→写像 という写像なので、ext(A, X) のように書いてもかまいません。しかし、ext(A, X) 自体がオペレータなので、f∈Map(A, X) を渡すと ext(A, X)(f) が出力されて、それがまた線形写像なので、ext(A, X)(f)(ξ)∈X となります。ここで最後の引数になっている ξ∈RA も写像(A→R)という状況です。引数渡しをすべて丸括弧で書くと区別が付きにくいので、添字にしたり角括弧〈ブラケット〉にしたりで、多少は見やすくするわけです。プログラミング言語だと、山形括弧もよく使います、ext<A, X> のように。
オペレータを表す添字や、集合や構造が引数になる場合の添字の例として、他に次があります(元の記事での出現順)。
- inclA,X:A→X (A⊆X の包含写像)
- A→ (上付き→は、基底からフレームを作るオペレータ)
- (A→)-1 (上付き-1は、逆写像を作るオペレータ)
- A← (上付き←は、基底から逆フレームを作るオペレータ)
- idX (Xの恒等写像)
問題の“あの添字記法”
僕が「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」で導入・解説したかった添字記法は、ベクトル空間Xとその基底Aに対して、gX,A:X×A→R という写像です。この写像の意味から、gではなくてdirectCoeffという長い名前を使いましょう。“ダイレクトな係数”〈direct coefficient〉の短縮です。
directCoeffは、ベクトル空間Xとその基底Aに依存して決まる写像です。directCoeff(X, A)でもいいですが、前節で述べた理由から、directCoeffX,Aとします。
directCoeffX,A:X×A→R なので、x∈X と a∈A を渡すと directCoeffX,A(x, a)∈R が定まります。この値を自然言語で説明すると*6:
- directCoeffX,A(x, a) := (Xのベクトルxを、基底Aで展開したときの、aに対する係数)
ベクトルxの展開(線形結合による表現)は次のようになります。
いかにも長ったらしいので、directCoeffX,A(x, a) を coeff(x, a) に省略・短縮すれば:
これでも頻繁に書くには辛いので、二変数関数への引数渡し coeff(x, a) を上付き添字記法にしようというわけです。
- coeff(x, a) = xa
こうすると、固定したaに対して
- λx∈X.coeff(x, a) = λx∈X.xa
λx∈X.xa のラムダ変数を無名化(ハイフン化)して λx∈X.xa = (-)a 、したがって、
- (-)a = coeff(-, a)
いかなる(有限次元)ベクトル空間Xと基底Aに対しても同じ記法が使えます。標準双対ベクトル空間X*と双対基底A#に対しても、次のことは言えます。
- (-)w = directCoeffX*,A#(-, w)
しかし、w = (-)a のときに、
- (-)a = directCoeffX*,A#(-, (-)a)
という下付き記法を導入します。X*上での下付き添字と上付き添字の関係は (-)a = (-)(-)a です。
今までの説明のなかに、X*とA#という上付き添字が出てますが、これは、集合や構造に作用するオペレータとしての添字です。上付き星印は、ベクトル空間の標準双対空間を作るオペレータ、上付きシャープ記号は、ベクトル空間の基底に対して双対基底(標準双対空間の基底)を作るオペレータです。
今になって思っていることは; (-)aという記法は分かりにくかったなー、です。基底Aと双対基底A#のあいだには、集合としての1:1対応(全単射)があるので、その全単射も上付きシャープ記号でオーバーロード(同じ名前で違うものを表す)して、(-)aの代わりに a# を使えば良かったかな、と。上付きシャープを、ゲルファント変換を表す上付きハット(サーカムフレックス記号)と一緒に使うと、展開公式が次の形になります。
[tex: x \,=\, \sum_{a \in A}a ]
[tex: v \,=\, \sum_{a \in A}a^{\sharp} ]
<-|-> は標準ペアリング(<-|-> は評価 eval(-, -) と同じ)だとして、xa := <a#|x> , va := <a^|v> がダイレクトインデックス方式による上付き・下付き添字の定義になります。これって、スッキリしてんでしょ、まだ改善の余地があるかもしれないけど。構文・記法の設計は難しいけど楽しいなー。
カリー化した関数を表す添字
gは2変数関数 g:X×Y→Z だとします。gの第一引数をaに固定して Y→Z という関数だとみなしたものを ga と書きます。これも下付き添字ですな。
- ga(y) = g(a, y)
無名ラムダ変数(ハイフン)を使って書けば、ga(-) = g(a, -) ですが、ちゃんとしたラムダ記法で書くと:
- ga = ga(-) = λy∈Y.g(a, y)
aも動かしていいので、
- g(-) = λa∈X.ga(-) = λa∈X.λy∈Y.g(a, y)
ラムダ変数は束縛変数なので、リネームしてもいいですから λa∈X.λy∈Y.g(a, y) = λx∈X.λy∈Y.g(a, y) 、こう書くと分かってくると思いますが、g(-) はgのカリー化だったのです。
もとの関数が λ(x, y)∈X×Y.g(x, y) という二変数だったのを、λx∈X.λy∈Y.g(a, y) という“一変数関数を値とする一変数関数”にしています。これがカリー化です。
- gx(y) = (λx∈X.λy∈Y.g(a, y))(x)(y)
なので、下付き添字は、カリー化した後の変数〈引数〉として使われます。
g:X×Y→Z のカリー化を g∩:X→ZY と書きます。これまた上付き添字を使ってます。カリー化オペレータを表す上付き添字ですね。この書き方の由来(絵)は、「非対称閉圏のカリー化:記号法を工夫すれば、右と左の混乱も解消」を参照してください。
- g(-) = g∩
- gx = (g∩)(x)
- gx(y) = (g∩)(x)(y)
g:X×Y→Z に対して、∩g:Y→ZX というカリー化もできます。ラムダ記法で書くなら:
- ∩g := λy∈Y.λx∈X.g(x, y)
∩g を添字で表現するときは、上付きにします。
- g(-) = ∩g
- gy = (∩g)(y)
- gy(x) = (∩g)(y)(x)
「古典的微分幾何・ベクトル解析のモダン化: ダイレクトインデックス記法」のなかで、クロネッカーのデルタ δ:S×S→R に対して次の書き方を許しました。
- δ(s, t)
- δs(t)
- δt(s)
- δst
最初の3つは、δ, δ∩, ∩δ に引数を順次(添字が先、丸括弧が後で)渡した形です。最後のは δst = δ(s, t) とみなしてかまいません。
カリー化が登場する別なケースを見てみましょう。evalS,T:TS×S→T, appS,T:S×TS→T で、evalとappは引数順序が逆転するだけとします。
- eval(m, s) = app(s, m) = m(s)
evalA,R:RA×A→R を考えると、eval(ξ, a) = ξ(a) です。このevalを左側で(もとの第二引数が変数になる形で)カリー化すると:
- (∩eval(a))(ξ) = evala(ξ) = ξ(a)
つまり、evalの左カリー化は射影に他なりません。
- evala(ξ) = πa(ξ) = ξ(a)
evalaの上付きaは左カリー化に起因して、πaの上付きaは異なる射影を識別するラベルです。もとの定義も上付きの使用法も違いますが、evala = πa です。
ベクトル空間Xの標準双対ベクトル空間X*は、関数の空間なのでevalを考えことができます。evalX,R:X*×X→R で、
- eval(v, x) = v(x) = <v|x>
このevalを左カリー化すると:
- (∩eval(x))(v) = evalx(v) = v(x) = x^(x)
evalxはxのゲルファント変換x^です。∩eval自体は、∩eval = ЖX : X→X* を与えます。ЖXは「双対ベクトル空間、もう少し知っておいたほうがイイカモ // シャーとジェー」で定義しています。
おわりに
上付き・下付き添字は、併置の次に簡単で便利な記法です。長い関数名などを使わないで上付き・下付き添字で略記したい、とは誰もが思うでしょう。その結果、いろいろな関数が上付き・下付き添字記法で略記されることになります。出現した上付き・下付き添字が何を意味するかは、注意深く判断する必要があります。
使える文字・記号・記法はたいして多くないので、多義的使用/文脈依存は仕方ないのですが、そのなかでも上付き・下付き添字は大人気の記法ですから、超多義的使用/超文脈依存なのです。ちょっと頭痛がします。
*1:「カン拡張における上下左右: 入門の前に整理すべきこと」では、左上、左下、右上、右下に配置した添字をすべて使っています。互いに関連した4種類の二項操作を表現するためです。
*2:R×Rの定義として、R[2]を採用してよい、ということです。
*3:インデックス族とかパラメータ族というと、値の領域が確定した集合ではないような印象はあります。集合とは限らない類〈class〉に値をとる場合が族の雰囲気。このテの話を、印象・雰囲気で議論してもラチがあかないので、やめときます。
*4:厳密には、Map(A, X)のXは、忘却関手をUとして U(X) です。集合圏とベクトル空間の圏のあいだの随伴関手対があるのです。
*6:directCoeffの定義を形式言語でしようとすると、述語論理の論理式以外にヒルベルトのイプシロン記号が必要になります。