python convert vector input function to multiinput - python

I have a function that takes a vector input, e.g.
f(x) = x[0]*x[1]
I want a function that takes this function and creates a new function:
g(x,y) = x*y
fcn_translator(f)
# intelligent code here
return g
Does anyone know how to do this? Has this been done before. The reason for this question is that I have a python package that optimizes a function of the form f(x,y...) but the function that I'm calling acts on a vector.

Looks like you want a function that takes two parameters, combines them into a vector, and calls f:
def g1(x, y):
return f([x, y])
As a more general solution, the function g2 takes any number of parameters, combines them into a vector, and calls f:
def g2(*x):
return f(x)
Finally, since the first two elements of the vector are required for f, this function takes at least two parameters:
def g3(x, y, *rest):
return f((x, y) + rest)

Related

Evolving functions in python

Updated Question
Following from my original post, with the use of #Attack68 's code, I have created a program that successfully evolved the function with a choice of multiplicative functions based on a random variable. However, now I am receiving an error saying the list indices must be integers (even though I'm fairly sure they are), I'm not sure what has happened, The code is as follows:
import numpy as np
import scipy.integrate as integrate
x=np.linspace(0.0,1.0,100)
n=10 #iterations
d=700.0
def f(x):
return np.sin(x)
def g(x,list_):
return np.cos(x)*apply(x,list_)
base = [f, g]
list_ = list()
for i in range(n):
testvar=np.random.randint(1, 100, 1)
if testvar> 50 and i!=0:
func_idx = 0 # choose a random operation: 0=ten, 1=inv
else:
func_idx= 1
list_.append(func_idx)
# now you have a list of indexes referencing your base functions so you can apply them:
def apply(x,list_):
y = 1
for i in range(len(list_)):
y *= base[list_[i]](x)
return y
print(list_)
#testint=integrate.quad(apply(x,list_),-d,d)[0]
#print(testint)
print(apply(list_, x))
I am now getting the error:
TypeError: list indices must be integers or slices, not numpy.float64
I am also attempting to get this to integrate the new function after each iteration but it seems that the form of this function is not callable by scipys quad integrator, any suggestions on how to integrate the evolving function on each iteration would also be appreciated.
Original:
I am creating a simulation in python where I consider a function that evolves over a loop. This function starts off defined as:
def f(x):
return 1.0
So simply a flat distribution. After each iteration of the loop, I want the function to be redefined depending on certain (random) conditions. It could be multiplied by cos(b*x) or it could be multiplied by some function A(x), the evolution will not be the same each time due to the randomness, so I cannot simply multiply by the same value each time.
The progression in one instance could be:
f(x)----> f(x)*A(x)----> f(x)*A(x)*A(x)...
but in another instance it could be:
f(x)----> f(x)*A(x)----> f(x)*A(x)*cos(x)...
or
f(x)----> f(x)*cos(x)----> f(x)*cos(x)*cos(x)...
etc.
after each, of n iterations of this evolution, I have to compute an integral that is related to the function, so I need to essentially update the function after each iteration to be called by scipys quad integrator.
I have tried to use arrays to manipulate the distribution instead and it works as far as the function evolution goes, but upon integration, it gives the incorrect result with numpy.trapz and I cannot work out why. Sci-pys quad integrator is more accurate anyway and I had managed to get this to work previously for the first iteration only, but it requires a function based input, so without this function evolution I cannot use it.
If someone could show me if/how this function evolution is possible that'd be great. If it is not possible, perhaps someone could try to help me understand what numpy.trapz actually does so I can workout how to fix it?
How about this:
class MyFunction:
def __init__(self):
def f1(x):
return 1.0
self.functions = [f1]
def append_function(self, fn):
self.functions.append(fn)
def __call__(self, x):
product = 1.0
for f in self.functions:
product *= f(x)
return product
This object starts off as simply returning 1.0. Later you add more functions and it returns the product of all of them.
Your description suggests your iterated values are combined through a product and are not in fact a composition of functions. A simple way of recording these is to have a set of base functions:
import numpy as np
import scipy.integrate as int
def two(x):
return x*2
def inv(x):
return 1/x
base = [two, inv]
funcs = np.random.choice(base, size=10)
def apply(x, funcs):
y = 1
for func in funcs:
y *= func(x)
return y
print('function value at 1.5 ', apply(1.5, funcs))
answer = int.quad(apply, 1, 2, args=(funcs,))
print('integration over [1,2]: ', answer)

Function that is sum of arbitrary many other functions

