[petsc-users] Orthogonalization of a (sparse) PETSc matrix

Jose E. Roman jroman at dsic.upv.es
Tue Aug 29 12:13:05 CDT 2023


The result of bv.orthogonalize() is most probably a dense matrix, and the result replaces the input matrix, that's why the input matrix is required to be dense.

You can simply do this:

  bv = SLEPc.BV().createFromMat(A.convert('dense'))

Jose

> El 29 ago 2023, a las 18:50, Thanasis Boutsikakis <thanasis.boutsikakis at corintis.com> escribió:
> 
> Hi all, I have the following code that orthogonalizes a PETSc matrix. The problem is that this implementation requires that the PETSc matrix is dense, otherwise, it fails at bv.SetFromOptions(). Hence the assert in orthogonality().
> 
> What could I do in order to be able to orthogonalize sparse matrices as well? Could I convert it efficiently? (I tried to no avail)
> 
> Thanks!
> 
> """Experimenting with matrix orthogonalization"""
> 
> import contextlib
> import sys
> import time
> import numpy as np
> from firedrake import COMM_WORLD
> from firedrake.petsc import PETSc
> 
> import slepc4py
> 
> slepc4py.init(sys.argv)
> from slepc4py import SLEPc
> 
> from numpy.testing import assert_array_almost_equal
> 
> EPSILON_USER = 1e-4
> EPS = sys.float_info.epsilon
> 
> 
> def Print(message: str):
>     """Print function that prints only on rank 0 with color
> 
>     Args:
>         message (str): message to be printed
>     """
>     PETSc.Sys.Print(message)
> 
> 
> def create_petsc_matrix(input_array, sparse=True):
>     """Create a PETSc matrix from an input_array
> 
>     Args:
>         input_array (np array): Input array
>         partition_like (PETSc mat, optional): Petsc matrix. Defaults to None.
>         sparse (bool, optional): Toggle for sparese or dense. Defaults to True.
> 
>     Returns:
>         PETSc mat: PETSc matrix
>     """
>     # Check if input_array is 1D and reshape if necessary
>     assert len(input_array.shape) == 2, "Input array should be 2-dimensional"
>     global_rows, global_cols = input_array.shape
> 
>     size = ((None, global_rows), (global_cols, global_cols))
> 
>     # Create a sparse or dense matrix based on the 'sparse' argument
>     if sparse:
>         matrix = PETSc.Mat().createAIJ(size=size, comm=COMM_WORLD)
>     else:
>         matrix = PETSc.Mat().createDense(size=size, comm=COMM_WORLD)
>     matrix.setUp()
> 
>     local_rows_start, local_rows_end = matrix.getOwnershipRange()
> 
>     for counter, i in enumerate(range(local_rows_start, local_rows_end)):
>         # Calculate the correct row in the array for the current process
>         row_in_array = counter + local_rows_start
>         matrix.setValues(
>             i, range(global_cols), input_array[row_in_array, :], addv=False
>         )
> 
>     # Assembly the matrix to compute the final structure
>     matrix.assemblyBegin()
>     matrix.assemblyEnd()
> 
>     return matrix
> 
> 
> def orthogonality(A):  # sourcery skip: avoid-builtin-shadow
>     """Checking and correcting orthogonality
> 
>     Args:
>         A (PETSc.Mat): Matrix of size [m x k].
> 
>     Returns:
>         PETSc.Mat: Matrix of size [m x k].
>     """
>     # Check if the matrix is dense
>     mat_type = A.getType()
>     assert mat_type in (
>         "seqdense",
>         "mpidense",
>     ), "A must be a dense matrix. SLEPc.BV().createFromMat() requires a dense matrix."
> 
>     m, k = A.getSize()
> 
>     Phi1 = A.getColumnVector(0)
>     Phi2 = A.getColumnVector(k - 1)
> 
>     # Compute dot product using PETSc function
>     dot_product = Phi1.dot(Phi2)
> 
>     if abs(dot_product) > min(EPSILON_USER, EPS * m):
>         Print("    Matrix is not orthogonal")
> 
>         # Type can be CHOL, GS, mro(), SVQB, TSQR, TSQRCHOL
>         _type = SLEPc.BV().OrthogBlockType.GS
> 
>         bv = SLEPc.BV().createFromMat(A)
>         bv.setFromOptions()
>         bv.setOrthogonalization(_type)
>         bv.orthogonalize()
> 
>         A = bv.createMat()
> 
>         Print("    Matrix successfully orthogonalized")
> 
>         # # Assembly the matrix to compute the final structure
>         if not A.assembled:
>             A.assemblyBegin()
>             A.assemblyEnd()
>     else:
>         Print("    Matrix is orthogonal")
> 
>     return A
> 
> 
> # --------------------------------------------
> # EXP: Orthogonalization of an mpi PETSc matrix
> # --------------------------------------------
> 
> m, k = 11, 7
> # Generate the random numpy matrices
> np.random.seed(0)  # sets the seed to 0
> A_np = np.random.randint(low=0, high=6, size=(m, k))
> 
> A = create_petsc_matrix(A_np, sparse=False)
> 
> A_orthogonal = orthogonality(A)
> 
> # --------------------------------------------
> # TEST: Orthogonalization of a numpy matrix
> # --------------------------------------------
> # Generate A_np_orthogonal
> A_np_orthogonal, _ = np.linalg.qr(A_np)
> 
> # Get the local values from A_orthogonal
> local_rows_start, local_rows_end = A_orthogonal.getOwnershipRange()
> A_orthogonal_local = A_orthogonal.getValues(
>     range(local_rows_start, local_rows_end), range(k)
> )
> 
> # Assert the correctness of the multiplication for the local subset
> assert_array_almost_equal(
>     np.abs(A_orthogonal_local),
>     np.abs(A_np_orthogonal[local_rows_start:local_rows_end, :]),
>     decimal=5,
> )



More information about the petsc-users mailing list