package edu.stanford.nlp.loglinear.model;
import com.pholser.junit.quickcheck.ForAll;
import com.pholser.junit.quickcheck.From;
import com.pholser.junit.quickcheck.generator.GenerationStatus;
import com.pholser.junit.quickcheck.generator.Generator;
import com.pholser.junit.quickcheck.random.SourceOfRandomness;
import org.junit.contrib.theories.Theories;
import org.junit.contrib.theories.Theory;
import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
/**
* Created on 10/20/15.
* @author keenon
* <p>
* This checks the coherence of the ConcatVectorNamespace approach against the basic ConcatVector approach, using a cute
* trick where we map random ints as "feature names", and double check that the output is always the same.
*/
@RunWith(Theories.class)
public class ConcatVectorNamespaceTest {
@Theory
public void testResizeOnSetComponent(@ForAll(sampleSize = 50) @From(MapGenerator.class) Map<Integer, Integer> featureMap1,
@ForAll(sampleSize = 50) @From(MapGenerator.class) Map<Integer, Integer> featureMap2) {
ConcatVectorNamespace namespace = new ConcatVectorNamespace();
ConcatVector namespace1 = toNamespaceVector(namespace, featureMap1);
ConcatVector namespace2 = toNamespaceVector(namespace, featureMap2);
ConcatVector regular1 = toVector(featureMap1);
ConcatVector regular2 = toVector(featureMap2);
assertEquals(regular1.dotProduct(regular2), namespace1.dotProduct(namespace2), 1.0e-5);
ConcatVector namespaceSum = namespace1.deepClone();
namespaceSum.addVectorInPlace(namespace2, 1.0);
ConcatVector regularSum = regular1.deepClone();
regularSum.addVectorInPlace(regular2, 1.0);
assertEquals(regular1.dotProduct(regularSum), namespace1.dotProduct(namespaceSum), 1.0e-5);
assertEquals(regularSum.dotProduct(regular2), namespaceSum.dotProduct(namespace2), 1.0e-5);
}
public ConcatVector toNamespaceVector(ConcatVectorNamespace namespace, Map<Integer, Integer> featureMap) {
ConcatVector newVector = namespace.newVector();
for (int i : featureMap.keySet()) {
String feature = "feat" + i;
String sparse = "index" + featureMap.get(i);
namespace.setSparseFeature(newVector, feature, sparse, 1.0);
}
return newVector;
}
public ConcatVector toVector(Map<Integer, Integer> featureMap) {
ConcatVector vector = new ConcatVector(20);
for (int i : featureMap.keySet()) {
vector.setSparseComponent(i, featureMap.get(i), 1.0);
}
return vector;
}
public static class MapGenerator extends Generator<Map<Integer, Integer>> {
public MapGenerator(Class<Map<Integer, Integer>> type) {
super(type);
}
@Override
public Map<Integer, Integer> generate(SourceOfRandomness sourceOfRandomness, GenerationStatus generationStatus) {
int numFeatures = sourceOfRandomness.nextInt(1, 15);
Map<Integer, Integer> featureMap = new HashMap<>();
for (int i = 0; i < numFeatures; i++) {
int featureValue = sourceOfRandomness.nextInt(20);
while (featureMap.containsKey(featureValue)) {
featureValue = sourceOfRandomness.nextInt(20);
}
featureMap.put(featureValue, sourceOfRandomness.nextInt(2));
}
return featureMap;
}
}
}