0

When I create an mp model in docplex I can check whether or not a solution is feasible and can show the unsatisfied constraints for infeasible solutions:

from docplex.cp.model import CpoModel 
from docplex.mp.model import Model

mp_model = Model('MP')
mp_x = mp_model.integer_var(0, 10, "x")

mp_model.add_constraint(mp_x <= 5)
mp_model.add_constraint(mp_x <= 2)

possible_mp_solution = mp_model.new_solution()
possible_mp_solution.add_var_value(mp_x,3) 

print(possible_mp_solution.find_unsatisfied_constraints(mp_model))

Is the same (or something similar) possible for CP? I know you can create solutions to use the as starting point, but i am searching for a way to get information on a possible solution.

cp_model = CpoModel(name='CP')
cp_x = cp_model.integer_var(0, 10, "x")

cp_model.add_constraint(cp_x <= 5)
cp_model.add_constraint(cp_x <= 2)


possible_cp_solution = cp_model.create_empty_solution()
possible_cp_solution.set_value(cp_x,3)

# does not exist
# print(possible_cp_solution.find_unsatisfied_constraints(cp_model))
Finn
  • 2,333
  • 1
  • 10
  • 21

1 Answers1

1

Checking a solution against a model is not directly available in CP Optimizer, but you could add your solution as additional constraints in the model and run the conflict refiner. This would find "one" of the constraints that explains why the solution is infeasible, together with a subset of the variables assignments.

Here is an illustration on your example:

from docplex.cp.model import *

# Assumes solution only contains fixed integer or interval variables
def solution_as_constraints(sol) :
    cts = []
    vars = sol.get_all_var_solutions()
    for v in vars:
        if isinstance(v, CpoIntVarSolution):
            cts.append(v.get_expr() == v.get_value())
        elif isinstance(v, CpoIntervalVarSolution):
            if v.is_present():
                cts.append(presence_of(v.get_expr()))
                cts.append(start_of(v.get_expr()) == v.get_start())
                cts.append(end_of  (v.get_expr()) == v.get_end())
                cts.append(size_of (v.get_expr()) == v.get_size())
            else:
                cts.append(presence_of(v.get_expr())==0)
    return cts

cp_model = CpoModel(name='CP')
cp_x = cp_model.integer_var(0, 10, "x")

cp_model.add_constraint(cp_x <= 5)
cp_model.add_constraint(cp_x <= 2)

possible_cp_solution = cp_model.create_empty_solution()
possible_cp_solution.set_value(cp_x,3)

cp_model.add(solution_as_constraints(possible_cp_solution))
if not cp_model.solve():
    cp_model.refine_conflict().write()

You will get something like:

Conflict refiner result (TerminatedNormally):
Member constraints:
   x == 3
   x <= 2