Lab 14-2: COO Sparse Matrix 相加 (40%)

  • 輸入:以整數 (符合 long 型態) 的兩矩陣 \(M\) 及 \(N\)
    • 矩陣 \(M\) 及 \(N\) 的維度為正整數 \(M_n\)、\(M_m\)、\(N_n\)、\(N_m\)。
    • 矩陣的起始位置為 \(M[0][0]\)、\(N[0][0]\)。
    • 欲輸入的元素的個數為 \(M_{elements}\)、\(N_{elements}\)。
    • 元素紀錄的方式為 (i, j, v)
    • 紀錄格式參考以下的範例。
  • 輸出:顯示使用者輸入的兩 Sparse Matrix 及相加結果的 Sparse Matrix & 展開的 Matrix。
    • 矩陣 \(P\) 的維度 \(P_n\) 與 \(P_m\)。
    • 0 元素 (i, j, v)
      • 需以 (0, 0), (0, 1), ... (0, n-1), (1, 0), ... (n-1, m-1) 的順序顯示。
    • 展開 matrix 輸出格式參考以下的範例。
  • 檔名:lab14_2_<學號>.cpp (e.g. lab14_2_106062802.cpp)

Notice:

  • 程式需提示輸入 Sparse Matrix \(M\) 及 \(N\),程式需分析輸入後顯示使用者輸入的矩陣資訊。
  • 計算完 \(P\) 後,顯示矩陣 \(P\),及展開後的 \(P\)。
  • 程式需檢查輸入的資料是否為合法矩陣,若不相符則顯示錯誤訊息 Invalid matrix. 並結束程式。
    • 若矩陣維度為非正整數,則該矩陣為非法矩陣。
    • 欲輸入的元素的個數為負整數,則該矩陣為非法矩陣。
    • 如元素的索引值大於矩陣的維度則不算為合法元素。
    • 若元素的索引值重複,則以最後一筆紀錄為主。
    • 若元素的值為 0 則忽略不紀錄。
  • 程式需檢查矩陣 \(N\) 的維度是否與矩陣 \(M\) 相同,若不相同則在輸入完矩陣 \(N\) 時顯示錯誤訊息 Invalid matrix. 並結束程式。
  • 程式需使用 function 來處理輸入與輸出、比較、運算。
  • 程式需在 30 秒之內執行完畢,所有測資皆不會超過 30 秒的執行時間。

Format

Input COO matrix M:
<matrix rows>⏎
<matrix columns>⏎
<number of input elements>⏎
<element index> <element index> <element value>⏎
<element index> <element index> <element value>⏎
...⏎
The COO matrix M is:
<matrix rows>
<matrix columns>
<element index> <element index> <element value>
<element index> <element index> <element value>
...
Input COO matrix N:
<matrix rows>⏎
<matrix columns>⏎
<number of input elements>⏎
<element index> <element index> <element value>⏎
<element index> <element index> <element value>⏎
...⏎
The COO matrix N is:
<matrix rows>
<matrix columns>
<element index> <element index> <element value>
<element index> <element index> <element value>
...
The COO matrix P = M + N is:
<matrix rows>
<matrix columns>
<element index> <element index> <element value>
<element index> <element index> <element value>
...
The matrix P is:
<P0_0> <P0_1> ... <P0_n>
<P1_0> <P1_1> ... <P1_n>
...
<Pm_0> <Pm_1> ... <Pm_n>

Example

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
0 3 4⏎
The COO matrix M is:
3
4
0 0 1
0 3 4
1 1 2
2 2 3
Input COO matrix N:
3⏎
4⏎
4⏎
0 1 5⏎
1 2 6⏎
2 3 7⏎
2 2 4⏎
The COO matrix N is:
3
4
0 1 5
1 2 6
2 2 4
2 3 7
The COO matrix P = M + N is:
3
4
0 0 1
0 1 5
0 3 4
1 1 2
1 2 6
2 2 7
2 3 7
The matrix P is:
1 5 0 4
0 2 6 0
0 0 7 7

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 0⏎
2 2 3⏎
0 0 4⏎
The COO matrix M is:
3
4
0 0 4
2 2 3
Input COO matrix N:
3⏎
4⏎
4⏎
0 1 5⏎
1 2 6⏎
2 3 7⏎
1 1 4⏎
The COO matrix N is:
3
4
0 1 5
1 1 4
1 2 6
2 3 7
The COO matrix P = M + N is:
3
4
0 0 4
0 1 5
1 1 4
1 2 6
2 2 3
2 3 7
The matrix P is:
4 5 0 0
0 4 6 0
0 0 3 7

