Sympy solver bug in a for loop? - python-3.x

So I'm playing with Sympy in an effort to build a generic solver/generator of physics problems. One component is that I'm going for a function that will take kwargs and, according to what it got, rearrange the equation and substitute values in it. Thanks to SO, I managed to find the things I need for that.
However..... I've tried putting sympy.solve in a for loop to generate all those expressions and I've ran into.... something.
import sympy
R, U, I, eq = sympy.symbols('R U I eq')
eq = R - U/I
for x in 'RUI':
print(x)
print(sympy.solve(eq, x))
The output?
R
[U/I]
U
[I*R]
I
[]
However, whenever I do sympy.solve(eq, I) it works and returns [U/R].
Now, I'm guessing the issue is with sympy using I for imaginary unit and with variable hiding in blocks, but even when I transfer the symbol declaration inside the for loop (and equation as well), I still get the same problem.
I'm not sure I'll need this badly in the end, but this is interesting to say the least.

It's more like an undocumented feature than a bug. The loop for x in 'RUI' is equivalent to for x in ['R', 'U', 'I'], meaning that x runs over one-character strings, not sympy symbols. Insert print(type(x)) in the loop to see this. And note that sympy.solve(eq, 'I') returns [].
The loop for x in [R, U, I] solves correctly for each variable. This is the right way to write this loop.
The surprising thing is that you get anything at all when passing a string as the second argument of solve. Sympy documentation does not list strings among acceptable arguments. Apparently, it tries to coerce the string to a sympy object and does not always guess your meaning correctly: works with sympy.solve(eq, 'R') but not with sympy.solve(eq, 'I')

The issue is that some sympy functions "accidentally" work with strings as input because they call sympify on their input. But sympify('I') gives the imaginary unit (sqrt(-1)), not Symbol('I').
You should always define your symbols explicitly like
R, U, I = symbols("R U I")
and use those instead of strings.
See https://github.com/sympy/sympy/wiki/Idioms-and-Antipatterns#strings-as-input for more information on why you should avoid using strings with SymPy.

Related

Most beautiful way of chaining a list of functions in python/numpy

I have a list of numpy functions
fcts = [lambda x : np.power(x,2),np.sqrt,lambda x : np.add(x,3.)]
that I want to apply to an input x by chaining, i.e.
np.power(np.sqrt(np.add(x,3.)),2)
(or the other way around)
Is there an intrinsic numpy function for that or what is the most elegant/fastest way to do that (for a large list of functions) instead of
input = np.random.uniform(0,1,(2,3))
for fct in fcts:
input = fct(input)
Edit:
Numpy is written in C++ and I am wondering, wether there is any 'loss in speed' when the results are converted to python between the functions (and assigned to the variable input).
Here, reduce() from the functools module can do the trick, although I believe the underlying behaviour is pretty close to what you did.
import functools
functools.reduce(lambda o, func: func(o), fcts , input_object)

Using `functools.partial` and `map` with built-in `getattr`?

I apologize if am completely missing something obvious or if I have not dug into the documentation hard enough, but after 30 mins or so I found a work around (without having understood the error I was getting) and ... hence the question here. Suppose I have a class:
class RGB(object):
def __init__(self, r, g, b):
super(RGB, self).__init__()
self.red = r
self.blue = b
self.green = g
and I define a list of RGB instances as follows:
from random import random
rr, gg, bb = [[random() for _ in range(20)] for _ in range(3)]
list_of_rgbs = [RGB(*item) for item in zip(rr, gg, bb)]
why can't I extract a list of red values by doing:
from functools import partial
*reds, = map(partial(getattr, name="red"), list_of_rgbs)
or
*reds, = map(partial(getattr, "red"), list_of_rgbs)
I know I can make it do what I want by saying reds = [x.red for x in list_of_rbgs] but that would be difficult if the list of attributes to extract comes from elsewhere like: attribs_to_get = ['red', 'blue']. In this particular case I can still do what I want by:
reds, blues = [[getattr(x, attrib) for x in list_of_rgbs] for attrib in attribs_to_get]
but my question is about what causes the error. Can someone explain why, or how to make it work using partial and map? I have a hunch it has something to do with this behavior (and so maybe the partial function needs a reference to self?) but I can't quite tease it out.
For reference I was on Python 3.7.
Partial can only set positional arguments starting at the first argument. You can't set the second argument as positional, but only as a keyword argument. As the first one for getattr is the object, it won't work well together with map and partial.
What you can use however is operator.attrgetter():
from operator import attrgetter
*reds, _ = map(attrgetter("red"), list_of_rgbs)

