Dynamically build a lambda function in python - python

Supose that I want to generate a function to be later incorporated in a set of equations to be solved with scipy nsolve function. I want to create a function like this:
xi + xi+1 + xi+3 = 1
in which the number of variables will be dependent on the number of components. For example, if I have 2 components:
f = lambda x: x[0] + x[1] - 1
for 3:
f = lambda x: x[0] + x[1] + x[2] - 1
I specify the components as an array within the arguments of the function to be called:
def my_func(components):
for component in components:
.....
.....
return f
I can't just find a way of doing this. I've to be able to make it this way as this function and other functions need to be solved together with nsolve:
x0 = scipy.optimize.fsolve(f, [0, 0, 0, 0 ....])
Any help would be appreciated
Thanks!
Since I'm not sure which is the best way of doing this I will fully explain what I'm trying to do:
-I'm trying to generate this two functions to be later nsolved:
So I want to create a function teste([list of components]) that can return me this two equations (Psat(T) is a function I can call depending on the component and P is a constant(value = 760)).
Example:
teste(['Benzene','Toluene'])
would return:
xBenzene + xToluene = 1
xBenzenePsat('Benzene') + xToluenePsat('Toluene') = 760
in the case of calling:
teste(['Benzene','Toluene','Cumene'])
it would return:
xBenzene + xToluene + xCumene = 1
xBenzenePsat('Benzene') + xToluenePsat('Toluene') + xCumene*Psat('Cumene') = 760
All these x values are not something I can calculate and turn into a list I can sum. They are variables that are created as a function ofthe number of components I have in the system...
Hope this helps to find the best way of doing this

A direct translation would be:
f = lambda *x: sum(x) - 1
But not sure if that's really what you want.

You can dynamically build a lambda with a string then parse it with the eval function like this:
a = [1, 2, 3]
s = "lambda x: "
s += " + ".join(["x[" + str(i) + "]" for i in xrange(0, 3)]) # Specify any range
s += " - 1"
print s
f = eval(s)
print f(a)

I would take advantage of numpy and do something like:
def teste(molecules):
P = np.array([Psat(molecule) for molecule in molecules])
f1 = lambda x: np.sum(x) - 1
f2 = lambda x: np.dot(x, P) - 760
return f1, f2
Actually what you are trying to solve is a possibly underdetermined system of linear equations, of the form A.x = b. You can construct A and b as follows:
A = np.vstack((np.ones((len(molecules),)),
[Psat(molecule) for molecule in molecules]))
b = np.array([1, 760])
And you could then create a single lambda function returning a 2 element vector as:
return lambda x: np.dot(A, x) - b
But I really don´t think that is the best approach to solving your equations: either you have a single solution you can get with np.linalg.solve(A, b), or you have a linear system with infinitely many solutions, in which case what you want to find is a base of the solution space, not a single point in that space, which is what you will get from a numerical solver that takes a function as input.

If you really want to define a function by building it up iteratively, you can. I can't think of any situation where this would be the best answer, or even a reasonable one, but it's what you asked for, so:
def my_func(components):
f = lambda x: -1
for component in components:
def wrap(f):
return lambda x: component * x[0] + f(x[1:])
f = wrap(f)
return f
Now:
>>> f = my_func([1, 2, 3])
>>> f([4,5,6])
44
Of course this will be no fun to debug. For example, look at the traceback from calling f([4,5]).

def make_constraint_function(components):
def constraint(vector):
return sum(vector[component] for component in components) - 1
return constraint
You could do it with a lambda, but a named function may be more readable. deffed functions can do anything lambdas can and more. Make sure to give the function a good docstring, and use variable and function names appropriate for your program.

Related

How to find roots of an equation where a variable is an output from a function, having target variable as an argument itself?

