OR-Tools: Obtaining every optimal solution - python
I am using OR-Tools to solve a MIP with SCIP. OR-Tools returns optimal values for continuous and integer (binary) variables of my problem.
When I then fix the binary variables of this MIP to the optimal values returned by OR-Tools (for the MIP) and I solve the corresponding LP with GLOP, OR-Tools returns new values for the optimal values of the continuous variables.
My understanding is that the initial problem does not have a unique solution (in terms of optimal values of variables).
So my question is: How can I make OR-tools return every optimal solution, and not just one?
Please find the code bellow:
from ortools.linear_solver import pywraplp
#Fixed parameters
K = 4
L = 3
J = {}
J[0,0] = 3
J[0,1] = 2
J[0,2] = 1
J[1,0] = 3
J[1,1] = 1
J[1,2] = 2
J[2,0] = 2
J[2,1] = 2
J[2,2] = 2
J[3,0] = 1
J[3,1] = 1
J[3,2] = 1
S_up = {}
S_lw = {}
U = {}
S_up[0,0,0] = 20
S_up[0,1,0] = 40
S_up[0,2,0] = 60
S_up[0,0,1] = 15
S_up[0,1,1] = 40
S_up[0,0,2] = 50
S_lw[0,0,0] = 0
S_lw[0,1,0] = 21
S_lw[0,2,0] = 41
S_lw[0,0,1] = 5
S_lw[0,1,1] = 16
S_lw[0,0,2] = 10
U[0,0,0] = 5
U[0,1,0] = 7
U[0,2,0] = 8
U[0,0,1] = 2
U[0,1,1] = 5
U[0,0,2] = 6
S_up[1,0,0] = 25
S_up[1,1,0] = 35
S_up[1,2,0] = 50
S_up[1,0,1] = 30
S_up[1,0,2] = 30
S_up[1,1,2] = 30
S_lw[1,0,0] = 5
S_lw[1,1,0] = 26
S_lw[1,2,0] = 36
S_lw[1,0,1] = 10
S_lw[1,0,2] = 5
S_lw[1,1,2] = 31
U[1,0,0] = 6
U[1,1,0] = 8
U[1,2,0] = 9
U[1,0,1] = 3
U[1,0,2] = 5
U[1,1,2] = 7
S_up[2,0,0] = 40
S_up[2,1,0] = 60
S_up[2,0,1] = 60
S_up[2,1,1] = 80
S_up[2,0,2] = 40
S_up[2,1,2] = 60
S_lw[2,0,0] = 5
S_lw[2,1,0] = 41
S_lw[2,0,1] = 5
S_lw[2,1,1] = 61
S_lw[2,0,2] = 5
S_lw[2,1,2] = 41
U[2,0,0] = 5
U[2,1,0] = 6
U[2,0,1] = 4
U[2,1,1] = 5
U[2,0,2] = 5
U[2,1,2] = 6
S_up[3,0,0] = 100
S_up[3,0,1] = 90
S_up[3,0,2] = 90
S_lw[3,0,0] = 0
S_lw[3,0,1] = 0
S_lw[3,0,2] = 0
U[3,0,0] = 5
U[3,0,1] = 4
U[3,0,2] = 5
D = [100,100,90]
P = [50,30,20]
Q_up = [0,1,1,1]
Q_lw = [0,0,0.1,0]
#Declare MIP solver
solver_mip = pywraplp.Solver.CreateSolver('SCIP')
#Define variables
infinity = solver_mip.infinity()
y = {}
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
y[k, j, l] = solver_mip.NumVar(0, infinity, '')
x = {}
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
x[k, j, l] = solver_mip.IntVar(0, 1, '')
print('Number of variables =', solver_mip.NumVariables())
#Define constraints
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
solver_mip.Add(y[k, j, l] <= x[k, j, l]*S_up[k, j, l])
solver_mip.Add(x[k, j, l]*S_lw[k, j, l] <= y[k, j, l])
for k in range(K):
for l in range(L):
solver_mip.Add(sum([x[k, j, l] for j in range(J[k,l])]) <= 1)
for l in range(L):
solver_mip.Add(sum([sum([y[k, j, l] for j in range(J[k,l])]) for k in range(K)]) == D[l])
for k in range(K):
solver_mip.Add(sum([sum([y[k, j, l]*P[l] for j in range(J[k,l])]) for l in range(L)]) <= Q_up[k]*sum([D[l]*P[l] for l in range(L)]))
solver_mip.Add(Q_lw[k]*sum([D[l]*P[l] for l in range(L)]) <= sum([sum([y[k, j, l]*P[l] for j in range(J[k,l])]) for l in range(L)]))
print('Number of constraints =', solver_mip.NumConstraints())
#Define objective
solver_mip.Minimize(sum([sum([sum([y[k,j,l]*U[k,j,l] for j in range(J[k,l])]) for k in range(K)]) for l in range(L)]))
#Call MIP solver
status = solver_mip.Solve()
#Display solution
if status == pywraplp.Solver.OPTIMAL:
print('Solution of MIP:')
print('Objective value =', solver_mip.Objective().Value())
x_opt = {} #store optimal values of binary variable
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
x_opt[k,j,l] = x[k,j,l].solution_value()
if x[k,j,l].solution_value() == 1:
print('y[',k,',',j,',',l,']=',y[k,j,l].solution_value())
else:
print('The problem does not have an optimal solution.')
print('\nAdvanced usage:')
print('Problem solved in %f milliseconds' % solver_mip.wall_time())
print('Problem solved in %d iterations' % solver_mip.iterations())
print('Problem solved in %d branch-and-bound nodes' % solver_mip.nodes())
#Primal problem with fixed binary variables to optimal value becomes a LP
#Declare LP solver
solver_lp = pywraplp.Solver.CreateSolver('GLOP')
##Quantity variable
y_fixed_binary = {}
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
y_fixed_binary[k, j, l] = solver_lp.NumVar(0, infinity, '')
#Define constraints
##Quantity should be in bounds defined by reinsurer
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
solver_lp.Add(y_fixed_binary[k, j, l] <= x_opt[k, j, l]*S_up[k, j, l])
solver_lp.Add(x_opt[k, j, l]*S_lw[k, j, l] <= y_fixed_binary[k, j, l])
for l in range(L):
solver_lp.Add(sum([sum([y_fixed_binary[k, j, l] for j in range(J[k,l])]) for k in range(K)]) == D[l])
for k in range(K):
solver_lp.Add(sum([sum([y_fixed_binary[k, j, l]*P[l] for j in range(J[k,l])]) for l in range(L)]) <= Q_up[k]*sum([D[l]*P[l] for l in range(L)]))
solver_lp.Add(Q_lw[k]*sum([D[l]*P[l] for l in range(L)]) <= sum([sum([y_fixed_binary[k ,j ,l]*P[l] for j in range(J[k,l])]) for l in range(L)]))
#Define objective
solver_lp.Minimize(sum([sum([sum([y_fixed_binary[k,j,l]*U[k,j,l] for j in range(J[k,l])]) for k in range(K)]) for l in range(L)]))
status = solver_lp.Solve()
if status == pywraplp.Solver.OPTIMAL:
print('Solution of LP:')
print('Objective value =', solver_mip.Objective().Value())
for k in range(K):
for l in range(L):
for j in range(J[k,l]):
if x_opt[k,j,l] == 1:
print('y[',k,',',j,',',l,']=',y_fixed_binary[k,j,l].solution_value())
else:
print('The LP does not have an optimal solution.')
print('Advanced usage:')
print('Problem solved in %f milliseconds' % solver_lp.wall_time())
And the output is
Solution of MIP:
Objective value = 1280.0
y[ 1 , 0 , 1 ]= 30.0
y[ 2 , 0 , 0 ]= 13.999999999999998
y[ 2 , 0 , 1 ]= 5.0
y[ 2 , 0 , 2 ]= 5.0
y[ 3 , 0 , 0 ]= 86.0
y[ 3 , 0 , 1 ]= 55.0
y[ 3 , 0 , 2 ]= 85.0
Solution of LP:
Objective value = 1280.0
y[ 1 , 0 , 1 ]= 30.0
y[ 2 , 0 , 0 ]= 40.0
y[ 2 , 0 , 1 ]= 60.0
y[ 2 , 0 , 2 ]= 40.0
y[ 3 , 0 , 0 ]= 60.0
y[ 3 , 0 , 1 ]= 0.0
y[ 3 , 0 , 2 ]= 50.0
You can get all optimal solutions by calling NextSolution() after the first Solve()
Related
Print nxn grid clockwise and print the sum of the diagonal elements
Example if n = 5 it should print 21 22 23 24 25 20 7 8 9 10 19 6 1 2 11 18 5 4 3 12 17 16 15 14 13 Sum = 21+7+1+3+13+17+5+9+25 = 101 Here is my code dim=5 result= n = 1 for in range(2,dim,2): for i in range(4): n+=k result+=n print(result)
Here is what I made def spiral(n): # Initialize the values m = [[0]*n for _ in" "*n] # Define a list of list of n dim d = n v = n*n # values y = 0 # cord of y x = n # cord of x while d > 0: for _ in" "*d: # Equivalent to <=> for i in range(d) x -= 1 m[y][x] = v v-=1 d -= 1 for _ in" "*d: y += 1 m[y][x] = v v-=1 for _ in" "*d: x += 1 m[y][x] = v v-=1 d -= 1 for _ in" "*d: y -= 1 m[y][x] = v v-=1 return m # return the list of list n = 5 matrix = spiral(n) # Print lines of the matrix print("Matrix:") for e in matrix: print(*e) # Print the sum print(f"Sum: {sum(matrix[i][i]for i in range(n)) + sum(matrix[i][n - i - 1]for i in range(n)) - 1}") # There is a - 1 at the end, because the value of the middle is 1 You can rewrite the while loop like this: while d > 0: for i in range(4): for _ in" "*d: if i%2: y -= 2 * (i==3) - 1 else: x -= 2 * (i==0) - 1 m[y][x] = v v-=1 if i%2 == 0: d -= 1 It's shorter but less easy to understand
You can compute The Sum this way def Spiral(size: int): if(size<=1): return 1 else: Sum = 4*(size)**2 - 6(size-1) return (Sum+Spiral(size-2)) Spiral(5)
How to make this run 'faster'? Or is that the right terminology?
I am new to python and I submitted this code for a Hackerrank problem Arrays and Simple Queries, but for a large number of test cases the program is 'terminated due to timeout'. How can I make this more efficient? I've pasted the main swap function below. (Repeats M times) temp = input() temp = temp.split(" ") i = int(temp[1])-1 j = int(temp[2])-1 rep = (i-1)+1 if(temp[0]=='1') : rep = (i-1)+1 while(i<=j) : count = i-1 ex1 = count ex2 = i for k in range(0,rep) : arr[ex1], arr[ex2] = arr[ex2], arr[ex1] ex1 = ex1-1 ex2 = ex2-1 i = i+1 else : rep = (N-(j+1)) while(j>=i) : count = j+1 ex1 = count ex2 = j for k in range(0,rep) : arr[ex1], arr[ex2] = arr[ex2], arr[ex1] ex1 = ex1+1 ex2 = ex2+1 j=j-1
Instead of using many loops, you can try simply concatenating slices: def query(lst, t, start, end): # Convert to proper zero-indexed index start -= 1 if t == '1': return lst[start:end] + lst[:start] + lst[end:] elif t == '2': return lst[:start] + lst[end:] + lst[start:end] # Get the input however you want N, M = map(int, input().split()) arr = list(map(int, input().split())) assert len(arr) == N for _ in range(M): t, start, end = input().split() arr = query(arr, t, int(start), int(end)) print(abs(arr[0] - arr[N - 1])) print(*arr) Input: 8 4 1 2 3 4 5 6 7 8 1 2 4 2 3 5 1 4 7 2 1 4 Output: 1 2 3 6 5 7 8 4 1
Creating a Rhombus with numbers in python
Create a Rhombus through numbers if i input a number it should print the number of lines as same as input number and print the numbers upto given number, I'm not getting exact solution, Please help me out. Examples : If the input is 4 This will be the expected output. 1 1 2 3 1 2 3 1 If the input is 5 This will be the expected output. 1 1 2 3 1 2 3 4 5 1 2 3 1 If the input is 7 This will be the expected output. 1 1 2 3 1 2 3 4 5 1 2 3 4 5 6 7 1 2 3 4 5 1 2 3 1 I have tried, size = 4 maxlen = len(str(size * size)) m = size * 2 - 1 matrix = [[' ' * maxlen] * m for _ in range(m)] for n in range(size * size): r = n // size c = n % size matrix[c + r][size - r - 1 + c] = '{0:{1}}'.format(n + 1, maxlen) print '\n'.join(''.join(row) for row in matrix) But i'm not getting exact solution. Please help me out..
def pattern_gen(n): k = n for i in range(1, n + 1): if i % 2 != 0: for j in range(0, int(k/2)): print(end=" ") for j in range(1, i+1): print(j, end="") print() k = k - 1 k = 1 if n % 2 != 0: n = n-1 k = 2 for i in range(n, 0, -1): if i % 2 != 0: for j in range(0, int(k/2)): print(end=" ") for j in range(1, i+1): print(j, end="") print() k = k + 1
Java for loop in Python example
I have in java: public static void main(String[] args) { int x = 10; for(int i = 0; i <= x; i++ ){ System.out.println("i = " + i + "******"); for(int j = 0; j <= i; j++){ System.out.print("j = " + j + " "); } } with output: run: i = 0****** j = 0 i = 1****** j = 0 j = 1 i = 2****** j = 0 j = 1 j = 2 i = 3****** j = 0 j = 1 j = 2 j = 3 i = 4****** j = 0 j = 1 j = 2 j = 3 j = 4 i = 5****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 i = 6****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 i = 7****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 i = 8****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 i = 9****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 i = 10****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 j = 10 I'd like to achieve exactly effect in python for loop: x = 10 for i in range(0, x, 1): print("i = ", i, "*******") for j in range(0, i, 1): print("j = ", j, end="") Output: i = 0 ******* i = 1 ******* j = 0i = 2 ******* j = 0j = 1i = 3 ******* j = 0j = 1j = 2i = 4 ******* j = 0j = 1j = 2j = 3i = 5 ******* j = 0j = 1j = 2j = 3j = 4i = 6 ******* j = 0j = 1j = 2j = 3j = 4j = 5i = 7 ******* j = 0j = 1j = 2j = 3j = 4j = 5j = 6i = 8 ******* j = 0j = 1j = 2j = 3j = 4j = 5j = 6j = 7i = 9 ******* j = 0j = 1j = 2j = 3j = 4j = 5j = 6j = 7j = 8 I started learning python, I know java at intermediate level and cant start thinking in those pyhon loops. Python 3.6
The upper bound of range(..) is exclusive, so you simply need to add one to the upper bound: x = 10 for i in range(0, x+1): print("i = ",i,"*******",sep='') for j in range(0, i+1): print("j = ",j, sep='', end=' ') If the step is 1, you do not have to mention this. By default Python uses 1 as step. Furthermore by default Python will separate two arguments with a space, you can use the sep parameter to split it with no space (or another character sequence). This prints: i = 0******* j = 0 i = 1******* j = 0 j = 1 i = 2******* j = 0 j = 1 j = 2 i = 3******* j = 0 j = 1 j = 2 j = 3 i = 4******* j = 0 j = 1 j = 2 j = 3 j = 4 i = 5******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 i = 6******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 i = 7******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 i = 8******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 i = 9******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 i = 10******* j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 j = 10
You want to use end=" " rather than end="" to have a space between a value of j and the string j = from next iteration. Besides, the result of range does not include the upper limit, you have to add 1 to compensate for it. And finally, instead of: print("i = ", i, "*******") use print("i = {}*******".format(i)) to exactly reproduce your Java output.
Simple solution of your problem. x=10 for i in range(0,x+1): print "i = "+str(i)+"******" for j in range(0,i+1): print "j = "+str(j)+" ", output:- i = 0****** j = 0 i = 1****** j = 0 j = 1 i = 2****** j = 0 j = 1 j = 2 i = 3****** j = 0 j = 1 j = 2 j = 3 i = 4****** j = 0 j = 1 j = 2 j = 3 j = 4 i = 5****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 i = 6****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 i = 7****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 i = 8****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 i = 9****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 i = 10****** j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6 j = 7 j = 8 j = 9 j = 10
Python Nested For Loop Counting Backwards
This is probably a simple problem, but I am trying to created a nested loop that would count up from 0 to 9 in the outer loop, and in the inner loop, start from the value (or index. They are the same in this case) of the outer loop and count backwards. Here's an example: i= 0 k= 0 i= 1 k= 1 k= 0 i= 2 k= 2 k= 1 k= 0 i= 3 k= 3 k= 2 k= 1 k= 0 I got this far: x = range(0,10) for i in x: print 'i = ',x[i] for k in x: print 'k = ', x[i::-1] Obviously, the code above doesn't do what I want it to do. For one, the second for loop doesn't start from the value of i in the outer loop and counts backwards. For another, it doesn't print a new k = for every new value.
I think this should be like this: x = range(0,10) for i in x: print 'i = ',x[i] for k in x[i::-1]: print 'k = ', k print("\n") The result is: i = 0 k = 0 i = 1 k = 1 k = 0 i = 2 k = 2 k = 1 k = 0 i = 3 k = 3 k = 2 k = 1 k = 0 i = 4 k = 4 k = 3 k = 2 k = 1 k = 0 i = 5 k = 5 k = 4 k = 3 k = 2 k = 1 k = 0 i = 6 k = 6 k = 5 k = 4 k = 3 k = 2 k = 1 k = 0 i = 7 k = 7 k = 6 k = 5 k = 4 k = 3 k = 2 k = 1 k = 0 i = 8 k = 8 k = 7 k = 6 k = 5 k = 4 k = 3 k = 2 k = 1 k = 0 i = 9 k = 9 k = 8 k = 7 k = 6 k = 5 k = 4 k = 3 k = 2 k = 1 k = 0 Basicly, x[i::-1] should be in the for not in the print.
What about just manipulate it with print function? i = 0 k = 0 while True: print (i) print (k) if 1<k: #tricky part print ("\n".join([str(h) for h in range(0,k+1)][::-1])) print ("") i += 1 k += 1 if i == 10: break
You are very close. If you are new to the world of python you can take some inspiration from this example where I use list comprehension. list = lambda k: [ [ i for i in reversed(xrange(j+1)) ] for j in xrange(k+1) ] Note: If you are using python 3 "xrange" is changed to "range" Now call: list(3) And you'll see that the result is similar to what you are looking for. [[0], [1, 0], [2, 1, 0], [3, 2, 1, 0]]