edu.nyu.vida.data_polygamy.relationship_computation.CorrelationReducer.java Source code

Java tutorial

Introduction

Here is the source code for edu.nyu.vida.data_polygamy.relationship_computation.CorrelationReducer.java

Source

/* Copyright (C) 2016 New York University
   This file is part of Data Polygamy which is released under the Revised BSD License
   See file LICENSE for full license details. */
package edu.nyu.vida.data_polygamy.relationship_computation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Days;
import org.joda.time.Hours;
import org.joda.time.Months;
import org.joda.time.Weeks;
import org.joda.time.Years;

import edu.nyu.vida.data_polygamy.utils.FrameworkUtils;
import edu.nyu.vida.data_polygamy.utils.FrameworkUtils.PairAttributeWritable;
import edu.nyu.vida.data_polygamy.utils.FrameworkUtils.TimeSeriesStats;
import edu.nyu.vida.data_polygamy.utils.FrameworkUtils.TopologyTimeSeriesWritable;
import edu.nyu.vida.data_polygamy.utils.SpatialGraph;

public class CorrelationReducer extends Reducer<PairAttributeWritable, TopologyTimeSeriesWritable, Text, Text> {

    public static FrameworkUtils utils = new FrameworkUtils();

    Configuration conf;
    int dataset1, dataset2, spatial, temporal;
    int dataset1Key = 0;
    int dataset2Key = 1;
    String fileName;
    HashMap<Integer, String> datasets = new HashMap<Integer, String>();

    float scoreThreshold;
    float strengthThreshold;
    boolean hasScoreThreshold = false;
    boolean hasStrengthThreshold = false;
    boolean removeNotSignificant = false;
    boolean outputIds = false;

    // spatial information
    SpatialGraph spatialGraph = new SpatialGraph();
    SpatialGraph nbhdGraph = new SpatialGraph();
    SpatialGraph zipGraph = new SpatialGraph();
    int gridSize = 0;
    int[][] originalGrid;
    boolean isNbhd = false;
    boolean isGrid = false;
    boolean isZip = false;
    boolean isCity = false;

    // temporal information
    boolean isHour = false;
    boolean isDay = false;
    boolean isWeek = false;
    boolean isMonth = false;
    boolean isYear = false;

    // randomization
    boolean completeRandomization = false;
    String randomizationStr;
    int size = 0;

    // header
    HashMap<Integer, HashMap<Integer, String>> header = new HashMap<Integer, HashMap<Integer, String>>();

    // Monte Carlo permutation test
    //  null hypothesis (H0): random predictability
    //  we want to reject H0
    //  p-value is the rate of repetitions in the
    //    permutation test that have high score
    //    (i.e., if p-value is high, it means that
    //    a high score can be computed by random;
    //    in other words, a high p-value confirms H0)
    //  we reject H0 if p-value <= alpha
    float alpha = 0.05f;
    int repetitions = 1000;

    ArrayList<TopologyTimeSeriesWritable[]> timeSeriesPerSpatial = new ArrayList<TopologyTimeSeriesWritable[]>();

    Text keyWritable = new Text();
    Text valueWritable = new Text();

    boolean s3 = true;
    private MultipleOutputs<Text, Text> out;

    private void resolutionHandler(int spatialResolution, int temporalResolution) {
        spatial = spatialResolution;
        temporal = temporalResolution;

        // resetting
        isNbhd = false;
        isZip = false;
        isGrid = false;
        isCity = false;

        isHour = false;
        isDay = false;
        isWeek = false;
        isMonth = false;
        isYear = false;

        switch (spatial) {
        case FrameworkUtils.NBHD:
            spatialGraph.init(nbhdGraph);
            isNbhd = true;
            break;
        case FrameworkUtils.ZIP:
            spatialGraph.init(zipGraph);
            isZip = true;
            break;
        case FrameworkUtils.GRID:
            isGrid = true;
            break;
        case FrameworkUtils.CITY:
            isCity = true;
            break;
        default:
            isCity = true;
            break;
        }

        switch (temporal) {
        case FrameworkUtils.HOUR:
            isHour = true;
            break;
        case FrameworkUtils.DAY:
            isDay = true;
            break;
        case FrameworkUtils.WEEK:
            isWeek = true;
            break;
        case FrameworkUtils.MONTH:
            isMonth = true;
            break;
        case FrameworkUtils.YEAR:
            isYear = true;
            break;
        default:
            isYear = true;
            break;
        }
    }

