Skip to content

Commit 25d5910

Browse files
authored
Merge pull request Pyomo#3319 from jsiirola/nlv2_nested_external
NLv2: support expressions with nested external functions
2 parents 3c36377 + 4464b99 commit 25d5910

File tree

2 files changed

+82
-12
lines changed

2 files changed

+82
-12
lines changed

pyomo/repn/plugins/nl_writer.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,18 @@ def _record_named_expression_usage(self, named_exprs, src, comp_type):
19881988
elif info[comp_type] != src:
19891989
info[comp_type] = 0
19901990

1991+
def _resolve_subexpression_args(self, nl, args):
1992+
final_args = []
1993+
for arg in args:
1994+
if arg in self.var_id_to_nl_map:
1995+
final_args.append(self.var_id_to_nl_map[arg])
1996+
else:
1997+
_nl, _ids, _ = self.subexpression_cache[arg][1].compile_repn(
1998+
self.visitor
1999+
)
2000+
final_args.append(self._resolve_subexpression_args(_nl, _ids))
2001+
return nl % tuple(final_args)
2002+
19912003
def _write_nl_expression(self, repn, include_const):
19922004
# Note that repn.mult should always be 1 (the AMPLRepn was
19932005
# compiled before this point). Omitting the assertion for
@@ -2007,18 +2019,7 @@ def _write_nl_expression(self, repn, include_const):
20072019
nl % tuple(map(self.var_id_to_nl_map.__getitem__, args))
20082020
)
20092021
except KeyError:
2010-
final_args = []
2011-
for arg in args:
2012-
if arg in self.var_id_to_nl_map:
2013-
final_args.append(self.var_id_to_nl_map[arg])
2014-
else:
2015-
_nl, _ids, _ = self.subexpression_cache[arg][1].compile_repn(
2016-
self.visitor
2017-
)
2018-
final_args.append(
2019-
_nl % tuple(map(self.var_id_to_nl_map.__getitem__, _ids))
2020-
)
2021-
self.ostream.write(nl % tuple(final_args))
2022+
self.ostream.write(self._resolve_subexpression_args(nl, args))
20222023

20232024
elif include_const:
20242025
self.ostream.write(self.template.const % repn.const)

pyomo/repn/tests/ampl/test_nlv2.py

+69
Original file line numberDiff line numberDiff line change
@@ -2703,3 +2703,72 @@ def test_presolve_check_invalid_monomial_constraints(self):
27032703
r"\(fixed body value 5.0 outside bounds \[10, None\]\)\.",
27042704
):
27052705
nl_writer.NLWriter().write(m, OUT, linear_presolve=True)
2706+
2707+
def test_nested_external_expressions(self):
2708+
# This tests nested external functions in a single expression
2709+
DLL = find_GSL()
2710+
if not DLL:
2711+
self.skipTest("Could not find the amplgsl.dll library")
2712+
2713+
m = ConcreteModel()
2714+
m.hypot = ExternalFunction(library=DLL, function="gsl_hypot")
2715+
m.p = Param(initialize=1, mutable=True)
2716+
m.x = Var(bounds=(None, 3))
2717+
m.y = Var(bounds=(3, None))
2718+
m.z = Var(initialize=1)
2719+
m.o = Objective(expr=m.z**2 * m.hypot(m.z, m.hypot(m.x, m.y)) ** 2)
2720+
m.c = Constraint(expr=m.x == m.y)
2721+
2722+
OUT = io.StringIO()
2723+
nl_writer.NLWriter().write(
2724+
m, OUT, symbolic_solver_labels=True, linear_presolve=False
2725+
)
2726+
self.assertEqual(
2727+
*nl_diff(
2728+
"""g3 1 1 0 #problem unknown
2729+
3 1 1 0 1 #vars, constraints, objectives, ranges, eqns
2730+
0 1 0 0 0 0 #nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
2731+
0 0 #network constraints: nonlinear, linear
2732+
0 3 0 #nonlinear vars in constraints, objectives, both
2733+
0 1 0 1 #linear network variables; functions; arith, flags
2734+
0 0 0 0 0 #discrete variables: binary, integer, nonlinear (b,c,o)
2735+
2 3 #nonzeros in Jacobian, obj. gradient
2736+
1 1 #max name lengths: constraints, variables
2737+
0 0 0 0 0 #common exprs: b,c,o,c1,o1
2738+
F0 1 -1 gsl_hypot
2739+
C0 #c
2740+
n0
2741+
O0 0 #o
2742+
o2 #*
2743+
o5 #^
2744+
v0 #z
2745+
n2
2746+
o5 #^
2747+
f0 2 #hypot
2748+
v0 #z
2749+
f0 2 #hypot
2750+
v1 #x
2751+
v2 #y
2752+
n2
2753+
x1 #initial guess
2754+
0 1 #z
2755+
r #1 ranges (rhs's)
2756+
4 0 #c
2757+
b #3 bounds (on variables)
2758+
3 #z
2759+
1 3 #x
2760+
2 3 #y
2761+
k2 #intermediate Jacobian column lengths
2762+
0
2763+
1
2764+
J0 2 #c
2765+
1 1
2766+
2 -1
2767+
G0 3 #o
2768+
0 0
2769+
1 0
2770+
2 0
2771+
""",
2772+
OUT.getvalue(),
2773+
)
2774+
)

0 commit comments

Comments
 (0)