Skip to content

Commit

Permalink
Remove Port.Conservative, be more selective for evar bounds
Browse files Browse the repository at this point in the history
This removes the Conservative rule and its helper methods and instead
changes the handling of include_splitfrac to that specifying
include_splitfrac=False will prevent the split fraction variables from
being created.  This also changes how expanded arc variables' domains
and bounds are set, so that the domain is only tightened when the arc
has a single source or single destination.
  • Loading branch information
jsiirola committed Jan 30, 2020
1 parent a108b21 commit edb99d5
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 140 deletions.
110 changes: 27 additions & 83 deletions pyomo/network/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
IPyomoScriptModifyInstance, TransformationFactory
from pyomo.core.kernel.component_map import ComponentMap

from pyomo.network.util import replicate_var
from pyomo.network.util import create_var, tighten_var_domain

logger = logging.getLogger('pyomo.network')

Expand Down Expand Up @@ -205,10 +205,6 @@ def is_extensive(self, name):
"""Return True if the rule for this port member is Port.Extensive"""
return self.rule_for(name) is Port.Extensive

def is_conservative(self, name):
"""Return True if the rule for this port member is Port.Conservative"""
return self.rule_for(name) is Port.Conservative

def fix(self):
"""
Fix all variables in the port at their current values.
Expand Down Expand Up @@ -385,13 +381,23 @@ def _add_from_container(self, port, items):
if type(items) is dict:
for key, val in iteritems(items):
if type(val) is tuple:
port.add(val[0], key, val[1])
if len(val) == 2:
obj, rule = val
port.add(obj, key, rule)
else:
obj, rule, kwds = val
port.add(obj, key, rule, **kwds)
else:
port.add(val, key)
else:
for val in self._initialize:
if type(val) is tuple:
port.add(val[0], rule=val[1])
if len(val) == 2:
obj, rule = val
port.add(obj, rule=rule)
else:
obj, rule, kwds = val
port.add(obj, rule=rule, **kwds)
else:
port.add(val)

Expand Down Expand Up @@ -452,7 +458,7 @@ def Equality(port, name, index_set):
Port._add_equality_constraint(arc, name, index_set)

@staticmethod
def Extensive(port, name, index_set, include_splitfrac=False,
def Extensive(port, name, index_set, include_splitfrac=None,
write_var_sum=True):
"""
Arc Expansion procedure for extensive variable properties
Expand Down Expand Up @@ -501,23 +507,6 @@ def Extensive(port, name, index_set, include_splitfrac=False,
include_splitfrac=include_splitfrac, write_var_sum=write_var_sum)
in_vars = Port._Combine(port, name, index_set)

@staticmethod
def Conservative(port, name, index_set):
"""
Arc Expansion procedure for conservative variable properties.
This procedure is the rule to use when variable quantities should
be conserved without fixing a split for inlets or fixing combinations
for outlet.
It acts like Extensive but does not introduces a split variable
nor a split constraint.
"""

port_parent = port.parent_block()
out_vars = Port._Split_Conservative(port, name, index_set)
in_vars = Port._Combine(port, name, index_set)

@staticmethod
def _Combine(port, name, index_set):
port_parent = port.parent_block()
Expand All @@ -541,6 +530,9 @@ def _Combine(port, name, index_set):
evar = Port._create_evar(port.vars[name], name, eblock, index_set)
in_vars.append(evar)

if len(sources) == 1:
tighten_var_domain(port.vars[name], in_vars[0], index_set)

