# How to make an interactive solver function?

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: 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:

• Except is not accepted as a valid string pattern. As a way around, you could first replace all "==" by "=" and then replace all "=" by "==". Nov 6, 2021 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}]] Nov 6, 2021 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. Nov 6, 2021 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. Nov 7, 2021 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? Nov 8, 2021 at 1:17

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 = ReduceFreeVariables[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_] /; InternalWouldBeNumericQ[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]

• 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. Nov 8, 2021 at 1:19
• @PeterBurbery What did you type? When I type "a^2 == b^2 - c^2", I get no error. Nov 8, 2021 at 2: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. Nov 8, 2021 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. Nov 8, 2021 at 16:34
• I was pressing Shift+Enter every time instead of Enter. It is working now. Nov 8, 2021 at 16:42