//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 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^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; }