@Override
	protected Relatedness calcRelatedness( Concept synset1, Concept synset2 ) {
		StringBuilder tracer = new StringBuilder();
		if ( synset1 == null || synset2 == null ) return new Relatedness( min, null, illegalSynset );
		if ( synset1.getSynset().equals( synset2.getSynset() ) ) return new Relatedness( max, identicalSynset, null );
		
		Set<String> horizontal1 = Traverser.getHorizontalSynsets( synset1.getSynset() );	
		Set<String> horizontal2 = Traverser.getHorizontalSynsets( synset2.getSynset() );
		
		boolean inHorizon = horizontal2.contains(synset1.getSynset()) || horizontal1.contains(synset2.getSynset());
		
		if ( inHorizon ) return new Relatedness( max );
		
		Set<String> upward2 = Traverser.getUpwardSynsets( synset2.getSynset() );
		Set<String> downward2 = Traverser.getDownwardSynsets( synset2.getSynset() );
		
		if ( enableTrace ) {
			tracer.append( "Horizontal Links of "+synset1.getSynset()+": "+horizontal1+"\n");
			tracer.append( "Horizontal Links of "+synset2.getSynset()+": "+horizontal1+"\n");
			tracer.append( "Upward Links of "+synset2.getSynset()+": "+upward2+"\n");
			tracer.append( "Downward Links of "+synset2.getSynset()+": "+downward2+"\n");
		}
		
		// Compare all possible surface forms related to the synset (improved from the Wordnet::Similarity)
		boolean contained = Traverser.contained( synset1, synset2 );
		// We don't need if synset2 is contained in upward1 or downward1!
		boolean inUpOrDown = upward2.contains( synset1.getSynset() ) || downward2.contains( synset1.getSynset() );
		if ( contained && inUpOrDown ) {
			tracer.append( "Strong Rel (Compound Word Match).\n" );
			return new Relatedness( max, tracer.toString(), null );
		}
		
		MedStrong medStrong = new MedStrong();
		int score = medStrong.medStrong( 0, 0, 0, synset1.getSynset(), synset1.getSynset(), synset2.getSynset() );
		
		return new Relatedness( score, tracer.toString(), null );
	}