python 3, quadratic function - python

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]

Related

Filling a vector with a varying amount of variables

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)

Find minimum return value of function with two parameters

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.

Issue with recursive function in python

I have an issue with defining this function recursively. My goal is for the function to return the maximal income from a given n. n (in meters) here is the amount of cloth. The h list is the profit when selling a rug that is n meters long. For example, h[2]=5 is the profit when making a 2 meters long carpet which is for simplicity 5 dollars, and h[0]=0 since no cloth is available and no product produced. So the h list is just the market value of rugs of different lengths. I want the function to return the maximum profit if I have n meters of cloth. The prices are only defined for carpets up to 4 m, hence why the h list is what it is. The recursion for n=2 for example calculates the value of making a rug 2 m big and compares the profit with making two 1 m carpets and so on.
The recursion is loosely stated as:
income(0) = 0
income(n) = max(h[i]+income(n-i)) for 1<=i<=n
As of now, by the code below, I'm getting a recursion limit exceeded. Which I don't find weird as I have no condition for limiting the loop but the issue is I don't know how to proceed and define some sort of constraint. I realize the description here might be very confusing but please ask and I'll try to explain more extensively.
def income(n):
h = [0,2,5,6,9]
for i in range(n):
return max(h[i]+income(n-i))
EDIT:
This is my solution I came up with.
def income(n):
"""Returns maximum profit by a given n."""
h = [2,5,6,9,0]
m = []
if n == 0:
return 0
else:
for i in range(n):
m.append(h[i]+income(n-i-1))
return max(m)
With cache:
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
income = memoize(income)
The problem you're trying to solve is a version of the unbounded knapsack problem. Instead of trying to maximize the value you can fit into a pack, you're trying to maximize the value the rugs you can make with your cloth. Instead of caring about item weight, you care about how much of your cloth gets used in the rug. But it works out the same. In any case, that's a very hard problem to solve efficiently for arbitrary inputs, but you can brute force it pretty easily for small n values.
You correctly identified that your recursion continues forever (or rather until the recursion limit) because you've not written a base case. It's actually a bit worse than that, since the first recursion is with i equal to 0, which calls the function again with the exact same n you were already trying to solve (since n-i is n when i==0).
You really don't want to recurse when i is zero, since you won't have reduced the scope of the problem at all. The simplest approach is probably just to modify your range to start i at 1, and increase from there. You also need some logic to prevent the loop from going past index 4, since you don't have any more values in the list for longer lengths.
def income(n):
if n == 0: # base case
return 0
h = [0,2,5,6,9]
return max(h[i]+income(n-i) for i in range(1, min(n+1, len(h)))) # recursive case
In addition to adding a base case for n==0 and fixing the range, I also replaced the loop with a generator expression that does the recursion. This is necessary because max expects either several arguments (which it compares against each other), or a single iterable argument (who's values get compared). You were passing just a single value, which doesn't work.
The version above works just fine for small n values, up to about 15. But going higher than that begins to take longer and longer times because the recursion gets very deep and broad, and you end up calculating a lot of values over and over. This is what I meant when I said the knapsack problem is hard!
One trick that will speed things up a whole lot is to cache the results of each computation the first time you figure it out, and use the cached value if its needed again later.
_cache = {0: 0} # the cache is pre-seeded to handle our base case of n=0
def income(n):
if n not in _cache:
h = [0,2,5,6,9]
_cache[n] = max(h[i]+income(n-i) for i in range(1, min(n+1, len(h))))
return _cache[n]
I'd further note that for your specific h list, it looks like it is always best to make as many 2 meter rugs as you can, plus up to one 1 meter rug to use up the last meter of cloth if you started with an odd n. So if you're willing to hard code this optimal solution to the very specific problem in your example, you could skip the recursion and just do:
def income(n):
return n//2 * 5 + n%2 * 2

recursive function in python but with strange return

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, []))

How does enumerate work in polynomial function (Python)?

I am a Python beginner and a bit confused about enumerate function in summing the polynomial problem in the following SO thread:
Evaluating Polynomial coefficients
The thread includes several ways to solve the summing of polynomials. I understand the following version well:
def evalP(lst, x):
total = 0
for power in range(len(lst)):
total += (x**power) * lst[power] # lst[power] is the coefficient
return total
E.g. if I take third degree polynomial with x = 2, the program returns 15 as I expected based on pen and paper calculations:
evalP([1,1,1,1],2)
Out[64]:
15
But there is another, neater version of doing this that uses enumerate function:
evalPoly = lambda lst, x: sum((x**power) * coeff for power, coeff in enumerate(lst))
The problem is that I just can't get that previous result replicated with that. This is what I've tried:
coeff = 1
power = 3
lst = (power,coeff)
x = 2
evalPoly(lst,x)
And this is what the program returns:
Out[68]:
5
Not what I expected. I think I have misunderstood how that enumerate version takes on the coefficient. Could anyone tell me how I am thinking this wrong?
The previous version seems more general as it allows for differing coefficients in the list, whereas I am not sure what that scalar in enumerate version represents.
You should call evalPoly with the same arguments as evalP, e.g. evalPoly([1,1,1,1],2)
When you call evalPoly([3,1],2), it return 3*2^0 + 1*2^1 which equals 5.

Categories

Resources