I am trying to solve an equation for variable 'X' in python where some of the variables in the equation ('ABC, PQR') are output from a function 'calculations'. The problem is, in order to get an output from the function, I need to pass variable X as an argument itself. I am kind of stuck in a loop here. I tried two different approaches but didn't get any success. Is there a way I can solve the equation?
Any help/direction is really appreciated.
My first approach is to start with a small value and run a loop. I tried to use math.isclose() but receive 'math bound error' once the values go off the range and it runs into an infinite loop.
The second approach is to write the complete expression and use scipy.optimize fsolve() but I am unable to understand how to properly implement it.
# function
def calculations(X, a, b, c):
ABC = X*a*b + c
XYZ = X*b*c + a
PQR = X*a*c + b
return ABC, XYZ, PQR
# ABC, PQR is the output from a function which uses X as input
# solve for X
func = 2*ABC + sqrt(PQR*ABC) + X*100*0.5
# Approach 1
X = 0.001
step = 0.001
while True:
# function call
Var_ABC, Var_XYZ, Var_PQR = calculations(X, a, b, c)
func = 2*Var_ABC + math.sqrt(Var_PQR * Var_ABC) + X*100*0.5
if (math.isclose(func, 0.0, rel_tol=0.1) == True):
break
else:
X = X + step
# Approach 2
# Since I don't know the value of X, how can I get the output from the function and then solve it again?
func_output[0] = calculations(X, a, b, c) # ABC
func_output[2] = calculations(X, a, b, c) # PQR
func = 2* func_output[0] + math.sqrt (func_output[0] * func_output[2] ) + X*100*0.5
from scipy.optimize import fsolve
desired_output_X = fsolve(func, [0.01, 1])
This may help you getting started with fsolve:
# function of X
def func(X):
func_output = calculations(X, a, b, c)
func = 2* func_output[0] + math.sqrt (func_output[0] * func_output[2]) + X*100*0.5
return func
# extra arguments for calculations function, dummy values used: set them as desired
a,b,c = 1,2,6
# initiating X = 0.01 and solve for X
desired_output_X = fsolve(func, x0 = 0.01)

Writing a function for x * sin(3/x) in python

I have to write a function, s(x) = x * sin(3/x) in python that is capable of taking single values or vectors/arrays, but I'm having a little trouble handling the cases when x is zero (or has an element that's zero). This is what I have so far:
def s(x):
result = zeros(size(x))
for a in range(0,size(x)):
if (x[a] == 0):
result[a] = 0
else:
result[a] = float(x[a] * sin(3.0/x[a]))
return result
Which...doesn't work for x = 0. And it's kinda messy. Even worse, I'm unable to use sympy's integrate function on it, or use it in my own simpson/trapezoidal rule code. Any ideas?
When I use integrate() on this function, I get the following error message: "Symbol" object does not support indexing.
This takes about 30 seconds per integrate call:
import sympy as sp
x = sp.Symbol('x')
int2 = sp.integrate(x*sp.sin(3./x),(x,0.000001,2)).evalf(8)
print int2
int1 = sp.integrate(x*sp.sin(3./x),(x,0,2)).evalf(8)
print int1
The results are:
1.0996940
-4.5*Si(zoo) + 8.1682775
Clearly you want to start the integration from a small positive number to avoid the problem at x = 0.
You can also assign x*sin(3./x) to a variable, e.g.:
s = x*sin(3./x)
int1 = sp.integrate(s, (x, 0.00001, 2))
My original answer using scipy to compute the integral:
import scipy.integrate
import math
def s(x):
if abs(x) < 0.00001:
return 0
else:
return x*math.sin(3.0/x)
s_exact = scipy.integrate.quad(s, 0, 2)
print s_exact
See the scipy docs for more integration options.
If you want to use SymPy's integrate, you need a symbolic function. A wrong value at a point doesn't really matter for integration (at least mathematically), so you shouldn't worry about it.
It seems there is a bug in SymPy that gives an answer in terms of zoo at 0, because it isn't using limit correctly. You'll need to compute the limits manually. For example, the integral from 0 to 1:
In [14]: res = integrate(x*sin(3/x), x)
In [15]: ans = limit(res, x, 1) - limit(res, x, 0)
In [16]: ans
Out[16]:
9⋅π 3⋅cos(3) sin(3) 9⋅Si(3)
- ─── + ──────── + ────── + ───────
4 2 2 2
In [17]: ans.evalf()
Out[17]: -0.164075835450162

