package edu.neu.ccs.evergreen.ir; /** * Utility class used to work with relation constraints that are of rank 3 and * represent truth tables between 0 and 255 inclusive. For more details see: * http://www.ccs.neu.edu/evergreen/ */ public class Relation { /** * Private constructor to force utility class usage. */ private Relation() { } /** * Determine if a variable position is forced to a particular value based on * the relation that it is in. * * @param relationNumber * Relation number * @param variablePosition * Variable position to check * @return 0 if forced to false, 1 if forced to true; -1 otherwise * @throws IllegalArgumentException * If relationNumber not [0..255] * @throws IllegalArgumentException * If variablePosition not [0..2] */ public static int forcedValue(int relationNumber, int variablePosition) { checkRelationNumber(relationNumber); checkVariablePosition(variablePosition); if (notInRelation(relationNumber, variablePosition)) { return -1; } int oneMagicNumber = getMagicNumber(variablePosition, 1); int matchingRelationNumber = (relationNumber & oneMagicNumber); if (matchingRelationNumber == 0) { return 0; } if (matchingRelationNumber == relationNumber) { return 1; } return -1; } /** * Reduce the relation by setting the value of a variable position in the * relation. * * @param relationNumber * Relation number to reduce * @param variablePosition * Variable position to set * @param value * Value to set variable to 0 = false or 1 = true * @return Reduced relation number * @throws IllegalArgumentException * If relationNumber not [0..255] * @throws IllegalArgumentException * If variablePosition not [0..2] * @throws IllegalArgumentException * If value not [0..1] */ public static int reduce(int relationNumber, int variablePosition, int value) { checkRelationNumber(relationNumber); checkVariablePosition(variablePosition); if ((value != 0) && (value != 1)) { throw new IllegalArgumentException( "Value is not valid. Must be [0..1] got " + value); } int magicNumber = getMagicNumber(variablePosition, value); int matchingRelationNumber = (relationNumber & magicNumber); if (value == 0) { return matchingRelationNumber | (matchingRelationNumber << (1 << variablePosition)); } return matchingRelationNumber | (matchingRelationNumber >> (1 << variablePosition)); } /** * Rename the relation by negating the truth table of a variable position in * the relation. * * @param relationNumber * Relation number to rename * @param variablePosition * Variable position to negate * @return Renamed relation number * @throws IllegalArgumentException * If relationNumber not [0..255] * @throws IllegalArgumentException * If variablePosition not [0..2] */ public static int rename(int relationNumber, int variablePosition) { checkRelationNumber(relationNumber); checkVariablePosition(variablePosition); int zeroMagicNumber = getMagicNumber(variablePosition, 0); int oneMagicNumber = getMagicNumber(variablePosition, 1); int shiftAmount = (1 << variablePosition); return ((relationNumber & zeroMagicNumber) << shiftAmount) | ((relationNumber & oneMagicNumber) >> shiftAmount); } /** * Determine how many variables are still in a relation, that is setting a * variable position to true or false will change the relation number. * * @param relationNumber * Relation number to check * @return Number of variables in relation * @throws IllegalArgumentException * If relationNumber not [0..255] */ public static int variableCount(int relationNumber) { checkRelationNumber(relationNumber); int rank = 3; for (int i = 0; i < 3; i++) { if (notInRelation(relationNumber, i)) { rank--; } } return rank; } /** * Determine how many rows in the relation's truth table evaluate to true * given trueCount variable positions set to true. * * @param relationNumber * Relation number to check * @param trueVariablePositionsCount * Number of variable positions set to true [0..3] * @return Number of rows that evaluate to true * @throws IllegalArgumentException * If relationNumber not [0..255] * @throws IllegalArgumentException * If trueCount not [0..3] */ public static int containsRowCount(int relationNumber, int trueVariablePositionsCount) { checkRelationNumber(relationNumber); // relation number for truth table that is true, if and only if // that many variable positions are set to the true count int trueCountRelationNumber; switch (trueVariablePositionsCount) { case 0: trueCountRelationNumber = 1; break; case 1: trueCountRelationNumber = 22; break; case 2: trueCountRelationNumber = 104; break; case 3: trueCountRelationNumber = 128; break; default: throw new IllegalArgumentException( "True variable positions count must be in [0..3] got " + trueVariablePositionsCount); } return satisfyingRowCount(relationNumber & trueCountRelationNumber); } /** * Determine the total number of rows in the relation's truth table that * evaluate to true. * * @param relationNumber * Relation number to check * @return Number of rows that evaluate to true * @throws IllegalArgumentException * If relationNumber not [0..255] */ public static int satisfyingRowCount(int relationNumber) { checkRelationNumber(relationNumber); int count = 0; for (int i = 0; i < 8; i++) { if ((relationNumber & (1 << i)) != 0) { count++; } } return count; } /** * Determine if a variable position is still in a relation. * * @param relationNumber * Relation to check * @param variablePosition * Variable position to check * @return False if the variable position is still in the relation * @throws IllegalArgumentException * If relationNumber not [0..255] * @throws IllegalArgumentException * If variablePosition not [0..2] */ public static boolean notInRelation(int relationNumber, int variablePosition) { checkRelationNumber(relationNumber); checkVariablePosition(variablePosition); int magicNumber = getMagicNumber(variablePosition, 1); return ((relationNumber & magicNumber) >> (1 << variablePosition)) == (relationNumber & (~magicNumber)); } /** * Determine the magic number for a variable position and value. * * @param variablePosition * Variable position * @param value * Value * @return Magic number */ private static int getMagicNumber(int variablePosition, int value) { // Valid variable position and value is checked by calling method if (value == 0) { // 1st variable position (Least Significant), value 0 if (variablePosition == 0) { return 85; } if (variablePosition == 1) { return 51; } return 15; } // 1st variable position (Least Significant), value 1 if (variablePosition == 0) { return 170; } if (variablePosition == 1) { return 204; } return 240; } /** * Check to ensure that we are working with a valid relation number. * * @param relationNumber * Relation number to check */ private static void checkRelationNumber(int relationNumber) { if ((relationNumber < 0) || (relationNumber > 255)) { throw new IllegalArgumentException( "Relation number is not valid. Must be [0..255] got " + relationNumber); } } /** * Check to ensure that we are working with a valid variable position. * * @param variablePosition * Variable position to check */ private static void checkVariablePosition(int variablePosition) { if ((variablePosition < 0) || (variablePosition > 2)) { throw new IllegalArgumentException( "Variable position is not valid. Muse be [0..2] got " + variablePosition); } } }