Skip to main content

Creating only necessary variables (associated with a constraint)

Answered

Comments

3 comments

  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Selim,

    I would not expect variables that don't appear in a constraint to take random values, I'd expect them to take one of their bounds, or 0 in the case they are not bounded.  But to answer your questions I can think of two approaches to create a model without unused variables.

    The first is to create all variables as you are currently doing, then remove any which don't appear in a constraint.  To do this you can add the following two lines before calling optimize():

    model.update()
    model.remove([v for v in model.getVars() if model.getCol(v).size() == 0])

    The second approach is to extend our tupledict to create a new class which generates variables on the fly:

    import gurobipy as gp

    class td_auto(gp.tupledict):

        def __init__(self, model, *args, name="", **kwargs):
            self.model = model
            self.args = args
            self.name = name
            self.kwargs=kwargs
            super().__init__()

        def __missing__(self, key):
            v = self.model.addVar(*self.args, name=self.name%key, **self.kwargs)
            self.__setitem__(key, v)
            return v

    m = gp.Model()
    x = td_auto(m, vtype=gp.GRB.BINARY, name="z_msea-i%d-f%d-t%d")
    example = gp.quicksum([x[i,2,3] for i in range(10)])

    m.update()
    print(example)
    print(x)

    This does avoid creating unnecessary variables as you requested, but it's more complicated than the first, so in this case I'd suggest that the first approach is used unless it turns out to be too slow and the second approach is faster.

    - Riley

     

     

    0
  • Selim Turkoglu
    First Comment
    First Question

    Thanks for your detailed reply Riley!

    Yes, you are right. Maybe I explained it wrong.

    The problem is that the unused variables take their bounds (in that case 0 or 1 since they are binary). But then I calculate u_msea based on them (which is my essential constraint for cost). So if they take random values (0 or 1) my calculations will be wrong.

    In your first approach, instead of deleting them, I set them to 0. So they are not gonna break any other constraint.

    [model.addConstr(v==0) for v in model.getVars() if model.getCol(v).size() == 0]
    model.update()

    In GAMS, I assume it is easier to create such constraints since it does not need if condition;

    sum (t$((ord(t) >= ord(t) – t_cost(i,j)+1) and (ord(t) <= ord(t))), z_msea(i,f,t)) =l= 1 - y_msea(j,f,t)

    As far as I know, GAMS do not create such variables without using

    if t-t_cost.iloc[i][j]+1>0:

    and ignore adding constraint if variable is not exist (such as z_msea[-1,0,0] etc.).

    My constraint is:

    The weird thing is; if I create mVar instead of Var, the constraint adding process does not give any error for non exist variables (with negative index etc.).

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Selim,

    I can't really comment on GAMS as I've never used it.

    However I do need to comment on your last statement:

    The weird thing is; if I create mVar instead of Var, the constraint adding process does not give any error for non exist variables (with negative index etc.).

    Our Matrix API is built on top of numpy and scipy.  What you are seeing with negative indices is a consequence of numpy indexing.  Eg

    >> import numpy as np
    >> arr = np.array([1,2,3])
    >> arr[-1]
    3
    >> arr[-2]
    2

    So if you have a MVar and use a negative index it won't error, it won't ignore it, it will give you back a variable and if you're unaware of numpy indexing then I'd guess you're creating incorrect constraints.

    - Riley

     

     

     

     

    0

Please sign in to leave a comment.