C++による乱数正方行列の生成と読み込み


# プログラムについて
乱数で生成した正方行列をCSV形式で出力するプログラムです．
以下の行列が生成できます．
- 非対称行列
- 対称行列

# 環境
- Ubuntu 20.04.5 LTS

# プログラム
クラスファイル

```C++:make_matrix.hpp
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <vector>

enum MatrixType
{
    Symmetric,
    Asymmetric
};

class MakeSquareMatrix
{
private:
    int N;
    std::vector<std::vector<double>> matrix;
    std::vector<int> NonZeroList;

public:
    MakeSquareMatrix(int size, enum MatrixType type, double density)
    {
        N = size;
        matrix.resize(N, std::vector<double>(N));
        NonZeroList.resize(N);
        for (int i = 0; i < N; i++)
        {
            switch (type)
            {
            // 対称正方行列の生成
            case Symmetric:
                for (int j = i; j < N; j++)
                {
                    double random_number = ((double)rand() / (RAND_MAX));
                    double probability = ((double)rand() / (RAND_MAX));
                    if (probability < density)
                    {
                        if (j != i)
                        {
                            matrix[i][j] = random_number;
                            matrix[j][i] = random_number;
                            NonZeroList[i]++;
                            NonZeroList[j]++;
                        }
                        else
                        {
                            matrix[i][i] = random_number;
                            NonZeroList[i]++;
                        }
                    }
                    else
                    {
                        matrix[i][j] = 0;
                        matrix[j][i] = 0;
                    }
                }
                break;
            // 非対称正方行列の生成
            case Asymmetric:
                for (int j = 0; j < N; j++)
                {
                    double random_number = ((double)rand() / (RAND_MAX));
                    double probability = ((double)rand() / (RAND_MAX));
                    if (probability < density)
                    {
                        matrix[i][j] = random_number;
                        NonZeroList[i]++;
                    }
                    else
                    {
                        matrix[i][j] = 0;
                    }
                }
                break;
            default:
                break;
            }
        }
    }

    void outputToCSV(std::string filename)
    {
        int NonZero = 0;
        int MaxNonZero = 0;
        std::ofstream ofs(filename);
        // 非ゼロ要素数を数える
        for (int i = 0; i < N; i++)
        {
            NonZero += NonZeroList[i];
            int tmp = NonZeroList[i];
            // 各行における最大非ゼロ要素数を見つける
            if (tmp > MaxNonZero)
            {
                MaxNonZero = tmp;
            }
        }

        ofs << N << "," << NonZero << "," << MaxNonZero << "\n";
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (j < N - 1)
                {
                    ofs << matrix[i][j] << ",";
                }
                else
                {
                    ofs << matrix[i][j] << "\n";
                }
            }
        }
        ofs.close();
    }
};

```

```C++:make_matrix.cpp
#include "make_matrix.hpp"

int main()
{
    srand(time(0));

    int N;
    std::cout << "Enter the size of the matrix: ";
    std::cin >> N;

    std::string filename;
    std::cout << "Enter the filename: ";
    std::cin >> filename;
    filename = filename + ".csv";

    enum MatrixType type;
    int type_num;
    std::cout << "Enter the type of the matrix, 0 or 1:\n";
    std::cout << "0:Symmetric,  1:Asymmetric ";
    std::cin >> type_num;
    if (type_num == 0)
    {
        type = Symmetric;
    }
    else if (type_num == 1)
    {
        type = Asymmetric;
    }

    // sparse .. dense
    // 0 .. 1
    double density;
    std::cout << "Enter the density of the matrix(0 .. 1): ";
    std::cin >> density;

    MakeSquareMatrix matrix(N, type, density);
    matrix.outputToCSV(filename);

    return 0;
}
```
# 実行方法

実行すると，以下の入力が求められますので，生成したい行列に応じて入力して下さい．

- 1行目: 行列の大きさを指定

- 2行目: ファイル名を指定

- 3行目: 対称行列か非対称行列かを0か1で指定

- 4行目: 非ゼロ要素数の割合を指定(0:疎 ~ 1:密)
```
./a.out

Enter the size of the matrix: 5
Enter the filename: matrix
Enter the type of the matrix, 0 or 1:
0:Symmetric,  1:Asymmetric 0
Enter the density of the matrix(0 .. 1): 0.8
```

# 実行結果

```:生成されたファイル
5,17,5
0.634102,0.896232,0.601307,0.564086,0.159429
0.896232,0,0.45777,0,0.358383
0.601307,0.45777,0.910682,0,0.0695973
0.564086,0,0,0,0
0.159429,0.358383,0.0695973,0,0.487071
```

# 生成したファイルの読み込み

プログラム
```C++:read_matrix.cpp
#include <iostream>
#include <fstream>
#include <sstream>

int main(int argc, char *argv[])
{
    // コマンドラインからファイル名を取得
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " <filename>" << std::endl;
        return 1;
    }
    const std::string filename = argv[1];

    // CSVファイルを開く
    std::ifstream csv_file(filename);
    if (!csv_file.is_open())
    {
        std::cerr << "Failed to open file " << filename << std::endl;
        return 1;
    }

    // 行列の大きさ -> N
    // 非ゼロ要素数 -> NonZero
    // 各行における最大非ゼロ要素数 -> MaxNonZero
    int N, NonZero, MaxNonZero;
    std::string line;
    std::getline(csv_file, line);
    std::stringstream ss(line);
    for (int j = 0; j < 3; ++j)
    {
        std::string cell;
        std::getline(ss, cell, ',');
        if (j == 0)
        {
            N = std::stoi(cell);
        }
        else if (j == 1)
        {
            NonZero = std::stoi(cell);
        }
        else if (j == 2)
        {
            MaxNonZero = std::stoi(cell);
        }
    }

    std::cout << N << "," << NonZero << "," << MaxNonZero << std::endl;

    double matrix[N][N];

    // 正方行列のデータを読み込む
    for (int i = 0; i < N; ++i)
    {
        std::string line;
        std::getline(csv_file, line);
        std::stringstream ss(line);
        for (int j = 0; j < N; ++j)
        {
            std::string cell;
            std::getline(ss, cell, ',');
            matrix[i][j] = std::stod(cell);
        }
    }

    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            std::cout << matrix[i][j] << ",";
        }
        std::cout << "\n";
    }

    return 0;
}
```

# 実行方法

読み込んだ行列を出力するだけのプログラムになっています．必要に応じて修正して下さい．

```
./main matrix.csv
5,17,5
0.634102,0.896232,0.601307,0.564086,0.159429,
0.896232,0,0.45777,0,0.358383,
0.601307,0.45777,0.910682,0,0.0695973,
0.564086,0,0,0,0,
0.159429,0.358383,0.0695973,0,0.487071,
```