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