    @Override
    public void setup(Context context) throws IOException, InterruptedException {

        out = new MultipleOutputs<Text, Text>(context);
        conf = context.getConfiguration();

        String[] datasetIdsStr = conf.get("dataset-keys", "").split(",");
        String[] datasetNames = conf.get("dataset-names", "").split(",");

        if (datasetIdsStr.length != datasetNames.length) {
            System.out.println("Something went wrong... Number of ids should match number of datasets");
            System.exit(-1);
        }

        for (int i = 0; i < datasetIdsStr.length; i++) {
            int datasetId = Integer.parseInt(datasetIdsStr[i]);
            String[] datasetAggHeader = conf.get("dataset-" + datasetIdsStr[i] + "-agg", "").split(",");

            HashMap<Integer, String> headerTemp = new HashMap<Integer, String>();
            for (int j = 0; j < datasetAggHeader.length; j++) {
                int attribute = Integer
                        .parseInt(datasetAggHeader[j].substring(0, datasetAggHeader[j].indexOf("-")));
                String name = datasetAggHeader[j].substring(datasetAggHeader[j].indexOf("-") + 1,
                        datasetAggHeader[j].length());
                headerTemp.put(attribute, name);
            }

            header.put(datasetId, headerTemp);
            datasets.put(datasetId, datasetNames[i]);
        }

        String scoreThresholdStr = conf.get("score-threshold", "");
        if (!scoreThresholdStr.isEmpty()) {
            hasScoreThreshold = true;
            scoreThreshold = Math.abs(Float.parseFloat(scoreThresholdStr));
        }

        String strengthThresholdStr = conf.get("strength-threshold", "");
        if (!strengthThresholdStr.isEmpty()) {
            hasStrengthThreshold = true;
            strengthThreshold = Math.abs(Float.parseFloat(strengthThresholdStr));
        }

        removeNotSignificant = Boolean.parseBoolean(conf.get("remove-not-significant"));
        completeRandomization = Boolean.parseBoolean(conf.get("complete-random"));
        randomizationStr = conf.get("complete-random-str", "");
        outputIds = conf.getBoolean("output-ids", false);

        // nbhd grapgh
        nbhdGraph.init(true, conf);

        // zipcode graph
        zipGraph.init(false, conf);

        // grid
        gridSize = 2048;
        //gridSize = Integer.parseInt(conf.get("spatial-resolution").replace("grid", ""));
        originalGrid = new int[gridSize][gridSize];
        for (int j = 0; j < gridSize; j++) {
            for (int i = 0; i < gridSize; i++)
                originalGrid[i][j] = j * gridSize + i;
        }
    }

