Use of log function in pyomo from spyder with couenne solver - pyomo

I have the following constraint in a simple MINLP model:
model.cm2=Constraint(expr = model.xB2 == log(1.0+model.xA2))
This works when I call bonmin (windows64 binary distribution from AMPL)
When swithing to the couenne solver I need to convert to log10 base
model.cm2=Constraint(expr = model.xB2 == 2.3*log10(1.0+model.xA2))
otherwise I get the error:
ApplicationError: Solver (asl) did not exit normally.
model.pprint() gives in the first case:
cm2 : Size=1, Index=None, Active=True
Key : Lower : Body : Upper : Active
None : 0.0 : xB2 - log( 1.0 + xA2 ) : 0.0 : True
I use the anaconda python installation and work with spyder.
Do anyone have an idea of the reason for this behaviour?
I have read the comment from jsiirola, but I do not think that the problem is evaluating the log of a negative number. Here is a complete test problem, that behaves the same way. If I solve with bonmin i can use log() if I use cuonne I have to use ln(10)*log10().
from pyomo.environ import *
solverpathb="..\\solversAMPL\\bonmin\\bonmin"
solverpathc="..\\solversAMPL\\couenne\\couenne"
model=ConcreteModel()
model.x = Var(within=NonNegativeReals,bounds=(1,2),doc='Nonnegative')
model.y = Var(within=NonNegativeReals,doc='Nonnegative')
model.obj = Objective(expr= model.x+model.y, sense=maximize)
model.c1=Constraint(expr = model.y == log(1.0+model.x))
#model.c2=Constraint(expr = model.y == 2.3*log10(1.0+model.x))
#Works with version c1 and c2 of the constraint
#solver = pyomo.opt.SolverFactory("bonmin", executable=solverpathb)
#only constraint c2 works with this solver
solver = pyomo.opt.SolverFactory("couenne", executable=solverpathc)
results = solver.solve(model, tee = True)
model.display()
The log file that should include errors only includes the model. This is the last part of the errors.
...
File "C:/../testproblem.py", line 24, in
results = solver.solve(model, tee = True)
File "C:\Users..\Python\Python36\site-packages\pyomo\opt\base\solvers.py", line 623, in solve
"Solver (%s) did not exit normally" % self.name)
ApplicationError: Solver (asl) did not exit normally.
Note: I can use the following code for the object function, also with couenne
model.obj = Objective(expr= model.x+log(1.0+model.x), sense=maximize)

