I am using python (3.7.3) with sympy (1.6.2) to store a function with squared terms and non-squared terms, with each term being the product of exactly two variables.
For example,
>> import sympy as sy
>> x = sy.Symbol('x')
>> y = sy.Symbol('y')
>> F = x*x+x*y
>> print(F)
x**2+x*y
I want to be able to iterate through the terms and get each operand.
For example,
terms = F.expand(basic=True).args
for term in terms
(t0,t1) = term.args
print('t0:{}, t1:{}'.format(t0,t1))
# do some stuff using t0, t1
This works for the x*y term, but not the x**2 term.
>> print((x*y).args)
(x,y)
>> print((x**2).args) # I want this to be (x,x)
(x,2)
I tried running (x**2).expand(), but this appears to be the fully expanded version of the expression.
My question is twofold:
is there a way to expand x**2 so that it is stored as x*x?
is there a better way to go about getting each operand in each term than the for loop I show above?
You could define a custom function that defactors in the way you want:
def get_factors(expr):
if expr.func == sy.Mul:
return expr.args
elif expr.func == sy.Pow:
return tuple(expr.args[0] for _ in range(expr.args[1]))
else:
raise NotImplementedError()
Usage:
>>> a, b = terms
>>> get_factors(a)
(x, x)
>>> get_factors(b)
(x, y)
Related
I read such a script:
add_numbers = lambda x, y: x+y
add_five = lambda y: add_numbers(5,y)
It derive a new function of one variable, add_five, that adds 5 to its argument:
from this point, introduced functools
In [9]: from functools import partial
In [10]: add_five = partial(add_numbers, 5)
In [11]: add_five(7)
Out[11]: 12
As a novice, I guess it can be easily achieved by
add_five = lambda y: 5+y
add_six = lambda y: 6+y
I am confused what's the benefit if not define add_five in a straighforward method?
The utility of partial is to easily create specialised versions of functions from a general definition.
The case of adding numbers can be illustrating here add_numbers is the general case.
from functools import partial
def add_numbers(x, y):
return x + y
add5 = partial(add_nums, 5)
Here add5 is a specialised case of add_numbers roughly equivalent to
def add5(x):
return add_numbers(x, 5)
Adding numbers is a very trivial example and does not show the utility of partial
The following is a simple example that may better show the utility of partial.
Consider writing a procedure to compute the square root of a number using the Babylonian method.
def square_root(x, tolerance, convergence_test):
y = 1
while not convergence_test(x, y, tolerance):
y = (y + x/y)/2
return y
For most numbers, the convergence test can simply check the difference between y squared and x is 0. Let's call this the absolute error of the estimate
def absolute_error(x, y, tolerance):
return abs(x - y**2) <= tolerance
For very large and small numbers, using absolute error of the estimate can lead to wrong answers for various reasons. In those cases, it is better to use the relative error:
def relative_error(x, y, tolerance):
return abs(x/(y**2) - 1) <= tolerance
With partial, we can easily create specialised functions for using the either absolute and relative error.
sqrt_rel_err = partial(square_root, convergence_test=relative_error)
sqrt_abs_err = partial(square_root, convergence_test=absolute_error)
Now using either is trivial
>>> sqrt_rel_err(2, 0.00001)
1.4142156862745097
>>> sqrt_abs_err(2, 0.00001)
1.4142156862745097
And for small numbers: we see using absolute error gives the wrong answer (especially when the tolerance is greater than the number we are trying to get the square root of)
>>> x = sqrt_abs_err(1e-6, 0.00001)
>>> x**2
4.4981362843183905e-06
Whilst the relative error method yields a more accurate answer.
>>> x = sqrt_rel_err(1e-6, 0.00001)
>>> x**2
1.0000003066033492e-06
I'm a coding newcomer and I'm trying to work with Bokeh. Newcomer to StackOverflow too, so please tell me if I did something wrong here.
I'm playing with this example from Bokeh website and I ran into a problem. When the x values are set, as in the example, using np.linspace, I'm able to use the interact and play with the update function. But, if I change x to a list, using range(), then I get this error: TypeError: can only concatenate list (not "float") to list. As I understand it, the problem lies in "x + phi", since x is a list and phi is a float.
I get that it's not possible to concatenate a list with a float, but why is it only when I use a numpy.ndarray that Python understands that I want to modify the function that controls the y values?
Here is the code (I'm using Jupyter Notebook):
x = np.linspace(0,10,1000)
y = np.sin(x)
p = figure(title="example", plot_height=300, plot_width=600, y_range=(-5,5))
r = p.line(x, y)
def update(f, w=1, A=1, phi=0):
if f == "sin": func = np.sin
elif f == "cos": func = np.cos
elif f == "tan": func = np.tan
r.data_source.data["y"] = A * func(w * x + phi)
push_notebook()
show(p, notebook_handle=True)
interact(update, f=["sin", "cos", "tan"], w=(0,100), A=(1,5), phi=(0,20, 0.1))
Yes, please compare your numpy documentation with the documentation of lists: https://docs.python.org/3.6/tutorial/datastructures.html
You can also play with the following code:
from numpy import linspace
a = linspace(2, 3, num=5)
b = range(5)
print(type(a), a)
print(type(b), b)
print()
print("array + array:", a + a)
print("list + list:", b + b)
print(a + 3.14159)
print(b + 2.718) # will fail as in your example, because it is a list
My advise is to not mix lists and arrays if there is no other good reason to do so. I personally often cast function arguments to arrays if necessary:
def f(an_array):
an_array = numpy.array(an_array)
# continue knowing that it is an array now,
# being aware that I make a copy of an_array at this point
I want to receive input from a user, parse it, then perform some substitutions on the resulting expression. I know that I can use sympy.parsing.sympy_parser.parse_expr to parse arbitrary input from the user. However, I am having trouble substituting in function definitions. Is it possible to make subsitutions in this manner, and if so, how would I do so?
The overall goal is to allow a user to provide a function of x, which is then used to fit data. parse_expr gets me 95% of the way there, but I would like to provide some convenient expansions, such as shown below.
import sympy
from sympy.parsing.sympy_parser import parse_expr
x,height,mean,sigma = sympy.symbols('x height mean sigma')
gaus = height*sympy.exp(-((x-mean)/sigma)**2 / 2)
expr = parse_expr('gaus(100, 5, 0.2) + 5')
print expr.subs('gaus',gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus'),gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus')(height,mean,sigma),gaus) # prints 'gaus(100, 5, 0.2) + 5'
# Desired output: '100 * exp(-((x-5)/0.2)**2 / 2) + 5'
This is done using python 2.7.9, sympy 0.7.5.
You can use the replace method. For instance
gaus = Function("gaus") # gaus is parsed as a Function
expr.replace(gaus, Lambda((height, mean, sigma), height*sympy.exp(-((x-mean)/sigma)**2 / 2)))
replace also has other options, such as pattern matching.
After some experimentation, while I did not find a built-in solution, it was not difficult to build one that satisfies simple cases. I am not a sympy expert, and so there may be edge cases that I haven't considered.
import sympy
from sympy.core.function import AppliedUndef
def func_sub_single(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand an instance of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub_single(linear(2, 1), linear(m, b), m*x+b) # returns 2*x+1
"""
# Find the expression to be replaced, return if not there
for unknown_func in expr.atoms(AppliedUndef):
if unknown_func.func == func_def.func:
replacing_func = unknown_func
break
else:
return expr
# Map of argument name to argument passed in
arg_sub = {from_arg:to_arg for from_arg,to_arg in
zip(func_def.args, replacing_func.args)}
# The function body, now with the arguments included
func_body_subst = func_body.subs(arg_sub)
# Finally, replace the function call in the original expression.
return expr.subs(replacing_func, func_body_subst)
def func_sub(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand all instances of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub(linear(linear(2,1), linear(3,4)),
linear(m, b), m*x+b) # returns x*(2*x+1) + 3*x + 4
"""
if any(func_def.func==body_func.func for body_func in func_body.atoms(AppliedUndef)):
raise ValueError('Function may not be recursively defined')
while True:
prev = expr
expr = func_sub_single(expr, func_def, func_body)
if prev == expr:
return expr
I'm looking for an example of operations with logarithms in Python. I've tried with sympy and numpy and I still can't do what I want. For example, for an input like this:
log(x+1)+log(4-x)=log(100) # it's just an example
the output should give me the x value. I need to do this with any other functions like log(x+1)=4 or log(x)-log(x+1)=log(x).
Is there some method or somewhere (documentation or similar) where can I find how to do this?
I may be misunderstanding what you need to do because you said you tried sympy already. However, it looks like you just want to solve for x in an algebraic equation.
Solving for x in the equation
log(x+1)+log(4-x)=log(100)
using sympy would be
>>> from sympy import Symbol, solve, log
>>> x = Symbol('x')
>>> solve(log(x+1) + log(4-x) - log(100), x)
[3/2 - 5*sqrt(15)*I/2, 3/2 + 5*sqrt(15)*I/2]
If you want, you can check that these two solutions are correct with numpy.
>>> import numpy as np
>>> a = 3/2 - 5*np.sqrt(15)*1j/2
>>> b = 3/2 + 5*np.sqrt(15)*1j/2
>>> np.log(a + 1) + np.log(4-a)
(4.6051701859880918+0j)
>>> np.log(b + 1) + np.log(4-b)
(4.6051701859880918+0j)
>>> np.log(100)
4.6051701859880918
Is that not what you are looking for?
Since log is a non-linear function, you will need to use a non-linear solver like scipy.optimize.fsolve. It take in a function and a guess value and returns the answer in the form of an array. For simplicity reason, I defined the function as a lambda function since we don't need it outside of this line, but creating a function using standard def methods would work as well. The [0] on the back end get the value out of the array to return just the float.
import scipy.optimize
import math
scipy.optimize.fsolve(lambda x: math.log(x+1) - 4, 5)[0] # 5 is guess value
>>> 53.598
# Check
math.exp(4) - 1
>>> 53.598
Good advice already given. I just note that you can also check the answer in SymPy.
>>> L, R = log(x+1)+log(4-x), log(100)
>>> eq = Eq(L, R)
>>> eq
log(-x + 4) + log(x + 1) == log(100)
>>> sol = solve(eq)
>>> [eq.subs(x, i) for i in sol]
[True, True]
So in the Eq form the solutions were verified automatically. This is not always
true but you can use numerical evaluation to check the value:
>>> f = eq.lhs - eq.rhs; f
log(-x + 4) + log(x + 1) - log(100)
>>> f.subs(x, sol[0])
-log(100) + log(5/2 - 5*sqrt(15)*I/2) + log(5/2 + 5*sqrt(15)*I/2)
>>> _.n()
0.e-124 + 0.e-125*I
>>> f.subs(x, sol[0]).n(chop=True) # the small numbers can be chopped
0
I want to have some sort of reference to a function but I do not know if I need to use a def f(x) or a lambda of some kind.
For instance I'd like to print f(3) and have it output 9a, or is this not how python works?
Second question: Assuming I have a working function, how do I return the degree of it?
To create a function, you define it. Functions can do anything, but their primary use pattern is taking parameters and returning values. You have to decide how exactly it transforms parameters into the return value.
For instance, if you want f(x) to return a number, then a should also be a numeric variable defined globally or inside the function:
In [1]: def f(x):
...: a = 2.5
...: return a * x**2
...:
In [2]: f(3)
Out[2]: 22.5
Or maybe you want it to return a string like this:
In [3]: def f(x):
...: return str(x**2) + 'a'
...:
In [4]: f(3)
Out[4]: '9a'
You have to specify your needs if you need more help.
EDIT: As it turns out, you want to work with polynomials or algebraic functions as objects and do some algebraic stuff with them. Python will allow doing that, but not using standard data types. You can define a class for a polynomial and then define any methods or functions to get the highest power or anything else. But Polynomial is not a built-in data type. There may be some good libraries defining such classes, though.
Python (and most other computer languages) don't do algebra, which is what you'll need if you want symbolic output like this. But you could have a function f(a,x) which returns the result for particular (numerical) values of a:
def f(a, x):
return a*x*x
But if you want a program or language which actually does algebra for you, check out sympy or commercial programs like Mathematica.
If you are just working with polynomials, and you just need a data structure which deals well with them, check out numpy and its polynomial class.
I normally use lambda for short and simple functions:
f = lambda a, x: a * x**2
here a and x are parameters of my function. You need to enter a and x
f(2,4)
If you want a as a constant parameter eg. a=2:
f = lambda x: 2 * x**2
f(5)
if you have a list of input values of x, you can combine map with lambda.
it is straighforward and easily readable.
(*map(lambda x: 3 * x**2, [1,2,3,4]),)
or
list(map(lambda x: 3 * x**2, [1,2,3,4])
cheers!
def func():
print "F(x) = 2x + 3"
x = int(raw_input('Enter an integer value for x: '))
Fx = 2 * x + 3
return Fx
print func()
have fun :)
Cheese,
you can use the def function in Python to create a math function, you could type this:
def f(x):
return(2x + (3 + 3) * 11 + 88) # <- you could make your own function.
print(f(3))
Log:
220
Like THAT
or in this:
def f(a, x):
return((a + x) ** (a * x))
then...
print(f(1, 2))
Log...
6