    @Override
    public void reduce(PairAttributeWritable key, Iterable<TopologyTimeSeriesWritable> values, Context context)
            throws IOException, InterruptedException {

        //long start = System.currentTimeMillis();

        timeSeriesPerSpatial.clear();
        resolutionHandler(key.getSpatialResolution(), key.getTemporalResolution());

        TopologyTimeSeriesWritable[] elem;
        switch (spatial) {
        case FrameworkUtils.NBHD:
            for (int i = 0; i < spatialGraph.nbNodes(); i++) {
                elem = new TopologyTimeSeriesWritable[2];
                elem[0] = null;
                elem[1] = null;
                timeSeriesPerSpatial.add(elem);
            }
            break;
        case FrameworkUtils.ZIP:
            for (int i = 0; i < zipGraph.nbNodes(); i++) {
                elem = new TopologyTimeSeriesWritable[2];
                elem[0] = null;
                elem[1] = null;
                timeSeriesPerSpatial.add(elem);
            }
            break;
        case FrameworkUtils.GRID:
            for (int i = 0; i < gridSize; i++) {
                elem = new TopologyTimeSeriesWritable[2];
                elem[0] = null;
                elem[1] = null;
                timeSeriesPerSpatial.add(elem);
            }
            break;
        case FrameworkUtils.CITY:
            elem = new TopologyTimeSeriesWritable[2];
            elem[0] = null;
            elem[1] = null;
            timeSeriesPerSpatial.add(elem);
            break;
        default:
            // do nothing
            break;
        }

        size = timeSeriesPerSpatial.size();

        // initializing some variables
        dataset1 = key.getFirstDataset();
        dataset2 = key.getSecondDataset();
        fileName = datasets.get(dataset1) + "-" + datasets.get(dataset2) + "/"
                + utils.temporalResolutionStr(key.getTemporalResolution()) + "-"
                + utils.spatialResolutionStr(key.getSpatialResolution()) + "-"
                + ((key.getIsOutlier()) ? "outliers" : "events") + "-" + randomizationStr + "/data";

        Iterator<TopologyTimeSeriesWritable> it = values.iterator();
        TopologyTimeSeriesWritable timeSeries;
        while (it.hasNext()) {
            timeSeries = it.next();
            int indexSpatial = timeSeries.getSpatial();
            int dataset = timeSeries.getDataset();

            int datasetKey = 0;
            if (dataset == dataset1)
                datasetKey = dataset1Key;
            else
                datasetKey = dataset2Key;

            elem = timeSeriesPerSpatial.get(indexSpatial);
            if (elem[datasetKey] != null) {
                System.out.println("Something went wrong... Data already filled");
                System.exit(-1);
            }
            elem[datasetKey] = new TopologyTimeSeriesWritable(timeSeries);
            timeSeriesPerSpatial.set(indexSpatial, elem);
        }

        /*
         * Aligned Score and Strength
         */

        TimeSeriesStats stats = new TimeSeriesStats();
        for (int i = 0; i < size; i++) {
            elem = timeSeriesPerSpatial.get(i);
            TimeSeriesStats tempStats = getStats(temporal, elem[dataset1Key], elem[dataset2Key], false);
            stats.add(tempStats);
        }
        stats.computeScores();

        if (!stats.isIntersect())
            return;

        float alignedScore = stats.getRelationshipScore();
        float alignedStrength = stats.getRelationshipStrength();

        if ((hasScoreThreshold) && (Math.abs(alignedScore) < scoreThreshold))
            return;
        if ((hasStrengthThreshold) && (Math.abs(alignedStrength) < strengthThreshold))
            return;

        // assuming city resolution
        /*float nPosEventAtt1 = timeSeriesPerSpatial.get(0)[0].getNbPosEvents();
        float nNegEventAtt1 = timeSeriesPerSpatial.get(0)[0].getNbNegEvents();
        float nNonEventAtt1 = timeSeriesPerSpatial.get(0)[0].getNbNonEvents();
        float nPosEventAtt2 = timeSeriesPerSpatial.get(0)[1].getNbPosEvents();
        float nNegEventAtt2 = timeSeriesPerSpatial.get(0)[1].getNbNegEvents();
        float nNonEventAtt2 = timeSeriesPerSpatial.get(0)[1].getNbNonEvents();*/

        float nMatchEvents = stats.getMatchEvents();
        float nMatchPosEvents = stats.getMatchPosEvents();
        float nMatchNegEvents = stats.getMatchNegEvents();
        float nPosFirstNonSecond = stats.getPosFirstNonSecond();
        float nNegFirstNonSecond = stats.getNegFirstNonSecond();
        float nNonFirstPosSecond = stats.getNonFirstPosSecond();
        float nNonFirstNegSecond = stats.getNonFirstNegSecond();

        //HashSet<String> posEvents = stats.getPosEvents();
        //HashSet<String> negEvents = stats.getNegEvents();

        //long end = System.currentTimeMillis();

        /*
         * Monte Carlo Permutation Test
         */

        float pValue = 0;
        ArrayList<Integer[]> pairs = new ArrayList<Integer[]>();

        //long start2 = System.currentTimeMillis();

        switch (spatial) {
        case FrameworkUtils.NBHD:

            for (int j = 0; j < repetitions; j++) {
                //long startNbhd = System.currentTimeMillis();
                pairs.clear();
                pairs = (completeRandomization) ? spatialCompleteRandom() : bfsShift(true);

                stats = new TimeSeriesStats();
                for (int i = 0; i < pairs.size(); i++) {
                    Integer[] pair = pairs.get(i);
                    stats.add(getStats(temporal, timeSeriesPerSpatial.get(pair[0])[dataset1Key],
                            timeSeriesPerSpatial.get(pair[1])[dataset2Key], false));
                }
                stats.computeScores();

                float mcScore = stats.getRelationshipScore();
                //float mcStrength = stats.getRelationshipStrength();

                if (alignedScore > 0) {
                    if (mcScore >= alignedScore)
                        pValue += 1;
                } else {
                    if (mcScore <= alignedScore)
                        pValue += 1;
                }
                if (pValue > (alpha * repetitions))
                    break; // pruning
                //long endNbhd = System.currentTimeMillis();
                //if (j == 0) System.out.println("One repetition: " + (endNbhd-startNbhd) + " ms");
            }

            pValue = pValue / ((float) (repetitions));
            if ((!removeNotSignificant) || ((pValue <= alpha) && (removeNotSignificant))) {
                emitKeyValue(outputIds, key, alignedScore, alignedStrength, pValue, nMatchEvents, nMatchPosEvents,
                        nMatchNegEvents, nPosFirstNonSecond, nNegFirstNonSecond, nNonFirstPosSecond,
                        nNonFirstNegSecond);
            }

            break;

        case FrameworkUtils.ZIP:

            for (int j = 0; j < repetitions; j++) {
                //long startNbhd = System.currentTimeMillis();
                pairs.clear();
                pairs = (completeRandomization) ? spatialCompleteRandom() : bfsShift(false);

                stats = new TimeSeriesStats();
                for (int i = 0; i < pairs.size(); i++) {
                    Integer[] pair = pairs.get(i);
                    stats.add(getStats(temporal, timeSeriesPerSpatial.get(pair[0])[dataset1Key],
                            timeSeriesPerSpatial.get(pair[1])[dataset2Key], false));
                }
                stats.computeScores();

                float mcScore = stats.getRelationshipScore();
                //float mcStrength = stats.getRelationshipStrength();

                if (alignedScore > 0) {
                    if (mcScore >= alignedScore)
                        pValue += 1;
                } else {
                    if (mcScore <= alignedScore)
                        pValue += 1;
                }
                if (pValue > (alpha * repetitions))
                    break; // pruning
                //long endNbhd = System.currentTimeMillis();
                //if (j == 0) System.out.println("One repetition: " + (endNbhd-startNbhd) + " ms");
            }

            pValue = pValue / ((float) (repetitions));
            if ((!removeNotSignificant) || ((pValue <= alpha) && (removeNotSignificant))) {
                emitKeyValue(outputIds, key, alignedScore, alignedStrength, pValue, nMatchEvents, nMatchPosEvents,
                        nMatchNegEvents, nPosFirstNonSecond, nNegFirstNonSecond, nNonFirstPosSecond,
                        nNonFirstNegSecond);
            }

            break;

        case FrameworkUtils.GRID:

            for (int j = 0; j < repetitions; j++) {
                pairs.clear();
                pairs = (completeRandomization) ? spatialCompleteRandom() : toroidalShift();

                stats = new TimeSeriesStats();
                for (int i = 0; i < pairs.size(); i++) {
                    Integer[] pair = pairs.get(i);
                    stats.add(getStats(temporal, timeSeriesPerSpatial.get(pair[0])[dataset1Key],
                            timeSeriesPerSpatial.get(pair[1])[dataset2Key], false));
                }
                stats.computeScores();

                float mcScore = stats.getRelationshipScore();
                //float mcStrength = stats.getRelationshipStrength();

                if (alignedScore > 0) {
                    if (mcScore >= alignedScore)
                        pValue += 1;
                } else {
                    if (mcScore <= alignedScore)
                        pValue += 1;
                }
                if (pValue > (alpha * repetitions))
                    break; // pruning
            }

            pValue = pValue / ((float) (repetitions));
            if ((!removeNotSignificant) || ((pValue <= alpha) && (removeNotSignificant))) {
                emitKeyValue(outputIds, key, alignedScore, alignedStrength, pValue, nMatchEvents, nMatchPosEvents,
                        nMatchNegEvents, nPosFirstNonSecond, nNegFirstNonSecond, nNonFirstPosSecond,
                        nNonFirstNegSecond);
            }

            break;

        case FrameworkUtils.CITY:

            if (timeSeriesPerSpatial.size() > 1) {
                System.out.println("Something went wrong... There should be only one spatial element.");
                System.exit(-1);
            }

            elem = timeSeriesPerSpatial.get(0);

            for (int j = 0; j < repetitions; j++) {
                //long startCity = System.currentTimeMillis();
                stats = new TimeSeriesStats();
                stats.add(getStats(temporal, elem[dataset1Key], elem[dataset2Key], true));

                stats.computeScores();

                float mcScore = stats.getRelationshipScore();
                //float mcStrength = stats.getRelationshipStrength();

                if (alignedScore > 0) {
                    if (mcScore >= alignedScore)
                        pValue += 1;
                } else {
                    if (mcScore <= alignedScore)
                        pValue += 1;
                }
                if (pValue > (alpha * repetitions))
                    break; // pruning
                //long endCity = System.currentTimeMillis();
                //if (j == 0) System.out.println("One repetition: " + (endCity-startCity) + " ms");
            }

            pValue = pValue / ((float) (repetitions));
            if ((!removeNotSignificant) || ((pValue <= alpha) && (removeNotSignificant))) {
                emitKeyValue(outputIds, key, alignedScore, alignedStrength, pValue, nMatchEvents, nMatchPosEvents,
                        nMatchNegEvents, nPosFirstNonSecond, nNegFirstNonSecond, nNonFirstPosSecond,
                        nNonFirstNegSecond);
            }

            break;

        default:
            // do nothing
            break;
        }

    }

