2

I am working on creating a function that takes in any physics equation as a string and converts it to an equation that I will then paste into an interactive interface as asked here: How to make an interactive calculator for any mathematical relation?. I am implementing the first answer as a function that accepts any physics equation as a string and does two things before replacing the example of a^2+b^2==c^2.

First I want to replace any instance of "=" with "==" except for an instance of "==". The goal of this is to make a user-friendly function if the user enters an equation with incorrect programming syntax. I will then convert it to an expression.

Second, after it has been converted to an expression I will extract the symbols from the equation using this code, which I got from How to find all symbols in an expression and perform an operation on them?.

Symbols[x_String] := 
 DeleteDuplicates@Cases[ToExpression[x], _Symbol, Infinity]

The function for the first program is as follows:

StringReplace["\!\(\*SuperscriptBox[\(a\), \
\(2\)]\)+\!\(\*SuperscriptBox[\(b\), \
\(2\)]\)==\!\(\*SuperscriptBox[\(c\), \(2\)]\)", 
 Except[{"=="}, "="] -> "=="]

I am trying to base my code off this example

StringReplace["the cat in the hat", 
 Except[Characters["aeiou"], "c"] -> ""]

Unfortunately, this causes an error: enter image description here I am not sure what I am doing wrong here.

EDIT: I have my attempt here: https://www.wolframcloud.com/obj/burbery1/Published/Interactive%20Solver%20Function.nb In the process I came across two more unexpected hurdles: if the variable the user is solving for was already defined in a previous call of Interactive Solver or another piece of program that already executed, the symbol is regarded as a numerical value and not a variable.

The second problem is that the InteractiveSolver function returns a list of Null values when I run it for some reason.

I tried some code provided as an answer to this question and encountered the following error: enter image description here

