Skip to content

Commit

Permalink
Merge pull request #2676 from jsiirola/activate-nlv2
Browse files Browse the repository at this point in the history
Switch default NL writer to nlv2
  • Loading branch information
mrmundt authored Jan 27, 2023
2 parents 200e777 + 50d518a commit 7edd5f0
Show file tree
Hide file tree
Showing 23 changed files with 406 additions and 67 deletions.
5 changes: 2 additions & 3 deletions doc/OnlineDocs/modeling_extensions/gdp/modeling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,10 @@ Usage:
>>> m.Y = BooleanVar(m.my_set)
>>> m.p = LogicalConstraint(expr=atleast(3, m.Y))
>>> m.p.pprint()
p : Size=1, Index=None, Active=False
p : Size=1, Index=None, Active=True
Key : Body : Active
None : atleast(3: [Y[1], Y[2], Y[3], Y[4]]) : False
None : atleast(3: [Y[1], Y[2], Y[3], Y[4]]) : True
>>> TransformationFactory('core.logical_to_linear').apply_to(m)
...
>>> # constraint auto-generated by transformation
>>> m.logic_to_linear.transformed_constraints.pprint()
transformed_constraints : Size=1, Index=logic_to_linear.transformed_constraints_index, Active=True
Expand Down
13 changes: 5 additions & 8 deletions doc/OnlineDocs/pyomo_modeling_components/Suffixes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ Suffix component with an IMPORT_EXPORT direction.

ipopt = pyo.SolverFactory('ipopt')


The difference in performance can be seen by examining Ipopt's iteration
log with and without warm starting:

Expand All @@ -405,13 +406,9 @@ log with and without warm starting:
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 1.6109693e+01 1.12e+01 5.28e-01 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 1.6982239e+01 7.30e-01 1.02e+01 -1.0 6.11e-01 - 7.19e-02 1.00e+00f 1
2 1.7318411e+01 3.60e-02 5.05e-01 -1.0 1.61e-01 - 1.00e+00 1.00e+00h 1
3 1.6849424e+01 2.78e-01 6.68e-02 -1.7 2.85e-01 - 7.94e-01 1.00e+00h 1
4 1.7051199e+01 4.71e-03 2.78e-03 -1.7 6.06e-02 - 1.00e+00 1.00e+00h 1
5 1.7011979e+01 7.19e-03 8.50e-03 -3.8 3.66e-02 - 9.45e-01 9.98e-01h 1
6 1.7014271e+01 1.74e-05 9.78e-06 -3.8 3.33e-03 - 1.00e+00 1.00e+00h 1
7 1.7014021e+01 1.23e-07 1.82e-07 -5.7 2.69e-04 - 1.00e+00 1.00e+00h 1
8 1.7014017e+01 1.77e-11 2.52e-11 -8.6 3.32e-06 - 1.00e+00 1.00e+00h 1
2 1.7318411e+01 ...
...
8 1.7014017e+01 ...

Number of Iterations....: 8
...
Expand Down Expand Up @@ -441,7 +438,7 @@ log with and without warm starting:
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 1.7014032e+01 2.00e-06 4.07e-06 -6.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 1.7014019e+01 3.65e-12 1.00e-11 -6.0 2.50e-01 - 1.00e+00 1.00e+00h 1
2 1.7014017e+01 4.48e-12 6.42e-12 -9.0 1.92e-06 - 1.00e+00 1.00e+00h 1
2 1.7014017e+01 ...

Number of Iterations....: 2
...
Expand Down
2 changes: 1 addition & 1 deletion examples/pyomobook/abstract-ch/pyomo.abstract7.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ model:
save file: None
save format: None
symbolic solver labels: false
file determinism: 1
file determinism: None
transform: []
preprocess: []
runtime:
Expand Down
2 changes: 1 addition & 1 deletion examples/pyomobook/abstract-ch/pyomo.model3.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# @cmd:
pyomo convert --output=concrete1.nl concrete1.py
# @:cmd
diff concrete1.nl concrete1-ref.nl
python -m pyomo.repn.tests.ampl.nl_diff concrete1.nl concrete1-ref.nl
rm -f results.yml results.json concrete1.nl
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def test_pyomo_external_model_scaling(self):
inputs=[m.Pin, m.c1, m.c2, m.F],
outputs=[m.P1, m.P2],
outputs_eqn_scaling=[10.0, 11.0],
nl_file_options={'file_determinism': 3},
nl_file_options={'file_determinism': 2},
)

# solve the problem
Expand Down Expand Up @@ -220,7 +220,7 @@ def test_pyomo_external_model_ndarray_scaling(self):
inputs=[m.Pin, m.c1, m.c2, m.F],
outputs=[m.P1, m.P2],
outputs_eqn_scaling=np.asarray([10.0, 11.0], dtype=np.float64),
nl_file_options={'file_determinism': 3},
nl_file_options={'file_determinism': 2},
)

