Skip to content

Commit

Permalink
Merge pull request Pyomo#2896 from michaelbynum/empty_blocks
Browse files Browse the repository at this point in the history
Make min and max work with MPIBlockVector when some blocks have size 0
  • Loading branch information
jsiirola authored Aug 15, 2023
2 parents 3b3b7e7 + 0f9eefa commit 1cb37aa
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
28 changes: 20 additions & 8 deletions pyomo/contrib/pynumero/sparse/mpi_block_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,10 +567,16 @@ def min(self, axis=None, out=None, keepdims=False):
assert_block_structure(self)
local_min = np.inf
for i in self._owned_blocks:
lmin = self._block_vector.get_block(i).min()
if lmin <= local_min:
local_min = lmin
return self._mpiw.allreduce(local_min, op=mpi4py.MPI.MIN)
block = self._block_vector.get_block(i)
if block.size > 0:
lmin = block.min()
if lmin <= local_min:
local_min = lmin
res = self._mpiw.allreduce(local_min, op=mpi4py.MPI.MIN)
if res == np.inf:
if self.size == 0:
raise ValueError('cannot get the min of a size 0 array')
return res

def max(self, axis=None, out=None, keepdims=False):
"""
Expand All @@ -580,10 +586,16 @@ def max(self, axis=None, out=None, keepdims=False):
assert_block_structure(self)
local_max = -np.inf
for i in self._owned_blocks:
lmax = self._block_vector.get_block(i).max()
if lmax >= local_max:
local_max = lmax
return self._mpiw.allreduce(local_max, op=mpi4py.MPI.MAX)
block = self._block_vector.get_block(i)
if block.size > 0:
lmax = block.max()
if lmax >= local_max:
local_max = lmax
res = self._mpiw.allreduce(local_max, op=mpi4py.MPI.MAX)
if res == -np.inf:
if self.size == 0:
raise ValueError('cannot get the max of a size 0 array')
return res

def sum(self, axis=None, dtype=None, out=None, keepdims=False):
"""
Expand Down
29 changes: 29 additions & 0 deletions pyomo/contrib/pynumero/sparse/tests/test_mpi_block_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,35 @@ def test_min(self):
self.assertEqual(self.v1.min(), 0.0)
self.assertEqual(self.v2.min(), 0.0)

def test_min_max_with_size0_blocks(self):
v = MPIBlockVector(3, [0, 1, 2], comm)
rank = comm.Get_rank()
if rank == 0:
v.set_block(0, np.array([8, 4, 7, 12]))
if rank == 1:
v.set_block(1, np.array([]))
if rank == 2:
v.set_block(2, np.array([5, 6, 3]))
self.assertAlmostEqual(v.min(), 3)
self.assertAlmostEqual(v.max(), 12)

if rank == 0:
v.set_block(0, np.array([np.inf, np.inf, np.inf, np.inf]))
if rank == 2:
v.set_block(2, np.array([np.inf, np.inf, np.inf]))
self.assertEqual(v.min(), np.inf)
self.assertEqual(v.max(), np.inf)
v *= -1
self.assertEqual(v.min(), -np.inf)
self.assertEqual(v.max(), -np.inf)

v = MPIBlockVector(3, [0, 1, 2], comm)
v.set_block(rank, np.array([]))
with self.assertRaisesRegex(ValueError, 'cannot get the min of a size 0 array'):
v.min()
with self.assertRaisesRegex(ValueError, 'cannot get the max of a size 0 array'):
v.max()

def test_max(self):
v = MPIBlockVector(2, [0, 1], comm)
rank = comm.Get_rank()
Expand Down

0 comments on commit 1cb37aa

Please sign in to comment.