Integral function (x,y) in python

I have a function like:
(np.sqrt((X)**2 + (Y)**2))/(np.sqrt((X)**2 + (Y)**2 + d**2))
I wrote a program for calculating integral by using series:
for i in range (num): # for X
print i
Y=(-distance)
for j in range(num): # for Y
f=(np.sqrt((X)**2 + (Y)**2))/(np.sqrt((X)**2 + (Y)**2 + d**2))
Y=Y+delta
sum+=(f*(delta**2))/((2*distance)**2)
X=X+delta
print sum
And It works fine for me.. But it takes too long for some complex function.
Is there any python module for integrating this function when -2.0 < X and Y < 2.0? (or something else)
I guess that you want to integrate fun between x equals a and b and y equals c and d. In this case what you have to do is:
import numpy as np
# Define 'd' to whatever value you need
d = 1.
# Function to integrate
fun = lambda x, y: np.sqrt(x**2. + y**2.) / np.sqrt(x**2. + y**2. + d**2.)
# Limits of integration
a, b = -2., 2.
c, d = -2., 2.
gfun = lambda x: c
hfun = lambda x: d
# Perform integration
from scipy.integrate import dblquad
int, err = dblquad(fun, a, b, gfun, hfun)
If you need more complex limits of integration you just need to change gfun and hfun. If you are interested in more advanced feature you can take a look at the documentation of dblquad: http://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.dblquad.html#scipy.integrate.dblquad
There's a library for this, scipy.integrate.
This should be pretty straightforward to do:
func = lambda y: (np.sqrt((X)**2 + (Y)**2))/(np.sqrt((X)**2 + (Y)**2 + d**2)) and a == -2 and b == 2
from scipy import integrate
integrate.quad(func, a b)
This should do it. I would consult the documentation for SciPy for more info.
Edit: If there are issues, make sure you're using floats instead of ints.

Best way to find roots of a multidimensional, scalar function with SciPy

Suppose I have a function whose range is a scalar but whose domain is a vector. For example:
def func(x):
return x[0] + 1 + x[1]**2
What's a good way to find the a root of this function? scipy.optimize.fsolve and scipy.optimize.root expect func to return a vector (rather than a scalar), and scipy.optimize.newton only takes scalar arguments. I can redefine func as
def func(x):
return [x[0] + 1 + x[1]**2, 0]
Then root and fsolve can find a root, but the zeros in the Jacobian means it won't always do a good job. For example:
fsolve(func, array([0,2]))
=> array([-5, 2])
It'll only vary the first parameter but not the second, meaning that it often finds a zero that's far away.
EDIT: it looks like the following redefinition of func works better:
def func(x):
fx = x[0] + 1 + x[1]**2
return [fx, fx]
fsolve(func, array([0,5]))
=>array([-16.27342781, 3.90812331])
So it's now willing to change both parameters. The code is still kind of ugly though.
Have you tried the minimization of the absolute value of your function using fmin?
For example:
>>> import scipy.optimize as op
>>> import numpy as np
>>> def func(x):
>>> return x[0] + 1 + x[1]**2
>>> func1 = lambda x: np.abs(func(x))
>>> tmp = op.fmin(func1, [10000., 10000.])
>>> func(tmp)
0.0
>>> print tmp
[-8346.12025122 91.35162971]
Since -- for my problem -- I have a good initial guess and a non-crazy function, Newton's method works well. For a scalar, multidimensional function, Newton's method becomes:
Here's a rough code example:
def func(x): #the function to find a root of
return x[0] + 1 + x[1]**2
def dfunc(x): #the gradient of that function
return array([1, 2*x[1]])
def newtRoot(x0, func, dfunc):
x = array(x0)
for n in xrange(100): # do at most 100 iterations
f = func(x)
df = dfunc(x)
if abs(f) < 1e-6: # exit function if we're close enough
break
x = x - df*f/norm(df)**2 # update guess
return x
In use:
nsolve([0,2],func,dfunc)
=> array([-1.0052546 , 0.07248865])
func([-1.0052546 , 0.07248865])
=> 4.3788225025098715e-09
Not bad! Of course, this function is very rough, but you get the idea. It also won't work well for "tricky" functions or where you don't have a good starting guess. I think I'll use something like this but then fall back to fsolve or root if Newton's method doesn't converge.

