simplenlg.phrasespec.SPhraseSpec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SimpleNLG Show documentation
Show all versions of SimpleNLG Show documentation
Java API for Natural Language Generation
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is "Simplenlg".
*
* The Initial Developer of the Original Code is Ehud Reiter, Albert Gatt and Dave Westwater.
* Portions created by Ehud Reiter, Albert Gatt and Dave Westwater are Copyright (C) 2010-11 The University of Aberdeen. All Rights Reserved.
*
* Contributor(s): Ehud Reiter, Albert Gatt, Dave Wewstwater, Roman Kutlak, Margaret Mitchell.
*/
package simplenlg.phrasespec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import simplenlg.features.ClauseStatus;
import simplenlg.features.Feature;
import simplenlg.features.InternalFeature;
import simplenlg.features.LexicalFeature;
import simplenlg.framework.CoordinatedPhraseElement;
import simplenlg.framework.InflectedWordElement;
import simplenlg.framework.LexicalCategory;
import simplenlg.framework.NLGElement;
import simplenlg.framework.NLGFactory;
import simplenlg.framework.PhraseCategory;
import simplenlg.framework.PhraseElement;
import simplenlg.framework.WordElement;
/**
*
* This class defines a clause (sentence-like phrase). It is essentially a
* wrapper around the PhraseElement
class, with methods for setting
* common constituents such as Subject. For example, the setVerb
* method in this class sets the head of the element to be the specified verb
*
* From an API perspective, this class is a simplified version of the
* SPhraseSpec class in simplenlg V3. It provides an alternative way for
* creating syntactic structures, compared to directly manipulating a V4
* PhraseElement
.
*
* Methods are provided for setting and getting the following constituents:
*
* - FrontModifier (eg, "Yesterday")
*
- Subject (eg, "John")
*
- PreModifier (eg, "reluctantly")
*
- Verb (eg, "gave")
*
- IndirectObject (eg, "Mary")
*
- Object (eg, "an apple")
*
- PostModifier (eg, "before school")
*
* Note that verb, indirect object, and object are propagated to the underlying
* verb phrase
*
* NOTE: The setModifier method will attempt to automatically determine whether
* a modifier should be expressed as a FrontModifier, PreModifier, or
* PostModifier
*
* Features (such as negated) must be accessed via the setFeature
* and getFeature
methods (inherited from NLGElement
).
* Features which are often set on SPhraseSpec include
*
* - Form (eg, "John eats an apple" vs "John eating an apple")
*
- InterrogativeType (eg, "John eats an apple" vs "Is John eating an apple"
* vs "What is John eating")
*
- Modal (eg, "John eats an apple" vs "John can eat an apple")
*
- Negated (eg, "John eats an apple" vs "John does not eat an apple")
*
- Passive (eg, "John eats an apple" vs "An apple is eaten by John")
*
- Perfect (eg, "John ate an apple" vs "John has eaten an apple")
*
- Progressive (eg, "John eats an apple" vs "John is eating an apple")
*
- Tense (eg, "John ate" vs "John eats" vs "John will eat")
*
* Note that most features are propagated to the underlying verb phrase
* Premodifers are also propogated to the underlying VP
*
* SPhraseSpec
are produced by the createClause
method
* of a PhraseFactory
*
*
* @author E. Reiter, University of Aberdeen.
* @version 4.1
*
*/
public class SPhraseSpec extends PhraseElement {
// the following features are copied to the VPPhraseSpec
static final List vpFeatures = Arrays.asList(Feature.MODAL,
Feature.TENSE, Feature.NEGATED, Feature.NUMBER, Feature.PASSIVE,
Feature.PERFECT, Feature.PARTICLE, Feature.PERSON,
Feature.PROGRESSIVE, InternalFeature.REALISE_AUXILIARY,
Feature.FORM, Feature.INTERROGATIVE_TYPE);
/**
* create an empty clause
*/
public SPhraseSpec(NLGFactory phraseFactory) {
super(PhraseCategory.CLAUSE);
this.setFactory(phraseFactory);
// create VP
setVerbPhrase(phraseFactory.createVerbPhrase());
// set default values
setFeature(Feature.ELIDED, false);
setFeature(InternalFeature.CLAUSE_STATUS, ClauseStatus.MATRIX);
setFeature(Feature.SUPRESSED_COMPLEMENTISER, false);
setFeature(LexicalFeature.EXPLETIVE_SUBJECT, false);
setFeature(Feature.COMPLEMENTISER, phraseFactory.createWord(
"that", LexicalCategory.COMPLEMENTISER)); //$NON-NLS-1$
}
// intercept and override setFeature, to set VP features as needed
/**
* adds a feature, possibly to the underlying VP as well as the SPhraseSpec
* itself
*
* @see simplenlg.framework.NLGElement#setFeature(java.lang.String,
* java.lang.Object)
*/
@Override
public void setFeature(String featureName, Object featureValue) {
super.setFeature(featureName, featureValue);
if (vpFeatures.contains(featureName)) {
NLGElement verbPhrase = (NLGElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
verbPhrase.setFeature(featureName, featureValue);
}
}
/*
* adds a premodifier, if possible to the underlying VP
*
* @see
* simplenlg.framework.PhraseElement#addPreModifier(simplenlg.framework.
* NLGElement)
*/
@Override
public void addPreModifier(NLGElement newPreModifier) {
NLGElement verbPhrase = (NLGElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null) {
if (verbPhrase instanceof PhraseElement) {
((PhraseElement) verbPhrase).addPreModifier(newPreModifier);
} else if (verbPhrase instanceof CoordinatedPhraseElement) {
((CoordinatedPhraseElement) verbPhrase)
.addPreModifier(newPreModifier);
} else {
super.addPreModifier(newPreModifier);
}
}
}
/*
* adds a complement, if possible to the underlying VP
*
* @seesimplenlg.framework.PhraseElement#addComplement(simplenlg.framework.
* NLGElement)
*/
@Override
public void addComplement(NLGElement complement) {
PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
verbPhrase.addComplement(complement);
else
super.addComplement(complement);
}
/*
* adds a complement, if possible to the underlying VP
*
* @see simplenlg.framework.PhraseElement#addComplement(java.lang.String)
*/
@Override
public void addComplement(String newComplement) {
PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
verbPhrase.addComplement(newComplement);
else
super.addComplement(newComplement);
}
/*
* (non-Javadoc)
*
* @see simplenlg.framework.NLGElement#setFeature(java.lang.String, boolean)
*/
@Override
public void setFeature(String featureName, boolean featureValue) {
super.setFeature(featureName, featureValue);
if (vpFeatures.contains(featureName)) {
//PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
//AG: bug fix: VP could be coordinate phrase, so cast to NLGElement not PhraseElement
NLGElement verbPhrase = (NLGElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
verbPhrase.setFeature(featureName, featureValue);
}
}
/* (non-Javadoc)
* @see simplenlg.framework.NLGElement#getFeature(java.lang.String)
*/
@Override
public Object getFeature(String featureName) {
if (super.getFeature(featureName) != null)
return super.getFeature(featureName);
if (vpFeatures.contains(featureName)) {
NLGElement verbPhrase = (NLGElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
return verbPhrase.getFeature(featureName);
}
return null;
}
/**
* @return VP for this clause
*/
public NLGElement getVerbPhrase() {
return getFeatureAsElement(InternalFeature.VERB_PHRASE);
}
public void setVerbPhrase(NLGElement vp) {
setFeature(InternalFeature.VERB_PHRASE, vp);
vp.setParent(this); // needed for syntactic processing
}
/**
* Set the verb of a clause
*
* @param verb
*/
public void setVerb(Object verb) {
// get verb phrase element (create if necessary)
NLGElement verbPhraseElement = getVerbPhrase();
// set head of VP to verb (if this is VPPhraseSpec, and not a coord)
if (verbPhraseElement != null
&& verbPhraseElement instanceof VPPhraseSpec)
((VPPhraseSpec) verbPhraseElement).setVerb(verb);
/*
* // WARNING - I don't understand verb phrase, so this may not work!!
* NLGElement verbElement = getFactory().createWord(verb,
* LexicalCategory.VERB);
*
* // get verb phrase element (create if necessary) NLGElement
* verbPhraseElement = getVerbPhrase();
*
* // set head of VP to verb (if this is VPPhraseSpec, and not a coord)
* if (verbPhraseElement != null && verbPhraseElement instanceof
* VPPhraseSpec) ((VPPhraseSpec)
* verbPhraseElement).setHead(verbElement);
*/}
/**
* Returns the verb of a clause
*
* @return verb of clause
*/
public NLGElement getVerb() {
// WARNING - I don't understand verb phrase, so this may not work!!
PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
return verbPhrase.getHead();
else
// return null if VP is coordinated phrase
return null;
}
/**
* Sets the subject of a clause (assumes this is the only subject)
*
* @param subject
*/
public void setSubject(Object subject) {
NLGElement subjectPhrase;
if (subject instanceof PhraseElement
|| subject instanceof CoordinatedPhraseElement)
subjectPhrase = (NLGElement) subject;
else
subjectPhrase = getFactory().createNounPhrase(subject);
List subjects = new ArrayList();
subjects.add(subjectPhrase);
setFeature(InternalFeature.SUBJECTS, subjects);
}
/**
* Returns the subject of a clause (assumes there is only one)
*
* @return subject of clause (assume only one)
*/
public NLGElement getSubject() {
List subjects = getFeatureAsElementList(InternalFeature.SUBJECTS);
if (subjects == null || subjects.isEmpty())
return null;
return subjects.get(0);
}
/**
* Sets the direct object of a clause (assumes this is the only direct
* object)
*
* @param object
*/
public void setObject(Object object) {
// get verb phrase element (create if necessary)
NLGElement verbPhraseElement = getVerbPhrase();
// set object of VP to verb (if this is VPPhraseSpec, and not a coord)
if (verbPhraseElement != null
&& verbPhraseElement instanceof VPPhraseSpec)
((VPPhraseSpec) verbPhraseElement).setObject(object);
}
/**
* Returns the direct object of a clause (assumes there is only one)
*
* @return subject of clause (assume only one)
*/
public NLGElement getObject() {
PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
return ((VPPhraseSpec) verbPhrase).getObject();
else
// return null if VP is coordinated phrase
return null;
}
/**
* Set the indirect object of a clause (assumes this is the only direct
* indirect object)
*
* @param indirectObject
*/
public void setIndirectObject(Object indirectObject) {
// get verb phrase element (create if necessary)
NLGElement verbPhraseElement = getVerbPhrase();
// set head of VP to verb (if this is VPPhraseSpec, and not a coord)
if (verbPhraseElement != null
&& verbPhraseElement instanceof VPPhraseSpec)
((VPPhraseSpec) verbPhraseElement)
.setIndirectObject(indirectObject);
}
/**
* Returns the indirect object of a clause (assumes there is only one)
*
* @return subject of clause (assume only one)
*/
public NLGElement getIndirectObject() {
PhraseElement verbPhrase = (PhraseElement) getFeatureAsElement(InternalFeature.VERB_PHRASE);
if (verbPhrase != null || verbPhrase instanceof VPPhraseSpec)
return ((VPPhraseSpec) verbPhrase).getIndirectObject();
else
// return null if VP is coordinated phrase
return null;
}
// note that addFrontModifier, addPostModifier, addPreModifier are inherited
// from PhraseElement
// likewise getFrontModifiers, getPostModifiers, getPreModifiers
/**
* Add a modifier to a clause Use heuristics to decide where it goes
*
* @param modifier
*/
@Override
public void addModifier(Object modifier) {
// adverb is frontModifier if sentenceModifier
// otherwise adverb is preModifier
// string which is one lexicographic word is looked up in lexicon,
// above rules apply if adverb
// Everything else is postModifier
if (modifier == null)
return;
// get modifier as NLGElement if possible
NLGElement modifierElement = null;
if (modifier instanceof NLGElement)
modifierElement = (NLGElement) modifier;
else if (modifier instanceof String) {
String modifierString = (String) modifier;
if (modifierString.length() > 0 && !modifierString.contains(" "))
modifierElement = getFactory().createWord(modifier,
LexicalCategory.ANY);
}
// if no modifier element, must be a complex string
if (modifierElement == null) {
addPostModifier((String) modifier);
return;
}
// AdvP is premodifer (probably should look at head to see if
// sentenceModifier)
if (modifierElement instanceof AdvPhraseSpec) {
addPreModifier(modifierElement);
return;
}
// extract WordElement if modifier is a single word
WordElement modifierWord = null;
if (modifierElement != null && modifierElement instanceof WordElement)
modifierWord = (WordElement) modifierElement;
else if (modifierElement != null
&& modifierElement instanceof InflectedWordElement)
modifierWord = ((InflectedWordElement) modifierElement)
.getBaseWord();
if (modifierWord != null
&& modifierWord.getCategory() == LexicalCategory.ADVERB) {
// adverb rules
if (modifierWord
.getFeatureAsBoolean(LexicalFeature.SENTENCE_MODIFIER))
addFrontModifier(modifierWord);
else
addPreModifier(modifierWord);
return;
}
// default case
addPostModifier(modifierElement);
}
}