facility location with OR-tools - python

i'm trying to write facility location MIP solution with OR tools. i translated a Scip solution, from here:
https://scipbook.readthedocs.io/en/latest/flp.html
but im getting a table with only zeros means a no solution..
is the framing of the problem or/and the way I'm using OR-tools here supposed to work?
def or_tools_scip_mine(facilities, customers, time_limit=None):
import numpy
import datetime
if time_limit is None:
time_limit = 1000 * 60 # 1 minute
solver = pywraplp.Solver.CreateSolver('SCIP')
customer_count = range(len(customers))
facility_count = range(len(facilities))
x =[[] for _ in range(len(customers))]
y = []
facility_capacities=[facilities[i][2] for i in facility_count]
facility_setup_costs = [facilities[i][1] for i in facility_count]
demands=[customers[i][1] for i in customer_count]
c=dist_matrix(facilities,customers)
for j in facility_count:
y.append(solver.BoolVar("y(%s)" % j))
for i in customer_count:
x[i].append(solver.BoolVar("x(%s,%s)" % (i, j)))
for i in customer_count:
solver.Add(solver.Sum(x[i][j] for j in facility_count) <= demands[i])#, "Demand(%s)" % i
for j in facility_count:
solver.Add(solver.Sum(x[i][j] for i in customer_count) <= facility_capacities[j] * y[j])#, "Capacity(%s)" % j)
for j in facility_count:
for i in customer_count:
solver.Add(x[i][j] <= demands[i] * y[j])
a=solver.Sum((facility_setup_costs[j] * y[j] for j in facility_count))
b=solver.Sum((c[i, j] * x[i][j] for i in customer_count for j in facility_count))
func_=solver.Sum([a,b])
solver.Minimize(func_)
solver.set_time_limit(time_limit)
result_status = solver.Solve()
print(result_status)
val = solver.Objective().Value()
x_val = [[] for _ in range(len(customers))]
solution = []
for j in range(len(facilities)):
for i in range(len(customers)):
x_val[i].append(int(x[i][j].solution_value()))
x_val = numpy.array(x_val)
for j in range(len(customers)):
solution.append(numpy.where(x_val[:, j] == 1)[0][0])
return val, solution
the Error:
solution.append(numpy.where(x_val[:, j] == 1)[0][0])
IndexError: index 0 is out of bounds for axis 0 with size 0

Add solver.EnableOutput() after CreateSolver line in your code. This will give you more insight what is going on.
Below are the helping solver parameters and status. If you need more
details click on this documentation link
print('Number of variables = %d' % solver.NumVariables())
print('Number of constraints = %d' % solver.NumConstraints())
print('The Optimal Objective value =',solver.Objective().Value())
print('Total Iterations:',solver.iterations())
print('Total Nodes:',solver.nodes())
print('Total number of Variables:',solver.NumVariables())
print(pywraplp.Solver.FEASIBLE)
print(pywraplp.Solver.MODEL_INVALID)
print(pywraplp.Solver.OPTIMAL)
print(pywraplp.Solver.INFEASIBLE)
print(pywraplp.Solver.UNBOUNDED)

Related

how to fix 'gurobipy.LinExpr' object is not iterable

