Skip to content
Advertisement

Convert a list of Vector to a matrix with petsc4py

I have a list of vectors that I want to gather in a single matrix Z. Here is the code I tried to use :

import sys, slepc4py
slepc4py.init(sys.argv)
from petsc4py import PETSc
from slepc4py import SLEPc

n = 5
d = 10

l = []   # creation of the list of vectors
for i in range(d):
    v = PETSc.Vec().create()
    v.setSizes(n)
    v.setFromOptions()
    v.set(i)
    l.append(v)

Z = PETSc.Mat().create()
Z.setSizes([n, d])
Z.setFromOptions()
Z.setUp()
for i, v in enumerate(l):
    # Z.setValuesBlocked(range(n), i, v)
    Z.setValues(range(n), i, v)
Z.assemble()
Z.view()    # to display the matrix in the terminal

I tried setValues and setValuesBlocked. When I run this script on one core, that works well. The result printed is :

row 0: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 1: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 2: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 3: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 4: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 

but in parallel I have issues :

Traceback (most recent call last):
  File "t.py", line 26, in <module>
    Z.setValues(range(n), i, v)
  File "PETSc/Mat.pyx", line 885, in petsc4py.PETSc.Mat.setValues
  File "PETSc/petscmat.pxi", line 826, in petsc4py.PETSc.matsetvalues
ValueError: incompatible array sizes: ni=5, nj=1, nv=3
Traceback (most recent call last):
  File "t.py", line 26, in <module>
    Z.setValues(range(n), i, v)
  File "PETSc/Mat.pyx", line 885, in petsc4py.PETSc.Mat.setValues
  File "PETSc/petscmat.pxi", line 826, in petsc4py.PETSc.matsetvalues
ValueError: incompatible array sizes: ni=5, nj=1, nv=2

I think it’s because PetSc waits for the local indices in the function setValues, but I don’t know how to access it (local_size gives the local size of the matrix, if I put Z.local_size[0] in setValues, the result in parallel is

Mat Object: 2 MPI processes
  type: mpiaij
row 0: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 1: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 2: (0, 0.)  (1, 1.)  (2, 2.)  (3, 3.)  (4, 4.)  (5, 5.)  (6, 6.)  (7, 7.)  (8, 8.)  (9, 9.) 
row 3:
row 4:

)

Which function or what argument should I use to fulfill this ?

EDIT :

I tried a more tedious way to fill the matrix Z, using the following double loop :

for i, v in enumerate(l):
    for j in range(n):
        Z.setValue(j, i, v[j])

once again in sequential, that works fine, but if I run it over 2 cores here is the result, totally wrong !

Mat Object: 2 MPI processes
  type: mpiaij
row 0: (0, 6.93107e-310)  (1, 6.93107e-310)  (2, 6.93107e-310)  (3, 0.)  (4, 6.93107e-310)  (5, 6.93107e-310)  (6, 6.93107e-310)  (7, 6.93107e-310)  (8, 6.93107e-310)  (9, 6.93107e-310) 
row 1: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, -1.)  (7, -1.)  (8, 0.)  (9, 0.) 
row 2: (0, 1.63042e-322)  (1, 1.63042e-322)  (2, 1.63042e-322)  (3, 1.63042e-322)  (4, 1.63042e-322)  (5, 1.63042e-322)  (6, 1.63042e-322)  (7, 1.63042e-322)  (8, 1.63042e-322)  (9, 1.63042e-322) 
row 3: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 4: (0, 0.)  (1, -1.)  (2, 0.)  (3, 0.)  (4, -1.)  (5, 4.24399e-314)  (6, 0.)  (7, -1.)  (8, -1.)  (9, 0.)

Advertisement

Answer

Thank to the help of the team developping PetSc, I managed to do it. Here is the code :

from petsc4py import PETSc

n = 10
d = 5

l = []   # creation of the list of vectors
for i in range(d):
    v = PETSc.Vec().create(comm=PETSc.COMM_WORLD)
    v.setSizes(n)
    v.setFromOptions()
    v.setUp()
    v.set(i)
    l.append(v)

Z = PETSc.Mat().createDense((n,d),comm=PETSc.COMM_WORLD)
Z.setFromOptions()
Z.setUp()
for i, v in enumerate(l):
    r = Z.getDenseColumnVec(i)
    v.copy(r)
    Z.restoreDenseColumnVec(i)
Z.assemble()
Z.view()

We need to use a dense matrix, and the function getDenseColumnVec allows to access to a column of the matrix, and modify it at will.

That works both in sequential and parallel.

Mat Object: 6 MPI processes
  type: mpidense
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
0.0000000000000000e+00 1.0000000000000000e+00 2.0000000000000000e+00 3.0000000000000000e+00 4.0000000000000000e+00 
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement