public bool TryParseExpression(string expression, out ComplexFunction.ComplexFunction complexFunction, bool mutable = false) { complexFunction = null; if (operators.ContainsKey(expression)) { if (mutable) { //if (expression == "-" && ExpressionStack.Count == 1) //{ // //= "Could fix the minus..."; //} // an unsupported operator if (/*operators[expression].function == null || */ ExpressionStack.Count < operators[expression].ArgumentCount) { return(false); } // collect the arguments var arguments = new ComplexFunction.ComplexFunction[operators[expression].ArgumentCount]; // remember about the reverse order! for (int i = operators[expression].ArgumentCount - 1; i >= 0; i--) { arguments[i] = ExpressionStack.Pop(); } complexFunction = ComplexFunction.Generator.Generate(expression, arguments); } } else { if (constants.ContainsKey(expression)) { complexFunction = ComplexFunction.Generator.Generate(expression); } else { // could be a number bool succeededParsing = double.TryParse(expression, out double result); if (succeededParsing) { complexFunction = ComplexFunction.Generator.Generate("custom_constant", result); } else { return(false); } } } // let's be fair and do not provide anythin undefined if the user just asks for parsability if (!mutable) { complexFunction = null; } return(true); }
public bool TryParseTree(out ComplexFunction.ComplexFunction returnValue) { if (ExpressionStack.Count == 1) { returnValue = ExpressionStack.Peek(); return(true); } else { returnValue = null; return(false); } }
private void ComputeFractal(Complex complexCoordinates) { switch ((DragEffect)Settings.Instance.drageffect) { case DragEffect.Move: Settings.Instance.Center = CenterLastClicked - (GetComplexCoords(MouseLastMove, CenterLastClicked) - MouseLastClickedComplex); break; case DragEffect.SingleRoot: AlgorithmFunction = new ComplexFunction.ProductCF(Function, new ComplexFunction.DifferenceCF(new ComplexFunction.ArgumentCF(), new ComplexFunction.ConstantCF(complexCoordinates))); break; case DragEffect.DoubleRoot: AlgorithmFunction = new ComplexFunction.ProductCF(Function, new ComplexFunction.DifferenceCF(new ComplexFunction.ArgumentCF(), new ComplexFunction.ConstantCF(complexCoordinates)), new ComplexFunction.DifferenceCF(new ComplexFunction.ArgumentCF(), new ComplexFunction.ConstantCF(complexCoordinates)) ); break; case DragEffect.Singularity: AlgorithmFunction = new ComplexFunction.QuotientCF(Function, new ComplexFunction.DifferenceCF(new ComplexFunction.ArgumentCF(), new ComplexFunction.ConstantCF(complexCoordinates))); break; case DragEffect.Reset: AlgorithmFunction = Function; break; default: AlgorithmFunction = Function; break; } ComputeFractal(); }
public static bool TryParse(string formula, out ComplexFunction.ComplexFunction complexFunction) { var expressionQueue = new ParseTreeGenerator(); var operatorStack = new Stack <string>(); string lastExpression = string.Empty; string expression = string.Empty; complexFunction = null; bool delayUntilLast = false; int deepness = 0; // remove all whitespace characters formula = Regex.Replace(formula, @"\s+", ""); try { for (int cursor = 0; cursor < formula.Length; cursor++) { expression += formula[cursor].ToString().ToLower(); if (!expressionQueue.TryParseExpression(expression, out _, false)) { continue; } var lastPossibility = cursor == formula.Length - 1 || !expressionQueue.TryParseExpression(expression + formula[cursor + 1], out _, false); // nonoperator should be interpreted lazily // operators should be treated firstly // first successful encounter if (!delayUntilLast) { delayUntilLast = true; // succeeded interpreting the first time// if able to parse, but no further (lazy evaluation) if (operators.ContainsKey(expression)) { if (expression == "-") { if (operators.ContainsKey(lastExpression)) { if (operators[lastExpression].IsOpening || lastExpression != ")") { // "sin(-" "acos(-" "(-" "*-" "--" "+-" "^-" // interpret as negation // carry on to last interpretation] // consider replacing "-" with "(-1)*" or "i*i*" switch (expression) { case "-": // important negation formula = formula.Remove(cursor, 1).Insert(cursor, "_&"); break; //case "+": // formula = formula.Remove(cursor, 1); // break; } cursor -= expression.Length; expression = string.Empty; continue; } else { // )- // interpret as subtraction } } else { // a variable // 1234- // z- // could be 123+456- // interpret as subtraction } } } // expression is not an operator else if (lastExpression != string.Empty && !operators.ContainsKey(lastExpression)) { // should not be the case that nonoperator follows another nonoperator (as if it was implicit multiplication) return(false); } else { // last time I've interpreted an operator // it is alwright if (!lastPossibility) { continue; } } } else if (!lastPossibility) { continue; } // other cases consider subsequent (not first) succsessful interpretation if (operators.ContainsKey(expression)) { if (expression == ",") { // crush to another "," or to "sin(" } else if (expression == ")") { // crushing until "(" or "sin(" found while (operatorStack.Count > 0 && !operators[operatorStack.Peek()].IsOpening) { expressionQueue.Enqueue(operatorStack.Pop()); } // no "(" nor "sin(" found that is an error! if (operatorStack.Count == 0) { return(false); } var openingOperator = operatorStack.Pop(); // an opening operator that is not "(" should carry useful information with it, let's keep it! if (openingOperator != "(") { expressionQueue.Enqueue(openingOperator); } --deepness; } else if (operators[expression].IsOpening) { // highest priority when adding yet lowest when already inside (to stop propagating) operatorStack.Push(expression); ++deepness; } else { // > and >= shoud be differentiated when computing from the right or from the left // rightmost evaluation works ONLY for supported operators and ONLY if the are neighbouring to each other // leftmost evaluation pops more often while (operatorStack.Count > 0 && !operators[operatorStack.Peek()].IsOpening && operators[operatorStack.Peek()].Priority >= operators[expression].Priority) { expressionQueue.Enqueue(operatorStack.Pop()); } operatorStack.Push(expression); } } else { // a constant value like "12345", or argument "z" expressionQueue.Enqueue(expression); } lastExpression = expression; // clear the expression before proceeding expression = string.Empty; delayUntilLast = false; } if (deepness != 0 || expression != string.Empty) { return(false); } while (operatorStack.Count > 0) { expressionQueue.Enqueue(operatorStack.Pop()); } return(expressionQueue.TryParseTree(out complexFunction)); } catch (ArgumentException e) { // incorrect formula return(false); } }
public FractalAlgorithm GetAutoConfiguredAlgorithmByID(Algorithm algorithmID, params ComplexFunction.ComplexFunction[] Derivatives) { if (Derivatives.Length == 0) { return(new NullAlgorithm()); } FractalAlgorithm algorithm; switch (algorithmID) { // actually we really need the derivative so really (... >= 2) case Algorithm.Newton: if (Derivatives.Length < 2) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[0].GetDerivative() }; } algorithm = new NewtonFractal(); break; case Algorithm.Halley: if (Derivatives.Length < 2) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[0].GetDerivative() }; } if (Derivatives.Length < 3) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[1], Derivatives[1].GetDerivative() }; } algorithm = new HalleyFractal(); break; case Algorithm.Quadruple: if (Derivatives.Length < 2) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[0].GetDerivative() }; } if (Derivatives.Length < 3) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[1], Derivatives[1].GetDerivative() }; } if (Derivatives.Length < 4) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[1], Derivatives[2], Derivatives[2].GetDerivative() }; } algorithm = new HalleyFractal(); break; case Algorithm.Halley_overnewtoned: if (Derivatives.Length < 2) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[0].GetDerivative() }; } if (Derivatives.Length < 3) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[1], Derivatives[1].GetDerivative() }; } algorithm = new HalleyNewton(); break; case Algorithm.Halley_without_derivative: algorithm = new HalleyWithoutDerivativeFractal(); break; case Algorithm.Quadratic: if (Derivatives.Length < 2) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[0].GetDerivative() }; } if (Derivatives.Length < 3) { Derivatives = new ComplexFunction.ComplexFunction[] { Derivatives[0], Derivatives[1], Derivatives[1].GetDerivative() }; } algorithm = new QuadraticFractal(); break; case Algorithm.Quadratic_without_derivative: algorithm = new QuadraticWithoutDerivativeFractal(); break; case Algorithm.Newton_without_derivative: algorithm = new NewtonWithoutDerivativeFractal(); break; case Algorithm.Secant_Newton_combination: algorithm = new SecantNewtonFractal(); break; case Algorithm.Secant: algorithm = new SecantFractal(); break; case Algorithm.Muller: algorithm = new MullerFractal(); break; case Algorithm.Moler_real: algorithm = new MolerRealFractal(); break; case Algorithm.Inverse: algorithm = new InverseQuadraticFractal(); break; case Algorithm.Steffensen: algorithm = new SteffensenFractal(); break; case Algorithm.Custom: algorithm = new CustomFractal(); break; default: algorithm = new NullAlgorithm(); break; } algorithm.Derivatives = Derivatives; algorithm.MaximumIterationCount = Settings.Instance.iterations; if (algorithm is ParametrizedFractalAlgorithm) { (algorithm as ParametrizedFractalAlgorithm).Parameter = (double)Settings.Instance.parameter; } return(algorithm); }