private static bool ReduceMultipliedAlphabeticFactors(ComponentListFactor leftFactor, ComponentListFactor rightFactor, out Expression expression)
		{
			// If any alphabetic factors are identical, convert to exponent
			if (leftFactor.Factor is AlphabeticFactor && rightFactor.Factor is AlphabeticFactor)
			{
				var leftAlpha = (AlphabeticFactor) leftFactor.Factor;
				var rightAlpha = (AlphabeticFactor) rightFactor.Factor;

				if (leftAlpha.Value.Equals(rightAlpha.Value))
				{
					var shouldPower = leftFactor.IsInNumerator && rightFactor.IsInNumerator;
					if (shouldPower)
					{
						expression = new SingleComponentExpression(new FunctionComponent("^", new List<Expression> { Expressionizer.ToExpression(leftAlpha), NumberToExpression(new Integer(2)) }));
						return true;
					}

					expression = NumberToExpression(new Integer(1));
					return true;
				}
			}

			expression = null;
			return false;
		}
		private static bool ReduceFunctionsWithSameOperands(ComponentListFactor leftFactor, ComponentListFactor rightFactor, out Expression expression, Expression left, Expression right)
		{
			FunctionComponent leftFunction;
			FunctionComponent rightFunction;
			// If there are two functions with the same operands that should cancel out, cancel them out
			if (Common.IsFunction(left, out leftFunction) && Common.IsFunction(right, out rightFunction))
			{
				if (leftFunction.Function.Name == rightFunction.Function.Name &&
				    leftFunction.Operands.Count == rightFunction.Operands.Count)
				{
					for (var i = 0; i < leftFunction.Operands.Count; i++)
					{
						var leftOperand = leftFunction.Operands[i];
						var rightOperand = rightFunction.Operands[i];

						if (!leftOperand.ToString().Equals(rightOperand.ToString()))
						{
							break;
						}

						if (leftFactor.IsInNumerator != rightFactor.IsInNumerator)
						{
							expression = Expressionizer.ToExpression(new NumericFactor(new Integer(1)));
							return true;
						}
					}
				}
			}

			expression = null;
			return false;
		}
		private static bool CanReduce(ComponentListFactor leftFactor, ComponentListFactor rightFactor, out Expression expression)
		{
			if (ReduceMultipliedAlphabeticFactors(leftFactor, rightFactor, out expression))
			{
				return true;
			}

			var left = Expressionizer.ToExpression(leftFactor.Factor);
			var right = Expressionizer.ToExpression(rightFactor.Factor);

			Number leftNumber;
			Number rightNumber;

			if ((Common.IsConstant(left, out leftNumber) && Common.IsFloat(right, out rightNumber)) ||
				(Common.IsFloat(left, out leftNumber) && Common.IsConstant(right, out rightNumber)) ||
				(Common.IsNumber(left, out leftNumber) && Common.IsNumber(right, out rightNumber)))
			{
				expression = Evaluate(leftNumber, rightNumber, leftFactor.IsInNumerator, rightFactor.IsInNumerator);
				return true;
			}

			ExpressionList leftList;
			ExpressionList rightList;

			if (Common.IsList(left, out leftList))
			{
				expression = Evaluate(leftList, right, leftFactor.IsInNumerator == rightFactor.IsInNumerator);
				return true;
			}

			if (Common.IsList(right, out rightList))
			{
				expression = Evaluate(rightList, left, leftFactor.IsInNumerator == rightFactor.IsInNumerator);
				return true;
			}

			IntegerFraction leftFraction;
			IntegerFraction rightFraction;

			if (Common.IsNumber(left, out leftNumber) && Common.IsIntegerFraction(right, out rightFraction))
			{
				expression = Expressionizer.ToExpression(Evaluate(leftNumber, rightFraction, leftFactor.IsInNumerator, rightFactor.IsInNumerator));
				return true;
			}

			if (Common.IsIntegerFraction(left, out leftFraction) && Common.IsNumber(right, out rightNumber))
			{
				expression = Expressionizer.ToExpression(Evaluate(leftFraction, rightNumber, leftFactor.IsInNumerator, rightFactor.IsInNumerator));
				return true;
			}

			if (Common.IsIntegerFraction(left, out leftFraction) && Common.IsIntegerFraction(right, out rightFraction))
			{
				expression = Expressionizer.ToExpression(Evaluate(leftFraction, rightFraction, leftFactor.IsInNumerator, rightFactor.IsInNumerator));
				return true;
			}

			if (ReduceFunctionsWithSameOperands(leftFactor, rightFactor, out expression, left, right))
			{
				return true;
			}

			if (ReduceExponents(out expression, left, right))
			{
				return true;
			}

			expression = null;
			return false;
		}