$ ./a.out⏎
Input COO matrix M:
0⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
0⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
-1⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
3 3 4⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
0 3 4⏎
The COO matrix M is:
3
4
0 0 1
0 3 4
1 1 2
2 2 3
Input COO matrix N:
0⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
0 3 4⏎
The COO matrix M is:
3
4
0 0 1
0 3 4
1 1 2
2 2 3
Input COO matrix N:
3⏎
0⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
0 3 4⏎
The COO matrix M is:
3
4
0 0 1
0 3 4
1 1 2
2 2 3
Input COO matrix N:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
3 3 4⏎
Invalid matrix.

$ ./a.out⏎
Input COO matrix M:
3⏎
4⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
0 3 4⏎
The COO matrix M is:
3
4
0 0 1
0 3 4
1 1 2
2 2 3
Input COO matrix N:
4⏎
5⏎
4⏎
0 0 1⏎
1 1 2⏎
2 2 3⏎
3 3 4⏎
The COO matrix N is:
4
5
0 0 1
1 1 2
2 2 3
3 3 4
Invalid matrix.

Pseudo Code

#include <iostream>
#include <vector>

typedef struct coo_sparse_matrix_struct
{
    unsigned long rows;
    unsigned long cols;
    std::vector<unsigned long> row_ind;
    std::vector<unsigned long> col_ind;
    std::vector<long> val;
} coo_sparse_matrix;

typedef struct matrix_struct
{
    unsigned long rows;
    unsigned long cols;
    std::vector<std::vector<long> > val;
} matrix;

void sort_col_ind(coo_sparse_matrix &coo_matrix)
{
    for (i = 0; i < coo_matrix.col_ind.size(); i++)
    {
        for (j = i + 1; j < coo_matrix.col_ind.size(); j++)
        {
            if (coo_matrix.col_ind[i] > coo_matrix.col_ind[j])
            {
                swap(coo_matrix.col_ind[i], coo_matrix.col_ind[j]);
                swap(coo_matrix.row_ind[i], coo_matrix.row_ind[j]);
                swap(coo_matrix.val[i], coo_matrix.val[j]);
            }
        }
    }
}
void sort_row_ind(coo_sparse_matrix &coo_matrix)
{
    for (i = 0; i < coo_matrix.row_ind.size(); i++)
    {
        for (j = i + 1; j < coo_matrix.row_ind.size(); j++)
        {
            if (coo_matrix.row_ind[i] > coo_matrix.row_ind[j] ||
                (coo_matrix.row_ind[i] == coo_matrix.row_ind[j] &&
                 coo_matrix.col_ind[i] > coo_matrix.col_ind[j]))
            {
                swap(coo_matrix.row_ind[i], coo_matrix.row_ind[j]);
                swap(coo_matrix.col_ind[i], coo_matrix.col_ind[j]);
                swap(coo_matrix.val[i], coo_matrix.val[j]);
            }
        }
    }
}
void sort_coo_matrix(coo_sparse_matrix &coo_matrix)
{
    sort_col_ind(coo_matrix);
    sort_row_ind(coo_matrix);
}
void insert_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val);
void add_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val);
void parse_coo_matrix(coo_sparse_matrix &coo_matrix);
void print_coo_matrix(const coo_sparse_matrix &coo_matrix);
coo_sparse_matrix add_coo_matrix(
    const coo_sparse_matrix &coo_matrix_M,
    const coo_sparse_matrix &coo_matrix_N);
matrix convert_coo_matrix_to_matrix(const coo_sparse_matrix &coo_matrix);
void print_matrix(const matrix &matrix);

int main()
{
    coo_sparse_matrix coo_matrix_M, coo_matrix_N, coo_matrix_P;
    std::cout << "Input COO matrix M:" << std::endl;
    parse_coo_matrix(coo_matrix_M);
    std::cout << "The COO matrix M is:" << std::endl;
    print_coo_matrix(coo_matrix_M);
    std::cout << "Input COO matrix N:" << std::endl;
    parse_coo_matrix(coo_matrix_N);
    std::cout << "The COO matrix N is:" << std::endl;
    print_coo_matrix(coo_matrix_N);
    coo_matrix_P = add_coo_matrix(coo_matrix_M, coo_matrix_N);
    std::cout << "The COO matrix P = M + N is:" << std::endl;
    print_coo_matrix(coo_matrix_P);
    matrix matrix_P = convert_coo_matrix_to_matrix(coo_matrix_P);
    std::cout << "The matrix P is:" << std::endl;
    print_matrix(matrix_P);
    return 0;
}

Reference: Sparse matrix - Wikipedia

TA version:

#include <iostream>
#include <vector>
using namespace std;
typedef struct coo_sparse_matrix_struct
{
    unsigned long rows;
    unsigned long cols;
    std::vector<unsigned long> row_ind;
    std::vector<unsigned long> col_ind;
    std::vector<long> val;
} coo_sparse_matrix;

