LinearPrinter.println("   filter needs to consume " + totalConsumption + " item");
LinearPrinter.println("   filter needs to consume " + totalConsumption + " items");
    public static LinearTransform calculateRoundRobin(List representationList,					       int[] joinerWeights,					       int[] splitterWeights) {       	LinearPrinter.println(" calculating splitjoin transform with roundrobin splitter.");	if (representationList.size() != splitterWeights.length) {	    throw new IllegalArgumentException("different numbers of reps and splitter weights " +					       "while transforming splitjoin");	}	// calculate the rep list from the passed in list	LinearFilterRepresentation[] filterReps = parseRepList(representationList);	if (filterReps == null) { return new LinearTransformNull("Peek didn't match pop rate."); }	int filterCount = filterReps.length;	// first, we are going to figure out how many times the roundrobin splitter	// fires in the steady state by determining the lcm of the weight and rows	// of each A  divided by weightsand then the overall Lcm of that.	int[] splitterFiringLcms = new int[filterCount];	for (int i=0; i<filterCount; i++) {	    int rows = filterReps[i].getPeekCount();	    int weight = splitterWeights[i];	    int currentLcm = lcm(rows, weight); // number of items that need to be produced in the steady state	    // number of times splitter needs to be fired to produce the correct number of outputs	    int currentSplitterFirings = currentLcm / weight;	    splitterFiringLcms[i] = currentSplitterFirings;	    	    LinearPrinter.println("  lcm of filter " + i + "'s rows (" + rows +				  ") and weight(" + weight + ") = " + lcm(weight, rows));	    LinearPrinter.println("  splitter firings: " + splitterFiringLcms[i]);	}	int splitterFirings = lcm(splitterFiringLcms);	LinearPrinter.println("  overall splitter firings: " + splitterFirings);	// now, figure out the sum of the splitter weights (eg the total number	// of rows (possibly off by an integer factor) that we would like	// each of the filter reps to end up having	int splitterSum = 0;	for (int i=0; i<filterCount; i++) {	    splitterSum += splitterWeights[i];	}	LinearPrinter.println("  total splitter sum: " + splitterSum);	// first expand all reps by a factor of splitterFirings. 	// then, we know that each filter can be expanded into splitterSum * currentRows new rows.	// with (splitterSum - splitterWeights[i])*rows of zeros	LinearFilterRepresentation[] duplicateReps = new LinearFilterRepresentation[filterCount];	int currentOffset = 0;	for (int i=0; i<filterCount; i++) {	    LinearPrinter.println("  expanding filter: " + i);	    LinearFilterRepresentation expandedRep;	    // the number of items the new filter needs to consume	    int totalConsumption = (splitterFirings * splitterWeights[i]);	    LinearPrinter.println("   filter needs to consume " + totalConsumption + " item");	    // the total number of times that a filter needs to execute (eg how much to expand it by)	    // note this is always going to be an integer due to the way we calculated splitterFirings	    int filterExecutions = totalConsumption / filterReps[i].getPeekCount();	    LinearPrinter.println("   filter needs to execute " + filterExecutions + " times");	    if ((totalConsumption % filterReps[i].getPeekCount()) != 0) {		throw new RuntimeException("filter executes a fractional number of times");	    }	    // now, just expand the current rep be the factor that we have calculated	    expandedRep = filterReps[i].expand(filterExecutions);	    	    // make a new representation that has the same # of cols	    // but splitterSum * currentRows rows.	    int newRows = splitterSum * splitterFirings;	    int newCols = expandedRep.getPushCount();	    FilterMatrix newA = new FilterMatrix(newRows, newCols);	    FilterVector newb = (FilterVector)expandedRep.getb().copy();	    LinearPrinter.println("  created new A(" + newRows + "," + newCols + ")");	    LinearPrinter.println("  copied b(" + newCols + ")");	    	    // now, copy the rows from old representation into the new representation	    int numSections = expandedRep.getPeekCount() / splitterWeights[i];	    LinearPrinter.println("  number of " + splitterWeights[i] + " sections is " + numSections); 	    // each section has the splitterWeights[i] rows associated with it	    for (int j=0; j<numSections; j++) { // j is the jth chunk of weights[i] rows		LinearPrinter.println("  copying chunk " + j + " of " + splitterWeights[i] + " rows into filter " + i);		// copy the rows into A and b of the new representation		int newStart = currentOffset + j*splitterSum; // start row in newRep		int sourceStart = j*splitterWeights[i]; // start row in expandedRep.A		int numRows = splitterWeights[i]; // number of rows to copy		newA.copyRowsAt(newStart, expandedRep.getA(), sourceStart, numRows);	    }	    // update the current offset (from the top) where we copy data to	    currentOffset += splitterWeights[i];	    //LinearPrinter.println("  new A: \n" + newA);	    //LinearPrinter.println("  new b: \n" + newb);	    duplicateReps[i] = new LinearFilterRepresentation(newA, newb, newRows);	}	// now we are ready to try duplicating	return calculateDuplicate(duplicateReps, joinerWeights);    }