/// <summary> /// Converts this collapsed product operation into a normal mathematical expression. /// </summary> public Expression ToExpression() { //If we have zero or less terms, we have no idea what the hell is going on if (this.Arity <= 0) throw new Exceptions.SimplexMathException("Unable to convert collapsed product operation to expression - invalid arity"); //If we only have one term, just return that term if (this.Arity == 1) return this.ChildExpressions[0]; //If we only have two terms, just return the product of those two terms if (this.Arity == 2) { if (!Propositions.IsNonValueInverse[this.ChildExpressions[0]] && Propositions.IsNonValueInverse[this.ChildExpressions[1]]) return (this.ChildExpressions[0] / (1 / this.ChildExpressions[1])); if (Propositions.IsNonValueInverse[this.ChildExpressions[0]] && !Propositions.IsNonValueInverse[this.ChildExpressions[1]]) return (this.ChildExpressions[1] / (1 / this.ChildExpressions[0])); if (Propositions.IsNonValueInverse[this.ChildExpressions[0]] && Propositions.IsNonValueInverse[this.ChildExpressions[1]]) return 1 / ((1 / this.ChildExpressions[0]) * (1 / this.ChildExpressions[1])); return (this.ChildExpressions[0] * this.ChildExpressions[1]); } //Otherwise, if we have more than two terms, we will return a new product of the first term //and the rest of the terms cast to a CPO which are converted back to an expression. var FirstTerm = this.ChildExpressions[0]; var SecondTerm = new CollapsedProductOperation(this.ChildExpressions.GetRange(1, this.ChildExpressions.Count - 1).ToArray()).ToExpression(); if (!Propositions.IsNonValueInverse[FirstTerm] && Propositions.IsNonValueInverse[SecondTerm]) return (FirstTerm / (1 / SecondTerm)); if (Propositions.IsNonValueInverse[FirstTerm] && !Propositions.IsNonValueInverse[SecondTerm]) return (SecondTerm / (1 / FirstTerm)); if (Propositions.IsNonValueInverse[FirstTerm] && Propositions.IsNonValueInverse[SecondTerm]) return 1 / ((1 / FirstTerm) * (1 / SecondTerm)); return new Product(FirstTerm, SecondTerm); }
/// <summary> /// Merges two collapsed product operations together into a single collapsed product operation. /// </summary> /// <param name="CPO1">The first collapsed product operation to merge</param> /// <param name="CPO2">The second collapsed product operation to merge</param> public static CollapsedProductOperation Merge(CollapsedProductOperation CPO1, CollapsedProductOperation CPO2) { return new CollapsedProductOperation(CPO1.ChildExpressions.Concat(CPO2.ChildExpressions).ToArray()); }
/// <summary> /// Tests the equality between two CPOs. Assumes associative and commutative rules. /// </summary> /// <param name="CPO1">The first CPO to test</param> /// <param name="CPO2">The second CPO to test</param> public static bool TestEquality(CollapsedProductOperation CPO1, CollapsedProductOperation CPO2) { //First, lets make sure our CPO's have the same number of terms (we will assume our CPOs are NOT reduced) if (CPO1.Arity != CPO2.Arity) { //If reducing our CPOs makes them have the same number of terms, test the reduced CPOs var CPO1r = CPO1.Reduce(); var CPO2r = CPO2.Reduce(); if (CPO1r.Arity == CPO2r.Arity) return TestEquality(CPO1r, CPO2r); else return false; } //We will use a dictionary object to store our records of matches (since product operations can contain multiples of the same expression) //This makes it so that the test for {x, y, x, 1} == {x, y, z, 1} would not pass. Dictionary<int, int> IndexMatches = new Dictionary<int, int>(CPO1.ChildExpressions.Count); //For each item in the first CPO: for (int i = 0; i < CPO1.ChildExpressions.Count; i++) { //For each item in the second CPO: for (int j = 0; j < CPO2.ChildExpressions.Count; j++) { //If these two expressions are equal: if (CPO1.ChildExpressions[i] == CPO2.ChildExpressions[j]) { //If the index of the expression in CSO2 has not been matched to something in CSO1 AND this index hasn't been matched to anything yet: if (!IndexMatches.ContainsValue(j) && !IndexMatches.ContainsKey(i)) IndexMatches.Add(i, j); } } //When we are done going through CSO2, if we didn't find a unique match, then return false if (!IndexMatches.ContainsKey(i)) return false; } //If we didn't find any conflicts, return true return true; }