/**
* Copyright 2016
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.tudarmstadt.ukp.lmf.transform.germanet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import de.tudarmstadt.ukp.lmf.model.core.Definition;
import de.tudarmstadt.ukp.lmf.model.core.Sense;
import de.tudarmstadt.ukp.lmf.model.core.TextRepresentation;
import de.tudarmstadt.ukp.lmf.model.enums.ELanguageIdentifier;
import de.tudarmstadt.ukp.lmf.model.enums.ERelNameSemantics;
import de.tudarmstadt.ukp.lmf.model.enums.ERelTypeSemantics;
import de.tudarmstadt.ukp.lmf.model.semantics.MonolingualExternalRef;
import de.tudarmstadt.ukp.lmf.model.semantics.SynsetRelation;
import de.tuebingen.uni.sfs.germanet.api.ConRel;
import de.tuebingen.uni.sfs.germanet.api.GermaNet;
import de.tuebingen.uni.sfs.germanet.api.LexUnit;
import de.tuebingen.uni.sfs.germanet.api.Synset;
/**
* Instance of this class offers methods for creating {@link Synset} instances out of GermaNet's data
* @author Zijad Maksuti
* @author Judith Eckle-Kohler
*
*/
public class SynsetGenerator {
public static final String SYNSET = "synset";
private final GermaNet gnet; // GermaNet Object
private int lmfSynsetNumber = 0; // running number used for creating IDs of LMFSynsets
private int senseNumber = 0; // running number used for creating IDs of Senses
private final Map<Synset, Sense> gnSynsetSenseMappings = new HashMap<Synset, Sense>(); // The mappings between Synset provided by GN and Senses
private final Map<LexUnit, de.tudarmstadt.ukp.lmf.model.semantics.Synset> LexUnitSynsetMappings = new HashMap<LexUnit, de.tudarmstadt.ukp.lmf.model.semantics.Synset>();
private final Map<LexUnit, Sense> luSenseMappings = new HashMap<LexUnit, Sense>();
private final String resourceVersion;
// Mappings between LMF-Synsets and Senses
private static Map<de.tudarmstadt.ukp.lmf.model.semantics.Synset, List<Sense>>
synsetSenseMappings = new HashMap<de.tudarmstadt.ukp.lmf.model.semantics.Synset, List<Sense>>();
// Mappings between LMF-Synsets and GN-Synsets
private static Map<de.tudarmstadt.ukp.lmf.model.semantics.Synset, Synset>
lmfSynsetGNSynsetMappings = new HashMap<de.tudarmstadt.ukp.lmf.model.semantics.Synset, Synset>();
// Mappings between GN-Synsets and LMF-Synsets
private static Map<Synset, de.tudarmstadt.ukp.lmf.model.semantics.Synset>
gnSynsetLMFSynsetMappings = new HashMap<Synset, de.tudarmstadt.ukp.lmf.model.semantics.Synset>();
//private static final String has_component_holonym ="has_component_holonym";
//private static final String has_component_meronym = "has_component_meronym";
//private static final String has_member_holonym = "has_member_holonym";
//private static final String has_member_meronym = "has_member_meronym";
//private static final String causes = "causes";
//private static final String has_portion_holonym = "has_portion_holonym";
//private static final String has_portion_meronym = "has_portion_meronym";
//private static final String has_substance_holonym = "has_substance_holonym";
//private static final String has_substance_meronym = "has_substance_meronym";
//private static final String has_hypernym = "has_hypernym";
//private static final String is_entailed_by = "is_entailed_by";
//private static final String is_related_to = "is_related_to";
//private static final String has_hyponym = "has_hyponym";
//private static final String entails = "entails";
/**
* Constructs a {@link SynsetGenerator} associated with the consumed {@link GermaNet} instance
* @param gnet instance of GermaNet used for obtaining information from GermaNet's files
* @param resourceVersion Version of the resource
*/
public SynsetGenerator(GermaNet gnet, String resourceVersion){
this.gnet = gnet;
this.resourceVersion = resourceVersion;
}
/**
* This method initializes the {@link SynsetGenerator}
*/
public void initialize(){
if(LexUnitSynsetMappings.isEmpty()){
// List of all GermaNet Synsets
List<Synset> gnSynsets = gnet.getSynsets();
for(Synset gnSynset : gnSynsets){
// Create a LMF-Synset for each gn-Synset
de.tudarmstadt.ukp.lmf.model.semantics.Synset lmfSynset = new de.tudarmstadt.ukp.lmf.model.semantics.Synset();
lmfSynset.setId(getNewID());
// *** Generating Monolingual ExternalRef**//
MonolingualExternalRef mer = new MonolingualExternalRef();
mer.setExternalReference(Integer.toString(gnSynset.getId()));
mer.setExternalSystem(resourceVersion + "_" + SYNSET);
LinkedList<MonolingualExternalRef> mers = new LinkedList<MonolingualExternalRef>();
mers.add(mer);
lmfSynset.setMonolingualExternalRefs(mers);
lmfSynsetGNSynsetMappings.put(lmfSynset, gnSynset);
gnSynsetLMFSynsetMappings.put(gnSynset, lmfSynset);
// Setting Definitions
String writtenText = gnSynset.getParaphrase();
if (writtenText != null && !writtenText.equals("") && !writtenText.equals(" ")) {
// Definition for a Synset can be created only if the Synset has a paraphrase (gloss)
List<Definition> definitions = new LinkedList<Definition>();
Definition definition = new Definition();
List<TextRepresentation> textRepresentations = new LinkedList<TextRepresentation>();
TextRepresentation textRepresentation = new TextRepresentation();
textRepresentation.setLanguageIdentifier(ELanguageIdentifier.GERMAN);
textRepresentation.setWrittenText(writtenText);
textRepresentations.add(textRepresentation);
definition.setTextRepresentations(textRepresentations);
definitions.add(definition);
lmfSynset.setDefinitions(definitions);
}
for(LexUnit lu : gnSynset.getLexUnits()){
// Generating a Sense for each LU
Sense sense = new Sense();
sense.setId(getNewSenseID());
LexUnitSynsetMappings.put(lu, lmfSynset);
luSenseMappings.put(lu, sense);
gnSynsetSenseMappings.put(gnSynset, sense);
// Adding LMF-Synset_Sense Mappings
if(!synsetSenseMappings.containsKey(lmfSynset)){
LinkedList<Sense> temp = new LinkedList<Sense>();
synsetSenseMappings.put(lmfSynset, temp);
}
synsetSenseMappings.get(lmfSynset).add(sense);
}
}
finalizeGeneration();
}
}
/**
* This method consumes an instance of {@link LexUnit} and returns it's corresponing instance of
* {@link de.tudarmstadt.ukp.lmf.model.semantics.Synset}. <br>
* This method should be evoked after the initialization
* of this SynsetGenerator!
* @param lu LexUnit for which generated synset should be returned
* @return synset that corresponds to the consumed lu
*/
public de.tudarmstadt.ukp.lmf.model.semantics.Synset getLMFSynset(LexUnit lu){
return LexUnitSynsetMappings.get(lu);
}
/**
* This method generates a Synset-ID
* @see de.tudarmstadt.ukp.lmf.model.semantics.Synset
*/
private String getNewID(){
StringBuffer sb = new StringBuffer(64);
sb.append("GN_Synset_").append(Integer.toString(lmfSynsetNumber));
lmfSynsetNumber++;
return sb.toString();
}
/**
* This method generates a Sense-ID
* @see de.tudarmstadt.ukp.lmf.model.semantics.Sense
*/
private String getNewSenseID(){
StringBuffer sb = new StringBuffer(64);
sb.append("GN_Sense_").append(Integer.toString(senseNumber));
senseNumber++;
return sb.toString();
}
/**
* This method returns a Sense for the consumed {@link LexUnit}
* @param lu LexicalUnit for which the corresponding instance of {@link Sense} class should be returned
* @return the lu's corresponding sense
*/
public Sense getSense(LexUnit lu){
return luSenseMappings.get(lu);
}
/**
* This method returns an instance of {@link Sense} class associated with the consumed instance of
* {@link Synset} class
* @param gnSynset synset for which associated sense should be returned
* @return sense associated with the consumed gnSynset
*/
public Sense getSense(Synset gnSynset){
return gnSynsetSenseMappings.get(gnSynset);
}
/**
* This method returns a sorted list of all {@link de.tudarmstadt.ukp.lmf.model.semantics.Synset} instances generated by this generator.
* @return a sorted {@link List} of all synsets generated by this generator
*/
public List<de.tudarmstadt.ukp.lmf.model.semantics.Synset> getSynsets(){
List<de.tudarmstadt.ukp.lmf.model.semantics.Synset> result = new LinkedList<de.tudarmstadt.ukp.lmf.model.semantics.Synset>();
result.addAll(lmfSynsetGNSynsetMappings.keySet());
Collections.sort(result);
return result;
}
/**
* This method consumes an instance of {@link Synset} and generates and returns a {@link List} of synset relations that correspond to
* consumed conceptual relation.
* @param gnSynset synset for which corresponding list of synset relations should be generated
* @param conRelation conceptual relation equal to the type of the returned synset relations
* @return a list of synset relations based on the consumed arguments
* @see SynsetRelation
* @see ConRel
*/
private List<SynsetRelation> generateSynsetRelations(Synset gnSynset, ConRel conRelation){
List<SynsetRelation> synsetRelations = new LinkedList<SynsetRelation>();
// Generating Relation
List<Synset> targets = gnSynset.getRelatedSynsets(conRelation);
if(!targets.isEmpty()){
// If Synset has a conRelation to other Synsets, a SynsetRelation should be generated
ERelTypeSemantics relType = getRelType(conRelation);
String relName = getRelName(conRelation);
for(Synset target : targets){
// Generate a SynsetRelation
SynsetRelation synsetRelation = new SynsetRelation();
synsetRelation.setTarget(gnSynsetLMFSynsetMappings.get(target));
synsetRelation.setRelType(relType);
synsetRelation.setRelName(relName);
synsetRelations.add(synsetRelation);
}
}
return synsetRelations;
}
/**
* This method consumes a conceptual relation and returns the
* corresponding Uby-LMF relation type
* @param conRel for which Uby-LMF relation type should be returned
* @return conRel relation type in Uby-LMF or null if no entry for conRel exists
* @see ConRel
* @see ERelTypeSemantics
*/
private ERelTypeSemantics getRelType(ConRel conRel){
ERelTypeSemantics relType;
switch (conRel){
case causes : relType = ERelTypeSemantics.taxonomic; break;
case entails : relType = ERelTypeSemantics.taxonomic; break;
case has_component_holonym : relType = ERelTypeSemantics.partWhole; break;
case has_component_meronym : relType = ERelTypeSemantics.partWhole; break;
case has_hypernym : relType = ERelTypeSemantics.taxonomic ; break;
case has_hyponym : relType = ERelTypeSemantics.taxonomic; break;
case has_member_holonym : relType = ERelTypeSemantics.partWhole; break;
case has_member_meronym : relType = ERelTypeSemantics.partWhole; break;
case has_portion_holonym : relType = ERelTypeSemantics.partWhole; break;
case has_portion_meronym : relType = ERelTypeSemantics.partWhole; break;
case has_substance_holonym : relType = ERelTypeSemantics.partWhole; break;
case has_substance_meronym : relType = ERelTypeSemantics.partWhole; break;
case is_entailed_by : relType = ERelTypeSemantics.taxonomic; break;
case is_related_to : relType = ERelTypeSemantics.association; break;
default : relType = null;
}
return relType;
}
/**
* This method consumes a conceptual relation and returns the
* corresponding Uby-LMF relation name
* @param conRel for which Uby-LMF relation name should be returned
* @return conRel's relation name in Uby-LMF or null if no entry for conRel exists
* @see ConRel
* @see ERelTypeSemantics
*/
private String getRelName(ConRel conRel){
String relName;
switch (conRel){
case causes : relName = ERelNameSemantics.CAUSES; break;
case entails : relName = ERelNameSemantics.ENTAILS; break;
case has_component_holonym : relName = ERelNameSemantics.HOLONYMCOMPONENT; break;
case has_component_meronym : relName = ERelNameSemantics.MERONYMCOMPONENT; break;
case has_hypernym : relName = ERelNameSemantics.HYPERNYM; break;
case has_hyponym : relName = ERelNameSemantics.HYPONYM; break;
case has_member_holonym : relName = ERelNameSemantics.HOLONYMMEMBER; break;
case has_member_meronym : relName = ERelNameSemantics.MERONYMMEMBER; break;
case has_portion_holonym : relName = ERelNameSemantics.HOLONYMPORTION; break;
case has_portion_meronym : relName = ERelNameSemantics.MERONYMPORTION; break;
case has_substance_holonym : relName = ERelNameSemantics.HOLONYMSUBSTANCE; break;
case has_substance_meronym : relName = ERelNameSemantics.MERONYMSUBSTANCE; break;
case is_entailed_by : relName = ERelNameSemantics.ENTAILEDBY; break;
case is_related_to : relName = ERelNameSemantics.RELATED; break;
default : relName = null;
}
return relName;
}
/**
* This method consumes an instance of {@link Synset} and appends all synset relations to
* it's corresponding instance of {@link de.tudarmstadt.ukp.lmf.model.semantics.Synset}
* @param synset GermaNet's synset on which associated Uby-LMF synset, should be appended
* @see SynsetRelation
*/
private void setSynsetRelations(Synset gnSynset){
List<SynsetRelation> synsetRelations = new LinkedList<SynsetRelation>();
for(ConRel conRel : ConRel.values()){
synsetRelations.addAll(generateSynsetRelations(gnSynset,conRel));
}
de.tudarmstadt.ukp.lmf.model.semantics.Synset lmfSynset = gnSynsetLMFSynsetMappings.get(gnSynset);
if(!synsetRelations.isEmpty()) {
lmfSynset.setSynsetRelations(synsetRelations);
}
}
/**
* This method finalizes the generation of the {@link de.tudarmstadt.ukp.lmf.model.semantics.Synset} instances <br>
* produced by this generator, by appending synset relations to them. <br>
* It should be evoked after all {@link Sense} instances are initialized.
* @see SynsetRelation
*/
private void finalizeGeneration(){
// append all SynsetRelations
for(Synset gnSynset : gnSynsetLMFSynsetMappings.keySet()){
this.setSynsetRelations(gnSynset);
}
}
}