# solve the problem
Expand Down
37 changes: 30 additions & 7 deletions pyomo/contrib/sensitivity_toolbox/tests/test_sens_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,9 +698,16 @@ def test_get_dsdp1(self):
getattr(m, v).setlb(theta[v])
getattr(m, v).setub(theta[v])
dsdp, col = get_dsdp(m, variable_name, theta)
np.testing.assert_almost_equal(dsdp.toarray(),[[1., 0., 1., 0.],[0., 1., 0., 1.]])

assert col == ['x1', 'x2', 'p1', 'p2']
ref = {
'x1': [1., 0.],
'x2': [0., 1.],
'p1': [1., 0.],
'p2': [0., 1.],
}
np.testing.assert_almost_equal(
dsdp.toarray(),
np.vstack(ref[c] for c in col).transpose()
)

@unittest.skipIf(not opt_kaug.available(False), "k_aug is not available")
@unittest.skipIf(not opt_ipopt.available(False), "ipopt is not available")
Expand Down Expand Up @@ -757,10 +764,26 @@ def test_get_dfds_dcds(self):
getattr(m, v).setlb(theta[v])
getattr(m, v).setub(theta[v])
gradient_f, gradient_c, col ,row, line_dic= get_dfds_dcds(m, variable_name)
np.testing.assert_almost_equal( gradient_f, [10., 50., 15., 35.])
np.testing.assert_almost_equal( gradient_c.toarray(), [[ 1., 0., -1., 0.], [ 0., 1., 0., -1.]])
assert col == ['x1', 'x2', 'p1', 'p2']
assert row == ['c1', 'c2', 'obj']

ref_f = {
'x1': [10.],
'x2': [50.],
'p1': [15.],
'p2': [35.],
}
ref_c = {
'x1': [1., 0.],
'x2': [0., 1.],
'p1': [-1., 0.],
'p2': [0., -1.],
}
np.testing.assert_almost_equal(
gradient_f, np.hstack(ref_f[v] for v in col)
)
np.testing.assert_almost_equal(
gradient_c.toarray(),
np.vstack(ref_c[v] for v in col).transpose()
)

@unittest.skipIf(not opt_kaug.available(False), "k_aug is not available")
@unittest.skipIf(not opt_dotsens.available(False), "dot_sens is not available")
Expand Down
13 changes: 7 additions & 6 deletions pyomo/mpec/complementarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ def to_standard_form(self):
# the form:
# l1 <= v1 <= u1 OR l2 <= v2 <= u2
#
# Note that this transformation creates more variables and constraints
# than are strictly necessary. However, we don't have a complete list of
# the variables used in a model's complementarity conditions when adding
# a single condition, so we add additional variables.
# Note that this transformation creates more variables and
# constraints than are strictly necessary. However, we don't
# have a complete list of the variables used in a model's
# complementarity conditions when adding a single condition, so
# we add additional variables.
#
# This has the form:
#
Expand Down Expand Up @@ -144,14 +145,14 @@ def set_value(self, cc):
# The ComplementarityTuple has a fixed length, so we initialize
# the _args component and return
#
self._args = ( as_numeric(cc.arg0), as_numeric(cc.arg1) )
self._args = ( cc.arg0, cc.arg1 )
#
elif cc.__class__ is tuple:
if len(cc) != 2:
raise ValueError(
"Invalid tuple for Complementarity %s (expected 2-tuple):"
"\n\t%s" % (self.name, cc) )
self._args = tuple( as_numeric(x) for x in cc )
self._args = cc
elif cc is Complementarity.Skip:
del self.parent_component()[self.index()]
elif cc.__class__ is list:
Expand Down
2 changes: 1 addition & 1 deletion pyomo/mpec/tests/t11_nlxfrm.nl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
g3 1 1 0 # problem unknown
3 1 0 0 1 # vars, constraints, objectives, ranges, eqns
3 1 0 0 1 # vars, constraints, objectives, ranges, eqns; KNOWN BUG WITH NLv1 WRTIER!!!
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
Expand Down
31 changes: 31 additions & 0 deletions pyomo/mpec/tests/t11_nlxfrm.nl_v2
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
g3 1 1 0 # problem unknown
3 2 0 0 1 # vars, constraints, objectives, ranges, eqns
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
0 0 0 1 # linear network variables; functions; arith, flags
0 0 0 0 0 # discrete variables: binary, integer, nonlinear (b,c,o)
4 0 # nonzeros in Jacobian, obj. gradient
0 0 # max name lengths: constraints, variables
0 0 0 0 0 # common exprs: b,c,o,c1,o1
C0
n0
C1
n0
x0
r
5 0 2
4 2.0
b
3
3
3
k2
1
2
J0 1
2 1
J1 3
0 1
1 1
2 1
2 changes: 1 addition & 1 deletion pyomo/mpec/tests/t12_nlxfrm.nl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
g3 1 1 0 # problem unknown
3 1 0 0 1 # vars, constraints, objectives, ranges, eqns
3 1 0 0 1 # vars, constraints, objectives, ranges, eqns; KNOWN BUG WITH NLv1 WRTIER!!!
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
Expand Down
31 changes: 31 additions & 0 deletions pyomo/mpec/tests/t12_nlxfrm.nl_v2
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
g3 1 1 0 # problem unknown
3 2 0 0 1 # vars, constraints, objectives, ranges, eqns
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
0 0 0 1 # linear network variables; functions; arith, flags
0 0 0 0 0 # discrete variables: binary, integer, nonlinear (b,c,o)
4 0 # nonzeros in Jacobian, obj. gradient
0 0 # max name lengths: constraints, variables
0 0 0 0 0 # common exprs: b,c,o,c1,o1
C0
n0
C1
n0
x0
r
5 0 2
4 2.0
b
3
3
3
k2
1
2
J0 1
2 1
J1 3
0 1
1 1
2 1
42 changes: 42 additions & 0 deletions pyomo/mpec/tests/t2a_nlxfrm.nl_v2
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
g3 1 1 0 # problem unknown
5 3 0 0 2 # vars, constraints, objectives, ranges, eqns
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
0 0 0 1 # linear network variables; functions; arith, flags
0 0 0 0 0 # discrete variables: binary, integer, nonlinear (b,c,o)
7 0 # nonzeros in Jacobian, obj. gradient
0 0 # max name lengths: constraints, variables
0 0 0 0 0 # common exprs: b,c,o,c1,o1
C0
n0
C1
n0
C2
n0
x0
r
5 2 5
4 0.0
4 0.0
b
3
3
3
3
1 -1
k4
1
3
4
6
J0 1
3 1
J1 3
0 1
1 1
3 1
J2 3
1 -1
2 1
4 1
42 changes: 42 additions & 0 deletions pyomo/mpec/tests/t2b_nlxfrm.nl_v2
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
g3 1 1 0 # problem unknown
5 3 0 0 2 # vars, constraints, objectives, ranges, eqns
0 0 1 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
0 0 # network constraints: nonlinear, linear
0 0 0 # nonlinear vars in constraints, objectives, both
0 0 0 1 # linear network variables; functions; arith, flags
0 0 0 0 0 # discrete variables: binary, integer, nonlinear (b,c,o)
7 0 # nonzeros in Jacobian, obj. gradient
0 0 # max name lengths: constraints, variables
0 0 0 0 0 # common exprs: b,c,o,c1,o1
C0
n0
C1
n0
C2
n0
x0
r
5 1 5
4 -1.0
4 0.0
b
3
3
3
3
2 0
k4
1
3
4
6
J0 1
3 1
J1 3
1 1
2 -1
3 1
J2 3
0 -1
1 -1
4 1
28 changes: 21 additions & 7 deletions pyomo/mpec/tests/test_complementarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from pyomo.gdp import Disjunct, Disjunction
from pyomo.mpec import Complementarity, complements, ComplementarityList
from pyomo.opt import ProblemFormat
from pyomo.repn.plugins.nl_writer import FileDeterminism
from pyomo.repn.tests.ampl.nl_diff import load_and_compare_nl_baseline

