Title CPLEX crashes when loading a MIP with only empty constraints.
Priority bug Status chatting
Superseder Nosy List clemens, florian, jendrik, malte, silvan
Assigned To Keywords
Optional summary

Created on 2023-09-05.12:46:36 by clemens, last changed by clemens.

msg11510 (view) Author: clemens Date: 2024-01-09.12:03:21
Florian and I have implemented a solution. Instead of returning just the result of vector::data(), we call a function that returns vector::data() when the vector is non-empty and otherwise it returns the address to a static instance of the corresponding type. With this, we allow the special case of empty or trivial constraints as discussed below. Pull request:

One potential drawback we discussed is that it now becomes harder to realize if one adds trivial/useless constraints, because the code simply accepts them when it previously crashed. It might be a good idea to trigger a warning in such cases, but we consider this a separate issue and didn't discuss this much further.
msg11345 (view) Author: malte Date: 2023-09-05.15:06:24
I think it's best not to disallow special cases like 0 <= 0.
msg11344 (view) Author: florian Date: 2023-09-05.15:04:53
Just to clarify a detail: CPXcopylp is not the problem here, it is our own code, as far as I understand. If we pass a matrix with one empty row rather than a matrix with 0 rows, I think CPXcopylp expects a non-zero pointer to the coefficients even if there are none. That is, it expects a non-zero double* that is interpreted as a double[] of length 0. In our code, we avoid dealing with C-style arrays by using vectors and the vector::data() method to pass the data to CPLEX's interface. If the vector is empty, vector::data() gives us the nullptr.

So an alternative to forbidding the case would be to pass in any non-zero pointer in this case, say the address of a static double. The pointer is checked against nullptr obviously (this is what triggers the warning), but we also pass in the number of entries in each row or column so if that is 0, the pointer should never be accessed.

I think saying "you are not allowed to add only trivial constraints (0 <= 0) to your LP" would be fine, but we can also try to add support for this edge case.
msg11336 (view) Author: clemens Date: 2023-09-05.12:46:36
CPLEX yields "CPLEX Error  1004: Null pointer for required data." when the function CPXcopylp is called with a non-empty set of empty constraints. Since this is a valid MIP, it is not unthinkable that somebody tries to load that, and in fact I did. (The reason was an issue from the previously used OSI interface which did not allow empty constraint sets but empty constraints. Note that loading a MIP with an empty set of constraints is accepted by CPLEX now, even though it is basically the same as loading a non-empty set of empty constraints.)

While I don't think we will stumble over this often in the future, I still think it might make sense to add some help for debugging this while we understand the problem. The suggestion which I discussed offline with Florian is to extend cplex_solver_interface.h as follows:

class CplexMatrix {
    // ...
    // ...
    bool empty() const {return coefficients.empty();}

// ...
void CplexSolverInterface::load_problem(const LinearProgram &lp) {
    // ...
    assert(!matrix.empty() || constraints.empty());
    CPX_CALL(CPXcopylp, env, problem, variables.size(), constraints.size(), ...);

The member *coefficients* contains all non-zero entries of the matrix. If it is empty, the matrix has only zero entries. This can either be because there are no constraints or because all constraints are empty. By asserting that either the matrix (i.e., the non-zero coefficients) are not empty or that the constraints are empty, we disallow the case that triggers the CPLEX error. It is not a proper solution because we forbid a valid MIP, but it is currently our best suggestion.
Date User Action Args
2024-01-09 12:03:21clemenssetmessages: + msg11510
2023-09-05 15:06:24maltesetmessages: + msg11345
2023-09-05 15:04:53floriansetmessages: + msg11344
2023-09-05 12:46:36clemenscreate