/** * Perform aggregation on a single phrase. This method only works on a * {@link simplenlg.framework.CoordinatedPhraseElement}, in which case it * calls {@link #apply(List)} on the children of the coordinated phrase, * returning a coordinated phrase whose children are the result. * * @param phrase * @return aggregated result */ public virtual NLGElement apply(NLGElement phrase) { NLGElement result = null; if (phrase is CoordinatedPhraseElement) { IList <NLGElement> children = ((CoordinatedPhraseElement)phrase).Children; IList <NLGElement> aggregated = apply(children); if (aggregated.Count == 1) { result = aggregated[0]; } else { result = factory.createCoordinatedPhrase(); foreach (NLGElement agg in aggregated) { ((CoordinatedPhraseElement)result).addCoordinate(agg); } } } if (result != null) { foreach (string feature in phrase.AllFeatureNames) { result.setFeature(feature, phrase.getFeature(feature)); } } return(result); }
/** * Applies aggregation to two NLGElements e1 and e2, succeeding only if they * are clauses (that is, e1.getCategory() == e2.getCategory == * {@link simplenlg.framework.PhraseCategory#CLAUSE}). */ public override NLGElement apply(NLGElement previous, NLGElement next) { NLGElement aggregated = null; if (previous.Category == PhraseCategory.PhraseCategoryEnum.CLAUSE && next.Category == PhraseCategory.PhraseCategoryEnum.CLAUSE && PhraseChecker.nonePassive(previous, next) && !PhraseChecker.expletiveSubjects(previous, next)) { if (PhraseChecker.sameSentences(previous, next)) { // case 1: identical sentences: remove the current aggregated = previous; } else if (PhraseChecker.sameFrontMods(previous, next) && PhraseChecker.sameSubjects(previous, next) && PhraseChecker.samePostMods(previous, next)) { // case 2: subjects identical: coordinate VPs aggregated = factory.createClause(); aggregated.setFeature(InternalFeature.SUBJECTS, previous.getFeatureAsElementList(InternalFeature.SUBJECTS)); aggregated.setFeature(InternalFeature.FRONT_MODIFIERS, previous.getFeatureAsElement(InternalFeature.FRONT_MODIFIERS)); aggregated.setFeature(Feature.CUE_PHRASE, previous.getFeatureAsElement(Feature.CUE_PHRASE)); aggregated.setFeature(InternalFeature.POSTMODIFIERS, previous.getFeatureAsElementList(InternalFeature.POSTMODIFIERS)); NLGElement vp; if (!PhraseChecker.sameVPArgs(previous, next) && PhraseChecker.sameVPHead(previous, next) && PhraseChecker.sameVPModifiers(previous, next)) { // case 2.1: VPs have different arguments but same head & mods NLGElement vp1 = previous.getFeatureAsElement(InternalFeature.VERB_PHRASE); vp = factory.createVerbPhrase(); vp.setFeature(InternalFeature.HEAD, vp1.getFeatureAsElement(InternalFeature.HEAD)); vp.setFeature(InternalFeature.COMPLEMENTS, vp1.getFeatureAsElementList(InternalFeature.COMPLEMENTS)); vp.setFeature(InternalFeature.PREMODIFIERS, vp1.getFeatureAsElementList(InternalFeature.PREMODIFIERS)); vp.setFeature(InternalFeature.POSTMODIFIERS, vp1.getFeatureAsElementList(InternalFeature.POSTMODIFIERS)); } else { // case 2.2: just create a coordinate vP NLGElement vp1 = previous.getFeatureAsElement(InternalFeature.VERB_PHRASE); NLGElement vp2 = next.getFeatureAsElement(InternalFeature.VERB_PHRASE); vp = factory.createCoordinatedPhrase(vp1, vp2); } // case 2.3: expletive subjects aggregated.setFeature(InternalFeature.VERB_PHRASE, vp); } else if (PhraseChecker.sameFrontMods(previous, next) && PhraseChecker.sameVP(previous, next) && PhraseChecker.samePostMods(previous, next)) { // case 3: identical VPs: conjoin subjects and front modifiers aggregated = factory.createClause(); aggregated.setFeature(InternalFeature.FRONT_MODIFIERS, previous.getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS)); CoordinatedPhraseElement subjects = factory.createCoordinatedPhrase(); subjects.Category = new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE); IList <NLGElement> allSubjects = previous.getFeatureAsElementList(InternalFeature.SUBJECTS); ((List <NLGElement>)allSubjects).AddRange(next.getFeatureAsElementList(InternalFeature.SUBJECTS)); foreach (NLGElement subj in allSubjects) { subjects.addCoordinate(subj); } aggregated.setFeature(InternalFeature.SUBJECTS, subjects); aggregated.setFeature(InternalFeature.POSTMODIFIERS, previous.getFeatureAsElementList(InternalFeature.POSTMODIFIERS)); aggregated.setFeature(InternalFeature.VERB_PHRASE, previous.getFeature(InternalFeature.VERB_PHRASE)); } } return(aggregated); }
/* (non-Javadoc) * @see simplenlg.framework.NLGElement#getFeature(java.lang.String) */ public override object getFeature(string featureName) { if (base.getFeature(featureName) != null) { return(base.getFeature(featureName)); } if (vpFeatures.Contains(featureName)) { NLGElement verbPhrase = (NLGElement)getFeatureAsElement(InternalFeature.VERB_PHRASE); if (verbPhrase != null || verbPhrase is VPPhraseSpec) { return(verbPhrase.getFeature(featureName)); } } return(null); }
/** * Retrieves the correct representation of the word from the element. This * method will find the <code>WordElement</code>, if it exists, for the * given phrase or inflected word. * * @param element * the <code>NLGElement</code> from which the head is required. * @return the <code>WordElement</code> */ private static WordElement getHeadWordElement(NLGElement element) { WordElement head = null; if (element is WordElement) { head = (WordElement)element; } else if (element is InflectedWordElement) { head = (WordElement)element.getFeature(InternalFeature.BASE_WORD); } else if (element is PhraseElement) { head = getHeadWordElement(((PhraseElement)element).getHead()); } return(head); }
/** * Checks to see if any of the complements to the phrase are plural. * * @param complements * the list of complements of the phrase. * @return <code>true</code> if any of the complements are plural. */ private static bool hasPluralComplement(IList <NLGElement> complements) { bool plural = false; IEnumerator <NLGElement> complementIterator = complements.GetEnumerator(); NLGElement eachComplement = null; object numberValue = null; while (complementIterator.MoveNext() && !plural) { eachComplement = complementIterator.Current; if (eachComplement != null && eachComplement.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE))) { numberValue = eachComplement.getFeature(Feature.NUMBER); if (numberValue != null && NumberAgreement.PLURAL.Equals(numberValue)) { plural = true; } } } return(plural); }
public static IList <FunctionalSet> collectFunctionalPairs(NLGElement phrase1, NLGElement phrase2) { IList <NLGElement> children1 = getAllChildren(phrase1); IList <NLGElement> children2 = getAllChildren(phrase2); IList <FunctionalSet> pairs = new List <FunctionalSet>(); if (children1.Count == children2.Count) { Periphery periph = Periphery.LEFT; for (int i = 0; i < children1.Count; i++) { NLGElement child1 = children1[i]; NLGElement child2 = children2[i]; ElementCategory cat1 = child1.Category; ElementCategory cat2 = child2.Category; DiscourseFunction func1 = (DiscourseFunction)child1.getFeature(InternalFeature.DISCOURSE_FUNCTION); DiscourseFunction func2 = (DiscourseFunction)child2.getFeature(InternalFeature.DISCOURSE_FUNCTION); if (cat1 == cat2 && func1 == func2) { pairs.Add(FunctionalSet.newInstance(func1, cat1, periph, child1, child2)); if (cat1 == LexicalCategory.LexicalCategoryEnum.VERB) { periph = Periphery.RIGHT; } } else { pairs.Clear(); break; } } } return(pairs); }
/** * Realises coordinated phrases. Where there are more than two coordinates, * then a comma replaces the conjunction word between all the coordinates * save the last two. For example, <em>John and Peter and Simon</em> becomes * <em>John, Peter and Simon</em>. * * @param components * the <code>List</code> of <code>NLGElement</code>s representing * the components that make up the sentence. * @return the realised element as an <code>NLGElement</code>. */ private NLGElement realiseCoordinatedPhrase(IList <NLGElement> components) { StringBuilder realisation = new StringBuilder(); NLGElement realisedChild = null; int length = components.Count; for (int index = 0; index < length; index++) { realisedChild = components[index]; if (index < length - 2 && DiscourseFunction.CONJUNCTION.Equals(realisedChild.getFeature(InternalFeature.DISCOURSE_FUNCTION))) { realisation.Append(", "); //$NON-NLS-1$ } else { realisedChild = realise(realisedChild); realisation.Append(realisedChild.Realisation).Append(' '); } } realisation.Length = realisation.Length - 1; return(new StringElement(realisation.ToString().Replace(" ,", ","))); //$NON-NLS-1$ //$NON-NLS-2$ }
/** * Checks the subjects of the phrase to determine if there is more than one * subject. This ensures that the verb phrase is correctly set. Also set * person correctly * * @param phrase * the <code>PhraseElement</code> representing this clause. * @param verbElement * the <code>NLGElement</code> representing the verb phrase for * this clause. */ private static void checkSubjectNumberPerson(PhraseElement phrase, NLGElement verbElement) { NLGElement currentElement = null; IList <NLGElement> subjects = phrase.getFeatureAsElementList(InternalFeature.SUBJECTS); bool pluralSubjects = false; Person?person = null; if (subjects != null) { switch (subjects.Count) { case 0: break; case 1: currentElement = subjects[0]; // coordinated NP with "and" are plural (not coordinated NP with "or") if (currentElement is CoordinatedPhraseElement && ((CoordinatedPhraseElement)currentElement).checkIfPlural()) { pluralSubjects = true; } else if (((NumberAgreement?)currentElement.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL) && !(currentElement is SPhraseSpec)) // ER mod- { // ER mod-clauses are singular as NPs, even if they are plural internally pluralSubjects = true; } else if (currentElement.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE))) { NLGElement currentHead = currentElement.getFeatureAsElement(InternalFeature.HEAD); person = (Person?)currentElement.getFeature(Feature.PERSON); if (currentHead == null) { // subject is null and therefore is not gonna be plural pluralSubjects = false; } else if ((NumberAgreement?)currentHead.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL) { pluralSubjects = true; } else if (currentHead is ListElement) { pluralSubjects = true; /* * } else if (currentElement instanceof * CoordinatedPhraseElement && * "and".equals(currentElement.getFeatureAsString( * //$NON-NLS-1$ Feature.CONJUNCTION))) { pluralSubjects * = true; */ } } break; default: pluralSubjects = true; break; } } if (verbElement != null) { verbElement.setFeature(Feature.NUMBER, pluralSubjects ? NumberAgreement.PLURAL : (NumberAgreement?)phrase.getFeature(Feature.NUMBER)); if (person != null) { verbElement.setFeature(Feature.PERSON, person); } } }
/** * ~Set the features for a sentence. This method also checks whether any * features have been set on the VP, in which case, they are set if they * haven't been set on the S * * @param wp * the xml SPhraseSpec object * @param sp * the sentence. * @param vp * the verb phrase. */ private void setSFeatures(wrapper.XmlSPhraseSpec wp, SPhraseSpec sp, NLGElement vp) { if (wp.CLAUSESTATUS != null) { Enum.TryParse(wp.CLAUSESTATUS.ToString(), out ClauseStatus clauseStatus); sp.setFeature(InternalFeature.CLAUSE_STATUS, clauseStatus); } if (wp.PERSON != null) { Enum.TryParse(wp.PERSON.ToString(), out Person person); sp.setFeature(Feature.PERSON, person); } if (wp.FORM != null) { Enum.TryParse(wp.FORM.ToString(), out Form form); sp.setFeature(Feature.FORM, form); } if (wp.TENSE != null) { Enum.TryParse(wp.TENSE.ToString(), out Form tense); sp.setFeature(Feature.TENSE, tense); } else if (vp != null && vp.hasFeature(Feature.TENSE)) { sp.setFeature(Feature.TENSE, vp.getFeature(Feature.TENSE)); } // modal -- set on S or inherited from VP if (wp.MODAL != null) { sp.setFeature(Feature.MODAL, wp.MODAL); } else if (vp != null && vp.hasFeature(Feature.MODAL)) { sp.setFeature(Feature.MODAL, vp.getFeature(Feature.MODAL)); } // interrogative if (wp.INTERROGATIVETYPE != null) { Enum.TryParse(wp.INTERROGATIVETYPE.ToString(), out InterrogativeType interrogativeType); sp.setFeature(Feature.INTERROGATIVE_TYPE, interrogativeType); } else if (vp != null && vp.hasFeature(Feature.INTERROGATIVE_TYPE)) { sp.setFeature(Feature.INTERROGATIVE_TYPE, vp.getFeature(Feature.INTERROGATIVE_TYPE)); } // set on clauses. bool sAggregateAuxiliary = wp.AGGREGATEAUXILIARY ?? false; bool vAggregateAuxiliary = vp?.getFeatureAsBoolean(Feature.AGGREGATE_AUXILIARY) ?? false; sp.setFeature(Feature.AGGREGATE_AUXILIARY, sAggregateAuxiliary || vAggregateAuxiliary); // passive: can be set on S or VP bool sPass = wp.PASSIVE ?? false; bool vPass = vp?.getFeatureAsBoolean(Feature.PASSIVE) ?? false; sp.setFeature(Feature.PASSIVE, sPass || vPass); // progressive: can be set on S or VP bool sProg = wp.PROGRESSIVE ?? false; bool vProg = vp?.getFeatureAsBoolean(Feature.PROGRESSIVE) ?? false; sp.setFeature(Feature.PROGRESSIVE, sProg || vProg); // perfect: can be set on S or VP bool sPerf = wp.PERFECT ?? false; bool vPerf = vp?.getFeatureAsBoolean(Feature.PERFECT) ?? false; sp.setFeature(Feature.PERFECT, sPerf || vPerf); // negation: can be set on S or VP bool sNeg = wp.NEGATED ?? false; bool vNeg = vp?.getFeatureAsBoolean(Feature.NEGATED) ?? false; sp.setFeature(Feature.NEGATED, sNeg || vNeg); // set on clauses. bool ssgg = wp.SUPPRESSGENITIVEINGERUND ?? false; bool vsgg = vp?.getFeatureAsBoolean(Feature.SUPPRESS_GENITIVE_IN_GERUND) ?? false; sp.setFeature(Feature.SUPPRESS_GENITIVE_IN_GERUND, ssgg || vsgg); // set on clauses. bool ssc = wp.SUPRESSEDCOMPLEMENTISER ?? false; bool vsc = vp?.getFeatureAsBoolean(Feature.SUPRESSED_COMPLEMENTISER) ?? false; sp.setFeature(Feature.SUPRESSED_COMPLEMENTISER, ssc || vsc); }
public override IList <NLGElement> realise(IList <NLGElement> elements) { IList <NLGElement> realisedElements = new List <NLGElement>(); NLGElement currentElement = null; NLGElement determiner = null; NLGElement prevElement = null; if (elements != null) { foreach (NLGElement eachElement in elements) { currentElement = realise(eachElement); if (currentElement != null) { //pass the discourse function and appositive features -- important for orth processor currentElement.setFeature(Feature.APPOSITIVE, eachElement.getFeature(Feature.APPOSITIVE)); object function = eachElement.getFeature(InternalFeature.DISCOURSE_FUNCTION); if (function != null) { currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION, function); } if (prevElement != null && prevElement is StringElement && eachElement is InflectedWordElement && ((InflectedWordElement)eachElement).Category == LexicalCategory.LexicalCategoryEnum.NOUN) { string prevString = prevElement.Realisation; //realisedElements.get(realisedElements.size() - 1) prevElement.Realisation = DeterminerAgrHelper.checkEndsWithIndefiniteArticle(prevString, currentElement.Realisation); } // realisedElements.add(realise(currentElement)); realisedElements.Add(currentElement); if (determiner == null && DiscourseFunction.SPECIFIER.Equals(currentElement.getFeature(InternalFeature.DISCOURSE_FUNCTION))) { determiner = currentElement; determiner.setFeature(Feature.NUMBER, eachElement.getFeature(Feature.NUMBER)); // MorphologyRules.doDeterminerMorphology(determiner, // currentElement.getRealisation()); } else if (determiner != null) { if (currentElement is ListElement) { // list elements: ensure det matches first element NLGElement firstChild = ((ListElement)currentElement).Children[0]; if (firstChild != null) { //AG: need to check if child is a coordinate if (firstChild is CoordinatedPhraseElement) { MorphologyRules.doDeterminerMorphology(determiner, firstChild.Children[0].Realisation); } else { MorphologyRules.doDeterminerMorphology(determiner, firstChild.Realisation); } } } else { // everything else: ensure det matches realisation MorphologyRules.doDeterminerMorphology(determiner, currentElement.Realisation); } determiner = null; } } prevElement = eachElement; } } return(realisedElements); }
public override NLGElement realise(NLGElement element) { NLGElement realisedElement = null; if (element != null && !element.getFeatureAsBoolean(Feature.ELIDED)) { if (element is DocumentElement) { IList <NLGElement> children = element.Children; ((DocumentElement)element).Components = realise(children); realisedElement = element; } else if (element is PhraseElement) { realisedElement = realisePhraseElement((PhraseElement)element); } else if (element is ListElement) { realisedElement = new ListElement(); ((ListElement)realisedElement).addComponents(realise(element.Children)); } else if (element is InflectedWordElement) { string baseForm = ((InflectedWordElement)element).BaseForm; ElementCategory category = element.Category; if (lexicon != null && !ReferenceEquals(baseForm, null)) { WordElement word = ((InflectedWordElement)element).BaseWord; if (word == null) { if (category is LexicalCategory) { word = lexicon.lookupWord(baseForm, (LexicalCategory)category); } else { word = lexicon.lookupWord(baseForm); } } if (word != null) { ((InflectedWordElement)element).BaseWord = word; } } realisedElement = element; } else if (element is WordElement) { // AG: need to check if it's a word element, in which case it // needs to be marked for inflection InflectedWordElement infl = new InflectedWordElement((WordElement)element); // the inflected word inherits all features from the base word foreach (string feature in element.AllFeatureNames) { infl.setFeature(feature, element.getFeature(feature)); } realisedElement = realise(infl); } else if (element is CoordinatedPhraseElement) { realisedElement = CoordinatedPhraseHelper.realise(this, (CoordinatedPhraseElement)element); } else { realisedElement = element; } } // Remove the spurious ListElements that have only one element. if (realisedElement is ListElement) { if (((ListElement)realisedElement).size() == 1) { realisedElement = ((ListElement)realisedElement).First; } } return(realisedElement); }
public override NLGElement realise(NLGElement element) { NLGElement realisedElement = null; object function = null; //the element's discourse function //get the element's function first if (element is ListElement) { IList <NLGElement> children = element.Children; if (children.Any()) { NLGElement firstChild = children[0]; function = firstChild.getFeature(InternalFeature.DISCOURSE_FUNCTION); } } else { if (element != null) { function = element.getFeature(InternalFeature.DISCOURSE_FUNCTION); } } if (element != null) { ElementCategory category = element.Category; if (category is DocumentCategory && element is DocumentElement) { IList <NLGElement> components = ((DocumentElement)element).Components; switch (((DocumentCategory)category).GetDocumentCategory()) { case DocumentCategory.DocumentCategoryEnum.SENTENCE: realisedElement = realiseSentence(components, element); break; case DocumentCategory.DocumentCategoryEnum.LIST_ITEM: if (components != null && components.Any()) { // recursively realise whatever is in the list item // NB: this will realise embedded lists within list items realisedElement = new ListElement(realise(components)); realisedElement.Parent = element.Parent; } break; default: ((DocumentElement)element).Components = realise(components); realisedElement = element; break; } } else if (element is ListElement) { // AG: changes here: if we have a premodifier, then we ask the // realiseList method to separate with a comma. // if it's a postmod, we need commas at the start and end only // if it's appositive StringBuilder buffer = new StringBuilder(); if (DiscourseFunction.PRE_MODIFIER.Equals(function)) { bool all_appositives = true; foreach (NLGElement child in element.Children) { all_appositives = all_appositives && child.getFeatureAsBoolean(Feature.APPOSITIVE); } // TODO: unless this is the end of the sentence if (all_appositives) { buffer.Append(", "); } realiseList(buffer, element.Children, commaSepPremodifiers ? "," : ""); if (all_appositives) { buffer.Append(", "); } } else if (DiscourseFunction.POST_MODIFIER.Equals(function)) { // && appositive) IList <NLGElement> postmods = element.Children; // bug fix due to Owen Bennett int len = postmods.Count; for (int i = 0; i < len; i++) { // for(NLGElement postmod: element.getChildren()) { NLGElement postmod = postmods[i]; // if the postmod is appositive, it's sandwiched in commas if (postmod.getFeatureAsBoolean(Feature.APPOSITIVE)) { buffer.Append(", "); buffer.Append(realise(postmod)); buffer.Append(", "); } else { buffer.Append(realise(postmod)); if (postmod is ListElement || (postmod.Realisation != null && !postmod.Realisation.Equals(""))) { buffer.Append(" "); } } } } else if ((DiscourseFunction.CUE_PHRASE.Equals(function) || DiscourseFunction.FRONT_MODIFIER.Equals(function)) && commaSepCuephrase) { realiseList(buffer, element.Children, commaSepCuephrase ? "," : ""); } else { realiseList(buffer, element.Children, ""); } // realiseList(buffer, element.getChildren(), ""); realisedElement = new StringElement(buffer.ToString()); } else if (element is CoordinatedPhraseElement) { realisedElement = realiseCoordinatedPhrase(element.Children); } else { realisedElement = element; } // make the realised element inherit the original category // essential if list items are to be properly formatted later if (realisedElement != null) { realisedElement.Category = category; } //check if this is a cue phrase; if param is set, postfix a comma if ((DiscourseFunction.CUE_PHRASE.Equals(function) || DiscourseFunction.FRONT_MODIFIER.Equals(function)) && commaSepCuephrase) { string realisation = realisedElement.Realisation; if (!realisation.EndsWith(",", StringComparison.Ordinal)) { realisation = realisation + ","; } realisedElement.Realisation = realisation; } if (element.Capitalized) { string realisation = realisedElement.Realisation; realisedElement.Realisation = realisation.Substring(0, 1).ToUpper() + realisation.Substring(1); } } //remove preceding and trailing whitespace from internal punctuation removePunctSpace(realisedElement); return(realisedElement); }
/** * 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 <code>PhraseElement</code> representing this noun phrase. * @return the <code>NumberAgreement</code> 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 is 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 is PhraseElement) { if (parent.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.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); }