class ContextualOutlierDetector {

    public Map<Context, List<OutlierClassificationResult>> searchContextualOutliers(List<ContextualDatum> data) throws Exception {
        Stopwatch sw = Stopwatch.createUnstarted();
        log.debug("Find global context outliers on data num tuples: {} , MBs {} ", data.size());
        sw.start();
        HashSet<ContextualDatum> sample = randomSampling(data, 100);
        globalContext = new Context(sample, densityPruning, dependencyPruning, alpha);
        contextualOutlierDetection(data, globalContext);
        sw.stop();
        long globalOutlierDetecionTime = sw.elapsed(TimeUnit.MILLISECONDS);
        sw.reset();
        log.debug("Done global context outlier remaining data size {} : (duration: {}ms)", data.size(),
                  globalOutlierDetecionTime);
        List<LatticeNode> preLatticeNodes = new ArrayList<LatticeNode>();
        List<LatticeNode> curLatticeNodes = new ArrayList<LatticeNode>();
        for (int level = 1; level <= totalContextualDimensions; level++) {
            if (level > maxPredicates)
                break;
            log.debug("Build {}-dimensional contexts on all attributes", level);
            sw.start();
            if (level == 1) {
                curLatticeNodes = buildOneDimensionalLatticeNodes(data);
            } else {
                curLatticeNodes = levelUpLattice(preLatticeNodes, data);
            }
            sw.stop();
            long latticeNodesBuildTimeCurLevel = sw.elapsed(TimeUnit.MILLISECONDS);
            sw.reset();
            log.debug("Done building {}-dimensional contexts on all attributes (duration: {}ms)", level,
                      latticeNodesBuildTimeCurLevel);
            log.debug("Memory Usage: {}", MemoryUtil.checkMemoryUsage());
            if (curLatticeNodes.size() == 0) {
                log.debug("No more dense contexts, thus no need to level up anymore");
                break;
            }
            log.debug("Find {}-dimensional contextual outliers", level);
            sw.start();
            int numDenseContextsCurLevel = 0;
            //run contextual outlier detection
            for (LatticeNode node : curLatticeNodes) {
                for (Context context : node.getDenseContexts()) {
                    contextualOutlierDetection(data, context);
                    numDenseContextsCurLevel++;
                }
            }
            sw.stop();
            long contextualOutlierDetectionTimeCurLevel = sw.elapsed(TimeUnit.MILLISECONDS);
            sw.reset();
            log.debug("Done Find {}-dimensional contextual outliers (duration: {}ms)", level,
                      contextualOutlierDetectionTimeCurLevel);
            log.debug(
                    "Done Find {}-dimensional contextual outliers, there are {} dense contexts(average duration per context: {}ms)",
                    level, numDenseContextsCurLevel,
                    (numDenseContextsCurLevel == 0) ? 0 : contextualOutlierDetectionTimeCurLevel / numDenseContextsCurLevel);
            log.debug("Done Find {}-dimensional contextual outliers, densityPruning2: {}, "
                      + "numOutlierDetectionRunsWithoutTrainingWithoutScoring: {},  "
                      + "numOutlierDetectionRunsWithoutTrainingWithScoring: {},  "
                      + "numOutlierDetectionRunsWithTrainingWithScoring: {}",
                      level, densityPruning2,
                      numOutlierDetectionRunsWithoutTrainingWithoutScoring,
                      numOutlierDetectionRunsWithoutTrainingWithScoring,
                      numOutlierDetectionRunsWithTrainingWithScoring);
            log.debug("----------------------------------------------------------");
            //free up memory
            if (level >= 2) {
                for (LatticeNode node : preLatticeNodes) {
                    for (Context context : node.getDenseContexts()) {
                        context2BitSet.remove(context);
                    }
                }
            }
            preLatticeNodes = curLatticeNodes;
        }
        return context2Outliers;
    }

    public  ContextualOutlierDetector(MacroBaseConf conf);

}