I am having some issues with my Linear Program Model in gurobi. I am quite new to programming, and don't really understand what the error is. It comes up as 'gurobipy.LinExpr' object is not iterable with my Objective Function. This is my code currently
from gurobipy import *
IDtoLVC = [
[40.4,61.2,69.3,60.9,86.8,13.1,70.5,69.7],
[59.5,5.6,45.8,85.6,62.6,46.9,77.8,29.7],
[27.2,62.7,26.9,30.1,30.3,62.6,11.7,45.0]
]
CCDPop = [2180,4887,2174,4244,2444,2156,2433,2096,4148,3636,4935,3160,4153,2058,4614,3862,4588,4264,2559,2770,3964,2333,3681,4786,3256]
CCDtoLVC = [
[48.8,0,0,0,0,19.2,0,0],
[46.3,0,0,0,0,8.3,0,0],
[0,37.2,0,0,0,17.7,0,0],
[0,14.0,0,0,0,0,0,36.1],
[0,18.4,0,0,0,0,0,42.2],
[35.5,0,0,0,0,20.1,0,0],
[33.3,0,0,0,0,6.8,0,0],
[24.9,0,0,0,0,18.7,0,0],
[0,17.4,0,0,0,30.8,0,0],
[0,12.4,0,0,0,0,0,20.1],
[23.5,0,0,31.6,0,0,0,0],
[6.9,0,0,28.3,0,0,0,0],
[17.9,0,27.7,0,0,0,0,0],
[0,24.4,20.3,0,0,0,0,16.4],
[0,28.9,26.1,0,0,0,0,11.5],
[28.3,0,0,12.0,0,0,0,0],
[13.0,0,0,14.4,0,0,24.9,0],
[13.1,0,26.7,31.0,0,0,24.0,0],
[0,0,6.5,0,17.1,0,0,25.4],
[0,0,20.3,0,16.4,0,0,23.3],
[0,0,0,15.1,0,0,35.3,0],
[27.2,0,0,14.1,0,0,7.8,0],
[0,0,25.6,0,25.0,0,14.7,0],
[0,0,26.7,0,12.0,0,0,0],
[0,0,30.2,0,15.5,0,0,0]
]
LVCCost = [194, 105, 184]
# Sets
I = range(3) # no. of IDs
J = range(8) # no. of LVCs
K = range(25) # no. of CCDs
T = range(6) # length of time
# Model
m = Model('Vaccine Distribution')
X = { (i,j,t): m.addVar() for i in I for j in J for t in T }
Y = { (j,k,t): m.addVar() for j in J for k in K for t in T }
m.setObjective((0.20 * quicksum(quicksum(quicksum(X[i,j,t] * IDtoLVC[i][j] for i in I for j in J for t in T)))) +
(quicksum(quicksum(quicksum(Y[j,k,t] * CCDtoLVC[k][j] for j in J for k in K for t in T)))) +
(quicksum(quicksum(quicksum(X[i,j,t] * LVCCost[i] for i in I for j in J for t in T)))),
GRB.MINIMIZE)
m.optimize()
You don't need three nested calls to quicksum in order to express a triple sum. Instead, you just call quicksum once:
sum1 = quicksum(X[i,j,t] * IDtoLVC[i][j] for i in I for j in J for t in T)
sum2 = quicksum(Y[j,k,t] * CCDtoLVC[k][j] for j in J for k in K for t in T)
sum3 = quicksum(X[i,j,t] * LVCCost[i] for i in I for j in J for t in T)
m.setObjective(0.20 * sum1 + sum2 + sum3, GRB.MINIMIZE)

How to code subtour constraint in cplex python

I am quite new in python cplex. I tried to model VRP and needed to eliminate subtours for feasible solution, but I cannot do that with the following code:
from docplex.mp.model import Model
import numpy as np
n = 10
Q = 20
N = [i for i in range(1, n+1)]
V = [0] + N
rnd = np.random
rnd.seed(0)
q = {i: rnd.randint(1, 10) for i in N}
loc_x = rnd.rand(len(V))*200
loc_y = rnd.rand(len(V))*100
A = [(i, j) for i in V for j in V if i != j]
c = {(i, j): np.hypot(loc_x[i]-loc_x[j], loc_y[i]-loc_y[j]) for i, j in A}
mdl = Model('CVRP')
x = mdl.binary_var_dict(A, name='x')
u = mdl.continuous_var_dict(N, lb=0, name='u')
mdl.minimize(mdl.sum(c[i, j]*x[i, j] for i, j in A))
mdl.add_constraints(mdl.sum(x[i, j] for j in V if j != i) == 1 for i in N)
mdl.add_constraints(mdl.sum(x[i, j] for i in V if i != j) == 1 for j in N)
mdl.add_constraints(mdl.add(u[i] - u[j] + n*(x[i,j]) <= n - 1 for i,j in N if i!=j))
mdl.parameters.timelimit = 15
solution = mdl.solve()
print(solution)
When I run it, I get the following error:
File "C:\Users\user.spyder-py3\TSP\cplexExp.py", line 25, in
mdl.add_constraints(mdl.add(u[i] - u[j] + n*(x[i,j]) <= n - 1 for i,j in N if i!=j))
TypeError: cannot unpack non-iterable int object
I really appreciate for any help. thanks!!
Thanks guys, the problem is that N is one dimensional array, but I considered it as two dimensional by using i,j in N. I figured that out. By the way, do you know any good resource to learn CPLEX Python? I am new and do not know where to start. Thanks!!
Have a look at the Docplex examples here:
https://github.com/IBMDecisionOptimization/docplex-examples

