public Relation join(Relation r) {
		Relation result = this.clone().dropTuples();
		
		HashMap<Integer, Integer> matchingCols = new HashMap<Integer, Integer>(); 
		int i = 0;
		for (Token col : r.schema) {
			if (result.schema.contains(col))
				matchingCols.put(i, result.schema.indexOf(col));
			else {
				result.schema.attributes.add(col.clone());
				result.query.arguments.arguments.add(new Argument(col.clone()));
			}
			++i;
		}

		for (Tuple t1 : this.facts) {
			nextfact:
			for (Tuple t2 : r.facts) {
				for (int col2 : matchingCols.keySet()) {
					int col1 = matchingCols.get(col2);
					if (!t1.parameters.get(col1).equals(t2.parameters.get(col2)))
						continue nextfact;
				}
				
				Tuple newTuple = t1.clone();
				i = 0;
				for (Token val : t2.parameters) {
					if (!matchingCols.containsKey(i))
						newTuple.parameters.add(val);
					++i;
				}
				
				result.addFact(newTuple);
			}
		}
		
		return result;
	}