python 'concatenate' requires extra parentheses - python-3.x

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

Related

How to iterate a dynamic nested loop over a particular values as its range, in python?

If I take a boolean expression and number of input variables from user, then how can I evaluate the expression (to create its truth table) by using dynamic nested loops instead of doing it like this:
expression= "a and (b or a)"
inputs=2
if inputs==2:
for a in range(0,2):
for b in range(0,2):
x = eval(expression)
print(a,b,x)
if inputs==3:
for a in range(0,2):
for b in range(0,2):
for c in range(0,2):
x = eval(expression)
print(a,b,x)
It limits the number of variables user can evaluate expression on, as I can not write loops manually. I tried using itertools.product() for this, but I don't know how to give values to the iterating variables.
from itertools import product
variables=['a','b','c']
for items in product(*variables):
rows=(eval(expression))
print(rows)
As you can see, it obviously gives error that a,b,c are undefined in eval(expression). How can I iterate each one of them over [0,1] ?
You could do it using itertools.product() simply
import itertools
inputs = int(input())
temp = [[0, 1]] * inputs
for combination in itertools.product(*temp):
print(combination)
I think you were on the right path here and itertools.product() is what you are looking for. The following is a one-liner, but you could expand it if you want. Note that I am not using eval, but rather a list comprehension paired with the already mentioned itertools.product(). Note also that you can use and, or and () in normal code.
import itertools
rows = [a and (b or c) for a, c, b in itertools.product([True, False], [True, False], [True, False])]
print(rows)
If you are using user input, it might make sense to define truthy values.
Also if you want the inputs for the truth-table, you can also do this first:
import itertools
inputs = [[a, b, c] for a, b, c in itertools.product([True, False], [True, False], [True, False])]
rows = [a and (b or c) for a, c, b in inputs]
print(rows)
Edit: If you have a lot of inputs, the logical expression would likely include any() and all().
Edit2: Now I understand what you mean. Here is a full version with a dynamic number of inputs using the above-mentioned any() and all(). In this example of a logical condition, the first half of the array (rounded down if it is an uneven length) needs to be true and at least one of the second half. Feel free to adapt the expression as you see fit. Note that your original expression does not make much sense. If the first part a is Truthy then the second part where you check for a or b is necessarily also Truthy because we already checked for a. That is why I picked a slightly modified version.
import itertools
input_num = int(input())
arrs = [[False, True]] * input_num
inputs = [x for x in itertools.product(*arrs)]
rows = [all(x[:int(len(x)/2)]) and any(x[int(len(x)/2):]) if len(x) > 1 else bool(x) for x in inputs ]
print(rows)

Python assigning variables with an OR on assignment, multiple statements in one line?

I am not super familiar with python, and I am having trouble reading this code. I have never seen this syntax, where there multiple statements are paired together (I think) on one line, separated by commas.
if L1.data < L2.data:
tail.next, L1 = L1, L1.next
Also, I don't understand assignment in python with "or": where is the conditional getting evaluated? See this example. When would tail.next be assigned L1, and when would tail.next be assigned L2?
tail.next = L1 or L2
Any clarification would be greatly appreciated. I haven't been able to find much on either syntax
See below
>>> a = 0
>>> b = 1
>>> a, b
(0, 1)
>>> a, b = b, a
>>> a, b
(1, 0)
>>>
It allows one to swap values without requiring a temporary variable.
In your case, the line
tail.next, L1 = L1, L1.next
is equivalent to
tail.next = L1
L1 = L1.next
In python when we write any comma separated values it creates a tuple (a kind of a datastructure).
a = 4,5
type(a) --> tuple
This is called tuple packing.
When we do:
a, b = 4,5
This is called tuple unpacking. It is equivalent to:
a = 4
b = 5
or is the boolean operator here.

Manipulating sympy expression trees