First, the entire model would be most useful when debugging problems like this. Second, what error is being thrown by Couenne when it exits abnormally?
As to answers:
Pyomo uses the same interface for BONMIN and Couenne (they are both through the ASL), so you should never have to change your expression just because you switched solvers. log and log10 are not the same function, of course, so you are not solving the same problem.
I suspect the problem is that model.xA2 is going less than or equal to -1 (i.e., the solver is asking the ASL to evaluate log(0). The way to verify this is by looking at the solver log. Additionally, you will want to make sure that Pyomo sends "symbolic" labels to the solver so that the error will reference actual variable / constraint names and not just "x1, x2, x3, ..." and "c1, c2, c3, ..." in the error message.
Couenne is a global solver, whereas BONMIN is a local solver. As this is a nonconvex problem, Couenne is probably exploring parts of the solution space that BONMIN never went to.

Using a binary distribution from COIN-OR solved the problem, it was not a pyomo problem. The binary distribution of couenne downloaded from ampl.com doesn't, for some odd reason, accept the log-function, only log10.

Related

HiGHS solver returns error when using Pyomo Kernel

I've been trying to get the HiGHS solver to work with the Pyomo kernel interface, but when I try to solve it it gives me this error: "AttributeError: unreadable attribute 'domain'".
I created a simple example to reproduce is - does HiGHS not not support the kernel?
import pyomo.kernel as pmo
from pyomo.contrib import appsi
m = pmo.block()
m.x1 = pmo.variable(domain=pmo.NonNegativeReals)
m.c = pmo.constraint(m.x1 == 5)
m.o = pmo.objective(m.x1*10, sense=1)
opt = pmo.SolverFactory("appsi_highs")
#opt = appsi.solvers.Highs()
result = opt.solve(m)
Pyomo's interface to HiGHS does not currently support kernel.

Handling map function in python2 & python3

Recently i came across a question & confused with a possible solution,
code part is
// code part in result reader
result = map(int, input())
// consumer call
result_consumer(result)
its not about how do they work, the problem is when you are running in python2 it will raise an exception, on result fetching part, so result reader can handle the exception, but incase of python3 a map object is returned, so only consumer will be able to handle exception.
is there any solution keeping map function & handle the exception in python2 & python3
python3
>>> d = map(int, input())
1,2,3,a
>>> d
<map object at 0x7f70b11ee518>
>>>
python2
>>> d = map(int, input())
1,2,3,'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'a'
>>>
the behavior of map is not the only difference between python2 and python3, input is also difference, you need to keep in mind the basic differences between the two to make code compatible for both
python 3 vs python 2
map = itertools.imap
zip = itertools.izip
filter = itertools.ifilter
range = xrange
input = raw_input
so to make code for both, you can use alternatives like list comprehension that work the same for both, and for those that don't have easy alternatives, you can make new functions and/or use conditional renames, like for example
my_input = input
try:
raw_input
except NameError: #we are in python 3
my_input = lambda msj=None: eval(input(msj))
(or with your favorite way to check which version of python is in execution)
# code part in result reader
result = [ int(x) for x in my_input() ]
# consumer call
result_consumer(result)
that way your code do the same regardless of which version of python you run it.
But as jsbueno mentioned, eval and python2's input are dangerous so use the more secure raw_input or python3's input
try:
input = raw_input
except NameError: #we are in python 3
pass
(or with your favorite way to check which version of python is in execution)
then if your plan is to provide your input as 1,2,3 add an appropriate split
# code part in result reader
result = [ int(x) for x in input().split(",") ]
# consumer call
result_consumer(result)
If you always need the exception to occur at the same place you can always force the map object to yield its results by wrapping it in a list call:
result = list(map(int, input()))
If an error occurs in Python 2 it will be during the call to map while, in Python 3, the error is going to surface during the list call.
The slight downside is that in the case of Python 2 you'll create a new list. To avoid this you could alternatively branch based on sys.version and use the list only in Python 3 but that might be too tedious for you.
I usually use my own version of map in this situations to escape any possible problem may occur and it's
def my_map(func,some_list):
done = []
for item in some_list:
done.append( func(item) )
return done
and my own version of input too
def getinput(text):
import sys
ver = sys.version[0]
if ver=="3":
return input(text)
else:
return raw_input(text)
if you are working on a big project add them to a python file and import them any time you need like what I do.

Datapath#ports is kept for compatibility

I am trying to get ryu to run, especially the topology discovery.
Now I am running the demo application for that under ryu/topology/dumper.py, which is supposed to dump all topology events. I am in the ryu/topology direcory and run it using ryu-manager dumper.py. The version of ryu-manager is 2.23.2.
Shortly after starting it gives me this error:
/usr/local/lib/python2.7/dist-packages/ryu/topology/switches.py:478: UserWarning:
Datapath#ports is kept for compatibility with the previous openflow versions (< 1.3).
This not be updated by EventOFPPortStatus message. If you want to be updated,
you can use 'ryu.controller.dpset' or 'ryu.topology.switches'.
for port in dp.ports.values():
What's really weird to me is that it recommends to use ryu.topology.switches, but that error is triggered by line 478 of that very file!
The function in question is this:
class Switches(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_2.OFP_VERSION,
ofproto_v1_3.OFP_VERSION, ofproto_v1_4.OFP_VERSION]
_EVENTS = [event.EventSwitchEnter, event.EventSwitchLeave,
event.EventPortAdd, event.EventPortDelete,
event.EventPortModify,
event.EventLinkAdd, event.EventLinkDelete]
DEFAULT_TTL = 120 # unused. ignored.
LLDP_PACKET_LEN = len(LLDPPacket.lldp_packet(0, 0, DONTCARE_STR, 0))
LLDP_SEND_GUARD = .05
LLDP_SEND_PERIOD_PER_PORT = .9
TIMEOUT_CHECK_PERIOD = 5.
LINK_TIMEOUT = TIMEOUT_CHECK_PERIOD * 2
LINK_LLDP_DROP = 5
#...
def _register(self, dp):
assert dp.id is not None
self.dps[dp.id] = dp
if dp.id not in self.port_state:
self.port_state[dp.id] = PortState()
for port in dp.ports.values(): # THIS LINE
self.port_state[dp.id].add(port.port_no, port)
Has anyone else encountered this problem before? How can I fix it?
I ran into the same issue (depending on your application, maybe it's not a problem, just a warning that you can ignore). Here is what I figured out after a find . -type f | xargs grep "ports is kept"
This warning is triggered in ryu.topology.switches, by a call to _get_ports() in class Datapath of file ryu/controller/controller.py.
class Datapath(ofproto_protocol.ProtocolDesc):
#......
def _get_ports(self):
if (self.ofproto_parser is not None and
self.ofproto_parser.ofproto.OFP_VERSION >= 0x04):
message = (
'Datapath#ports is kept for compatibility with the previous '
'openflow versions (< 1.3). '
'This not be updated by EventOFPPortStatus message. '
'If you want to be updated, you can use '
'\'ryu.controller.dpset\' or \'ryu.topology.switches\'.'
)
warnings.warn(message, stacklevel=2)
return self._ports
def _set_ports(self, ports):
self._ports = ports
# To show warning when Datapath#ports is read
ports = property(_get_ports, _set_ports)
My understanding is that if the warning is from ryu.topology.switches or ryu.controller.dpset, you can ignore it; because those two classes handle the event for you. But if you use Datapath directly, port status is not updated automatically. Anyone correct me if I'm wrong.
class Switches(app_manager.RyuApp):
#......
#set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
def port_status_handler(self, ev):
I have encountered that problem before but I just ignored it and so far every thing has been working as it was expected.
If you are trying to learn the topology I would recommend using ryu.topology.api. i.e.
from ryu.topology.api import get_switch, get_link
There is this tutorial. However there are some of the stuff missing.
Here is what I have so far: Controller.py
In the Controller.py the two functions get_switch(self, None) and get_link(self, None) would give you list of links and switches.

ValueError: need more than 1 value to unpack - python graph core

I was planning to try to use this code in order to do a critical path analysis.
When running this code I got the following error but I have no idea what it means (because I don't now how the code works).
Traceback (most recent call last): File
"/Users/PeterVanvoorden/Desktop/test.py", line 22, in
G.add_edge('A','B',1) File "/Library/Python/2.7/site-packages/python_graph_core-1.8.2-py2.7.egg/pygraph/classes/digraph.py",
line 161, in add_edge
u, v = edge ValueError: need more than 1 value to unpack
# Copyright (c) 2007-2008 Pedro Matiello <pmatiello#gmail.com>
# License: MIT (see COPYING file)
import sys
sys.path.append('..')
import pygraph
from pygraph.classes.digraph import digraph
from pygraph.algorithms.critical import transitive_edges, critical_path
#demo of the critical path algorithm and the transitivity detection algorithm
G = digraph()
G.add_node('A')
G.add_node('B')
G.add_node('C')
G.add_node('D')
G.add_node('E')
G.add_node('F')
G.add_edge('A','B',1)
G.add_edge('A','C',2)
G.add_edge('B','C',10)
G.add_edge('B','D',2)
G.add_edge('B','E',8)
G.add_edge('C','D',7)
G.add_edge('C','E',3)
G.add_edge('E','D',1)
G.add_edge('D','F',3)
G.add_edge('E','F',1)
#add this edge to add a cycle
#G.add_edge('E','A',1)
print transitive_edges(G)
print critical_path(G)
I know it is kind of stupid just to copy code without understanding it but I thought I'd first try the example code in order to see if the package is working but apparently it's not working. Now I wonder if it's just because of a little mistake in the example code or if it's a more fundamental problem.
I peeked at the source code for this and see that add_edge is trying to unpack the first positional argument as a 2-tuple.
If you change these lines:
G.add_edge('A','B',1)
G.add_edge('A','C',2)
...
to:
G.add_edge(('A', 'B'), 1) # note the extra parens
G.add_edge(('A', 'C'), 2)
...
it should work. However, I have not used pygraph before so this may still not produce the desired results.

Simple matplotlib Annotating example not working in Python 2.7

Code
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=2)
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops=dict(facecolor='black', shrink=0.05),
)
ax.set_ylim(-2,2)
plt.show()
from http://matplotlib.org/1.2.0/users/annotations_intro.html
return
TypeError: 'dict' object is not callable
I manged to fixed it with
xxx={'facecolor':'black', 'shrink':0.05}
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops=xxx,
)
Is this the best way ?
Also what caused this problem ? ( I know that this started with Python 2.7)
So if somebody know more, please share.
Since the code looks fine and runs ok on my machine, it seems that you may have a variable named "dict" (see this answer for reference). A couple of ideas on how to check:
use Pylint.
if you suspect one specific builtin, try checking it's type (type(dict)), or look at the properties/functions it has (dir(dict)).
open a fresh notebook and try again, if you only observe the problem in interactive session.
try alternate syntax to initialise the dictionary
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops={'facecolor':'black', 'shrink':0.05})
try explicitly instancing a variable of this type, using the alternate syntax (as you did already).