blob: b063e929ff5e5b120ba3a1eefdc03d8754f5b998 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Gabor Bergmann - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.tuple;
import java.util.LinkedList;
import java.util.List;
/**
* @author Gabor Bergmann
*
* Specifies select indices of a tuple. If viewed through this
* mask, the signature of the pattern will consist of its individual
* substitutions at the given positions, in the exact same order as they
* appear in indices[].
*
*/
public class TupleMask {
/**
* indices[i] specifies the index of the substitution in the original
* tuple that occupies the i-th place in the masked signature.
*/
public final int[] indices;
/**
* indicesSorted is indices, sorted in ascending order.
*/
public int[] indicesSorted;
/**
* the size of the tuple this mask is applied to
*/
public int sourceWidth;
/**
* Creates a TupleMask instance with the given indices array
*/
public TupleMask(int[] indices, int sourceWidth) {
this.sourceWidth = sourceWidth;
this.indices = indices;
indicesSorted = null;
}
/**
* Creates a TupleMask instance of the given size that maps the first
* 'size' elements intact
*/
public static TupleMask linear(int size, int sourceWidth) {
int[] indices = new int[size];
for (int i=0; i<size; i++) indices[i]=i;
return new TupleMask(indices, sourceWidth);
}
/**
* Creates a TupleMask instance of the given size that maps every single
* element intact
*/
public static TupleMask identity(int size) {
return linear(size, size);
}
/**
* Creates a TupleMask instance of the given size that does not emit output.
*/
public static TupleMask empty(int sourceWidth) {
return linear(0, sourceWidth);
}
/**
* Creates a TupleMask instance that maps the tuple intact save for a single element at the specified index which is omitted
*/
public static TupleMask omit(int omission, int sourceWidth) {
int size = sourceWidth-1;
int[] indices = new int[size];
for (int i=0; i<omission; i++) indices[i]=i;
for (int i=omission; i<size; i++) indices[i]=i+1;
return new TupleMask(indices, sourceWidth);
}
/**
* Creates a TupleMask instance that discards positions where keep is true
*/
public TupleMask(boolean[] keep) {
this.sourceWidth = keep.length;
int size = 0;
for (int k = 0; k < keep.length; ++k)
if (keep[k])
size++;
this.indices = new int[size];
int l = 0;
for (int k = 0; k < keep.length; ++k)
if (keep[k])
indices[l++] = k;
indicesSorted = null;
}
/**
* Creates a TupleMask instance that moves an element from one index to other, shifting the others if neccessary.
*/
public static TupleMask displace(int from, int to, int sourceWidth) {
int[] indices = new int[sourceWidth];
for (int i=0; i<sourceWidth; i++)
if (i==to) indices[i]=from;
else if (i>=from && i<to) indices[i]=i+1;
else if (i>to && i<=from) indices[i]=i-1;
else indices[i]=i;
return new TupleMask(indices, sourceWidth);
}
/**
* Creates a TupleMask instance that selects a single element of the tuple.
*/
public static TupleMask selectSingle(int selected, int sourceWidth) {
int[] indices = {selected};
return new TupleMask(indices, sourceWidth);
}
/**
* Creates a TupleMask instance that selects whatever is selected by left, and appends whatever is selected by right.
* PRE: left and right have the same sourcewidth
*/
public static TupleMask append(TupleMask left, TupleMask right) {
int leftLength = left.indices.length;
int rightLength = right.indices.length;
int[] indices = new int[leftLength + rightLength];
for (int i=0; i<leftLength; ++i) indices[i] = left.indices[i];
for (int i=0; i<rightLength; ++i) indices[i+leftLength] = right.indices[i];
return new TupleMask(indices, left.sourceWidth);
}
/**
* Generates indicesSorted from indices
*
*/
public void sort() {
indicesSorted = new int[indices.length];
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < indices.length; ++i)
list.add(indices[i]);
java.util.Collections.sort(list);
int i = 0;
for (Integer a : list)
indicesSorted[i++] = a;
}
/**
* Generates a masked view of the original pattern.
*/
public Tuple transform(Tuple original) {
Object signature[] = new Object[indices.length];
for (int i = 0; i < indices.length; ++i)
signature[i] = original.get(indices[i]);
return new FlatTuple(signature);
}
/**
* Transforms a given mask directly, instead of transforming tuples that were transformed by the other mask.
* @return a mask that cascades the effects this mask after the mask provided as parameter.
*/
public TupleMask transform(TupleMask mask) {
int[] cascadeIndices = new int[indices.length];
for (int i = 0; i < indices.length; ++i)
cascadeIndices[i] = mask.indices[indices[i]];
return new TupleMask(cascadeIndices, mask.sourceWidth);
}
// /**
// * Generates a complementer mask that maps those elements that were
// untouched by the original mask.
// * Ordering is left intact.
// * A Tuple is used for reference concerning possible equalities among
// elements.
// */
// public TupleMask complementer(Tuple reference)
// {
// HashSet<Object> touched = new HashSet<Object>();
// LinkedList<Integer> untouched = new LinkedList<Integer>();
//
// for (int index : indices) touched.add(reference.get(index));
// for (int index=0; index<reference.getSize(); ++index)
// {
// if (touched.add(reference.get(index))) untouched.addLast(index);
// }
//
// int[] complementer = new int[untouched.size()];
// int k = 0;
// for (Integer integer : untouched) complementer[k++] = integer;
// return new TupleMask(complementer, reference.getSize());
// }
/**
* Combines two substitutions. The new pattern will contain all
* substitutions of masked and unmasked, assuming that the elements of
* masked indicated by this mask are already matched against unmasked.
*
* POST: the result will start with an exact copy of unmasked
*
* @param unmasked
* primary pattern substitution that is left intact.
* @param masked
* secondary pattern substitution that is transformed to the end
* of the result.
* @param useInheritance
* whether to use inheritance or copy umasked into result
* instead.
* @param asComplementer
* whether this mask maps from the masked Tuple to the tail of
* the result or to the unmasked one.
* @return new pattern that is a combination of unmasked and masked.
*/
public Tuple combine(Tuple unmasked, Tuple masked, boolean useInheritance, boolean asComplementer) {
int combinedLength = asComplementer ? indices.length : masked.getSize()
- indices.length;
if (!useInheritance)
combinedLength += unmasked.getSize();
Object combined[] = new Object[combinedLength];
int cPos = 0;
if (!useInheritance) {
for (int i = 0; i < unmasked.getSize(); ++i)
combined[cPos++] = unmasked.get(i);
}
if (asComplementer) {
for (int i = 0; i < indices.length; ++i)
combined[cPos++] = masked.get(indices[i]);
} else {
if (indicesSorted == null)
sort();
int mPos = 0;
for (int i = 0; i < masked.getSize(); ++i)
if (mPos < indicesSorted.length && i == indicesSorted[mPos])
mPos++;
else
combined[cPos++] = masked.get(i);
}
return useInheritance ? new LeftInheritanceTuple(unmasked, combined)
: new FlatTuple(combined);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int PRIME = 31;
int result = sourceWidth;
for (int i : indices)
result = PRIME * result + i;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final TupleMask other = (TupleMask) obj;
if (sourceWidth != other.sourceWidth)
return false;
if (indices.length != other.indices.length)
return false;
for (int k = 0; k < indices.length; k++)
if (indices[k] != other.indices[k])
return false;
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("M("+sourceWidth+"->");
for (int i : indices) {
s.append(i);
s.append(',');
}
s.append(')');
return s.toString();
}
}