//a/c + b/c = (a+b)/c public static ExpressionBase AddFractionWithCommonDenominatorRule(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a sum. VariadicOperatorExpression variadicExpression = expression as VariadicOperatorExpression; if (variadicExpression != null && variadicExpression.Type == OperatorType.Add) { BinaryOperatorExpression binaryOperand; List<ExpressionBase> terms = new List<ExpressionBase>(); ExpressionBase commonDenominator = null; //Foreach operand in sum. foreach (ExpressionBase operand in variadicExpression) { //If operand is a fraction. binaryOperand = operand as BinaryOperatorExpression; if (binaryOperand != null && binaryOperand.Type == OperatorType.Divide) { //If operand is the first fraction in sum if (terms.Count == 0) { //Add numerator to list of numerators. terms.Add(binaryOperand.Left.Clone()); //Set commonDenominator to operand's denominator. commonDenominator = binaryOperand.Right.Clone(); } else if (commonDenominator == binaryOperand.Right) { //Add fraction's numerator to list if its denominator equals commenDenominator. terms.Add(binaryOperand.Left.Clone()); } else { //Return null if an fraction's denominator does not equals commenDenominator. return null; } } else { //Return if operand is not a fraction. return null; } } if (terms.Count > 1) { //Initialize sum of all fractions' numerators. VariadicOperatorExpression SuggestionNumerator = new VariadicOperatorExpression(OperatorType.Add, terms[0], terms[1]); SuggestionNumerator.Add(terms.Skip(2).ToList()); //Return fraction with sum of all fractions' numerators and with their common denominator. return new BinaryOperatorExpression(SuggestionNumerator, commonDenominator, OperatorType.Divide); } } return null; }
public List<Identity> GetIdentities(List<ExpressionBase> selection) { var identities = new List<Identity>(); if (selection.Count == 0) { return identities; } ExpressionBase commonParent = GetCommonParent(selection); if (commonParent is VariadicOperatorExpression) { VariadicOperatorExpression variadicParent = commonParent as VariadicOperatorExpression; List<ExpressionBase> operandsLeftOfSelection = new List<ExpressionBase>(); List<ExpressionBase> operandsRightOfSelection = new List<ExpressionBase>(); List<ExpressionBase> selectedOperands = new List<ExpressionBase>(); foreach (ExpressionBase operand in variadicParent) { if (operand.Selected == false && operand.GetNodesRecursive().Any((n) => n.Selected == true) == false) { if (selectedOperands.Count == 0) { operandsLeftOfSelection.Add(operand); } else { operandsRightOfSelection.Add(operand); } } else { selectedOperands.Add(operand); } } VariadicOperatorExpression toBeReplaced = new VariadicOperatorExpression(variadicParent.Type, selectedOperands[0].Clone(), selectedOperands[1].Clone()); List<ExpressionBase> toBeReplacedSelection = new List<ExpressionBase>(); foreach (ExpressionBase operand in selectedOperands.Skip(2)) { toBeReplaced.Add(operand.Clone()); } toBeReplacedSelection = toBeReplaced.GetNodesRecursive().Where((n) => n.Selected == true).ToList(); foreach (ExpressionRule rule in rules) { ExpressionBase suggestion = rule(toBeReplaced, toBeReplacedSelection); if (identities.Select((i) => i.Suggestion).Contains(suggestion) == false && suggestion != commonParent) { if (suggestion != null) { ExpressionBase result; if (variadicParent.Count == selectedOperands.Count) { result = suggestion; } else { VariadicOperatorExpression variadicResult = new VariadicOperatorExpression(variadicParent.Type, new NumericExpression(-1), new NumericExpression(-1)); variadicResult.Add(operandsLeftOfSelection.Select((o) => o.Clone()).ToList()); variadicResult.Add(WrapInDelimiterIfNeccessary(suggestion.Clone(), variadicResult)); variadicResult.Add(operandsRightOfSelection.Select((o) => o.Clone()).ToList()); variadicResult.RemoveAt(0); variadicResult.RemoveAt(0); result = variadicResult; } identities.Add(new Identity(suggestion, WrapInDelimiterIfNeccessary(result, commonParent.Parent))); } } } } else { foreach (ExpressionRule rule in rules) { ExpressionBase suggestion = WrapInDelimiterIfNeccessary(rule(commonParent, selection), commonParent.Parent); if (identities.Select((i) => i.Suggestion).Contains(suggestion) == false && suggestion != commonParent) { if (suggestion != null) { identities.Add(new Identity(suggestion, suggestion)); } } } } return identities; }
public ExpressionBase Parse(List<Token> postFix) { var stack = new ExpressionStack(); ExpressionBase root = null; ExpressionBase left = null; ExpressionBase right = null; foreach (var token in postFix) { switch (token.Type) { case TokenType.Function: root = new FunctionExpression(stack.Pop(), (string)token.Data); stack.Push(root); break; case TokenType.Delimiter: switch (token.Data.ToString()) { case "()": root = new DelimiterExpression(stack.Pop()); stack.Push(root); break; case "{}": root = stack.Pop(); stack.Push(root); break; } break; case TokenType.Number: root = new NumericExpression(int.Parse(token.Data.ToString())); stack.Push(root); break; case TokenType.Constant: root = new ConstantExpression((ConstantType)token.Data); stack.Push(root); break; case TokenType.Variable: root = new VariableExpression((string)token.Data); stack.Push(root); break; case TokenType.Operator: switch (token.Data.ToString()) { case "~": root = new UnaryMinusExpression(stack.Pop()); stack.Push(root); break; case "+": right = stack.Pop(); left = stack.Pop(); if (left is VariadicOperatorExpression && (left as VariadicOperatorExpression).Type == OperatorType.Add) { (left as VariadicOperatorExpression).Add(right); root = left; stack.Push(root); } else { root = new VariadicOperatorExpression(OperatorType.Add, left, right); stack.Push(root); } break; case "-": if (this.TreatMinusAsUnaryMinusInVariadicPlus) { right = new UnaryMinusExpression(stack.Pop()); left = stack.Pop(); if (left is VariadicOperatorExpression && (left as VariadicOperatorExpression).Type == OperatorType.Add) { (left as VariadicOperatorExpression).Add(right); root = left; stack.Push(root); } else { root = new VariadicOperatorExpression(OperatorType.Add, left, right); stack.Push(root); } } else // treat it at binary operator { right = stack.Pop(); left = stack.Pop(); root = new BinaryOperatorExpression(left, right, OperatorType.Subtract); stack.Push(root); } break; case "*": right = stack.Pop(); left = stack.Pop(); if (left is VariadicOperatorExpression && (left as VariadicOperatorExpression).Type == OperatorType.Multiply) { (left as VariadicOperatorExpression).Add(right); root = left; stack.Push(root); } else { root = new VariadicOperatorExpression(OperatorType.Multiply, left, right); stack.Push(root); } break; case "/": right = stack.Pop(); left = stack.Pop(); root = new BinaryOperatorExpression(left, right, OperatorType.Divide); stack.Push(root); break; case "^": right = stack.Pop(); left = stack.Pop(); root = new BinaryOperatorExpression(left, right, OperatorType.Power); stack.Push(root); break; } break; } } return root; }
public override ExpressionBase Clone() { if (Count < 2) throw new InvalidOperationException("Tried to clone invalid VariadicExpression."); var expression = new VariadicOperatorExpression(Type, this[0].Clone(), this[1].Clone()) { Selected = Selected }; foreach (var expr in this.Skip(2)) { expression.Add(expr.Clone()); } return expression; }
//{a*b}/c = a/c * b/c public static ExpressionBase SplittingFractions(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a fraction. e.g. {a*b}/c BinaryOperatorExpression binaryExpression = expression as BinaryOperatorExpression; if (binaryExpression != null && binaryExpression.Type == OperatorType.Divide) { //If the fraction's numerator is a sum e.g. a*b in fraction {a*b}/c VariadicOperatorExpression numerators = binaryExpression.Left.Clone() as VariadicOperatorExpression; if (numerators != null && numerators.Type == OperatorType.Add && numerators.Count > 1) { List<ExpressionBase> fractionList = new List<ExpressionBase>(); //Foeach operand in the numerator's sum. e.g. a and b in fraction {a*b}/c foreach (var i in numerators) { //Initialize a fraction with the operand as numerator and add to list. e.g. a/c and b/c fractionList.Add(new BinaryOperatorExpression(i, binaryExpression.Right.Clone(), OperatorType.Divide)); } //Initialize and return the product of all the fractions in the list. e.g. a/c * b/c VariadicOperatorExpression suggestion = new VariadicOperatorExpression(OperatorType.Add, fractionList[0], fractionList[1]); foreach (var i in fractionList.Skip(2)) { suggestion.Add(i); } return suggestion; } } return null; }
//(a*b)^c = a^c * b^c public static ExpressionBase ReverseCommonPowerParenthesisRule(ExpressionBase expression, List<ExpressionBase> selection) { List<ExpressionBase> itemsInParenthesis = new List<ExpressionBase>(); VariadicOperatorExpression suggestion; //If expression is a power var binaryExpression = expression as BinaryOperatorExpression; if (binaryExpression != null && binaryExpression.Type == OperatorType.Power) { var commonparrent = binaryExpression.Right.Clone(); //If power's base is a parenthesis if (binaryExpression.Left is DelimiterExpression) { var delimiterExpression = binaryExpression.Left as DelimiterExpression; //If the parenthesis' content is a product if (delimiterExpression.Expression is VariadicOperatorExpression) { var variadicExpression = delimiterExpression.Expression.Clone() as VariadicOperatorExpression; if (variadicExpression.Type == OperatorType.Multiply) { //Raise every operand to the power's exponent. foreach (var item in variadicExpression) { itemsInParenthesis.Add(new BinaryOperatorExpression(item, commonparrent, OperatorType.Power)); } //Initialize and reutrn product of exponents suggestion = new VariadicOperatorExpression(OperatorType.Multiply, itemsInParenthesis[0].Clone(), itemsInParenthesis[1].Clone()); if (itemsInParenthesis.Count > 2) { foreach (var item in itemsInParenthesis.Skip(2)) { suggestion.Add(item.Clone()); } return suggestion; } else { return suggestion; } } } } } return null; }
//a*b+a*c = (b+c)*a //a*b-a*c = (b-c)*a public static ExpressionBase ProductParenthesis(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a sum. e.g. a*b*c - a*b*d VariadicOperatorExpression sum = expression as VariadicOperatorExpression; if (sum != null && sum.Type == OperatorType.Add) { List<ExpressionBase> suggestionSum = new List<ExpressionBase>(); List<ExpressionBase> commonProductOperands = new List<ExpressionBase>(); //Foreach operand in sum e.g. a*b*c and a*b*d foreach (var actualOperand in sum) { ExpressionBase operand; bool negative; //If operand is unary minus take its operand and set negative = true. e.g. -a*b*d => operand = a*b*d, negative = true UnaryMinusExpression minus = actualOperand as UnaryMinusExpression; if (minus != null) { operand = minus.Expression; negative = true; } else { operand = actualOperand; negative = false; } List<ExpressionBase> selectedProductOperands = new List<ExpressionBase>() { operand }; List<ExpressionBase> nonSelectedProductOperands = new List<ExpressionBase>() { }; VariadicOperatorExpression product = operand as VariadicOperatorExpression; //If operand in the sum is a product. e.g. a*b*d if (product != null && product.Type == OperatorType.Multiply) { //Store all selected and nonselected operands in the product. selectedProductOperands = product.Where((o) => (o.Selected == true || o.GetNodesRecursive().Any((n) => n.Selected))).ToList(); nonSelectedProductOperands = product.Where((o) => o.Selected == false && o.GetNodesRecursive().Any((n) => n.Selected) == false).ToList(); } bool allEqual = true; //Determine if all selected operands of the product are equal and in same order to the commen product operands. if (commonProductOperands.Count == 0 || commonProductOperands.Count == selectedProductOperands.Count) { for (int index = 0; index < commonProductOperands.Count; index++) { if (commonProductOperands[index] != selectedProductOperands[index]) { allEqual = false; } } } else { return null; } //If all selected operands in the product are in the common products operands. if (allEqual || commonProductOperands.Count == 0) { commonProductOperands = selectedProductOperands; //If the whole operand of the sum is selected leave 1 or -1 at its placing when factor outside parenthesis. if (nonSelectedProductOperands.Count == 0) { suggestionSum.Add(negative ? ToNumeric(-1) : ToNumeric(1)); } else if (nonSelectedProductOperands.Count == 1) { //If one operand of the product is not selected leave it when factorize the rest outside. ExpressionBase clone = nonSelectedProductOperands[0].Clone(); suggestionSum.Add(negative ? new UnaryMinusExpression(clone) : clone); } else { //If two or more operands of the product is not selected leave these when factorize the rest outside. VariadicOperatorExpression nonSelectedProduct = new VariadicOperatorExpression(OperatorType.Multiply, nonSelectedProductOperands[0].Clone(), nonSelectedProductOperands[1].Clone()); nonSelectedProduct.Add(nonSelectedProductOperands.Skip(2).Select((o) => o.Clone()).ToList()); suggestionSum.Add(negative ? (ExpressionBase)new UnaryMinusExpression(nonSelectedProduct) : nonSelectedProduct); } } else { //If two operands in the sum has two different selections return null return null; } } //Return product where the common product selection is factorized outside a parenthesis. e.g. (c - d)*a*b VariadicOperatorExpression sumExpression = new VariadicOperatorExpression(OperatorType.Add, suggestionSum[0], suggestionSum[1]); sumExpression.Add(suggestionSum.Skip(2).ToList()); VariadicOperatorExpression suggestion = new VariadicOperatorExpression(OperatorType.Multiply, sumExpression, new NumericExpression(-1)); suggestion.Add(commonProductOperands.Select((o) => o.Clone()).ToList()); suggestion.RemoveAt(1); return suggestion; } return null; }
// a/b * c/d = {a*c}/{b*d} public static ExpressionBase ProductOfFractions(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is product if two or more operands VariadicOperatorExpression variadicExpression = expression as VariadicOperatorExpression; if (variadicExpression != null && variadicExpression.Type == OperatorType.Multiply && variadicExpression.Count >= 2) { List<ExpressionBase> listOfNumerators = new List<ExpressionBase>(); List<ExpressionBase> listOfDenominators = new List<ExpressionBase>(); //Foreach operand in product foreach (ExpressionBase operand in variadicExpression) { //If operand is a fraction BinaryOperatorExpression binaryExpression = operand as BinaryOperatorExpression; if(binaryExpression != null && binaryExpression.Type == OperatorType.Divide) { //Add numerator and donimator to list listOfNumerators.Add(binaryExpression.Left.Clone()); listOfDenominators.Add(binaryExpression.Right.Clone()); } else { //If operands i not a fraction return null return null; } } //Convert list to product of numerators VariadicOperatorExpression suggestionNumerator = new VariadicOperatorExpression(OperatorType.Multiply, listOfNumerators[0], listOfNumerators[1]); foreach (var item in listOfNumerators.Skip(2)) { suggestionNumerator.Add(item); } //Convert list to product of denominators VariadicOperatorExpression suggestionDenominator = new VariadicOperatorExpression(OperatorType.Multiply, listOfDenominators[0], listOfDenominators[1]); foreach (var item in listOfDenominators.Skip(2)) { suggestionDenominator.Add(item); } //Return fraction with product of numerators and denominators return new BinaryOperatorExpression(suggestionNumerator, suggestionDenominator, OperatorType.Divide); } return null; }
// a*{b/c} = {a*b}/c public static ExpressionBase ProductOfConstantAndFraction(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a product with to operands var variadicExpression = expression as VariadicOperatorExpression; if (variadicExpression != null && variadicExpression.Type == OperatorType.Multiply && variadicExpression.Count == 2) { BinaryOperatorExpression fraction = null; ExpressionBase other = null; //Find which operand is a fraction if ((fraction = variadicExpression[0] as BinaryOperatorExpression) != null && fraction.Type == OperatorType.Divide) { other = variadicExpression[1]; } else if ((fraction = variadicExpression[1] as BinaryOperatorExpression) != null && fraction.Type == OperatorType.Divide) { other = variadicExpression[0]; } else { //Return null of non of the operands is a fraction return null; } //Multiply numerator with other operand VariadicOperatorExpression numerators = new VariadicOperatorExpression(OperatorType.Multiply, fraction.Left.Clone(), other.Clone()); //Return fraction BinaryOperatorExpression suggestion = new BinaryOperatorExpression(numerators.Clone(), fraction.Right.Clone(), OperatorType.Divide); return suggestion; } return null; }
//a/b = a*b^-1 public static ExpressionBase FractionToProductRule(ExpressionBase expression, List<ExpressionBase> selection) { //If expression a fraction. e.g. a/b BinaryExpression fraction = expression as BinaryExpression; if (fraction != null && fraction.Type == OperatorType.Divide) { //Convert denominator to power of -1. b => b^-1 ExpressionBase exponent = new BinaryOperatorExpression( fraction.Right.Clone(), new UnaryMinusExpression(new NumericExpression(1)), OperatorType.Power ); //Return product of numerator and power. a*b^-1 ExpressionBase suggestion = new VariadicOperatorExpression( OperatorType.Multiply, fraction.Left.Clone(), exponent ); return suggestion; } else { return null; } }
//-a = (-1)*a public static ExpressionBase FactorizeUnaryMinus(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is unary minus var unaryMinusExpression = expression as UnaryMinusExpression; if (unaryMinusExpression != null) { //Return product of operand and (-1) var numericExpression = new NumericExpression(1); var suggestion = new VariadicOperatorExpression(OperatorType.Multiply, new UnaryMinusExpression(numericExpression), unaryMinusExpression.Expression.Clone()); return suggestion; } return null; }
//6 = 2*3 public static ExpressionBase FactorizationRule(ExpressionBase expression, List<ExpressionBase> selection) { VariadicOperatorExpression suggestion; //If expression is a number if (expression is NumericExpression && expression != null) { var numericExpression = selection[0] as NumericExpression; var n = numericExpression.Number; //Find integers a != 1 and b != 1 such that n = a*b for (int count = 2; count < n; count++) { if (n % count == 0) { NumericExpression a = new NumericExpression(count); NumericExpression b = new NumericExpression(n / count); //Return product of a and b suggestion = new VariadicOperatorExpression(OperatorType.Multiply, a, b); return suggestion; } } } return null; }
//a^n = a*a*...*a where n is an integer. public static ExpressionBase ExponentToProductRule(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a power. BinaryOperatorExpression exponent = expression as BinaryOperatorExpression; if (exponent != null && exponent.Type == OperatorType.Power) { //If exponent is a number. NumericExpression numericExpression = exponent.Right as NumericExpression; if (numericExpression != null) { int number = (int)numericExpression.Number; if (number == 0) { //a^0 = 1 return new NumericExpression(1); } else if (number == 1) { //a^1 = a return exponent.Left.Clone(); } else if (number > 1) { //a^n = a*a*..*a VariadicOperatorExpression result = new VariadicOperatorExpression(OperatorType.Multiply, exponent.Left.Clone(), exponent.Left.Clone()); for (int i = 2; i < number; i++) { result.Add(exponent.Left.Clone()); } return result; } } else { return null; } } return null; }
//a^n*a^m = a^{n+m} public static ExpressionBase ExponentProduct(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a product. e.g. a*a^2 VariadicOperatorExpression product = expression as VariadicOperatorExpression; if (product != null && product.Type == OperatorType.Multiply) { List<ExpressionBase> sum = new List<ExpressionBase>(); ExpressionBase commonBase = null; //Foreach operand in product foreach (var operand in product) { ExpressionBase operandLeft = operand; ExpressionBase operandRight = new NumericExpression(1); BinaryOperatorExpression power = operand as BinaryOperatorExpression; if (power != null && power.Type == OperatorType.Power) { operandLeft = power.Left; operandRight = power.Right; } //If operand's base equals commonBase. if (operandLeft == commonBase || commonBase == null) { //Add operands exponent to sum. commonBase = operandLeft; sum.Add(operandRight.Clone()); } else { return null; } } if (sum.Count > 1) { //Return power with common base and sum of all operands' exponents. VariadicOperatorExpression suggestionRight = new VariadicOperatorExpression(OperatorType.Add, sum[0], sum[1]); suggestionRight.Add(sum.Skip(2).ToList()); return new BinaryOperatorExpression(commonBase, suggestionRight, OperatorType.Power); } } return null; }
//a^c * b^c = (a*b)^c public static ExpressionBase CommonPowerParenthesisRule(ExpressionBase expression, List<ExpressionBase> selection) { //If expression is a product. e.g. a^c * b^c VariadicOperatorExpression product = expression as VariadicOperatorExpression; if (product != null && product.Type == OperatorType.Multiply) { ExpressionBase commonPower = null; List<ExpressionBase> baseList = new List<ExpressionBase>(); //Foreach operand in product foreach (ExpressionBase operand in product) { //If operand is a power BinaryOperatorExpression power = operand as BinaryOperatorExpression; if (power != null && power.Type == OperatorType.Power) { //If power's exponent equals the common exponent if (power.Right == commonPower || commonPower == null) { //Add power's base to list commonPower = power.Right; baseList.Add(power.Left); } else { return null; } } else { return null; } } if (baseList.Count > 1) { //Initialize product of all bases in the list. VariadicOperatorExpression resultProduct = new VariadicOperatorExpression(OperatorType.Multiply, baseList[0].Clone(), baseList[1].Clone()); resultProduct.Add(baseList.Skip(2).Select((b) => b.Clone()).ToList()); //return exponent with product as base and common exponent. e.g. (a*b)^c BinaryOperatorExpression result = new BinaryOperatorExpression(resultProduct, commonPower.Clone(), OperatorType.Power); return result; } } return null; }