Dynamic Python function parameter rerouting - python-3.x

I have a python function
func(a, b, c, d, e).
I want to pass this function to another function that evaluates it. The catch is that this other function only varies an arbitrary subset of the parameters (a, b, c, d, e), and the other parameters shall be preloaded with a constant. The parameter order may also change.
For example: I would like func_2 to vary a, c, and d, while b=3 and e=4. So I need a routine
def convert(func, variables=[3, 0, 2], constants=[1, 4], vals=[3, 4]):
...
python magic
...
return func_2
that converts:
func(a, b, c, d, e) -> func_2(d, a, c, b=3, e=4),
so that when I call func_2(1, 2, 3), what is actually called behind the scenes is func(2, 3, 3, 1, 4).
(This is for an optimization algorithm that operates on subspaces of a parameter space, and these subspaces can change from cycle to cycle. func is a cost function.)
How do I code convert in Python 3?

This works:
def convert(func, vars, fixed):
# vars: list of indices
# fixed: dictionary mapping indices to constants
n = len(vars) + len(fixed)
def func_2(*args):
newargs = [None] * n
for i, j in enumerate(vars):
newargs[j] = args[i]
for k in fixed:
newargs[k] = fixed[k]
return func(*newargs)
return func_2

Here you have a possible solution:
def convert(func, var, const, vals):
def func2(*args):
params = [args[var.index(i)] if i in var
else vals[const.index(i)]
for i in range(len(var)+len(const))]
return func(*params)
return func2
It works with any number of parameters

Related

python 'concatenate' requires extra parentheses

I'm trying to concatenate 3 lists. When I try to use concatenate, like so, I get an error (TypeError: 'list' object cannot be interpreted as an integer):
import numpy as np
a = [1]
b = [2]
c = [3]
z = np.concatenate(a, b, c)
But if I put "extra" parentheses, it works like so:
z = np.concatenate((a, b, c))
Why?
I am not sure what library you are using (concatenate is not a built-in python 3.x function). However, I'll explain what I think is going on.
When you call concatenate(a, b, c), the function concatenate is sent three parameters: a, b, and c. concatenate then performs some logic that is (presumably) not the desired behavior.
When you call concatenate((a, b, c)), a tuple (effectively a list that cannot be changed) is created with a value of (a, b, c), which is evaluated to ([1], [2], [3]). Then this tuple is passed to the concatenate function. The following code is actually equivalent to your second code snippet:
a = [1]
b = [2]
c = [3]
y = (a, b, c) # This evaluates to ([1], [2], [3]).
z = concatenate(y)
I hope I've explained this clearly enough. Here's an article that explains tuples in more depth, if I haven't: https://www.w3schools.com/python/python_tuples.asp
EDIT: Thanks for including the library. Here's the code for what you're probably trying to do:
import numpy as np
a = [1]
b = [2]
c = [3]
z = np.array(a + b + c) # Lists can be concatenated using the `+` operator. Then, to make a numpy array, just call the constructor

Why does Python 3 print statement appear to alter a variable, declared later in the code, but works fine without it?

