numpycplexsquare-rootdocplex

docplex does not support square root np.sqrt(x), please suggest an alternative solution


I have implemented docplex model with python, everything goes well: problem formulation, variables, constraints and objective function. The problem raised when I tried to compute Euclidian distance Between two centers of circles, simply numpy can do it np.sqrt((x2-x1)**2 + (y2-y1)**2). please suggest me how to resolve this issue, I could not find quadratic equation for Euclidian distance without using square roots.

Working code attached, were you can see the issue at constraint 1.

from docplex.mp.model import Model
import numpy as np

def packing_cplex(CDA, R, H, items):

  # continuous variables x,y range from -R to +R
  x = [ CDA.continuous_var(name="x{}:".format(i), lb=-R, ub=R)
        for i in range(len(items))]

  y = [ CDA.continuous_var(name="y{}:".format(i), lb=-R, ub=R)
        for i in range(len(items))]
  
  # integer variable z range from 0 to H 
  z = [ CDA.integer_var(name="z{}:".format(i), lb=0, ub=H)
        for i in range(len(items))]
  
  # indicator denotes whether an item is packed into the container
  # i=1, .., n, values 1/0
  d = [ CDA.binary_var(name="d{}:".format(i))
         for i in range(len(items))]

  # sqrt root issue--> np.sqrt((x[i]**2 + y[i]**2))
  # 1.constraint packed items and container radius
  CDA.add_quadratic_constraints(R >= (items[i][0] + (x[i]**2 + y[i]**2)**1 )
                                      for i in range(len(items)))
    
  # 2.constraint packed items and container height
  for i in range(len(items)):                  
    CDA.add( CDA.if_then( d[i]==1, H >= ( items[i][1] + z[i] ) ) )
    
  # objective maximise max∑_(i=0 .. n-1 (π * ri^2 * hi * di)
  CDA.set_objective("max", np.sum([d[i] * np.pi * items[i][0]**2 * items[i][1]
                                                for i in range(len(items))]))

# radius and height of cylinder container  
R, H = 3, 2
volume = np.pi * R**2 * H

# pack, [(ri,hi), ... ([rn,hn]) where ri/hi is radius/height of item
items = [(1,2),(1,2),(1,2),(1,2),(1,2),(1,2),(1,2)]
CDA = Model(name='CDA')
packing_cplex(CDA, R, H, items)
CDA.print_information()
solution = CDA.solve()
utilization = solution._objective / volume
print('Utilization (%) ', utilization)

I expect alternative solution for square roots


Solution

  • If you have non linear functions you can use CPOptimizer within cplex.

    For instance, https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoononlinear.py

    Or with square root:

    from docplex.cp.model import CpoModel
    
    mdl = CpoModel(name='buses')
    nbbus40 = mdl.integer_var(0,1000,name='nbBus40')
    nbbus30 = mdl.integer_var(0,1000,name='nbBus30')
    mdl.add(nbbus40*40 + nbbus30*30 >= 300)
    
    #non linear objective
    mdl.minimize(mdl.power(nbbus40,0.5)*500 + mdl.power(nbbus30,0.5)*400)
    
    msol=mdl.solve()
    
    print(msol[nbbus40]," buses 40 seats")
    
    print(msol[nbbus30]," buses 30 seats") 
    

    And to handle your decimal variables see

    https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoodecimalcpo.py

    from docplex.cp.model import CpoModel
    
    mdl = CpoModel(name='buses')
    
    #now suppose we can book a % of buses not only complete buses
    
    scale=100
    scalenbbus40 = mdl.integer_var(0,1000,name='scalenbBus40')
    scalenbbus30 = mdl.integer_var(0,1000,name='scalenbBus30')
    
    nbbus40= scalenbbus40 / scale
    nbbus30= scalenbbus30 / scale
    
     
    
    mdl.add(nbbus40*40 + nbbus30*30 >= 310)
    mdl.minimize(nbbus40*500 + nbbus30*400)
    
    msol=mdl.solve()
    
    print(msol[scalenbbus40]/scale," buses 40 seats")
    print(msol[scalenbbus30]/scale," buses 30 seats")