Skip to main content

How to define that m successive variables should be the same

Answered

Comments

5 comments

  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Huib,

    The question you have posed doesn't need to be posed as an optimization problem.  If you have the expression

    K * m + R == a + b

    and all values are non-negative integers with R < m then K, R can be calculated as

    K = floor( (a+b)/m)  # or (a+b)//m in Python
    R = a+b - K*m

    The sequence that you're wanting to print can be achieved with

    arr = ["B"]*(a+b+1)
    arr[::2*m] = ["A"]*len(arr[::2*m])
    arr[1::2*m] = ["A"]*len(arr[1::2*m])
    print(arr)

    You mentioned that a player wins when they reach n points, but you neither use the value of n inside your function, or explain how it relates to the outputs you want to see.

    Can you please clarify?

    - Riley

    0
  • Huib Meulenbelt
    Gurobi-versary
    Curious
    Conversationalist

    Ah yes, thank you for taking a look at it. So, I was making it way too difficult. 

    You're right, I excluded that from my question to simplify the project. But a player wins when he reaches points or when there is a tie (both players score n - 1) and the player wins two consecutive points hereafter. In the case of a tie, the serve changes per point. How would you include these rules into your array?

     

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Huib,

    I think we're still missing a part of the question here.

    Let's say n = 5, a = 0, b = 0.  So a game of "first to 5" is about to start.

    What do you want to do with this information?  If there was a question such as "how many different ways can player A win, given the current scores" then this would make more sense, but at the moment it is not clear what you are wanting to produce and how the value of n affects this.

    Maybe we can use n = 5, a = 0, b = 0 as an example.  What are the exact outputs you would like to see in this case?

    - Riley

    0
  • Huib Meulenbelt
    Gurobi-versary
    Curious
    Conversationalist

    Hi Riley,

    In the end that's exactly what I want to do; get all the different ways a score can be achieved. To be precise, I want all the ways A (B) can score a (b) points on his own serve. Below is my script where the output is all the different paths:

    def get_score_on_serve_sequences(a: int, b: int, m: int, n: int, server: str, receiver: str) -> list:
    sequences = []

    model = create_model()
    served = get_serve_sequence(a=a, b=b, m=m, n=n, server=server, receiver=receiver)
    scored = [model.addVar(vtype=GRB.BINARY, name=f'serve_{idx+1}') for idx, _ in enumerate(served)]

    if server == 'A':
    model.addConstr(gurobi.quicksum([serve * score for serve, score in zip(served, scored)]) == a)
    else:
    model.addConstr(gurobi.quicksum([serve * score for serve, score in zip(served, scored)]) == b)
    model.addConstrs((scored[_] == 0 for _, serve in enumerate(served) if serve == 0))

    model.optimize()
    if model.Status == GRB.OPTIMAL:
    solutions = model.SolCount

    for solution in range(0, solutions):
    model.setParam(GRB.Param.SolutionNumber, solution)
    sequences.append([int(score.Xn) for score in scored])

    return sequences

    However, I want to rewrite my function get_serve_sequence(). I used your earlier suggestion to write the following:

    def get_serve_sequence(a: int, b: int, m: int, n: int, server: str, receiver: str) -> list:
    sequence = [receiver] * (a + b + 1)
    sequence[::2 * m] = [server] * len(sequence[::2 * m])
    sequence[1::2 * m] = [server] * len(sequence[1::2 * m])

    return sequence

    However, now I want to also include a tie. When a tie is reached at score n - 1, n - 1, the server changes per turn.

    So the output of get_serve_sequence(a=14, b=12, m=2, n=11, server='A', receiver='B') should be 

    ['A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'B', 'A', 'B', 'A', 'B'] 

     

     

     

     

     

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Huib,

    I think something like this would work.  Some of the numbers may need tweaking as I haven't tested it, but this is the general idea.

    def get_serve_sequence(a: int, b: int, m: int, n: int, server: str, receiver: str) -> list:
    sequence
    = [receiver] * (a + b + 1)
    sequence[::2 * m] = [server] * len(sequence[::2 * m])
    sequence[1::2 * m] = [server] * len(sequence[1::2 * m])
    if a + b > 2*(n-1):
    sequence[:2*(n-1)-a-b] = [receiver] * (a+b - 2*(n-1))
           sequence[2*(n-1)::2] = [server] * sequence[2*(n-1)::2]
      return sequence


    Unfortunately, mixed integer linear programming is really not the appropriate solution to "get all the different ways a score can be achieved".  This is either solved directly with binomial coefficients, or with dynamic programming.

    Your model doesn't have an objective so the solver will stop at the first feasible solution, and model.SolCount will always be 1.  You could force it to find multiple solutions using SolutionPools, but then you need to tell it how many solutions to find - which is the problem you're trying to solve.

    - Riley

    0

Please sign in to leave a comment.