I am running Python 3.6.2 on Windows 10 and was learning about the zip() function.
I wanted to print part of the object returned by the zip() function.
Here is my code, without the troublesome print statement:
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")
x = zip(a, b)
tup = tuple(x)
print(tup)
print(type(tup))
print(len(tup))
print(tup[1])
Here is my code with the troublesome print statement:
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")
x = zip(a, b)
print(tuple(x)[1])
tup = tuple(x)
print(tup)
print(type(tup))
print(len(tup))
print(tup[1])
The print(tuple(x)[1]) statement appears to change the tuple 'tup' into a zero-length one and causes the print(tup[1]) to fail later in the code!
In this line, you create an iterator:
x = zip(a, b)
Within the print statement, you convert the iterator to a tuple. This tuple has 3 elements. This exhausts the iterator and anytime you call it afterwards, it will return no further elements.
Therefore, upon your creation of tup, your iterator does not return an element. Hence, you have a tuple with length 0. And of course, this will raise an exception when you try to access the element with index 1.
For testing, consider this:
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")
x = zip(a, b)
tup1 = tuple(x)
tup2 = tuple(x)
print(tup1)
print(tup2)
It will give you the following result:
(('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
()
This is basically what you do when creating a tuple out of an iterator twice.

Search for sequence of items in a list

Is there an easy way to search for a sequence of strings in a list? For example:
testlist = [a,b,c,d,e,f,g,a,b,c,d,j,k,j]
and I want to search for the sequence abc and getting the index returned. So to clarify if the string I want to search consists of more than one element of the list. For some context: I have a list with datablocks and I want to find out how big each datablock is therefore searching for a reoccuring string in the list.
There are many good string search algorithms: KMP, Boyer-Moore, Rabin-Karp. You can use the builtin str.index function on ''.join(L) if you are dealing with characters (str.index implements Boyer-Moore algorithm in CPython: https://github.com/python/cpython/blob/3.7/Objects/stringlib/fastsearch.h).
But in most cases, the naive algorithm is good enough. Check every index of the haystack to find the needle:
>>> a, b, c, d, e, f, g, j, k = [object() for _ in range(9)]
>>> haystack = [a, b, c, d, e, f, g, a, b, c, d, j, k, j]
>>> needle = [a, b, c]
>>> for i in range(len(haystack)-len(needle)+1):
... if haystack[i:i+len(needle)] == needle:
... print(i)
...
0
7
The complexity is O(|haystack|*|needle|).

Transforming a Groovy Map

This is my Map
[a: 1, b: 1, c: 2, d: 2, e: 1, f: 2]
I want to group similar values and get:
[1: [a, b, e], 2: [c, d, f]]
My best effort is
myMap.groupBy{it.value}.collectEntries{key, value -> [(key): value.keySet()]}
Anything that is groov'ier?
The following code:
def result = [a: 1, b: 1, c: 2, d: 2, e: 1, f: 2].inject([:].withDefault {[]}) { a, k, v ->
a[v] << k
a
}
println result
prints:
[1:[a, b, e], 2:[c, d, f]]
this uses the groovy Map.inject method which is similar to foldLeft or reduce in other languages and the groovy Map.withDefault method so that when you access a map and a key is not found, a default value of empty list ([]) is returned.
Explanation:
.inject( - go through the map one key-value pair at a time
[:].withDefault {[]} - starting with an empty map which will return an empty list if you access a key that does not exist
) { a, k, v - for each key-value pair, do something with the initial map a
a[v] << k - specifically, add the incoming key as an element in a list (as returned by withDefault) contained in the map under key v.
a - return the modified map so that it is sent in as a in {a, k, v -> in the next iteration
What you have already is already simple and elegant. You can still refine it to
map.groupBy { it.value }.collectEntries { [it.key, it.value*.key ] }
to get the same result.

back solve for a variable using python

I'm trying to write a function to back solve for a variable from another function in python, kind of like what Excel solver does.
To simplify my example, I have a function takes in several variables then calculate a price. I will be passing actual values (a,b,c,d,x) into this function so it returns a numeric value.
def calc_price(a,b,c,d,x):
value = a+b*c-d + x
return value
Now I'm given a target price, and a,b,c,d. Only unknown is variable x, so I want to back solve variable x. I want to build this into a function that takes into the same variables as calc_price, with an additional variable target_price.
def solve(target_price, a,b,c,d):
#this function takes in values for target_price, a,b,c,d
#and should do something like this:
target_price = calc_price(a,b,c,d,x)
solve for x <---------this is the part I'm not sure how to do
return x
I created a function like this below to back solve the value x by a loop but it's inefficient in calculating large datasets, so I'm looking for a more efficient solution.
def solve(target_price,a,b,c,d):
x = 0.01
while x < 1:
if abs(target_price - calc_price(a,b,c,d,x)) < 0.001:
return x
x += 0.001
Thank you!
Consider this a demo (as your task is still a bit unclear to me) and make sure to read scipy's docs to learn about the basic guarantees these method provides.
One could argue, that an approach based on root-finding is more appropriate (we are minimizing a function here; therefore the abs-construction in the residual-function), but this approach here does not need you to give some bracketing-interval.
Code:
import numpy as np
from scipy.optimize import minimize_scalar
np.random.seed(0)
""" Utils """
def calc_price(x, a, b, c, d):
value = a+b*c-d + x
return value
def calc_price_res(x, target, a, b, c, d):
value = a+b*c-d + x
return abs(value - target) # we are looking for f(x) == 0
""" Create fake-data (typically the job of OP!) """
a, b, c, d, x = np.random.random(size=5)
fake_target = calc_price(x, a, b, c, d)
print('a, b, c, d: ', a, b, c, d)
print('real x: ', x)
print('target: ', fake_target)
print('noisy obj (just to be sure): ', calc_price_res(x, fake_target, a, b, c, d))
""" Solve """
res = minimize_scalar(calc_price_res, args=(fake_target, a, b, c, d))
print('optimized x: ', res.x)
print('optimized fun: ', res.fun)
Output:
a, b, c, d: 0.548813503927 0.715189366372 0.602763376072 0.544883182997
real x: 0.423654799339
target: 0.858675077275
noisy obj (just to be sure): 0.0
optimized x: 0.423654796297
optimized fun: 3.04165614917e-09

Resources