Lets say, we have a sympy function cos(x). Every function can be
presented by a tree, e.g. like the image here https://reference.wolfram.com/language/tutorial/ExpressionsAsTrees.html
I want to insert a parameter into every node of this expression tree, that means
cos(x) -> a*cos(b*x)
For more complicated expression, it should look like
(exp(x)+cos(x)*x)/(x) -> h*(b*exp(a*x)+f*(c*cos(d*x)*e*x))/(j*x)
where a,b,c,d,e,f,g,h,j are parameters, that I want to fit.
A helpful source could be https://docs.sympy.org/latest/tutorial/manipulation.html in the chapter "walking the tree". I tried to replace parts of the
expr.args
tuple, but it is not possible.
This is the expression:
from simply import symbols, exp, cos
x, y = symbols('x y')
expr = (exp(x)+cos(x)*y)/(x)
This might get you started:
>>> s = numbered_symbols('C')
>>> cform = ((exp(x)+cos(x)*x)/(x)).replace(
... lambda x:not x.is_Number,
... lambda x:x*next(s))
>>> cform
C1*C8*C9*(C2*C4*C5*x*cos(C3*x) + C7*exp(C6*x))/(C0*x)
>>> from sympy.solvers.ode import constantsimp, constant_renumber
>>> constantsimp(cform, [i for i in cform.atoms(Symbol) if i.name.startswith('C')])
C0*(C2*x*cos(C3*x) + C7*exp(C6*x))/x
>>> constant_renumber(_)
C1*(C2*x*cos(C3*x) + C4*exp(C5*x))/x
>>> eq = _
>>> cons = ordered(i for i in eq.atoms(Symbol) if i.name.startswith('C'))
>>> eq.xreplace(dict(zip(cons, var('a:z'))))
a*(b*x*cos(c*x) + d*exp(e*x))/x

Python reduce & Lambda with multiple params

Is There any way by which I could use 3 variables in reduce(lambda f) combination like
reduce(lambda a, b, c : a*b+c, <list_for_a&b>, <range_for_c>)
I can use map() function. But thought of knowing a new possibility, if any.
You can zip the two sequences and them work on the result.
values_for_a_and_b = ... # I assume this is a list of tuples
values_for_c = ... #
product = zip(values_for_a_and_b, values_for_c) # This gives a list like [((a, b), c)]
Now it looks like you're trying to do a map, rather than a reduce.
You can use the product as follows:
map(lambda x: x[0][0] * x[0][1] + x[1], product)
But since Python doesn't have pattern matching, it's not really elegant.

Lambdify A Parametric Integral

I have the following issue: I want to lambdify a sympy expression containing parametric integrals like Integral(tanh(a*x),(x,0,1)). I tried to do a manual implementation like here.
What we want is essentially that the integral gets converted to something like:
lambda theta: quad(lambda x: g(x,theta), a,b)[0]
where
g = sp.lambdify((x,param), f, modules='numpy'))
Consider the following MWE:
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = function.free_symbols - {x}
f = sp.lambdify( (x,*param), function, modules='numpy')
return lambda y: quad(lambda x: f(x,y), a,b)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x),(x,0,1))
K = integral_as_quad(sp.tanh(a*x),(x,0,1))
L = sp.lambdify(a, I, modules=['numpy', {'Integral':integral_as_quad}] )
Then calling for example K(1) returns the correct value. However L(1) gives
AttributeError: 'Mul' object has no attribute 'tanh'
Does anyone have an idea how to fix this?
NOTE: Doing it manually is no option, since the expressions I deal with are way more complicated and may contain several different integrals. So I really need to get the lambdify working.
I think returning a lambda from integral_as_quad cannot work, because this lambda will never be called, as the Integral object in SymPy is not callable. Instead, the parameter tuple can be passed to quad via its args argument. Another change I made is in the outer lambdification, replacing
modules=['numpy', {'Integral':integral_as_quad}]
with
modules=[{'Integral': integral_as_quad}, 'sympy']
The idea is that at this stage we don't need NumPy functions yet, we just want to replace the Integral by our callable. The order of modules list matters: the dictionary comes first to prevent SymPy from keeping Integral as an Integral.
Now L(1) returns the correct amount.
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = tuple(function.free_symbols - {x})
f = sp.lambdify((x, *param), function, modules=['numpy'])
return quad(f, a, b, args=param)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x), (x,0,1))
L = sp.lambdify(a, I, modules=[{'Integral': integral_as_quad}, 'sympy'])
So one possible workaround I have found, but I am unhappy with because it is too slow for my application, is the following:
def to_lambda(expr, param):
# Preprocessing
expr = expr.evalf()
f = sp.lambdify([param], expr, modules='sympy')
fun = lambda x: np.array(np.array(f(x).evalf()), dtype='float64')
return fun
So first, expr gets cast into a lambda function using sympy-functions, e.g. we have
f = lambda a: Integral(tanh(a*x),(x,0,1))
and then we use sympy's internal integrator via evalf() (slow!).
Also, don't ask me why theres the double np.array, if one puts the dtype='float64' into the first one, then it returns TypeError: __array__() takes 1 positional argument but 2 were given

Resources