I have a question about obtaining values from the objective function. My objective function consists of 2 parts, objective = X + Y. X = grb.quicksum(Z_vars[i,j,k] * TC_distmatrix[i,j] for i in set_N for j in set_N for k in set_K and Y = grb.quicksum(X_vars[q,r,p] * TC_distmatrix2[q,r] for q in set_M for r in set_M for p in set_P) are both calculated using a summation of other variables. Now, I would like to know what the individual value of X and Y are. However, I can't figure out how to do this. Can someone help me with this?
quicksum returns a LinExpr object. You can call getValue() on it to get its (current) solution value. (https://www.gurobi.com/documentation/9.1/refman/py_lex_getvalue.html)
So for your example:
sol_x = X.getValue()
sol_y = Y.getValue()
Related
Hey currently I'm trying to program a quadratic programming algorithm with Python.
My goal:
I want to program a function where the given parameters are one vector c, and a matrix G. They are connected through the function Phi = 0.5 *(x^T * G * x) + c^T *x (x^T in this context means vector x transposed). The goal of the function is to find a vector x so that the function Phi is minimized. In order to do that, I need to perform some algebraic calculations (multiplication, transposing and deriving the gradient of the function Phi).
My problem: But I'm struggling with creating a vector which indicates the dimensions of the problem. I am trying to create a vector x = [x_1, x_2, x_3, ..., x_N] which containts N elements. N varies. The elements 'x_N' should be variables (since I want to compute them later on, but I need them 'beforehand' to calculate e.g. the gradient).
My code so far: ('NoE'... is equal to N+1, thats why Im substracting 1 in my while statement)
#filling the x-vector according to the dimension of the given problem
temp_2 = 0
while temp_2 <= (NoE-1):
x[temp_2]= 'x_' + temp_2
print(x)
The previous answer just helped me partially:
The only problem I am encountering now, is that those are all strings and I cant perform any kind of mathematical operation with them (like multiplying them with a matrix). Do you know any fix how I can still do it with strings?
Or do you think I could use the sympy library (which would help me with future calculations)?
Im open to every suggestion of solving this, since I dont have a lot of experience in programming generally
Thanks in advance!
Sounds like an x y problem, because I don't understand how you are going to initialize those variables. If you provide more context I will update my answer.
If you want to have your list to contain variables or "symbols" on which you do algebraic operations, then the standard library doesn't have that, but you can use sympy:
import sympy
from sympy import symbols
### First we initialize some Symbol objects
# this does essentially what you were doing in the question, but in one line
# see list comprehensions*
symbol_names = [f'x_{i}' for i in range(NoE-1)]
# then we make them become 'Symbols'
x = symbols(symbol_names)
### Next we can do stuff with them:
# multiply the first two
expr = x[0] * x[1]
print(expr) # x_0*x_1
# evaluate the expression `expr` with x_0=3, x_1=2
res = expr.evalf(subs={'x_0':3, 'x_1':2})
print(res) # 6.00000
Even though the sympy code above answer your question as it is, I don't think that it's the best solution to the problem you were describing.
For example you could just have a list called x and then you populate it with elements
x = []
for i in range(NoE-1):
x.append(
float(input(f'insert value x_{i}'))
)
This way x will have all the inputted elements and you can access them via x[0], x[1], and so on.
* docs.python.org/3/tutorial/datastructures.html#list-comprehensions
You can create you own type (class) and implement any logic you want there:
class Vector(int):
def __new__(cls, name: str, number: int):
created_object = super().__new__(cls, number)
return created_object
def __init__(self, name, number):
self.name = name
self.number = number
# print(f'{name} is called with number={number}')
# if ypu want to get the same type after math operation
# you'll have to implement all magics like so
## otherwise comment it and you'll get the result of int type on multiplying
def __mul__(self, other):
return Vector("".join([self.name, "*",other.name]), self.number * other.number)
def __repr__(self):
return f'{self.name}: {self.number}'
v1 = Vector("v1", 3)
v2 = Vector("v2", 4)
print(v1)
print(v2)
print(v1*v2)
# int result as it is not implemented in class
v3 = v1 + v2
print(v3)
v = [ Vector(f"v_{x}", x+1) for x in range(0,2)]
print(v)
t = [mv * v1 for mv in v]
print(t)
I have an error function, and sum of all errors on self.array:
#'array' looks something like this [[x1,y1],[x2,y2],[x3,y3],...,[xn,yn]]
#'distances' is an array with same length as array with different int values in it
def calcError(self,n,X,Y): #calculate distance of nth member of array from given point
X,Y = float(X),float(Y)
arrX = float(self.array[n][0])
arrY = float(self.array[n][1])
e = 2.71828
eToThePower = e**(-1*self.distances[n])
distanceFromPoint=math.sqrt((arrX-X)**2+(arrY-Y)**2)
return float(eToThePower*(distanceFromPoint-self.distances[n])**2)
def sumFunction(self,X,Y):
res = 0.0
for i in range(len(self.array)):
res += self.calcError(i,X,Y)
return res
I have been looking for a way to find for which coordinates sumFunction return value is minimal. I have heard about scipy yet I am looking for a way to build that manualy. Gradient descent won't seem to work either since it is very hard to derive this sum function.
Thank you!
Did you try that create variable as a dictionary then append all iteration like this {self.calcError(i,X,Y)}:{i,X,Y}. If you return minimum the variable.keys then you can reach the coordinate from the min keys to value.
I have a matrix x, and a matrix p of the same structure and size.
One row represents the coordinates of an n-dimensional point.
I have a function f which takes a point (a row so to say) and computes a score for it.
Given x and p, I'd like to replace row i in p with row i in x if row i in x is smaller than row i in p according to my function f, formally:
for all row indices i do:
p[i] = (x[i] if f(x[i]) < f(p[i]) else p[i])
Python's list comprehension is way to slow, so I need to do it in numpy, but I'm new to numpy and have tried and failed hard while trying to figure it out.
From other computations I already have, I've called them benchmarks for some reason, vectors for x and p where the value at index i is the score of row i.
Here's the relevant code:
benchmark_x = FUNCTION(x)
benchmark_p = FUNCTION(p)
# TODO Too slow, ask smart guys from StackOverflow
p = np.array([x[i] if benchmark_x[i] < benchmark_p[i] else p[i] for i in range(p.shape[0])])
How about this ?
pos = benchmark_x < benchmark_p
p[pos] = x[pos]
For lack of a Latex editor, here is a picture of a piecewise function that I wish to plot using Sympy. I want to pass in two arrays of the coefficients and a value for x, then evaluate it and plot the function. (Edit : there are exactly one more p than there are alphas, image updated)
This is my attempt so far (alpha and p are lists/arrays, t is a number):
def getf(alpha,p,t):
#Create the argument list of tuples for the SymPy.Piecewise function
argtuples = []
for n,number in enumerate(alpha):
if n == 0:
argtuples.append((p[0]*x, x<alpha[0]))
elif 0<n and n<list(enumerate(alpha))[-1][0]:
argtuples.append((p[0]*alpha[0] + Sum(p[i]*(alpha[i] - alpha[i-1]),(i,1,n)) + p[n+1]*(x-alpha[n]), alpha[n-1] <= x < alpha[n]))
else:
argtuples.append((p[0]*alpha[0] + Sum(p[i]*(alpha[i] - alpha[i-1]),(i,1,n)) + p[n+1]*(x-alpha[n]), x>=alpha[n]))
f = Piecewise(argtuples)
return f(t)
from sympy import Piecewise, Sum
from sympy.abc import x, i
getf([10000,50000,100000,1000000],[0.05,0.08,0.15,0.30,0.40],1000001)
However, I'm getting the error "list indices must be integers or slices, not Symbol". How can I reference the coefficient values that I have passed into the function, given that the array could be any length?
You cannot use a symbolic index on a Python list (here i is symbolic, since you are importing it from abc). If you know the list ahead of time, you should use the Python sum function to sum the values, instead of Sum.
sum(p[i]*(alpha[i] - alpha[i-1]) for i in range(1, n))
There is also another problem, which is that you have alpha[n-1] <= x < alpha[n]. This unfortunately won't work, due to the way Python handles chained inequalities. You have to write this as And(alpha[n-1] <= 1, x < alpha[n]) Otherwise you will get TypeError: cannot determine truth value of Relational.
I'm new at programming so, I had troubles even with simple things;
I am trying to get 3 vectorsg1vec & a1vec & z1vec out of a triple for loop below, I have a Xvec which has 120 data in it, what I want is for every x in Xvec trying 90 A values and at every A there will be Zs up to that A (Zs are float at first then by comparing the ceil and floor I will take the one which gives me minimum) then with these values find the best A,Zs couple that minimizes my function gibbs for 120 Xvec values.
After days of trials, I could write the code below, but the code works so slow and I think there should be direct method to find these A and Zs argument, actually I'm not even sure that with this code I am getting the results I need. Any advice is highly appreciated
for x in Xvec:
for A in range(1,91):
for Zs in (np.arange(1, A+1 , 0.1 , dtype=float)):
g = gibbs(x,A,Zs)
g1 = np.append(g1,g)
min_pos, minofg = g1.argmin() , g1.min()
Zpos = 1+(0.1)*min_pos
Zceil = np.ceil(Zpos)
Zfloor = np.floor(Zpos)
gc = gibbs(x,A,Zceil)
gf = gibbs(x,A,Zfloor)
k = min(gc,gf)
if k == gc: Z = Zceil
else: Z = Zfloor
z1 = np.append(z1,Z)
x1 = np.append(x1,x)
a1 = np.append(a1,A)
for N in range(0,10711,90):
a = min(g1[N:N+90])
g1vec = np.append(g1vec,a)
b = g1[N:N+90].argmin()
a1vec = np.append(a1vec,a1[N+b])
z1vec = np.append(z1vec,z1[N+b])
So at the end I need to have 3 vectors one with a minimum possible values of a function gibbs at every x and the other 2 are the A and Zs values that gives that minimum value of the function.
After I could not find any other way I calculated all posibilities and then tried to seperate them in another for loop but it takes forever and I have lots of doubts that it actually even works.