eu.interedition.collatex.dekker.matrix.IslandConflictResolver.java Source code

Java tutorial

Introduction

Here is the source code for eu.interedition.collatex.dekker.matrix.IslandConflictResolver.java

Source

/*
 * Copyright (c) 2013 The Interedition Development Group.
 *
 * This file is part of CollateX.
 *
 * CollateX is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CollateX is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CollateX.  If not, see <http://www.gnu.org/licenses/>.
 */

package eu.interedition.collatex.dekker.matrix;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;

/**
 * 
 * @author Ronald Haentjens Dekker
 * @author Bram Buitendijk
 * @author Meindert Kroese
 */
public class IslandConflictResolver {
    Logger LOG = Logger.getLogger(IslandConflictResolver.class.getName());
    // fixed islands contains all the islands that are selected for the final alignment
    private final MatchTableSelection selection;

    //NOTE: outlierTranspositionLimit is ignored for now
    public IslandConflictResolver(MatchTable table, int outlierTranspositionsSizeLimit) {
        selection = new MatchTableSelection(table);
    }

    /*
     * Create a non-conflicting version by simply taken all the islands that do
     * not conflict with each other, largest first. 
     */
    public MatchTableSelection createNonConflictingVersion() {
        List<Island> possibleIslands;
        do {
            possibleIslands = selection.getPossibleIslands();
            // check the possible islands of a certain size against each other.
            if (possibleIslands.size() == 1) {
                selection.addIsland(possibleIslands.get(0));
            } else if (possibleIslands.size() > 1) {
                Multimap<IslandCompetition, Island> analysis = analyzeConflictsBetweenPossibleIslands(
                        possibleIslands);
                resolveConflictsBySelectingPreferredIslands(selection, analysis);
            }
        } while (!possibleIslands.isEmpty());
        return selection;
    }

    /*
     * This method analyzes the relationship between all the islands of the same
     * size that have yet to be selected. They can compete with one another
     * (choosing one locks out the other), some of them can be on the ideal line.
     *
     * Parameters: the size of the islands that you want to analyze
     */
    public Multimap<IslandCompetition, Island> analyzeConflictsBetweenPossibleIslands(
            List<Island> possibleIslands) {
        Multimap<IslandCompetition, Island> conflictMap = ArrayListMultimap.create();
        Set<Island> competingIslands = getCompetingIslands(possibleIslands);
        for (Island island : competingIslands) {
            if (selection.doesCandidateLayOnVectorOfCommittedIsland(island)) {
                conflictMap.put(IslandCompetition.CompetingIslandAndOnIdealIine, island);
            } else {
                conflictMap.put(IslandCompetition.CompetingIsland, island);
            }
        }
        for (Island island : getNonCompetingIslands(possibleIslands, competingIslands)) {
            conflictMap.put(IslandCompetition.NonCompetingIsland, island);
        }
        return conflictMap;
    }

    /*
     * The preferred Islands are directly added to the result Archipelago 
     * If we want to
     * re-factor this into a pull construction rather then a push construction
     * we have to move this code out of this method and move it to the caller
     * class
     */
    private void resolveConflictsBySelectingPreferredIslands(MatchTableSelection selection,
            Multimap<IslandCompetition, Island> islandConflictMap) {
        // First select competing islands that are on the ideal line
        Multimap<Double, Island> distanceMap1 = makeDistanceMap(
                islandConflictMap.get(IslandCompetition.CompetingIslandAndOnIdealIine));
        LOG.fine("addBestOfCompeting with competingIslandsOnIdealLine");
        addBestOfCompeting(selection, distanceMap1);

        // Second select other competing islands
        Multimap<Double, Island> distanceMap2 = makeDistanceMap(
                islandConflictMap.get(IslandCompetition.CompetingIsland));
        LOG.fine("addBestOfCompeting with otherCompetingIslands");
        addBestOfCompeting(selection, distanceMap2);

        // Third select non competing islands
        LOG.fine("add non competing islands");
        for (Island i : islandConflictMap.get(IslandCompetition.NonCompetingIsland)) {
            selection.addIsland(i);
        }
    }

    private void addBestOfCompeting(MatchTableSelection selection, Multimap<Double, Island> distanceMap1) {
        for (Double d : shortestToLongestDistances(distanceMap1)) {
            for (Island ci : distanceMap1.get(d)) {
                if (selection.isIslandPossibleCandidate(ci)) {
                    selection.addIsland(ci);
                }
            }
        }
    }

    // TODO: This method calculates the distance from the ideal line
    // TODO: by calculating the ratio x/y.
    // TODO: but the ideal line may have moved (due to additions/deletions).
    private Multimap<Double, Island> makeDistanceMap(Collection<Island> competingIslands) {
        Multimap<Double, Island> distanceMap = ArrayListMultimap.create();
        for (Island isl : competingIslands) {
            Coordinate leftEnd = isl.getLeftEnd();
            double ratio = ((leftEnd.column + 1) / (double) (leftEnd.row + 1));
            double b2 = Math.log(ratio) / Math.log(2);
            double distanceToIdealLine = Math.abs(b2);
            distanceMap.put(distanceToIdealLine, isl);
        }
        return distanceMap;
    }

    private List<Double> shortestToLongestDistances(Multimap<Double, Island> distanceMap) {
        List<Double> distances = Lists.newArrayList(distanceMap.keySet());
        Collections.sort(distances);
        return distances;
    }

    private Set<Island> getNonCompetingIslands(List<Island> islands, Set<Island> competingIslands) {
        Set<Island> nonCompetingIslands = Sets.newHashSet(islands);
        nonCompetingIslands.removeAll(competingIslands);
        return nonCompetingIslands;
    }

    private Set<Island> getCompetingIslands(List<Island> islands) {
        Set<Island> competingIslands = Sets.newHashSet();
        for (int i = 0; i < islands.size(); i++) {
            Island i1 = islands.get(i);
            for (int j = 1; j < islands.size() - i; j++) {
                Island i2 = islands.get(i + j);
                if (i1.isCompetitor(i2)) {
                    competingIslands.add(i1);
                    competingIslands.add(i2);
                }
            }
        }
        return competingIslands;
    }
}