# Create constraint: var == sum of evars
# Same logic as Port._Split
cname = unique_component_name(port_parent, "%s_%s_insum" %
Expand All @@ -556,12 +548,11 @@ def rule(m, *args):
return in_vars

@staticmethod
def _Split(port, name, index_set, include_splitfrac=False,
def _Split(port, name, index_set, include_splitfrac=None,
write_var_sum=True):
port_parent = port.parent_block()
var = port.vars[name]
out_vars = []
no_splitfrac = False
dests = port.dests(active=True)

if not len(dests):
Expand All @@ -577,7 +568,8 @@ def _Split(port, name, index_set, include_splitfrac=False,
"Cannot fix splitfrac not at 1 for port '%s' with a "
"single dest '%s'" % (port.name, dests[0].name))

no_splitfrac = True
if include_splitfrac is not True:
include_splitfrac = False

if len(dests[0].destination.sources(active=True)) == 1:
# This is a 1-to-1 connection, no need for evar, just equality.
Expand All @@ -592,7 +584,7 @@ def _Split(port, name, index_set, include_splitfrac=False,
evar = Port._create_evar(port.vars[name], name, eblock, index_set)
out_vars.append(evar)

if no_splitfrac:
if include_splitfrac is False:
continue

# Create and potentially initialize split fraction variables.
Expand Down Expand Up @@ -627,7 +619,7 @@ def _Split(port, name, index_set, include_splitfrac=False,
"splitfracs, please pass the "
" include_splitfrac=True argument." %
(port.name, arc.name))
no_splitfrac = True
include_splitfrac = False
continue

eblock.splitfrac = Var()
Expand All @@ -647,6 +639,9 @@ def rule(m, *args):
con = Constraint(index_set, rule=rule)
eblock.add_component(cname, con)

if len(dests) == 1:
tighten_var_domain(port.vars[name], out_vars[0], index_set)

if write_var_sum:
# Create var total sum constraint: var == sum of evars
# Need to alphanum port name in case it is indexed.
Expand All @@ -661,7 +656,7 @@ def rule(m, *args):
port_parent.add_component(cname, con)
else:
# OR create constraint on splitfrac vars: sum == 1
if no_splitfrac:
if include_splitfrac is False:
raise ValueError(
"Cannot choose to write split fraction sum constraint for "
"ports with a single destination or a single Extensive "
Expand All @@ -676,56 +671,6 @@ def rule(m, *args):

return out_vars

@staticmethod
def _Split_Conservative(port, name, index_set):
port_parent = port.parent_block()
var = port.vars[name]
out_vars = []
no_splitfrac = False
dests = port.dests(active=True)

if not len(dests):
return out_vars

if len(dests) == 1:
# No need for splitting on one outlet.
# Make sure they do not try to fix splitfrac not at 1.
splitfracspec = port.get_split_fraction(dests[0])
if splitfracspec is not None:
if splitfracspec[0] != 1 and splitfracspec[1] is True:
raise ValueError(
"Cannot fix splitfrac not at 1 for port '%s' with a "
"single dest '%s'" % (port.name, dests[0].name))

if len(dests[0].destination.sources(active=True)) == 1:
# This is a 1-to-1 connection, no need for evar, just equality.
arc = dests[0]
Port._add_equality_constraint(arc, name, index_set)
return out_vars

for arc in dests:
eblock = arc.expanded_block

# Make and record new variables for every arc with this member.
evar = Port._create_evar(port.vars[name], name, eblock, index_set)
out_vars.append(evar)

# Create var total sum constraint: var == sum of evars
# Need to alphanum port name in case it is indexed.
cname = unique_component_name(port_parent, "%s_%s_outsum" %
(alphanum_label_from_name(port.local_name), name))

def rule(m, *args):
if len(args):
return sum(evar[args] for evar in out_vars) == var[args]
else:
return sum(evar for evar in out_vars) == var

con = Constraint(index_set, rule=rule)
port_parent.add_component(cname, con)

return out_vars

@staticmethod
def _add_equality_constraint(arc, name, index_set):
# This function will add the equality constraint if it doesn't exist.
Expand All @@ -751,10 +696,9 @@ def _create_evar(member, name, eblock, index_set):
# before making a new one.
evar = eblock.component(name)
if evar is None:
evar = replicate_var(member, name, eblock, index_set)
evar = create_var(member, name, eblock, index_set)
return evar


class SimplePort(Port, _PortData):

def __init__(self, *args, **kwd):
Expand Down
70 changes: 35 additions & 35 deletions pyomo/network/tests/test_arc.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,14 +984,14 @@ def test_inactive(self):
1 Declarations: v_equality
""")

def test_conservative_single_var(self):
def test_extensive_no_splitfrac_single_var(self):
m = ConcreteModel()
m.x = Var()
m.y = Var()
m.z = Var()
m.p1 = Port(initialize={'v': (m.x, Port.Conservative)})
m.p2 = Port(initialize={'v': (m.y, Port.Conservative)})
m.p3 = Port(initialize={'v': (m.z, Port.Conservative)})
m.p1 = Port(initialize={'v': (m.x, Port.Extensive, {'include_splitfrac':False})})
m.p2 = Port(initialize={'v': (m.y, Port.Extensive, {'include_splitfrac':False})})
m.p3 = Port(initialize={'v': (m.z, Port.Extensive, {'include_splitfrac':False})})
m.a1 = Arc(source=m.p1, destination=m.p2)
m.a2 = Arc(source=m.p1, destination=m.p3)

Expand Down Expand Up @@ -1136,7 +1136,7 @@ def test_extensive_single_var(self):
13 Declarations: x y z p1 p2 p3 a1 a2 a1_expanded a2_expanded p1_v_outsum p2_v_insum p3_v_insum
""")

def test_conservative_expansion(self):
def test_extensive_no_splitfrac_expansion(self):
m = ConcreteModel()
m.time = Set(initialize=[1, 2, 3])

Expand All @@ -1147,12 +1147,12 @@ def test_conservative_expansion(self):
def source_block(b):
b.t = Set(initialize=[1, 2, 3])
b.p_out = Var(b.t)
b.outlet = Port(initialize={'p': (b.p_out, Port.Conservative)})
b.outlet = Port(initialize={'p': (b.p_out, Port.Extensive, {'include_splitfrac':False})})

def load_block(b):
b.t = Set(initialize=[1, 2, 3])
b.p_in = Var(b.t)
b.inlet = Port(initialize={'p': (b.p_in, Port.Conservative)})
b.inlet = Port(initialize={'p': (b.p_in, Port.Extensive, {'include_splitfrac':False})})

source_block(m.source)
load_block(m.load1)
Expand Down Expand Up @@ -1530,9 +1530,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1558,9 +1558,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1586,9 +1586,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1614,9 +1614,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : 0 : None : None : False : True : Reals
b : 0 : None : None : False : True : Reals
c : 0 : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand Down Expand Up @@ -1657,9 +1657,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1685,9 +1685,9 @@ def test_extensive_expansion(self):
2 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : 0 : None : None : False : True : Reals
b : 0 : None : None : False : True : Reals
c : 0 : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1702,9 +1702,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1730,9 +1730,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand All @@ -1758,9 +1758,9 @@ def test_extensive_expansion(self):
3 Var Declarations
flow : Size=3, Index=comp
Key : Lower : Value : Upper : Fixed : Stale : Domain
a : 0 : None : None : False : True : NonNegativeReals
b : 0 : None : None : False : True : NonNegativeReals
c : 0 : None : None : False : True : NonNegativeReals
a : None : None : None : False : True : Reals
b : None : None : None : False : True : Reals
c : None : None : None : False : True : Reals
mass : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
Expand Down Expand Up @@ -1873,4 +1873,4 @@ def test_extensive_expansion(self):


if __name__ == "__main__":
unittest.main()
unittest.main()
Loading

0 comments on commit edb99d5

Please sign in to comment.