Imaginantia

思ったことを書きます

よく使う関数たちの一覧

名前のまんまです。が、説明の為に諸々語を定義します。

空間一覧

  •  \mathbb{R}: 実数全体 (0 とか -42 とか 3.141592\dots とか)
  •  \mathbb{R}^+: 正の実数全体 (0-42 も入ってない)
  •  \mathbb{R}^+_0: 0と正の実数全体 (0 は入ってる)
  •  \mathbb{R}\setminus\{0\}: 0を除く実数全体
  •  [a,b]: a 以上 b 以下の実数全体 ([0,1] なら 0.147 とか 1 とか)
    • a の方が大きい場合は [b,a] を表すことにします。
  •  [a,b):  a 以上 b 未満の実数全体 ([0,1) には 1 は入ってない)
    • a の方が大きい場合は  [b,a] から b を抜いたものを表すことにします。
  •  (a,b]: a より大きい b 以下の実数全体 ((0,1] には 0 が入ってない)
    • 同上。
  •  \mathbb{Z}: 整数全体 ( 0 とか  -4 とか、 0.5 は入ってない)
  •  \mathbb{Z}^+: 正の整数 (0 は入ってない)
  •  X \times Y: 空間 X と空間 Y の点を独立に保持することで構成できる空間
  •  \mathbb{R}^2 = \mathbb{R} \times \mathbb{R}: 2次元平面 ( (3.2, 5.7) とか  (1,2) とかって書きます)
  •  \mathbb{R}^2\setminus\{\mathbf{0}\}: 原点 (\mathbf{0} = (0,0)) を含まない2次元平面
  •  S^1 = \{(x,y):\mathbb{R}^2\mid x^2+y^2=1\}: 1次元の円周 ((0,1) とか (3/5,4/5) とか)
    •  x^2 + y^2 = 1 は制約条件
  •  \mathbf{n} = \{0,1,\ldots,n-1\}: 0 から n-1 までの n 個の自然数の成す空間。
    • \mathbf{4} には  0, 1, 2, 3 が入ってる。

空間 X から空間 Y への変換 f は点の対応で表現されます。 これを  f\colon X \to Y と書きます。具体的な対応は x \mapsto f(x) のように書きます。


扱う空間には「群」という構造が入っていることが多いです。なのでそこも一応書きます。

群とは

簡単に言うと「全ての点が同等であるような空間」のこと。平行移動を行う演算が伴っていて、好きな点を好きな点に「空間ごと」移動することができます。 例えば整数 \mathbb{Z} は加法 + によって群になりますが、自然数は加法では群にはなりません (負の方向に平行移動できないから)。

平行移動は「原点をどこに持っていくか」によって記述されます。空間に依って原点は違うのでこれも群を記述するのに必要です。これを単位元と言います。 そして「空間ごと移動しきった」ことを証明するために「逆向きの平行移動」ができることを示す必要があります。このための証人を逆元と言います。

全ての点が同等であるが故に群の各点は「この空間が対称的である証拠」を記述します。

話に出てくる群一覧

(空間, 演算, 単位元)」の順番で書きます。逆元は計算すればわかるので書きません。

  •  (\mathbb{R}, +, 0): 実数上加法の成す群。一番よく使う。
  •  (\mathbb{R}^+, \times, 1): 実数上乗法の成す群。逆元は逆数。
  •  (\mathbb{Z}, +, 0): 整数も加法で群になる。
  •  ([0,1), +, 0): これは特殊な加法で、足した結果の小数部を取る。そうすると群。
    • + の記号は同じだけど違うもの。大体同じなので同じ記号で書いてます。
  •  ([0,a), +, 0): 同様にして弄った加法を入れると群。
    • 結果が 0 以上 a 未満になるまで a を足し引きする。
  •  (\mathbf{n}, +, 0): これも同様の加法で、足した結果を n で割った余りを取る。
    •  (\mathbf{5}, +, 0) の下では、 2 + 4 = 1 ということ。
  •  (S^1, \oplus, (1,0)): この演算はもっと特殊で、円周上の回転を表す。
    •  (a,b) \oplus (c,d) = (ac-bd, ac+bd)
  •  (\mathbb{Z}\times[0,1), \boxplus, (0,0)): 変な演算を入れると群。
    •  (m,d) \boxplus (n,e) = \text{if } d+e \ge 1 \text{ in } \mathbb{R} \text{ then } (m+n+1, d+e-1) \text{ else } (m+n, d+e)
    • 2要素目は  ([0,1), +, 0) の演算と同じだけど1要素目に絡み合っている

