/// <summary> /// Returns the deepest shared parent of this node and the specified node. /// If the nodes are identical then their parent is returned. /// If one node is the parent of the other then the parent node is returned. /// </summary> /// <param name="node"> /// The node from which parents are compared to this node's parents. /// </param> /// <returns> /// the deepest shared parent of this node and the specified node. /// </returns> public virtual Parse GetCommonParent(Parse node) { if (this == node) { return(this.Parent); } Util.HashSet <Parse> parents = new Util.HashSet <Parse>(); Parse parentParse = this; while (parentParse != null) { parents.Add(parentParse); parentParse = parentParse.Parent; } while (node != null) { if (parents.Contains(node)) { return(node); } node = node.Parent; } return(null); }
public static /*<V, E>*/ List <V> GetShortestPath <V, E>(IGraph <V, E> graph, V node1, V node2, bool directionSensitive) { if (node1.Equals(node2)) { //return Collections.singletonList(node2); return(new List <V>() { node2 }); } Set <V> visited = new Util.HashSet <V>(); var previous = new Dictionary <V, V>(); var unsettledNodes = new BinaryHeapPriorityQueue <V>(); unsettledNodes.Add(node1, 0); while (unsettledNodes.Size() > 0) { var distance = unsettledNodes.GetPriority(); var u = unsettledNodes.RemoveFirst(); visited.Add(u); if (u.Equals(node2)) { break; } unsettledNodes.Remove(u); var candidates = ((directionSensitive) ? graph.GetChildren(u) : new ReadOnlyCollection <V>(graph.GetNeighbors(u))); foreach (var candidate in candidates) { var alt = distance - 1; // nodes not already present will have a priority of -inf if (alt > unsettledNodes.GetPriority(candidate) && !visited.Contains(candidate)) { unsettledNodes.RelaxPriority(candidate, alt); previous[candidate] = u; } } } if (!previous.ContainsKey(node2)) { return(null); } var path = new List <V> { node2 }; var n = node2; while (previous.ContainsKey(n)) { path.Add(previous[n]); n = previous[n]; } path.Reverse(); return(path); }
/// <summary> /// Remove duplicate relations: it can happen when collapsing stranded /// prepositions. E.g., "What does CPR stand for?" we get dep(stand, what), and /// after collapsing we also get prep_for(stand, what). /// </summary> /// <param name="list">A list of typed dependencies to check through</param> private static void RemoveDep(List<TypedDependency> list) { Set<GrammaticalRelation> prepRels = new Util.HashSet<GrammaticalRelation>(EnglishGrammaticalRelations.GetPreps()); prepRels.AddAll(EnglishGrammaticalRelations.GetPrepsC()); foreach (TypedDependency td1 in list) { if (prepRels.Contains(td1.Reln)) { // if we have a prep_ relation IndexedWord gov = td1.Gov; IndexedWord dep = td1.Dep; foreach (TypedDependency td2 in list) { if (td2.Reln == GrammaticalRelation.Dependent && td2.Gov.Equals(gov) && td2.Dep.Equals(dep)) { td2.Reln = GrammaticalRelation.Kill; } } } } // now remove typed dependencies with reln "kill" /*for (Iterator<TypedDependency> iter = list.iterator(); iter.hasNext();) { TypedDependency td = iter.next(); if (td.reln() == KILL) { iter.remove(); } }*/ list.RemoveAll(td => td.Reln == GrammaticalRelation.Kill); }
/// <summary> /// Returns the deepest shared parent of this node and the specified node. /// If the nodes are identical then their parent is returned. /// If one node is the parent of the other then the parent node is returned. /// </summary> /// <param name="node"> /// The node from which parents are compared to this node's parents. /// </param> /// <returns> /// the deepest shared parent of this node and the specified node. /// </returns> public virtual Parse GetCommonParent(Parse node) { if (this == node) { return this.Parent; } Util.HashSet<Parse> parents = new Util.HashSet<Parse>(); Parse parentParse = this; while (parentParse != null) { parents.Add(parentParse); parentParse = parentParse.Parent; } while (node != null) { if (parents.Contains(node)) { return node; } node = node.Parent; } return null; }
private static void TreatCc(List<TypedDependency> list) { // Construct a map from tree nodes to the set of typed // dependencies in which the node appears as dependent. var map = new Dictionary<IndexedWord, Set<TypedDependency>>(); // Construct a map of tree nodes being governor of a subject grammatical // relation to that relation var subjectMap = new Dictionary<IndexedWord, TypedDependency>(); // Construct a set of TreeGraphNodes with a passive auxiliary on them Set<IndexedWord> withPassiveAuxiliary = new Util.HashSet<IndexedWord>(); // Construct a map of tree nodes being governor of an object grammatical // relation to that relation // Map<TreeGraphNode, TypedDependency> objectMap = new // HashMap<TreeGraphNode, TypedDependency>(); var rcmodHeads = new List<IndexedWord>(); var prepcDep = new List<IndexedWord>(); foreach (TypedDependency typedDep in list) { if (!map.ContainsKey(typedDep.Dep)) { // NB: Here and in other places below, we use a TreeSet (which extends // SortedSet) to guarantee that results are deterministic) map.Add(typedDep.Dep, new TreeSet<TypedDependency>()); } map[typedDep.Dep].Add(typedDep); if (typedDep.Reln.Equals(EnglishGrammaticalRelations.AuxPassiveModifier)) { withPassiveAuxiliary.Add(typedDep.Gov); } // look for subjects if (typedDep.Reln.GetParent() == EnglishGrammaticalRelations.NominalSubject || typedDep.Reln.GetParent() == EnglishGrammaticalRelations.Subject || typedDep.Reln.GetParent() == EnglishGrammaticalRelations.ClausalSubject) { if (!subjectMap.ContainsKey(typedDep.Gov)) { subjectMap.Add(typedDep.Gov, typedDep); } } // look for objects // this map was only required by the code commented out below, so comment // it out too // if (typedDep.reln() == DIRECT_OBJECT) { // if (!objectMap.containsKey(typedDep.gov())) { // objectMap.put(typedDep.gov(), typedDep); // } // } // look for rcmod relations if (typedDep.Reln == EnglishGrammaticalRelations.RelativeClauseModifier) { rcmodHeads.Add(typedDep.Gov); } // look for prepc relations: put the dependent of such a relation in the // list // to avoid wrong propagation of dobj if (typedDep.Reln.ToString().StartsWith("prepc")) { prepcDep.Add(typedDep.Dep); } } // create a new list of typed dependencies var newTypedDeps = new List<TypedDependency>(list); // find typed deps of form conj(gov,dep) foreach (TypedDependency td in list) { if (EnglishGrammaticalRelations.GetConjs().Contains(td.Reln)) { IndexedWord gov = td.Gov; IndexedWord dep = td.Dep; // look at the dep in the conjunct Set<TypedDependency> govRelations = map[gov]; if (govRelations != null) { foreach (TypedDependency td1 in govRelations) { IndexedWord newGov = td1.Gov; // in the case of errors in the basic dependencies, it // is possible to have overlapping newGov & dep if (newGov.Equals(dep)) { continue; } GrammaticalRelation newRel = td1.Reln; if (newRel != GrammaticalRelation.Root) { if (rcmodHeads.Contains(gov) && rcmodHeads.Contains(dep)) { // to prevent wrong propagation in the case of long dependencies in relative clauses if (newRel != EnglishGrammaticalRelations.DirectObject && newRel != EnglishGrammaticalRelations.NominalSubject) { newTypedDeps.Add(new TypedDependency(newRel, newGov, dep)); } } else { newTypedDeps.Add(new TypedDependency(newRel, newGov, dep)); } } } } // propagate subjects // look at the gov in the conjunct: if it is has a subject relation, // the dep is a verb and the dep doesn't have a subject relation // then we want to add a subject relation for the dep. // (By testing for the dep to be a verb, we are going to miss subject of // copular verbs! but // is it safe to relax this assumption?? i.e., just test for the subject // part) // CDM 2008: I also added in JJ, since participial verbs are often // tagged JJ string tag = dep.Tag(); if (subjectMap.ContainsKey(gov) && (PartsOfSpeech.IsVerb(tag) || PartsOfSpeech.IsAdjective(tag)) && ! subjectMap.ContainsKey(dep)) { TypedDependency tdsubj = subjectMap[gov]; // check for wrong nsubjpass: if the new verb is VB or VBZ or VBP or JJ, then // add nsubj (if it is tagged correctly, should do this for VBD too, but we don't) GrammaticalRelation relation = tdsubj.Reln; if (relation == EnglishGrammaticalRelations.NominalPassiveSubject) { if (IsDefinitelyActive(tag)) { relation = EnglishGrammaticalRelations.NominalSubject; } } else if (relation == EnglishGrammaticalRelations.ClausalPassiveSubject) { if (IsDefinitelyActive(tag)) { relation = EnglishGrammaticalRelations.ClausalSubject; } } else if (relation == EnglishGrammaticalRelations.NominalSubject) { if (withPassiveAuxiliary.Contains(dep)) { relation = EnglishGrammaticalRelations.NominalPassiveSubject; } } else if (relation == EnglishGrammaticalRelations.ClausalSubject) { if (withPassiveAuxiliary.Contains(dep)) { relation = EnglishGrammaticalRelations.ClausalPassiveSubject; } } newTypedDeps.Add(new TypedDependency(relation, dep, tdsubj.Dep)); } // propagate objects // cdm july 2010: This bit of code would copy a dobj from the first // clause to a later conjoined clause if it didn't // contain its own dobj or prepc. But this is too aggressive and wrong // if the later clause is intransitive // (including passivized cases) and so I think we have to not have this // done always, and see no good "sometimes" heuristic. // IF WE WERE TO REINSTATE, SHOULD ALSO NOT ADD OBJ IF THERE IS A ccomp // (SBAR). // if (objectMap.containsKey(gov) && // dep.tag().startsWith("VB") && ! objectMap.containsKey(dep) // && ! prepcDep.contains(gov)) { // TypedDependency tdobj = objectMap.get(gov); // newTypedDeps.add(new TypedDependency(tdobj.reln(), dep, // tdobj.dep())); // } } } list.Clear(); list.AddRange(newTypedDeps); }