-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Termination condition is optimal but number of solutions is 0 #2290
Comments
Please include a minimal example that reproduces the problem. It looks like the SOL file parser is not picking up the "infeasible" message from that version of CBC. Also note that Pyomo 5.7.3 is more than a year old. Please consider upgrading and testing against the current release. |
Updating to pyomo 6.2 doesn't solve the issue. I initially posted the question on OR stackexchange : https://or.stackexchange.com/questions/7810/problem-is-infeasible-with-gurobi-feasible-with-cbc-but-cant-access-objective |
The title of this issue is a duplicate of #556.
Your comment about the number of constraints and variables being 0 is also duplicated in #1033 As for issues with different versions of CBC, there are several known issues and feature requests summarized in #1926. I'm going to close this as I think all of your bug reports are captured in the issues linked above. |
I don't see how #556 relates to my problem, which is not about printing information, but about pyomo returning the wrong status and termination condition. I don't see how any request of #1926 relates to the fact that pyomo is returning the wrong status and termination condition with cbc. I don't understand how you answered the issue and why you closed it. Again, the issue is pyomo returning ok and optimal when it should return infeasible. |
If you solve the model with the If you read through issues #556 and #1033 they describe why printing the results object doesn't really give you the information you might expect it to and is not a recommended way for querying the result. Using If I have misinterpreted your issue report I apologize, feel free to reopen it. Including a snippet of the solver log showing the termination status would help us pinpoint the issue. |
I put together a small infeasible problem (see below), and Pyomo correctly reports the problem as infeasible. However, this could certainly depend on the versions of Pyomo and CBC. I was using Pyomo 6.2 and CBC 2.10.7. I agree with @blnicho - more information is probably needed to debug this. It sounds like an edge case that may be difficult to replicate.
|
I started diving into the CBC source. There appears to be a set of infeasible / not optimal messages that can be emitted that I do not think are caught by our parser (emitted here) [and I think these are what are being emitted by this example]. That said, it is really difficult to see from the code how those messages get triggered, so I am not sure how to generate a Pyomo test case that exercises this particular branch of the CBC code. |
Interesting... |
I converted the LP file from the SO ticket into an equivalent (flat) Pyomo model (issue-2290.py.txt). When sent to CBC, the interface correctly identifies the model as Infeasible (in the presolve). At this point, I am not sure there is much more we can do without a Pyomo model that reproduces the problem. |
I seem to be running into the issue described here, though I'm probably doing something stupid as this is my first Pyomo project. Here is a model that reproduces the problem. import os
import numpy as np
import pandas as pd
import pyomo.environ as pe
#####
# Constants
days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
activities = ["hard", "moderate", "active-recovery", "low-impact"]
activityCost = np.array([0.8, 0.85, 0.9, 0.75])
activityCapCost = np.array([0.5, 0.25, 0.1, 0.75]) # Will be added to 1 and applied
# Cost matrices
activityCosts = np.matrix(np.tile(activityCost.transpose(), (len(days), 1))).transpose()
activityCapCosts = np.matrix(
np.tile(activityCapCost.transpose(), (len(days), 1))
).transpose()
activityAffinities = np.matrix(np.ones((len(activities), len(days))))
# activityAffinities[1, 5] = 0.015
# activityAffinities[1, 6] = 0.015
#####
# Inputs
previousDay = [0, 0, 0, 0]
activityReq = [2, 2, 0, 0]
remainingDays = 7
#####
# Model
model = pe.ConcreteModel("activity Scheduler")
model.activities = pe.Var(
((day, activity) for day in days for activity in activities),
within=pe.Binary,
initialize=0,
bounds=(0, 1),
)
#####
# Objective
def objective_rule(model, verbose=False):
# Build activity matrix and capacity matrix
activityMtx = np.matrix(np.zeros((len(activities), len(days))))
capMtx = np.matrix(np.zeros((len(activities), len(days))))
capMtx[:, 0] = np.reshape(previousDay, (len(activities), 1))
for i, day in enumerate(days):
for j, activity in enumerate(activities):
activityMtx[j, i] = pe.value(model.activities[day, activity])
if i < 6:
capMtx[j, i + 1] = pe.value(model.activities[day, activity])
# Calculate basic activity costs
cost_matrix = np.multiply(activityMtx, activityCosts)
# Apply affinity credit
cost_matrix = np.multiply(cost_matrix, activityAffinities)
# Add penalty costs
penalty_matrix = np.multiply(capMtx, activityCapCosts)
penalty_vector = penalty_matrix.sum(axis=0)
penalty_vector = np.add(penalty_vector, 1.0)
cost_matrix = np.multiply(cost_matrix, penalty_vector)
return cost_matrix.sum()
model.obj = pe.Objective(
rule=objective_rule, sense=pe.minimize, name="activity Schedule"
)
#####
# Constraints
model.constraints = pe.ConstraintList()
# No more than one activity per day
for day in days:
model.constraints.add(
sum(model.activities[day, activity] for activity in activities) <= 1
)
# Do not exceed the activity requirements
for i, activity in enumerate(activities):
model.constraints.add(
sum(model.activities[day, activity] for day in days) <= activityReq[i]
)
# Assign the maximum allowable activities
model.constraints.add(
sum(model.activities[day, activity] for day in days for activity in activities)
== min(remainingDays, sum(activityReq))
)
#####
# Solution
solver_manager = pe.SolverManagerFactory("serial")
solver = pe.SolverFactory("cbc")
# solver.options = {"maxIt": 268435456}
results = solver_manager.solve(model, opt=solver, tee=True)
# model.display()
print(f"Is optimal: {pe.check_optimal_termination(results)}")
# print(results)
activities_table = pd.DataFrame(
np.zeros((len(activities), len(days))), index=activities, columns=days
)
for i, day in enumerate(days):
for j, activity in enumerate(activities):
activities_table.iloc[j, i] = pe.value(model.activities[day, activity])
def map_activity_type(day):
if day[0] == 1:
return "hard"
elif day[1] == 1:
return "moderate"
elif day[2] == 1:
return "active-recovery"
elif day[3] == 1:
return "low-impact"
else:
return None
print(activities_table.apply(map_activity_type, axis=0)) The basic idea here is that we're trying to optimally schedule a number of activities. Doing an activity two days in a row incurs a penalty. We want to bias towards scheduling harder activities, but have a higher penalty for activities after a hard day. |
This is the result when I run this locally:
|
@jessecurry if you would like to report a bug please open a new issue following our issue template rather than commenting on an old closed issue. If you think your bug report is related to a closed issue then you can easily link to it by including the issue number in your bug report. |
I am using pyomo (Pyomo 5.7.3 (CPython 3.9.6 on Windows 10)) with cbc (CBC 2.10.5) to solve a MILP. Using the following command
I get the following
Status if
ok
and termination isoptimal
, however the number of solution if 0, which is confirmed when trying to access the objective value.I've used different solvers with pyomo, as well as stand alone cbc, and, and in any case the solver returned a status of infeasible.
I'm also surprised that number of constraints and number of variables are 0.
The text was updated successfully, but these errors were encountered: