/// <summary> /// Applies the multiplicative distributive property. /// </summary> /// <param name="node">The <see cref="MultiplicationOperNode"/> to simplify.</param> /// <param name="simplifier">The <see cref="Simplifier"/> calling.</param> /// <returns>The resuling <see cref="ExpNode"/>.</returns> public static ExpNode Distribute(MultiplicationOperNode node, Simplifier simplifier) { if (node.GetChild(node.ChildCount - 1) is ParenthesisOperNode parNode) { // Last child is parenthesis if (parNode.Child is AdditionOperNode aNode) { // Last grandchild is addition for (int i = 0; i < aNode.ChildCount; i++) { MultiplicationOperNode mNode = new(); mNode.AddChild(aNode.GetChild(i)); for (int j = 0; j < node.ChildCount - 1; j++) { mNode.AddChild(node.GetChild(j).Clone()); } aNode.ReplaceChild(mNode, i); } return(aNode.Execute(simplifier)); } } return(node); }
/// <inheritdoc/> public override ExpNode Execute(MultiplicationOperNode node) { // TODO: Sinusoidal u substitutions // TODO: Constants recognitions for v Differentiator differentiator = new(_variable); // \int{u'vwx} = uvwx - \int{uv'wx} - \int{uvw'x} - \int{uvwx'} int partCount = node.ChildCount - 1; // Get u and du ExpNode du = node.GetChild(partCount); ExpNode u = du.Clone().Execute(this); // Get dvs and vs ExpNode[] dvs = new ExpNode[partCount]; ExpNode[] vs = new ExpNode[partCount]; for (int i = 0; i < partCount; i++) { vs[i] = node.GetChild(i); dvs[i] = vs[i].Clone().Execute(differentiator); } AdditionOperNode aNode = new(); // u*vs MultiplicationOperNode mNode = new(); mNode.AddChild(u.Clone()); for (int i = 0; i < partCount; i++) { mNode.AddChild(vs[i].Clone()); } aNode.AddChild(mNode); // Combinatoric integrals for (int i = 0; i < partCount; i++) { IntegralOperNode intNode = new(); mNode = new MultiplicationOperNode(); intNode.Variable = new VarValueNode(_variable); mNode.AddChild(u.Clone()); for (int j = 0; j < partCount; j++) { if (i == j) { mNode.AddChild(dvs[j].Clone()); } else { mNode.AddChild(vs[j].Clone()); } } intNode.AddChild(mNode); aNode.AddChild(QuickOpers.Negative(intNode)); } return(aNode); }
/// <inheritdoc/> public override ExpNode Execute(MultiplicationOperNode node) { double valueProg = 1; 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 MultiplicationOperNode mNode) { mNode.TransferChildren(node); node.RemoveChild(i); i--; } else { node.ReplaceChild(simpleChild, i); } } // Anything multiplied by 0, is zero if (valueProg == 0) { return(QuickOpers.MakeNumericalNode(0)); } if (node.ChildCount == 0 || valueProg != 1) { node.AddChild(QuickOpers.MakeNumericalNode(valueProg)); } MultiplicationHelpers.SimplfiyMTerms(node, this); if (node.ChildCount == 0) { return(QuickOpers.MakeNumericalNode(0)); } else if (node.ChildCount == 1) { return(node.GetChild(0)); } node = MultiplicationHelpers.MultiplyScalarTensor(node, this); if (node == null) { return(node); } return(MultiplicationHelpers.Distribute(node, this)); }
/// <summary> /// Splits an <see cref="MultiplicationOperNode"/> into terms and simplifies by common terms. /// </summary> /// <param name="node">The <see cref="MultiplicationOperNode"/> to simplify.</param> /// <param name="simplifier">The <see cref="Simplifier"/> calling.</param> /// <returns>The resulting <see cref="ExpNode"/>.</returns> public static MultiplicationOperNode SimplfiyMTerms(MultiplicationOperNode node, Simplifier simplifier) { SortedSet <MultiplicativeTerm> mTerms = new(); for (int i = 0; i < node.ChildCount; i++) { MultiplicativeTerm mTerm = new(node.GetChild(i)); if (mTerms.TryGetValue(mTerm, out MultiplicativeTerm existingMTerm)) { existingMTerm.AddToExponent(mTerm, simplifier); } else { mTerms.Add(mTerm); } } node.ClearChildren(); foreach (var term in mTerms) { node.AddChild(term.AsExpNode()); } return(node); }
/// <summary> /// Multiplies a tensor by scalars. /// </summary> /// <param name="node">The <see cref="MultiplicationOperNode"/> to simplify.</param> /// <param name="simplifier">The <see cref="Simplifier"/> calling.</param> /// <returns>The resuling <see cref="MultiplicationOperNode"/>.</returns> public static MultiplicationOperNode MultiplyScalarTensor(MultiplicationOperNode node, Simplifier simplifier) { TensorNode tensor1 = null; int ti = -1; for (int i = 0; i < node.ChildCount; i++) { if (i == ti) { continue; } if (node.GetChild(i) is TensorNode tensor2) { if (tensor1 != null) { if (i < ti) { TensorNode swap = tensor1; tensor1 = tensor2; tensor2 = swap; } if (!tensor1.CanMatrixMultiply(tensor2)) { return((MultiplicationOperNode)simplifier.HandleError(new CannotMultiplyTensors(simplifier, node, $"Tensor nodes of size {tensor1.SizeIdentity} and {tensor2.SizeIdentity} could not be multiplied."))); } } else { tensor1 = tensor2; ti = i; i = -1; } } else { if (tensor1 != null) { for (int j = 0; j < tensor1.ChildCount; j++) { ExpNode simpleChild = QuickOpers.Multiply(tensor1.GetChild(j), node.GetChild(i)).Execute(simplifier); tensor1.ReplaceChild(simpleChild, j); } node.RemoveChild(i); if (i < ti) { ti--; } i--; } } } return(node); }
/// <inheritdoc/> public override string Print(MultiplicationOperNode node) { string cache = string.Empty; // No need to seperate with '*' // All remain multiplication should be represented with implied for (int i = 0; i < node.ChildCount; i++) { cache += node.GetChild(i).Print(this); } return(cache); }
/// <inheritdoc/> public override ExpNode Execute(MultiplicationOperNode node) { // Product rule AdditionOperNode aNode = new(); for (int i = 0; i < node.ChildCount; i++) { MultiplicationOperNode mNode = new(); mNode.AddChild(node.GetChild(i).Clone().Execute(this)); for (int j = 0; j < node.ChildCount; j++) { if (j != i) { mNode.AddChild(node.GetChild(j).Clone()); } } aNode.AddChild(mNode); } return(aNode); }