How to pass in element into For-loop to run a function

It's been a while since I have asked a questions but I am needing help with what I think is a simple task.
I have a list of string values which I have passed into a loop. Each one of the strings pertains to a function of a parent package (in this case, QuantStats).
Code appears as follows:
import QuantStats as qs
list = ['avg_loss', 'avg_gain', 'best']
for l in list:
(>>) print(l)
(>>) print(qs.stats.l(df['returns']) (Error here - 'l' not recognised. no output)
For some reason the qs.stats.l line does not work. I am not sure how to reference each element in the list, such that the qs function can run.
Hopefully there is a simple work around? Any thoughts would be very much appreciated :) thanks.
Use the getattr() function to get the defined function. Like this:
import QuantStats as qs
list = ['avg_loss', 'avg_gain', 'best']
for l in list:
(>>) print(l)
(>>) print(getattr(qs.stats,l)(df['returns'])
I think you entered 1 instead of i ,
It should be (for i in List:)

How do I integrate a function that returns a value in terms of another symbol

I am currently trying to integrate a function using scipy.integrate.quad, but my function has two variables, the first is x, which is a variable being integrated out, and the second is G, which I am trying to solve for after the integration is complete.
I've already tried to use sympy.integrate which supports the integration of symbols, but my integral is too complex to be evaluated.
An example of the integral I am trying to solve is shown here:
C = integrate.quad(lambda x: x/(1+(3*G)*x)
I want to be able to evaluate the integral so that I could then solve for G because C is a constant value.
I expect the output to be some function of G that I can then use to solve for G, but I can't figure out how to integrate the function without previously defining G.
First note what your ultimate goal is: solve the equation f(G)==C, where f() is a function of a single argument. Now, it so happens that your f is the result of the integration with respect to a second variable. Therefore, simply define a single-argument function that computes this integral as follows:
def f(G):
return quad(lambda x: x/(1+(3*G)*x), 0, 10)[0]
and call scipy.optimize.root_scalar to solve the equation (with C==1 in this example)
root_scalar(lambda G: f(G)-1, x0=2, bracket = [0,5])
converged: True
flag: 'converged'
function_calls: 10
iterations: 9
root: 3.1734489114921782

Find all possible variations of a string of letters

Newb programmer here, I'm most familiar with Python but also learning C and Java, so either of 3 would be fine.
What I have is a string of letters, say:
ABXDEYGH
However say,
X is possible to be M and N.
Y is possible to be P and Q.
In this example, I would like basically to print all possible variations of this string of letters.
Like:
ABMDEPGH
ABNDEPGH
ABMDEQGH
ABNDEQGH
Any help would be appreciated. Thanks in advance
This boils down to a simple problem of permutations. What you care about is the part of the text that can change; the variables. The rest can be ignored, until you want to display it.
So your question can be more simply stated: What are all the possible permutations of 1 item from set X and another item from set Y? This is known as a cross-product, sometimes also simply called a product.
Here's a possible Python solution:
import itertools
x = set(['M', 'N'])
y = set(['P', 'Q'])
for items in itertools.product(x, y)
print 'AB{0}DE{1}GH'.format(*items)
Note that the print ''.format() command uses the "unpack arguments" notation described here.
why dont you write two loops. one to replace all possible characters with X and one for Y.
foreach(char c in charSet1){
// replaces X
foreach(char ch in charSet2){
// replace Y
}
}

Resources