Search code examples
cplexdocplex

Logical formula in docplex


Given the following formula

enter image description here

with the table below encode the relationship of x_0, x_1 and r for Objective 2':

enter image description here

For objective 2, we can code it as following with Docplex, where we have either 0 or 1 for priority p.

CPriorityInFreight = mdl.binary_var_matrix(catPriorities, freights, name='CPriorityInFreight')
FreightMixture = mdl.binary_var_dict(freights, name='FreightMixture')
for p in catPriorities:
    for f in freights:
        # CPriorityInFreight[c, f] = 1 <-> priority c is in freight f
        CPriorityInFreight[p, f] = (
                    1 <= mdl.sum(Assignment[o, f] for o in orders if get_order(o).CategoryPriority == p))

for f in freights:
    # sums == 2 <-> we have both cat 0 and cat 1
    FreightMixture[f] = (2 == mdl.sum(CPriorityInFreight[c, f] for c in catPriorities))


o2 = mdl.sum(FreightMixture[f] for f in freights)

In Objective 2', we now have the following code for decision variable declaration (with FreightMixture containing value 0,1,2) and first formula

CPriorityInFreight = mdl.binary_var_matrix(catPriorities, freights, name='CPriorityInFreight')
FreightMixture = mdl.integer_var_dict(freights, name='FreightMixture')
for p in catPriorities:
    for f in freights:
        # CPriorityInFreight[c, f] = 1 <-> priority c is in freight f
        CPriorityInFreight[p, f] = (
                    1 <= mdl.sum(Assignment[o, f] for o in orders if get_order(o).CategoryPriority == p))

But how do we translate these relationship on second formula of Objective 2' into Docplex? (I am ok with OPL as I can understand it too)

(Of course if there are simpler way to achieve semantically equivalent formulas with Objective 2', feel free to suggest)


Solution

  • Both in docplex and OPL you can use logical constraints.

    In OPL for instance:

    int R[0..1][0..1]=[[0,0],[2,1]];
    
    dvar boolean x;
    dvar boolean y;
    
    dvar int obj;
    
    maximize obj;
    subject to
    {
      forall(i in 0..1,j in 0..1) (x==i) && (y==j) => (obj==R[i][j]);
    }
    

    that is generic to any R table and gives

    obj = 2;
    x = 1;
    y = 0;
    

    You can write less logical constraints if you adapt to the table. In your example

    int R[0..1][0..1]=[[0,0],[2,1]];
    
    dvar boolean x;
    dvar boolean y;
    
    dvar int obj;
    
    maximize obj;
    subject to
    {
      
      
      (x==0) => (obj==0);
      (x==1) => (obj==2-y);
      
    }
    

    works fine

    And the equivalent code in python docplex

    from docplex.mp.model import Model
    
    mdl = Model(name='logical')
    
    x = mdl.binary_var(name='x')
    y = mdl.binary_var(name='y')
    obj= mdl.integer_var(name='obj')
    
    R=[[0,0],[2,1]]
    
    
    decisionVars=[x,y,obj]
    
    for i in range(0,2):
        for j in range(0,2):
            mdl.add_constraint(mdl.if_then((x==i)+(y==j)==2,(obj==R[i][j])))
                
    
    mdl.maximize(obj)
    
    mdl.solve()
    
    for v in decisionVars:
        print(v.name," = ",int(v.solution_value))
    

    that gives

    x  =  1
    y  =  0
    obj  =  2