Sympy: working with equalities manually

I'm currently doing a maths course where my aim is to understand the concepts and process rather than crunch through problem sets as fast as possible. When solving equations, I'd like to be able to poke at them myself rather than have them solved for me.
Let's say we have the very simple equation z + 1 = 4- if I were to solve this myself, I would obviously subtract 1 from both sides, but I can't figure out if sympy provides a simple way to do this. At the moment the best solution I can come up with is:
from sympy import *
z = symbols('z')
eq1 = Eq(z + 1, 4)
Eq(eq1.lhs - 1, eq1.rhs - 1)
# Output:
# z == 3
Where the more obvious expression eq1 - 1 only subtracts from the left-hand side. How can I use sympy to work through equalities step-by-step like this (i.e. without getting the solve() method to just given me the answer)? Any pointers to the manipulations that are actually possible with sympy equalities would be appreciated.
There is a "do" method and discussion at https://github.com/sympy/sympy/issues/5031#issuecomment-36996878 that would allow you to "do" operations to both sides of an Equality. It's not been accepted as an addition to SymPy but it is a simple add-on that you can use. It is pasted here for convenience:
def do(self, e, i=None, doit=False):
"""Return a new Eq using function given or a model
model expression in which a variable represents each
side of the expression.
Examples
========
>>> from sympy import Eq
>>> from sympy.abc import i, x, y, z
>>> eq = Eq(x, y)
When the argument passed is an expression with one
free symbol that symbol is used to indicate a "side"
in the Eq and an Eq will be returned with the sides
from self replaced in that expression. For example, to
add 2 to both sides:
>>> eq.do(i + 2)
Eq(x + 2, y + 2)
To add x to both sides:
>>> eq.do(i + x)
Eq(2*x, x + y)
In the preceding it was actually ambiguous whether x or i
was to be added but the rule is that any symbol that are
already in the expression are not to be interpreted as the
dummy variable. If we try to add z to each side, however, an
error is raised because now it is unclear whether i or z is being
added:
>>> eq.do(i + z)
Traceback (most recent call last):
...
ValueError: not sure what symbol is being used to represent a side
The ambiguity must be resolved by indicating with another parameter
which is the dummy variable representing a side:
>>> eq.do(i + z, i)
Eq(x + z, y + z)
Alternatively, if only one Dummy symbol appears in the expression then
it will be automatically used to represent a side of the Eq.
>>> eq.do(2*Dummy() + z)
Eq(2*x + z, 2*y + z)
Operations like differentiation must be passed as a
lambda:
>>> Eq(x, y).do(lambda i: i.diff(x))
Eq(1, 0)
Because doit=False by default, the result is not evaluated. to
evaluate it, either use the doit method or pass doit=True.
>>> _.doit == Eq(x, y).do(lambda i: i.diff(x), doit=True)
True
"""
if not isinstance(e, (FunctionClass, Lambda, type(lambda:1))):
e = S(e)
imaybe = e.free_symbols - self.free_symbols
if not imaybe:
raise ValueError('expecting a symbol')
if imaybe and i and i not in imaybe:
raise ValueError('indicated i not in given expression')
if len(imaybe) != 1 and not i:
d = [i for i in imaybe if isinstance(i, Dummy)]
if len(d) != 1:
raise ValueError(
'not sure what symbol is being used to represent a side')
i = set(d)
else:
i = imaybe
i = i.pop()
f = lambda side: e.subs(i, side)
else:
f = e
return self.func(*[f(side) for side in self.args], evaluate=doit)
from sympy.core.relational import Equality
Equality.do = do

Categories

Resources