* @param gemFactory used for creating value and function gems
* @param calServices
*/
public static GemGraph positiveOutlierDetectorGemGraph(GemFactory gemFactory, BasicCALServices calServices) throws TypeException {
GemGraph gemGraph = new GemGraph();
gemGraph.getTargetCollector().setName("positiveOutlierDetector");
// A collector targeting the target collector. It will be an argument of the positiveOutlierDetector gem.
CollectorGem sourceDataCollector = new CollectorGem();
sourceDataCollector.setName("sourceData");
gemGraph.addGem(sourceDataCollector);
// Local collector: avg
// Corresponding source: avg = Summary.average sourceData;
CollectorGem avgCollector = new CollectorGem();
avgCollector.setName("avg");
gemGraph.addGem(avgCollector);
// a ReflectorGem provides as output the value that is collected by the corresponding CollectorGem
ReflectorGem sourceDataReflector1 = new ReflectorGem(sourceDataCollector);
gemGraph.addGem(sourceDataReflector1);
Gem averageGem = gemFactory.makeFunctionalAgentGem(CAL_Summary.Functions.average);
gemGraph.addGem(averageGem);
gemGraph.connectGems(sourceDataReflector1.getOutputPart(), averageGem.getInputPart(0));
gemGraph.connectGems(averageGem.getOutputPart(), avgCollector.getInputPart(0));
// Local collector: stdDev
// Corresponding source: stdDev = Summary.populationStandardDeviation sourceData;
CollectorGem stdDevCollector = new CollectorGem();
stdDevCollector.setName("stdDev");
gemGraph.addGem(stdDevCollector);
ReflectorGem sourceDataReflector2 = new ReflectorGem(sourceDataCollector);
gemGraph.addGem(sourceDataReflector2);
Gem populationStdDevGem = gemFactory.makeFunctionalAgentGem(CAL_Summary.Functions.populationStandardDeviation);
gemGraph.addGem(populationStdDevGem);
gemGraph.connectGems(sourceDataReflector2.getOutputPart(), populationStdDevGem.getInputPart(0));
gemGraph.connectGems(populationStdDevGem.getOutputPart(), stdDevCollector.getInputPart(0));
// Local collector: isPositiveOutlier
// Corresponding source: isPositiveOutlier x_1 = x_1 - avg >= x_2 * stdDev;
CollectorGem isPositiveOutlierCollector = new CollectorGem();
isPositiveOutlierCollector.setName("isPositiveOutlier");
gemGraph.addGem(isPositiveOutlierCollector);
Gem subtractGem = gemFactory.makeFunctionalAgentGem(CAL_Prelude.Functions.subtract);
gemGraph.addGem(subtractGem);
ReflectorGem avgReflector = new ReflectorGem(avgCollector);
gemGraph.addGem(avgReflector);
// Retarget the first input of subtract to the isPositiveOutlier collector
//
// This means that the first input of subtract is no longer an argument for the overall Gem defined by the
// GemGraph's target collector, but rather a local argument for the isPositiveOutlier collector.
gemGraph.retargetInputArgument(subtractGem.getInputPart(0), isPositiveOutlierCollector, -1);
gemGraph.connectGems(avgReflector.getOutputPart(), subtractGem.getInputPart(1));
Gem multiplyGem = gemFactory.makeFunctionalAgentGem(CAL_Prelude.Functions.multiply);
gemGraph.addGem(multiplyGem);
ReflectorGem stdDevReflector = new ReflectorGem(stdDevCollector);
gemGraph.addGem(stdDevReflector);
// Leave the first input of multiply targeting the target collector (it will be an argument of the positiveOutlierDetector gem),
// but hook up the second input of multiply to the stdDev reflector
gemGraph.connectGems(stdDevReflector.getOutputPart(), multiplyGem.getInputPart(1));
Gem greaterThanEqualsGem = gemFactory.makeFunctionalAgentGem(CAL_Prelude.Functions.greaterThanEquals);
gemGraph.addGem(greaterThanEqualsGem);
gemGraph.connectGems(subtractGem.getOutputPart(), greaterThanEqualsGem.getInputPart(0));
gemGraph.connectGems(multiplyGem.getOutputPart(), greaterThanEqualsGem.getInputPart(1));
gemGraph.connectGems(greaterThanEqualsGem.getOutputPart(), isPositiveOutlierCollector.getInputPart(0));
// Update the reflected inputs of the collector because one of the inputs in the gem tree was retargeted
isPositiveOutlierCollector.updateReflectedInputs();
// Construct the gem tree connected to the target collector
ReflectorGem isPositiveOutlierReflector = new ReflectorGem(isPositiveOutlierCollector);
gemGraph.addGem(isPositiveOutlierReflector);
isPositiveOutlierReflector.getInputPart(0).setBurnt(true);
ReflectorGem sourceDataReflector3 = new ReflectorGem(sourceDataCollector);
gemGraph.addGem(sourceDataReflector3);
Gem filterGem = gemFactory.makeFunctionalAgentGem(CAL_List.Functions.filter);
gemGraph.addGem(filterGem);
gemGraph.connectGems(isPositiveOutlierReflector.getOutputPart(), filterGem.getInputPart(0));
gemGraph.connectGems(sourceDataReflector3.getOutputPart(), filterGem.getInputPart(1));
gemGraph.connectGems(filterGem.getOutputPart(), gemGraph.getTargetCollector().getInputPart(0));
gemGraph.typeGemGraph(calServices.getTypeCheckInfo(GEM_GRAPH_TYPE_CHECKING_MODULE));
return gemGraph;
}