Forum Discussion

FICO's avatar
FICO
Community Manager
7 years ago

Dynamic array type in Xpress Python interface

Hello,

I query is there any functionality or method in Xpress Python Interface that can be used to resemble the dynamic array type (e.g., "dynamic array(set of range) of mpvar/linctr)") available in Xpress IVE?

Thanks in advance

4 Replies

  • FICO's avatar
    FICO
    Community Manager

    Hello,

    the distinction between array and dynamic array in Mosel disappears when one uses Python, because the array of variables or constraints is created on the spot, based on a set of indices. If your question is about how to create an array with a sparse index set, I would suggest using dictionaries like in the following example:

    import xpress as xp
     
    S = set(['NY', 'AK', 'WA', 'ME'])
     
    cost = {'NY': 4, 'AK': 3, 'WA': 7, 'ME': 11}
     
    x = {i: xp.var() for i in S}
     
    con1 = xp.Sum(x) <= 1
    obj = xp.Sum(cost[i] * x[i] for i in S)
     
    p = xp.problem()
     
    p.addVariable(x)
    p.addConstraint(con1)
    p.setObjective(obj)

    The python interface allows for declaring a dictionary of variables with multiple indices, and provides the shortcut xpress.vars function:

    import xpress as xp
     
    S1 = set(['a', 'b', 'c', 'd'])
    S2 = set(['y', 'z', 't', 'w'])
     
    A = [2,2,4,5]
     
    x = {(i,j): xp.var(ub=A[i]) for i in range(len(A)) for j in S}
     
    x2 = xp.vars(S1, S2, ub=1)

    I hope this helps.

  • FICO's avatar
    FICO
    Community Manager

    Hello Pietro,

    Thank you for your reply and please have a look of the example I gave in this post which I thought will be helpful to clarify my question.

    In my case, I am iterating the optimization and dynamically adding a set of variable X into the objective function as well as adding a set of constraints Constr1. The question is the dimension of variable X and constriant Constr1 is unknown.

    In Xpress IVE, the code snippet looks as follows:

    declaration
    prob:mmproblem
    I=1..NI # Set of index for X 
    iter:integer
     
    X:dynamic array (range,range) of mpvar
    sol_X:dynamic array(range,range) of real
     
    Constr1:dynamic array(set of mpproblem,range,range) of linctr
    Obj:array(set of mpproblem) of linctr
    end-declaration
     
    [#############]
    # Define Optimization
    ...
    [#############]
    iter:=0
    repeat
        [#############]
        # Solve Optimization
        with prob do 
            minimize( Obj(prob) )
        end-do
        # Get Output...
        if iter>=1 then
            forall(i in I) create( sol_X(i,iter) )
            forall(i in I, j in 1..iter) sol_X(i,j):=getsol( X(i,j) )
        end-if
        [#############]
        iter+=1
        forall(i in I) create( X(i,iter) ) # Create a new set of variable
     
        with prob do
            Obj(prob)+=sum(i in I)( X(i,iter) ) # Add the new set of variable into Obj 
     
             if iter>=2 then
                 # Create and define a new set of constraint based on the X which is just solved
                 forall(i in I) create( Constr1(prob,i,iter-1) )  
                 forall(i in I, j in 1..iter-1) Constr1(prob,i,j):= X(i,j)<=sol_X(i,j)
             end-if
        end-do
    until condition
  • FICO's avatar
    FICO
    Community Manager

    Hello Yijun,

    I translated the script you provided to Python, I hope this helps clarify. As you can see in Python you can amend an item to a dictionary at any time as (i,j) in this point is just a key to a dictionary, but we can use it as our index set.

    import xpress as xp
     
    X = {}
    sol_X = {}
     
    # Define optimization problem here
     
    iter = 0
    condition = True
    objective = 0  # Initially, the objective function is null
     
    while condition:
     
        prob.solve()  # Optimization sense has been specified in the
                      # definition of prob
     
        if iter >= 1:
            for i in I:
                for j in range(1, iter + 1):
                    sol_X[i,j] = prob.getSolution(X[i, j])
     
        iter += 1
     
        # Create new variables
        for i in I:
            X[i,iter] = xp.var()
            prob.addVariable(X[i, iter])
     
        # Update objective function
        objective += xp.Sum(X[i,iter] for i in I)
        prob.setObjective(objective)
     
        if iter >= 2:
            prob.addConstraint(X[i, j] <= sol_X[i, j] for i in I for j in range(1, iter))
     
        condition = ...  # update exit condition here

    Using dictionaries for both X and sol_X, while ensuring both have the same set of keys (which you can get with X.keys() and sol_X.keys()).

    I hope this helps. Regards,

    Pietro

  • FICO's avatar
    FICO
    Community Manager

    Many thanks Pietro, very helpful indeed!

    Best wishes,

    Yijun