/// <summary> /// Splits an <see cref="AdditionOperNode"/> into terms and simplifies by common terms. /// </summary> /// <param name="node">The <see cref="AdditionOperNode"/> to simplify.</param> /// <returns>The resulting <see cref="ExpNode"/>.</returns> public static AdditionOperNode SimplfiyATerms(AdditionOperNode node) { SortedSet <AdditiveTerm> aTerms = new(); for (int i = 0; i < node.ChildCount; i++) { AdditiveTerm aTerm = new(node.GetChild(i)); if (aTerms.TryGetValue(aTerm, out AdditiveTerm existingATerm)) { existingATerm.AddToCoefficient(aTerm); } else { aTerms.Add(aTerm); } } node.ClearChildren(); foreach (var term in aTerms) { node.AddChild(term.AsExpNode()); } return(node); }
/// <inheritdoc/> public override ExpNode Execute(AdditionOperNode node) { // Sum rule for (int i = 0; i < node.ChildCount; i++) { ExpNode diffChild = node.GetChild(i).Execute(this); node.ReplaceChild(diffChild, i); } return(node); }
/// <inheritdoc/> public override ExpNode Execute(PowOperNode node) { // TODO: Handle variable in exponent if (node.IsConstantBy(_variable)) { return(ConstantRule(node)); } // Increment exponent, divide by exponent AdditionOperNode exponent = QuickOpers.Add(1, node.RightChild); RecipricalOperNode coefficient = QuickOpers.Reciprical(exponent.Clone()); PowOperNode @base = QuickOpers.Pow(node.LeftChild, exponent); return(QuickOpers.Multiply(coefficient, @base)); }
/// <summary> /// Adds tensors. /// </summary> /// <param name="node">The <see cref="AdditionOperNode"/> containing tensors.</param> /// <param name="simplifier">The <see cref="Simplifier"/> calling.</param> /// <returns>The resuling <see cref="ExpNode"/>.</returns> public static ExpNode SumTensors(AdditionOperNode node, Simplifier simplifier) { if (node.GetChild(0) is TensorNode tensorNode) { for (int i = 1; i < node.ChildCount; i++) { if (node.GetChild(i) is TensorNode otherTensorNode) { if (otherTensorNode.SizeIdentity == tensorNode.SizeIdentity) { for (int j = 0; j < tensorNode.ChildCount; j++) { ExpNode addedNode = QuickOpers .Sum(tensorNode.GetChild(j), otherTensorNode.GetChild(j)) .Execute(simplifier); tensorNode.ReplaceChild(addedNode, j); } } else { return(simplifier.HandleError(new CannotAddTensors(simplifier, node, $"Cannot add tensor of shape {otherTensorNode.SizeIdentity} and tensor of shape {tensorNode.SizeIdentity}."))); } } else { return(simplifier.HandleError(new CannotAddTensors(simplifier, node, "Cannot add scalar and tensor."))); } } return(tensorNode); } else { // There is a scalar. // There cannot be any tensors for (int i = 1; i < node.ChildCount; i++) { if (node.GetChild(i) is TensorNode) { return(simplifier.HandleError(new CannotAddTensors(simplifier, node, "Cannot add tensor and scalar."))); } } } return(node); }
/// <inheritdoc/> public override ExpNode Execute(AdditionOperNode node) { double valueProg = 0; for (int i = 0; i < node.ChildCount; i++) { ExpNode simpleChild = node.GetChild(i).Execute(this); if (simpleChild is NumericalValueNode nvNode) { valueProg += nvNode.DoubleValue; node.RemoveChild(i); i--; } else if (simpleChild is AdditionOperNode aNode) { aNode.TransferChildren(node); node.RemoveChild(i); i--; } else { node.ReplaceChild(simpleChild, i); } } if (node.ChildCount == 0 || valueProg != 0) { node.AddChild(QuickOpers.MakeNumericalNode(valueProg)); } AdditionHelpers.SimplfiyATerms(node); if (node.ChildCount == 0) { return(QuickOpers.MakeNumericalNode(0)); } else if (node.ChildCount == 1) { return(node.GetChild(0)); } return(AdditionHelpers.SumTensors(node, this)); }
/// <inheritdoc/> public override string Print(AdditionOperNode node) { string cache = string.Empty; // Add each child seperated by a '+' for (int i = 0; i < node.ChildCount; i++) { var child = node.GetChild(i); bool implicitSign = child is SignOperNode || ((child is NumericalValueNode nvChild) && nvChild.DoubleValue < 0); if (!(i == 0 || implicitSign)) { // Don't add if is a negative sign operator, // a negative numerical value // or if first iteration cache += "+"; } cache += child.Print(this); } return(cache); }
// All methods by default call their direct parent type except ExpNode because it is the root type. // As a result, types only need to be overriden if they can't be handled by a parent type. /// <summary> /// Executes operation on an <see cref="AdditionOperNode"/>. /// </summary> /// <param name="node">The <see cref="AdditionOperNode"/> to execute operation on.</param> /// <returns>The result of the operation on an <see cref="AdditionOperNode"/>.</returns> public virtual ExpNode Execute(AdditionOperNode node) => Execute((NOperNode)node);
/// <summary> /// Initializes a new instance of the <see cref="CannotAddTensors"/> class. /// </summary> /// <param name="simplifier">The simplified that threw.</param> /// <param name="context">The <see cref="AdditionOperNode"/> that it threw simplifying.</param> /// <param name="message">The <see cref="Exception"/> message.</param> public CannotAddTensors(Simplifier simplifier, AdditionOperNode context, string message = "") : base(simplifier, context, message) { }
// All methods by default call their direct parent type except ExpNode because it is the root type. // As a result, types only need to be overriden if they can't be handled by a parent type. /// <summary> /// Prints an <see cref="AdditionOperNode"/>. /// </summary> /// <param name="node">The <see cref="AdditionOperNode"/> to print.</param> /// <returns>The <see cref="AdditionOperNode"/> printed to a string.</returns> public virtual string Print(AdditionOperNode node) => Print((NOperNode)node);