Sum with index as derivative order - python

I want to define a sum that contains derivatives of a function, where the summation index is the derivative order.
Simple example:
x, i = symbols("x i")
f = Function("f")(x)
Sum(diff(f,x,i), [i,1,3])
However, this only returns a sum of zeros. I assume this is because it tries to differentiate f wrt x first, and then wrt i. Since f is not a function of i, it evaluates to zero before it is processed by the Sum function. What I want to happen is
diff(f,x,1)
diff(f,x,2)
diff(f,x,3)
etc.
Is there a way to make this work?

sympy.diff(f,x,i) is equivalent to i'th order derivative of f only if i is an integer. In your case it is a symbol.
Use instead the builtin sum() along with a generator expression:
>>> sum(diff(f,x,j) for j in range(1,4))
Derivative(f(x), x) + Derivative(f(x), x, x) + Derivative(f(x), x, x, x)

Related

Filter the terms of a trigonometric SymPy expression, keeping those with a given coefficient

Let us suppose that we have an expression:
x*sin(y) + y*cos(x) + x*cos(z)
From the above expression, I want to obtain a new polynomial, having only the terms with the coefficient x, namely:
x*sin(y) + x*cos(z)
or
x*(sin(y) + cos(z))
Clearly, setting y=0 is not a solution, since x*sin(y) would become 0. How to filter the terms of a polynomial in SymPy to choose only terms with some give coefficient?
I think you're looking for collect.
collect(x*sin(y) + x*cos(z) + y*cos(x), x, evaluate=False)
will return
{x: sin(y) + cos(z), 1: y*cos(x)}
To begin with, this is not a trigonometric polynomial. Trigonometric polynomials have constant coefficients in front of cosines and sines.
With expr.coeff(x) you can get the terms that have x as a factor: that is sin(y) + cos(z).
But if the expression was x**3*sin(y) + y*cos(x) + x*cos(z) then only cos(z) would be returned. Maybe this is what you want. But if the desired result for this example is x**3*sin(y) + x*cos(z), then use
Add(*[v for v in expr.args if v.is_polynomial(x) and v.has(x)])
The logic is to filter the tuple of summands expr.args by the conditions that a term is a polynomial in x, and is a nonconstant polynomial. (Assuming you don't want to include constants).

Factoring a SymPy expression into groups that involve one symbol only

Suppose I have an expression in sympy that only consists of a single term. This expression either has subexpressions that depend on a symbol x, on a symbol y, or on neither x nor y. I would like sympy to return three expressions, the first depends only on x, the second only on y, and the third on neither, such that the product of the three expressions is the original expression. E.g.
expr = x^2*cos(x)*2/sin(y)/y
should return x^2 * cos(x) and 1/sin(y)/y and 2. Is this possible?
In general, this is impossible: for example, sqrt(x+y) cannot be separated into a function of x times a function of y. But when factorization is possible, the method as_independent can help in finding it:
expr = x**2*cos(x)*2/sin(y)/y
temp, with_x = expr.as_independent(x, as_Mul=True)
const, with_y = temp.as_independent(y, as_Mul=True)
print((with_x, with_y, const))
prints (x**2*cos(x), 1/(y*sin(y)), 2)
With the hint as_Mul, the method is trying to separate the expression into a factor that does not depend on the given variable, and the rest. So, the first step isolates a term without x (called temp), from which the second step isolates a term without y (constant).
Such a thing can also be done for sums instead of products, with the hint as_Add=True.
Assuming you have a single term expr made up by multiplying terms in x, y and other symbols or constants you can do something like below:
from sympy import sin, cos, Mul, init_printing
from sympy.abc import x,y
init_printing()
expr = x**2*cos(x)*2/sin(y)/y
def splitXYC(expr):
xterm = Mul(*[t for t in expr.args if t.has(x)])
yterm = Mul(*[t for t in expr.args if t.has(y)])
others = Mul(*[t for t in expr.args if not (t.has(x) or t.has(y)) ])
return xterm, yterm, others
X,Y,C = splitXYC(expr)
print(X) # Prints x**2*cos(x)
print(Y) # Prints 1/(y*sin(y))
print(C) # Prints 2
Is this as you wanted?

Sum of squares using lambda functions

I am thinking of different ways to take the sum of squares in python. I have found that the following works using list comprehensions:
def sum_of_squares(n):
return sum(x ** 2 for x in range(1, n))
But, when using lambda functions, the following does not compute:
def sum_of_squares_lambda(n):
return reduce(lambda x, y: x**2 + y**2, range(1, n))
Why is this?
Think about what reduce does. It takes the output of one call and uses it as the first argument when calling the same function again. So imagine n is 4. Suppose you call your lambda f. Then you are doing f(f(1, 2), 3). That is equivalent to:
(1**2 + 2**2)**2 + 3**2
Because the first argument to your lambda is squared, your first sum of squares will be squared again on the next call, and then that sum will be squared again on the next, and so on.
You're only supposed to square each successive element. x**2 + y**2 squares the running total (x) as well as each successive element (y). Change that to x + y**2 and you'll get the correct result. Note that, as mentioned in comments, this requires a proper initial value as well, so you should pass 0 as the optional third argument.
>>> sum(x ** 2 for x in range(5,15))
985
>>> reduce(lambda x, y: x + y**2, range(5,15))
965
>>> reduce(lambda x, y: x + y**2, range(5,15), 0)
985
Suppose you plug in 4:
1^2 + 2^2 = 5 (you then take this result and put it back in the lambda)
5^2 + 3^2 = 34 (for reference the correct answer is 14)
It squares the "previous" sum as well in the lambda.
(You also have an off by one issue, it should be n+1 in your range calls.)
(for python 3 users)
from functools import reduce
To be able to use reduce.
Second, your function sum_of_squares_lambda won't work the way you expect it to because reduce will take twice (instead of once) every argument except the first and the last one.

How can I create functions that handle polynomials?

I have these problems about polynomials and I've spent about 4 hours on this, but I just can't get it. I'm new to Python and programming and I've tried working it out on paper, but I just don't know.
Write and test a Python function negate(p) that negates the polynomial represented by the list of its coeffeicients p and returns a new polynomial (represented as a list). In other words, write a function that makes the list of numbers negative.
Write a Python function eval_polynomial(p, x) that returns the value of P(x), where P is the polynomial represented by the list of its coefficients p. For example, eval_polynomial([1, 0, 3], 2) should return 1*2^2 + 0*2 + 3 = 7. Use a single while loop.
Write and test a function multiply_by_one_term(p, a, k) that multiplies a given polynomial p, represented by a list of coefficients, by ax^k and returns the product as a new list.
I would really appreciate it if someone could help me.
I'd recommend using numpy.poly1d and numpy.polymul, where the coefficients are a0*x2 + a1*x + a2.
For example, to represent 3*x**2 + 2*x + 1:
p1 = numpy.poly1d([3,2,1])
And with the resulting poly1d object you can operate using *, / and so on...:
print(p1*p1)
# 4 3 2
#9 x + 12 x + 10 x + 4 x + 1
If you want to build your own functions, assuming that p contains the coefficients in order: a0 + a1*x + a2*x**2 + ...:
def eval_polynomial(p,x):
return sum((a*x**i for i,a in enumerate(p)))
def multiply_by_one_term(p, a, k):
return [0]*k + [a*i for i in p]
Note
My evaluate function uses exponentials, which can be avoided with Horner's rule, as posted in another answer, which is available in Numpy's polyval function
Please use Horner's Method instead!
For polynomials, you should consider Horner's Method. Its main feature is that computing a polynomial of order N requires only N multiplies and N additions -- no exponentials:
def eval_polynomial(P, x):
'''
Compute polynomial P(x) where P is a vector of coefficients, highest
order coefficient at P[0]. Uses Horner's Method.
'''
result = 0
for coeff in P:
result = x * result + coeff
return result
>>> eval_poly([1, 0, 3], 2)
7
You can work through it by hand, or follow the link to see how it works.

Python lambda function

What is happening here?
reduce(lambda x,y: x+y, [x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0])
I understand how x is iterating through all of the numbers from 1 to 999 and taking out those that are divisible by 3 or 5, but the 'lambda x,y: x+y' part is stumping me.
This is bad Python for
sum(x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0)
It simply sums all numbers in the range 1..999 divisible by 3 or 5.
reduce() applies the given function to the first two items of the iterable, then to the result and the next item of the iterable, and so on. In this example, the function
lambda x, y: x + y
simply adds its operands.
saying
f = lambda x, y : x + y
is almost the same as saying
def f(x, y):
return x + y
in other words lambda returns a function that given the parameters to the left of the : sign will return the value of the expression on the right of it.
In respect to a function is however quite limited, for example allows only one expression and no statements are allowed. This is not a serious problem however because in Python you can define a full function even in the middle of another function and pass that instead.
The usage you shown is however quite bad bacause a lambda there is pointless... Python would allow to compute that sum directly instead of using reduce.
Also, by the way, for the result of that computation there is an easy closed-form solution that doesn't require any iteration at all... (hint: the sum of all numbers from 1 to n is n*(n+1)/2 and the sum of all multiples of 5 from 5 to n is 5*(sum of all numbers from 1 to n/5) ... therefore ...)
A lambda designates an anonymous function. The syntax lambda x,y: x+y can be stated in English as "declare a nameless function taking two parameters named x and y. Perform the operation x+y. The return value of this nameless function will by the result of this operation"
reduce applies some function sequentially to the first two elements of a supplied list, then to the result of that function and the third element, and so on. Therefore, the lambda in the supplied code is used by reduce to add together the elements of the supplied list, which will contain all of the multiples of 3 and 5 less than 1000.

Categories