//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 加算と乗算の行列演算
CMatrix A(3),B(3),C();
//--- 配列の行を準備する
double a1[3]={1,2,3}, a2[3]={2,3,1}, a3[3]={3,1,2};
double b1[3]={3,2,1}, b2[3]={1,3,2}, b3[3]={2,1,3};
//--- 行列に書き込む
A[0]=a1; A[1]=a2; A[2]=a3;
B[0]=b1; B[1]=b2; B[2]=b3;
//--- エキスパート操作ログに行列を出力する
Print("---- Elements of matrix A");
Print(A.String());
Print("---- Elements of matrix B");
Print(B.String());
//--- 行列の加算
Print("---- Addition of matrices A and B");
C=A+B;
//--- フォーマットされた文字列表現を出力する
Print(C.String());
//--- 行列の乗算
Print("---- Multiplication of matrices A and B");
C=A*B;
Print(C.String());
//--- 次に動的配列 matrix[i][j] のスタイルで値を取得する方法を示す
Print("Output the values of matrix C elementwise");
//--- ループを使用して行列の行(CRow オブジェクト)を順番にみる
for(int i=0;i<3;i++)
{
string com="| ";
//--- 行列の行の値を形成する
for(int j=0;j<3;j++)
{
//--- 行と列の数を使用して行列要素を取得する
double element=C[i][j];// [i] - m_rows[] 配列で CRow にアクセスする
// [j] - CRowでのインデックス作成演算オーバーロード
com=com+StringFormat("a(%d,%d)=%G ; ",i,j,element);
}
com+="|";
//--- 行の値を出力する
Print(com);
}
}
//+------------------------------------------------------------------+
//| Row クラス |
//+------------------------------------------------------------------+
class CRow
{
private:
double m_array[];
public:
//--- コンストラクタとデストラクタ
CRow(void) { ArrayResize(m_array,0); }
CRow(const CRow &r) { this=r; }
CRow(const double &array[]);
~CRow(void){};
//--- 行の要素数
int Size(void) const { return(ArraySize(m_array));}
//--- 値を持つ文字列を返す
string String(void) const;
//--- インデックス作成演算子
double operator[](int i) const { return(m_array[i]); }
//--- 代入演算子
void operator=(const double &array[]); // 配列
void operator=(const CRow & r); // あと 1 つの CRow オブジェクト
double operator*(const CRow &o); //乗算に使用される CRow オブジェクト
};
//+------------------------------------------------------------------+
//| 行を配列と初期化するためのコンストラクタ |
//+------------------------------------------------------------------+
void CRow::CRow(const double &array[])
{
int size=ArraySize(array);
//--- 配列が空でない場合
if(size>0)
{
ArrayResize(m_array,size);
//--- 値を書き込む
for(int i=0;i<size;i++)
m_array[i]=array[i];
}
//---
}
//+------------------------------------------------------------------+
//| 配列の代入演算子 |
//+------------------------------------------------------------------+
void CRow::operator=(const double &array[])
{
int size=ArraySize(array);
if(size==0) return;
//--- 配列に値を書き込む
ArrayResize(m_array,size);
for(int i=0;i<size;i++) m_array[i]=array[i];
//---
}
//+------------------------------------------------------------------+
//| CRow の 代入演算子 |
//+------------------------------------------------------------------+
void CRow::operator=(const CRow &r)
{
int size=r.Size();
if(size==0) return;
//--- 配列に値を書き込む
ArrayResize(m_array,size);
for(int i=0;i<size;i++) m_array[i]=r[i];
//---
}
//+------------------------------------------------------------------+
//| 別の行の乗算演算子 |
//+------------------------------------------------------------------+
double CRow::operator*(const CRow &o)
{
double res=0;
//--- 検証
int size=Size();
if(size!=o.Size() || size==0)
{
Print(__FUNCSIG__,": Failed to multiply two matrices, their sizes are different");
return(res);
}
//--- 配列の要素ごとに乗算し、結果を加算する
for(int i=0;i<size;i++)
res+=m_array[i]*o[i];
//--- 結果
return(res);
}
//+------------------------------------------------------------------+
//| フォーマットされた文字列表現を返す |
//+------------------------------------------------------------------+
string CRow::String(void) const
{
string out="";
//--- 配列のサイズがゼロでない場合
int size=ArraySize(m_array);
//--- 要素の数がゼロ以外の配列を取り扱う
if(size>0)
{
out="{";
for(int i=0;i<size;i++)
{
//--- 値を文字列に収集する
out+=StringFormat(" %G;",m_array[i]);
}
out+=" }";
}
//--- 結果
return(out);
}
//+------------------------------------------------------------------+
//| Matrix クラス |
//+------------------------------------------------------------------+
class CMatrix
{
private:
CRow m_rows[];
public:
//--- コンストラクタとデストラクタ
CMatrix(void);
CMatrix(int rows) { ArrayResize(m_rows,rows); }
~CMatrix(void){};
//--- 行列のサイズを取得する
int Rows() const { return(ArraySize(m_rows)); }
int Cols() const { return(Rows()>0? m_rows[0].Size():0); }
//--- CRow の行の形で列の値を返す
CRow GetColumnAsRow(const int col_index) const;
//--- マトリックス値を持つ文字列を返す
string String(void) const;
//--- 索引付け演算子は文字列をその数で返す
CRow *operator[](int i) const { return(GetPointer(m_rows[i])); }
//--- 加算演算子
CMatrix operator+(const CMatrix &m);
//--- 乗算演算子
CMatrix operator*(const CMatrix &m);
//--- 代入演算子
CMatrix *operator=(const CMatrix &m);
};
//+------------------------------------------------------------------+
//| サイズがゼロの行の配列を作成するフォルトコンストラクタ |
//+------------------------------------------------------------------+
CMatrix::CMatrix(void)
{
//--- 行列の行がゼロ
ArrayResize(m_rows,0);
//---
}
//+------------------------------------------------------------------+
//| CRow の行の形で列の値を返す |
//+------------------------------------------------------------------+
CRow CMatrix::GetColumnAsRow(const int col_index) const
{
//--- 列から値を取得する変数
CRow row();
//--- 行列の行数
int rows=Rows();
//--- 行の数がゼロより大きい場合、演算を実行する
if(rows>0)
{
//--- インデックス col_index で列の値を受け取る配列
double array[];
ArrayResize(array,rows);
//---配列に書き込む
for(int i=0;i<rows;i++)
{
//--- 配列の境界を超えるかもしれないので 行 i の列の数を確認する
if(col_index>=this[i].Size())
{
Print(__FUNCSIG__,": Error! Column number ",col_index,"> row size ",i);
break; // 行は初期化されていないオブジェクトになる
}
array[i]=this[i][col_index];
}
//--- 配列の値に基づいて CRow の行を作成する
row=array;
}
//--- 結果
return(row);
}
//+------------------------------------------------------------------+
//| 2 つの行列の加算 |
//+------------------------------------------------------------------+
CMatrix CMatrix::operator+(const CMatrix &m)
{
//--- 渡された行列の行と列の数
int cols=m.Cols();
int rows=m.Rows();
//--- 加算結果を受け取る行列
CMatrix res(rows);
//--- 行列のサイズが一致していなければいけない
if(cols!=Cols() || rows!=Rows())
{
//--- 加算が不可能
Print(__FUNCSIG__,": Failed to add two matrices, their sizes are different");
return(res);
}
//--- 補助配列
double arr[];
ArrayResize(arr,cols);
//--- 行を 1 つづつ加算する
for(int i=0;i<rows;i++)
{
//--- 行列の文字列の加算結果を配列に書く
for(int k=0;k<cols;k++)
{
arr[k]=this[i][k]+m[i][k];
}
//--- 配列を行列の行に配置する
res[i]=arr;
}
//--- 行列の加算の結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| 2 つの行列の乗算 |
//+------------------------------------------------------------------+
CMatrix CMatrix::operator*(const CMatrix &m)
{
//--- 1 番目の行列の列数、行列に渡された行数
int cols1=Cols();
int rows2=m.Rows();
int rows1=Rows();
int cols2=m.Cols();
//--- 加算結果を受け取る行列
CMatrix res(rows1);
//--- 行列は調整を必要とする
if(cols1!=rows2)
{
//--- 乗算が不可能
Print(__FUNCSIG__,": Failed to multiply two matrices, format is not compatible "
"- number of columns in the first factor should be equal to the number of rows in the second");
return(res);
}
//--- 補助配列
double arr[];
ArrayResize(arr,cols1);
//--- 乗算行列の行に書き込む
for(int i=0;i<rows1;i++)// 行ごとに処理する
{
//--- 受け取り側の配列をリセットする
ArrayInitialize(arr,0);
//--- 行の要素を 1 つずつみる
for(int k=0;k<cols1;k++)
{
//--- CRow の形で行列 m の列 k の値をとる
CRow column=m.GetColumnAsRow(k);
//--- 2 つの行を乗算し、i 番目の要素内のベクトルのスカラー乗算の結果を書き込む
arr[k]=this[i]*column;
}
//--- 配列 arr[] を行列の i 番目の行に配置する
res[i]=arr;
}
//--- 行列の乗算の結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| 代入演算 |
//+------------------------------------------------------------------+
CMatrix *CMatrix::operator=(const CMatrix &m)
{
//--- 行数を検索して設定する
int rows=m.Rows();
ArrayResize(m_rows,rows);
//--- 渡された行列の行の値で行を埋める
for(int i=0;i<rows;i++) this[i]=m[i];
//---
return(GetPointer(this));
}
//+------------------------------------------------------------------+
//| 行列の文字列表現 |
//+------------------------------------------------------------------+
string CMatrix::String(void) const
{
string out="";
int rows=Rows();
//---文字列で文字列を作る
for(int i=0;i<rows;i++)
{
out=out+this[i].String()+"\r\n";
}
//--- 結果
return(out);
}
|