public override IEnumerable<OperatorElement> FindPath(Element target)
 {
     var pathHere = new[] {this};
     if (ReferenceEquals(Elements.Lhs, target) || ReferenceEquals(Elements.Rhs, target)) return pathHere;
     var pathFromHere = Elements.Lhs.FindPath(target) ?? Elements.Rhs.FindPath(target);
     return pathFromHere != null ? pathHere.Concat(pathFromHere) : null;
 }
 private static AssignmentElement MoveVariableToLhs(AssignmentElement equals, string variable, out Element varEl)
 {
     if (ReferenceEquals(equals, null)) throw new MissingAssignmentException();
     varEl = equals.Elements.Lhs.FindVariable(variable);
     if (!ReferenceEquals(varEl, null)) return equals;
     varEl = equals.Elements.Rhs.FindVariable(variable);
     if (ReferenceEquals(varEl, null)) throw new UnrecognisedVariableException(variable);
     // Swap lhs/rhs
     return new AssignmentElement(equals.Elements.Swap());
 }
 private Element Rearrange(AssignmentElement root, Element targetVar)
 {
     while (true)
     {
         // Check for no rearrange necessary
         if (root.Elements.Lhs == targetVar) return root.Elements.Rhs;
         // Rearrange first part of tree
         var targetPath = root.Elements.Lhs.FindPath(targetVar).ToArray();
         var lastOperation = targetPath.First();
         var varBranch = targetPath.Skip(1).FirstOrDefault() ?? targetVar;
         var newRoot = root.Replace(lastOperation, varBranch) as AssignmentElement;
         var inversion = lastOperation.Invert(varBranch, newRoot.Elements.Rhs);
         root = newRoot.Replace(newRoot.Elements.Rhs, inversion) as AssignmentElement;
     }
 }
 public ElementPair Replace(Element original, Element replacement, out Replacement result)
 {
     Element newLhs;
     Element newRhs;
     result = Replacement.None;
     if (ReferenceEquals(Lhs, original))
     {
         newLhs = replacement;
         result |= Replacement.Lhs;
     }
     else newLhs = Lhs.Replace(original, replacement);
     if (ReferenceEquals(Rhs, original))
     {
         newRhs = replacement;
         result |= Replacement.Rhs;
     }
     else newRhs = Rhs.Replace(original, replacement);
     return new ElementPair(newLhs, newRhs);
 }
 private Expression(Element expression)
 {
     _expression = expression;
     // Discover variables
     Variables = _expression.AllLeaves.OfType<VariableElement>().Select(vr => vr.Value);
 }
 public abstract Element Invert(Element original, Element replacement);
 public override Element Replace(Element original, Element replacement)
 {
     return Clone(Elements.Replace(original, replacement));
 }
 public override Element Invert(Element original, Element replacement)
 {
     // Cannot perform this operation
     throw new System.NotImplementedException();
 }
 public override Element Invert(Element original, Element replacement)
 {
     ElementPair.Replacement result;
     var newElements = Elements.Replace(original, replacement, out result);
     return result == ElementPair.Replacement.Lhs ? new AdditionElement(newElements) : new SubtractionElement(newElements) as Element;
 }
 public override Element Invert(Element original, Element replacement)
 {
     ElementPair.Replacement result;
     var newElements = Elements.Replace(original, replacement, out result);
     return result == ElementPair.Replacement.Lhs ? new MultiplicationElement(newElements) : new DivisionElement(newElements) as Element;
 }
 public ElementPair ReplaceLhs(Element original, Element replacement)
 {
     if (ReferenceEquals(Lhs, original)) return new ElementPair(replacement, Rhs);
     if (ReferenceEquals(Rhs, original)) return new ElementPair(replacement, Lhs);
     return this;
 }
 public ElementPair Replace(Element original, Element replacement)
 {
     Replacement dummy;
     return Replace(original, replacement, out dummy);
 }
 public ElementPair(Element lhs, Element rhs)
 {
     Lhs = lhs;
     Rhs = rhs;
 }
 public override Element Invert(Element original, Element replacement)
 {
     return new SubtractionElement(Elements.ReplaceLhs(original, replacement));
 }
 public abstract Element Replace(Element original, Element replacement);
 /// <summary>
 /// Find the route elements of the element specified starting from here
 /// </summary>
 /// <param name="target">Target element to find route to</param>
 /// <returns>List of route elements</returns>
 public abstract IEnumerable<OperatorElement> FindPath(Element target);