/**
* 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.framenet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.saar.coli.salsa.reiter.framenet.Frame;
import de.saar.coli.salsa.reiter.framenet.FrameElement;
import de.saar.coli.salsa.reiter.framenet.FrameElementNotFoundException;
import de.saar.coli.salsa.reiter.framenet.FrameNet;
import de.saar.coli.salsa.reiter.framenet.FrameNetRelationDirection;
import de.saar.coli.salsa.reiter.framenet.FrameNotFoundException;
import de.saar.coli.salsa.reiter.framenet.ParsingException;
import de.saar.coli.salsa.reiter.framenet.SemanticType;
import de.saar.coli.salsa.reiter.framenet.SemanticTypeNotFoundException;
import de.tudarmstadt.ukp.lmf.model.core.Definition;
import de.tudarmstadt.ukp.lmf.model.core.TextRepresentation;
import de.tudarmstadt.ukp.lmf.model.enums.ECoreType;
import de.tudarmstadt.ukp.lmf.model.enums.ELabelTypeSemantics;
import de.tudarmstadt.ukp.lmf.model.enums.ELanguageIdentifier;
import de.tudarmstadt.ukp.lmf.model.enums.ERelTypeSemantics;
import de.tudarmstadt.ukp.lmf.model.meta.SemanticLabel;
import de.tudarmstadt.ukp.lmf.model.semantics.ArgumentRelation;
import de.tudarmstadt.ukp.lmf.model.semantics.MonolingualExternalRef;
import de.tudarmstadt.ukp.lmf.model.semantics.PredicateRelation;
import de.tudarmstadt.ukp.lmf.model.semantics.SemanticArgument;
import de.tudarmstadt.ukp.lmf.model.semantics.SemanticPredicate;
/**
* Methods for generating {@link SemanticPredicate SemanticPredicates} out of {@link Frame Frames}.
*
* @author Zijad Maksuti
* @author Silvana Hartmann
*/
public class SemanticPredicateGenerator {
private final FrameNet fn;
public static final String SEMANTIC_TYPE = "semanticType";
//Mappings between SemanticPredicates and corresponding Frames
private final Map<Frame, SemanticPredicate> frameSemanticPredicateMappings = new LinkedHashMap<Frame, SemanticPredicate>();
private int semanticPredicateNumber = 0; // Used for creating IDs
private int semanticArgumentNumber = 0; // Used for creating IDs
// Mappings between FrameElement-names and SemanticArguments in order to prevent duplication of SemanticArgumens
private final Map<String, SemanticArgument> feSemArgMapping = new TreeMap<String, SemanticArgument>();
// list of incorporated SemanticSArguments
// private List<SemanticArgument> incorporatedSemArgs = new ArrayList<SemanticArgument>();
// all frame relations in FrameNet, used for creating PredicateRelations
private Set<String> frameRelations;
private final Log logger = LogFactory.getLog(getClass());
private final String resourceVersion;
/**
* Constructs an instance of {@link SemanticPredicateGenerator} used for generating
* SemanticPredicates out of {@link Frame Frames}
*
* @param fn
* initialized {@link FrameNet} object used for accessing Frames
* @param resourceVersion
* Version of the resource
* @see SemanticPredicate
*/
public SemanticPredicateGenerator(FrameNet fn, String resourceVersion){
this.fn = fn;
this.resourceVersion = resourceVersion;
this.init();
}
/**
* Initializes {@link SemanticPredicateGenerator}
*/
private void init(){
for(Frame frame : fn.getFrames()) {
frameSemanticPredicateMappings.put(frame, createSemanticPredicate(frame));
}
updateArgumentRelations();
initializeFrameRelations();
updatePredicateRelations();
}
/**
* Consumes a {@link Frame} and generates a {@link SemanticPredicate} that corresponds to the
* consumed Frame
*
* @param frame
* Frame for which a SemanticPredicate should be generated
* @return SemanticPredicate that corresponds to the consumed frame
*/
private SemanticPredicate createSemanticPredicate(Frame frame) {
SemanticPredicate semanticPredicate = new SemanticPredicate();
semanticPredicate.setLabel(frame.getName());
// Creating Definition
List<Definition> definitions = new LinkedList<Definition>();
Definition definition = new Definition();
List<TextRepresentation> textRepresentations = new LinkedList<TextRepresentation>();
TextRepresentation textRepresentation = new TextRepresentation();
textRepresentation.setLanguageIdentifier(ELanguageIdentifier.ENGLISH);
textRepresentation.setWrittenText(FNUtils.filterTags(frame.getDefinition()));
textRepresentations.add(textRepresentation);
definition.setTextRepresentations(textRepresentations);
definitions.add(definition);
semanticPredicate.setDefinitions(definitions);
//setting id
StringBuffer sb = new StringBuffer(32);
sb.append("FN_SemanticPredicate_").append(semanticPredicateNumber++);
semanticPredicate.setId(sb.toString());
List<SemanticLabel> semanticLabels = new LinkedList<SemanticLabel>();
for(String semTypeID : frame.getSemTypeIDs()){
if(semTypeID.equals("16")) {
semanticPredicate.setLexicalized(false);
}
else{
semanticPredicate.setLexicalized(true);
if(semTypeID.equals("52")) {
semanticPredicate.setPerspectivalized(false);
}
else{
semanticPredicate.setPerspectivalized(true);
// semTypeIDs 68 and 182 need to be processed manually because of a bug in FN-API
SemanticType semanticType = null;
if(semTypeID.equals("68")) {
try {
semanticType = fn.getSemanticType("Physical_object");
} catch (SemanticTypeNotFoundException e) {
e.printStackTrace();
}
}
else if(semTypeID.equals("182")) {
try {
semanticType = fn.getSemanticType("Locative_relation");
} catch (SemanticTypeNotFoundException e) {
e.printStackTrace();
}
}
else {
try {
semanticType = fn.getSemanticType(semTypeID);
} catch (SemanticTypeNotFoundException e) {
e.printStackTrace();
}
}
// Checking if the root of this semanticType != "Lexical_type"
SemanticType rootSemanticType = null;
for(SemanticType temp : semanticType.getSuperTypes()){
rootSemanticType = temp;
}
// if the root is still == null, semanticType has no parents
if(rootSemanticType == null) {
rootSemanticType = semanticType;
}
// if the root of semanticType != "Lexical_type", then we have an ontological type
if(!rootSemanticType.getName().equals("Lexical_type")){
// Creating SemanticLabels for FN-"Ontological types"
SemanticLabel semanticLabel = new SemanticLabel();
semanticLabel.setLabel(semanticType.getName());
semanticLabel.setType(ELabelTypeSemantics.semanticCategory);
// creating MonolingualExternalRef
List<MonolingualExternalRef> monolingualExternalRefs = new LinkedList<MonolingualExternalRef>();
MonolingualExternalRef monolingualExternalRef = new MonolingualExternalRef();
monolingualExternalRef.setExternalReference(semTypeID);
monolingualExternalRef.setExternalSystem(resourceVersion + "_" + SEMANTIC_TYPE);
monolingualExternalRefs.add(monolingualExternalRef);
semanticLabel.setMonolingualExternalRefs(monolingualExternalRefs);
semanticLabels.add(semanticLabel);
}
}
}
}
semanticPredicate.setSemanticLabels(semanticLabels);
// generate semanticArguments
semanticPredicate.setSemanticArguments(generateSemanticArguments(frame));
return semanticPredicate;
}
/**
* This method consumes a {@link Frame} and returns a list of {@link SemanticArgument
* SemanticArguments} associated to the consumed Frame's FrameElements
*
* @param frame
* a Frame for which associated SemanticArguments should be generated
* @return a list of SemanticArguments associated with the consumed frame's {@link FrameElement
* FrameElements}
*/
private List<SemanticArgument> generateSemanticArguments(Frame frame) {
List<SemanticArgument> semanticArguments = new LinkedList<SemanticArgument>();
// Creating SemanticArgument
for (FrameElement fe : frame.frameElements()) {
// feName = frameName.feName
String feName = frame.getName().concat(".").concat(fe.getName());
SemanticArgument semanticArgument = new SemanticArgument();
// Setting id
StringBuffer semArgID = new StringBuffer(32);
semArgID.append("FN_SemanticArgument_").append(semanticArgumentNumber++);
semanticArgument.setId(semArgID.toString());
// Setting semanticRole
semanticArgument.setSemanticRole(fe.getName());
// Setting definition
List<Definition> definitions = new ArrayList<Definition>();
Definition definition = new Definition();
List<TextRepresentation> textRepresentations = new ArrayList<TextRepresentation>();
TextRepresentation textRepresentation = new TextRepresentation();
textRepresentation.setLanguageIdentifier(ELanguageIdentifier.ENGLISH);
textRepresentation.setWrittenText(FNUtils.filterTags(fe.getDefinition()));
textRepresentations.add(textRepresentation);
definition.setTextRepresentations(textRepresentations);
definitions.add(definition);
semanticArgument.setDefinitions(definitions);
// setting coreType
ECoreType coreType = FNUtils.getCoreType(fe.getCoreType());
if(coreType == null){
StringBuffer sb = new StringBuffer(256);
sb.append("SemanticPredicate generator could not find ECoreType for FrameElement: ");
sb.append(fe);
sb.append('\n');
sb.append("Aborting all operations!");
logger.error(sb.toString());
System.exit(1);
}
semanticArgument.setCoreType(coreType);
// not incorporated
semanticArgument.setIncorporated(false);
List<SemanticLabel> semanticLabels = new LinkedList<SemanticLabel>();
for (SemanticType semanticType : fe.getSemanticTypes()) {
// Checking if the root of this semanticType != "Lexical_type"
SemanticType rootSemanticType = null;
for (SemanticType temp : semanticType.getSuperTypes()) {
rootSemanticType = temp;
}
// if the root is still == null, semanticType has no parents
if (rootSemanticType == null) {
rootSemanticType = semanticType;
}
// if the root of semanticType != "Lexical_type", then we have
// an ontological type
if (!rootSemanticType.getName().equals("Lexical_type")) {
// Creating SemanticLabels for FN-"Ontological types"
SemanticLabel semanticLabel = new SemanticLabel();
semanticLabel.setLabel(semanticType.getName());
semanticLabel.setType(ELabelTypeSemantics.selectionalPreference);
// creating MonolingualExternalRef. Avoid having NULL and random ids.
String semanticTypeId = semanticType.getId();
if (semanticTypeId != null && semanticTypeId.indexOf(".") < 0) {
List<MonolingualExternalRef> monolingualExternalRefs = new LinkedList<MonolingualExternalRef>();
MonolingualExternalRef monolingualExternalRef = new MonolingualExternalRef();
monolingualExternalRef.setExternalReference(semanticTypeId);
monolingualExternalRef.setExternalSystem("FrameNet 1.5 semantic type ID");
monolingualExternalRefs.add(monolingualExternalRef);
semanticLabel.setMonolingualExternalRefs(monolingualExternalRefs);
}
semanticLabels.add(semanticLabel);
}
}
semanticArgument.setSemanticLabels(semanticLabels);
semanticArguments.add(semanticArgument);
// record the Mapping
feSemArgMapping.put(feName, semanticArgument);
}
return semanticArguments;
}
/**
* This method adds {@link ArgumentRelation ArgumentRelations} to all previously generated
* {@link SemanticArgument SemanticArguments}.
*/
private void updateArgumentRelations(){
for(String feName :feSemArgMapping.keySet()){
FrameElement fe=null;
try {
fe = fn.getFrameElement(feName);
} catch (ParsingException e1) {
e1.printStackTrace();
} catch (FrameElementNotFoundException e1) {
e1.printStackTrace();
} catch (FrameNotFoundException e1) {
e1.printStackTrace();
}
SemanticArgument semArg = feSemArgMapping.get(feName);
List<ArgumentRelation> relationsFrom = semArg.getArgumentRelations();
if(relationsFrom == null) {
relationsFrom = new LinkedList<ArgumentRelation>();
}
// setting relations FROM semArg
semArg.setArgumentRelations(relationsFrom);
//###### MAPPING REQUIRED AND EXCLUDED RELATION
Set<String> excludedFENames = fe.getExcludedFEs();
for(String excludedFEName : excludedFENames){
try {
FrameElement excludedFE = fn.getFrameElement(excludedFEName);
SemanticArgument excluded = feSemArgMapping.get(excludedFE.getFrame().getName().concat(".").concat(excludedFE.getName()));
// Creating ArgumentRelation from semArg
ArgumentRelation argumentRelation = new ArgumentRelation();
argumentRelation.setTarget(excluded);
argumentRelation.setRelType("fn_same_frame");
argumentRelation.setRelName("excludes");
relationsFrom.add(argumentRelation);
// Creating ArgumentRelation in opposite direction
ArgumentRelation opposite = new ArgumentRelation();
opposite.setTarget(semArg);
opposite.setRelType(ERelTypeSemantics.sameFrame.toString());
opposite.setRelName("excludes");
List<ArgumentRelation> fromExcluded = excluded.getArgumentRelations();
if(fromExcluded == null) {
fromExcluded = new LinkedList<ArgumentRelation>();
}
fromExcluded.add(opposite);
} catch (ParsingException e) {
e.printStackTrace();
} catch (FrameElementNotFoundException e) {
e.printStackTrace();
} catch (FrameNotFoundException e) {
e.printStackTrace();
}
}
//###### MAPPING REQUIRED RELATION
Set<String> requiredFENames = fe.getRequiredFEs();
for(String requiredFEName : requiredFENames){
FrameElement requiredFE = null;
try {
requiredFE = fn.getFrameElement(requiredFEName);
} catch (ParsingException e) {
e.printStackTrace();
} catch (FrameElementNotFoundException e) {
e.printStackTrace();
} catch (FrameNotFoundException e) {
e.printStackTrace();
}
SemanticArgument required = feSemArgMapping.get(requiredFE.getFrame().getName().concat(".").concat(requiredFE.getName()));
// Creating ArgumentRelation from semArg
ArgumentRelation argumentRelation = new ArgumentRelation();
argumentRelation.setTarget(required);
argumentRelation.setRelType(ERelTypeSemantics.sameFrame.toString());
argumentRelation.setRelName("requires");
relationsFrom.add(argumentRelation);
}
}
//###### MAPPING CORE_SET RELATION
// it is easier to do this by iterating over frames :)
for(Frame frame : fn.getFrames()){
Map<Integer, FrameElement[]> coreSets = frame.getFeCoreSets();
for(int setNumber : coreSets.keySet()){
String label = "core_set_".concat(Integer.toString(setNumber));
FrameElement[] coreSet = coreSets.get(setNumber);
for(FrameElement frameElement : coreSet){
SemanticArgument source = feSemArgMapping.get(frameElement.getFrame().getName()+"."+frameElement.getName());
if(source == null){
semanticArgumentNotFound(frameElement);
}
List<ArgumentRelation> argumentRelations = source.getArgumentRelations();
if(argumentRelations == null) {
argumentRelations = new ArrayList<ArgumentRelation>();
}
for(FrameElement target : coreSet){
if(frameElement.equals(target)) {
continue;
}
ArgumentRelation argumentRelation = new ArgumentRelation();
SemanticArgument targetSemanticArgument = feSemArgMapping.get(target.getFrame().getName()+"."+target.getName());
if(targetSemanticArgument == null){
semanticArgumentNotFound(target);
}
argumentRelation.setTarget(targetSemanticArgument);
argumentRelation.setRelType(ERelTypeSemantics.coreSet.toString());
argumentRelation.setRelName(label);
argumentRelations.add(argumentRelation);
}
source.setArgumentRelations(argumentRelations);
}
}
}
}
/**
* This method adds {@link PredicateRelation PredicateRelations} to all previously generated
* {@link PredicateRelation SemanticPredicates}.
*/
private void updatePredicateRelations(){
for(Frame frame : fn.getFrames()){
SemanticPredicate semanticPredicate = frameSemanticPredicateMappings.get(frame);
List<PredicateRelation> relations = semanticPredicate.getPredicateRelations();
if(relations == null) {
relations = new ArrayList<PredicateRelation>();
}
for(String relationName : frameRelations){
relations.addAll(getPredicateRelations(frame, relationName));
}
semanticPredicate.setPredicateRelations(relations);
}
}
/**
* Returns all SemanticPredicates generated by this instance of
* {@link SemanticPredicateGenerator}
*
* @return {@link SemanticPredicate SemanticPredicates} generated by this
* SemanticPredicateGenerator
*/
public Collection<SemanticPredicate> getSemanticPredicates() {
return frameSemanticPredicateMappings.values();
}
/**
* Returns {@link SemanticPredicate}, generated by this {@link SemanticPredicateGenerator},
* associated with the consumed {@link Frame}
*
* @param frame
* a Frame for which generated SemanticPredicate should be returned
* @return SemanticPredicate associated with the consumed frame
*/
public SemanticPredicate getSemanticPredicate(Frame frame){
return frameSemanticPredicateMappings.get(frame);
}
/**
* Returns {@link SemanticArgument}, generated by this {@link SemanticPredicateGenerator},
* associated with the consumed {@link FrameElement}
*
* @param frameElement
* a FrameElement for which generated SemanticArgument should be returned
* @return SemanticArgument associated with the consumed frameElement
*/
public SemanticArgument getSemanticArgument(FrameElement frameElement){
return feSemArgMapping.get(frameElement.getFrame().getName()+"."+frameElement.getName());
}
/**
* This method initializes the names of frame-relations, as described in FrameNet's files
*/
private void initializeFrameRelations(){
frameRelations = new LinkedHashSet<String>();
frameRelations.add("Inheritance");
frameRelations.add("Subframe");
frameRelations.add("Using");
frameRelations.add("See_also");
frameRelations.add("ReFraming_Mapping");
frameRelations.add("Inchoative_of");
frameRelations.add("Causative_of");
frameRelations.add("Precedes");
frameRelations.add("Perspective_on");
}
/**
* This method returns a list of {@link PredicateRelation PredicateRelations} for the given
* {@link Frame} and the name of the frame relation.
*
* @param frame
* the Frame from which PredicateRelations should be generated
* @param relationName
* the name of the relation that should be taken into account when generating
* PredicateRelations
* @return list of PredicateRelations generated from consumed frame and relationName
*/
private List<PredicateRelation> getPredicateRelations(Frame frame, String relationName){
List<PredicateRelation> result = new ArrayList<PredicateRelation>();
/*
* Used for determining the relevantSemanticPredicate by "precedes"
* relation
*/
Collection<Frame> subframeOf = frame.subframeOf();
Frame superFrame = null;
for(Frame fr : subframeOf) {
if(superFrame == null) {
superFrame = fr;
}
}
Collection<Frame> parents = frame.relatedFrames(relationName, FrameNetRelationDirection.UP);
String relType = ERelTypeSemantics.frameRelation.toString();
String relNameUp = null;
if(parents != null && !parents.isEmpty()){
relNameUp = FNUtils.getRelName(relationName, FrameNetRelationDirection.UP);
for(Frame parent : parents ){
PredicateRelation predicateRelation = new PredicateRelation();
predicateRelation.setRelType(relType);
predicateRelation.setRelName(relNameUp);
SemanticPredicate target = frameSemanticPredicateMappings.get(parent);
// relevantSemanticPredicate for "precedes"
if((relNameUp.equals("is_preceded_by") || relNameUp.equals("precedes")) && !subframeOf.isEmpty()){
predicateRelation.setRelevantSemanticPredicate(frameSemanticPredicateMappings.get(superFrame));
}
predicateRelation.setTarget(target);
result.add(predicateRelation);
}
}
Collection<Frame> children = frame.relatedFrames(relationName, FrameNetRelationDirection.DOWN);
String relNameDown = null;
if(children != null && !children.isEmpty()){
relNameDown = FNUtils.getRelName(relationName, FrameNetRelationDirection.DOWN);
for(Frame child : children){
PredicateRelation predicateRelation = new PredicateRelation();
predicateRelation.setRelType(relType);
predicateRelation.setRelName(relNameDown);
SemanticPredicate target = frameSemanticPredicateMappings.get(child);
if(target == null){
StringBuffer sb = new StringBuffer(128);
sb.append("SemanticPredicateGenerator could not find SemanticPredicate for Frame: ");
sb.append(child);
sb.append('\n');
sb.append("Aborting all operations!");
logger.error(sb.toString());
System.exit(1);
}
// relevantSemanticPredicate for "precedes"
if((relNameDown.equals("is_preceded_by") || relNameDown.equals("precedes")) && !subframeOf.isEmpty()){
predicateRelation.setRelevantSemanticPredicate(frameSemanticPredicateMappings.get(superFrame));
}
predicateRelation.setTarget(frameSemanticPredicateMappings.get(child));
result.add(predicateRelation);
}
}
Collections.sort(result, new Comparator<PredicateRelation>() {
@Override
public int compare(PredicateRelation arg0, PredicateRelation arg1) {
return arg0.getTarget().getId().compareTo(arg1.getTarget().getId());
}
});
return result;
}
/**
* This method consumes the name of the incorporated frame element and creates the corresponding
* SemanticArgument
*
* @return corresponding SemanticArgument
*/
SemanticArgument createIncorporatedSemanticArgument(String incorporatedFEName) {
SemanticArgument semanticArgument = new SemanticArgument();
// Setting id
StringBuffer semArgID = new StringBuffer(32);
semArgID.append("FN_SemanticArgument_").append(semanticArgumentNumber++);
semanticArgument.setId(semArgID.toString());
semanticArgument.setSemanticRole(incorporatedFEName);
semanticArgument.setIncorporated(true);
// incorporatedSemArgs.add(semanticArgument);
return semanticArgument;
}
/**
* This method is called when a {@link SemanticArgument}, that corresponds to the consumed
* {@link FrameElement} could not be found. <br>
* It terminates the execution of {@link SemanticPredicateGenerator}
*
* @param fe
* FrameElement for which a SemanticArgument could not be found
*/
private void semanticArgumentNotFound(FrameElement fe){
StringBuffer sb = new StringBuffer(256);
sb.append("SemanticPredicateGenerator could not find SemanticArgument for FrameElement: ");
sb.append(fe).append('\n');
sb.append("Aborting all operations!");
logger.error(sb.toString());
System.exit(1);
}
}