I'm trying to write a function in Python for a polynomial p that is a linear combination of n basis functions phi_i. How can I define a function that is itself a sum of n other functions?
I know that this works:
phi1 = lambda x: x**2
phi2 = lambda x: x
p = lambda x: phi1(x) + phi2(x)
But if I try a loop like this:
p = lambda x: 0
for i in range(0,n):
p = lambda x: p(x)+phi[i](x)
where phi is a list of my basis functions, I create an infinite loop.
I checked Writing a function that is sum of functions, but unfortunately that's not in Python.
You can do this by passing a simple generator expression to sum:
def sigma(funcs, x):
return sum(f(x) for f in funcs)
phi = [lambda x: x**2, lambda x: x]
y = sigma(phi, x)
BTW, it's considered bad style to use lambda for named functions, it's supposed to be for anonymous functions.
If you want a function that doesn't need phi to be passed in each time you call it, there are a couple of ways to do that. The easiest way is to simply use phi in the function. Eg,
def sigma(x):
return sum(f(x) for f in phi)
However, that has a couple of downsides. It won't work if phi isn't in the scope where you call sigma; you can get around that by making phi global, but that may not be convenient, and it's best to avoid globals when they aren't necessary. The other downside is that it uses the current contents of phi, not the contents it had when sigma was defined, so if you modify the contents of phi those changes will be reflected in sigma, which may or may not be desirable.
Another option is to use a closure to create the function. Then we won't be affected by the scope issue: you can call the resulting summing function inside a scope where the original function list isn't visible. We can also create a copy of the function list, so it won't be affected by changes to the passed-in function list.
def make_adder(funcs):
# Copy the function list
funcs = funcs[:]
def sigma(x):
return sum(f(x) for f in funcs)
return sigma
phi = [lambda x: x**2, lambda x: x]
sigma = make_adder(phi)
y = sigma(x)
Yet another option is to use my original sigma and pass it and the phi functions to functools.partial, eg
from functools import partial
sig = partial(sigma, phi)
y = sig(x)
Straight answer to OP
Store your phis in a list:
phis = [
lambda x: x**2,
lambda x: x,
]
p = lambda x: sum(phi(x) for phi in phis)
Further considerations
If you want to achieve a polynomial, I would suggest something similar to this:
def poly(c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
poly function accepts a sequence as the only argument, where its elements need to be int or float. The first element is assigned as the coeficient of x^0, the second to x^1 and so on. So your example (p(x) = x + x^2) would end up being constructed like this: p = poly([0, 1, 1])
Another option is to accept any number of arguments where each of them needs to be a int or float instead of the first being a sequence. This would only require to add one * to the function declaration.
def poly(*c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
To construct your example with this function you would not require the list: p = poly(0, 1, 1).
Any of those methods would create a polynomic function that can be called as you would expect: p(1) would return 2, p(2) would return 6 and so on.
Function explained
def poly(c):
# Create a list where we are gonna store the functions for every term in the polynomial
terms = []
# Create as many terms as the arguments length
for i in range(len(c)):
# Each term is the product of the nth coefficient from c and x to the power of n
terms.append(lambda x, n=i: c[n]*x**n)
# The second parameter n is needed because if we pass i directly
# inside the function algorithm, Python wouldn't check its value
# inmediately, but when it gets executed, and by then the loop will
# be finished and i would be constant for every term. This argument
# is not exposed to the polynomial function as the next lambda only
# has one argument, so there is no way to wrongly call this function
# We return a function that adds the result of every term
return lambda x: sum(f(x) for f in terms)

Generating a sorting function for counter-clockwise sort

As part of a script I am making, I want to sort a series of points in a counter-clockwise order around a central point, which we will call 'a'.
I have a function that determines, for two points 'b' and 'c', if c is to the right of or left of the ray a->b. This function is right_of(a, b, c), and it is tested and works.
I want to use this function to sort a list of tuples with 2-d coordinates e.g. [(0, 0), (0, 1), (1, 1),...]. However, each time I sort, there will be a different point 'a' to pass to the function right_of(). What I want is a 'function' returnSortFunction(a) that will return a function with two arguments, f(b, c), and and when f(b, c) is called on each pair of coordinates as I sort, it should return the result of right_of(a, b, c) with 'a' already filled in.
I have tried to implement this using a factory, but I don't think I understand factories well enough to do it correctly, or determine if that is not what a factory is for. How can I build this feature?
You can have a function return a function, no problem. A simple way to do it is something like
def returnSortFunction(a):
return lambda b,c: right_of(a,b,c)
You need a wrapper function around your right_of function. You could use a lambda, but I think your logic is going to be more complicated than that. Assuming you want to pass in a function as a comparator to your sorting method, it's going to look something like this:
def returnSortFunction(a):
def comparator(p1, p2, a = a):
if p1 == p2:
return 0
elif right_of(a, p1, p2):
return 1
else:
return -1
return comparator
Functions are first class objects in python, so you can do something like this:
def prepare_funcs(number):
def inc(a):
return number + a
def mult(a):
return number * a
return inc, mult
inc5, mult5 = prepare_funcs(5)
inc2, mult2 = prepare_funcs(2)
inc5(2) #Out: 7
mult2(10) #Out: 20
For your specific context you should also check out functools module, specifically partial function. With it, you can 'partially' prepare arguments to your function like this:
right_of_5 = functools(right_of, 5)
right_of_5(b, c)
That will work, because right_of_5 will automatically fill right_of first argument - a - with number 5.

How to obtain a math function as an output in python

I want to do something like this
def gaussian(x, amp):
return amp * exp(-(x-cen)**2 /wid)
I want to substitute just amp and x and obtain an equation as output
for example:
gaussian(1,3)
3 * exp(-(1-cen)**2 /wid) as output.
Can I do this for a couple of lists, in one several values of amplitude an in the other their respective x's
I am not sure what you mean by "I need an equation". Do you need something you can evaluate? Then probably you can return a lambda object, and then you can evaluate that. Or you can use closure something like:
import math
def gaussian(x, amp):
def _gauss( cen,wid):
return amp * math.exp(-(x-cen)**2 /wid)
return _gauss
g = gaussian(10,1)
print g(2,4)
g now is a callable function where x and amp has been replaced so you need to pass only cen and wid
The reason why this work is because the internal function, _gauss, gets evaluated every time you call the wrapper function, doing so the function will be evaluated using the argument passed by the parent function and be used there as "static". Since then you return a function you can evaluate that and pass all the params left, this is a common technique for when a library forces you to have parameterlles callbacks.
Only draw back is more expensive then a simple function call, that is to generate the child function, not to evaluate it.
I would convert your return to a string:
def gaussian(x, amp):
return str(amp) + '* exp(-(' + str(x) + '-cen)**2 /wid)'
This should return the value you want:
gaussian(1,3)
returns
'3 * exp(-(1-cen)**2 /wid)'

Functions as arguments to functions

I saw this example in a Python book, which showcases how to use a function as an argument to another function:
def diff2(f, x, h=1E-6):
r = (f(x-h) - 2*f(x) + f(x+h))/float(h*h)
return r
def g(t):
return t**(-6)
t = 1.2
d2g = diff2(g, t)
print d2g
My question is, how does this script work without providing an argument to function g? The line in question is:
d2g = diff2(g,t)
Shouldn't it be done like:
d2g = diff2(g(t), t)
g is passed as an argument to diff2. In diff2, that argument is called f, so inside diff2 the name f refers to the function g. When diff2 calls f(x-h) (and the other calls it does), it is calling g, and providing the argument.
In other words, when you do diff2(g, t), you are telling diff2 that g is the function to call. The arguments to g are provided in diff2:
f(x-h) # calls g with x-h as the argument
f(x) # calls g with x as the argument
f(x+h) # calls g with x+h as the argument
If you called diff2(g(t), t), you would be passing the result of g(1.2) as the argument. g would be called before calling diff2, and diff2 would then fail when it tries to call f, because f would be a number (the value g(1.2)) instead of a function.
The functions in question are rather random, and perhaps difficult to understand. Let's consider a simple example, a function sum which takes two numbers a and b, and returns their sum. Actually, we can easily define another function prod, which returns their product too.
def sum(a,b):
return a + b
def prod(a,b):
return a * b
Let's say we have another function compute, which takes as its arguments the operation (a function), and two operands (two numbers to call the function on). In compute, we call the given operation on the arguments.
def compute(fn, a, b):
return fn(a, b)
We can compute different things. We can compute the sum of two numbers:
compute(sum, 1, 3)
We can compute the product of two numbers:
compute(prod, 1, 3)
Basically, without parentheses after the function name, we're not actually calling the function, it's just another object in the namespace (which happens to be a function which we can call). We don't call the function until inside of compute, when we do fn(a,b).
Let's see what the console outputs look like:
>>> compute(sum,1,3)
4
>>> compute(prod,1,3)
3
>>> sum
<function sum at mem-address>
>>> prod
<function prod at mem-address>
>>> sum(1,2)
3

Categories

Resources