
eu.interedition.collatex.dekker.matrix.MatchTable Maven / Gradle / Ivy
/*
* 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 .
*/
package eu.interedition.collatex.dekker.matrix;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
import eu.interedition.collatex.Token;
import eu.interedition.collatex.VariantGraph;
import eu.interedition.collatex.matching.EqualityTokenComparator;
import eu.interedition.collatex.matching.Matches;
import eu.interedition.collatex.util.VariantGraphRanking;
// @author: Ronald Haentjens Dekker
//
// This class represents a table of the matches
// Since this table is sparse a Hashmap based implementation
// is used rather than a Arraylist based one.
// However the API of this class looks very much like an array based one
// since you can use tokenAt(row, column) or vertexAt(row, column)
public class MatchTable {
private final HashBasedTable table;
private final Iterable witness;
private final List ranks;
//this fields are needed for the locking of table cells
private final Set fixedRows = Sets.newHashSet();
private final Set fixedVertices = Sets.newHashSet();
// assumes default token comparator
public static MatchTable create(VariantGraph graph, Iterable witness) {
Comparator comparator = new EqualityTokenComparator();
return MatchTable.create(graph, witness, comparator);
}
public static MatchTable create(VariantGraph graph, Iterable witness, Comparator comparator) {
final VariantGraphRanking ranking = VariantGraphRanking.of(graph);
// step 1: build the MatchTable
MatchTable table = createEmptyTable(ranking, graph, witness);
// step 2: do the matching and fill the table
table.fillTableWithMatches(ranking, graph, witness, comparator);
return table;
}
public VariantGraph.Vertex vertexAt(int rowIndex, int columnIndex) {
MatchTableCell cell = table.get(rowIndex, columnIndex);
return cell==null ? null : cell.vertex;
}
public Token tokenAt(int rowIndex, int columnIndex) {
MatchTableCell cell = table.get(rowIndex, columnIndex);
return cell==null ? null : cell.token;
}
// Warning: this method reiterates the witness!
// This method is only meant for the user interface and serialization classes!
// Use the tokenAt method in all other cases.
public List rowList() {
return Lists.newArrayList(witness);
}
public List columnList() {
return ranks;
}
// Since the coordinates in allMatches are ordered from upper left to lower right,
// we don't need to check the lower right neighbor.
public Set getIslands() {
Map coordinateMapper = Maps.newHashMap();
List allMatches = allMatches();
for (Coordinate c : allMatches) {
// LOG.debug("coordinate {}", c);
addToIslands(coordinateMapper, c);
}
Set smallestIslandsCoordinates = Sets.newHashSet(allMatches);
smallestIslandsCoordinates.removeAll(coordinateMapper.keySet());
for (Coordinate coordinate : smallestIslandsCoordinates) {
Island island = new Island();
island.add(coordinate);
coordinateMapper.put(coordinate, island);
}
return Sets.newHashSet(coordinateMapper.values());
}
/*
* Commit an island in the match table
* Island will be part of the final alignment
*/
public void commitIsland(Island isl) {
for (Coordinate coordinate : isl) {
fixedRows.add(coordinate.row);
fixedVertices.add(vertexAt(coordinate.row, coordinate.column));
}
}
/*
* Return whether an island overlaps with an already committed island
*/
public boolean isIslandPossibleCandidate(Island island) {
for (Coordinate coordinate : island) {
if (doesCoordinateOverlapWithCommittedCoordinate(coordinate)) return false;
}
return true;
}
/*
* Return whether a coordinate overlaps with an already committed coordinate
*/
public boolean doesCoordinateOverlapWithCommittedCoordinate(Coordinate coordinate) {
return fixedRows.contains(coordinate.row) || //
fixedVertices.contains(vertexAt(coordinate.row, coordinate.column));
}
private MatchTable(Iterable tokens, List ranks) {
this.table = HashBasedTable.create();
this.witness = tokens;
this.ranks = ranks;
}
private static MatchTable createEmptyTable(VariantGraphRanking ranking, VariantGraph graph, Iterable witness) {
// -2 === ignore the start and the end vertex
Range ranksRange = Range.closed(0, Math.max(0, ranking.apply(graph.getEnd()) - 2));
ImmutableList ranksSet = ContiguousSet.create(ranksRange, DiscreteDomain.integers()).asList();
return new MatchTable(witness, ranksSet);
}
// move parameters into fields?
private void fillTableWithMatches(VariantGraphRanking ranking, VariantGraph graph, Iterable witness, Comparator comparator) {
Matches matches = Matches.between(graph.vertices(), witness, comparator);
Set unique = matches.getUnique();
Set ambiguous = matches.getAmbiguous();
int rowIndex=0;
for (Token t : witness) {
if (unique.contains(t) || ambiguous.contains(t)) {
List matchingVertices = matches.getAll().get(t);
for (VariantGraph.Vertex vgv : matchingVertices) {
set(rowIndex, ranking.apply(vgv) - 1, t, vgv);
}
}
rowIndex++;
}
}
private void set(int rowIndex, int columnIndex, Token token, VariantGraph.Vertex vertex) {
// LOG.debug("putting: {}<->{}<->{}", new Object[] { token, columnIndex, variantGraphVertex });
MatchTableCell cell = new MatchTableCell(token, vertex);
table.put(rowIndex, columnIndex, cell);
}
private void addToIslands(Map coordinateMapper, Coordinate c) {
int diff = -1;
Coordinate neighborCoordinate = new Coordinate(c.row + diff, c.column + diff);
VariantGraph.Vertex neighbor = null;
try {
neighbor = vertexAt(c.row + diff, c.column + diff);
} catch (IndexOutOfBoundsException e) {}
if (neighbor != null) {
Island island = coordinateMapper.get(neighborCoordinate);
if (island == null) {
// LOG.debug("new island");
Island island0 = new Island();
island0.add(neighborCoordinate);
island0.add(c);
coordinateMapper.put(neighborCoordinate, island0);
coordinateMapper.put(c, island0);
} else {
// LOG.debug("add to existing island");
island.add(c);
coordinateMapper.put(c, island);
}
}
}
// Note: code taken from MatchMatrix class
// TODO: might be simpler to work from the valueSet
// TODO: try remove the call to rowList / columnList
List allMatches() {
List pairs = Lists.newArrayList();
int rows = rowList().size();
int cols = columnList().size();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (vertexAt(i, j) != null) pairs.add(new Coordinate(i, j));
}
}
return pairs;
}
private class MatchTableCell {
public final Token token;
public final VariantGraph.Vertex vertex;
public MatchTableCell(Token token, VariantGraph.Vertex vertex) {
this.token = token;
this.vertex = vertex;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy