PatternEmbeddingsMap.java
/*
* Copyright © 2014 - 2021 Leipzig University (Database Research Group)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradoop.flink.algorithms.fsm.dimspan.tuples;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.flink.api.java.tuple.Tuple1;
import org.apache.flink.api.java.tuple.Tuple2;
import org.gradoop.flink.algorithms.fsm.dimspan.model.Simple16Compressor;
import org.gradoop.flink.model.impl.tuples.WithCount;
import java.util.Objects;
/**
* f0 : [pattern1,..,patternN]
* f1 : [[vertexCount,edgeCount,v11,..,vj1,e11,..,ek1,v21,..]1,..]
*/
public class PatternEmbeddingsMap extends Tuple2<int[][], int[][]> {
/**
* Default Constructor.
*/
public PatternEmbeddingsMap() {
}
/**
* Valued constructor.
*
* @param patternMuxes multiplexes of patterns
* @param embeddingMuxes multiplexes of embeddings
*/
public PatternEmbeddingsMap(
int[][] patternMuxes, int[][] embeddingMuxes) {
super(patternMuxes, embeddingMuxes);
}
/**
* Convenience method.
*
* @return number of contained patterns
*/
public int getPatternCount() {
return getKeys().length;
}
/**
* Convenience method to check is an embeddings map is empty
*
* @return true, if empty
*/
public boolean isEmpty() {
return getPatternCount() == 0;
}
/**
* Returns a pattern at a given index.
*
* @param index index
*
* @return pattern multiplex
*/
public int[] getPattern(int index) {
return getKeys()[index];
}
/**
* Find index of a given pattern
*
* @param patternMux search pattern
*
* @return index if contained, -1 otherwise
*/
public int getIndex(int[] patternMux) {
int index = -1;
int i = 0;
for (int[] mux : getKeys()) {
if (Objects.deepEquals(mux, patternMux)) {
index = i;
break;
}
i++;
}
return index;
}
/**
* Creates an entry for a pattern including an initial embedding or just adds an embedding.
*
* @param patternMux pattern
* @param vertexIds the embedding's vertex ids
* @param edgeIds the embedding's edge ids
*/
public void put(int[] patternMux, int[] vertexIds, int[] edgeIds) {
int patternIndex = getIndex(patternMux);
int[] vertexEdgeIds = ArrayUtils.addAll(vertexIds, edgeIds);
if (patternIndex < 0) {
// insert
setKeys(ArrayUtils.add(getKeys(), patternMux));
int[] embeddingData = new int[] {vertexIds.length, edgeIds.length};
embeddingData = ArrayUtils.addAll(embeddingData, vertexEdgeIds);
setValues(ArrayUtils.add(getValues(), embeddingData));
} else {
// update
getValues()[patternIndex] =
ArrayUtils.addAll(getValues()[patternIndex], vertexEdgeIds);
}
}
/**
* Adds a pattern and existing embeddings.
*
* @param patternMux pattern
* @param embeddingsMux embeddings
*/
public void put(int[] patternMux, int[] embeddingsMux) {
setKeys(ArrayUtils.add(getKeys(), patternMux));
setValues(ArrayUtils.add(getValues(), embeddingsMux));
}
/**
* Adds all patterns and embeddings of another map.
*
* @param that other map
*/
public void append(PatternEmbeddingsMap that) {
setKeys(ArrayUtils.addAll(this.getKeys(), that.getKeys()));
setValues(ArrayUtils.addAll(this.getValues(), that.getValues()));
}
/**
* Adds a pattern but no embeddings.
*
* @param muxWithCount pattern
*/
public void collect(WithCount<int[]> muxWithCount) {
setKeys(ArrayUtils.add(getKeys(), muxWithCount.getObject()));
setValues(ArrayUtils.add(getValues(), new int[] {(int) muxWithCount.getCount()}));
}
/**
* Returns all embeddings for a give pattern index.
*
* @param index pattern index
* @param uncompress true, if embeddings need to be uncompressed
*
* @return array of embeddings
*/
public int[][] getEmbeddings(int index, boolean uncompress) {
int[] embeddingData = getValues()[index];
if (uncompress) {
embeddingData = Simple16Compressor.uncompress(embeddingData);
}
int vertexCount = embeddingData[0];
int edgeCount = embeddingData[1];
int embeddingLength = vertexCount + edgeCount;
int embeddingCount = (embeddingData.length - 2) / embeddingLength;
int[][] embeddings = new int[2 * embeddingCount][];
int i = 2;
for (int m = 0; m < embeddingCount; m++) {
int[] vertexIds = new int[vertexCount];
for (int v = 0; v < vertexCount; v++) {
vertexIds[v] = embeddingData[i];
i++;
}
embeddings[2 * m] = vertexIds;
int[] edgeIds = new int[edgeCount];
for (int e = 0; e < edgeCount; e++) {
edgeIds[e] = embeddingData[i];
i++;
}
embeddings[2 * m + 1] = edgeIds;
}
return embeddings;
}
// GETTERS AND SETTERS
public int[][] getKeys() {
return this.f0;
}
public int[][] getValues() {
return this.f1;
}
private void setKeys(int[][] patternMuxes) {
this.f0 = patternMuxes;
}
private void setValues(int[][] embeddingMuxes) {
this.f1 = embeddingMuxes;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < getPatternCount(); i++) {
builder.append(new Tuple1<>(getPattern(i)));
builder.append("\t");
builder.append(new Tuple1<>(getValues()[i]));
builder.append("\n");
}
return builder.toString();
}
/**
* Convenience method to create and empty map.
*
* @return empty map
*/
public static PatternEmbeddingsMap getEmptyOne() {
return new PatternEmbeddingsMap(new int[0][], new int[0][]);
}
}