![JAR search and dependency download from the Maven repository](/logo.png)
simplenlg.syntax.english.VerbPhraseHelper 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 newest version!
/*
* The contents of this file are subject to the Mozilla Public License
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* https://www.mozilla.org/en-US/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 Westwater, Roman Kutlak, Margaret Mitchell, and Saad Mahamood.
*/
package simplenlg.syntax.english;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import simplenlg.features.*;
import simplenlg.framework.*;
import simplenlg.phrasespec.SPhraseSpec;
/**
*
* This class contains static methods to help the syntax processor realise verb
* phrases. It adds auxiliary verbs into the element tree as required.
*
*
* @author D. Westwater, University of Aberdeen.
* @version 4.0
*/
abstract class VerbPhraseHelper {
/**
* The main method for realising verb phrases.
*
* @param parent the SyntaxProcessor
that called this method.
* @param phrase the PhraseElement
to be realised.
* @return the realised NLGElement
.
*/
static NLGElement realise(SyntaxProcessor parent, PhraseElement phrase) {
ListElement realisedElement = null;
Stack vgComponents = null;
Stack mainVerbRealisation = new Stack();
Stack auxiliaryRealisation = new Stack();
if(phrase != null) {
vgComponents = createVerbGroup(parent, phrase);
splitVerbGroup(vgComponents, mainVerbRealisation, auxiliaryRealisation);
realisedElement = new ListElement();
if(!phrase.hasFeature(InternalFeature.REALISE_AUXILIARY)
|| phrase.getFeatureAsBoolean(InternalFeature.REALISE_AUXILIARY).booleanValue()) {
realiseAuxiliaries(parent, realisedElement, auxiliaryRealisation);
PhraseHelper.realiseList(parent,
realisedElement,
phrase.getPreModifiers(),
DiscourseFunction.PRE_MODIFIER);
realiseMainVerb(parent, phrase, mainVerbRealisation, realisedElement);
} else if(isCopular(phrase.getHead())) {
realiseMainVerb(parent, phrase, mainVerbRealisation, realisedElement);
PhraseHelper.realiseList(parent,
realisedElement,
phrase.getPreModifiers(),
DiscourseFunction.PRE_MODIFIER);
} else {
PhraseHelper.realiseList(parent,
realisedElement,
phrase.getPreModifiers(),
DiscourseFunction.PRE_MODIFIER);
realiseMainVerb(parent, phrase, mainVerbRealisation, realisedElement);
}
realiseComplements(parent, phrase, realisedElement);
PhraseHelper.realiseList(parent,
realisedElement,
phrase.getPostModifiers(),
DiscourseFunction.POST_MODIFIER);
}
return realisedElement;
}
/**
* Realises the auxiliary verbs in the verb group.
*
* @param parent the parent SyntaxProcessor
that will do the
* realisation of the complementiser.
* @param realisedElement the current realisation of the noun phrase.
* @param auxiliaryRealisation the stack of auxiliary verbs.
*/
private static void realiseAuxiliaries(SyntaxProcessor parent,
ListElement realisedElement,
Stack auxiliaryRealisation) {
NLGElement aux = null;
NLGElement currentElement = null;
while(!auxiliaryRealisation.isEmpty()) {
aux = auxiliaryRealisation.pop();
currentElement = parent.realise(aux);
if(currentElement != null) {
realisedElement.addComponent(currentElement);
currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.AUXILIARY);
}
}
}
/**
* Realises the main group of verbs in the phrase.
*
* @param parent the parent SyntaxProcessor
that will do the
* realisation of the complementiser.
* @param phrase the PhraseElement
representing this noun phrase.
* @param mainVerbRealisation the stack of the main verbs in the phrase.
* @param realisedElement the current realisation of the noun phrase.
*/
private static void realiseMainVerb(SyntaxProcessor parent,
PhraseElement phrase,
Stack mainVerbRealisation,
ListElement realisedElement) {
NLGElement currentElement = null;
NLGElement main = null;
while(!mainVerbRealisation.isEmpty()) {
main = mainVerbRealisation.pop();
main.setFeature(Feature.INTERROGATIVE_TYPE, phrase.getFeature(Feature.INTERROGATIVE_TYPE));
currentElement = parent.realise(main);
if(currentElement != null) {
realisedElement.addComponent(currentElement);
}
}
}
/**
* Realises the complements of this phrase.
*
* @param parent the parent SyntaxProcessor
that will do the
* realisation of the complementiser.
* @param phrase the PhraseElement
representing this noun phrase.
* @param realisedElement the current realisation of the noun phrase.
*/
private static void realiseComplements(SyntaxProcessor parent, PhraseElement phrase, ListElement realisedElement) {
ListElement indirects = new ListElement();
ListElement directs = new ListElement();
ListElement unknowns = new ListElement();
Object discourseValue = null;
NLGElement currentElement = null;
for(NLGElement complement : phrase.getFeatureAsElementList(InternalFeature.COMPLEMENTS)) {
discourseValue = complement.getFeature(InternalFeature.DISCOURSE_FUNCTION);
currentElement = parent.realise(complement);
if(currentElement != null) {
currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.COMPLEMENT);
if(DiscourseFunction.INDIRECT_OBJECT.equals(discourseValue)) {
indirects.addComponent(currentElement);
} else if(DiscourseFunction.OBJECT.equals(discourseValue)) {
directs.addComponent(currentElement);
} else {
unknowns.addComponent(currentElement);
}
}
}
if(!InterrogativeType.isIndirectObject(phrase.getFeature(Feature.INTERROGATIVE_TYPE))) {
realisedElement.addComponents(indirects.getChildren());
}
if(!phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()) {
if(!InterrogativeType.isObject(phrase.getFeature(Feature.INTERROGATIVE_TYPE))) {
realisedElement.addComponents(directs.getChildren());
}
realisedElement.addComponents(unknowns.getChildren());
}
}
/**
* Splits the stack of verb components into two sections. One being the verb
* associated with the main verb group, the other being associated with the
* auxiliary verb group.
*
* @param vgComponents the stack of verb components in the verb group.
* @param mainVerbRealisation the main group of verbs.
* @param auxiliaryRealisation the auxiliary group of verbs.
*/
private static void splitVerbGroup(Stack vgComponents,
Stack mainVerbRealisation,
Stack auxiliaryRealisation) {
boolean mainVerbSeen = false;
for(NLGElement word : vgComponents) {
if(!mainVerbSeen) {
mainVerbRealisation.push(word);
if(!word.equals("not")) { //$NON-NLS-1$
mainVerbSeen = true;
}
} else {
auxiliaryRealisation.push(word);
}
}
}
/**
* Creates a stack of verbs for the verb phrase. Additional auxiliary verbs
* are added as required based on the features of the verb phrase.
*
* @param parent the parent SyntaxProcessor
that will do the
* realisation of the complementiser.
* @param phrase the PhraseElement
representing this noun phrase.
* @return the verb group as a Stack
of NLGElement
* s.
*/
static final private Stack createVerbGroup(SyntaxProcessor parent, PhraseElement phrase) {
String actualModal = null;
Object formValue = phrase.getFeature(Feature.FORM);
Tense tenseValue = (Tense) phrase.getFeature(Feature.TENSE);
String modal = phrase.getFeatureAsString(Feature.MODAL);
boolean modalPast = false;
Stack vgComponents = new Stack();
boolean interrogative = phrase.hasFeature(Feature.INTERROGATIVE_TYPE);
if(Form.GERUND.equals(formValue) || Form.INFINITIVE.equals(formValue)) {
tenseValue = Tense.PRESENT;
}
if(Form.INFINITIVE.equals(formValue)) {
actualModal = "to"; //$NON-NLS-1$
} else if(formValue == null || Form.NORMAL.equals(formValue)) {
if(Tense.FUTURE.equals(tenseValue) && modal == null && (
(!(phrase.getHead() instanceof CoordinatedPhraseElement)) || (
phrase.getHead() instanceof CoordinatedPhraseElement && interrogative))) {
actualModal = "will"; //$NON-NLS-1$
} else if(modal != null) {
actualModal = modal;
if(Tense.PAST.equals(tenseValue)) {
modalPast = true;
}
}
}
pushParticles(phrase, parent, vgComponents);
NLGElement frontVG = grabHeadVerb(phrase, tenseValue, modal != null);
checkImperativeInfinitive(formValue, frontVG);
if(phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()) {
frontVG = addBe(frontVG, vgComponents, Form.PAST_PARTICIPLE);
}
if(phrase.getFeatureAsBoolean(Feature.PROGRESSIVE).booleanValue()) {
frontVG = addBe(frontVG, vgComponents, Form.PRESENT_PARTICIPLE);
}
if(phrase.getFeatureAsBoolean(Feature.PERFECT).booleanValue() || modalPast) {
frontVG = addHave(frontVG, vgComponents, modal, tenseValue);
}
frontVG = pushIfModal(actualModal != null, phrase, frontVG, vgComponents);
frontVG = createNot(phrase, vgComponents, frontVG, modal != null);
if(frontVG != null) {
pushFrontVerb(phrase, vgComponents, frontVG, formValue, interrogative);
}
pushModal(actualModal, phrase, vgComponents);
return vgComponents;
}
/**
* Pushes the modal onto the stack of verb components.
*
* @param actualModal the modal to be used.
* @param phrase the PhraseElement
representing this noun phrase.
* @param vgComponents the stack of verb components in the verb group.
*/
private static void pushModal(String actualModal, PhraseElement phrase, Stack vgComponents) {
if(actualModal != null && !phrase.getFeatureAsBoolean(InternalFeature.IGNORE_MODAL).booleanValue()) {
vgComponents.push(new InflectedWordElement(actualModal, LexicalCategory.MODAL));
}
}
/**
* Pushes the front verb onto the stack of verb components.
*
* @param phrase the PhraseElement
representing this noun phrase.
* @param vgComponents the stack of verb components in the verb group.
* @param frontVG the first verb in the verb group.
* @param formValue the Form
of the phrase.
* @param interrogative true
if the phrase is interrogative.
*/
private static void pushFrontVerb(PhraseElement phrase,
Stack vgComponents,
NLGElement frontVG,
Object formValue,
boolean interrogative) {
Object interrogType = phrase.getFeature(Feature.INTERROGATIVE_TYPE);
if(Form.GERUND.equals(formValue)) {
frontVG.setFeature(Feature.FORM, Form.PRESENT_PARTICIPLE);
vgComponents.push(frontVG);
} else if(Form.PAST_PARTICIPLE.equals(formValue)) {
frontVG.setFeature(Feature.FORM, Form.PAST_PARTICIPLE);
vgComponents.push(frontVG);
} else if(Form.PRESENT_PARTICIPLE.equals(formValue)) {
frontVG.setFeature(Feature.FORM, Form.PRESENT_PARTICIPLE);
vgComponents.push(frontVG);
} else if((!(formValue == null || Form.NORMAL.equals(formValue)) || interrogative)
&& !isCopular(phrase.getHead()) && vgComponents.isEmpty()) {
// AG: fix below: if interrogative, only set non-morph feature in
// case it's not WHO_SUBJECT OR WHAT_SUBJECT
if(!(InterrogativeType.WHO_SUBJECT.equals(interrogType) || InterrogativeType.WHAT_SUBJECT.equals(
interrogType))) {
frontVG.setFeature(InternalFeature.NON_MORPH, true);
}
vgComponents.push(frontVG);
} else {
NumberAgreement numToUse = determineNumber(phrase.getParent(), phrase);
frontVG.setFeature(Feature.TENSE, phrase.getFeature(Feature.TENSE));
frontVG.setFeature(Feature.PERSON, phrase.getFeature(Feature.PERSON));
frontVG.setFeature(Feature.NUMBER, numToUse);
//don't push the front VG if it's a negated interrogative WH object question
if(!(phrase.getFeatureAsBoolean(Feature.NEGATED).booleanValue() && (
InterrogativeType.WHO_OBJECT.equals(interrogType) || InterrogativeType.WHAT_OBJECT.equals(
interrogType)))) {
vgComponents.push(frontVG);
}
}
}
/**
* Adds not to the stack if the phrase is negated.
*
* @param phrase the PhraseElement
representing this noun phrase.
* @param vgComponents the stack of verb components in the verb group.
* @param frontVG the first verb in the verb group.
* @param hasModal the phrase has a modal
* @return the new element for the front of the group.
*/
private static NLGElement createNot(PhraseElement phrase,
Stack vgComponents,
NLGElement frontVG,
boolean hasModal) {
NLGElement newFront = frontVG;
if(phrase.getFeatureAsBoolean(Feature.NEGATED).booleanValue()) {
NLGFactory factory = phrase.getFactory();
// before adding "do", check if this is an object WH
// interrogative
// in which case, don't add anything as it's already done by
// ClauseHelper
Object interrType = phrase.getFeature(Feature.INTERROGATIVE_TYPE);
boolean addDo = !(InterrogativeType.WHAT_OBJECT.equals(interrType) || InterrogativeType.WHO_OBJECT.equals(
interrType));
if(!vgComponents.empty() || frontVG != null && isCopular(frontVG)) {
vgComponents.push(new InflectedWordElement("not", LexicalCategory.ADVERB)); //$NON-NLS-1$
} else {
if(frontVG != null && !hasModal) {
frontVG.setFeature(Feature.NEGATED, true);
vgComponents.push(frontVG);
}
vgComponents.push(new InflectedWordElement("not", LexicalCategory.ADVERB)); //$NON-NLS-1$
if(addDo) {
if(factory != null) {
newFront = factory.createInflectedWord("do", LexicalCategory.VERB);
} else {
newFront = new InflectedWordElement("do", LexicalCategory.VERB); //$NON-NLS-1$
}
}
}
}
return newFront;
}
/**
* Pushes the front verb on to the stack if the phrase has a modal.
*
* @param hasModal the phrase has a modal
* @param phrase the PhraseElement
representing this noun phrase.
* @param frontVG the first verb in the verb group.
* @param vgComponents the stack of verb components in the verb group.
* @return the new element for the front of the group.
*/
private static NLGElement pushIfModal(boolean hasModal,
PhraseElement phrase,
NLGElement frontVG,
Stack vgComponents) {
NLGElement newFront = frontVG;
if(hasModal && !phrase.getFeatureAsBoolean(InternalFeature.IGNORE_MODAL).booleanValue()) {
if(frontVG != null) {
frontVG.setFeature(InternalFeature.NON_MORPH, true);
vgComponents.push(frontVG);
}
newFront = null;
}
return newFront;
}
/**
* Adds have to the stack.
*
* @param frontVG the first verb in the verb group.
* @param vgComponents the stack of verb components in the verb group.
* @param modal the modal to be used.
* @param tenseValue the Tense
of the phrase.
* @return the new element for the front of the group.
*/
private static NLGElement addHave(NLGElement frontVG,
Stack vgComponents,
String modal,
Tense tenseValue) {
NLGElement newFront = frontVG;
if(frontVG != null) {
frontVG.setFeature(Feature.FORM, Form.PAST_PARTICIPLE);
vgComponents.push(frontVG);
}
newFront = new InflectedWordElement("have", LexicalCategory.VERB); //$NON-NLS-1$
newFront.setFeature(Feature.TENSE, tenseValue);
if(modal != null) {
newFront.setFeature(InternalFeature.NON_MORPH, true);
}
return newFront;
}
/**
* Adds the be verb to the front of the group.
*
* @param frontVG the first verb in the verb group.
* @param vgComponents the stack of verb components in the verb group.
* @param frontForm the form the current front verb is to take.
* @return the new element for the front of the group.
*/
private static NLGElement addBe(NLGElement frontVG, Stack vgComponents, Form frontForm) {
if(frontVG != null) {
frontVG.setFeature(Feature.FORM, frontForm);
vgComponents.push(frontVG);
}
return new InflectedWordElement("be", LexicalCategory.VERB); //$NON-NLS-1$
}
/**
* Checks to see if the phrase is in imperative, infinitive or bare
* infinitive form. If it is then no morphology is done on the main verb.
*
* @param formValue the Form
of the phrase.
* @param frontVG the first verb in the verb group.
*/
private static void checkImperativeInfinitive(Object formValue, NLGElement frontVG) {
if((Form.IMPERATIVE.equals(formValue) || Form.INFINITIVE.equals(formValue) || Form.BARE_INFINITIVE.equals(
formValue)) && frontVG != null) {
frontVG.setFeature(InternalFeature.NON_MORPH, true);
}
}
/**
* Grabs the head verb of the verb phrase and sets it to future tense if the
* phrase is future tense. It also turns off negation if the group has a
* modal.
*
* @param phrase the PhraseElement
representing this noun phrase.
* @param tenseValue the Tense
of the phrase.
* @param hasModal true
if the verb phrase has a modal.
* @return the modified head element
*/
private static NLGElement grabHeadVerb(PhraseElement phrase, Tense tenseValue, boolean hasModal) {
NLGElement frontVG = phrase.getHead();
if(frontVG != null) {
if(frontVG instanceof WordElement) {
frontVG = new InflectedWordElement((WordElement) frontVG);
}
// AG: tense value should always be set on frontVG
if(tenseValue != null) {
frontVG.setFeature(Feature.TENSE, tenseValue);
}
// if (Tense.FUTURE.equals(tenseValue) && frontVG != null) {
// frontVG.setFeature(Feature.TENSE, Tense.FUTURE);
// }
if(hasModal) {
frontVG.setFeature(Feature.NEGATED, false);
}
}
return frontVG;
}
/**
* Pushes the particles of the main verb onto the verb group stack.
*
* @param phrase the PhraseElement
representing this noun phrase.
* @param parent the parent SyntaxProcessor
that will do the
* realisation of the complementiser.
* @param vgComponents the stack of verb components in the verb group.
*/
private static void pushParticles(PhraseElement phrase, SyntaxProcessor parent, Stack vgComponents) {
Object particle = phrase.getFeature(Feature.PARTICLE);
if(particle instanceof String) {
vgComponents.push(new StringElement((String) particle));
} else if(particle instanceof NLGElement) {
vgComponents.push(parent.realise((NLGElement) particle));
}
}
/**
* Determines the number agreement for the phrase ensuring that any number
* agreement on the parent element is inherited by the phrase.
*
* @param parent the parent element of the phrase.
* @param phrase the PhraseElement
representing this noun phrase.
* @return the NumberAgreement
to be used for the phrase.
*/
private static NumberAgreement determineNumber(NLGElement parent, PhraseElement phrase) {
Object numberValue = phrase.getFeature(Feature.NUMBER);
NumberAgreement number = null;
if(numberValue != null && numberValue instanceof NumberAgreement) {
number = (NumberAgreement) numberValue;
} else {
number = NumberAgreement.SINGULAR;
}
// Ehud Reiter = modified below to force number from VP for WHAT_SUBJECT
// and WHO_SUBJECT interrogatuves
if(parent instanceof PhraseElement) {
if(parent.isA(PhraseCategory.CLAUSE) && (PhraseHelper.isExpletiveSubject((PhraseElement) parent)
|| InterrogativeType.WHO_SUBJECT.equals(parent.getFeature(Feature.INTERROGATIVE_TYPE))
|| InterrogativeType.WHAT_SUBJECT.equals(parent.getFeature(Feature.INTERROGATIVE_TYPE)))
&& isCopular(phrase.getHead())) {
if(hasPluralComplement(phrase.getFeatureAsElementList(InternalFeature.COMPLEMENTS))) {
number = NumberAgreement.PLURAL;
} else {
number = NumberAgreement.SINGULAR;
}
}
}
return number;
}
/**
* Checks to see if any of the complements to the phrase are plural.
*
* @param complements the list of complements of the phrase.
* @return true
if any of the complements are plural.
*/
private static boolean hasPluralComplement(List complements) {
boolean plural = false;
Iterator complementIterator = complements.iterator();
NLGElement eachComplement = null;
Object numberValue = null;
while(complementIterator.hasNext() && !plural) {
eachComplement = complementIterator.next();
if(eachComplement != null && eachComplement.isA(PhraseCategory.NOUN_PHRASE)) {
numberValue = eachComplement.getFeature(Feature.NUMBER);
if(numberValue != null && NumberAgreement.PLURAL.equals(numberValue)) {
plural = true;
}
}
}
return plural;
}
/**
* Checks to see if the base form of the word is copular, i.e. be.
*
* @param element the element to be checked
* @return true
if the element is copular.
*/
public static boolean isCopular(NLGElement element) {
boolean copular = false;
if(element instanceof InflectedWordElement) {
copular = "be".equalsIgnoreCase(((InflectedWordElement) element) //$NON-NLS-1$
.getBaseForm());
} else if(element instanceof WordElement) {
copular = "be".equalsIgnoreCase(((WordElement) element) //$NON-NLS-1$
.getBaseForm());
} else if(element instanceof PhraseElement) {
// get the head and check if it's "be"
NLGElement head = element instanceof SPhraseSpec ? ((SPhraseSpec) element).getVerb() :
((PhraseElement) element).getHead();
if(head != null) {
copular = (head instanceof WordElement && "be".equals(((WordElement) head).getBaseForm()));
}
}
return copular;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy