• トップページ
  • project
    • 全ての作品
    • 全てのタグ
  • blog
    • 全ての記事
    • 全てのタグ
  • tag
    • 全てのタグ
    • 全ての作品タグ
    • 全ての記事タグ
  • about
    • p進大好きサークル photo

      p進大好きサークル

      p進大好きサークルのHPです。

    • もっと読む
    • Twitter
    • pixiv
    • 巨大数Wiki

機能和声の実装 - 3和音

2020/03/20

トップページ 前の記事 親記事 次の記事

twitter pixiv yukicoder お題箱 マシュマロ

数式での翻訳

音名の\(3\)つ組\((N_0,N_1,N_2)\)であって各成分が互いに異なるものを全体の集合を\(\textrm{SanWaOn}\)と置き、\(\textrm{SanWaOn}\)上の\(2\)項関係 \[ (N_{1,0},N_{1,1},N_{1,2}) \sim (N_{2,0},N_{2,1},N_{2,2}) \] を\(\{N_{1,0},N_{1,1},N_{1,2}\} = \{N_{2,0},N_{2,1},N_{2,2}\}\)と定めます。\(\sim\)は\(\textrm{SanWaOn}\)上の同値関係となり、\((N_0,N_1,N_2) \in \textrm{SanWaOn}\)の\(\sim\)に関する同値類 \[ \{(N’_0,N’_1,N’_2) \in \textrm{SanWaOn} \mid (N_0,N_1,N_2) \sim (N’_0,N’_1,N’_2)\} \] を\([N_0,N_1,N_2]\)と置きます。\(\textrm{SanWaOn}\)の元\(\sim\)に関する同値類全体の集合である商集合 \[ \textrm{SanWaOn}/{\sim} = \{[N_0,N_1,N_2] \mid (N_0,N_1,N_2) \in \textrm{SanWaOn}\} \] を\(\overline{\textrm{SanWaOn}}\)と置き、\(\overline{\textrm{SanWaOn}}\)の元を\(3\)和音と呼びます。流儀によっては\((\textrm{Do}3,\textrm{Mi}4,\textrm{So}4,\textrm{Do}5)\)等の適当な条件を満たすピッチの有限列を\(3\)和音と呼ぶかもしれませんが、ここではそれに類する概念を後に改めて定義し\(3\)和音の配置と呼んで区別していきます。


\(3\)和音に関してはそれ以上何も述べることがないので、代わりに商集合と写像のwell-defined性に関する数学の話をします。まず概念がwell-definedであるというのはかなり多義な言葉で、大雑把には「その概念の定義文が与えられている」とか「その概念を特徴付けようとしている論理式は実際に定義文である」という意味です。そして定義文というものは「\(P(x)\)を満たす\(x\)が一意に存在する」という論理式が証明可能であるような論理式\(P(x)\)のことです。要するに、概念がwell-definedであるとは「何らかの具体的な論理式で一意に特徴付けられている」ということですね。例えばそもそも定義文になることを想定している論理式を何も提示していない状況ではwell-definedになりえず、ill-definedであると表現されます。

上記の説明はあくまで多義語であるwell-definedの用法に共通する概要を述べた大雑把なもので、実際に数学でwell-definedという言葉を用いる際は「定義文が与えられている」とか「特徴付けようとしている」みたいなメタで非形式的な言明を意図しているわけではありません。より正確な話をするために、well-definedという用語の厳密な定義をいくつか挙げ、実際に例や反例を見ていきましょう。

集合\(X\)と\(Y\)と写像\(f \colon X \to Y\)と\(X\)上の同値関係\(\approx\)に対し、\(f\)がwell-definedな写像\(X/{\approx} \to Y\)を誘導するとは「写像\(\overline{f} \colon X/{\approx} \to Y\)であって以下の条件(*)を満たすものが一意に存在する」という意味です。

(*) 任意の\(E \in X/{\approx}\)と\(x \in E\)に対し\(\overline{f}(E) = f(x)\)である。

