/* * INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa * Copyright 2013 INESC-ID and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3.0 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.dataplacement; import org.infinispan.dataplacement.c50.keyfeature.Feature; import org.infinispan.dataplacement.c50.keyfeature.FeatureValue; import org.infinispan.dataplacement.c50.keyfeature.NameListFeature; import org.infinispan.dataplacement.c50.keyfeature.NumericFeature; import org.infinispan.dataplacement.c50.tree.DecisionTree; import org.infinispan.dataplacement.c50.tree.DecisionTreeBuilder; import org.infinispan.dataplacement.c50.tree.DecisionTreeParser; import org.infinispan.dataplacement.c50.tree.ParseTreeNode; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Decision Tree test * * @author Pedro Ruivo * @since 5.2 */ @Test(groups = "functional", testName = "dataplacement.DecisionTreeTest") public class DecisionTreeTest { private static final Log log = LogFactory.getLog(DecisionTreeTest.class); public void testEx0() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex0"); assertNode(root, 0, "1", new int[] {0,0,2000}, null, 0, null, null); ParseTreeNode[] forks = root.getForks(); assert forks == null; } public void testEx1() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex1.tree"); assertNode(root, 3, "2", new int[] {0,0,0,3,2,3,0,0,0,0}, "name", 5, null, new String[][] {new String[] {"N/A"}, new String[] {"peter"}, new String[] {"per"}, new String[] {"por"}, new String[] {"par\\,","pir \\\"na"}}); ParseTreeNode[] forks = root.getForks(); assertNode(forks[0], 0, "1", null, null, 0, null, null); assertNode(forks[1], 0, "2", new int[] {0,0,0,0,2,0,0,0,0,0}, null, 0, null, null); assertNode(forks[2], 0, "3", new int[] {0,0,0,3,0,0,0,0,0,0}, null, 0, null, null); assertNode(forks[3], 0, "4", new int[] {0,0,0,0,0,3,0,0,0,0}, null, 0, null, null); assertNode(forks[4], 0, "5", null, null, 0, null, null); } public void testEx2() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex2.tree"); assertNode(root, 1, "2", new int[] {0,0,0,3,2,3,0,0,0,0}, "name", 4, null, null); ParseTreeNode[] forks = root.getForks(); assertNode(forks[0], 0, "2", null, null, 0, null, null); assertNode(forks[1], 0, "3", new int[] {0,0,0,0,2,0,0,0,0,0}, null, 0, null, null); assertNode(forks[2], 0, "4", new int[] {0,0,0,3,0,0,0,0,0,0}, null, 0, null, null); assertNode(forks[3], 0, "5", new int[] {0,0,0,0,0,3,0,0,0,0}, null, 0, null, null); } public void testEx3() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex3.tree"); assertNode(root, 2, "5", new int[] {0,0,0,0,1,1,2,2,0,1}, "key_index", 3, "27", null); ParseTreeNode[] forks = root.getForks(); assertNode(forks[0], 0, "5", null, null, 0, null, null); assertNode(forks[1], 0, "3", new int[] {0,0,0,0,1,0,0,0,0,1}, null, 0, null, null); assertNode(forks[2], 0, "2", new int[] {0,0,0,0,0,1,2,2,0,0}, null, 0, null, null); } public void testBig() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("big"); //too big to do all the cases. test only the root assertNode(root, 2, "5", new int[] {0,0,39,34,45,5,46,31,25,13}, "thread_index", 3, "8", null); } public void testEx0Decision() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex0"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature feature = new NumericFeature("ola"); featureMap.put(feature.getName(), feature); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); assertDecisionInEx0(tree, feature); } public void testEx1Decision() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex1"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature feature = new NameListFeature("name", "peter", "per", "por", "par\\,", "pir \\\"na"); featureMap.put(feature.getName(), feature); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); assertDecisionInEx1(tree, feature); } public void testEx2Decision() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex2"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature feature = new NameListFeature("name", "name1", "name2", "name3"); featureMap.put(feature.getName(), feature); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); assertDecisionInEx2(tree, feature); } public void testEx3Decision() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex3"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature feature = new NumericFeature("key_index"); featureMap.put(feature.getName(), feature); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); assertDecisionInEx3(tree, feature); } public void testBigDecision() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("big"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature keyIndex = new NumericFeature("key_index"); Feature threadIndex = new NumericFeature("thread_index"); featureMap.put(keyIndex.getName(), keyIndex); featureMap.put(threadIndex.getName(), threadIndex); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); assertDecisionInBig(tree, keyIndex, threadIndex); } public void testSerializable() throws Exception { ParseTreeNode root = DecisionTreeParser.parse("ex1"); Map<String, Feature> featureMap = new HashMap<String, Feature>(); Feature feature = new NameListFeature("name", "peter", "per", "por", "par\\,", "pir \\\"na"); featureMap.put(feature.getName(), feature); DecisionTree tree = DecisionTreeBuilder.build(root, featureMap); DecisionTree readTree = serializeAndClone(tree, "Example 1"); assertDecisionInEx1(tree, feature); assertDecisionInEx1(readTree, feature); root = DecisionTreeParser.parse("ex0"); featureMap = new HashMap<String, Feature>(); feature = new NumericFeature("name"); featureMap.put(feature.getName(), feature); tree = DecisionTreeBuilder.build(root, featureMap); readTree = serializeAndClone(tree, "Example 0"); assertDecisionInEx0(tree, feature); assertDecisionInEx0(readTree, feature); root = DecisionTreeParser.parse("ex2"); featureMap = new HashMap<String, Feature>(); feature = new NameListFeature("name", "name1", "name2", "name3"); featureMap.put(feature.getName(), feature); tree = DecisionTreeBuilder.build(root, featureMap); readTree = serializeAndClone(tree, "Example 2"); assertDecisionInEx2(tree, feature); assertDecisionInEx2(readTree, feature); root = DecisionTreeParser.parse("ex3"); featureMap = new HashMap<String, Feature>(); feature = new NumericFeature("key_index"); featureMap.put(feature.getName(), feature); tree = DecisionTreeBuilder.build(root, featureMap); readTree = serializeAndClone(tree, "Example 3"); assertDecisionInEx3(tree, feature); assertDecisionInEx3(readTree, feature); root = DecisionTreeParser.parse("big"); featureMap = new HashMap<String, Feature>(); Feature keyIndex = new NumericFeature("key_index"); Feature threadIndex = new NumericFeature("thread_index"); featureMap.put(keyIndex.getName(), keyIndex); featureMap.put(threadIndex.getName(), threadIndex); tree = DecisionTreeBuilder.build(root, featureMap); readTree = serializeAndClone(tree, "Big Example"); assertDecisionInBig(tree, keyIndex, threadIndex); assertDecisionInBig(readTree, keyIndex, threadIndex); } private DecisionTree serializeAndClone(DecisionTree tree, String where) throws IOException, ClassNotFoundException { ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(arrayOutputStream); oos.writeObject(tree); oos.flush(); oos.close(); byte[] bytes = arrayOutputStream.toByteArray(); log.infof("Size of tree for %s is %s bytes", where, bytes.length); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); DecisionTree readTree = (DecisionTree) ois.readObject(); ois.close(); return readTree; } private void assertDecisionInEx0(DecisionTree tree, Feature feature) { assert tree.query(Collections.<Feature, FeatureValue>emptyMap()) == 1; Map<Feature, FeatureValue> keyFeature = new HashMap<Feature, FeatureValue>(); keyFeature.put(feature, feature.createFeatureValue(3)); assert tree.query(keyFeature) == 1; keyFeature.put(feature, feature.createFeatureValue(4)); assert tree.query(keyFeature) == 1; } private void assertDecisionInEx1(DecisionTree tree, Feature feature) { assert tree.query(Collections.<Feature, FeatureValue>emptyMap()) == 1; Map<Feature, FeatureValue> keyFeature = new HashMap<Feature, FeatureValue>(); keyFeature.put(feature, feature.createFeatureValue("peter")); assert tree.query(keyFeature) == 2; keyFeature.put(feature, feature.createFeatureValue("per")); assert tree.query(keyFeature) == 3; keyFeature.put(feature, feature.createFeatureValue("por")); assert tree.query(keyFeature) == 4; keyFeature.put(feature, feature.createFeatureValue("par\\,")); assert tree.query(keyFeature) == 5; keyFeature.put(feature, feature.createFeatureValue("pir \\\"na")); assert tree.query(keyFeature) == 5; } private void assertDecisionInEx2(DecisionTree tree, Feature feature) { assert tree.query(Collections.<Feature, FeatureValue>emptyMap()) == 2; Map<Feature, FeatureValue> keyFeature = new HashMap<Feature, FeatureValue>(); keyFeature.put(feature, feature.createFeatureValue("name1")); assert tree.query(keyFeature) == 3; keyFeature.put(feature, feature.createFeatureValue("name2")); assert tree.query(keyFeature) == 4; keyFeature.put(feature, feature.createFeatureValue("name3")); assert tree.query(keyFeature) == 5; } private void assertDecisionInEx3(DecisionTree tree, Feature feature) { assert tree.query(Collections.<Feature, FeatureValue>emptyMap()) == 5; Map<Feature, FeatureValue> keyFeature = new HashMap<Feature, FeatureValue>(); keyFeature.put(feature, feature.createFeatureValue(27)); assert tree.query(keyFeature) == 3; keyFeature.put(feature, feature.createFeatureValue(28)); assert tree.query(keyFeature) == 2; } private void assertDecisionInBig(DecisionTree tree, Feature keyIndex, Feature threadIndex) { assert tree.query(Collections.<Feature, FeatureValue>emptyMap()) == 5; Map<Feature, FeatureValue> keyFeature = new HashMap<Feature, FeatureValue>(); keyFeature.put(keyIndex, keyIndex.createFeatureValue(2)); assert tree.query(keyFeature) == 5; keyFeature.clear(); keyFeature.put(threadIndex, threadIndex.createFeatureValue(7)); assert tree.query(keyFeature) == 3; keyFeature.put(threadIndex, threadIndex.createFeatureValue(5)); keyFeature.put(keyIndex, keyIndex.createFeatureValue(1841)); assert tree.query(keyFeature) == 5; keyFeature.put(threadIndex, threadIndex.createFeatureValue(6)); assert tree.query(keyFeature) == 2; keyFeature.put(threadIndex, threadIndex.createFeatureValue(9)); keyFeature.put(keyIndex, keyIndex.createFeatureValue(44)); assert tree.query(keyFeature) == 9; keyFeature.put(keyIndex, keyIndex.createFeatureValue(45)); assert tree.query(keyFeature) == 5; //the deepest in the tree keyFeature.put(threadIndex, threadIndex.createFeatureValue(1)); keyFeature.put(keyIndex, keyIndex.createFeatureValue(1117)); assert tree.query(keyFeature) == 0; keyFeature.put(keyIndex, keyIndex.createFeatureValue(1118)); assert tree.query(keyFeature) == 5; keyFeature.put(keyIndex, keyIndex.createFeatureValue(2334)); assert tree.query(keyFeature) == 2; keyFeature.put(keyIndex, keyIndex.createFeatureValue(2335)); assert tree.query(keyFeature) == 0; } private void assertNode(ParseTreeNode node, int type, String clazz, int[] freq, String att, int numberOfForks, String cut, String[][] elts) { assert node != null; assert node.getType() == type; assert node.getClazz().equals(clazz); if (freq != null) { assert node.getFrequency() != null; assert freq.length == node.getFrequency().length; for (int i = 0; i < freq.length; ++i) { assert freq[i] == node.getFrequency()[i]; } } else { assert node.getFrequency() == null; } if (att != null) { assert node.getAttribute() != null; assert att.equals(node.getAttribute()); } else { assert node.getAttribute() == null; } assert node.getNumberOfForks() == numberOfForks; if (cut != null) { assert node.getCut() != null; assert cut.equals(node.getCut()); } else { assert node.getCut() == null; } if (elts != null) { assert elts.length == node.getElts().length; for (int i = 0; i < elts.length; ++i) { List<String> eltsValues = node.getElts()[i].getValues(); assert eltsValues.size() == elts[i].length; for (int j = 0; j < elts[i].length; ++j) { assert elts[i][j].equals(eltsValues.get(j)); } } } else { assert node.getElts() == null; } } }