Skip to content

Commit 64211e1

Browse files
committed
Fix error when removing unused variables
1 parent 927c46c commit 64211e1

File tree

2 files changed

+25
-14
lines changed

2 files changed

+25
-14
lines changed

pyomo/repn/plugins/standard_form.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -472,24 +472,22 @@ def write(self, model):
472472
# at the index pointer list (an O(num_var) operation).
473473
c_ip = c.indptr
474474
A_ip = A.indptr
475-
active_var_idx = list(
476-
filter(
477-
lambda i: A_ip[i] != A_ip[i + 1] or c_ip[i] != c_ip[i + 1],
478-
range(len(columns)),
479-
)
480-
)
481-
nCol = len(active_var_idx)
475+
active_var_mask = (A_ip[1:] > A_ip[:-1]) | (c_ip[1:] > c_ip[:-1])
476+
477+
# Masks on NumPy arrays are very fast. Build the reduced A
478+
# indptr and then check if we actually have to manipulate the
479+
# columns
480+
augmented_mask = np.concatenate((active_var_mask, [True]))
481+
reduced_A_indptr = A.indptr[augmented_mask]
482+
nCol = len(reduced_A_indptr) - 1
482483
if nCol != len(columns):
483-
# Note that the indptr can't just use range() because a var
484-
# may only appear in the objectives or the constraints.
485-
columns = list(map(columns.__getitem__, active_var_idx))
486-
active_var_idx.append(c.indptr[-1])
484+
columns = [v for k, v in zip(active_var_mask, columns) if k]
487485
c = scipy.sparse.csc_array(
488-
(c.data, c.indices, c.indptr.take(active_var_idx)), [c.shape[0], nCol]
486+
(c.data, c.indices, c.indptr[augmented_mask]), [c.shape[0], nCol]
489487
)
490-
active_var_idx[-1] = A.indptr[-1]
488+
# active_var_idx[-1] = len(columns)
491489
A = scipy.sparse.csc_array(
492-
(A.data, A.indices, A.indptr.take(active_var_idx)), [A.shape[0], nCol]
490+
(A.data, A.indices, reduced_A_indptr), [A.shape[0], nCol]
493491
)
494492

495493
if self.config.nonnegative_vars:

pyomo/repn/tests/test_standard_form.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ def test_linear_model(self):
4343
self.assertTrue(np.all(repn.A == np.array([[-1, -2, 0], [0, 1, 4]])))
4444
self.assertTrue(np.all(repn.rhs == np.array([-3, 5])))
4545

46+
def test_almost_dense_linear_model(self):
47+
m = pyo.ConcreteModel()
48+
m.x = pyo.Var()
49+
m.y = pyo.Var([1, 2, 3])
50+
m.c = pyo.Constraint(expr=m.x + 2 * m.y[1] + 4 * m.y[3] >= 10)
51+
m.d = pyo.Constraint(expr=5 * m.x + 6 * m.y[1] + 8 * m.y[3] <= 20)
52+
53+
repn = LinearStandardFormCompiler().write(m)
54+
55+
self.assertTrue(np.all(repn.c == np.array([0, 0, 0])))
56+
self.assertTrue(np.all(repn.A == np.array([[-1, -2, -4], [5, 6, 8]])))
57+
self.assertTrue(np.all(repn.rhs == np.array([-10, 20])))
58+
4659
def test_linear_model_row_col_order(self):
4760
m = pyo.ConcreteModel()
4861
m.x = pyo.Var()

0 commit comments

Comments
 (0)