    private void emitKeyValue(boolean outputIds, PairAttributeWritable key, float score, float strength,
            float pValue, float nMatchEvents, float nMatchPosEvents, float nMatchNegEvents,
            float nPosFirstNonSecond, float nNegFirstNonSecond, float nNonFirstPosSecond, float nNonFirstNegSecond)
            throws IOException, InterruptedException {
        if (outputIds) {
            keyWritable = new Text(key.getFirstDataset() + "," + key.getFirstAttribute() + ","
                    + key.getSecondDataset() + "," + key.getSecondAttribute() + "," + key.getSpatialResolution()
                    + "," + key.getTemporalResolution());
        } else {
            keyWritable = new Text(header.get(dataset1).get(key.getFirstAttribute()) + ","
                    + header.get(dataset2).get(key.getSecondAttribute()));
        }
        valueWritable = new Text(score + "," + strength + "," + pValue + "," + nMatchEvents + "," + nMatchPosEvents
                + "," + nMatchNegEvents + "," + nPosFirstNonSecond + "," + nNegFirstNonSecond + ","
                + nNonFirstPosSecond + "," + nNonFirstNegSecond);
        out.write(keyWritable, valueWritable, fileName);
    }

    @Override
    public void cleanup(Context context) throws IOException, InterruptedException {
        out.close();
    }

