@Override
	public Step execute(Algebra algebra) {
		Fraction frac = (Fraction) algebra;
		
		//get factors of top and bottom
		Map<AlgebraicParticle, Integer> factorsTop = factors(frac.getTop()),
				factorsBottom = factors(frac.getBottom());
		
		//find intersection of set of factors of top and bottom
		Set<AlgebraicParticle> commonFactors = new HashSet<AlgebraicParticle>(factorsTop.keySet());
		commonFactors.retainAll(factorsBottom.keySet());
		
		//cancel all the common factors and add what doesn't cancel to the respective list
		for(AlgebraicParticle element : commonFactors) {
			Integer numTop = factorsTop.get(element), numBottom = factorsBottom.get(element);
			
			//cancel the factors, and if there are more on top than bottom, leave some on top, else 
			//leave more on the bottom.
			int numToCancel = numTop > numBottom ? numBottom : numTop;
			int resultNumTop = numTop - numToCancel;
			int resultNumBottom = numBottom - numToCancel;
			
			//set the new coefficient for every factor (canceling)
			factorsTop.put(element, resultNumTop);
			factorsBottom.put(element, resultNumBottom);
		}
		
		//calculate the sign for the terms
		boolean sign = factorsTop.containsKey(Number.NEGATIVE_ONE) == factorsBottom.containsKey(Number.NEGATIVE_ONE);
		sign = sign == frac.sign();
		
		//remove -1 & 1 from factors (if necessary) (have already tracked -1, so can ignore now)
		factorsTop.remove(Number.NEGATIVE_ONE);
		factorsBottom.remove(Number.NEGATIVE_ONE);
		
		//we factored integers; now multiply the ones that didn't cancel
		multiplyIntegers(factorsTop);
		multiplyIntegers(factorsBottom);
		
		AlgebraicParticle top = constructResult(factorsTop);
		AlgebraicParticle bottom = constructResult(factorsBottom);
		
		Fraction done = new Fraction(sign, top, bottom, frac.exponent());
		AlgebraicParticle result = done;
		
		//if the bottom is 1, the result is the top (any number divided by 1 is that number)
		if(done.getBottom().equals(Number.ONE)) {
			if(sign) result = done.getTop();
			else result = done.getTop().cloneWithNewSign(sign);
		}
		
		Step step = new Step(result);

		AlgebraicParticle[] commonFactorsArray = commonFactors.toArray(new AlgebraicParticle[commonFactors.size()]);
		//if there were factors, explain. There aren't always factors; e.g. 4/1 simplifies to 4
		int count = commonFactorsArray.length;
		if(count != 0) {
			step.explain("In the fraction ").explain(frac)
			.explain(" the common factor" + (count == 1 ? " is " : "s are "))
			.list(commonFactorsArray).explain(". Dividing top and bottom by ");
			//specify the term to divide by if there's only 1, otherwise just say "these"
			if(count == 1) step.explain(commonFactorsArray[0]);
			else step.explain("these");
			step.explain(" leaves ").explain(result).explain(".");
		}
		//there weren't any factors that could cancel
		else step.explain("Simplify ").explain(frac).explain(" to get ").explain(result);
		
		return step;
	}