3

I have a Pyomo model with many constraints and variables. When solving it with Gurobi, I get the message "Model is infeasible or unbounded". Now I would like to find out which constraints cause the problem. Here in this question Finding out reason of Pyomo model infeasibility there is an advice to use the following command

log_infeasible_constraints(model)

The problem with this approach is that it just prints out every single value of a variable that causes problems. As I have quite many variables the printed out information is too large for the console of Spyder. So basically I have 2 questions:

  1. Can I print out the information from the log into a txt file? I tried the following but I get an error message:
file = open("Log.txt", "w") 
file.write(log_infeasible_constraints(model)) 
file.close()

--> TypeError: write() argument must be str, not None

  1. Is there another approach for finding out what is causing the problem in Pyomo? Can I somehow see the values of all variables at the time the infeasibility or unboundedness is found out?

Reminder: Does anyone have an idea how I can get more precise information about the error? Especially seeing the values of the variables would be quite helpful. Any idea?

PeterBe
  • 1,632
  • 2
  • 15
  • 30
  • Use "model.write(filename="your_model_name.lp",io_options={"symbolic_solver_labels":True})" and debugging on created lp file you can find problems. – kur ag Apr 23 '21 at 11:04
  • 1
    This is not Pyomo specific, but it explains very well how to achieve what you want, whatever modeler or solver you are using. – Kuifje Apr 26 '21 at 07:36
  • A combination of constraints makes the problem infeasible. I'm not sure which set of constraints would be made culprit of infeasibility. I see only way to do so is by solving the problem iteratively by adding more and more constraints. – mufassir Nov 07 '23 at 06:47

1 Answers1

4

You can find out which constraints cause the infeasibility by the following code. For details look at here:

log_infeasible_constraints(m)

$m$ is your model's name. In the provided link, you can find details of how the infeasible constraints log in Pyomo. The output of the provided code is a dictionary with constraint name, constraint's body value, constraint's lower bound, etc. These values can be obtained individually as well. Instead of write, I suggest using print to see what the output is.

UPDATE: The following is an MWE for your question:

from pyomo.environ import Param, ConcreteModel, Var, Objective, ConstraintList, value, minimize
from pyomo.opt import SolverFactory
from pyomo.util.infeasible import log_infeasible_constraints
import logging

m = ConcreteModel() m.LE = set([1, 2, 3]) m.x = Var(m.LE, initialize=0) m.M = Param(initialize=1000000)

def obj_rule(m): return sum(m.x[i] * 1 for i in m.LE)

m.z = Objective(rule=obj_rule, sense=minimize) m.cons1 = ConstraintList()

for i in m.LE: m.cons1.add(102 * m.x[i] >= m.M) m.cons1.add(102 * m.x[i] <= -3)

solver = SolverFactory('glpk') solution = solver.solve(m, tee=False) log_infeasible_constraints(m, log_expression=True, log_variables=True) logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.INFO) print(value(m.z))

And the example.log is the generated .txt file which includes the following data:

INFO:pyomo.util.infeasible:CONSTR cons1[1]: 1000000.0 </= 0
  - EXPR: 1000000.0 </= 100*x[1]
  - VAR x[1]: 0
INFO:pyomo.util.infeasible:CONSTR cons1[2]: 0 </= -3.0
  - EXPR: 100*x[1] </= -3.0
  - VAR x[1]: 0
INFO:pyomo.util.infeasible:CONSTR cons1[3]: 1000000.0 </= 0
  - EXPR: 1000000.0 </= 100*x[2]
  - VAR x[2]: 0
INFO:pyomo.util.infeasible:CONSTR cons1[4]: 0 </= -3.0
  - EXPR: 100*x[2] </= -3.0
  - VAR x[2]: 0
INFO:pyomo.util.infeasible:CONSTR cons1[5]: 1000000.0 </= 0
  - EXPR: 1000000.0 </= 100*x[3]
  - VAR x[3]: 0
INFO:pyomo.util.infeasible:CONSTR cons1[6]: 0 </= -3.0
  - EXPR: 100*x[3] </= -3.0
  - VAR x[3]: 0

example.log is generated in the same location that you run your code (same folder).

