Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
Thanasis: I have finished the change that I mentioned in my previous email, the details are here https://gitlab.com/slepc/slepc/-/merge_requests/586 The change has been already merged into the main branch, and thus will be included in version 3.20, to be released on Friday this week. You should now be able to do bv = SLEPc.BV().createFromMat(A)) instead of bv = SLEPc.BV().createFromMat(A.convert('dense')) without error or cost penalty. Thanks. Jose > El 30 ago 2023, a las 9:17, Jose E. Roman escribió: > > The conversion from MATAIJ to MATDENSE should be very cheap, see > https://gitlab.com/petsc/petsc/-/blob/main/src/mat/impls/dense/seq/dense.c?ref_type=heads#L172 > > The matrix copy hidden inside createFromMat() is likely more expensive. I am > currently working on a modification of BV that will be included in version > 3.20 if everything goes well - then I think I can allow passing a sparse > matrix to createFromMat() and do the conversion internally, avoiding the > matrix copy. > > Jose > > >> El 29 ago 2023, a las 22:46, Thanasis Boutsikakis >> escribió: >> >> Thanks Jose, >> >> This works indeed. However, I was under the impression that this conversion >> might be very costly for big matrices with low sparsity and it would scale >> with the number of non-zero values. >> >> Do you have any idea of the efficiency of this operation? >> >> Thanks >> >>> On 29 Aug 2023, at 19:13, Jose E. Roman wrote: >>> >>> 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 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 =
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
The conversion from MATAIJ to MATDENSE should be very cheap, see https://gitlab.com/petsc/petsc/-/blob/main/src/mat/impls/dense/seq/dense.c?ref_type=heads#L172 The matrix copy hidden inside createFromMat() is likely more expensive. I am currently working on a modification of BV that will be included in version 3.20 if everything goes well - then I think I can allow passing a sparse matrix to createFromMat() and do the conversion internally, avoiding the matrix copy. Jose > El 29 ago 2023, a las 22:46, Thanasis Boutsikakis > escribió: > > Thanks Jose, > > This works indeed. However, I was under the impression that this conversion > might be very costly for big matrices with low sparsity and it would scale > with the number of non-zero values. > > Do you have any idea of the efficiency of this operation? > > Thanks > >> On 29 Aug 2023, at 19:13, Jose E. Roman wrote: >> >> 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 >>> 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
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
Thanks Jose, This works indeed. However, I was under the impression that this conversion might be very costly for big matrices with low sparsity and it would scale with the number of non-zero values. Do you have any idea of the efficiency of this operation? Thanks > On 29 Aug 2023, at 19:13, Jose E. Roman wrote: > > 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 >> 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) >> >> # >> #
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
Ah, there is https://petsc.org/release/manualpages/Mat/MATSOLVERSPQR/#matsolverspqr See also https://petsc.org/release/manualpages/Mat/MatGetFactor/#matgetfactor and https://petsc.org/release/manualpages/Mat/MatQRFactorSymbolic/ > On Aug 29, 2023, at 1:17 PM, Jed Brown wrote: > > Suitesparse includes a sparse QR algorithm. The main issue is that (even with > pivoting) the R factor has the same nonzero structure as a Cholesky factor of > A^T A, which is generally much denser than a factor of A, and this degraded > sparsity impacts Q as well. > > I wonder if someone would like to contribute a sparse QR to PETSc. It could > have a default implementation via Cholesky QR and the ability to call SPQR > from Suitesparse. > > Barry Smith writes: > >> Are the nonzero structures of all the rows related? If they are, one could >> devise a routine to take advantage of this relationship, but if the nonzero >> structures of each row are "randomly" different from all the other rows, >> then it is difficult to see how one can take advantage of the sparsity. >> >> >> >>> On Aug 29, 2023, at 12:50 PM, Thanasis Boutsikakis >>> wrote: >>> >>> 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 >>>
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
Suitesparse includes a sparse QR algorithm. The main issue is that (even with pivoting) the R factor has the same nonzero structure as a Cholesky factor of A^T A, which is generally much denser than a factor of A, and this degraded sparsity impacts Q as well. I wonder if someone would like to contribute a sparse QR to PETSc. It could have a default implementation via Cholesky QR and the ability to call SPQR from Suitesparse. Barry Smith writes: > Are the nonzero structures of all the rows related? If they are, one could > devise a routine to take advantage of this relationship, but if the nonzero > structures of each row are "randomly" different from all the other rows, then > it is difficult to see how one can take advantage of the sparsity. > > > >> On Aug 29, 2023, at 12:50 PM, Thanasis Boutsikakis >> wrote: >> >> 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 >>
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
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 > 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
Re: [petsc-users] Orthogonalization of a (sparse) PETSc matrix
Are the nonzero structures of all the rows related? If they are, one could devise a routine to take advantage of this relationship, but if the nonzero structures of each row are "randomly" different from all the other rows, then it is difficult to see how one can take advantage of the sparsity. > On Aug 29, 2023, at 12:50 PM, Thanasis Boutsikakis > wrote: > > 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),
[petsc-users] Orthogonalization of a (sparse) PETSc matrix
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, )