Initialize a variable number of sympy symbols - sympy

Whenever you want to work with the python package sympy, a package for symbolic calculation, you need to initialize the variables as
x, y, z = symbols('x y z')
For my application, the number of symbols, that I need, is not fixed. I only have the information, that I have to calculate with e.g. 4 variables.
Is there a smart way to write to e.g. initialize
a,b,c = symbols('a b c')
when I need three variables and
a,b,c,d,e = symbols('a b c d e')
when I need five variables?
In case, that I need more variables than letters in the alphabet,
the function should start to initialize
aa, ab, ac,... .

You can use slice notation in symbols to create numbered symbols like
In [16]: symbols('a1:100')
Out[16]:
(a₁, a₂, a₃, a₄, a₅, a₆, a₇, a₈, a₉, a₁₀, a₁₁, a₁₂, a₁₃, a₁₄, a₁₅, a₁₆, a₁₇, a₁₈, a₁₉, a₂₀, a₂₁, a₂₂, a₂₃, a₂₄, a₂₅, a₂₆, a₂₇, a
₂₈, a₂₉, a₃₀, a₃₁, a₃₂, a₃₃, a₃₄, a₃₅, a₃₆, a₃₇, a₃₈, a₃₉, a₄₀, a₄₁, a₄₂, a₄₃, a₄₄, a₄₅, a₄₆, a₄₇, a₄₈, a₄₉, a₅₀, a₅₁, a₅₂, a₅₃,
a₅₄, a₅₅, a₅₆, a₅₇, a₅₈, a₅₉, a₆₀, a₆₁, a₆₂, a₆₃, a₆₄, a₆₅, a₆₆, a₆₇, a₆₈, a₆₉, a₇₀, a₇₁, a₇₂, a₇₃, a₇₄, a₇₅, a₇₆, a₇₇, a₇₈, a₇
₉, a₈₀, a₈₁, a₈₂, a₈₃, a₈₄, a₈₅, a₈₆, a₈₇, a₈₈, a₈₉, a₉₀, a₉₁, a₉₂, a₉₃, a₉₄, a₉₅, a₉₆, a₉₇, a₉₈, a₉₉)
Then if you want n symbols where n is an int you can do
syms = symbols('a1:%d' % n)

Related

Substitute numerical constants with symbols in sympy

I have a question similar to this one: How to substitute multiple symbols in an expression in sympy? but in reverse.
I have a sympy expression with numerical values and symbols alike. I would like to substitute all numerical values with symbolic constants. I appreciate that such query is uncommon for sympy. What can I try next?
For example, I have:
-0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939)) and would like to replace all numbers with a, b, c etc. ideally in a batch type of way.
The goal is to then apply trig identities to simplify the expression.
I'm not sure if there is already such a function. If there is not, it's quite easy to build one. For example:
import string
def num2symbols(expr):
# wild symbol to select all numbers
w = Wild("w", properties=[lambda t: isinstance(t, Number)])
# extract the numbers from the expression
n = expr.find(w)
# get a lowercase alphabet
alphabet = list(string.ascii_lowercase)
# create a symbol for each number
s = symbols(" ".join(alphabet[:len(n)]))
# create a dictionary mapping a number to a symbol
d = {k: v for k, v in zip(n, s)}
return d, expr.subs(d)
x0 = symbols("x0")
expr = -0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939))
d, new_expr = num2symbols(expr)
print(new_expr)
# out: b*sin(c + d*x0) - b*sin(sin(a + f*x0))
print(d):
# {-1.53909390000000: a, -0.596769500000000: b, 0.892569660000000: c, 0.152807470000000: d, 0.596769500000000: e, 0.00428988200000000: f}
I feel like dict.setdefault was made for this purpose in Python :-)
>>> c = numbered_symbols('c',cls=Dummy)
>>> d = {}
>>> econ = expr.replace(lambda x:x.is_Float, lambda x: sign(x)*d.setdefault(abs(x),next(c)))
>>> undo = {v:k for k,v in d.items()}
Do what you want with econ and when done (after saving results to econ)
>>> econ.xreplace(undo) == expr
True
(But if you change econ the exact equivalence may no longer hold.) This uses abs to store symbols so if the expression has constants that differ by a sign they will appear in econ with +/-ci instead of ci and cj.

Converting Dummy symbols to Symbols in Sympy

How can I convert Dummy variables (sympy.core.symbol.Dummy) to regular symbols in Sympy?
For example, say we want to find all vectors (x_1,x_2) in the kernel of a matrix that satisfying some equation f(x_1,x_2) = 0.
I would break it into two steps. First:
from sympy import Matrix
M = Matrix( [[1,0],
[0,0] ])
zeros = Matrix([[0],
[0]])
sol = M.gauss_jordan_solve(zeros)[0]
Second: solve f(sol) = 0.
But I don't know how to tell Sympy to treat the entries of sol as symbols. Any ideas?
sol.free_symbols returns a set of all symbols in sol ("free" is a detail that does not matter on this occasion). If you'd like to replace them with some other symbols of your choice, then create new symbols (as many as needed) and replace using subs, as shown below.
from sympy import symbols
dummies = list(sol.free_symbols)
my_syms = symbols("x0:{}".format(len(dummies))) # Example: symbols("x0:3") creates x0, x1, x2
sol = sol.subs(dict(zip(dummies, my_syms)))

Sympy gives unexpected differentiation result when the input is a string