\(f\)がwell-definedな写像\(X/{\approx} \to Y\)を誘導することは「任意の\((x_1,x_2) \in X^2\)に対し、\(x_1 \approx x_2\)ならば\(f(x_1) = f(x_2)\)である」という単純な条件と同値であるため、数学においてはwell-definedな写像を誘導することを証明する際には実際に写像の定義を書く代わりにこちらの条件を確認することが多いです。例えば\(\sim\)の定義から、\((N_0,N_1,N_2) \in \textrm{SanWaOn}\)を集合\(\{N_0,N_1,N_2\}\)に対応させる写像は\(\overline{\textrm{SanWaOn}}\)から濃度\(3\)である\(\textrm{OnMei}\)の部分集合全体の集合へのwell-definedな全単射を誘導します。その全単射により両者を同一視することで、\(3\)和音を単に濃度\(3\)の\(\textrm{OnMei}\)の部分集合とみなします。

well-definedという言葉の他の用法を確認します。例えば「各\(E \in X/{\approx}\)に対し\(x \in E\)を用いて\(\overline{f}(E) = f(x)\)と定めると、\(\overline{f} \colon X/{\approx} \to Y\)はwell-definedである」のように述べることがありますが、これは実際に選択公理で各\(E \in X/{\approx}\)に対し元\(x \in E\)を固定するということではなく、「各\(E \in X/{\approx}\)に対し、\(f(x)\)は\(x \in E\)の取り方に依存しない(そのためそれを\(\overline{f}(E)\)と置く)」という文の略記と考えることができます。このように定める\(\overline{f}\)は実際に条件(*)を満たすため、\(f\)がwell-definedな写像\(X/{\approx} \to Y\)を誘導していることが分かります。

ここで「\(\overline{f}\)はwell-definedである」と書いているのであたかも「各\(E \in X/{\approx}\)に対し\(x \in E\)を用いて\(\overline{f}(E) = f(x)\)と定めると、\(\overline{f} \colon X/{\approx} \to Y\)は条件(*)を満たす」という\(\overline{f}\)に関する述語のようですが、そう捉えてしまうと選択公理で各\(E \in X/{\approx}\)に対し元\(x \in E\)を固定して\(\overline{f}\)を定めるということになってしまいます。それでも選択公理を課している状況では基本的に問題がないのですが、通常はこのような選択公理による構成ではなく各値の一意存在性を用いて定義したいと考える人が多いと思いますので、\(\overline{f}\)に関する述語ではなく単に「各\(E \in X/{\approx}\)に対し、\(f(x)\)は\(x \in E\)の取り方に依存しない」という\(X\)と\(Y\)と\(f\)と\(\approx\)に関する述語の略記として考えます。

同様に「各\(E \in X/{\approx}\)に対し\(x \in E\)を用いて\(\overline{f}(E) = f(x)\)と定めると、\(\overline{f} \colon X/{\approx} \to Y\)はill-definedである」のように述べることがありますが、これは選択公理を用いて構成した\(\overline{f}\)に関する述語ではなく「条件(*)を満たす\(\overline{f} \colon X/{\approx} \to Y\)は一意に存在しない」という\(X\)と\(Y\)と\(f\)と\(\approx\)に関する述語の略記として考えます。「存在する」という言明はあくまで量化子を読んだものであり、それ自体は述語でないことに注意しましょう。

この他にも「well-definedな写像を誘導する」という表現は様々な状況で適用されます。例えば\(X\)と\(Y\)と\(I\)と写像\(f \colon X \times I \to Y\)と\(X\)上の同値関係\(\approx\)に対し、\(f\)がwell-definedな写像\(X/{\approx} \times I \to Y\)を誘導するとは「写像\(\overline{f} \colon X/{\approx} \times I \to Y\)であって以下の条件(**)を満たすものが一意に存在する」という意味です。

(**) 任意の\((E,i) \in X/{\approx} \times I\)と\(x \in E\)に対し\(\overline{f}(E,i) = f(x,i)\)である。

