All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.interedition.collatex.dekker.matrix.IslandConflictResolver Maven / Gradle / Ivy

Go to download

A Java library for collating textual sources, for example, to produce an apparatus.

There is a newer version: 1.7.1
Show newest version
/*
 * Copyright (c) 2015 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 .
 */

package eu.interedition.collatex.dekker.matrix;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Logger;

/**
 * @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) {
        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 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) {
                Map> 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 Map> analyzeConflictsBetweenPossibleIslands(List possibleIslands) {
        Map> conflictMap = new HashMap<>();
        Set competingIslands = getCompetingIslands(possibleIslands);
        for (Island island : competingIslands) {
            if (selection.doesCandidateLayOnVectorOfCommittedIsland(island)) {
                conflictMap.computeIfAbsent(IslandCompetition.CompetingIslandAndOnIdealIine, c -> new ArrayList<>()).add(island);
            } else {
                conflictMap.computeIfAbsent(IslandCompetition.CompetingIsland, c -> new ArrayList<>()).add(island);
            }
        }
        for (Island island : getNonCompetingIslands(possibleIslands, competingIslands)) {
            conflictMap.computeIfAbsent(IslandCompetition.NonCompetingIsland, c -> new ArrayList<>()).add(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, Map> islandConflictMap) {
        // First select competing islands that are on the ideal line
        LOG.fine("addBestOfCompeting with competingIslandsOnIdealLine");
        makeDistanceMap(islandConflictMap.getOrDefault(IslandCompetition.CompetingIslandAndOnIdealIine, Collections.emptyList()))
            .values().stream()
            .flatMap(List::stream).filter(ci1 -> selection.isIslandPossibleCandidate(ci1))
            .forEach(selection::addIsland);

        // Second select other competing islands
        LOG.fine("addBestOfCompeting with otherCompetingIslands");
        makeDistanceMap(islandConflictMap.getOrDefault(IslandCompetition.CompetingIsland, Collections.emptyList()))
            .values().stream()
            .flatMap(List::stream).filter(ci -> selection.isIslandPossibleCandidate(ci))
            .forEach(selection::addIsland);

        // Third select non competing islands
        LOG.fine("add non competing islands");
        islandConflictMap.getOrDefault(IslandCompetition.NonCompetingIsland, Collections.emptyList())
            .forEach(selection::addIsland);
    }

    // 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 SortedMap> makeDistanceMap(Collection competingIslands) {
        SortedMap> distanceMap = new TreeMap<>();
        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.computeIfAbsent(distanceToIdealLine, d -> new ArrayList<>()).add(isl);
        }
        return distanceMap;
    }

    private Set getNonCompetingIslands(List islands, Set competingIslands) {
        Set nonCompetingIslands = new HashSet<>(islands);
        nonCompetingIslands.removeAll(competingIslands);
        return nonCompetingIslands;
    }

    private Set getCompetingIslands(List islands) {
        Set competingIslands = new HashSet<>();
        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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy