| INDEX |

2月はのんべんだらりと暮らしたかったのですが、なかなかそうもいかないようで。
最近は多変量解析の勉強をしているのですが、その関連で行列の計算が必要だったので簡単なものをつくってみました。

とりあえず今必要な計算だけ書いてみました。例外処理とか全然やっていないですが。結構適当です。

public class MMatrix {
  
  internal var _m:uint;
  internal var _n:uint;
  internal var values:Array;
  
  /**
   * Constructor
   * @param  行数
   * @param  列数
   * @param  データ[...]
   */
  public function MMatrix(m_:uint,n_:uint,da:Array=null) {
    _m = m_;
    _n = n_;
    values = new Array(_m*_n);
    if( da!=null && _m*_n == da.length ){
      for( var i:int=0; i<da.length; i++ ){
        values[i] = da[i];
      }
    }
  }
  
  /**
   * 入れ子配列からコンストラクト
   * @param  [[a,b,c,...],[a,b,c,...],..]
   * @return
   */
  public static function makeFromArray( da:Array ):MMatrix{
    var mtx:MMatrix = new MMatrix( da.length, (da[0] as Array).length );
    var k:int=0;
    for( var i:int=0; i<mtx.m; i++ ){
      for( var j:int=0; j<mtx.n; j++ ){
        mtx.values[k] = da[i][j];
        k++;
      }
    }
    return mtx;
  }
  
  public function clone():MMatrix{
    var mtx:MMatrix = new MMatrix( _m, _n );
    for( var k:int=0; k<values.length; k++ ){
      mtx.values[k] = values[k];
    }
    return mtx;
  }
  
  
  //--------------------------------------------------------------------------------------------VALUE
  
  public function getValue( i:uint, j:uint ):Number{
    return values[_n*i+j];
  }
  
  public function setValue( i:uint, j:uint, v:Number ):void{
    values[_n*i+j] = v;
  }
  
  //---------------------------------------------------------------------------------------------演算
  
  /**
   * 加算
   */
  public function add( mtx:MMatrix ):MMatrix{
    if( _m==mtx.m && _n==mtx.n ){
      var mt:MMatrix = new MMatrix( _m, _n );
      for( var k:int=0; k<values.length; k++ ){
        mt.values[k] = values[k] + mtx.values[k];
      }
      return mt;
    }else{
      return null;
    }
  }
  
  /**
   * 減算
   */
  public function sub( mtx:MMatrix ):MMatrix{
    if( _m==mtx.m && _n==mtx.n ){
      var mt:MMatrix = new MMatrix( _m, _n );
      for( var k:int=0; k<values.length; k++ ){
        mt.values[k] = values[k] - mtx.values[k];
      }
      return mt;
    }else{
      return null;
    }
  }
  
  /**
   * 積
   */
  public function product( mtx:MMatrix ):MMatrix{
    if( _n==mtx.m ){
      var m2:uint = _m;
      var n2:uint = mtx.n;
      var mt:MMatrix = new MMatrix( m2, n2 );
      for( var i:int=0; i<m2; i++ ){
        for( var j:int=0; j<n2; j++ ){
          var dd:Number = 0;
          for( var k:int=0; k<_n; k++ ){
            dd += values[i*_n + k] * mtx.values[k*mtx.n+j];
          }
          mt.values[i*n2+j] = dd;
        }
      }
      return mt;
    }else{
      return null;
    }
  }
  
  /**
   * スカラーたす
   */
  public function offset(t:Number):void{
    for( var k:int=0; k<values.length; k++ ){
      values[k] += t;
    }
  }
  
  /**
   * スカラーかける
   */
  public function time(t:Number):void{
    for( var k:int=0; k<values.length; k++ ){
      values[k] *= t;
    }
  }
  
  //---------------------------------------------------------------------------------------------
  
  /**
   * 転置
   */
  public function get transpose():MMatrix{
    var mtx:MMatrix = new MMatrix( _n, _m );
    for( var i:int=0; i<_m; i++ ){
      for( var j:int=0; j<_n; j++ ){
        mtx.setValue(j, i, values[i*_n+j] );
      }
    }
    return mtx;
  }
  
  /**
   * 逆行列
   */
  public function get inverse():MMatrix{
    if( isSquare ){
      var d:Number = det;
      if( d!=0 ){
        var mtx:MMatrix;
        if( _m>2 ){
          mtx = cofactorMatrix();
        }else{
          mtx = new MMatrix(_m,_n);
          mtx.values = [ values[3], -values[1], -values[2], values[0] ];
        }
        mtx.time( 1/d );
        return mtx;
      }
    }else{
      return null;
    }
  }
  
  /**
   * 行列式
   */
  public function get det():Number{
    if( isSquare ){
      if( _m==2 ){
        return values[0]*values[3] - values[1]*values[2];
      }else{
        var d:Number=0;
        for( var k=0; k<_n; k++ ){
          d += values[k]*cofactor(0,k);
        }
        return d;
      }
    }else{
      return Number.NaN;
    }
  }
  //----------------------------------------------------------------------------------------------余因子
  /**
   * 余因子
   */
  private function cofactor(i:uint,j:uint):Number{
    var mtx:MMatrix = clone();
    //行削除
    mtx.values.splice(i*_n,_m);
    mtx._m--;
    //列削除
    for( var k:int=(mtx.m-1); k>=0; k-- ){
      mtx.values.splice(k*_n+j,1);
    }
    mtx._n--;
    return mtx.det*Math.pow(-1,i+j+2);
  }
  /**
   * 余因子行列
   */
  private function cofactorMatrix():MMatrix{
    var mtx:MMatrix = new MMatrix(_m,_n);
    for( var i:int=0; i<_m; i++ ){
      for( var j:int=0; j<_n; j++ ){
        mtx.setValue( j, i, cofactor(i,j) );
      }
    }
    return mtx;
  }
  
  //---------------------------------------------------------------------------------------------GET
  /**
   * 行数
   */
  public function get m():int{
    return _m;
  }
  /**
   * 列数
   */
  public function get n():int{
    return _n;
  }
  /**
   * 正方行列か?
   */
  public function get isSquare():Boolean{
    return (_m==_n);
  }
  //---------------------------------------------------------------------------------------------TO_STRING
  public function toString():String{
    return "[MMatrix "+_m+"x"+_n+" VALUES:" + values + "]";
  }
}

行列計算は、回帰直線の回帰係数をとりあえず出してみるときに使ったりします。他にも使うことがあると思いますし、後は必要に応じて。

| INDEX |