currdir = this_file_dir()
Expand Down Expand Up @@ -391,16 +392,32 @@ class CCTests_simple_disjunction(CCTests, unittest.TestCase):
xfrm = 'mpec.simple_disjunction'


class CCTests_nl_nlxfrm(CCTests, unittest.TestCase):

class CCTests_nl_nlxfrm(CCTests):
def _test(self, tname, M):
bfile = os.path.join(currdir, tname + '_nlxfrm.nl')
xfrm = TransformationFactory('mpec.nl')
xfrm.apply_to(M)
fd = FileDeterminism.SORT_INDICES if self._nl_version == 'nl_v2' else 1
with TempfileManager:
ofile = TempfileManager.create_tempfile(suffix='_nlxfrm.out')
M.write(ofile, format=ProblemFormat.nl)
self.assertEqual(*load_and_compare_nl_baseline(bfile, ofile))
M.write(
ofile,
format=self._nl_version,
io_options={
'symbolic_solver_labels': False,
'file_determinism': fd,
}
)
self.assertEqual(*load_and_compare_nl_baseline(
bfile, ofile, self._nl_version))


class CCTests_nl_nlxfrm_nlv1(CCTests_nl_nlxfrm, unittest.TestCase):
_nl_version = 'nl_v1'


class CCTests_nl_nlxfrm_nlv2(CCTests_nl_nlxfrm, unittest.TestCase):
_nl_version = 'nl_v2'


class DescendIntoDisjunct(unittest.TestCase):
Expand Down Expand Up @@ -453,9 +470,6 @@ def test_simple_nonlinear_descend_into_disjunct(self):

def test_simple_nonlinear_on_disjunct(self):
m = self.get_model()
TransformationFactory('mpec.simple_nonlinear').apply_to(m.disjunct1)
self.check_simple_nonlinear(m)

def check_standard_form(self, m):
# check that we have what we expect on disjunct1
compBlock = m.disjunct1.component('comp')
Expand Down
2 changes: 1 addition & 1 deletion pyomo/repn/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ def load():

from pyomo.opt import WriterFactory
WriterFactory.register('nl', 'Generate the corresponding AMPL NL file.')(
WriterFactory.get_class('nl_v1'))
WriterFactory.get_class('nl_v2'))
Loading

0 comments on commit 7edd5f0

Please sign in to comment.