typedef struct matrix_struct
{
    unsigned long rows;
    unsigned long cols;
    std::vector< std::vector<long> > val;
} matrix;

void sort_col_ind(coo_sparse_matrix &coo_matrix)
{
    for (int i = 0; i < coo_matrix.col_ind.size(); i++)
    {
        for (int j = i + 1; j < coo_matrix.col_ind.size(); j++)
        {
            if (coo_matrix.col_ind[i] > coo_matrix.col_ind[j])
            {
                swap(coo_matrix.col_ind[i], coo_matrix.col_ind[j]);
                swap(coo_matrix.row_ind[i], coo_matrix.row_ind[j]);
                swap(coo_matrix.val[i], coo_matrix.val[j]);
            }
        }
    }
}
void sort_row_ind(coo_sparse_matrix &coo_matrix)
{
    for (int i = 0; i < coo_matrix.row_ind.size(); i++)
    {
        for (int j = i + 1; j < coo_matrix.row_ind.size(); j++)
        {
            if (coo_matrix.row_ind[i] > coo_matrix.row_ind[j] ||
                (coo_matrix.row_ind[i] == coo_matrix.row_ind[j] &&
                 coo_matrix.col_ind[i] > coo_matrix.col_ind[j]))
            {
                swap(coo_matrix.row_ind[i], coo_matrix.row_ind[j]);
                swap(coo_matrix.col_ind[i], coo_matrix.col_ind[j]);
                swap(coo_matrix.val[i], coo_matrix.val[j]);
            }
        }
    }
}
void sort_coo_matrix(coo_sparse_matrix &coo_matrix)
{
    sort_col_ind(coo_matrix);
    sort_row_ind(coo_matrix);
}
void insert_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val);
void add_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val);
void parse_coo_matrix(coo_sparse_matrix &coo_matrix);
void print_coo_matrix(const coo_sparse_matrix &coo_matrix);
coo_sparse_matrix add_coo_matrix(
    const coo_sparse_matrix &coo_matrix_M,
    const coo_sparse_matrix &coo_matrix_N);
matrix convert_coo_matrix_to_matrix(const coo_sparse_matrix &coo_matrix);
void print_matrix(const matrix &matrix);

int main()
{
    coo_sparse_matrix coo_matrix_M, coo_matrix_N, coo_matrix_P;
    std::cout << "Input COO matrix M:" << std::endl;
    parse_coo_matrix(coo_matrix_M);
    std::cout << "The COO matrix M is:" << std::endl;
    print_coo_matrix(coo_matrix_M);
    std::cout << "Input COO matrix N:" << std::endl;
    parse_coo_matrix(coo_matrix_N);
    std::cout << "The COO matrix N is:" << std::endl;
    print_coo_matrix(coo_matrix_N);
    coo_matrix_P = add_coo_matrix(coo_matrix_M, coo_matrix_N);
    std::cout << "The COO matrix P = M + N is:" << std::endl;
    print_coo_matrix(coo_matrix_P);
    matrix matrix_P = convert_coo_matrix_to_matrix(coo_matrix_P);
    std::cout << "The matrix P is:" << std::endl;
    print_matrix(matrix_P);
    return 0;
}

void parse_coo_matrix(coo_sparse_matrix &coo_matrix)
{
    int n; // n lines of inputs

    // Exceptions: rows and col can't be nonpositive, n can't be negative
    for (int i = 0; i < 3; i++)
    {
        int temp;
        cin >> temp;
        if (i == 0 && temp > 0)
        {
            coo_matrix.rows = temp;
            continue;
        }
        if (i == 1 && temp > 0)
        {
            coo_matrix.cols = temp;
            continue;
        }
        if (i == 2 && temp >= 0)
        {
            n = temp;
            continue;
        }
        cout << "Invalid matrix." << endl;
        exit(0);
    }

    // Start of Parsing
    while (n--)
    {
        unsigned long r, c;
        long v;
        cin >> r >> c >> v;

        // Exceptions: Index Out of Range
        if (r < 0 ||
            r >= coo_matrix.rows ||
            c < 0 ||
            c >= coo_matrix.cols)
        {
            cout << "Invalid matrix." << endl;
            exit(0);
        }

        // Store COO
        bool flag = false;
        for (int i = 0; i < coo_matrix.row_ind.size(); i++)
        {
            // Rewrite val if already exist
            if (r == coo_matrix.row_ind[i] && c == coo_matrix.col_ind[i])
            {
                if (v == 0) // Erase if val = 0
                {
                    coo_matrix.row_ind.erase(coo_matrix.row_ind.begin() + i);
                    coo_matrix.col_ind.erase(coo_matrix.col_ind.begin() + i);
                    coo_matrix.val.erase(coo_matrix.val.begin() + i);
                }
                else // Rewrite if val != 0
                    coo_matrix.val[i] = v;

                flag = true;
                break;
            }
        }

        // Push_back if not exists yet and v is nonzero
        if (!flag && v != 0)
        {
            coo_matrix.row_ind.push_back(r);
            coo_matrix.col_ind.push_back(c);
            coo_matrix.val.push_back(v);
        }
    }
    // End of Parsing

    // Sorting
    sort_coo_matrix(coo_matrix);
}