Oguz Toragay
  • 8,652
  • 2
  • 13
  • 41
  • Thanks Oguz for your answer. Your posted solution is exactly what I was also using and what is mentioned in my question. And the 2 mentioned problems still persist (as it is exactly the same code). 1) I can't print it into a file and the console itself it soo small to see the whole message. 2) This approach is quite imprecise as it just reports every single value of a not valid constraint for every set which leads to an error for every value of a variable. Is there no better way of finding out what the problematic constraint or variables are? – PeterBe Apr 14 '21 at 16:21
  • By the way: Using print did not change anything. When using it for the console, the output is still too big sucht that it does not fit into the console. When using together with the file file.print(log_infeasible_constraints(model)) I get an error AttributeError: '_io.TextIOWrapper' object has no attribute 'print' – PeterBe Apr 14 '21 at 16:23
  • Thanks Oguz for your answer. Any comments to my last comments? Where can I see the dictionary you mentioned with the constraints? I'd highly appreciate every further comment from you. – PeterBe Apr 15 '21 at 07:40
  • Any comments on my last comments? – PeterBe Apr 16 '21 at 06:28
  • @PeterBe I hope it works this time. – Oguz Toragay Apr 27 '21 at 04:27
  • 1
    @PeterBe, one possible way would be scaling your problem as small as possible and trying to solve it and find out how you can fix it. As a second stuff, the IIS information might be tighter and helpful. Also, referred to the mentioned link by Kuifje. – A.Omidi Apr 27 '21 at 07:54
  • Thanks Oguz for your answer. When using your suggested code I get the error message "ValueError: Unrecognised argument(s): encoding" pointed at the line logging.basicConfig(filename='Log_example.log', encoding='utf-8', level=logging.INFO) – PeterBe Apr 28 '21 at 06:39
  • Did you import logging? – Oguz Toragay Apr 28 '21 at 06:46
  • Yes, I imported the logging by using import logging – PeterBe Apr 28 '21 at 10:00
  • If it is still not working, try the answering this link: https://stackoverflow.com/a/10711471/15417280 – Oguz Toragay Apr 28 '21 at 14:08
  • Thanks Oguz for your answer and the link. I tried the answer in the link and really strange things happen. So I have the code log_infeasible_constraints(model, log_expression=True, log_variables=True) root_logger= logging.getLogger() root_logger.setLevel(logging.DEBUG) # or whatever handler = logging.FileHandler('Log_example1.log', 'w', 'utf-8') # or whatever handler.setFormatter(logging.Formatter('%(name)s %(message)s')) # or whatever root_logger.addHandler(handler) – PeterBe Apr 29 '21 at 09:54
  • When running it, I get an empty file 'Log_example1.log'. When then adjusting the name in the Python code to 'Log_example2.log', a new empty txt file is created with the name ''Log_example2.log''. Strangely now the file from the previous run 'Log_example1.log' is not empty any more. It has a size of 4 MB and containts quite much information that is not useful to debug the model. – PeterBe Apr 29 '21 at 09:56
  • So basically I have 2 question: 1) Do you have an idea why this strange behaviour with the txt files and names occur? 2) How can I only print the error messages into the txt file and not the calculation formulars for every variable and constraint? – PeterBe Apr 29 '21 at 09:56
  • I don’t have any idea what’s going on in your code. But this approach worked perfectly in my case. – Oguz Toragay Apr 29 '21 at 14:08
  • Thanks Oguz for your answer and effort. What about my 2) question from my last comment and what do you mean by "worked perfectly" in your case? Did it only print the constraint violations to the file? How can I do that? With your suggested code it just prints the formulars for calculating every single value of a variable which is definitely not what I want. – PeterBe Apr 29 '21 at 15:22
  • Which approach are you talking about? Your suggested code logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.INFO) leads to an AttributeError. The code from the link you gave me creates very strange text files. Did you also use the code from the link you posted? – PeterBe Apr 29 '21 at 15:34
  • @OguzToragay: Thanks for the chat. I have responded to your answers in the chat and I have identified the problems (but I have no solution yet for them). Maybe you can have a look in the chat – PeterBe Apr 30 '21 at 08:26
  • Thanks for your help and effort Oguz. I really appreciate it. I upvoted the answer, accepted it and awarded the bountry to you due to your tremendous effort. Hopefully you can still have a look at my questions in the chat as my initial question is not yet fully answered. – PeterBe Apr 30 '21 at 15:57
  • @Oguz: Any comments to my last comment in the chat? I'd highly appreciate every further comment from you. – PeterBe May 10 '21 at 09:05