linopy
linopy copied to clipboard
Documentation on model debugging
I have been unable to find documentation specific to diagnosing issues with models.
I have found a few useful helper functions, such as model.variables.get_name_by_label() which returns the mapping from the numeric variable number found in the LP file to the variable name of the Python object.
Are there any other useful functions I should know about to help diagnose problems with an LP formulated in linopy (collating ideas here for a section in the documentation)?
Some ideas:
- Force writing out full variable names to LP generation to aid debugging
- Tutorial to demonstrate visualisation of the constraints, matrix, coefficient ranges etc.
Good point! This is one of the most important things on the list of missing features. In meanwhile, if you use gurobi, you can use the function
m.compute_set_of_infeasible_constraints()
in case you ran into non-feasibility with the gurobi solver. But the inspection of a subset of constraints still remains mediocre. I put that on my list. Ideally, I would like people to not have to look into the LP file in case of infeasibilities, as they can be very long. So in the first step, I would focus on the data inspection of the linopy model.
One incredibly hacky solution is to post-process the LP file with the constraint and variable names. I'm not proud of this, but it got the job done so I can compare the LP file of a test model from the original GNU MathProg implementation and the linopy. Perhaps this is a special case - porting a file, but inspection of a (small) LP file is very useful because it's one common file format almost all algebraic modelling languages can produce.
import re
<build your linopy.Model ``m``>
variable = re.compile('x[0-9]+')
constraint = re.compile('c[0-9]+')
with open('annotated_file.lp', 'w') as annotated:
with open('original.lp', 'r') as raw_lp_file:
for line in raw_lp_file:
vars = variable.findall(line)
cons = constraint.findall(line)
for con in cons:
label = int(con[1:])
name = m.constraints.get_name_by_label(label)
line = f"{name}:\n"
for var in vars:
label = int(var[1:])
name = m.variables.get_name_by_label(label)
line = line.replace(var, name)
annotated.write(line)
Interesting workaround :) However that would not work for indexed variables / constraints, as far as I can see. It would only insert the name. But given your thoughts, we can definitely think about introducing (optional) annotations to the LP file.