以後、たまに単位元を省略したりします。

群準同型

空間から空間への変換を表す関数は、大体なんらかの空間構造を「保つ」ようになっています。 ここでの保つの意味は、 (X, *_X, e_X) から  (Y, *_Y, e_Y) への変換  f

  •  f(x*_Xy) = f(x)*_Yf(y) (どんな x,y\colon X についても)
  •  f(e_X) = e_Y

であることの要求です。こういう空間構造を保つ変換を準同型と呼びます。

例えば  x \mapsto 2 \times x (\mathbb{R},+,0) から (\mathbb{R},+,0) (自分)への群準同型です。

  •  2 \times (x+y) = 2 \times (x) + 2 \times (y) なのでOK
  •  2 \times 0 = 0 なのでOK

以後、f\colon (X,*,e) \to (Y,*,e) のように群から群への変換のようなものを書いた場合は群準同型であるとします。

同型と群同型

変換で「情報を失わない」とき、その変換を同型と呼びます。情報を失わないというのは「逆向きの変換が在る」ことに拠ります。 さらに順方向・逆方向の変換が共に群準同型なら、それは群同型と呼びます。

先程の x \mapsto 2 \times x は群同型です。具体的には x \mapsto x / 2 によって完全に戻るし、どちらも群準同型だからです。

同型・群同型の場合は  f: X \simeq Y のように書きます。この時でも向きは  X \to Y です。


また、便宜上  (X,*,e) \to Y で「群構造を忘れて、単純な空間としての X から Y への変換」を示します。

そして  X \to Y \to Z のような表記で、変換としては X \to Z なんだけど気持ちの上では  Y を経由することを表します。

余談ですが群にはコンパクトな群というのがあって、適当に言うと周期的なやつです。  (\mathbf{n},+) とか  (S^1, \oplus) とか  ([0,a), +) とかはコンパクトです。 コンパクトじゃない空間からコンパクトな空間への変換はだいたい「ぐるぐる巻く」必要があります。その辺憶えておくと良いかも。

関数一覧

HLSLのやつです

 x \mapsto x \times M + R\colon  \mathbb{R} \simeq \mathbb{R}\text{  }(M\ne 0)

拡大縮小と平行移動です。大体対象が [0,1][0,1] \simeq [R,M+R] になることが多い。

具体的には  x \mapsto x \times 0.5 + 0.5\colon [-1,1] \simeq [0,1] とかあとその逆をめちゃくちゃ使います。

ちなみに R=0 のときは群同型です。特に x \mapsto -x \colon (\mathbb{R},+) \simeq (\mathbb{R},+) です。

x \mapsto (\mathsf{floor}(x), \mathsf{frac}(x))\colon  (\mathbb{R},+) \simeq (\mathbb{Z} \times [0,1), \boxplus)

整数部と小数部に分けて演算をすることを考えれば、それは実数として十分振る舞えます。x = \mathsf{floor}(x) + \mathsf{frac}(x) です。

特に \mathsf{frac}\colon (\mathbb{R},+) \to ([0,1), +) と捉えられるのも重要ですね。これは「周期で巻く」ということになります。

 x \mapsto \mathsf{fmod}(x,M)\colon \mathbb{R}^+ \to [0,M)

これも周期で巻くやつですが、負数を入力したときに負数が帰ってきます。なのでちょっといじる。

 x \mapsto \mathsf{fmod}(\mathsf{fmod}(x,M)+M)\colon  (\mathbb{R}, +) \to ([0,M), +)

これでまともな群準同型になります。特に M=1 のとき \mathsf{frac} と一致ですね。

