情報学部 菅沼ホーム 目次 索引

NumPy

  数学関係のプログラムにおいて,拡張モジュール NumPy がよく使用されています.配列(または,行列)は,多くの分野で頻繁に使用されています.Python における配列や行列に対する処理方法に問題があるとすれば,NumPy が使用されるのも当然だと思います.しかし,Python の仕様に不都合があるようであれば,当然,Python 自体の仕様を見直すべきだと思いますが,現時点では,そのようなこともいっておられません.そこで,ここでは,主として,多次元配列を扱う numpy.ndarray モジュールについて簡単に説明していきます.

  Python において多次元配列を表現するには,多重のリストが利用されます.リストでは,各セル毎に異なるオブジェクトを保持したり,各次元毎に要素数が異なるリストを生成できるなど,非常に汎用的なリストを実現できます.しかし,リンクでセルを結合した形式でメモリ上に保持されますので,処理速度の点で問題になります.

  numpy.ndarray モジュールでは,C/C++ の配列と同様,メモリの連続領域上に確保されます.また,各要素の型はすべて同じで,かつ,各次元ごとの要素数が等しくなければなりません.このことによって,より高速な処理が可能になっています.Python 内にも,リスト内に同じ型のデータだけを保持し,処理の高速化を狙った array オブジェクトが存在しますが,多次元配列への対応が多少面倒です.

  また,要素毎に何らかの処理をしたいような場合,例えば,各要素の平方根を計算したい場合,Python や C/C++ においては,繰り返しのプログラムを書く必要があります.しかし,numpy.ndarray モジュールには,ユニバーサル関数が準備されています.配列に対してこれらの関数を適用すると,自動的に,配列の各要素に対して希望する処理を適用してくれます.このことによって,プログラムの記述がかなり容易になるはずです.ただし,繰り返しのプログラム自体はそれほど面倒な処理ではなく,また,C++ であれば,関数名や演算子のオーバーロード機能を使用して,適切な処理方法を前もって用意しておけば良いだけのことです.この点だけを考えれば,Python の本質的な問題点であるとは思えません.むしろ,NumPy の中には,簡潔な記述を望むあまり,Python に詳しくない人にとっては理解することが困難な記述が多いことの方が問題だと思います.

  1. 配列の生成

      配列を生成する最も基本的な方法は,

    numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)

    を利用する方法です.ここで,object はリストタプルです.また,dtype はデータの型を表し,numpy.bool,numpy.int,numpy.float,numpy.complex などが使用されます.生成された array オブジェクトは,以下に示すようなインスタンス変数を持っています.

    • dtype : データの型.numpy.bool,numpy.int,numpy.float,numpy.complex など

    • itemsize : 1 要素のバイト数

    • nbytes : 配列全体のバイト数

    • ndim : 配列の次元

    • shape : 配列の形をタプルで表現.例えば,要素数が 3 の 1 次元配列では (3,),2 行 3 列の配列では (2, 3) となる.

    • size : 配列の全要素数

      02 行目の x のように指定すると,すべての要素は整数とみなされます.その結果,問題が起こる場合もありますので,浮動小数点数として扱いたい場合は,03 行目の z のように小数点を付加するか,または,04 行目の y のようにデータの型を指定してください.また,1 次元配列を,下の例における 02,03 行目のように宣言すると,それが,1 行 3 列なのか,あるいは,3 行 1 列 なのかが明確になりません.それを明確にしたい場合は,変数 u,v のような方法( 11 行目以降)を使用してください.
    01	>>> import numpy as np   # この方法が良く利用される
    02	>>> x = np.array([1, 2, 3])  # (1 行 3 列) or (3 行 1 列) ?
    03	>>> z = np.array([1.0, 2, 3])
    04	>>> y = np.array([[1, 2, 3], [4, 5, 6]], np.float)
    05	>>> x.dtype, y.dtype, z.dtype
    06	(dtype('int32'), dtype('float64'), dtype('float64'))
    07	>>> x.ndim, y.ndim
    08	(1, 2)
    09	>>> x.shape, y.shape
    10	((3,), (2, 3))
    11	>>> u = np.array([[1, 2, 3]])  # 1 行 3 列
    12	>>> v = np.array([[1], [2], [3]])  # 3 行 1 列
    13	>>> u.shape, v.shape
    14	((1, 3), (3, 1))
    			
      また,特別な初期値を持った配列を簡単に作成する方法もあります.

    • numpy.zeros(shape, dtype=None)

        すべての要素が 0 である配列

    • numpy.ones(shape, dtype=None)

        すべての要素が 1 である配列

    • numpy.empty(shape, dtype=None)

        すべての要素の値が不定である配列

    • numpy.zeros_like(a, dtype=None)
      numpy.ones_like(a, dtype=None)
      numpy.empty_like(a, dtype=None)

        各々,既に作成した配列 a と同じ大きさで,かつ,すべての要素を 0,すべての要素を 1,または,すべての要素を不定にした配列
      >>> import numpy as np   # この方法が良く利用される
      >>> np.zeros(2)
      array([ 0.,  0.])
      >>> np.zeros((2, 3))
      array([[ 0.,  0.,  0.],
             [ 0.,  0.,  0.]])
      >>> np.ones(3)
      array([ 1.,  1.,  1.])
      >>> np.empty(3)
      array([ 0.,  0.,  0.])
      >>> a = np.array([1, 2, 3])
      >>> a
      array([1, 2, 3])
      >>> np.zeros_like(a)
      array([0, 0, 0])
      				
      さらに,特別な配列を生成するメソッド,または,簡単な生成方法を行うメソッドが多数存在します.

    • numpy.arange([start, ]stop, [step, ]dtype=None)

        arange は,組み込み関数 range とほぼ同じ使用方法である.
      >>> import numpy as np   # この方法が良く利用される
      >>> np.arange(0, 5)
      array([0, 1, 2, 3, 4])
      >>> np.array([np.arange(1, 4), np.arange(4, 7)])
      array([[1, 2, 3],
             [4, 5, 6]])				

    • ndarray.copy(order='C') : インスタンスメソッド

        配列オブジェクトの深いコピー
      >>> import numpy as np   # この方法が良く利用される
      >>> v = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
      >>> w = v   # 代入
      >>> w[1][2] = 100   # w の要素の値を変更
      >>> w
      array([[  1,   2,   3],
             [  4,   5, 100],
             [  7,   8,   9]])
      >>> v
      array([[  1,   2,   3],
             [  4,   5, 100],   # v の値も変化
             [  7,   8,   9]])
      >>> x = v.copy()   # v の深いコピーを生成
      >>> x[1][2] = 200   # x の要素の値を変更
      >>> x
      array([[  1,   2,   3],
             [  4,   5, 200],   # x の値だけが変化
             [  7,   8,   9]])
      >>> v
      array([[  1,   2,   3],
             [  4,   5, 100],
             [  7,   8,   9]])
      >>> w
      array([[  1,   2,   3],
             [  4,   5, 100],
             [  7,   8,   9]])
      				

    • numpy.diag(v, k=0)

        配列 v から対角,または,それに近い要素から配列を生成.k が 0 の時は対角要素から,正の時は対角要素の k 個上の要素から,また,負の時は対角要素の k 個下の要素からなる配列を生成.(このような機能,必要?
      >>> import numpy as np   # この方法が良く利用される
      >>> v = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
      >>> v
      array([[1, 2, 3],
             [4, 5, 6],
             [7, 8, 9]])
      >>> np.diag(v)
      array([1, 5, 9])
      >>> np.diag(v, k = 1)
      array([2, 6])
      >>> np.diag(v, k = -1)
      array([4, 8])
      				

    • numpy.eye(n, m=None, k=0, dtype=<type 'float'>)

        n 行 m 列( m を省略すると n に等しくなる)の配列の対角要素を 1 に設定する.k に正または負の値を設定すると,対角要素ではなく,対角要素の k 個上(正の場合),または,下(負の場合)の要素を 1 に設定する.(このような機能,必要?
      >>> import numpy as np   # この方法が良く利用される
      >>> np.eye(3, 4)
      array([[ 1.,  0.,  0.,  0.],
             [ 0.,  1.,  0.,  0.],
             [ 0.,  0.,  1.,  0.]])
      >>> np.eye(3, 4, k = -1)
      array([[ 0.,  0.,  0.,  0.],
             [ 1.,  0.,  0.,  0.],
             [ 0.,  1.,  0.,  0.]])				

    • numpy.identity(n, dtype=None)

        n 次元の対角要素だけが 1 である配列
      >>> import numpy as np   # この方法が良く利用される
      >>> np.identity(3)
      array([[ 1.,  0.,  0.],
             [ 0.,  1.,  0.],
             [ 0.,  0.,  1.]])				

    • numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

        [start, stop] 区間を等分割した num 個の点(始点及び終点を含む)からなる配列.(このような機能,必要?
      >>> import numpy as np   # この方法が良く利用される
      >>> np.linspace(0, 4, 9)
      array([ 0. ,  0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ])				

    • numpy.random.randint(low, high=None, size=None, dtype='l')

        各要素の値を乱数によって決めた配列.
      >>> import numpy as np   # この方法が良く利用される
      >>> np.random.randint(0,100,10)
      array([ 4, 79,  4, 27, 52, 19, 15, 31, 63, 88])				

    • numpy.tile(A, reps)

        A を reps 回繰り返した配列(このような機能,必要?).
      >>> import numpy as np   # この方法が良く利用される
      >>> np.tile([1, 2], 3)
      array([1, 2, 1, 2, 1, 2])				

    • numpy.tri(n, m=None, k=0, dtype=<type 'float'>)

        n 行 m 列( m を省略すると n に等しくなる)の下三角の配列.k が 0 の時は対角要素まで,正の時は対角要素の k 個上まで,また,負の時は対角要素の k 個下までの要素を 1 に設定する.
      >>> import numpy as np   # この方法が良く利用される
      >>> np.tri(3, k = 0)
      array([[ 1.,  0.,  0.],
             [ 1.,  1.,  0.],
             [ 1.,  1.,  1.]])
      >>> np.tri(3, k = 1)
      array([[ 1.,  1.,  0.],
             [ 1.,  1.,  1.],
             [ 1.,  1.,  1.]])
      >>> np.tri(3, k = -1)
      array([[ 0.,  0.,  0.],
             [ 1.,  0.,  0.],
             [ 1.,  1.,  0.]])
      				

  2. 配列の参照と変更

      配列要素の値を参照や修正するには,リストと同様,添え字やスライスを利用できます.
    >>> import numpy as np   # この方法が良く利用される
    >>> a = np.array([[1, 2, 3], [4, 5, 6]])
    >>> a[1][2] = 10
    >>> a
    array([[ 1,  2,  3],
           [ 4,  5, 10]])
    >>> a[0][1:3] = [20, 20]   # a[0][1:3] = 20 でも同じ
    >>> a
    array([[ 1, 20, 20],
           [ 4,  5, 10]])
    >>> a[2:4] = [20, 20]   # 不可能( 1 次元配列としては処理できない)
    			
      添え字やスライスの基本的な使用方法に加え,以下に示すように,かなり特殊な使用法も可能です.ただし,便利だからといって,これらの方法は余り勧められません.他の方法で簡単に記述でき,かつ,そのようにすれば,Python に詳しくない人でもプログラムを容易に理解できるからです.
    >>> import numpy as np   # この方法が良く利用される
    >>> a = np.array([1, 2, 3, 4, 5, 6])
    >>> a[[0, 2, 4]]   # 添え字 0,2,4 の要素からなる配列
    array([1, 3, 5])
    >>> a > 3   # 各要素と 3 を比較した結果から構成される配列
    array([False, False, False,  True,  True,  True], dtype=bool)
    >>> a[a > 3]   # 3 より大きい要素から構成される配列
    array([4, 5, 6])
    >>> a[a > 3] = 100   # 3 より大きい要素に 100 を代入
    >>> a
    array([  1,   2,   3, 100, 100, 100])
    			
      配列要素の型を変更(キャスト)するためには,インスタントメソッド,

    ndarray.astype(dtype, order='K', casting='unsafe', subok=True, copy=True)

    を使用できます.このメソッドによって,元の配列が修正されるわけではなく,修正した内容を持つ新しい配列が生成されます.
    >>> import numpy as np   # この方法が良く利用される
    >>> a = np.array([1.2, 2.3, 3.14])
    >>> b = a.astype(np.int)
    >>> a
    array([ 1.2 ,  2.3 ,  3.14])
    >>> a.dtype
    dtype('float64')
    >>> b
    array([1, 2, 3])
    >>> b.dtype
    dtype('int32')
    			
      また,配列の形や要素数の変更,例えば,1 次元配列から 2 次元配列への変更なども可能です.配列の形を変更するための関数やインスタントメソッドとしては,以下に示すようなものがあります.

    • ndarray.flatten(order='C') : インスタンスメソッド

        多次元配列を 1 次元配列に変換した新しい配列を返す.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> b = a.flatten()
      >>> a
      array([[1, 2, 3],
             [4, 5, 6]])
      >>> b
      array([1, 2, 3, 4, 5, 6])				

    • numpy.reshape(a, newshape, order='C')
      ndarray.reshape(shape, order='C') : インスタンスメソッド

        配列 a を指定された形に変更し,その結果( view )を返す.view は,元の配列の表示形式を変更しているだけであり,同じ配列を指している.そのため,いずれかの配列の値を変更すれば,他の配列の値も変更される.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> b = np.reshape(a, 6)
      >>> b
      array([1, 2, 3, 4, 5, 6])
      >>> a[0][2] = 10
      >>> a
      array([[ 1,  2, 10],
             [ 4,  5,  6]])
      >>> b
      array([ 1,  2, 10,  4,  5,  6])
      				

    • numpy.resize(a, new_shape)
      ndarray.resize(new_shape, refcheck=True) : インスタンスメソッド

        配列 a を指定された形に変更し,新しい配列を返す.インスタントメソッドの場合は,オブジェクト(配列)自身を変更する.また,一度でも配列を参照していると,要素数の変更は不可能になる.ただし,キーワード refcheck を False に設定すれば可能である.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> b = np.resize(a, 6)
      >>> b
      array([1, 2, 3, 4, 5, 6])
      >>> a[0][2] = 10
      >>> a
      array([[ 1,  2, 10],
             [ 4,  5,  6]])
      >>> b
      array([1, 2, 3, 4, 5, 6])
              # インスタントメソッド
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> a.resize(6)
      >>> a
      array([1, 2, 3, 4, 5, 6])
      >>> a.resize(8)   # 不可能
      >>> a.resize(8, refcheck = False)
      >>> a
      array([1, 2, 3, 4, 5, 6, 0, 0])
      				

    • numpy.transpose(a, axes=None)
      ndarray.transpose(*axes) : インスタンスメソッド

        配列の転置(行と列の入れ替え)
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> a
      array([[1, 2, 3],
             [4, 5, 6]])
      >>> a.transpose()
      array([[1, 4],
             [2, 5],
             [3, 6]])
      >>> b = np.array([[1, 2, 3]])
      >>> b
      array([[1, 2, 3]])
      >>> b.transpose()
      array([[1],
             [2],
             [3]])
      				

  3. 配列内の検索

      配列内の要素を検索するための関数やインスタントメソッドとしては,以下に示すようなものがあります.

    • numpy.argmax(a, axis=None, out=None)
      ndarray.argmax(axis=None, out=None) : インスタンスメソッド

        最大となる要素を探し,その最も小さい添え字を返す.多次元配列の場合は,その配列を 1 次元配列とみなした添え字を返す.

    • numpy.argmin(a, axis=None, out=None)
      ndarray.argmin(axis=None, out=None) : インスタンスメソッド

        最小となる要素を探し,その最も小さい添え字を返す.多次元配列の場合は,その配列を 1 次元配列とみなした添え字を返す.

    • numpy.nonzero(a)
      ndarray.nonzero() : インスタンスメソッド

        0 でない要素の添え字から構成されるか配列を返す.

    • numpy.where(condition[, x, y])

        条件が真であれば x の要素,偽であれば y の要素から構成されるか配列を返す.x,y が省略された場合は,condition 内に記述された配列内で,条件を満たす要素の添え字から構成される配列を返す.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 0, 0], [3, 3, 0]])
      >>> a.argmax()
      3   # a を 1 次元配列としてみた位置
      >>> a.argmin()
      1
      >>> a.nonzero()   # a[0][0], a[1][0],a[1][1]
      (array([0, 1, 1], dtype=int32), array([0, 0, 1], dtype=int32))
      >>> np.where(a > 2)   # a[1][0],a[1][1]
      (array([1, 1], dtype=int32), array([0, 1], dtype=int32))
      >>> np.where([True, False, True], [1, 2, 3], [10, 20, 30])
      array([ 1, 20,  3])
      				

  4. 配列における演算

      配列に対しても,加減乗除,余り,べき乗などの演算が可能です.対応する要素毎,または,要素毎に目的とする演算が行われます.
    >>> import numpy as np   # この方法が良く利用される
    >>> a = np.array([[1, 2], [3, 4]])
    >>> b = np.array([[1, 0], [0, 1]])
    >>> a + b
    array([[2, 2],
           [3, 5]])
    >>> a * b
    array([[1, 0],
           [0, 4]])
    >>> a ** 2
    array([[ 1,  4],
           [ 9, 16]])
    >>> a * 2
    array([[2, 4],
           [6, 8]])
    >>> a / 2
    array([[ 0.5,  1. ],
           [ 1.5,  2. ]])
    			

      また,ほとんどの math モジュールに対応するユニバーサル関数が用意されていますので,配列の各要素に同じ演算を簡単に実行できます.(このような機能,必要?
    >>> import numpy as np   # この方法が良く利用される
    >>> a = np.array([[1, 2], [3, 4]])
    >>> np.sqrt(a)
    array([[ 1.        ,  1.41421356],
           [ 1.73205081,  2.        ]])			

      行列matrix )は,配列と似ていますが同じものではありません.例えば,先に述べた配列同士の乗算は,行列同士の乗算とは異なります.行列としても演算を行いたい場合は,

    class numpy.matrix(data, dtype=None, copy=True)

    を使用する必要があります.同様に,ベクトルvector )も,3 行 1 列(列ベクトル),または,1 行 3 列(行ベクトル)の行列として定義する必要があります.data が配列の場合は,同じ形の行列を生成してくれます.なお,配列に対して適用できる関数のほとんどは,行列に対しても適用できます.
    >>> import numpy as np   # この方法が良く利用される
    >>> A = np.matrix([[1, 2], [3, 4]])   # 2 行 2 列の行列
    >>> B = np.matrix([[1, 0], [0, 1]])   # 2 行 2 列の行列
    >>> A * B   # 行列の積
    matrix([[1, 2],
            [3, 4]])
    >>> A * 2   # スカラーをかける
    matrix([[2, 4],
            [6, 8]])
    >>> A / 2   # スカラーで割る
    matrix([[ 0.5,  1. ],
            [ 1.5,  2. ]])
    >>> A ** 2   # A * A
    matrix([[ 7, 10],
            [15, 22]])
    >>> u = np.matrix([[1, 2, 3]])   # 1 行 3 列の行列(行ベクトル)
    >>> v = np.matrix([[1], [2], [3]])   # 3 行 1 列の行列(列ベクトル)
    >>> u * v   # 行列の積(内積に相当する演算)
    matrix([[14]])
    			

  5. 配列に対するファイル入出力

      配列に対して,ファイル入出力を行う関数として,以下のようなものがあります.

    • numpy.loadtxt(fname, dtype=, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
      numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ')

        テキストファイルの入出力
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> np.savetxt('test.txt', a)
      >>> b = np.loadtxt('test.txt')
      >>> b
      array([[ 1.,  2.,  3.],
             [ 4.,  5.,  6.]])				

    • numpy.load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, encoding='ASCII')
      numpy.save(file, arr, allow_pickle=True, fix_imports=True)

        バイナリー形式での入出力.出力ファイルの拡張子は「 .npy 」となる.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> np.save('test_data', a)
      >>> b = np.load('test_data.npy')
      >>> b
      array([[1, 2, 3],
             [4, 5, 6]])				

    • numpy.savez(file, *args, **kwds)

        複数データのバイナリー形式での入出力.出力ファイルの拡張子は「 .npz 」となる.
      >>> import numpy as np   # この方法が良く利用される
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])
      >>> b = np.array([10, 20, 30])
      >>> np.savez('test_data', x = a, y = b)
      >>> data = np.load('test_data.npz')
      >>> data.files
      ['y', 'x']
      >>> data['x']
      array([[1, 2, 3],
             [4, 5, 6]])
      >>> data['y']
      array([10, 20, 30])
      				

  6. listarray,NumPy,及び,C/C++ の比較

      以下,listarrayNumPy の arrayNumPy の matrix,及び,C/C++ において,配列に対するファイル入出力,加算,減算,乗算,ユニバーサル関数機能(ここでは,平方根 sqrt を使用)の比較を行ってみます.

    list

    # -*- coding: UTF-8 -*-
    	# file 入出力
    f = open("test.txt", "w")   # 出力
    f.write("1 2 3\n")
    f.write("4 5 6\n")
    f.close()
    f = open("test.txt", "r")   # 入力
    A = [[], []]
    for i1 in range(0, 2):
    	A[i1] = f.readline().split()
    	for i2 in range(0, 3):
    		x = int(A[i1][i2])
    		A[i1][i2] = x;
    f.close()
    print("*** A ***")
    print(A)
    	# 設定
    B = [[0, 0, 0], [4, 5, 6]]
    print("*** B ***")
    print(B)
    C = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    print("*** C ***")
    print(C)
    	# 演算
    print("*** A+B ***")
    print(A+B)   # 行列の加算ではない
    print("*** A-B ***")
    print("  不可能")
    print("*** A*B ***")
    print("  不可能")
    print("*** sqrt(A) ***")
    print("  不可能")
    			
    (出力)
    *** A ***
    [[1, 2, 3], [4, 5, 6]]
    *** B ***
    [[0, 0, 0], [4, 5, 6]]
    *** C ***
    [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    *** A+B ***
    [[1, 2, 3], [4, 5, 6], [0, 0, 0], [4, 5, 6]]
    *** A-B ***
      不可能
    *** A*C ***
      不可能
    *** sqrt(A) ***
      不可能
    			

    array

    # -*- coding: UTF-8 -*-
    from array import *
    	# file 入出力
    f = open("test.txt", "w")   # 出力
    f.write("1 2 3\n")
    f.write("4 5 6\n")
    f.close()
    f = open("test.txt", "r")   # 入力
    A = [array("f", [0, 0, 0]), array("f", [0, 0, 0])]
    for i1 in range(0, 2):
    	x = f.readline().split()
    	for i2 in range(0, 3):
    		y = float(x[i2])
    		A[i1][i2] = y;
    f.close()
    print("*** A ***")
    print(A)
    	# 設定
    B = [array("f", [0, 0, 0]), array("f", [4, 5, 6])]
    print("*** B ***")
    print(B)
    C = [array("f", [1, 0, 0]), array("f", [0, 1, 0]), array("f", [0, 0, 1])]
    print("*** C ***")
    print(C)
    	# 演算
    print("*** A+B ***")
    print(A+B)   # 行列の加算ではない
    print("*** A-B ***")
    print("  不可能")
    print("*** A*B ***")
    print("  不可能")
    print("*** sqrt(A) ***")
    print("  不可能")
    			
    (出力)
    *** A ***
    [array('f', [1.0, 2.0, 3.0]), array('f', [4.0, 5.0, 6.0])]
    *** B ***
    [array('f', [0.0, 0.0, 0.0]), array('f', [4.0, 5.0, 6.0])]
    *** C ***
    [array('f', [1.0, 0.0, 0.0]), array('f', [0.0, 1.0, 0.0]), array('f', [0.0, 0.0, 1.0])]
    *** A+B ***
    [array('f', [1.0, 2.0, 3.0]), array('f', [4.0, 5.0, 6.0]), array('f', [0.0, 0.0, 0.0]), array('f', [4.0, 5.0, 6.0])]
    *** A-B ***
      不可能
    *** A*B ***
      不可能
    *** sqrt(A) ***
      不可能
    			

    NymPy array

    # -*- coding: UTF-8 -*-
    import numpy as np
    	# file 入出力
    np.savetxt('test.txt', np.array([[1, 2, 3], [4, 5, 6]]))   # 出力
    A = np.loadtxt('test.txt')   # 入力
    print("*** A ***")
    print(A)
    	# 設定
    B = np.array([[0, 0, 0], [4, 5, 6]])
    print("*** B ***")
    print(B)
    C = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    print("*** C ***")
    print(C)
    	# 演算
    print("*** A+B ***")
    print(A+B)   # 行列の加算
    print("*** A-B ***")
    print(A-B)   # 行列の減算
    print("*** A*B ***")
    print(A*B)   # 行列の乗算ではない
    print("*** A*C ***")
    print("  不可能")
    print("*** sqrt(A) ***")
    print(np.sqrt(A))   # ユニバーサル関数
    			
    (出力)
    *** A ***
    [[ 1.  2.  3.]
     [ 4.  5.  6.]]
    *** B ***
    [[0 0 0]
     [4 5 6]]
    *** C ***
    [[1 0 0]
     [0 1 0]
     [0 0 1]]
    *** A+B ***
    [[  1.   2.   3.]
     [  8.  10.  12.]]
    *** A-B ***
    [[ 1.  2.  3.]
     [ 0.  0.  0.]]
    *** A*B ***
    [[  0.   0.   0.]
     [ 16.  25.  36.]]
    *** A*C ***
      不可能
    *** sqrt(A) ***
    [[ 1.          1.41421356  1.73205081]
     [ 2.          2.23606798  2.44948974]]
    			

    NymPy matrix

    # -*- coding: UTF-8 -*-
    import numpy as np
    	# file 入出力
    np.savetxt('test.txt', np.matrix([[1, 2, 3], [4, 5, 6]]))   # 出力
    A = np.loadtxt('test.txt')   # 入力
    print("*** A ***")
    print(A)
    	# 設定
    B = np.matrix([[0, 0, 0], [4, 5, 6]])
    print("*** B ***")
    print(B)
    C = np.matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    print("*** C ***")
    print(C)
    	# 演算
    print("*** A+B ***")
    print(A+B)   # 行列の加算
    print("*** A-B ***")
    print(A-B)   # 行列の減算
    print("*** A*B ***")
    print("  不可能")
    print("*** A*C ***")
    print(A*C)   # 行列の乗算
    print("*** sqrt(A) ***")
    print(np.sqrt(A))   # ユニバーサル関数
    			
    (出力)
    *** A ***
    [[ 1.  2.  3.]
     [ 4.  5.  6.]]
    *** B ***
    [[0 0 0]
     [4 5 6]]
    *** C ***
    [[1 0 0]
     [0 1 0]
     [0 0 1]]
    *** A+B ***
    [[  1.   2.   3.]
     [  8.  10.  12.]]
    *** A-B ***
    [[ 1.  2.  3.]
     [ 0.  0.  0.]]
    *** A*B ***
      不可能
    *** A*C ***
    [[ 1.  2.  3.]
     [ 4.  5.  6.]]
    *** sqrt(A) ***
    [[ 1.          1.41421356  1.73205081]
     [ 2.          2.23606798  2.44948974]]
    			

    C++ の場合

      C/C++ に対しては,以下に示すように,クラス Matrix が定義されていると共に,必要な関数,及び,演算子のオーバーロードが行われているものとします.
    /**********************/
    /* クラスMatrixの定義 */
    /**********************/
    class Matrix {       /* 2次元行列 */
    		int n;              // 行の数
    		int m;              // 列の数
    	public:
    		double **mat;       // 行列本体
    		Matrix(int, int, double **);   // コンストラクタ(引数 3)
    		Matrix(int, int);   // コンストラクタ(引数 2)
    		Matrix(const Matrix &);   // 初期化のためのコンストラクタ
    		Matrix() {n = 0;}   // コンストラクタ(引数無し)
    		~Matrix()   // デストラクタ
    		{
    			if (n > 0) {
    				int i1;
    				for (i1 = 0; i1 < n; i1++)
    					delete [] mat[i1];
    				delete [] mat;
    			}
    		}
    		Matrix &operator= (const Matrix &);   // =のオーバーロード
    		Matrix operator+ (const Matrix &);          // +のオーバーロード
    		Matrix operator- (const Matrix &);          // -のオーバーロード
    		Matrix operator* (const Matrix &);          // *のオーバーロード
    	friend ostream &operator << (ostream &, Matrix);     // << のオーバーロード
    	friend Matrix sqrt(const Matrix &);     // 各要素の平方根
    };
    
    /****************************/
    /* コンストラクタ(引数 3) */
    /****************************/
    Matrix::Matrix(int n1, int m1, double **x)
    {
    	n    = n1;
    	m    = m1;
    	mat  = new double * [n];
    	for (int i1 = 0; i1 < n; i1++) {
    		mat[i1] = new double [m];
    		for (int i2 = 0; i2 < m; i2++)
    			mat[i1][i2] = x[i1][i2];
    	}
    }
    
    /****************************/
    /* コンストラクタ(引数 2) */
    /****************************/
    Matrix::Matrix(int n1, int m1)
    {
    	n    = n1;
    	m    = m1;
    	mat  = new double * [n];
    	for (int i1 = 0; i1 < n; i1++)
    		mat[i1] = new double [m];
    }
    
    /********************************/
    /* 初期化のためのコンストラクタ */
    /********************************/
    Matrix::Matrix(const Matrix &A)
    {
    	n    = A.n;
    	m    = A.m;
    	mat  = new double * [n];
    	for (int i1 = 0; i1 < n; i1++) {
    		mat[i1] = new double [m];
    		for (int i2 = 0; i2 < m; i2++)
    			mat[i1][i2] = A.mat[i1][i2];
    	}
    }
    
    /********************************/
    /* 出力( << のオーバーロード) */
    /********************************/
    ostream &operator << (ostream &stream, Matrix A)
    {
    	for (int i1 = 0; i1 < A.n; i1++) {
    		for (int i2 = 0; i2 < A.m; i2++)
    			stream << " " << A.mat[i1][i2];
    		stream << "\n";
    	}
    
    	return stream;
    }
    
    /*******************************/
    /* =のオーバーロード          */
    /*      A = B (A.operator=(B)) */
    /*******************************/
    Matrix& Matrix::operator= (const Matrix &B)
    {
    	if (&B != this) {   // 自分自身への代入を防ぐ
    		if (n > 0) {   // 代入する前のメモリを解放
    			for (int i1 = 0; i1 < n; i1++)
    				delete [] mat[i1];
    			delete [] mat;
    		}
    		n        = B.n;
    		m        = B.m;
    		mat  = new double * [n];   // メモリの確保と代入
    		for (int i1 = 0; i1 < n; i1++) {
    			mat[i1] = new double [m];
    			for (int i2 = 0; i2 < m; i2++)
    				mat[i1][i2] = B.mat[i1][i2];
    		}
    	}
    
    	return *this;
    }
    
    /**********************/
    /* +のオーバーロード */
    /**********************/
    Matrix Matrix::operator + (const Matrix &B)
    {
    	if (n != B.n || m != B.m) {
    		cout << "***error  invalid data\n";
    		exit(1);
    	}
    
    	Matrix C(n, m);
    
    	for (int i1 = 0; i1 < n; i1++) {
    		for (int i2 = 0; i2 < m; i2++)
    			C.mat[i1][i2] = mat[i1][i2] + B.mat[i1][i2];
    	}
    
    	return C;
    }
    
    /**********************/
    /* -のオーバーロード */
    /**********************/
    Matrix Matrix::operator - (const Matrix &B)
    {
    	if (n != B.n || m != B.m) {
    		cout << "***error  invalid data\n";
    		exit(1);
    	}
    
    	Matrix C(n, m);
    
    	for (int i1 = 0; i1 < n; i1++) {
    		for (int i2 = 0; i2 < m; i2++)
    			C.mat[i1][i2] = mat[i1][i2] - B.mat[i1][i2];
    	}
    
    	return C;
    }
    
    /**********************/
    /* *のオーバーロード */
    /**********************/
    Matrix Matrix::operator* (const Matrix &B)
    {
    	if (m != B.n) {
    		cout << "***error  invalid data\n";
    		exit(1);
    	}
    
    	Matrix C(n, B.m);
    
    	for (int i1 = 0; i1 < n; i1++) {
    		for (int i2 = 0; i2 < B.m; i2++) {
    			C.mat[i1][i2] = 0.0;
    			for (int i3 = 0; i3 < m; i3++)
    				C.mat[i1][i2] += mat[i1][i3] * B.mat[i3][i2];
    		}
    	}
    
    	return C;
    }
    
    /******************/
    /* 各要素の平方根 */
    /******************/
    Matrix sqrt(const Matrix &A)
    {
    	Matrix C(A.n, A.m);
    
    	for (int i1 = 0; i1 < A.n; i1++) {
    		for (int i2 = 0; i2 < A.m; i2++)
    			C.mat[i1][i2] = sqrt(A.mat[i1][i2]);
    	}
    
    	return C;
    }
    			

    main プログラム

    int main()
    {
    		// file 入出力
    	FILE *out = fopen("test.txt", "w");   // 出力
    	for (double i1 = 1; i1 <= 3; i1++)
    		fprintf(out, " %f", i1);
    	fprintf(out, "\n");
    	for (double i1 = 4; i1 <= 6; i1++)
    		fprintf(out, " %f", i1);
    	fprintf(out, "\n");
    	fclose(out);
    	FILE *in = fopen("test.txt", "r");   // 入力
    	double **x = new double *[2];
    	for (int i1 = 0; i1 < 2; i1++) {
    		x[i1] = new double [3];
    		fscanf(in, "%lf %lf %lf", &x[i1][0], &x[i1][1], &x[i1][2]);
    	}
    	fclose(in);
    	Matrix A(2, 3, x);
    		// 設定
    	Matrix B = A;
    	for (int i1 = 0; i1 < 3; i1++)
    		B.mat[0][i1] = 0;
    
    	double **z = new double *[3];
    	z[0] = new double [3];
    	z[0][0] = 1;
    	z[0][1] = 0;
    	z[0][2] = 0;
    	z[1] = new double [3];
    	z[1][0] = 0;
    	z[1][1] = 1;
    	z[1][2] = 0;
    	z[2] = new double [3];
    	z[2][0] = 0;
    	z[2][1] = 0;
    	z[2][2] = 1;
    	Matrix C(3, 3, z);
    		// 演算
    	cout << "*** A ***\n" << A;
    	cout << "*** B ***\n" << B;
    	cout << "*** C ***\n" << C;
    	cout << "*** A+B ***\n" << A+B;   // 行列の加算
    	cout << "*** A-B ***\n" << A-B;   // 行列の減算
    	cout << "*** A*C ***\n" << A*C;   // 行列の乗算
    	cout << "*** sqrt(A) ***\n" << sqrt(A);   // ユニバーサル関数
    
    	return 0;
    }
    			
    (出力)
    *** A ***
     1 2 3
     4 5 6
    *** B ***
     0 0 0
     4 5 6
    *** C ***
     1 0 0
     0 1 0
     0 0 1
    *** A+B ***
     1 2 3
     8 10 12
    *** A-B ***
     1 2 3
     0 0 0
    *** A*C ***
     1 2 3
     4 5 6
    *** sqrt(A) ***
     1 1.41421 1.73205
     2 2.23607 2.44949
    			

情報学部 菅沼ホーム 目次 索引