# -*- coding: utf-8 -*-
'''
Generation of pairs from Princeton WordNet using nltk

Created on May 24, 2010

@author: Bartosz Broda
'''

from nltk.corpus import wordnet as wn
import networkx as nx
import codecs

def lcs(paths, a, b):
	"""
	Gets Least Common Subsummer (LCS) for two nodes in a graph given paths in the graph.
	
	paths - shortest paths lengths in graph, generated, f.e., with networkx.all_pairs_shortest_path_length 
	a,b - nodes in graph
	
	Returns tuple:
	(length of lcs, synset_id, m, n)
	where m is path up from a to common node, and n is path down from common node to b
	and length is m+n
	
	Code taken from pyplwn.utils.Cousins._cousins_lcs
	"""
	
	a_paths = paths[a]
	b_paths = paths[b]
	
	if b in a_paths:
		return (a_paths[b], b, a_paths[b], 0)
	if a in b_paths:
		return (b_paths[a], a, 0, b_paths[a])
	
	all_cs = [] # (len, synset, m, n)
	for from_a_synset in a_paths:
		m = a_paths[from_a_synset] # m
		for from_b_synset in b_paths:
			n = b_paths[from_b_synset] # n
			if from_b_synset == from_a_synset:
				all_cs.append((m + n, from_a_synset, m, n))
	
	if not len(all_cs):
		return None

	all_cs = sorted(all_cs)
	return all_cs[0]	

def pwn_to_graph(pos = wn.NOUN):
	"""
	Converts PWN to DiGraph (using hypernyms links)
	"""
	g = nx.DiGraph()
	for synset in wn.all_synsets(pos = pos):
		hypernyms = synset.hypernyms()
		for hyp in hypernyms:
			g.add_edge(synset, hyp)
	return g

def write_cousins_lines(out, a, b, lcs_tuple):
	(length, synset, m, n) = lcs_tuple
	for a_lemma in a.lemmas:
		for b_lemma in b.lemmas:
			out.write(u"%s;%s;%s;%d;%d\n" % (a_lemma.name, b_lemma.name, str(synset), m, n))
			#out.write(u"%s;%s;%s;%d;%d\n" % (b_lemma.name, a_lemma.name, str(synset), n, m))

	
def extract_cousins(outfile, max_length, pos = wn.NOUN):
	"""
	Extracts all cousins and writes results to file named outfile.
	
	max_length is a constraint on max length of m or n (path from a synset to LCS), or 
	to put it another way: path between two synsets is <= 2*max_length
	"""
	print "Generating graph from PWN..."
	graph = pwn_to_graph(pos)
	nodes = graph.nodes()
	nodes_len = len(nodes)
	print "Generating paths"
	paths = nx.all_pairs_shortest_path_length(graph, max_length)
	
	out = codecs.open(outfile, 'w', 'utf8')
	out.write("LemmaA;LemmaB;LemmaLCS;m;n\n")
	
	for a_i in xrange(0, nodes_len):
			
		if a_i % 100 == 0:
			print a_i, nodes_len
		a = nodes[a_i]
		for b_i in xrange(0, a_i):
			b = nodes[b_i]
			if a != b:
				lcs_ab = lcs(paths, a, b)
				if lcs_ab:
					write_cousins_lines(out, a, b, lcs_ab)
					
def write_lex_relations(out, a,related, name):
	for b in related:
		if a == b:
			continue
		out.write(u"%s;%s;%s\n" % (name,a.name,b.name) )

def extract_lex_relations(outfile, pos = wn.NOUN):
	print "For other POS then NOUN Participle"
	out = codecs.open(outfile, 'w', 'utf8')
	out.write("LemmaA;LemmaB;relation\n")
	for lemma_name in list(wn.all_lemma_names()):
		lemmas = wn.lemmas(lemma_name)
		for lemma in lemmas:
			antonyms = lemma.antonyms()
			write_lex_relations(out, lemma, antonyms, 'antonyms')
			also_sees = lemma.also_sees()
			write_lex_relations(out, lemma, also_sees, 'also_sees')
			derivationally_related_forms = lemma.derivationally_related_forms()
			write_lex_relations(out, lemma, derivationally_related_forms, 'derivationally_related_forms')

def write_synset_relations(out, a, b, name):
	for a_lemma in a.lemmas:
		for s in b:
			for b_lemma in s.lemmas:
				out.write(u"%s;%s;%s\n" % (name,a_lemma.name, b_lemma.name))


def extract_synset_relations(outfile, pos = wn.NOUN):
	out = codecs.open(outfile, 'w', 'utf8')
	out.write("LemmaA;LemmaB;relation\n")
	for synset in wn.all_synsets(pos = pos):
		instance_hypernyms = synset.instance_hypernyms()
		write_synset_relations(out, synset, instance_hypernyms, 'instance_hypernyms')
		instance_hyponyms = synset.instance_hyponyms()
		write_synset_relations(out, synset, instance_hyponyms, 'instance_hyponyms')
		member_holonyms = synset.member_holonyms()
		write_synset_relations(out, synset, member_holonyms, 'member_holonyms')
		member_meronyms = synset.member_meronyms()
		write_synset_relations(out, synset, member_meronyms, 'member_meronyms')
		part_holonyms = synset.part_holonyms()
		write_synset_relations(out, synset, part_holonyms, 'part_holonyms')
		part_meronyms = synset.part_meronyms()
		write_synset_relations(out, synset, part_meronyms, 'part_meronyms')
		substance_holonyms = synset.substance_holonyms()
		write_synset_relations(out, synset, substance_holonyms, 'substance_holonyms')
		substance_meronyms = synset.substance_meronyms()
		write_synset_relations(out, synset, substance_meronyms, 'substance_meronyms')

def extract_synonyms(outfile, pos = wn.NOUN):
	out = codecs.open(outfile, 'w', 'utf8')
	out.write("LemmaA;LemmaB\n")
	for synset in wn.all_synsets(pos = pos):
		for lemma_a in synset.lemmas:
			for lemma_b in synset.lemmas:
				if lemma_a == lemma_b:
					continue
				out.write("%s;%s\n" % (lemma_a.name, lemma_b.name) )
	

def main():
	extract_cousins("pwn_cousins_path_max2_2.txt", 2)
	extract_lex_relations("pwn_lex_rel.txt")
	extract_synset_relations('pwn_synset_relations.txt')
	extract_synonyms('pwn_synonyms.txt')
		
if __name__ == '__main__':
	main()
	