\(f\)がwell-definedな写像\(X/{\approx} \times I \to Y\)を誘導することは「任意の\((x_1,x_2) \in X^2\)と\(i \in I\)に対し、\(x_1 \approx x_2\)ならば\(f(x_1,i) = f(x_2,i)\)である」という単純な条件と同値であるため、やはり数学においてはwell-definedな写像を誘導することを証明する際には実際に写像の定義を書く代わりにこちらの条件を確認することが多いです。先程はwell-definedな写像を誘導する例を挙げたので、今度はwell-definedな写像を誘導しない例を扱いましょう。写像 \[ \begin{align} \textrm{SanWaOn} \times \{0,1,2\} & \to \textrm{OnMei} \\
((N_0,N_1,N_2),i) & \mapsto N_i \end{align} \] を\(\textrm{GetOnMei}\)と置きます。すると\((\textrm{Do},\textrm{Re},\textrm{Mi}) \sim (\textrm{Re},\textrm{Do},\textrm{Mi})\)である一方で \[ \textrm{GetOnMei}((\textrm{Do},\textrm{Re},\textrm{Mi}),0) = \textrm{Do} \neq \textrm{Re} = \textrm{GetOnMei}((\textrm{Re},\textrm{Do},\textrm{Mi}),0) \] となります。このことから、\(\textrm{GetOnMei}\)はwell-definedな写像\(\overline{\textrm{SanWaOn}} \times \{0,1,2\} \to \textrm{OnMei}\)を誘導しないことが分かります。その意味で「\(3\)和音の\(1\)番目の音名」等はill-definedな概念となります。代わりに後に導入する「\(3\)和音の配置の\(1\)番目のピッチ」等はwell-definedとなります。

\(3\)和音\(H\)に対し、\(H = [N_0,N_1,N_2]\)を満たす\((N_0,N_1,N_2) \in \textrm{SanWaOn}\)を\(H\)の代表元と呼びます。\(H\)の代表元は一意でなく、実際\((N_0,N_1,N_2)\)が\(H\)の代表元であるならば\((N_1,N_0,N_2)\)は\((N_0,N_1,N_2)\)と異なる\(H\)の代表元となります。

C++での宣言

3和音のクラスおよび関係する関数たちを以下のように宣言します。


class SanWaOn
{

private:
  OnMei m_N0;
  OnMei m_N1;
  OnMei m_N2;
  
public:
  inline SanWaOn( const OnMei& N0 , const OnMei& N1 , const OnMei& N2 ) noexcept;
  
  inline bool IsValid() const noexcept;

  inline string Display() const noexcept;

  const OnMei& GetOnMei( const uint& i ) const noexcept;

};

bool operator==( const SanWaOn& H1 , const SanWaOn& H2 ) noexcept;
inline bool operator!=( const SanWaOn& H1 , const SanWaOn& H2 ) noexcept;

C++での定義

実際の実装例についてはこちらをご覧下さい。実装においては以下の仕様を要請します。

  • inline SanWaOn::SanWaOn( const OnMei& N0 , const OnMei& N1 , const OnMei& N2 ) noexceptはメンバ初期化子m_N0( N0 ) , m_N1( N1 ) , m_N2( N2 )で定める。
  • inline bool SanWaOn::IsValid() const noexceptはreturn m_N0 != m_N1 && m_N1 != m_N2 && m_N2 != m_N0と定める。
  • inline string SanWaOn::Display() const noexceptはreturn "(" + m_N0.Display() + "," + m_N1.Display() + "," + m_N2.Display() + ")"で定める。
  • const OnMei& SanWaOn::GetOnMei( const uint& i ) const noexceptはi < 3ならばm_N0, m_N1 , m_N2のi+1番目へのconst 参照返しである。
  • bool operator==( const SanWaOn& H1 , const SanWaOn& H2 ) noexceptはメタな数列\((0,1,2)\)を並び替えた数列\((i,j,k)\)であってH1.m_N0 == H2.m_NiかつH1.m_N1 == H2.m_NjかつH1.m_N2 == H2.m_Nkを満たすものが存在することとtrueを返すことが同値である。
  • inline bool operator!=( const SanWaOn& H1 , const SanWaOn& H2 ) noexceptはreturn !( H1 == H2 )で定める。
トップページ 前の記事 親記事 次の記事

twitter pixiv yukicoder お題箱 マシュマロ