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)
Related
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()
I have to Write a python function that can solve any quadratic equation in the form: ax2 + bx + c = 0, also handle the special case when some of the coefficients are zero, I have to write the function with 3 optional keyword arguments, with the default value of 0. In this way, one can use this function with any order of coefficients as long as the quadratic term is a, the linear is b and the constant is c. Also, one can leave out coefficients if they are 0.
and I have to return a list based on the following conditions: From these coefficients, calculate every real solution and return them as a list, not longer than 2.
Return None if all the coefficients are zero, because in that case you would have infinite number of solutions.
If there is no solution or only complex ones, then return an empty list.
If there is a real root with multiplicity 2, then return a one long list.
However the problem is that I didn't know how to set the default values of a dictionary when I get an empty dictionary as an input. Thank you in advance for your help!
This is my code
import math
def quadratic_solve(**dictr):
List=[]
x1=dictr['a']
x2=dictr['b']
x3=dictr['c']
delta=x1*x1-4*x2*x3
if (x1==0 and x2==0 and x3==0):
return None
if (x1==0):
List.append(-x3/x2)
return List
if(dictr['b']*dictr['b']-4*dictr['a']*dictr['c']<0) :
return List
if(x2*x2-4*x1*x3>0) :
List.append((-x2+math.sqrt(delta))/2*x1)
List.append((-x2-math.sqrt(delta))/2*x1)
return List
You could make better use of Python's feature to reduce the amount of code (i.e. focus on the essential conditions):
def quadratic_solve(params):
a,b,c = [params.get(p,0) for p in "abc"] # get this out of the way early
if a==0: return [] if b==0 else [-c/b] # linear equation
b2_4ac = b*b-4*a*c # part under the square root
if b2_4ac < 0: return [] # complex result
p,n = (-b+b2_4ac**0.5)/2/a, (-b-b2_4ac**0.5)/2/a # + or - square root results
return [p] if p==n else [p,n] # one or two solutions
quadratic_solve({'a':2,'b':3}) # [0.0, -1.5]
I am supposed to create a function that adds the absolute value of numbers that are larger than a certain number without using any python modules to do it. I wrote this:
def MatrixSumLarge(vals,large):
sum=0
sum1=0
sum2=0
i=0
#looking at the rows of the matrix
for i in range(len(vals[i])):
if abs(vals)>=large:
sum1=sum1+i
#lookinng at the columns of the matrix
for j in range(0,len(vals[j])):
if abs(vals[j])>=large:
sum2=sum2+vals[j]
sum=sum1+sum2
return(sum)
vals=[[1,-2.5,7,4],[-8,9,2,-1.5],[-12,7.5,4.2,11]]
# setting value of large
large = 7.1
#to print the final answer
print('b) Sum of Large Values = ',MatrixSumLarge(vals,large))
And got the error:
TypeError: bad operand type for abs(): 'list'
You vals is a list of list, so vals[i] is a list. However, abs() cannot be applied on a list, it should be applied on a number (floating number, integer, or complex number), see the official document here. You can for example, add an extra loop to add up the element in the row, like sum(abs(x) for x in vals[i] if x >= 2)
You can change 2 to the number you need.
Overall, your function could look something like this
def f(mat, v):
row_sums = [sum(abs(x) for x in row if x >= v) for row in mat]
return sum(row_sums)
From your question, it's not very clear to me whether you wanna
compare abs(x) to v or x to v
sum up abs(x) or x
But you should be able to adjust the code above to suit your need.
There is also a python module that helps you to flatten list of list. The function is called chain.from_iterable. So the above code could also be written like this
from itertools import chain
def f(mat, v):
sums = [sum(abs(x) for x in chain.from_iterable(mat) if x >= v]
return sum(sums)
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 am trying to solve a primary equation with several variables. For example:11x+7y+3z=20. non-negative integer result only.
I use code below in python 3.5.1, but the result contains something like [...]. I wonder what is it?
The code I have is to test every variables from 0 to max [total value divided by corresponding variable]. Because the variables may be of a large number, I want to use recursion to solve it.
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
testrest=equation(a[1:],b-a[0]*i,corelist)
if testrest:
total+=[testrest]
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
return relist
else:
return False
total=[]
re=equation([11,7,3],20,[])
print(re)
the result is
[[0, 2, 2], [...], [1, 0, 3], [...]]
change to a new one could get clean result, but I still need a global variable:
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
equation(a[1:],b-a[0]*i,corelist)
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
total+=[relist]
return
else:
return
total=[]
print(equation([11,7,3],20,[]))
I see three layers of problems here.
1) There seems to be a misunderstanding about recursion.
2) There seems to be an underestimation of the complexity of the problem you are trying to solve (a modeling issue)
3) Your main question exposes some lacking skills in python itself.
I will address the questions in backward order given that your actual question is "the result contains something like [...]. I wonder what is it?"
"[]" in python designates a list.
For example:
var = [ 1, 2 ,3 ,4 ]
Creates a reference "var" to a list containing 4 integers of values 1, 2, 3 and 4 respectively.
var2 = [ "hello", ["foo", "bar"], "world" ]
var2 on the other hand is a reference to a composite list of 3 elements, a string, another list and a string. The 2nd element is a list of 2 strings.
So your results is a list of lists of integers (assuming the 2 lists with "..." are integers). If each sublists are of the same size, you could also think of it as a matrix. And the way the function is written, you could end up with a composite list of lists of integers, the value "False" (or the value "None" in the newest version)
Now to the modeling problem. The equation 11x + 7y + 3z = 20 is one equation with 3 unknowns. It is not clear at all to me what you want to acheive with this program, but unless you solve the equation by selecting 2 independent variables, you won't achieve much. It is not clear at all to me what is the relation between the program and the equation save for the list you provided as argument with the values 11, 7 and 3.
What I would do (assuming you are looking for triplets of values that solves the equation) is go for the equation: f(x,y) = (20/3) - (11/3)x - (7/3)y. Then the code I would rather write is:
def func_f(x, y):
return 20.0/3.0 - (11.0/3.0) * x - (7.0/3.0) * y
list_of_list_of_triplets = []
for (x, y) in zip(range(100),range(100)):
list_of_triplet = [x, y, func_f(x,y)]
list_of_list_of_triplets += [list_of_triplet] # or .append(list_of_triplet)
Be mindful that the number of solutions to this equation is infinite. You could think of it as a straight line in a rectangular prism if you bound the variables. If you wanted to represent the same line in an abstract number of dimensions, you could rewrite the above as:
def func_multi_f(nthc, const, coeffs, vars):
return const - sum([a*b/nth for a,b in zip(coeffs, vars)])
Where nthc is the coefficient of the Nth variable, const is an offset constant, coeffs is a list of coefficients and vars the values of the N-1 other variables. For example, we could re-write the func_f as:
def func_f(x,y):
return func_multi_f(3.0, 20.0, [11.0, 7.0], [x,y])
Now about recursion. A recursion is a formulation of a reducible input that can be called repetivitely as to achieve a final result. In pseudo code a recursive algorithm can be formulated as:
input = a reduced value or input items
if input has reached final state: return final value
operation = perform something on input and reduce it, combine with return value of this algorithm with reduced input.
For example, the fibonacci suite:
def fibonacci(val):
if val == 1:
return 1
return fibonacci(val - 1) + val
If you wanted to recusively add elements from a list:
def sum_recursive(list):
if len(list) == 1:
return list[0]
return sum_recursive(list[:-1]) + list[-1]
Hope it helps.
UPDATE
From comments and original question edits, it appears that we are rather looking for INTEGER solutions to the equation. Of non-negative values. That is quite different.
1) Step one find bounds: use the equation ax + by + cz <= 20 with a,b,c > 0 and x,y,z >= 0
2) Step two, simply do [(x, y, z) for x, y, z in zip(bounds_x, bounds_y, bounds_z) if x*11 + y*7 + z*3 - 20 == 0] and you will have a list of valid triplets.
in code:
def bounds(coeff, const):
return [val for val in range(const) if coeff * val <= const]
def combine_bounds(bounds_list):
# here you have to write your recusive function to build
# all possible combinations assuming N dimensions
def sols(coeffs, const):
bounds_lists = [bounds(a, const) for a in coeffs]
return [vals for vals in combine_bounds(bounds_lists) if sum([a*b for a,b in zip(coeff, vals)] - const == 0)
Here is a solution built from your second one, but without the global variable. Instead, each call passes back a list of solutions; the parent call appends each solution to the current element, making a new list to return.
def equation (a, b):
result = []
if len(a) > 1:
# For each valid value of the current coefficient,
# recur on the remainder of the list.
for i in range(b // a[0]+1):
soln = equation(a[1:], b-a[0]*i)
# prepend the current coefficient
# to each solution of the recursive call.
for item in soln:
result.append([i] + item)
else:
# Only one item left: is it a solution?
if b%a[0] == 0:
# Success: return a list of the one element
result = [[b // a[0]]]
else:
# Failure: return empty list
result = []
return result
print(equation([11, 7, 3], 20, []))