    public static TimeSeriesStats getStats(int temporal, TopologyTimeSeriesWritable timeSeries1,
            TopologyTimeSeriesWritable timeSeries2, boolean temporalPermutationTest) {

        TimeSeriesStats output = new TimeSeriesStats();

        if ((timeSeries1 == null) || (timeSeries2 == null))
            return output;

        // detecting intersection

        long start1 = timeSeries1.getStart();
        long end1 = timeSeries1.getEnd();
        long start2 = timeSeries2.getStart();
        long end2 = timeSeries2.getEnd();

        if (((end1 < start2) && (start1 < start2)) || ((end1 > end2) && (start1 > end2)))
            return output;

        output.setIntersect(true);

        DateTime start1Obj = new DateTime(start1 * 1000, DateTimeZone.UTC);
        DateTime end1Obj = new DateTime(end1 * 1000, DateTimeZone.UTC);
        DateTime start2Obj = new DateTime(start2 * 1000, DateTimeZone.UTC);
        DateTime end2Obj = new DateTime(end2 * 1000, DateTimeZone.UTC);

        byte[] eventTimeSeries1 = timeSeries1.getTimeSeries();
        byte[] eventTimeSeries2 = timeSeries2.getTimeSeries();

        int startRange = 0;
        int endRange = 0;

        switch (temporal) {
        case FrameworkUtils.HOUR:
            startRange = (start1 > start2) ? Hours.hoursBetween(start2Obj, start1Obj).getHours()
                    : Hours.hoursBetween(start1Obj, start2Obj).getHours();
            endRange = (end1 > end2) ? Hours.hoursBetween(end2Obj, end1Obj).getHours()
                    : Hours.hoursBetween(end1Obj, end2Obj).getHours();
            break;
        case FrameworkUtils.DAY:
            startRange = (start1 > start2) ? Days.daysBetween(start2Obj, start1Obj).getDays()
                    : Days.daysBetween(start1Obj, start2Obj).getDays();
            endRange = (end1 > end2) ? Days.daysBetween(end2Obj, end1Obj).getDays()
                    : Days.daysBetween(end1Obj, end2Obj).getDays();
            break;
        case FrameworkUtils.WEEK:
            startRange = (start1 > start2) ? Weeks.weeksBetween(start2Obj, start1Obj).getWeeks()
                    : Weeks.weeksBetween(start1Obj, start2Obj).getWeeks();
            endRange = (end1 > end2) ? Weeks.weeksBetween(end2Obj, end1Obj).getWeeks()
                    : Weeks.weeksBetween(end1Obj, end2Obj).getWeeks();
            break;
        case FrameworkUtils.MONTH:
            startRange = (start1 > start2) ? Months.monthsBetween(start2Obj, start1Obj).getMonths()
                    : Months.monthsBetween(start1Obj, start2Obj).getMonths();
            endRange = (end1 > end2) ? Months.monthsBetween(end2Obj, end1Obj).getMonths()
                    : Months.monthsBetween(end1Obj, end2Obj).getMonths();
            break;
        case FrameworkUtils.YEAR:
            startRange = (start1 > start2) ? Years.yearsBetween(start2Obj, start1Obj).getYears()
                    : Years.yearsBetween(start1Obj, start2Obj).getYears();
            endRange = (end1 > end2) ? Years.yearsBetween(end2Obj, end1Obj).getYears()
                    : Years.yearsBetween(end1Obj, end2Obj).getYears();
            break;
        default:
            startRange = (start1 > start2) ? Hours.hoursBetween(start2Obj, start1Obj).getHours()
                    : Hours.hoursBetween(start1Obj, start2Obj).getHours();
            endRange = (end1 > end2) ? Hours.hoursBetween(end2Obj, end1Obj).getHours()
                    : Hours.hoursBetween(end1Obj, end2Obj).getHours();
            break;
        }

        int indexStart1 = (start2 > start1) ? startRange : 0;
        int indexStart2 = (start2 > start1) ? 0 : startRange;
        int indexEnd1 = (end2 > end1) ? eventTimeSeries1.length : eventTimeSeries1.length - endRange;
        int indexEnd2 = (end2 > end1) ? eventTimeSeries2.length - endRange : eventTimeSeries2.length;

        /*DateTime startIntersect = FrameworkUtils.addTime(temporal, indexStart1, start1Obj);
        if (!(startIntersect.isEqual(FrameworkUtils.addTime(temporal, indexStart2, start2Obj)))) {
        System.out.println("Something went wrong... Different starts");
        System.exit(-1);
        }*/

        byte[] timeSeries1Int = Arrays.copyOfRange(eventTimeSeries1, indexStart1, indexEnd1);
        byte[] timeSeries2Int = Arrays.copyOfRange(eventTimeSeries2, indexStart2, indexEnd2);

        if (timeSeries1Int.length != timeSeries2Int.length) {
            System.out.println("Something went wrong... Different sizes");
            System.exit(-1);
        }

        int nMatchEvents = 0;
        int nMatchPosEvents = 0;
        int nMatchNegEvents = 0;
        int nPosFirstNonSecond = 0;
        int nNegFirstNonSecond = 0;
        int nNonFirstPosSecond = 0;
        int nNonFirstNegSecond = 0;

        //String eventDateTime = null;
        int indexD1 = (temporalPermutationTest) ? new Random().nextInt(timeSeries1Int.length) : 0;
        int indexD2 = (temporalPermutationTest) ? new Random().nextInt(timeSeries2Int.length) : 0;
        for (int i = 0; i < timeSeries1Int.length; i++) {
            int j = (indexD1 + i) % timeSeries1Int.length;
            int k = (indexD2 + i) % timeSeries2Int.length;
            byte result = (byte) (timeSeries1Int[j] | timeSeries2Int[k]);

            //eventDateTime = FrameworkUtils.getTemporalStr(
            //        temporal, FrameworkUtils.addTime(temporal, j, startIntersect));

            switch (result) {
            case FrameworkUtils.nonEventsMatch: // both non events
                // do nothing
                break;
            case FrameworkUtils.posEventsMatch: // both positive
                nMatchEvents++;
                nMatchPosEvents++;
                //output.addMatchPosEvents(eventDateTime);
                break;
            case FrameworkUtils.nonEventPosEventMatch: // one positive, one non-event
                if (timeSeries1Int[j] == FrameworkUtils.positiveEvent)
                    nPosFirstNonSecond++;
                else
                    nNonFirstPosSecond++;
                break;
            case FrameworkUtils.negEventsMatch: // both negative
                nMatchEvents++;
                nMatchPosEvents++;
                //output.addMatchPosEvents(eventDateTime);
                break;
            case FrameworkUtils.nonEventNegEventMatch: // one negative, one non-event
                if (timeSeries1Int[j] == FrameworkUtils.negativeEvent)
                    nNegFirstNonSecond++;
                else
                    nNonFirstNegSecond++;
                break;
            case FrameworkUtils.negEventPosEventMatch: // one negative, one positive
                nMatchEvents++;
                nMatchNegEvents++;
                //output.addMatchNegEvents(eventDateTime);
                break;
            default:
                System.out.println("Something went wrong... Wrong case");
                System.exit(-1);
            }
        }

        output.setParameters(nMatchEvents, nMatchPosEvents, nMatchNegEvents, nPosFirstNonSecond, nNegFirstNonSecond,
                nNonFirstPosSecond, nNonFirstNegSecond);

        return output;
    }

