/******************************************************************************* * Copyright (c) 2007 IBM Corporation. * 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: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package org.rascalmpl.value; import java.util.Iterator; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISetWriter; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.exceptions.FactTypeUseException; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import junit.framework.TestCase; public abstract class BaseTestRelation extends TestCase { private IValueFactory vf; private TypeFactory tf; private IValue[] integers; private ITuple[] integerTuples; private ISet setOfIntegers; private ISet integerRelation; private IValue[] doubles; private ISet setOfDoubles; private ISet doubleRelation; private ITuple[] doubleTuples; protected void setUp(IValueFactory factory) throws Exception { super.setUp(); vf = factory; tf = TypeFactory.getInstance(); integers = new IValue[5]; ISetWriter sw = vf.setWriter(tf.integerType()); for (int i = 0; i < integers.length; i++) { IValue iv = vf.integer(i); integers[i] = iv; sw.insert(iv); } setOfIntegers = sw.done(); doubles = new IValue[10]; ISetWriter sw2 = vf.setWriter(tf.realType()); for (int i = 0; i < doubles.length; i++) { IValue iv = vf.real(i); doubles[i] = iv; sw2.insert(iv); } setOfDoubles = sw2.done(); ISetWriter rw = vf.setWriter(tf.tupleType(tf.integerType(), tf.integerType())); integerTuples = new ITuple[integers.length * integers.length]; for (int i = 0; i < integers.length; i++) { for (int j = 0; j < integers.length; j++) { ITuple t = vf.tuple(integers[i], integers[j]); integerTuples[i * integers.length + j] = t; rw.insert(t); } } integerRelation = rw.done(); ISetWriter rw2 = vf.setWriter(tf.tupleType(tf.realType(), tf.realType())); doubleTuples = new ITuple[doubles.length * doubles.length]; for (int i = 0; i < doubles.length; i++) { for (int j = 0; j < doubles.length; j++) { ITuple t = vf.tuple(doubles[i], doubles[j]); doubleTuples[i * doubles.length + j] = t; rw2.insert(t); } } doubleRelation = rw2.done(); } public void testIsEmpty() { if (integerRelation.isEmpty()) { fail("integerRelation is not empty"); } if (!vf.set(tf.tupleType(tf.integerType())).isEmpty()) { fail("this relation should be empty"); } ISet emptyRel = vf.set(); if (!emptyRel.isEmpty()) { fail("empty relation is not empty?"); } if (!emptyRel.getType().isRelation()) { fail("empty relation should have relation type"); } } public void testSize() { if (integerRelation.size() != integerTuples.length) { fail("relation size is not correct"); } } public void testArity() { if (integerRelation.asRelation().arity() != 2) { fail("arity should be 2"); } } public void testProductIRelation() { ISet prod = integerRelation.product(integerRelation); if (prod.asRelation().arity() != 2 ) { fail("arity of product should be 2"); } if (prod.size() != integerRelation.size() * integerRelation.size()) { fail("size of product should be square of size of integerRelation"); } } public void testProductISet() { ISet prod = integerRelation.product(setOfIntegers); if (prod.asRelation().arity() != 2) { fail("arity of product should be 2"); } if (prod.size() != integerRelation.size() * setOfIntegers.size()) { fail("size of product should be square of size of integerRelation"); } } public void testClosure() { try { if (!integerRelation.asRelation().closure().isEqual(integerRelation)) { fail("closure adds extra tuples?"); } } catch (FactTypeUseException e) { fail("integerRelation is reflexive, so why an error?"); } try { ISet rel = vf.set(tf.tupleType(tf.integerType(), tf.integerType())); rel.asRelation().closure(); } catch (FactTypeUseException e) { fail("reflexivity with subtyping is allowed"); } try { ITuple t1 = vf.tuple(integers[0], integers[1]); ITuple t2 = vf.tuple(integers[1], integers[2]); ITuple t3 = vf.tuple(integers[2], integers[3]); ITuple t4 = vf.tuple(integers[0], integers[2]); ITuple t5 = vf.tuple(integers[1], integers[3]); ITuple t6 = vf.tuple(integers[0], integers[3]); ISet test = vf.set(t1, t2, t3); ISet closed = test.asRelation().closure(); if (closed.asRelation().arity() != test.asRelation().arity()) { fail("closure should produce relations of same arity"); } if (closed.size() != 6) { fail("closure contains too few elements"); } if (!closed.intersect(test).isEqual(test)) { fail("closure should contain all original elements"); } if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) { fail("closure does not contain required elements"); } } catch (FactTypeUseException e) { fail("this should all be type correct"); } } public void testCompose() { try { ISet comp = integerRelation.asRelation().compose(integerRelation.asRelation()); if (comp.asRelation().arity() != integerRelation.asRelation().arity() * 2 - 2) { fail("composition is a product with the last column of the first relation and the first column of the last relation removed"); } if (comp.size() != integerRelation.size()) { fail("numner of expected tuples is off"); } } catch (FactTypeUseException e) { fail("the above should be type correct"); } try { ITuple t1 = vf.tuple(integers[0], doubles[0]); ITuple t2 = vf.tuple(integers[1], doubles[1]); ITuple t3 = vf.tuple(integers[2], doubles[2]); ISet rel1 = vf.set(t1, t2, t3); ITuple t4 = vf.tuple(doubles[0], integers[0]); ITuple t5 = vf.tuple(doubles[1], integers[1]); ITuple t6 = vf.tuple(doubles[2], integers[2]); ISet rel2 = vf.set(t4, t5, t6); ITuple t7 = vf.tuple(integers[0], integers[0]); ITuple t8 = vf.tuple(integers[1], integers[1]); ITuple t9 = vf.tuple(integers[2], integers[2]); ISet rel3 = vf.set(t7, t8, t9); assertTrue( "Non-comparable types should yield empty composition result.", vf.set(vf.tuple(doubles[0], doubles[0])).asRelation() .compose(rel1.asRelation()).isEmpty()); ISet comp = rel1.asRelation().compose(rel2.asRelation()); if (!comp.isEqual(rel3)) { fail("composition does not produce expected result"); } } catch (FactTypeUseException e) { fail("the above should be type correct"); } } public void testContains() { try { for (ITuple t : integerTuples) { if (!integerRelation.contains(t)) { fail("contains returns false instead of true"); } } } catch (FactTypeUseException e) { fail("this should be type correct"); } } public void testInsert() { try { ISet rel = integerRelation.insert(vf.tuple(vf.integer(0),vf.integer(0))); if (!rel.isEqual(integerRelation)) { fail("insert into a relation of an existing tuple should not change the relation"); } ISetWriter relw3 = vf.setWriter(tf.tupleType(tf.integerType(), tf.integerType())); relw3.insertAll(integerRelation); ISet rel3 = relw3.done(); final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100)); ISet rel4 = rel3.insert(tuple); if (rel4.size() != integerRelation.size() + 1) { fail("insert failed"); } if (!rel4.contains(tuple)) { fail("insert failed"); } } catch (FactTypeUseException e) { fail("the above should be type correct"); } } public void testIntersectIRelation() { try { if (!integerRelation.intersect(doubleRelation).isEmpty()) { fail("non-intersecting relations should produce empty intersections"); } ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result = vf.set(integerTuples[2]); if (!oneTwoThree.intersect(threeFourFive).isEqual(result)) { fail("intersection failed"); } if (!threeFourFive.intersect(oneTwoThree).isEqual(result)) { fail("intersection should be commutative"); } if (!oneTwoThree.intersect(vf.set(tf.tupleType(tf.integerType(),tf.integerType()))).isEmpty()) { fail("intersection with empty set should produce empty"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testIntersectISet() { ISet empty1 = vf.set(tf.tupleType(tf.integerType())); ISet empty2 = vf.set(tf.tupleType(tf.realType())); try { final ISet intersection = empty1.intersect(empty2); if (!intersection.isEmpty()) { fail("empty intersection failed"); } Type type = intersection.getType(); if (!type.getFieldType(0).isSubtypeOf(tf.numberType())) { fail("intersection should produce lub types"); } } catch (FactTypeUseException e) { fail("intersecting types which have a lub should be possible"); } try { if (!integerRelation.intersect(doubleRelation).isEmpty()) { fail("non-intersecting relations should produce empty intersections"); } ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result = vf.set(integerTuples[2]); if (!oneTwoThree.intersect(threeFourFive).isEqual(result)) { fail("intersection failed"); } if (!threeFourFive.intersect(oneTwoThree).isEqual(result)) { fail("intersection should be commutative"); } if (!oneTwoThree.intersect(vf.set(tf.tupleType(tf.integerType(),tf.integerType()))).isEmpty()) { fail("intersection with empty set should produce empty"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testSubtractIRelation() { ISet empty1 = vf.set(tf.tupleType(tf.integerType())); ISet empty2 = vf.set(tf.tupleType(tf.realType())); try { final ISet diff = empty1.subtract(empty2); if (!diff.isEmpty()) { fail("empty diff failed"); } } catch (FactTypeUseException e) { fail("subtracting types which have a lub should be possible"); } try { ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result1 = vf.set(integerTuples[0],integerTuples[1]); ISet result2 = vf.set(integerTuples[3],integerTuples[4]); if (!oneTwoThree.subtract(threeFourFive).isEqual(result1)) { fail("subtraction failed"); } if (!threeFourFive.subtract(oneTwoThree).isEqual(result2)) { fail("subtraction failed"); } ISet empty3 = vf.set(tf.tupleType(tf.integerType(),tf.integerType())); if (!empty3.subtract(threeFourFive).isEmpty()) { fail("subtracting from empty set should produce empty"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testSubtractISet() { ISet empty1 = vf.set(tf.tupleType(tf.integerType())); ISet empty2 = vf.set(tf.tupleType(tf.realType())); try { final ISet diff = empty1.subtract(empty2); if (!diff.isEmpty()) { fail("empty diff failed"); } } catch (FactTypeUseException e) { fail("subtracting types which have a lub should be possible"); } try { ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result1 = vf.set(integerTuples[0],integerTuples[1]); if (!oneTwoThree.subtract(threeFourFive).isEqual(result1)) { fail("subtraction failed"); } ISet empty3 = vf.set(tf.tupleType(tf.integerType(),tf.integerType())); if (!empty3.subtract(threeFourFive).isEmpty()) { fail("subtracting from empty set should produce empty"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testUnionIRelation() { try { if (integerRelation.union(doubleRelation).size() != integerRelation.size() + doubleRelation.size()) { fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); } ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result = vf.set(integerTuples[0], integerTuples[1], integerTuples[2], integerTuples[3], integerTuples[4]); if (!oneTwoThree.union(threeFourFive).isEqual(result)) { fail("union failed"); } if (!threeFourFive.union(oneTwoThree).isEqual(result)) { fail("union should be commutative"); } if (!oneTwoThree.union(vf.set(tf.tupleType(tf.integerType(),tf.integerType()))).isEqual(oneTwoThree)) { fail("union with empty set should produce same set"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testEmptySetIsARelation() { assertTrue(vf.set().getType().isRelation()); assertTrue(vf.set(tf.integerType()).getType().isRelation()); ISet r = vf.set().insert(vf.tuple(vf.integer(1), vf.integer(2))); r = r.subtract(r); assertTrue(r.getType().isRelation()); ISet s = vf.set().insert(vf.integer(1)); s = s.subtract(s); assertTrue(s.getType().isRelation()); // yes really! } public void testUnionISet() { try { if (integerRelation.union(doubleRelation).size() != integerRelation.size() + doubleRelation.size()) { fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); } ISet oneTwoThree = vf.set(integerTuples[0], integerTuples[1], integerTuples[2]); ISet threeFourFive = vf.set(integerTuples[2], integerTuples[3], integerTuples[4]); ISet result = vf.set(integerTuples[0], integerTuples[1], integerTuples[2], integerTuples[3], integerTuples[4]); if (!oneTwoThree.union(threeFourFive).isEqual(result)) { fail("union failed"); } if (!threeFourFive.union(oneTwoThree).isEqual(result)) { fail("union should be commutative"); } if (!oneTwoThree.union(vf.set(tf.tupleType(tf.integerType(),tf.integerType()))).isEqual(oneTwoThree)) { fail("union with empty set should produce same set"); } } catch (FactTypeUseException e) { fail("the above should all be type safe"); } } public void testIterator() { try { Iterator<IValue> it = integerRelation.iterator(); int i; for (i = 0; it.hasNext(); i++) { ITuple t = (ITuple) it.next(); if (!integerRelation.contains(t)) { fail("iterator produces strange elements?"); } } if (i != integerRelation.size()) { fail("iterator skipped elements"); } } catch (FactTypeUseException e) { fail("the above should be type correct"); } } public void testCarrier() { ISet carrier = integerRelation.asRelation().carrier(); if (!carrier.isEqual(setOfIntegers)) { fail("carrier should be equal to this set"); } try { ITuple t1 = vf.tuple(integers[0], doubles[0]); ITuple t2 = vf.tuple(integers[1], doubles[1]); ITuple t3 = vf.tuple(integers[2], doubles[2]); ISet rel1 = vf.set(t1, t2, t3); ISet carrier1 = rel1.asRelation().carrier(); if (carrier1.getElementType() != tf.numberType()) { fail("expected number type on carrier"); } if (carrier1.size() != 6) { fail("carrier does not contain all elements"); } if (carrier1.intersect(setOfIntegers).size() != 3) { fail("integers should be in there still"); } if (carrier1.intersect(setOfDoubles).size() != 3) { fail("doubles should be in there still"); } } catch (FactTypeUseException e) { fail("the above should be type correct"); } } }