matrix convert_coo_matrix_to_matrix(const coo_sparse_matrix &coo_matrix)
{
    matrix mtrx;
    mtrx.rows = coo_matrix.rows;
    mtrx.cols = coo_matrix.cols;

    for (unsigned long i = 0; i < mtrx.rows; i++)
        mtrx.val.push_back(vector<long>(mtrx.cols, 0));

    for (int i = 0; i < coo_matrix.row_ind.size(); i++)
    {
        unsigned long r = coo_matrix.row_ind[i], c = coo_matrix.col_ind[i];
        long v = coo_matrix.val[i];
        mtrx.val[r][c] = v;
    }

    return mtrx;
}

void print_matrix(const matrix &matrix)
{
    for (unsigned long i = 0; i < matrix.rows; i++)
    {
        for (unsigned long j = 0; j < matrix.cols; j++)
        {
            cout << matrix.val[i][j] << ' ';
        }
        cout << endl;
    }
}

void print_coo_matrix(const coo_sparse_matrix &coo_matrix)
{
    cout << coo_matrix.rows << '\n'
         << coo_matrix.cols << endl;
    for (unsigned long i = 0; i < coo_matrix.row_ind.size(); i++)
    {
        cout << coo_matrix.row_ind[i]
             << " "
             << coo_matrix.col_ind[i]
             << " "
             << coo_matrix.val[i]
             << endl;
    }
}

void insert_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val)
{
    coo_matrix.row_ind.push_back(row);
    coo_matrix.col_ind.push_back(col);
    coo_matrix.val.push_back(val);
}

void add_coo_matrix_element(
    coo_sparse_matrix &coo_matrix,
    unsigned long row,
    unsigned long col,
    long val);

coo_sparse_matrix add_coo_matrix(
    const coo_sparse_matrix &coo_matrix_M,
    const coo_sparse_matrix &coo_matrix_N)
{
    // Exception: Matrices are not addable
    if (coo_matrix_M.rows != coo_matrix_N.rows ||
        coo_matrix_M.cols != coo_matrix_N.cols)
    {
        cout << "Invalid matrix." << endl;
        exit(0);
    }

    coo_sparse_matrix P;
    P.rows = coo_matrix_M.rows;
    P.cols = coo_matrix_M.cols;

    int m = 0, n = 0;
    while (m < coo_matrix_M.row_ind.size() &&
           n < coo_matrix_N.row_ind.size())
    {
        if (coo_matrix_M.row_ind[m] > coo_matrix_N.row_ind[n] ||
            (coo_matrix_M.row_ind[m] == coo_matrix_N.row_ind[n] &&
             coo_matrix_M.col_ind[m] > coo_matrix_N.col_ind[n]))
        {
            insert_coo_matrix_element(
                P,
                coo_matrix_N.row_ind[n],
                coo_matrix_N.col_ind[n],
                coo_matrix_N.val[n]);
            n++;
        }

        else if (coo_matrix_M.row_ind[m] < coo_matrix_N.row_ind[n] ||
                 (coo_matrix_M.row_ind[m] == coo_matrix_N.row_ind[n] &&
                  coo_matrix_M.col_ind[m] < coo_matrix_N.col_ind[n]))
        {
            insert_coo_matrix_element(
                P,
                coo_matrix_M.row_ind[m],
                coo_matrix_M.col_ind[m],
                coo_matrix_M.val[m]);
            m++;
        }
        else
        {
            int sum = coo_matrix_M.val[m] + coo_matrix_N.val[n];

            if (sum != 0)
                insert_coo_matrix_element(
                    P,
                    coo_matrix_N.row_ind[n],
                    coo_matrix_N.col_ind[n],
                    sum);
            m++;
            n++;
        }
    }

    // Insert the Remaining COO
    while (m < coo_matrix_M.row_ind.size())
    {
        insert_coo_matrix_element(
            P,
            coo_matrix_M.row_ind[m],
            coo_matrix_M.col_ind[m],
            coo_matrix_M.val[m]);
        m++;
    }

    while (n < coo_matrix_N.row_ind.size())
    {
        insert_coo_matrix_element(
            P,
            coo_matrix_N.row_ind[n],
            coo_matrix_N.col_ind[n],
            coo_matrix_N.val[n]);
        n++;
    }

    sort_coo_matrix(P);
    return P;
}