    private ArrayList<Integer[]> spatialCompleteRandom() {

        // each element inside the array list represents a pair
        ArrayList<Integer[]> result = new ArrayList<Integer[]>();

        Random random = new Random();

        for (int k = 0; k < size; k++) {

            Integer[] pair = new Integer[2];
            pair[0] = random.nextInt(size);
            pair[1] = random.nextInt(size);
            result.add(pair);
        }

        return result;
    }

    private ArrayList<Integer[]> toroidalShift() {

        // each element inside the array list represents a pair
        ArrayList<Integer[]> result = new ArrayList<Integer[]>();

        Random random = new Random();

        int x = random.nextInt(gridSize);
        int y = random.nextInt(gridSize);

        // shifted grid
        for (int j = 0; j < gridSize; j++) {
            for (int i = 0; i < gridSize; i++) {
                int newX = (x + i) % gridSize;
                int newY = (y + j) % gridSize;
                Integer[] pair = new Integer[2];
                pair[0] = originalGrid[i][j];
                pair[1] = originalGrid[newX][newY];
                result.add(pair);
            }
        }

        return result;
    }

    // TODO: we may not have all the neighborhoods for the data
    private ArrayList<Integer[]> bfsShift(boolean isNbhd) {
        if (isNbhd)
            return spatialGraph.generateRandomShift();
        return zipGraph.generateRandomShift();
    }
}