Need help speeding up my solution for Project Euler #650

So Ive been working on project Euler problem #650, and it generates the correct answer for smaller values, but they are looking for the solution to values up to 20,000. At the speed my code is currently running that will take like a billion years. Any tips for improving this code and making it more efficient/faster would be appreciated. Here is a link to the problem: https://projecteuler.net/problem=650
and the code
from scipy.special import comb
import math
import time
t0 = time.time()
def B(x):
#takes product of binomial coefficients
product = 1
for i in range(x + 1):
product *= comb(x, i, exact=True)
return product
def D(y):
#Sums all divisors of the product of binom. coefficients
x = B(y)
summation = []
for i in range(1, int(math.sqrt(x)) + 1):
if x % i == 0:
summation.append(i)
summation.append(x // i)
summation = list(dict.fromkeys(summation))
return sum(summation)
def S(z):
"""sums up all the sums of divisors of the product of the binomial
coefficients"""
sigma = []
for i in range(1, z + 1):
sigma.append(D(i))
return sum(sigma)
print(S(20000))
t1 = time.time()
total = t1 - t0
print(total)
me too
but you can try this
from math import factorial
def n_choose_k(n, k):
if k == 0:
return 1
else:
return factorial(n)//((factorial(k))*factorial(n-k))
def B(n):
prods = []
for k in range(0, n):
prods.append(n_choose_k(n, k))

What do I get from Queue.get() (Python)

Overall question: How do I know what I am getting from a Queue object when I call Queue.get()? How do I sort it, or identify it? Can you get specific items from the Queue and leave others?
Context:
I wanted to learn a little about multi-proccessing (threading?) to make solving a matrix equation more efficient.
To illustrate, below is my working code for solving the matrix equation Ax = b without taking advantage of multiple cores. The solution is [1,1,1].
def jacobi(A, b, x_k):
N = len(x_k)
x_kp1 = np.copy(x_k)
E_rel = 1
iteration = 0
if (N != A.shape[0] or N != A.shape[1]):
raise ValueError('Matrix/vector dimensions do not match.')
while E_rel > ((10**(-14)) * (N**(1/2))):
for i in range(N):
sum = 0
for j in range(N):
if j != i:
sum = sum + A[i,j] * x_k[j]
x_kp1[i] =(1 / A[i,i]) * (b[i] - sum)
E_rel = 0
for n in range(N):
E_rel = E_rel + abs(x_kp1[n] - x_k[n]) / ((abs(x_kp1[n]) + abs(x_k[n])) / 2)
iteration += 1
# print("relative error for this iteration:", E_rel)
if iteration < 11:
print("iteration ", iteration, ":", x_kp1)
x_k = np.copy(x_kp1)
return x_kp1
if __name__ == '__main__':
A = np.matrix([[12.,7,3],[1,5,1],[2,7,-11]])
b = np.array([22.,7,-2])
x = np.array([1.,2,1])
print("Jacobi Method:")
x_1 = jacobi(A, b, x)
Ok, so I wanted to convert this code following this nice example: https://p16.praetorian.com/blog/multi-core-and-distributed-programming-in-python
So I got some code that runs and converges to the correct solution in the same number of iterations! That's really great, but what is the guarantee that this happens? It seems like Queue.get() just grabs whatever result from whatever process finished first (or last?). I was actually very surprised when my code ran, as I expected
for i in range(N):
x_update[i] = q.get(True)
to jumble up the elements of the vector.
Here is my code updated using the multi-processing library:
import numpy as np
import multiprocessing as mu
np.set_printoptions(precision=15)
def Jacobi_step(index, initial_vector, q):
N = len(initial_vector)
sum = 0
for j in range(N):
if j != i:
sum = sum + A[i, j] * initial_vector[j]
# this result is the updated element at given index of our solution vector.
q.put((1 / A[index, index]) * (b[index] - sum))
if __name__ == '__main__':
A = np.matrix([[12.,7,3],[1,5,1],[2,7,-11]])
b = np.array([22.,7,-2])
x = np.array([1.,2,1])
q = mu.Queue()
N = len(x)
x_update = np.copy(x)
p = []
error = 1
iteration = 0
while error > ((10**(-14)) * (N**(1/2))):
# assign a process to each element in the vector x,
# update one element with a single Jacobi step
for i in range(N):
process = mu.Process(target=Jacobi_step(i, x, q))
p.append(process)
process.start()
# fill in the updated vector with each new element aquired by the last step
for i in range(N):
x_update[i] = q.get(True)
# check for convergence
error = 0
for n in range(N):
error = error + abs(x_update[n] - x[n]) / ((abs(x_update[n]) + abs(x[n])) / 2)
p[i].join()
x = np.copy(x_update)
iteration += 1
print("iteration ", iteration, ":", x)
del p[:]
A Queue is first-in-first-out which means the first element inserted is the first element retrieved, in order of insertion.
Since you have no way to control that, I suggest you insert tuples in the Queue, containing the value and some identifying object that can be used to sort/relate to the original computation.
result = (1 / A[index, index]) * (b[index] - sum)
q.put((index, result))
This example puts the index in the Queue together with the result, so that when you .get() later you get the index too and use it to know which computation this is for:
i, x_i = q.get(True)
x_update[i] = x_i
Or something like that.

Optimizing Python Code for Competitions

I'm new to Python, and I'm trying to get familiar with it by solving problems on CodeChef. I'm attempting to solve the Easy problem Number Game. The issue is that the execution time is too long for my code.
I have translated the Python solution I wrote into C++, and the submission was accepted, so I know I have a correct answer, and it's just off by a constant multiple.
Is it possible to solve this problem in Python 3 in the allotted time? Can you help me speed up my code to accomplish this?
import time
def getStartValues(A, M):
startVals = [0]*M
b = [0]*len(A)
for i in range(len(A)-1):
b[i+1] = (10*b[i] + A[i]) % M
f = 0
power = 1
for i in range(len(A)-1,0,-1):
startVals[(b[i]*power + f) % M] += 1
f = (A[i]*power + f) % M
power = (power*10 % M)
startVals[f] += 1
return startVals, power
def checkValues(i, startVals, M, powNm1, checked, chklst):
if checked[i] == 1:
return startVals[i]
q = [i]
chk = [0]*M
chk[i] = 1
while len(q) > 0:
val = q.pop(0)
for j in chklst:
val2 = (powNm1*val + j) % M
if checked[val2] > 0:
checked[i] = 1
return startVals[i]
elif chk[val2] == 0:
q.append(val2)
chk[val2] = 1
return 0
def compute(A, M):
startVals, power = getStartValues(A, M)
checked = [0]*M
checked[0] = 1
chklst = [j for j in range(M) if startVals[j] > 0]
total = 0
for i in chklst:
c = checkValues(i, startVals, M, power, checked, chklst)
total += c
return total
start = time.time()
file = open('numbgame.in', 'r')
#T = int(input())
T = int(file.readline())
for i in range(T):
#A, M = input().split()
A, M = file.readline().split()
A = list(map(int,A))
M = int(M)
print(compute(A, M))
tDiff = time.time() - start
print('Total time: %s' % tDiff)
Note that I have modified the code to read from a file and to display execution time, as a convenience, and some small alterations are needed before it can be submitted.
getStartValues takes in the (big) list of digits of the input A and the (small) integer M and returns the values modulo M that can be generated from A by removing a single digit.
checkValues takes an index i, the list startValues, the integer M, the integer powNm1 (which is the value 10^(n-1) mod M, where n is the number of digits in A, a list checked that keeps track of whether a value has already been determined to be solvable, and the list chklst (which contains the indices i such that startValues[i] > 0).
The majority of the time is spent in the function getStartValues, since A could be up to 10^6 digits long. On my desktop, the getStartValues function call takes about 1.2s, while the rest of the compute function takes about 0.04s (for worst case inputs).

Categories