/// <inheritdoc/> public override ExpNode Execute(VectorProductOperNode node) { // Verify left and right child are two multiplyable vectors. if (node.LeftChild is TensorNode vector1 && vector1.DimensionCount == 1 && node.RightChild is TensorNode vector2 && vector2.DimensionCount == 1 && vector1.SizeIdentity == vector2.SizeIdentity) { int size = vector1.GetDimensionSize(1); switch (node.ProductMethod) { case VectorProductMethod.DOT: ExpNode[] terms = new ExpNode[size]; for (int i = 0; i < size; i++) { terms[i] = QuickOpers.Multiply(vector1.GetChild(i), vector2.GetChild(i)); } return(QuickOpers.Sum(terms).Execute(this)); case VectorProductMethod.CROSS: // TODO: Convert to matrix notation for determinant default: return(node); } } return(HandleError(new CannotMultiplyTensors(this, node))); }
/// <inheritdoc/> public override ExpNode Execute(VarValueNode node) { if (node.Character != _variable.Character) { return(ConstantRule(node)); } return(QuickOpers.Multiply(.5, QuickOpers.Pow(node, 2))); }
/// <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> /// 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 ExpNode Execute(RecipricalOperNode node) { node.Child = node.Child.Execute(this); if (node.Child is NumericalValueNode nvNode) { return(QuickOpers.MakeNumericalNode(1 / nvNode.DoubleValue)); } return(QuickOpers.Pow(node.Child, -1).Execute(this)); }
private void CompleteValue() { if (_state != ParserState.INT && _state != ParserState.FLOAT) { return; } double value = Convert.ToDouble(_cache); _tree.AddNode(QuickOpers.MakeNumericalNode(value)); _cache = string.Empty; }
/// <inheritdoc/> public override ExpNode Execute(VectorProjOperNode node) { if (node.LeftChild.AreEqualSizeVectors(node.RightChild, out TensorNode a, out TensorNode b)) { VectorProductOperNode adotb = QuickOpers.DotProduct(a, (TensorNode)b.Clone()); BOperNode bdotb = QuickOpers.DotProduct((TensorNode)b.Clone(), (TensorNode)b.Clone()); return(QuickOpers.Multiply(b, adotb, QuickOpers.Reciprical(bdotb)).Execute(this)); } return(HandleError(new CannotVectorProject(this, node))); }
private static ExpNode SineTable(SineOperNode node) { return(node.SineFunction switch { SineFunction.SINE => new SineOperNode(SineFunction.COSINE) { Child = node.Child }, SineFunction.COSINE => QuickOpers.Negative(new SineOperNode(SineFunction.SINE) { Child = node.Child }), _ => node, });
/// <inheritdoc/> public override ExpNode Execute(SineOperNode node) { if (node.IsConstantBy(_variable)) { return(QuickOpers.MakeNumericalNode(0)); } // Apply chain rule var coefficient = node.Child.Clone().Execute(this); // Apply table var sinFunc = SineTable(node); return(QuickOpers.Multiply(coefficient, sinFunc)); }
/// <inheritdoc/> public override ExpNode Execute(PowOperNode node) { // TODO: Handle variable in exponent if (node.IsConstantBy(_variable)) { return(QuickOpers.MakeNumericalNode(0)); } var coefficient = node.RightChild; var @base = node.LeftChild; var exponent = QuickOpers.Add(-1, coefficient); return(QuickOpers.Multiply(coefficient, QuickOpers.Pow(@base, exponent))); }
/// <inheritdoc/> public override ExpNode Execute(SineOperNode node) { if (node.IsConstantBy(_variable)) { return(ConstantRule(node)); } Differentiator diff = new(_variable); // Apply ChainRule var coefficient = node.Child.Execute(diff); // Apply table var sinFunc = SineTable(node); return(QuickOpers.Multiply(QuickOpers.Reciprical(coefficient), sinFunc)); }
/// <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> /// Converts the <see cref="NumericalValueNode"/> back to an <see cref="ExpNode"/>. /// </summary> /// <returns>The <see cref="NumericalValueNode"/> as an <see cref="ExpNode"/>.</returns> public ExpNode AsExpNode() { if (_exponent is NumericalValueNode nvNode) { if (nvNode.DoubleValue == 0) { return(QuickOpers.MakeNumericalNode(1)); } else if (nvNode.DoubleValue == 1) { return(_base); } } return(QuickOpers.Pow(_base, _exponent)); }
/// <summary> /// Initializes a new instance of the <see cref="MultiplicativeTerm"/> class. /// </summary> /// <param name="node">The node to create as a term.</param> public MultiplicativeTerm(ExpNode node) { DefaultPrinter printer = new(); if (node is PowOperNode powNode) { _base = powNode.LeftChild; _exponent = powNode.RightChild; } else { _base = node; _exponent = QuickOpers.MakeNumericalNode(1); } _baseString = _base.Print(printer); }
/// <inheritdoc/> public override ExpNode Execute(RowElimOperNode node) { // Ensure matrix. if (node.Child is TensorNode tensorNode && tensorNode.TensorType == TensorType.Matrix) { MatrixByRow matrix = new MatrixByRow(tensorNode); int[] leadingPositions = RefHelpers.GetLeadingColumns(matrix); // Put in row-echelon form for (int i = 0; i < matrix.Height; i++) { int leftMostCol = RefHelpers.GetLeftMostColumn(leadingPositions, i); matrix.SwapRows(i, leftMostCol); Common.Swap(ref leadingPositions[i], ref leadingPositions[leftMostCol]); if (leadingPositions[i] == -1) { continue; } matrix[i].MultiplyRow(QuickOpers.Reciprical(matrix[i][leadingPositions[i]])); for (int j = i + 1; j < matrix.Height; j++) { matrix[j].AddRowToRow(matrix[i], QuickOpers.Negative(matrix[j][leadingPositions[i]])); leadingPositions[j] = RefHelpers.GetLeadingColumn(matrix[j]); } } if (node.EliminationMethod == RowElimMethod.GaussJordan) { // Put in reduced row-echelon form for (int i = matrix.Height - 1; i > 0; i--) { for (int j = i - 1; j >= 0; j--) { matrix[j].AddRowToRow(matrix[i], QuickOpers.Negative(matrix[j][leadingPositions[i]])); leadingPositions[j] = RefHelpers.GetLeadingColumn(matrix[j]); } } } return(matrix.AsExpNode()); } return(HandleError(new CannotReduceNonMatrix(this, node.Child))); }
/// <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 ExpNode Execute(PowOperNode node) { node.LeftChild = node.LeftChild.Execute(this); node.RightChild = node.RightChild.Execute(this); if (node.LeftChild is NumericalValueNode lnvNode && node.RightChild is NumericalValueNode rnvNode) { return(QuickOpers.MakeNumericalNode(Math.Pow(lnvNode.DoubleValue, rnvNode.DoubleValue))); } if (node.RightChild is IntValueNode ivNode) { if (ivNode.DoubleValue == 0) { return(QuickOpers.MakeNumericalNode(1)); } if (ivNode.DoubleValue == 1) { return(node.LeftChild); } if (node.LeftChild is ValueNode) { // No good expanding return(node); } int n = ivNode.Value; // Expand n times MultiplicationOperNode mNode = new(); mNode.AddChild(node.LeftChild); for (int i = 1; i < n; i++) { mNode.AddChild(node.LeftChild.Clone()); } return(mNode.Execute(this)); } return(PowerHelpers.Distribute(node)); }
/// <summary> /// Applies the power distributive property. /// </summary> /// <param name="node">The <see cref="PowOperNode"/> to simplify.</param> /// <returns>The resuling <see cref="ExpNode"/>.</returns> public static ExpNode Distribute(PowOperNode node) { if (node.LeftChild is ParenthesisOperNode parNode) { // Child is parenthesis // Check for multiplication if (parNode.Child is MultiplicationOperNode mNode) { // Grand child is multiplication // Distribute for (int i = 0; i < mNode.ChildCount; i++) { PowOperNode pow = QuickOpers.Pow(mNode.GetChild(i), node.RightChild.Clone()); mNode.ReplaceChild(pow, i); } return(mNode); } } return(node); }
/// <inheritdoc/> public override ExpNode Execute(SineOperNode node) { node.Child = node.Child.Execute(this); if (node.Child is NumericalValueNode nvNode) { double value = 0; switch (node.SineFunction) { case SineFunction.SINE: value = Math.Sin(nvNode.DoubleValue); break; case SineFunction.COSINE: value = Math.Cos(nvNode.DoubleValue); break; case SineFunction.TANGENT: value = Math.Tan(nvNode.DoubleValue); break; case SineFunction.COSECANT: value = 1 / Math.Sin(nvNode.DoubleValue); break; case SineFunction.SECANT: value = 1 / Math.Cos(nvNode.DoubleValue); break; case SineFunction.COTANGENT: value = 1 / Math.Tan(nvNode.DoubleValue); break; } return(QuickOpers.MakeNumericalNode(value)); } return(node); }
/// <inheritdoc/> public override ExpNode Execute(SignOperNode node) { node.Child = node.Child.Execute(this); switch (node.Sign) { case Sign.POSITIVE: return(node.Child); case Sign.NEGATIVE: { if (node.Child is NumericalValueNode nvNode) { return(QuickOpers.MakeNumericalNode(nvNode.DoubleValue * -1)); } return(QuickOpers.Multiply(-1, node.Child).Execute(this)); } default: return(node); } }
/// <summary> /// Adds the exponent of another <see cref="MultiplicativeTerm"/>. /// </summary> /// <param name="other">The other <see cref="MultiplicativeTerm"/>.</param> /// <param name="simplifier">The <see cref="Simplifier"/> to simplify with after adding.</param> public void AddToExponent(MultiplicativeTerm other, Simplifier simplifier) { _exponent = QuickOpers.Sum(_exponent, other._exponent).Execute(simplifier); }
/// <inheritdoc/> public override ExpNode Execute(VarValueNode node) { return(QuickOpers.MakeNumericalNode(node.Character == _variable.Character ? 1 : 0)); }
/// <inheritdoc/> public override ExpNode Execute(NumericalValueNode node) { return(QuickOpers.MakeNumericalNode(0)); }