/// <summary> /// If the lhs is not already a variable try to rearrange the equation to place a variable on the lhs. /// </summary> public static EqnCalc IsolateFirstVariableIfRequired(EqnCalc eqOriginal, ContentManager cm) { try { if (eqOriginal.Inputs[0] is Variable) { return(eqOriginal); } // Nothing required IList <SingleValue> eqVars = eqOriginal?.FindAllVariables(); Result <EqnCalc> r_result = RearrangeEquation(eqOriginal, eqVars[0].Name, cm); if (r_result.IsNotGood()) { Logging.LogMessage(r_result.Message); return(eqOriginal); } return(r_result.Value); } catch (Exception ex) { Logging.LogException(ex); return(eqOriginal); } }
private static Result <bool> RearrangeOnce(EqnCalc eqCalc, int argIndexToPreserve, ContentManager cm) { FunctionCalc lhsFunCalc = eqCalc.Inputs[0] as FunctionCalc; Function lhsFunction = lhsFunCalc?.Function; if (lhsFunction == null) { return(Result <bool> .Bad($"Unexpected error: lhs is not a funcalc")); } SingleResult argToPreserve = lhsFunCalc.Inputs[argIndexToPreserve]; // Create placeholders that the function rearrangements will treat as variables IList <string> argPlaceholders = new List <string>(); IDictionary <string, SingleResult> placeFillers = new Dictionary <string, SingleResult>(); for (int i = 0; i < lhsFunCalc.Inputs.Count; i++) { string placeholder = $"v{i}"; argPlaceholders.Add(placeholder); if (i != argIndexToPreserve) { placeFillers.Add(placeholder, lhsFunCalc.Inputs[i]); } } string resPlaceHolder = "res"; placeFillers.Add(resPlaceHolder, eqCalc.Inputs[1]); // Ask the function definition for a rearrangement that isolates the required variable Result <string> r_rearrangement = lhsFunction.GetRearrangement(argPlaceholders, resPlaceHolder, argIndexToPreserve); if (r_rearrangement.IsNotGood() || string.IsNullOrEmpty(r_rearrangement.Value)) { return(Result <bool> .Bad($"Rearrangement failed: {r_rearrangement.Message}")); } // Parse the rearrangement expression JongErrWarn errW = null; FunctionCalc newRhs = cm.CreateFunctionCalcFromExpression(r_rearrangement.Value, "", null, out errW); if (newRhs == null) { return(Result <bool> .Bad($"Rearrangement cannot be used: {errW?.ErrWarnString}")); } // Subsitute for the placeholders Result <bool> r_ok = SubsituteForPlaceholders(newRhs, placeFillers); if (r_ok.IsNotGood()) { return(Result <bool> .Bad($"Error substituting for placeholders: {r_ok.Message}")); } // Update the eqCalc with the rearrangement eqCalc.Inputs[1] = newRhs; eqCalc.Inputs[0] = argToPreserve; return(Result <bool> .Good(true)); }
private static IList <Foundlocation> FindVariable(EqnCalc eqCalc, string varName) { IList <Foundlocation> foundVars = new List <Foundlocation>(); AddFoundVars(eqCalc.Inputs[0], varName, EqSide.Left, -1, 1, foundVars); AddFoundVars(eqCalc.Inputs[1], varName, EqSide.Right, -1, 1, foundVars); return(foundVars); }
public static Result <EqnCalc> RearrangeEquation(EqnCalc eqOriginal, string varRequired, ContentManager cm) { try { // Copy the structure of eqOriginal so we don't mess it up Result <EqnCalc> r_eqCalc = CreateStructureCopy(eqOriginal, cm); if (r_eqCalc.IsNotGood()) { return(Result <EqnCalc> .Bad(r_eqCalc.Message)); } EqnCalc eqCalc = r_eqCalc.Value; int varDepth = -1; while (true) { // --------- Find varRequired and check it only appears once IList <Foundlocation> found = FindVariable(eqCalc, varRequired); if ((found == null) || (found.Count == 0)) { return(Result <EqnCalc> .Bad($"Variable '{varRequired}' was not found in the equation")); } if (found.Count > 1) { return(Result <EqnCalc> .Bad( $"Cannot rearrange equation because it contains multiple instances of Variable '{varRequired}'")); } // --------- Swap sides if it was found on the right if (found[0].EqSide == EqSide.Right) { SingleResult side = eqCalc.Inputs[1]; eqCalc.Inputs[1] = eqCalc.Inputs[0]; eqCalc.Inputs[0] = side; } // --------- Check we are making progress if (found[0].Depth == 1) // Success! { // Try to simplify the equation before returning it Result <bool> r_changes = SimplifyEquation(eqCalc, cm); if (r_changes.IsNotGood()) { return(Result <EqnCalc> .Bad(r_changes.Message)); } bool changesWereMade = r_changes.Value; // Successful return return(Result <EqnCalc> .Good(eqCalc)); } else if (varDepth < 0) { varDepth = found[0].Depth; } else if (found[0].Depth >= varDepth) { return(Result <EqnCalc> .Bad($"Last rearrangement did not achieve anything")); } else if (found[0].Depth < 1) { return(Result <EqnCalc> .Bad($"Unexpected error: found[0].Depth < 1")); } // ------------ Rearrange once Result <bool> r_resOnce = RearrangeOnce(eqCalc, found[0].TopBranchindex, cm); if (r_resOnce.IsNotGood()) { return(Result <EqnCalc> .Bad(r_resOnce.Message)); } } } catch (Exception ex) { return(Result <EqnCalc> .Bad(ex)); } }