Why is the result of the differentiation not 2*x0 in the following code:
In [54]: import sympy
In [55]: x = [sympy.Symbol('x%d' % i, real=True) for i in range(3)]
In [56]: x
Out[56]: [x0, x1, x2]
In [57]: sympy.diff('x0*x0 + x1*x1 + x2*x2',x[0])
Out[57]: 0
First, the creation of multiple numbered symbols is simpler with
x = sympy.symbols('x0:3', real=True) # returns (x0, x1, x2)
Second, the SymPy function to turn a string into a SymPy expression is sympify. This function is called automatically when you provide input as a string; however, this gives you no control over the interpretation of the string, and "unexpected results" are likely.
In this case, SymPy is not sure that "x0" appearing in the string is the same as x0 you created earlier. After all, your x0 has the additional property of being real, and the symbol from the string has no such assumptions on it. It's Symbol('x0') vs Symbol('x0', real=True); not a match.
This is one of many reasons why throwing a string in a SymPy function is a bad idea. Use sympify, and read about its parameters which control the parsing of input. Specifically, locals parameter is a dictionary mapping pieces of the string to objects you already have in SymPy, precisely what is needed here.
locals = {'x{}'.format(i): x[i] for i in range(3)} # {'x0': x0, 'x1': x1, 'x2': x2}
expr = sympy.sympify('x0*x0 + x1*x1 + x2*x2', locals=locals)
Now you can differentiate expr with respect to any symbols and get expected results
[expr.diff(sym) for sym in x] # [2*x0, 2*x1, 2*x2]
(Another benefit of having an expression before trying diff is that you can invoke diff as a method of the expression, saving the trouble of typing sympy. prefix.)
In your declarations, you should use sympy.symbols that is the reference method (from the documentation and tutorial) to declare variables.
x = [sympy.symbols('x%d' % i, real=True) for i in range(3)]
On top of this, you must pick (from experimentations that I made) either a string in both arguments, as:
sympy.diff('x0*x0 + x1*x1 + x2*x2',str(x[0]))
or symbolic expressions on both sides:
sympy.diff(x[0]*x[0] + x[1]*x[1] + x[2]*x[2], x[0])

Excel | Get all column/row names in which a specific text is as a list

It is difficult for me to describe the problem in the title, so excuse any misleading description.
The easiest way to describe what I need is with an example. I have a table like:
A B C
1 x
2 x x
3 x x
Now what I want is the formula in a cell for every single column and row with each of the column or row name for every x that is placed. In the example like:
A B C
1,2 2,3 3
1 A x
2 A, B x x
3 B, C x x
The column and row names are not equivalent to the excel designation. It works with an easy WHEN statement for single cells (=WHEN(C3="x";C1)), but not for a bunch of them (=WHEN(C3:E3="x";C1:E1)). How should/can such a formula look like?
So I found the answer to my problem. Excel provides the normal CONCATENATE function. What is needed is something like a CONCATENATEIF (in German = verkettenwenn) function. By adding a module in VBA based on a thread from ransi from 2011 on the ms-office-forum.net the function verkettenwenn can be used. The code for the German module looks like:
Option Explicit
Public Function verkettenwenn(Bereich_Kriterium, Kriterium, Bereich_Verketten)
Dim mydic As Object
Dim L As Long
Set mydic = CreateObject("Scripting.Dictionary")
For L = 1 To Bereich_Kriterium.Count
If Bereich_Kriterium(L) = Kriterium Then
mydic(L) = Bereich_Verketten(L)
End If
Next
verkettenwenn = Join(mydic.items, ", ")
End Function
With that module in place one of the formula for the mentioned example looks like: =verkettenwenn(C3:E3;"x";$C$1:$K$1)
The English code for a CONCATENATEIF function should probably be:
Option Explicit
Public Function CONCATENATEIF(Criteria_Area, Criterion, Concate_Area)
Dim mydic As Object
Dim L As Long
Set mydic = CreateObject("Scripting.Dictionary")
For L = 1 To Criteria_Area.Count
If Criteria_Area(L) = Criterion Then
mydic(L) = Concate_Area(L)
End If
Next
CONCATENATEIF = Join(mydic.items, ", ")
End Function

Making subarray from function on multiple arrays

In one folder I have 13 txt files which have 3 columns of data t, x, y. I use for path in glob to set multiple arrays with the data values. My question is if I want to create a separate array from each of the main arrays (t, x, y)
for path in glob("F:\Thermal Motion\*.txt"):
t, x, y = np.loadtxt(path, unpack=True)
for i in range(len(x)):
D = ((x[i] - x[0])**2 + (y[i] - y[0])**2)**0.5
So when I print D, I don't get an array I get a list. I want to sort D into arrays according to the original 13 files. So the data from the first file going through D is one array, and so on...
D looks like a float to me, not an array or list. If I understand your need correctly, you need a list of "D-values" for each file that you're reading in. Let's say you want those list of values associated with the name of the file that produced them for simplicity; obviously you can reorder them however you want later. Use a list comprehension to store the values, and a dict to map file names to lists of D values. Something like this:
D_values = {}
for path in glob("F:\Thermal Motion\*.txt"):
t, x, y = np.loadtxt(path, unpack=True)
# Add a list of computed D values to the D_values dictionary.
D_list = []
for i in range(len(x)):
D = ((x[i] - x[0])**2 + (y[i] - y[0])**2)**0.5
D_list.append(D)
D_values[path] = D_list
The example above is extra verbose for clarity. If I were writing this code for real, I'd use a list comprehension rather than the explicit inner loop:
D_values = {}
for path in glob("F:\Thermal Motion\*.txt"):
t, x, y = np.loadtxt(path, unpack=True)
D_values[path] = [((x[i] - x[0])**2 + (y[i] - y[0])**2)**0.5
for i in range(len(x))]