最初から  x\mapsto x - \mathsf{floor}(x/M) \times M のほうが早いという説はある。

 \mathsf{round}, \mathsf{ceil}\colon \mathbb{R} \to \mathbb{Z}

\mathsf{floor} に似ている系です。実際 \mathsf{round}(x) = \mathsf{floor}(x+0.5), \mathsf{ceil} = -\mathsf{floor}(-x) です。 なので \mathsf{ceil}\colon \mathbb{R} \xrightarrow{-} \mathbb{R} \xrightarrow{\mathsf{floor}} \mathbb{Z} \xrightarrow{-} \mathbb{Z} ですね。

あんまり使わない。

 x \mapsto (\mathsf{cos}(x), \mathsf{sin}(x))\colon  (\mathbb{R}, +) \xrightarrow{\mathsf{fmod}(-,2\pi)} ([0,2\pi), +) \simeq (S^1, \oplus)

周期的にしてから S^1 に等速で埋め込みます。内部で \mathsf{fmod} が使われてるかは知らないしどうでもいいです。

ちなみに  x\mapsto (\mathsf{cos}(x), \mathsf{sin}(x))\colon ([0,2\pi), +) \simeq (S^1, \oplus) と捉えた場合には  x\mapsto (\mathsf{cos}(N\times x), \mathsf{sin}(N\times x))\colon ([0,2\pi), +) \to (S^1,\oplus) を考えることができます。 このとき N整数でないと群準同型にならないことに注意。逆に言えば整数ならぐるぐる巻きにできます。

 v \mapsto (\mathsf{length}(v), \mathsf{normalize}(v))\colon \mathbb{R}^2 \setminus \{\mathbf{0}\} \simeq \mathbb{R}^+ \times S^1

原点を抜いた2次元平面を、全ての正の半径から成る円周の集まりとして解釈できるという話ですね。 v = \mathsf{length}(v) \times \mathsf{normalize}(v) です。  \mathsf{length} \mathbb{R}^2 \to \mathbb{R}^+_0 にはなってるのでいつでも使えますが、 \mathsf{normalize} はそうでもないので注意。

 v \mapsto (\mathsf{length}(v), \mathsf{atan2}(v))\colon \mathbb{R}^2\setminus\{\mathbf{0}\} \simeq \mathbb{R}^+ \times [-\pi,\pi)

円周をもうちょっと具体的に角度に落とした状態です。前節と同様に  \mathsf{atan2}\mathbf{0} を入力に取れないので注意。

ちなみに \mathsf{atan2} の入力は大体2引数になってて y,xの順番なので注意ですね。元々 \mathsf{atan} に与える入力は y/x なのです。 ただこれだと情報が落ちている (逆向きが同一視されている、\pi の違いがわからない) ので分割して拾う \mathsf{atan2} があるのです。べんり。

 x \mapsto (\mathsf{sign}(x), \mathsf{abs}(x))\colon \mathbb{R}\setminus\{0\} \simeq \{-1,1\} \times \mathbb{R}^+

実数を符号と残りに分解した状態です。 x = \mathsf{sign}(x) \times \mathsf{abs}(x) です。\mathsf{abs} は負の数を正にするのにめちゃくちゃ使いますね。

 0 を入れると同型じゃなくなるので抜いてますが、\mathsf{sign}(0) = 0, \mathsf{abs}(0) = 0 です。 つまり 0 を抜かなくても \mathsf{atan2} とかとは違って怖い値にならないので怖くない。

 x \mapsto \mathsf{pow}(x,E)\colon [0,1] \simeq [0,1]\text{  }(E>0)

本来は \mathbb{R}^+_0 \simeq \mathbb{R}^+_0 ですが、大体シェーダで使うのはこうだと思います。

ちょっと重みを付けるのに便利。E>1 の時は 0 において微分0 なので「動き始め」になるんですが、E\lt 1 で出来るグラフは 1 において微分0 ではないことに注意。 急に止まったようになっちゃいます。「ゆっくり止める」場合は [0,1] \simeq [1,0] \xrightarrow{\mathsf{pow}(-,E)} [1,0] \simeq [0,1] が良いです。

 x \mapsto \mathsf{sign}(x) \times \mathsf{pow}(\mathsf{abs}(x),E)\colon [-1,1] \simeq [-1,1]\text{  }(E>0)

