Thanks! This is working perfectly, with the small exception that I need globals() instead of locals().
By the way, I had already seen this in the documentation but didn't understand how to use it. The Sympy documentation at https://docs.sympy.org/latest/modules/parsing.html#:~:text=A%20tuple%20of%20transformation%20functions%20used%20to%20modify,use%20of%20standard%20mathematical%20factorial%20notation%20%28e.g.%20x%21 mentions local_dict and global_dict, but doesn't say much on how to use it (probably documented somewhere else, but I didn't do much searching for that). This site gives 17 examples: https://www.programcreek.com/python/example/100568/sympy.parsing.sympy_parser.parse_expr including a case that uses global_dict=global_dict, but that didn't work for me (it probably requires creating a dictionary called global_dict, but that is not part of the sample). On Saturday, November 7, 2020 at 1:47:14 AM UTC+1 [email protected] wrote: > parse_expr converts any unknown variable names into symbols. If you > already have the variable Round1Bar defined as something you want it > to use, you should pass it in the locals dictionary, like > > parse_expr('Round1Bar', {'Round1Bar', symbols(r'\(1\)')}) > > Or if you already have them defined you can just use > > parse_expr('Round1Bar', locals()) > > Aaron Meurer > > On Fri, Nov 6, 2020 at 3:54 PM Thomas Ligon <[email protected]> wrote: > > > > Hi Aaron, > > this remark really throws me off. I certainly didn't think that Round > was a shortcut for anything. Here is how I understood Sympy: > > When I write > > Round1 = symbols('\\(1\\)') > > then I assume that the right-hand side is the form used by Sympy for > printout, especially for print(latex(...)), and the left-hand side is just > a name that I invent, meaning that Round is my way of remembering what it > is, and the name should avoid special characters that I want in the > printout, such as parentheses and minus signs, because they cause unwanted > things to happen in an expression. By the way, that is why I have a Roundm2 > = symbols('\\(-2\\)') > > meaning that I have used "m" to indicate (to me) that this is minus 2, > but avoiding "-" in a name. > > Now, as a bit more background, (j) is an arithmetic expression involving > j and m (a constant in this context), meaning that (j) is a shortcut for > something that would fill a lot of space in a normal printout. > > By the way, in the recent test code > > print(latex(Round1)) > > print(latex(parse_expr('Round1'))) > > print(latex(Round1Bar)) > > print(latex(parse_expr('Round1Bar'))) > > produces > > \(1\) > > Round_{1} > > \bar{\(1\)} > > \bar{Round1} > > so the problem I have is that > > print(latex(symbolname)) > > and > > print(latex(parse_expr('symbolname'))) > > are different. My old code with static limits uses the first case, and > the new code with variable limits uses the second. > > I can see now that parse_expr('string') is not converting 'string' into > the name of a symbol, as I expected. I also see that suffix 1 is being > converted to _{1} (as you mentioned earlier) and suffix Bar is being > converted to prefix \bar. That explains where this form is coming from. > > Finally, here is one more test to avoid the automatic assumption about > suffixes (like Microsoft Word's autocorrect, but I won't go into that rant > here). > > Round2BarX = symbols('\\bar{\\(2\\)}') > > print(latex(Round2BarX)) > > print(latex(parse_expr('Round2BarX'))) > > produces > > \bar{\(2\)} > > Round2BarX > > > > On Friday, November 6, 2020 at 10:25:54 PM UTC+1 [email protected] > wrote: > >> > >> I think Round as a shortcut for putting parentheses around something > >> is not implemented in the LaTeX printer. I've never seen that before, > >> but if it is common, we can add it. Otherwise, if you need custom > >> LaTeX in your symbol names you should just use it directly in the > >> symbol name. > >> > >> Aaron Meurer > >> > >> On Fri, Nov 6, 2020 at 1:15 PM Thomas Ligon <[email protected]> > wrote: > >> > > >> > Thanks again for the very valuable help. I think I am getting very > close to a good solution, but I must still have a bug in there. > >> > First, just a small piece of background: I am using some symbols like > >> > Round1 = symbols('\\(1\\)') > >> > Round1Bar = symbols('\\Bar{\\(1\\)}') > >> > In other words, a "1" in parentheses and the same thing with a bar > over it, plus some using square brackets. These were defined and used in > two papers I am referring to, published in 1854 and 1896, both by famous > mathematicians. One version of my code used something like E_1 instead, but > this time I chose to stick to the old symbols, even though they are not > typical today, since they could be confused with normal parentheses. > >> > Now, I have working code that has a hard-coded limit on the number of > symbols and I need to upgrade it so that it can handle an undetermined > (perhaps large) number of symbols. When creating expressions, I am using > functions like this one: > >> > def getRoundjBar (j): > >> > strJ = str(abs(j)) > >> > if j < 0: > >> > strJ = 'm' + strJ > >> > strSym = 'Round' + strJ + 'Bar' > >> > return parse_expr(strSym) > >> > and here is some test code showing it in action: > >> > ret1 = getRoundjBar(1) > >> > print(ret1) > >> > print(latex(ret1)) > >> > I can see that it is important for me to understand the type of the > variable and, fortunately, the "Locals" window in my debugger shows that > ret1 contains the value Round1Bar and has type Symbol. Good, that makes > almost everything work well, but > >> > print(latex(ret1)) > >> > produces > >> > \bar{Round1} > >> > where it should produce > >> > \\bar{\(1\)} > >> > > >> > On Wednesday, November 4, 2020 at 9:46:03 PM UTC+1 [email protected] > wrote: > >> >> > >> >> You can't use exec() to do a return statement for a function that is > >> >> not also part of the string. What you want is eval(), which evaluates > >> >> an expression and returns it, like > >> >> > >> >> return eval(string) > >> >> > >> >> However, you should consider just using sympify() or parse_expr() if > >> >> you are evaluating strings to SymPy expressions, as they are designed > >> >> for that and will give you things like automatically defining the > >> >> symbols. > >> >> > >> >> Actually, for what you've shown, I don't see the need to use exec() > or > >> >> eval() at all. You can just create the symbols from the strings, like > >> >> Symbol('a' + str(j)). Symbols are completely defined by name, so if > >> >> two symbols have the same name, they will be equal. > >> >> > >> >> Aaron Meurer > >> >> > >> >> On Wed, Nov 4, 2020 at 2:24 AM Thomas Ligon <[email protected]> > wrote: > >> >> > > >> >> > Now I see a solution: forget the function and create the > expression exp using string manipulation and exec, something like > >> >> > strExp = 'complex string' > >> >> > strSym = 'exp = ' + strExp > >> >> > exec(strSym) > >> >> > > >> >> > On Wednesday, November 4, 2020 at 9:51:35 AM UTC+1 Thomas Ligon > wrote: > >> >> >> > >> >> >> Thanks! > >> >> >> The automatic subscript is just a minor irritation, and your > response is helpful. > >> >> >> I have included a new test program that hopefully no longer > oversimplifies the situation. Currently, I have code (2000 lines) for > investigating a very complex series, and it runs to a maximum of 3 terms of > the series, requiring index values up to 6. I showed the results to the > mathematics professor who has mentored my work and he immediately says that > it is valuable and I should publish a version that can go up to a very > large number of terms. In order to do that, I need to produce a fully > automated version with a variable number of terms and indices. > >> >> >> So, for variable j, I want to use a_j in a formula. > >> >> >> The expression exp on line 20 does that, where I use get_a(1) to > represent aj for variable j, where j happens to be 1. > >> >> >> In line 5, the return is part of a function. In line 8, I expect > return in exec ('return...') to be a part of a function. > >> >> >> > >> >> >> maxIndex = 2 > >> >> >> import sympy > >> >> >> from sympy import symbols, latex > >> >> >> def get_a1(): > >> >> >> return a1 > >> >> >> def get_a2(): > >> >> >> strSym = 'return a2' > >> >> >> exec(strSym) > >> >> >> def get_a (j): > >> >> >> strSym = 'return a' + str(j) > >> >> >> exec(strSym) > >> >> >> lam = symbols('\\lambda') > >> >> >> for ind in range(1,maxIndex+1): > >> >> >> strSym = 'a' + str(ind) + ' = symbols(\'a_' + str(ind) + '\')' > >> >> >> exec(strSym) > >> >> >> #a1 = symbols('a_1') > >> >> >> #a2 = symbols('a_2') > >> >> >> print(latex(get_a1())) > >> >> >> #print(latex(get_a2())) # causes 'return' outside function > (<string>, line 1) > >> >> >> exp = 3*get_a(1) + 5*get_a(2)*lam**2 # causes 'return' outside > function (<string>, line 1) > >> >> >> print(latex(exp)) > >> >> >> print('end testSym') > >> >> >> > >> >> >> On Tuesday, November 3, 2020 at 11:29:00 PM UTC+1 > [email protected] wrote: > >> >> >>> > >> >> >>> I'm unclear what you're trying to achieve with the functions. > exec() > >> >> >>> takes a string of Python code and executes it. The entire string > must > >> >> >>> be valid Python code by itself, so exec('return x') fails > because a > >> >> >>> bare "return x" is not valid Python. "return" must be inside a > >> >> >>> function definition to be valid. But even defSym1 doesn't do > anything > >> >> >>> useful beyond just returning Sym1, so there's no point to having > it > >> >> >>> instead of just "Sym1" directly. > >> >> >>> > >> >> >>> The LaTeX version of Sym1 contains _ because SymPy automatically > >> >> >>> assumes that symbol names ending in numbers are subscripted, so > it > >> >> >>> renders it as a Sym_1 in LaTeX. If you don't want the 1 to be > >> >> >>> subscripted, you can use something like Symbol("{Sym1}"). > >> >> >>> > >> >> >>> Aaron Meurer > >> >> >>> > >> >> >>> On Tue, Nov 3, 2020 at 9:42 AM Thomas Ligon <[email protected]> > wrote: > >> >> >>> > > >> >> >>> > The following code is not working as I expected. > >> >> >>> > Why does Sym1 contain an underline (_{1})? > >> >> >>> > Why does return fail (unhandled exception) in line 7? > >> >> >>> > > >> >> >>> > Code: > >> >> >>> > import sympy > >> >> >>> > from sympy import symbols, latex > >> >> >>> > def defSym1(): > >> >> >>> > return Sym1 > >> >> >>> > def defSym2(): > >> >> >>> > strSym = 'return Sym2' > >> >> >>> > exec(strSym) > >> >> >>> > Sym1 = symbols('Sym1') > >> >> >>> > Sym2 = symbols('Sym2') > >> >> >>> > print(latex(defSym1())) > >> >> >>> > print(latex(defSym2())) > >> >> >>> > print('end testSym') > >> >> >>> > > >> >> >>> > Output: > >> >> >>> > Sym_{1} > >> >> >>> > 'return' outside function (<string>, line 1) > >> >> >>> > > >> >> >>> > > >> >> >>> > > >> >> >>> > > >> >> >>> > -- > >> >> >>> > You received this message because you are subscribed to the > Google Groups "sympy" group. > >> >> >>> > To unsubscribe from this group and stop receiving emails from > it, send an email to [email protected]. > >> >> >>> > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/4a1df466-d3a3-4f7b-8a14-5e5a906f2662n%40googlegroups.com > . > >> >> > > >> >> > -- > >> >> > You received this message because you are subscribed to the Google > Groups "sympy" group. > >> >> > To unsubscribe from this group and stop receiving emails from it, > send an email to [email protected]. > >> >> > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/00d00ac2-7b0c-4ac1-b81a-dcc9f7956572n%40googlegroups.com > . > >> > > >> > -- > >> > You received this message because you are subscribed to the Google > Groups "sympy" group. > >> > To unsubscribe from this group and stop receiving emails from it, > send an email to [email protected]. > >> > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/24d5bbe0-8388-4564-ad2f-10fa6412c94bn%40googlegroups.com > . > > > > -- > > You received this message because you are subscribed to the Google > Groups "sympy" group. > > To unsubscribe from this group and stop receiving emails from it, send > an email to [email protected]. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/2c2986a7-9d96-4dba-af62-b840c0c1736en%40googlegroups.com > . > -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/69e4e4b8-bfd0-4b38-b4c7-d32eeb734c91n%40googlegroups.com.
