Skip to main content

Performance of MVar vs. list of Var

Answered

Comments

4 comments

  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Lukas,

    Getting fast build times with MVars requires using methods which work efficiently with MVars.  Sometimes figuring out what this is requires a bit of experimentation.

    If I replace

    m1.setObjective(x1.sum(), GRB.MAXIMIZE)

    with

    m.setObjective(x1@np.ones(timesteps), GRB.MAXIMIZE)

    then I get the MVar code running about 4 times faster.

    You can accurately benchmark with the following code snippet (which accounts for background noise on your machine that affects execution time):

    import numpy as np
    import timeit

    setup = """
    import gurobipy as gp
    from gurobipy import GRB
    import numpy as np
    timesteps = 1000
    m = gp.Model()
    """


    statement1= """
    x = m.addMVar(timesteps, lb=0, ub=1, vtype=GRB.CONTINUOUS, name='load')
    m.setObjective(x@np.ones(timesteps), GRB.MAXIMIZE)
    """

    statement2= """
    x = {
        i:m.addVar(lb=0, ub=1, vtype=GRB.CONTINUOUS, name=f'load_{i}')
        for i in range(timesteps)
    }
    m.setObjective(np.sum([x[i] for i in range(timesteps)]), GRB.MAXIMIZE)
    """

    factor = np.divide(
        np.min(timeit.repeat(stmt=statement1, setup=setup, number=1, repeat=1000)),
        np.min(timeit.repeat(stmt=statement2, setup=setup, number=1, repeat=1000)),
    )

    print(f"MVars takes {factor:.2%} of the time.")

    - Riley

    0
  • Lukas Meier
    Gurobi-versary
    First Comment
    First Question

    Hey Riley, thanks for the answer.

    I tried using your code as well as @np.ones instead of np.sum in my own code.
    I noticed that while @np.ones is in fact faster, at a low number of timesteps and/or repeats lists of Vars still perform better. It's mainly the 1000 repeats that make MVars faster.

    I'm not familiar with how the repeat function is handled, could the time difference occur at initialization, meaning MVar initializes slower, which gets less significant the more often you repeat the segment?

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hey Lukas,

    at a low number of timesteps... lists of Vars still perform better

    It does appear to be the case.  I guess there is a fixed cost in performing the matrix multiplication which is a more significant portion of the time when timestamps is small

    at a low number of ... repeats lists of Vars still perform better

    I don't think this is true.  The repeats=1000 argument in the timeit.repeat function just tells the timeit module to perform the statement 1000 times, and it will return a list of 1000 individual times.  The result becomes more statistically robust as the number of repeats increases, but the actual times should be similar.

    - Riley

     

    0
  • Lukas Meier
    Gurobi-versary
    First Comment
    First Question

    I probably should have tested more cases, but setting repeat to 1 results in "MVars takes 908.07% of the time.", for anything above 1 MVars is significantly faster. At 2 it's 14.58%, starting at 10 it's about 10%. Like you said there probably is some sort of fixed duration when executing the statement for the first time, for my complex model I'll work with lists of vars first and see if I can restructure things afterwards.

    Best regards,
    Lukas

    0

Please sign in to leave a comment.