feat(poly): refactoring PolytropeOperator to work on the reduced system so as to avoid rank deficiencies

This commit is contained in:
2025-06-05 12:37:00 -04:00
parent 4eb8b71271
commit a31c966146
7 changed files with 272 additions and 113 deletions

View File

@@ -1,5 +1,96 @@
//
// Created by Emily Boudreaux on 6/4/25.
//
#include "utilities.h"
#include "mfem.hpp"
namespace serif::utilities {
mfem::SparseMatrix buildReducedMatrix(
const mfem::SparseMatrix& matrix,
const mfem::Array<int>& trialEssentialDofs,
const mfem::Array<int>& testEssentialDofs
) {
int M_orig = matrix.Height();
int N_orig = matrix.Width();
// 1. Create boolean lookup tables for eliminated rows/columns
// These tables help quickly check if an original row/column index is eliminated.
mfem::Array<bool> row_is_eliminated(M_orig);
row_is_eliminated = false; // Initialize all to false (no rows eliminated yet)
for (int i = 0; i < testEssentialDofs.Size(); ++i) {
int r_idx = testEssentialDofs[i];
if (r_idx >= 0 && r_idx < M_orig) { // Check for valid index
row_is_eliminated[r_idx] = true;
}
}
mfem::Array<bool> col_is_eliminated(N_orig);
col_is_eliminated = false; // Initialize all to false (no columns eliminated yet)
for (int i = 0; i < trialEssentialDofs.Size(); ++i) {
int c_idx = trialEssentialDofs[i];
if (c_idx >= 0 && c_idx < N_orig) { // Check for valid index
col_is_eliminated[c_idx] = true;
}
}
// 2. Create mappings from old (original) indices to new indices
// Also, count the number of rows and columns in the new, reduced matrix.
mfem::Array<int> old_row_to_new_row(M_orig);
int num_new_rows = 0;
for (int i = 0; i < M_orig; ++i) {
if (row_is_eliminated[i]) {
old_row_to_new_row[i] = -1; // Mark as eliminated (no corresponding new row)
} else {
old_row_to_new_row[i] = num_new_rows++; // Assign the next available new row index
}
}
mfem::Array<int> old_col_to_new_col(N_orig);
int num_new_cols = 0;
for (int i = 0; i < N_orig; ++i) {
if (col_is_eliminated[i]) {
old_col_to_new_col[i] = -1; // Mark as eliminated (no corresponding new column)
} else {
old_col_to_new_col[i] = num_new_cols++; // Assign the next available new column index
}
}
// 3. Create the new sparse matrix with the calculated reduced dimensions.
// It's initially empty (no non-zero entries).
mfem::SparseMatrix A_new(num_new_rows, num_new_cols);
// 4. Iterate through the non-zero entries of the original matrix (A_orig).
// A_orig is typically stored in Compressed Sparse Row (CSR) format.
// GetI() returns row pointers, GetJ() returns column indices, GetData() returns values.
const int* I_orig = matrix.GetI();
const int* J_orig = matrix.GetJ();
const double* V_orig = matrix.GetData(); // Assuming double, can be templated if needed
for (int r_orig = 0; r_orig < M_orig; ++r_orig) {
// If the original row is marked for elimination, skip all its entries.
if (row_is_eliminated[r_orig]) {
continue;
}
// Get the new row index for the current original row.
int r_new = old_row_to_new_row[r_orig];
// Iterate through non-zero entries in the current original row r_orig.
// I_orig[r_orig] is the start index in J_orig and V_orig for row r_orig.
// I_orig[r_orig+1]-1 is the end index.
for (int k = I_orig[r_orig]; k < I_orig[r_orig + 1]; ++k) {
int c_orig = J_orig[k]; // Original column index of the non-zero entry
double val = V_orig[k]; // Value of the non-zero entry
if (col_is_eliminated[c_orig]) {
continue;
}
int c_new = old_col_to_new_col[c_orig];
A_new.Add(r_new, c_new, val);
}
}
A_new.Finalize();
return A_new;
}
}