Peter Burbery
  • 1,695
  • 4
  • 15
  • 1
    Except is not accepted as a valid string pattern. As a way around, you could first replace all "==" by "=" and then replace all "=" by "==". – Daniel Huber Nov 06 '21 at 17:05
  • The function Symbols will return symbolic numeric constants as well as variables, e.g., look at the result of Symbols["Pi*x + E"]. Either modify the definition to Symbols[x_String] := DeleteDuplicates@Cases[ToExpression[x], _Symbol?(!NumericQ[#]&), Infinity] or use Symbols[x_String] := Variables[Level[x, {-1}]] – Bob Hanlon Nov 06 '21 at 17:13
  • I am wondering if I should attach code in the form of a cloud notebook link or paste it directly in Stack Exchange or both. I have a little more than a page of code if you include the code in the question. – Peter Burbery Nov 06 '21 at 17:18
  • Interpreter[] might be fast enough for you: parse = Interpreter["MathFormula"]; parse["a=b^2"]. Parsing takes a little less than a second, so it's not fast. – Michael E2 Nov 07 '21 at 16:27
  • I don't quite understand how the Interpreter capability of Mathematica can be used to turn any string with only one equations sign into an expression with an equality checking expression (==) instead of assignment (=). Can you provide an example or explain a little bit more how the Interpreter can help me accomplish my goal? – Peter Burbery Nov 08 '21 at 01:17
  • Why is the output of Manipulate labeled In[5] in the image? It isn't from executing the code I posted. It looks like you bypassed the CellContext -> Cell function. Just remove that option if you want to use it in some other way, but it puts all nonlocal symbols in the Global` context. -- I guess you hit shift-enter, which evaluates the output and creates a second, new one. You shouldn't do that in Manipulate. Maybe there's some way to prevent it. – Michael E2 Nov 08 '21 at 02:57

1 Answers1

1

FWIW, my take on the big problem. I'm not particularly interested in parsing strings, so I can delete if this is unhelpful.

(*"
 *  Calculator
"*)
CellPrint@
 ExpressionCell[
  Manipulate[
   Column[{
     (* displays some data for inspection *)
     Dynamic@{var, formula},
     Dynamic@Quiet[
       (* TBD:check input/output of Solve *)
       With[{sol = Solve[ReleaseHold@formula, var]},
        With[{sol0 = 
           sol /. Thread[freevariables -> value /@ freevariables]},
         value[var] = var /. Last[sol0];(* last sol *)
         Grid@Transpose@{sol, sol0} /. Rule -> Equal
         ]],
       {Power::infy}],
     (* parameter inputs *)
     Grid@Transpose@{
        freevariables,
        InputField[Dynamic@value@#] & /@ freevariables}
     }],

{{formula, formula}, (* user input = held expression ) InputField[Dynamic[formula, ({formula, variables, var} = parseFormula[#]; Clear[value]; (value[#] = 1) & /@ variables; freevariables = DeleteCases[variables, var]; ) &], Hold@Expression] &}, {{var, var}, Dynamic@variables, SetterBar, TrackingFunction -> ( (var = #; freevariables = DeleteCases[variables, var]) &)}, {{variables, variables}, None}, {{freevariables, freevariables}, None}, {{parseFormula, parseFormula}, None}, {{value, value}, None},( stores values of parameters *)

Initialization :> ( (* utility (parses held expression) ) parseFormula // ClearAll; parseFormula[f_] := Module[{myformula, myvars, myvar}, myformula = f /. {Set | SetDelayed | Rule | RuleDelayed -> Equal, Null -> $Failed}; ( TBD: Handle user error ) myvars = Reduce`FreeVariables[ReleaseHold@myformula]; myvar = Replace[{myformula, myvars}, {{Hold[v_ == _] /; MemberQ[myvars, v], } :> v, {, {a_, ___}} :> a, {, v} :> v ( TBD: Handle user error ) }]; myformula = Replace[myformula, {eq : Hold[_Equal] :> eq, Hold[x_] /; Internal`WouldBeNumericQ[x, Evaluate@myvars] :> (myvar = $ans; PrependTo[myvars, $ans]; Hold[$ans == x]), form_ :> (myvars = myvar = $Failed; form) }]; ( TBD: Handle user error ) {myformula, myvars, myvar} ]; ( init *) {formula, variables, var} = parseFormula[ToExpression["a^2+b^2==c^2", StandardForm, Hold]]; freevariables = DeleteCases[variables, var]; (value[#] = 1) & /@ variables; ) ], "Output", CellContext -> Cell]

Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • If I try to change the equation or relation inside the box I get an error that I would like to display in a screenshot but don't know how to. – Peter Burbery Nov 08 '21 at 01:19
  • @PeterBurbery What did you type? When I type "a^2 == b^2 - c^2", I get no error. – Michael E2 Nov 08 '21 at 02:01
  • When I type "a^2=b^2-c^2" I get an error because it is an assignment expression and I would like to make it convert any assignment expressions into equality testing expressions. – Peter Burbery Nov 08 '21 at 15:22
  • @PeterBurbery I get no error if I enter "a^2=b^2-c^2". The code converts = (Set) to == (Equal) when the formula is parsed. It also converts A -> b h to A == b h. Not that a student would think of that, but it's a sort of like an assignment (a substitution Rule technically), so I threw that in. Unfortunately (?) E = m c^2 gets converted to the base of the natural logarithm and E=mc^2 is in terms the single variable mc squared. – Michael E2 Nov 08 '21 at 16:34
  • I was pressing Shift+Enter every time instead of Enter. It is working now. – Peter Burbery Nov 08 '21 at 16:42
  • How do I force it to evaluate numerically like NSolve or NSolveValues? – Peter Burbery Nov 08 '21 at 16:45
  • @PeterBurbery There are probably several ways. One might be to wrap sol0 in N in the output: N[sol0]. Another might be to use NSolve instead of Solve. – Michael E2 Nov 08 '21 at 17:44