はじめに
筆者の立場と本稿の視点
筆者は電気工学を専門とし、情報工学の設計思想やOOPの形式体系については専門的な教育を受けていない。そのため本稿では、電気工学的・数理構造的な視点からソフトウェア設計の抽象性を再解釈するという立場を取っている。情報工学における慣習的な枠組みとは異なる見方を提示する可能性があるが、それゆえに新たな視点を提供できればと考えている。
対象読者と前提知識
本稿は、情報工学・電気工学・機械学習分野に関心を持つ大学院生や実務エンジニアを対象とする。以下のような基礎的知識を有している読者を想定する:
- Python等による基本的なプログラミング経験
- 線形代数の初歩(ベクトル、行列、内積、線形写像の概念)
- 機械学習の枠組みにおけるテンソル演算やAttentionの基礎的理解
- 必須ではないが、関数型プログラミングや型理論に片足を突っ込んでいる程度の抽象性への耐性があると望ましい
必要に応じて、本文中では重要な概念の簡潔な補足も行う。
本稿を読み進める上で最低限必要となる線形代数の基礎事項については、末尾に補足を設けている。必要に応じて参照されたい。
問題意識と背景
オブジェクト指向(Object-Oriented Programming, OOP)は、ソフトウェア設計における主流パラダイムとして長年にわたり用いられてきた。クラス、継承、ポリモーフィズムといった概念は、複雑な構造を整理・抽象化する手段として広く受け入れられている。
しかし近年、Transformer や Attention をはじめとする深層学習モデルの台頭により、ソフトウェア構造の記述パラダイムはより関数的・行列的・動的なものへと移行しつつある。これにより、OOP がもたらしてきた構造的抽象性の限界や、他の抽象体系(関数型、テンソル計算、カテゴリ的構造など)との統合的視座の必要性が浮かび上がってきた。
本稿の目的と問い
本稿の目的は、OOPの主要な設計要素(状態、継承、ポリモーフィズム)を、線形代数的構造に基づいて再解釈することである。これは、単にOOPを線形代数で置き換えることではなく、両者が共通して持つ構造的対応関係を明らかにし、さらにそれがAttentionやTransformerのような現代的なパラダイムと地続きであることを示す試みである。
これまでにも、OOPを状態遷移系や有限オートマトン、あるいはモデル駆動アーキテクチャと結びつける試みはあったが、多くは「設計言語」や「仕様の記述」の範疇に留まり、数理構造としての連続性(特に線形変換・テンソル操作との共通性)には踏み込んでこなかった。
本稿の新規性は、OOPの内部構造を関数合成と行列演算の形式性に基づいて捉え直すことで、OOP・線形代数・関数型プログラミング(FP)・Attentionといった異なる抽象体系が、操作ではなく「構造」の次元で連続していることを示す点にある。
その出発点として、以下の問いを掲げる:
「オブジェクトとは、線形代数的に変換行列として捉えられるのではないか?」
この問いは単なる思考実験にとどまらず、AIモデルの設計、並列処理の形式化、FPとの接続といった応用的な設計視座の再構成にもつながる可能性を持っている。
本稿ではこの問いを軸に、オブジェクトの再定義を試みながら、継承、ポリモーフィズム、非線形変換、Attention、さらに大規模言語モデル(LLM)との構造的連関について、順を追って考察していく。
オブジェクト = 変換行列:状態遷移モデルとしての再解釈
オブジェクト指向プログラミング(OOP)は、もともと物理シミュレーションの文脈で発展した設計思想である。物体が状態(位置、速度など)を持ち、時間とともに変化する様子を記述するために、オブジェクトという概念が導入された。ここでの「状態」はベクトル量であり、「振る舞い」はそれに作用する変換操作である。
この構造は、線形代数における状態遷移モデルと一致する。すなわち、ある時刻の状態ベクトル $x_t$に対して、変換行列 $A$ を作用させることで次の状態 $x_{t+1}$ を得る:
$$
\boldsymbol{x}_{t+1} = A \cdot \boldsymbol{x}_t
$$
※この式は、行列Aにベクトル $x_t$ を掛けることで、次の状態 $x_{t+1}$ を得る「線形変換」を表している。これは、物理システムやニューラルネットワークの基本構造でもある。
※この式は、離散時間状態空間モデルの簡略化形としても捉えることができる。通常の状態空間モデルでは、外部入力 $u_t$ を含む項 $Bu_t$ が加わるが、本稿ではオブジェクト内部の状態変化に焦点を当てるため、入力項を省略し、純粋な状態遷移のみを記述している。
離散状態空間モデル:
$$
\begin{eqnarray}
\boldsymbol{x}_{t+1}=A\boldsymbol{x}_t+B\boldsymbol{u}_t\\
\boldsymbol{y}_t=C\boldsymbol{x}_t+D\boldsymbol{u}_t
\end{eqnarray}
$$
※この式は、ニューラルネットワークの基本構造にも対応している。ニューラルネットワークでは、各レイヤーにおける出力は、前のレイヤーの状態ベクトル $x_t$ に対して重み行列 $A$ を掛けることで得られる。これは、線形変換による状態更新を表しており、活性化関数を加えることで次のような一般的なニューラルネットワークの層構造となる:
$$
\boldsymbol{x}_{t+1}=f(A\cdot \boldsymbol{x}_t)
$$
ここで $f$ は ReLU や sigmoid などの非線形関数であり、状態空間モデルにおける線形変換と非線形変換の組み合わせが、ニューラルネットワークの基本構造と一致することがわかる。
このとき、オブジェクトは「状態ベクトルとそれに作用する変換行列の組」として捉えることができる。これは、OOPにおける「プロパティ(属性)」と「メソッド(振る舞い)」の構造と対応している。
さらに、現代の計算環境では、単一の状態ベクトルに対する変換だけでなく、複数の状態ベクトルに対する一括変換(バッチ処理)が重要となる。たとえば、次のように複数の入力ベクトルを列方向に並べた行列 $X^{(n)}$ に対して、同一の変換行列 $A$ を適用することで、並列的に出力を得ることができる:
$$
Y^{(n)} = A \cdot X^{(n)},\ \ X\in\mathbb{R}^{d\times n}, Y\in\mathbb{R}^{d^\prime\times n},
$$
※ 上記式を行列表現にすると以下になる:
$$
\begin{bmatrix}
y_{11}&\dots&y_{1n}\\
\vdots&\ddots&\vdots\\
y_{d^\prime1}&\dots&y_{d^\prime n}\\
\end{bmatrix}=
\begin{bmatrix}
a_{11}&\dots&a_{1d}\\
\vdots&\ddots&\vdots\\
a_{d^\prime1}&\dots&a_{d^\prime d}\\
\end{bmatrix}
\begin{bmatrix}
x_{11}&\dots&x_{1n}\\
\vdots&\ddots&\vdots\\
x_{d1}&\dots&x_{dn}\\
\end{bmatrix}
$$
※ (d=3,d^\prime=2,n=4)の場合だと以下になる:
$$
\begin{bmatrix}
5&-1&5&11\\
-2&-2&1&-1
\end{bmatrix}=
\begin{bmatrix}
1&2&3\\
0&-1&1
\end{bmatrix}
\begin{bmatrix}
1&0&2&-1\\
2&1&0&3\\
0&-1&1&2
\end{bmatrix}
$$
ここでの $n$ はバッチサイズと呼ばれ、同時に処理されるデータの数を表す。これは、GPUなどの並列計算資源を最大限に活用するための単位であり、ディープラーニングや大規模データ処理において不可欠な概念である。各列ベクトル(個々の入力)に対する演算が独立しているため、スケーラブルかつ効率的な処理が可能となる。
バッチサイズ(batch size)とは、機械学習や並列処理において一度に処理されるデータの個数を指す。たとえば、画像分類タスクでバッチサイズが32であれば、32枚の画像が同時にネットワークに入力され、同じ重み行列に対して並列に処理される。
線形代数的には、各入力ベクトルを列として並べた行列 $X\in \mathbb{R}^{d\times n}$ に対して、変換行列Aを一括で適用する操作に相当する。GPUなどの並列計算資源を活用する上で、バッチ処理は計算効率とメモリ最適化の鍵となる。
加えて、変換行列の各「行」に対応する演算もまた独立しており、出力ベクトルの各成分は入力ベクトルとの内積によって個別に計算される:
$$
y_i=a_j\cdot x\ \ (j=1,2,\dots,d^\prime)
$$
ここで $a_j$ は変換行列Aの第j行であり、各 $y_i$ の計算は他の出力成分と独立している。これは、出力次元ごとの処理が並列化可能であることを意味し、ニューラルネットワークのフォワードパスなどにおいて重要な性質である。
このように、入力方向(列)と出力方向(行)の両面で並列性が存在することは、線形代数的モデルが高いスケーラビリティを持つ理由の一つであり、オブジェクト指向的な設計においても有用な視点となる。
オブジェクトを「状態遷移を担う変換行列」として捉えることで、物理的直感・数理的記述・並列処理の効率性が統合され、現代のソフトウェア設計における抽象化の強力な枠組みとなる。
例:オブジェクトを線形変換として表現する
import numpy as np
# 「オブジェクト」としての変換行列(例:2次元空間の回転)
class LinearObject:
def __init__(self, matrix):
self.matrix = matrix # 変換行列
def apply(self, vector):
return self.matrix @ vector # 線形変換を適用
# 例:2次元空間におけるオブジェクト(回転行列)による線形変換の適用
theta = np.pi / 4
rotation_matrix = np.array([
[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]
])
# オブジェクトを生成
rotator = LinearObject(rotation_matrix)
# 入力ベクトル
x = np.array([[1], [0]])
# 出力ベクトル(回転後)
y = rotator.apply(x)
print("入力ベクトル:\n", x)
print("変換後ベクトル:\n", y)
入力ベクトル:
[[1]
[0]]
変換後ベクトル:
[[0.70710678]
[0.70710678]]
コメント