0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-05-24

プログラムについて

乱数で生成した正方行列をCSV形式で出力するプログラムです.
以下の行列が生成できます.

  • 非対称行列
  • 対称行列

環境

  • Ubuntu 20.04.5 LTS

プログラム

クラスファイル

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();
    }
};

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

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

プログラム

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,
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0