たまに負の数に拡張したくなる。\mathsf{pow} に直接負の値を入れると爆発します。

 (x,y) \mapsto \mathsf{pow}(\mathsf{pow}(\mathsf{abs}(x),E) + \mathsf{pow}(\mathsf{abs}(y),E), 1/E): \mathbb{R}^2 \to \mathbb{R}^+_0\text{  }(E>0)

歪んだ距離で測った原点からの距離です。普通の円じゃなくて四角っぽくなった円とかが作れる (角丸ではない)。 ちなみに  E \lt 1 のときは星型、1 でダイアモンド型、1\lt E\lt2 でダイヤモンド型っぽい円、 E = 2 で円、それ以上は四角っぽい円。

 \mathsf{exp}\colon (\mathbb{R}, +) \simeq (\mathbb{R}^+, \times)\ {:}\mathsf{log}

お互いに逆向きの群同型です。まぁこの関係を使うことはあまりない気がする。

x \mapsto \mathsf{exp}(-x)\mathbb{R}^+_0 \to (0,1] で、「だんだん減衰」するのを表現するのに使えます。 特に入力に  x \mapsto x \times M\colon \mathbb{R}^+_0 \simeq \mathbb{R}^+_0 をつなげると減衰の速さを調節できるのが便利。

 x \mapsto \mathsf{log}(x) / \mathsf{log}(B)\colon (\mathbb{R}^+, \times) \simeq (\mathbb{R}, +)

\mathsf{log} を使うのはこの用途だと思います。これは「B 進法の時の桁数」に近い値を与えます。

ちゃんとやると  x \mapsto \mathsf{floor}(\mathsf{log}(x)/\mathsf{log}(10)) + 1\colon \mathbb{Z}^+ \to \mathbb{Z}^+ で10進数表示のときの桁数です。0 は定義域外なのに注意。

mipmapを自前実装するときにも使ったりします。

 x \mapsto \mathsf{min}(x,M)\colon \mathbb{R} \to (-\infty, M]

頭打ちにするのに便利。大体 M=1 です。

 x \mapsto \mathsf{max}(x,M)\colon \mathbb{R} \to [M,\infty)

今度は下を潰す側。よく M=0 で使います。いつもどっちがどっちだかわからなくなる。

 x \mapsto \mathsf{clamp}(x, A, B)\colon \mathbb{R} \to [A,B]

どっちだかわかるのでありがたいやつ。でも今度は x をどこに置くかわかんなくなる。

 x \mapsto \mathsf{saturate}(x)\colon \mathbb{R} \to [0,1]

A=0, B=1 で決め打ちされたもの。とてもべんり。

 x \mapsto \mathsf{smoothstep}(A,B,x) \colon [A,B] \simeq [0,1]

正確には \mathbb{R} \to [0,1] で、A より外側なら 0B より外側なら 1 を返します。 smoothと書いてあるとおり端点における微分0。とりあえず入れておけばなめらかに動くやつです。

 x \mapsto \mathsf{step}(A,x) \colon \mathbb{R} \to \mathbf{2}

A 以上なら 1、そうでないなら 0。ifを使う代わりに使われたりするけど正直if書けばいいと思います。引数がどっちか毎回忘れる。

 x \mapsto \mathsf{lerp}(A,B,x)\colon [0,1] \simeq [A,B]

適当に拡大するやつです。 x \mapsto x \times (B-A) + A と同じなので別に入力はもっと広く与えても大丈夫。

\mathsf{lerp}(A,B,\mathsf{smoothstep}(P,Q,x))\colon [P,Q] \simeq [A,B] とやるとなめらかなremapができます。よく使う。

終わり

あと \mathsf{distance}(x,y) = \mathsf{length}(x-y) とか線形代数系の演算 (\mathsf{dot} とか \mathsf{mul} とか) は使いますがこんなもんでしょうか。 ちゃんと空間を考えてあげると関数の理解もしやすいとおもうのではい。そんな感じで。